#include "xf86Version.h"
#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(3,9,0,0,0)
#define XFREE86_V4
#endif
#ifdef XFREE86_V4
#include "misc.h"
#include "xf86.h"
#if !defined(DGUX)
#include "xf86_ansic.h"
#endif
#include "xf86_OSproc.h"
#include "xf86Xinput.h"
#include "exevents.h"
#ifdef XFree86LOADER
#include "xf86Module.h"
#endif
#else
#include "Xos.h"
#include <signal.h>
#include <stdio.h>
#define NEED_EVENTS
#include "X.h"
#include "Xproto.h"
#include "inputstr.h"
#include "scrnintstr.h"
#include "XI.h"
#include "XIproto.h"
#include "compiler.h"
#include "xf86.h"
#include "xf86Procs.h"
#include "xf86_OSlib.h"
#include "xf86_Config.h"
#include "xf86Xinput.h"
#include "os.h"
#include "osdep.h"
#include "exevents.h"
#include "extnsionst.h"
#include "extinit.h"
#endif
#ifndef XFREE86_V4
#define FINGER_SECTION_NAME "microtouchfinger"
#define STYLUS_SECTION_NAME "microtouchstylus"
#define PORT 1
#define DEVICENAME 2
#define SCREEN_NO 3
#define MAXX 5
#define MAXY 6
#define MINX 7
#define MINY 8
#define DEBUG_LEVEL 9
#define HISTORY_SIZE 10
#define LINK_SPEED 11
#define ALWAYS_CORE 12
#define SWAP_AXES 13
#define FREQUENCY 14
#define PORTRAIT_MODE 15
static SymTabRec MuTTab[] = {
{ ENDSUBSECTION, "endsubsection" },
{ PORT, "port" },
{ DEVICENAME, "devicename" },
{ SCREEN_NO, "screenno" },
{ MAXX, "maximumxposition" },
{ MAXY, "maximumyposition" },
{ MINX, "minimumxposition" },
{ MINY, "minimumyposition" },
{ DEBUG_LEVEL, "debuglevel" },
{ HISTORY_SIZE, "historysize" },
{ LINK_SPEED, "linkspeed" },
{ ALWAYS_CORE, "alwayscore" },
{ SWAP_AXES, "swapxy" },
{ FREQUENCY, "frequency" },
{ PORTRAIT_MODE, "portraitmode" },
{ -1, "" },
};
#define LS300 1
#define LS1200 2
#define LS2400 3
#define LS9600 4
#define LS19200 5
static SymTabRec LinkSpeedTab[] = {
{ LS300, "b300" },
{ LS1200, "b1200" },
{ LS2400, "b2400" },
{ LS9600, "b9600" },
{ LS19200, "b19200" }
};
typedef struct {
int speed;
} LinkParameterStruct;
static LinkParameterStruct LinkSpeedValues[] = {
{ B300 },
{ B1200 },
{ B2400 },
{ B9600 },
{ B19200 }
};
#endif
#define MuT_MAX_TRIALS 5
#define MuT_MAX_WAIT 300000
#define MuT_LINK_SPEED B9600
#define MuT_PORT "/dev/ttyS1"
#define DEFAULT_MAX_X 3000
#define DEFAULT_MIN_X 600
#define DEFAULT_MAX_Y 3000
#define DEFAULT_MIN_Y 600
#define XI_FINGER "FINGER"
#define XI_STYLUS "STYLUS"
#define MuT_REPORT_SIZE 5
#define MuT_BUFFER_SIZE 256
#define MuT_PACKET_SIZE 10
#define MuT_LEAD_BYTE 0x01
#define MuT_TRAIL_BYTE 0x0D
#define MuT_RESET "R"
#define MuT_RESTORE_DEFAULTS "RD"
#define MuT_FORMAT_TABLET "FT"
#define MuT_FORMAT_RAW "FR"
#define MuT_CALIBRATE_RAW "CR"
#define MuT_CALIBRATE_EXT "CX"
#define MuT_OUTPUT_IDENT "OI"
#define MuT_UNIT_TYPE "UT"
#define MuT_FINGER_ONLY "FO"
#define MuT_PEN_ONLY "PO"
#define MuT_PEN_FINGER "PF"
#define MuT_MODE_STREAM "MS"
#define MuT_MODE_NOISE "MN"
#define MuT_MODE_EXTENDED "MX"
#define MuT_SET_CREEP "SC"
#define MuT_SET_SENSITIVITY "SS"
#define MuT_SET_FREQUENCY "SF"
#define MuT_SET_PHASE "SP"
#define MuT_SET_TYPE "ST"
#define MuT_SET_CORRECTION_X "SCX"
#define MuT_SET_CORRECTION_Y "SCY"
#define MuT_FORMAT_RAW_ASCII "FRA"
#define MuT_FORMAT_BASE_ASCII "FBA"
#define MuT_FORMAT_DEPTH_ASCII "FZA"
#define MuT_NOISE_ASCII "NOA"
#define MuT_OK '0'
#define MuT_ERROR '1'
#define MuT_SW1 0x01
#define MuT_SW2 0x02
#define MuT_WHICH_DEVICE 0x20
#define MuT_CONTACT 0x40
#define MuT_TOUCH_PEN_IDENT "P5"
#define MuT_SMT3_IDENT "Q1"
#define MuT_THRU_GLASS_IDENT "T1"
#define WORD_ASSEMBLY(byte1, byte2) (((byte2) << 7) | (byte1))
#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
#ifdef DBG
#undef DBG
#endif
#ifdef DEBUG
#undef DEBUG
#endif
static int debug_level = 0;
#define DEBUG 1
#if DEBUG
#define DBG(lvl, f) {if ((lvl) <= debug_level) f;}
#else
#define DBG(lvl, f)
#endif
#ifdef XFREE86_V4
#undef SYSCALL
#undef read
#undef write
#undef close
#define SYSCALL(call) call
#define read(fd, ptr, num) xf86ReadSerial(fd, ptr, num)
#define write(fd, ptr, num) xf86WriteSerial(fd, ptr, num)
#define close(fd) xf86CloseSerial(fd)
#endif
#define FINGER_ID 1
#define STYLUS_ID 2
#define DEVICE_ID(flags) ((flags) & 0x03)
typedef struct _MuTPrivateRec {
char *input_dev;
int min_x;
int max_x;
int min_y;
int max_y;
#ifndef XFREE86_V4
int link_speed;
#endif
int frequency;
int screen_no;
int screen_width;
int screen_height;
Bool inited;
char state;
int num_old_bytes;
LocalDevicePtr finger;
LocalDevicePtr stylus;
int swap_axes;
unsigned char rec_buf[MuT_BUFFER_SIZE];
} MuTPrivateRec, *MuTPrivatePtr;
#ifndef XFREE86_V4
static Bool
xf86MuTConfig(LocalDevicePtr *array,
int inx,
int max,
LexPtr val)
{
LocalDevicePtr local = array[inx];
MuTPrivatePtr priv = (MuTPrivatePtr)(local->private);
int token;
int portrait=0;
while ((token = xf86GetToken(MuTTab)) != ENDSUBSECTION) {
switch(token) {
case PORT:
if (xf86GetToken(NULL) != STRING)
xf86ConfigError("MicroTouch input port expected");
else {
int i;
for (i = 0; i < max; i++) {
if (i == inx)
continue;
if (array[i]->device_config == xf86MuTConfig &&
(strcmp(((MuTPrivatePtr) array[i]->private)->input_dev,
val->str) == 0)) {
ErrorF("%s MicroTouch config detected a device share between %s and %s\n",
XCONFIG_GIVEN, local->name, array[i]->name);
xfree(priv);
priv = local->private = array[i]->private;
switch (DEVICE_ID(local->private_flags)) {
case FINGER_ID:
priv->finger = local;
break;
case STYLUS_ID:
priv->stylus = local;
break;
}
break;
}
}
if (i == max) {
priv->input_dev = strdup(val->str);
if (xf86Verbose)
ErrorF("%s MicroTouch %s input port: %s\n",
XCONFIG_GIVEN, local->name, priv->input_dev);
}
}
break;
case DEVICENAME:
if (xf86GetToken(NULL) != STRING)
xf86ConfigError("MicroTouch device name expected");
local->name = strdup(val->str);
if (xf86Verbose)
ErrorF("%s MicroTouch %s X device name: %s\n",
XCONFIG_GIVEN, local->name, local->name);
break;
case SCREEN_NO:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch screen number expected");
priv->screen_no = val->num;
if (xf86Verbose)
ErrorF("%s MicroTouch %s associated screen: %d\n",
XCONFIG_GIVEN, local->name, priv->screen_no);
break;
case LINK_SPEED:
{
int ltoken = xf86GetToken(LinkSpeedTab);
if (ltoken == EOF ||
ltoken == STRING ||
ltoken == NUMBER)
xf86ConfigError("MicroTouch link speed expected");
priv->link_speed = LinkSpeedValues[ltoken-1].speed;
if (xf86Verbose)
ErrorF("%s MicroTouch %s link speed: %s bps\n",
XCONFIG_GIVEN, local->name, (LinkSpeedTab[ltoken-1].name)+1);
}
break;
case MAXX:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch maximum x position expected");
priv->max_x = val->num;
if (xf86Verbose)
ErrorF("%s MicroTouch %s maximum x position: %d\n",
XCONFIG_GIVEN, local->name, priv->max_x);
break;
case MAXY:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch maximum y position expected");
priv->max_y = val->num;
if (xf86Verbose)
ErrorF("%s Microtouch %s maximum y position: %d\n",
XCONFIG_GIVEN, local->name, priv->max_y);
break;
case MINX:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch minimum x position expected");
priv->min_x = val->num;
if (xf86Verbose)
ErrorF("%s MicroTouch %s minimum x position: %d\n",
XCONFIG_GIVEN, local->name, priv->min_x);
break;
case MINY:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch minimum y position expected");
priv->min_y = val->num;
if (xf86Verbose)
ErrorF("%s MicroTouch %s minimum y position: %d\n",
XCONFIG_GIVEN, local->name, priv->min_y);
break;
case DEBUG_LEVEL:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch driver debug expected");
debug_level = val->num;
if (xf86Verbose) {
#if DEBUG
ErrorF("%s MicroTouch %s debug level sets to %d\n", XCONFIG_GIVEN,
local->name, debug_level);
#else
ErrorF("%s MicroTouch %s debug not available\n",
XCONFIG_GIVEN, local->name, debug_level);
#endif
}
break;
case HISTORY_SIZE:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch motion history size expected");
local->history_size = val->num;
if (xf86Verbose)
ErrorF("%s MicroTouch %s motion history size is %d\n", XCONFIG_GIVEN,
local->name, local->history_size);
break;
case FREQUENCY:
if (xf86GetToken(NULL) != NUMBER)
xf86ConfigError("MicroTouch ThruGlass frequency expected");
priv->frequency = val->num;
if (xf86Verbose)
ErrorF("%s MicroTouch %s frequency is %d\n", XCONFIG_GIVEN,
local->name, priv->frequency);
break;
case ALWAYS_CORE:
xf86AlwaysCore(local, TRUE);
if (xf86Verbose)
ErrorF("%s MicroTouch %s device will always stays core pointer\n",
XCONFIG_GIVEN, local->name);
break;
case SWAP_AXES:
priv->swap_axes = 1;
if (xf86Verbose) {
ErrorF("%s Microtouch %s device will work with X and Y axes swapped\n",
XCONFIG_GIVEN, local->name);
}
break;
case PORTRAIT_MODE:
if (xf86GetToken(NULL) != STRING) {
portrait_mode_err:
xf86ConfigError("Microtouch portrait mode should be: Portrait, Landscape or PortraitCCW");
}
if (strcmp(val->str, "portrait") == 0) {
portrait = 1;
}
else if (strcmp(val->str, "portraitccw") == 0) {
portrait = -1;
}
else if (strcmp(val->str, "landscape") != 0) {
goto portrait_mode_err;
}
if (xf86Verbose) {
ErrorF("%s Microtouch %s device will work in %s mode\n",
XCONFIG_GIVEN, local->name, val->str);
}
break;
case EOF:
FatalError("Unexpected EOF (missing EndSubSection)");
break;
default:
xf86ConfigError("MicroTouch subsection keyword expected");
break;
}
}
if (priv->max_x - priv->min_x <=0) {
ErrorF("%s MicroTouch: reverse x mode (minimum x position >= maximum x position)\n",
XCONFIG_GIVEN);
}
if (priv->max_y - priv->min_y <=0) {
ErrorF("%s MicroTouch: reverse y mode (minimum y position >= maximum y position)\n",
XCONFIG_GIVEN);
}
if (portrait == 1) {
int tmp;
tmp = priv->min_y;
priv->min_y = priv->max_y;
priv->max_y = tmp;
priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
}
else if (portrait == -1) {
int tmp;
tmp = priv->min_x;
priv->min_x = priv->max_x;
priv->max_x = tmp;
priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
}
DBG(2, ErrorF("xf86MuTConfig port name=%s\n", priv->input_dev))
return Success;
}
#endif
static Bool
xf86MuTConvert(LocalDevicePtr local,
int first,
int num,
int v0,
int v1,
int v2,
int v3,
int v4,
int v5,
int *x,
int *y)
{
MuTPrivatePtr priv = (MuTPrivatePtr) local->private;
int width = priv->max_x - priv->min_x;
int height = priv->max_y - priv->min_y;
int input_x, input_y;
if (first != 0 || num != 2)
return FALSE;
if (priv->swap_axes) {
input_x = v1;
input_y = v0;
}
else {
input_x = v0;
input_y = v1;
}
*x = (priv->screen_width * (input_x - priv->min_x)) / width;
*y = (priv->screen_height -
(priv->screen_height * (input_y - priv->min_y)) / height);
#ifdef XFREE86_V4
xf86XInputSetScreen(local, priv->screen_no, *x, *y);
#endif
return TRUE;
}
static void
xf86MuTReadInput(LocalDevicePtr local)
{
MuTPrivatePtr priv = (MuTPrivatePtr)(local->private);
int cur_x, cur_y;
int state;
int num_bytes;
int bytes_in_packet;
unsigned char *ptr, *start_ptr;
DBG(4, ErrorF("Entering ReadInput\n"));
DBG(4, ErrorF("num_old_bytes is %d, Trying to read %d bytes from port\n",
priv->num_old_bytes, MuT_BUFFER_SIZE - priv->num_old_bytes));
SYSCALL(num_bytes = read(local->fd,
(char *) (priv->rec_buf + priv->num_old_bytes),
MuT_BUFFER_SIZE - priv->num_old_bytes));
if (num_bytes < 0) {
Error("System error while reading from MicroTouch touchscreen.");
return;
}
DBG(4, ErrorF("Read %d bytes of reports\n", num_bytes));
num_bytes += priv->num_old_bytes;
ptr = priv->rec_buf;
bytes_in_packet = 0;
start_ptr = ptr;
while (num_bytes >= (MuT_REPORT_SIZE-bytes_in_packet)) {
if (bytes_in_packet == 0) {
if ((ptr[0] & 0x80) == 0) {
DBG(3, ErrorF("Dropping a byte in an attempt to synchronize a report packet: 0x%X\n",
ptr[0]));
start_ptr++;
}
else {
bytes_in_packet++;
}
num_bytes--;
ptr++;
}
else if (bytes_in_packet != 5) {
if ((ptr[0] & 0x80) == 0) {
bytes_in_packet++;
}
else {
DBG(3, ErrorF("Reseting start of report packet data has been lost\n"));
bytes_in_packet = 1;
start_ptr = ptr;
}
ptr++;
num_bytes--;
}
if (bytes_in_packet == 5) {
LocalDevicePtr local_to_use;
state = start_ptr[0] & 0x7F;
cur_x = WORD_ASSEMBLY(start_ptr[1], start_ptr[2]);
cur_y = WORD_ASSEMBLY(start_ptr[3], start_ptr[4]);
DBG(3, ErrorF("Packet: 0x%X 0x%X 0x%X 0x%X 0x%X\n",
start_ptr[0], start_ptr[1], start_ptr[2], start_ptr[3], start_ptr[4]));
start_ptr = ptr;
bytes_in_packet = 0;
local_to_use = (state & MuT_WHICH_DEVICE) ? priv->stylus : priv->finger;
if (!local_to_use) {
static int whinged = 0;
if (!whinged) {
whinged++;
ErrorF("MicroTouch screen sent %s event, but that device is not configured.\n",
(state & MuT_WHICH_DEVICE)?"stylus":"finger");
ErrorF("You might want to consider altering your config accordingly.\n");
}
}
else {
xf86PostMotionEvent(local_to_use->dev, TRUE, 0, 2, cur_x, cur_y);
if ((state & MuT_CONTACT) != (priv->state & MuT_CONTACT)) {
xf86PostButtonEvent(local_to_use->dev, TRUE, 1, state & MuT_CONTACT,
0, 2, cur_x, cur_y);
}
}
DBG(3, ErrorF("TouchScreen %s: x(%d), y(%d), %s\n",
((state & MuT_WHICH_DEVICE) ? "Stylus" : "Finger"),
cur_x, cur_y,
(((state & MuT_CONTACT) != (priv->state & MuT_CONTACT)) ?
((state & MuT_CONTACT) ? "Press" : "Release") : "Stream")));
priv->state = state;
}
}
if (num_bytes != 0) {
memcpy(priv->rec_buf, ptr, num_bytes);
priv->num_old_bytes = num_bytes;
}
else {
priv->num_old_bytes = 0;
}
}
static Bool
xf86MuTSendPacket(unsigned char *packet,
int len,
int fd)
{
int result;
packet[0] = MuT_LEAD_BYTE;
packet[len+1] = MuT_TRAIL_BYTE;
DBG(4, ErrorF("Sending packet : 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",
packet[0], packet[1], packet[2], packet[3], packet[4],
packet[5], packet[6], packet[7], packet[8], packet[9]));
SYSCALL(result = write(fd, packet, len+2));
if (result != len+2) {
DBG(5, ErrorF("System error while sending to MicroTouch touchscreen.\n"));
return !Success;
}
else {
return Success;
}
}
static Bool
xf86MuTGetReply(unsigned char *buffer,
int *buffer_p,
int fd)
{
int num_bytes;
DBG(4, ErrorF("Entering xf86MuTGetReply with buffer_p == %d\n", *buffer_p));
DBG(4, ErrorF("buffer_p is %d, Trying to read %d bytes from port\n",
*buffer_p, MuT_BUFFER_SIZE - *buffer_p));
SYSCALL(num_bytes = read(fd,
(char *) (buffer + *buffer_p),
MuT_BUFFER_SIZE - *buffer_p));
if (num_bytes < 0) {
Error("System error while reading from MicroTouch touchscreen.");
return !Success;
}
DBG(4, ErrorF("Read %d bytes of reply\n", num_bytes));
while (num_bytes) {
if ((*buffer_p == 0) && (buffer[0] != MuT_LEAD_BYTE)) {
DBG(4, ErrorF("Dropping one byte in an attempt to synchronize: '%c' 0x%X\n",
buffer[0], buffer[0]));
memcpy(&buffer[0], &buffer[1], num_bytes-1);
num_bytes--;
}
else if (buffer[*buffer_p] == MuT_TRAIL_BYTE) {
*buffer_p = 0;
return Success;
}
else {
num_bytes--;
(*buffer_p)++;
}
}
return !Success;
}
#ifndef XFREE86_V4
static int
xf86WaitForInput(int fd,
int timeout)
{
fd_set readfds;
struct timeval to;
int r;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
to.tv_sec = 0;
to.tv_usec = timeout;
SYSCALL(r = select(FD_SETSIZE, &readfds, NULL, NULL, &to));
return r;
}
#endif
static Bool
xf86MuTWaitReply(unsigned char *reply,
int fd)
{
Bool ok;
int i, result;
int reply_p = 0;
unsigned char local_reply[3];
DBG(4, ErrorF("Waiting a reply\n"));
i = MuT_MAX_TRIALS;
do {
ok = !Success;
DBG(4, ErrorF("Waiting %d ms for data from port\n", MuT_MAX_WAIT / 1000));
result = xf86WaitForInput(fd, MuT_MAX_WAIT);
if (result > 0) {
if (reply) {
ok = xf86MuTGetReply(reply, &reply_p, fd);
}
else {
ok = xf86MuTGetReply(local_reply, &reply_p, fd);
if (ok && local_reply[1] != MuT_OK) {
DBG(3, ErrorF("Error reported by firmware\n"));
ok = !Success;
}
}
}
else {
DBG(3, ErrorF("No answer from port : %d\n", result));
}
if (result == 0)
i--;
} while(ok != Success && i);
return ok;
}
static Bool
xf86MuTSendCommand(unsigned char *request,
int len,
unsigned char *reply,
int fd)
{
Bool ok;
if (xf86MuTSendPacket(request, len, fd) == Success) {
ok = xf86MuTWaitReply(reply, fd);
return ok;
}
else {
return !Success;
}
}
static void
xf86MuTPrintIdent(unsigned char *packet)
{
int vers, rev;
#ifdef XFREE86_V4
xf86Msg(X_PROBED, "MicroTouch touchscreen is a ");
if (strncmp((char *) &packet[1], MuT_TOUCH_PEN_IDENT, 2) == 0) {
xf86Msg(X_NONE, "TouchPen");
}
else if (strncmp((char *) &packet[1], MuT_SMT3_IDENT, 2) == 0) {
xf86Msg(X_NONE, "Serial/SMT3");
}
else if (strncmp((char *) &packet[1], MuT_THRU_GLASS_IDENT, 2) == 0) {
xf86Msg(X_NONE, "ThruGlass");
}
xf86Msg(X_NONE, ", connected through a serial port.\n");
sscanf((char *) &packet[3], "%2d%2d", &vers, &rev);
xf86Msg(X_PROBED, "MicroTouch controller firmware revision is %d.%d.\n", vers, rev);
#else
ErrorF("%s MicroTouch touchscreen is a ", XCONFIG_PROBED);
if (strncmp((char *) &packet[1], MuT_TOUCH_PEN_IDENT, 2) == 0) {
ErrorF("TouchPen");
}
else if (strncmp((char *) &packet[1], MuT_SMT3_IDENT, 2) == 0) {
ErrorF("Serial/SMT3");
}
else if (strncmp((char *) &packet[1], MuT_THRU_GLASS_IDENT, 2) == 0) {
ErrorF("ThruGlass");
}
ErrorF(", connected through a serial port.\n");
sscanf((char *) &packet[3], "%2d%2d", &vers, &rev);
ErrorF("%s MicroTouch controller firmware revision is %d.%d.\n", XCONFIG_PROBED, vers, rev);
#endif
}
static void
xf86MuTPrintHwStatus(unsigned char *packet)
{
#ifdef XFREE86_V4
xf86Msg(X_PROBED, "MicroTouch status of errors: %c%c.\n", packet[7], packet[8]);
#else
ErrorF("%s MicroTouch status of errors: %c%c.\n", XCONFIG_PROBED, packet[7], packet[8]);
#endif
}
#if 0
static void
xf86MuTPtrControl(DeviceIntPtr dev,
PtrCtrl *ctrl)
{
}
#endif
static Bool
xf86MuTControl(DeviceIntPtr dev,
int mode)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
MuTPrivatePtr priv = (MuTPrivatePtr)(local->private);
unsigned char map[] = { 0, 1 };
unsigned char req[MuT_PACKET_SIZE];
unsigned char reply[MuT_BUFFER_SIZE];
char *id_string = DEVICE_ID(local->private_flags) == FINGER_ID ? "finger" : "stylus";
switch(mode) {
case DEVICE_INIT:
{
DBG(2, ErrorF("MicroTouch %s init...\n", id_string));
if (priv->screen_no >= screenInfo.numScreens ||
priv->screen_no < 0) {
priv->screen_no = 0;
}
priv->screen_width = screenInfo.screens[priv->screen_no]->width;
priv->screen_height = screenInfo.screens[priv->screen_no]->height;
if (InitButtonClassDeviceStruct(dev, 1, map) == FALSE) {
ErrorF("Unable to allocate ButtonClassDeviceStruct\n");
return !Success;
}
if (InitValuatorClassDeviceStruct(dev, 2, xf86GetMotionEvents,
local->history_size, Absolute) == FALSE) {
ErrorF("Unable to allocate ValuatorClassDeviceStruct\n");
return !Success;
}
else {
InitValuatorAxisStruct(dev, 0, priv->min_x, priv->max_x,
9500,
0 ,
9500 );
InitValuatorAxisStruct(dev, 1, priv->min_y, priv->max_y,
10500,
0 ,
10500 );
}
if (InitFocusClassDeviceStruct(dev) == FALSE) {
ErrorF("Unable to allocate FocusClassDeviceStruct\n");
}
xf86MotionHistoryAllocate(local);
#ifndef XFREE86_V4
AssignTypeAndName(dev, local->atom, local->name);
#endif
DBG(2, ErrorF("Done.\n"));
return Success;
}
case DEVICE_ON:
{
Bool already_open = FALSE;
char *report_what = "";
DBG(2, ErrorF("MicroTouch %s on...\n", id_string));
if (local->fd >= 0) {
already_open = TRUE;
}
else {
switch (DEVICE_ID(local->private_flags)) {
case FINGER_ID:
if (priv->stylus && priv->stylus->fd >= 0) {
already_open = TRUE;
local->fd = priv->stylus->fd;
}
break;
case STYLUS_ID:
if (priv->finger && priv->finger->fd >= 0) {
already_open = TRUE;
local->fd = priv->finger->fd;
}
break;
}
}
if (!already_open) {
#ifndef XFREE86_V4
struct termios termios_tty;
int result;
#endif
DBG(2, ErrorF("MicroTouch touchscreen opening : %s\n", priv->input_dev));
#ifdef XFREE86_V4
local->fd = xf86OpenSerial(local->options);
if (local->fd < 0) {
Error("Unable to open MicroTouch touchscreen device");
return !Success;
}
#else
SYSCALL(local->fd = open(priv->input_dev, O_RDWR|O_NDELAY, 0));
if (local->fd < 0) {
Error("Unable to open MicroTouch touchscreen device");
return !Success;
}
DBG(3, ErrorF("Try to see if the link is at the specified rate\n"));
memset(&termios_tty, 0, sizeof(termios_tty));
termios_tty.c_cflag = priv->link_speed | CS8 | CREAD | CLOCAL;
#ifdef CRTSCTS
termios_tty.c_cflag &= ~CRTSCTS;
#endif
termios_tty.c_cc[VMIN] = 1;
SYSCALL(result = tcsetattr(local->fd, TCSANOW, &termios_tty));
if (result < 0) {
Error("Unable to configure MicroTouch touchscreen port");
goto not_success;
}
#endif
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], MuT_RESET, strlen(MuT_RESET));
if (xf86MuTSendCommand(req, strlen(MuT_RESET), NULL, local->fd) != Success) {
DBG(3, ErrorF("Not at the specified rate, giving up\n"));
goto not_success;
}
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], MuT_OUTPUT_IDENT, strlen(MuT_OUTPUT_IDENT));
if (xf86MuTSendCommand(req, strlen(MuT_OUTPUT_IDENT),
reply, local->fd) != Success) {
ErrorF("Unable to ask MicroTouch touchscreen identification\n");
goto not_success;
}
xf86MuTPrintIdent(reply);
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], MuT_UNIT_TYPE, strlen(MuT_UNIT_TYPE));
if (xf86MuTSendCommand(req, strlen(MuT_UNIT_TYPE),
reply, local->fd) != Success) {
ErrorF("Unable to ask MicroTouch touchscreen status\n");
goto not_success;
}
xf86MuTPrintHwStatus(reply);
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], MuT_FORMAT_TABLET, strlen(MuT_FORMAT_TABLET));
if (xf86MuTSendCommand(req, strlen(MuT_FORMAT_TABLET),
NULL, local->fd) != Success) {
ErrorF("Unable to switch MicroTouch touchscreen to Tablet Format\n");
goto not_success;
}
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], MuT_MODE_STREAM, strlen(MuT_MODE_STREAM));
if (xf86MuTSendCommand(req, strlen(MuT_MODE_STREAM),
NULL, local->fd) != Success) {
ErrorF("Unable to switch MicroTouch touchscreen to Stream Mode\n");
goto not_success;
}
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], MuT_PEN_ONLY, strlen(MuT_PEN_ONLY));
if (xf86MuTSendCommand(req, strlen(MuT_PEN_ONLY),
NULL, local->fd) != Success) {
ErrorF("Unable to change MicroTouch touchscreen to pen mode\n");
goto not_success;
}
#ifndef XFREE86_V4
xf86AddEnabledDevice(local);
#else
AddEnabledDevice(local->fd);
#endif
}
switch (DEVICE_ID(local->private_flags)) {
case FINGER_ID:
if (priv->stylus && priv->stylus->dev->public.on) {
report_what = MuT_PEN_FINGER;
}
else {
report_what = MuT_FINGER_ONLY;
}
break;
case STYLUS_ID:
if (priv->finger && priv->finger->dev->public.on) {
report_what = MuT_PEN_FINGER;
}
else {
report_what = MuT_PEN_ONLY;
}
break;
}
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], report_what, strlen(report_what));
if (xf86MuTSendCommand(req, strlen(report_what), NULL, local->fd) != Success) {
ErrorF("Unable to change MicroTouch touchscreen to %s\n",
(strcmp(report_what, MuT_PEN_FINGER) == 0) ? "Pen & Finger" :
((strcmp(report_what, MuT_PEN_ONLY) == 0) ? "Pen Only" : "Finger Only"));
goto not_success;
}
dev->public.on = TRUE;
if (priv->frequency != 0) {
memset(req, 0, MuT_PACKET_SIZE);
strncpy((char *) &req[1], MuT_SET_FREQUENCY, strlen(MuT_SET_FREQUENCY));
req[1+strlen(MuT_SET_FREQUENCY)] = ' ';
req[2+strlen(MuT_SET_FREQUENCY)] = '0';
req[3+strlen(MuT_SET_FREQUENCY)] = (priv->frequency<=9?'0':'A'-10)+priv->frequency;
if (xf86MuTSendCommand(req, strlen((char *) &req[1]), NULL, local->fd) != Success) {
ErrorF("Unable to set MicroTouch ThruGlass frquency to %d\n", priv->frequency);
goto not_success;
}
}
DBG(2, ErrorF("Done\n"));
return Success;
not_success:
SYSCALL(close(local->fd));
local->fd = -1;
return !Success;
}
case DEVICE_OFF:
DBG(2, ErrorF("MicroTouch %s off...\n", id_string));
dev->public.on = FALSE;
DBG(2, ErrorF("Done\n"));
return Success;
case DEVICE_CLOSE:
DBG(2, ErrorF("MicroTouch %s close...\n", id_string));
dev->public.on = FALSE;
if (local->fd >= 0) {
#ifdef XFREE86_V4
xf86RemoveEnabledDevice(local);
#else
RemoveEnabledDevice(local->fd);
#endif
SYSCALL(close(local->fd));
local->fd = -1;
switch (DEVICE_ID(local->private_flags)) {
case FINGER_ID:
if (priv->stylus) {
priv->stylus->fd = -1;
}
break;
case STYLUS_ID:
if (priv->finger) {
priv->finger->fd = -1;
}
}
}
DBG(2, ErrorF("Done\n"));
return Success;
default:
ErrorF("unsupported mode=%d\n", mode);
return !Success;
}
}
static LocalDevicePtr
#ifndef XFREE86_V4
xf86MuTAllocate(char *name,
char *type_name,
int flag)
#else
xf86MuTAllocate(InputDriverPtr drv,
char *name,
char *type_name,
int flag)
#endif
{
#ifndef XFREE86_V4
LocalDevicePtr local = (LocalDevicePtr) xalloc(sizeof(LocalDeviceRec));
#else
LocalDevicePtr local = xf86AllocateInput(drv, 0);
#endif
MuTPrivatePtr priv = (MuTPrivatePtr) xalloc(sizeof(MuTPrivateRec));
if (!local) {
if (priv) {
xfree(priv);
}
return NULL;
}
if (!priv) {
if (local) {
xfree(local);
}
return NULL;
}
priv->input_dev = strdup(MuT_PORT);
#ifndef XFREE86_V4
priv->link_speed = MuT_LINK_SPEED;
#endif
priv->min_x = 0;
priv->max_x = 0;
priv->min_y = 0;
priv->max_y = 0;
priv->screen_no = 0;
priv->screen_width = -1;
priv->screen_height = -1;
priv->inited = 0;
priv->state = 0;
priv->num_old_bytes = 0;
priv->stylus = NULL;
priv->finger = NULL;
priv->swap_axes = 0;
priv->frequency = 0;
local->name = name;
local->flags = 0 ;
#ifndef XFREE86_V4
local->device_config = xf86MuTConfig;
#endif
local->device_control = xf86MuTControl;
local->read_input = xf86MuTReadInput;
local->control_proc = NULL;
local->close_proc = NULL;
local->switch_mode = NULL;
local->conversion_proc = xf86MuTConvert;
local->reverse_conversion_proc = NULL;
local->fd = -1;
local->atom = 0;
local->dev = NULL;
local->private = priv;
local->private_flags = flag;
local->type_name = type_name;
local->history_size = 0;
return local;
}
static LocalDevicePtr
#ifndef XFREE86_V4
xf86MuTAllocateFinger(void)
#else
xf86MuTAllocateFinger(InputDriverPtr drv)
#endif
{
#ifndef XFREE86_V4
LocalDevicePtr local = xf86MuTAllocate(XI_FINGER, "MicroTouch Finger", FINGER_ID);
#else
LocalDevicePtr local = xf86MuTAllocate(drv, XI_FINGER, "MicroTouch Finger", FINGER_ID);
#endif
if (local) {
((MuTPrivatePtr) local->private)->finger = local;
}
return local;
}
static LocalDevicePtr
#ifndef XFREE86_V4
xf86MuTAllocateStylus(void)
#else
xf86MuTAllocateStylus(InputDriverPtr drv)
#endif
{
#ifndef XFREE86_V4
LocalDevicePtr local = xf86MuTAllocate(XI_STYLUS, "MicroTouch Stylus", STYLUS_ID);
#else
LocalDevicePtr local = xf86MuTAllocate(drv, XI_STYLUS, "MicroTouch Stylus", STYLUS_ID);
#endif
if (local) {
((MuTPrivatePtr) local->private)->stylus = local;
}
return local;
}
#ifndef XFREE86_V4
DeviceAssocRec MuT_finger_assoc =
{
FINGER_SECTION_NAME,
xf86MuTAllocateFinger
};
DeviceAssocRec MuT_stylus_assoc =
{
STYLUS_SECTION_NAME,
xf86MuTAllocateStylus
};
#ifdef DYNAMIC_MODULE
int
#ifndef DLSYM_BUG
init_module(unsigned long server_version)
#else
init_xf86MuTouch(unsigned long server_version)
#endif
{
xf86AddDeviceAssoc(&MuT_finger_assoc);
xf86AddDeviceAssoc(&MuT_stylus_assoc);
if (server_version != XF86_VERSION_CURRENT) {
ErrorF("Warning: MicroTouch module compiled for version%s\n", XF86_VERSION);
return 0;
}
else {
return 1;
}
}
#endif
#else
static void
xf86MuTUninit(InputDriverPtr drv,
LocalDevicePtr local,
int flags)
{
MuTPrivatePtr priv = (MuTPrivatePtr) local->private;
xf86MuTControl(local->dev, DEVICE_OFF);
if (priv) {
priv->stylus->private = NULL;
priv->finger->private = NULL;
xfree(priv->input_dev);
xfree(priv);
}
xfree(local->name);
xfree(local);
xf86DeleteInput(local, 0);
}
static const char *default_options[] = {
"BaudRate", "9600",
"StopBits", "1",
"DataBits", "8",
"Parity", "None",
"Vmin", "10",
"Vtime", "1",
"FlowControl", "None",
NULL
};
static InputInfoPtr
xf86MuTInit(InputDriverPtr drv,
IDevPtr dev,
int flags)
{
LocalDevicePtr local=NULL, fake_local=NULL, current;
MuTPrivatePtr priv=NULL;
char *str;
int portrait=0;
fake_local = (LocalDevicePtr) xcalloc(1, sizeof(LocalDeviceRec));
if (!fake_local) {
goto init_err;
}
fake_local->conf_idev = dev;
xf86CollectInputOptions(fake_local, default_options, NULL);
str = xf86FindOptionValue(fake_local->options, "Type");
if (str && (xf86NameCmp(str, "finger") == 0)) {
local = xf86MuTAllocateFinger(drv);
}
else if (str && (xf86NameCmp(str, "stylus") == 0)) {
local = xf86MuTAllocateStylus(drv);
}
else {
xf86Msg(X_ERROR, "%s: Type field missing in Microtouch module config,\n"
"Must be stylus or finger\n", dev->identifier);
goto init_err;
}
if (!local) {
goto init_err;
}
priv = local->private;
local->options = fake_local->options;
local->conf_idev = fake_local->conf_idev;
xfree(fake_local);
fake_local = NULL;
str = xf86FindOptionValue(local->options, "Device");
if (!str) {
xf86Msg(X_ERROR, "%s: No Device specified in Microtouch module config.\n",
dev->identifier);
goto init_err;
}
priv->input_dev = strdup(str);
current = xf86FirstLocalDevice();
while (current) {
if ((local != current) &&
(current->device_control == xf86MuTControl) &&
(strcmp(((MuTPrivatePtr) (current->private))->input_dev, priv->input_dev) == 0)) {
xf86Msg(X_CONFIG, "MicroTouch config detected a device share between %s and %s\n",
local->name, current->name);
xfree(priv->input_dev);
xfree(priv);
priv = local->private = current->private;
switch (DEVICE_ID(local->private_flags)) {
case FINGER_ID:
priv->finger = local;
break;
case STYLUS_ID:
priv->stylus = local;
break;
}
break;
}
current = current->next;
}
if (!current) {
xf86Msg(X_CONFIG, "MicroTouch %s input device: %s\n", local->name, priv->input_dev);
}
xf86ProcessCommonOptions(local, local->options);
str = xf86FindOptionValue(local->options, "DeviceName");
if (str) {
local->name = strdup(str);
}
xf86Msg(X_CONFIG, "Microtouch X device name: %s\n", local->name);
priv->screen_no = xf86SetIntOption(local->options, "ScreenNo", 0);
xf86Msg(X_CONFIG, "Microtouch associated screen: %d\n", priv->screen_no);
priv->max_x = xf86SetIntOption(local->options, "MaxX", 3000);
xf86Msg(X_CONFIG, "Microtouch maximum x position: %d\n", priv->max_x);
priv->min_x = xf86SetIntOption(local->options, "MinX", 0);
xf86Msg(X_CONFIG, "Microtouch minimum x position: %d\n", priv->min_x);
priv->max_y = xf86SetIntOption(local->options, "MaxY", 3000);
xf86Msg(X_CONFIG, "Microtouch maximum y position: %d\n", priv->max_y);
priv->min_y = xf86SetIntOption(local->options, "MinY", 0);
xf86Msg(X_CONFIG, "Microtouch minimum y position: %d\n", priv->min_y);
priv->frequency = xf86SetIntOption(local->options, "Frequency", 0);
xf86Msg(X_CONFIG, "Microtouch ThruGlass frequency is: %d\n", priv->frequency);
priv->swap_axes = xf86SetBoolOption(local->options, "SwapXY", 0);
if (priv->swap_axes) {
xf86Msg(X_CONFIG, "Microtouch %s device will work with X and Y axes swapped\n",
local->name);
}
debug_level = xf86SetIntOption(local->options, "DebugLevel", 0);
if (debug_level) {
#if DEBUG
xf86Msg(X_CONFIG, "Microtouch debug level sets to %d\n", debug_level);
#else
xf86Msg(X_INFO, "Microtouch debug not available\n");
#endif
}
str = xf86SetStrOption(local->options, "PortraitMode", "Landscape");
if (strcmp(str, "Portrait") == 0) {
portrait = 1;
}
else if (strcmp(str, "PortraitCCW") == 0) {
portrait = -1;
}
else if (strcmp(str, "Landscape") != 0) {
xf86Msg(X_ERROR, "Microtouch portrait mode should be: Portrait, Landscape or PortraitCCW");
str = "Landscape";
}
xf86Msg(X_CONFIG, "Microtouch device will work in %s mode\n", str);
if (priv->max_x - priv->min_x <= 0) {
xf86Msg(X_INFO, "MicroTouch: reverse x mode (minimum x position >= maximum x position)\n");
}
if (priv->max_y - priv->min_y <= 0) {
xf86Msg(X_INFO, "MicroTouch: reverse y mode (minimum y position >= maximum y position)\n");
}
if (portrait == 1) {
int tmp;
tmp = priv->min_y;
priv->min_y = priv->max_y;
priv->max_y = tmp;
priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
}
else if (portrait == -1) {
int tmp;
tmp = priv->min_x;
priv->min_x = priv->max_x;
priv->max_x = tmp;
priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
}
local->flags |= XI86_CONFIGURED;
return local;
init_err:
if (fake_local) {
xfree(fake_local);
}
if (priv) {
if (priv->input_dev) {
xfree(priv->input_dev);
}
xfree(priv);
}
if (local) {
xfree(local);
}
return NULL;
}
#ifdef XFree86LOADER
static
#endif
InputDriverRec MUTOUCH = {
1,
"mutouch",
NULL,
xf86MuTInit,
xf86MuTUninit,
NULL,
0
};
#ifdef XFree86LOADER
static pointer
Plug(pointer module,
pointer options,
int *errmaj,
int *errmin)
{
xf86AddInputDriver(&MUTOUCH, module, 0);
return module;
}
static void
Unplug(pointer p)
{
DBG(1, ErrorF("MuTUnplug\n"));
}
static XF86ModuleVersionInfo version_rec = {
"mutouch",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XF86_VERSION_CURRENT,
1, 0, 0,
ABI_CLASS_XINPUT,
ABI_XINPUT_VERSION,
MOD_CLASS_XINPUT,
{ 0, 0, 0, 0 }
};
XF86ModuleData mutouchModuleData = { &version_rec, Plug, Unplug };
#endif
#endif