#define _microtouch_C_
#include <misc.h>
#include <xf86.h>
#define NEED_XF86_TYPES
#include <xf86_ansic.h>
#include <xf86_OSproc.h>
#include <xf86Xinput.h>
#include <xisb.h>
#include <exevents.h>
#include "microtouch.h"
static InputInfoPtr
MuTouchPreInit(InputDriverPtr drv, IDevPtr dev, int flags);
InputDriverRec MICROTOUCH = {
1,
"microtouch",
NULL,
MuTouchPreInit,
NULL,
NULL,
0
};
#ifdef XFree86LOADER
static XF86ModuleVersionInfo VersionRec =
{
"microtouch",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XF86_VERSION_CURRENT,
1, 0, 0,
ABI_CLASS_XINPUT,
ABI_XINPUT_VERSION,
MOD_CLASS_XINPUT,
{0, 0, 0, 0}
};
static const char *reqSymbols[] = {
"AddEnabledDevice",
"ErrorF",
"InitButtonClassDeviceStruct",
"InitProximityClassDeviceStruct",
"InitValuatorAxisStruct",
"InitValuatorClassDeviceStruct",
"RemoveEnabledDevice",
"Xcalloc",
"Xfree",
"XisbBlockDuration",
"XisbFree",
"XisbNew",
"XisbRead",
"XisbTrace",
"XisbWrite",
"screenInfo",
"xf86AddInputDriver",
"xf86AllocateInput",
"xf86CloseSerial",
"xf86CollectInputOptions",
"xf86ErrorF",
"xf86ErrorFVerb",
"xf86FindOptionValue",
"xf86FlushInput",
"xf86GetMotionEvents",
"xf86GetVerbosity",
"xf86LoaderReqSymLists",
"xf86MotionHistoryAllocate",
"xf86Msg",
"xf86NameCmp",
"xf86OpenSerial",
"xf86OptionListCreate",
"xf86OptionListFree",
"xf86OptionListReport",
"xf86PostButtonEvent",
"xf86PostMotionEvent",
"xf86PostProximityEvent",
"xf86ProcessCommonOptions",
"xf86ScaleAxis",
"xf86SetIntOption",
"xf86SetSerial",
"xf86SetStrOption",
"xf86XInputSetScreen",
"xf86XInputSetSendCoreEvents",
"xf86memset",
"xf86sscanf",
"xf86strcmp",
"xf86strlen",
"xf86strncmp",
"xf86strncpy",
NULL
};
static pointer
SetupProc( pointer module,
pointer options,
int *errmaj,
int *errmin )
{
xf86LoaderReqSymLists(reqSymbols, NULL);
xf86AddInputDriver(&MICROTOUCH, module, 0);
return (pointer) 1;
}
XF86ModuleData microtouchModuleData = {&VersionRec, &SetupProc, NULL };
#endif
static const char *default_options[] =
{
"BaudRate", "9600",
"StopBits", "1",
"DataBits", "8",
"Parity", "None",
"Vmin", "5",
"Vtime", "1",
"FlowControl", "None"
};
static const char *fallback_options[] =
{
"BaudRate", "9600",
"StopBits", "2",
"DataBits", "7",
"Parity", "None",
"Vmin", "1",
"Vtime", "1",
"FlowControl", "None"
};
static InputInfoPtr
MuTouchPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
LocalDevicePtr local;
MuTPrivatePtr priv;
char *s;
priv = xcalloc (1, sizeof (MuTPrivateRec));
if (!priv)
return NULL;
local = xf86AllocateInput(drv, 0);
if (!local) {
xfree(priv);
return NULL;
}
local->type_name = XI_TOUCHSCREEN;
local->device_control = DeviceControl;
local->read_input = ReadInput;
local->control_proc = ControlProc;
local->close_proc = CloseProc;
local->switch_mode = SwitchMode;
local->conversion_proc = ConvertProc;
local->dev = NULL;
local->private = priv;
local->private_flags = 0;
local->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
local->conf_idev = dev;
xf86CollectInputOptions(local, default_options, NULL);
xf86OptionListReport(local->options);
local->fd = xf86OpenSerial (local->options);
if (local->fd == -1)
{
ErrorF ("MicroTouch driver unable to open device\n");
goto SetupProc_fail;
}
xf86ErrorFVerb( 6, "tty port opened successfully\n" );
priv->min_x = xf86SetIntOption( local->options, "MinX", 0 );
priv->max_x = xf86SetIntOption( local->options, "MaxX", 1000 );
priv->min_y = xf86SetIntOption( local->options, "MinY", 0 );
priv->max_y = xf86SetIntOption( local->options, "MaxY", 1000 );
priv->screen_num = xf86SetIntOption( local->options, "ScreenNumber", 0 );
priv->button_number = xf86SetIntOption( local->options, "ButtonNumber", 1 );
s = xf86FindOptionValue (local->options, "ReportingMode");
if ((s) && (xf86NameCmp (s, "raw") == 0))
priv->reporting_mode = TS_Raw;
else
priv->reporting_mode = TS_Scaled;
priv->buffer = XisbNew (local->fd, 200);
priv->proximity = FALSE;
priv->button_down = FALSE;
DBG (9, XisbTrace (priv->buffer, 1));
MuTNewPacket (priv);
if (QueryHardware(local) != Success)
{
ErrorF ("Unable to query/initialize MicroTouch hardware.\n");
goto SetupProc_fail;
}
local->history_size = xf86SetIntOption( local->options, "HistorySize", 0 );
MuTNewPacket (priv);
local->name = xf86SetStrOption( local->options, "DeviceName", "MicroTouch TouchScreen" );
xf86ProcessCommonOptions(local, local->options);
local->flags |= XI86_CONFIGURED;
if (local->fd != -1)
{
RemoveEnabledDevice (local->fd);
if (priv->buffer)
{
XisbFree(priv->buffer);
priv->buffer = NULL;
}
xf86CloseSerial(local->fd);
}
RemoveEnabledDevice (local->fd);
local->fd = -1;
return (local);
SetupProc_fail:
if ((local) && (local->fd))
xf86CloseSerial (local->fd);
if ((local) && (local->name))
xfree (local->name);
if ((priv) && (priv->buffer))
XisbFree (priv->buffer);
if (priv)
xfree (priv);
return (local);
}
static Bool
DeviceControl (DeviceIntPtr dev,
int mode)
{
Bool RetValue;
switch (mode)
{
case DEVICE_INIT:
DeviceInit (dev);
RetValue = Success;
break;
case DEVICE_ON:
RetValue = DeviceOn( dev );
break;
case DEVICE_OFF:
case DEVICE_CLOSE:
RetValue = DeviceOff( dev );
break;
default:
RetValue = BadValue;
}
return( RetValue );
}
static Bool
DeviceOn (DeviceIntPtr dev)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
MuTPrivatePtr priv = (MuTPrivatePtr) (local->private);
local->fd = xf86OpenSerial(local->options);
if (local->fd == -1)
{
xf86Msg(X_WARNING, "%s: cannot open input device\n", local->name);
return (!Success);
}
priv->buffer = XisbNew(local->fd, 64);
if (!priv->buffer)
{
xf86CloseSerial(local->fd);
local->fd = -1;
return (!Success);
}
xf86FlushInput(local->fd);
AddEnabledDevice (local->fd);
dev->public.on = TRUE;
return (Success);
}
static Bool
DeviceOff (DeviceIntPtr dev)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
MuTPrivatePtr priv = (MuTPrivatePtr) (local->private);
if (local->fd != -1)
{
RemoveEnabledDevice (local->fd);
if (priv->buffer)
{
XisbFree(priv->buffer);
priv->buffer = NULL;
}
xf86CloseSerial(local->fd);
}
RemoveEnabledDevice (local->fd);
dev->public.on = FALSE;
return (Success);
}
static Bool
DeviceInit (DeviceIntPtr dev)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
MuTPrivatePtr priv = (MuTPrivatePtr) (local->private);
unsigned char map[] =
{0, 1};
priv->screen_width = screenInfo.screens[priv->screen_num]->width;
priv->screen_height = screenInfo.screens[priv->screen_num]->height;
if (InitButtonClassDeviceStruct (dev, 1, map) == FALSE)
{
ErrorF ("Unable to allocate MicroTouch touchscreen ButtonClassDeviceStruct\n");
return !Success;
}
if (InitValuatorClassDeviceStruct (dev, 2, xf86GetMotionEvents,
local->history_size, Absolute) == FALSE)
{
ErrorF ("Unable to allocate MicroTouch touchscreen 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 (InitProximityClassDeviceStruct (dev) == FALSE)
{
ErrorF ("Unable to allocate MicroTouch touchscreen ProximityClassDeviceStruct\n");
return !Success;
}
xf86MotionHistoryAllocate (local);
return (Success);
}
#define WORD_ASSEMBLY(byte1, byte2) (((byte2) << 7) | (byte1))
static void
ReadInput (LocalDevicePtr local)
{
int x, y;
int type;
MuTPrivatePtr priv = (MuTPrivatePtr) (local->private);
XisbBlockDuration (priv->buffer, -1);
while (MuTGetPacket (priv) == Success)
{
type = priv->packet[0];
x = WORD_ASSEMBLY (priv->packet[1], priv->packet[2]);
y = WORD_ASSEMBLY (priv->packet[3], priv->packet[4]);
if (priv->reporting_mode == TS_Scaled)
{
x = xf86ScaleAxis (x, 0, priv->screen_width, priv->min_x,
priv->max_x);
y = xf86ScaleAxis (y, 0, priv->screen_height, priv->min_y,
priv->max_y);
}
xf86XInputSetScreen (local, priv->screen_num, x, y);
if ((priv->proximity == FALSE) && (type & MuT_CONTACT))
{
priv->proximity = TRUE;
xf86PostProximityEvent (local->dev, 1, 0, 2, x, y);
}
xf86PostMotionEvent (local->dev, TRUE, 0, 2, x, y);
if ((priv->button_down == FALSE) && (type & MuT_CONTACT))
{
xf86PostButtonEvent (local->dev, TRUE,
priv->button_number, 1, 0, 2, x, y);
priv->button_down = TRUE;
}
if ((priv->button_down == TRUE) && !(type & MuT_CONTACT))
{
xf86PostButtonEvent (local->dev, TRUE,
priv->button_number, 0, 0, 2, x, y);
priv->button_down = FALSE;
}
if ((priv->proximity == TRUE) && !(type & MuT_CONTACT))
{
priv->proximity = FALSE;
xf86PostProximityEvent (local->dev, 0, 0, 2, x, y);
}
xf86ErrorFVerb( 3, "TouchScreen: x(%d), y(%d), %d %d %s\n",
x, y, type, type & MuT_CONTACT,
(type & MuT_CONTACT) ? "Press" : "Release" );
}
}
static int
ControlProc (LocalDevicePtr local, xDeviceCtl * control)
{
xDeviceTSCalibrationCtl *c = (xDeviceTSCalibrationCtl *) control;
MuTPrivatePtr priv = (MuTPrivatePtr) (local->private);
priv->min_x = c->min_x;
priv->max_x = c->max_x;
priv->min_y = c->min_y;
priv->max_y = c->max_y;
return (Success);
}
static void
CloseProc (LocalDevicePtr local)
{
}
static int
SwitchMode (ClientPtr client, DeviceIntPtr dev, int mode)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
MuTPrivatePtr priv = (MuTPrivatePtr) (local->private);
if ((mode == TS_Raw) || (mode == TS_Scaled))
{
priv->reporting_mode = mode;
return (Success);
}
else if ((mode == SendCoreEvents) || (mode == DontSendCoreEvents))
{
xf86XInputSetSendCoreEvents (local, (mode == SendCoreEvents));
return (Success);
}
else
return (!Success);
}
static Bool
ConvertProc (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);
if (priv->reporting_mode == TS_Raw)
{
*x = xf86ScaleAxis (v0, 0, priv->screen_width, priv->min_x,
priv->max_x);
*y = xf86ScaleAxis (v1, 0, priv->screen_height, priv->min_y,
priv->max_y);
}
else
{
*x = v0;
*y = v1;
}
return (TRUE);
}
static Bool
xf86MuTSendCommand (unsigned char *type, MuTPrivatePtr priv)
{
int r;
int retries = MuT_RETRIES;
while (retries--)
{
if (xf86MuTSendPacket (type, strlen ( (char *)type), priv) != Success)
continue;
r = xf86MuTWaitReply ( (unsigned char *)MuT_OK, priv);
if (r == ACK)
return (TRUE);
else if (r == NACK)
return (FALSE);
}
return (FALSE);
}
static Bool
QueryHardware (LocalDevicePtr local)
{
MuTPrivatePtr priv = (MuTPrivatePtr) local->private;
pointer fallback;
Bool ret = Success;
int cs7 = FALSE;
fallback = xf86OptionListCreate (fallback_options,
(sizeof (fallback_options) / sizeof (fallback_options[0])), 0);
priv->cs7flag = TRUE;
if (!xf86MuTSendCommand ( (unsigned char *)MuT_RESET, priv))
{
xf86ErrorFVerb( 5,
"Switching Com Parameters to CS7, 2 stop bits, no parity\n" );
xf86SetSerial (priv->buffer->fd, fallback);
cs7 = TRUE;
if (!xf86MuTSendCommand ( (unsigned char *)MuT_RESET, priv))
{
ret = !Success;
goto done;
}
}
if (!xf86MuTSendCommand ( (unsigned char *)MuT_ABDISABLE, priv))
{
ret = !Success;
goto done;
}
if (!xf86MuTSendCommand ( (unsigned char *)MuT_SETRATE, priv))
{
ret = !Success;
goto done;
}
if (cs7)
{
xf86ErrorFVerb( 5,
"Switching Com Parameters back to CS8, 1 stop bit, no parity\n" );
xf86SetSerial (priv->buffer->fd, local->options);
}
priv->cs7flag = FALSE;
if (!xf86MuTSendCommand ( (unsigned char *)MuT_FORMAT_TABLET, priv))
{
ret = !Success;
goto done;
}
if (!xf86MuTSendCommand ( (unsigned char *)MuT_MODE_STREAM, priv))
{
ret = !Success;
goto done;
}
if (!xf86MuTSendCommand ( (unsigned char *)MuT_PARAM_LOCK, priv))
{
ret = !Success;
goto done;
}
if( 1 )
{
if (xf86MuTSendPacket ( (unsigned char *)MuT_OUTPUT_IDENT, strlen (MuT_OUTPUT_IDENT),
priv) == Success)
{
if (MuTGetPacket (priv) == Success)
xf86MuTPrintIdent (priv->packet);
}
if (xf86MuTSendPacket ( (unsigned char *)MuT_UNIT_VERIFY, strlen (MuT_UNIT_VERIFY),
priv) == Success)
{
if ((MuTGetPacket (priv) == Success) &&
(strcmp ( (char *)&(priv->packet[1]), MuT_ERROR) == 0))
{
if (xf86MuTSendPacket ( (unsigned char *)MuT_UNIT_TYPE,
strlen (MuT_UNIT_TYPE), priv) == Success)
{
if ((MuTGetPacket (priv) != Success))
{
ret = !Success;
goto done;
}
}
}
ret = xf86MuTPrintHwStatus (priv->packet);
}
}
done:
xf86OptionListFree (fallback);
return (ret);
}
static void
MuTNewPacket (MuTPrivatePtr priv)
{
priv->lex_mode = microtouch_normal;
priv->packeti = 0;
priv->binary_pkt = FALSE;
}
static Bool
xf86MuTSendPacket (unsigned char *type, int len, MuTPrivatePtr priv)
{
int result;
unsigned char req[MuT_PACKET_SIZE];
memset (req, 0, MuT_PACKET_SIZE);
strncpy ((char *) &req[1], (char *)type, strlen ( (char *)type));
req[0] = MuT_LEAD_BYTE;
req[len + 1] = MuT_TRAIL_BYTE;
result = XisbWrite (priv->buffer, req, len + 2);
if (result != len + 2)
{
xf86ErrorFVerb( 5, "System error while sending to MicroTouch touchscreen.\n" );
return !Success;
}
else
return Success;
}
static int
xf86MuTWaitReply (unsigned char *type, MuTPrivatePtr priv)
{
Bool ok;
int wrong, empty;
wrong = MuT_MAX_WRONG_PACKETS;
empty = MuT_MAX_EMPTY_PACKETS;
do
{
ok = !Success;
xf86ErrorFVerb( 4, "Waiting %d ms for data from port\n", MuT_MAX_WAIT / 1000 );
MuTNewPacket (priv);
XisbBlockDuration (priv->buffer, MuT_MAX_WAIT);
ok = MuTGetPacket (priv);
if (ok != Success)
{
xf86ErrorFVerb( 4, "Recieved empty packet.\n" );
empty--;
continue;
}
if (ok == Success)
{
if (priv->cs7flag && (priv->packet[1] == MuT_OK7) &&
(priv->packet[2] == '\0'))
{
xf86ErrorFVerb( 4, "Detected the 7 bit ACK in 8bit mode.\n" );
return (NACK);
}
if (strcmp ( (char *)&(priv->packet[1]), (char *)type) == 0)
{
xf86ErrorFVerb( 5, "\t\tgot an ACK\n" );
return (ACK);
}
else if (strcmp ( (char *)&(priv->packet[1]), MuT_ERROR) == 0)
{
xf86ErrorFVerb( 5, "\t\tgot a NACK\n" );
return (NACK);
}
else
{
xf86ErrorFVerb( 2, "Wrong reply received\n" );
ok = !Success;
wrong--;
}
}
}
while (ok != Success && wrong && empty);
if (wrong)
return (TIMEOUT);
else
return (WRONG_PACKET);
}
static Bool
MuTGetPacket (MuTPrivatePtr priv)
{
int count = 0;
int c;
while ((c = XisbRead (priv->buffer)) >= 0)
{
if (count++ > 100)
{
MuTNewPacket (priv);
return (!Success);
}
switch (priv->lex_mode)
{
case microtouch_normal:
if ((c == MuT_LEAD_BYTE) ||
(priv->cs7flag && ((c & 0x7f) == MuT_LEAD_BYTE)))
{
xf86ErrorFVerb( 8, "Saw MuT_LEAD_BYTE\n" );
priv->packet[priv->packeti++] = (unsigned char) c;
priv->lex_mode = microtouch_body;
}
if (c & 0x80)
{
xf86ErrorFVerb( 8, "Saw BINARY start\n" );
priv->packet[priv->packeti++] = (unsigned char) c;
priv->lex_mode = mtouch_binary;
priv->bin_byte = 0;
}
break;
case mtouch_binary:
priv->packet[priv->packeti++] = (unsigned char) c;
priv->bin_byte++;
if (priv->bin_byte == 4)
{
xf86ErrorFVerb( 8, "got a good BINARY packet\n" );
MuTNewPacket (priv);
priv->binary_pkt = TRUE;
return (Success);
}
break;
case microtouch_body:
if ((c == MuT_LEAD_BYTE) ||
(priv->cs7flag && ((c & 0x7f) == MuT_LEAD_BYTE)))
{
priv->packeti = 0;
}
if ((c == MuT_TRAIL_BYTE) ||
(priv->cs7flag && ((c & 0x7f) == MuT_TRAIL_BYTE)))
{
priv->packet[priv->packeti++] = '\0';
xf86ErrorFVerb( 8, "got a good packet\n" );
MuTNewPacket (priv);
return (Success);
}
else
priv->packet[priv->packeti++] = (unsigned char) c;
break;
}
}
return (!Success);
}
static void
xf86MuTPrintIdent (unsigned char *packet)
{
int vers, rev;
if (strlen ( (char *)packet) < 6)
return;
xf86Msg( X_PROBED, " MicroTouch touchscreen is " );
if (strncmp ((char *) &packet[1], MuT_TOUCH_PEN_IDENT, 2) == 0)
xf86ErrorF( "a TouchPen.\n" );
else if (strncmp ((char *) &packet[1], MuT_SMT3_IDENT, 2) == 0)
xf86ErrorF( "a Serial/SMT3.\n" );
else if (strncmp ((char *) &packet[1], MuT_GENERAL_IDENT, 2) == 0)
xf86ErrorF( "an SMT2, SMT3V or SMT3RV.\n" );
else
xf86ErrorF( "Unknown Type %c%c.\n", packet[1], packet[2] );
sscanf ((char *) &packet[3], "%2d%2d", &vers, &rev);
xf86Msg( X_PROBED, " MicroTouch controller firmware revision is %d.%d.\n", vers, rev);
}
static Bool
xf86MuTPrintHwStatus (unsigned char *packet)
{
int i;
int err;
for (i = 3; i < 7; i++)
{
if (packet[i] == 'R')
{
xf86Msg( X_PROBED,
" MicroTouch controller is a resistive type.\n" );
}
}
if (packet[7] == '1')
{
xf86Msg( X_PROBED,
" MicroTouch controller reports the following errors:\n" );
err = packet[8];
if (err & 0x01)
xf86ErrorF( "\tReserved\n" );
if (err & 0x02)
xf86ErrorF( "\tROM error. Firmware checksum verification error.\n" );
if (err & 0x04)
xf86ErrorF( "\tPWM error. Unable to establish PWM operating range at power-up.\n" );
if (err & 0x08)
xf86ErrorF( "\tNOVRAM error. The operating parameters in the controller NOVRAM are invalid.\n" );
if (err & 0x10)
xf86ErrorF( "\tHWD error. The controller hardware failed.\n" );
if (err & 0x20)
xf86ErrorF( "\tReserved\n" );
if (err & 0x40)
xf86ErrorF( "\tCable NOVRAM error. The linearization data in the cable NOVRAM is invalid.\n" );
if (err & 0x80)
xf86ErrorF( "\tNOVRAM2 error. The linearization data in the controller NOVRAM is invalid.\n" );
return (!Success);
}
return (Success);
}