#define _CALCOMP_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 "xf86Calcomp.h"
#define DEBUG 1
InputDriverRec CALCOMP = {
1,
"calcomp",
NULL,
CalcompPreInit,
NULL,
NULL,
0
};
static const char *default_options[] =
{
"Device", "/dev/ttyS1",
"BaudRate", "9600",
"StopBits", "1",
"DataBits", "8",
"Parity", "None",
"Vmin", "1",
"Vtime", "1",
"FlowControl", "None"
};
#ifdef XFree86LOADER
static XF86ModuleVersionInfo VersionRec =
{
"calcomp",
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",
"InitPtrFeedbackClassDeviceStruct",
"RemoveEnabledDevice",
"Xcalloc",
"Xfree",
"XisbBlockDuration",
"XisbFree",
"XisbNew",
"XisbRead",
"XisbTrace",
"screenInfo",
"xf86AddInputDriver",
"xf86AllocateInput",
"xf86CloseSerial",
"xf86CollectInputOptions",
"xf86ErrorFVerb",
"xf86FindOptionValue",
"xf86GetMotionEvents",
"xf86GetVerbosity",
"xf86MotionHistoryAllocate",
"xf86NameCmp",
"xf86OpenSerial",
"xf86OptionListCreate",
"xf86OptionListMerge",
"xf86OptionListReport",
"xf86PostButtonEvent",
"xf86PostMotionEvent",
"xf86PostProximityEvent",
"xf86ProcessCommonOptions",
"xf86ScaleAxis",
"xf86SetIntOption",
"xf86SetStrOption",
"xf86XInputSetScreen",
"xf86XInputSetSendCoreEvents",
NULL
};
static pointer
CalcompSetupProc( pointer module,
pointer options,
int *errmaj,
int *errmin )
{
xf86LoaderReqSymLists(reqSymbols, NULL);
xf86AddInputDriver(&CALCOMP, module, 0);
return (pointer) 1;
}
XF86ModuleData calcompModuleData = { &VersionRec, CalcompSetupProc, NULL };
#endif
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:
RetValue = DeviceOff( dev );
break;
case DEVICE_CLOSE:
RetValue = DeviceClose( dev );
break;
default:
ErrorF ("\tBAD MODE\n");
RetValue = BadValue;
}
return( RetValue );
}
static Bool
DeviceOn (DeviceIntPtr dev)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
AddEnabledDevice (local->fd);
dev->public.on = TRUE;
return (Success);
}
static Bool
DeviceOff (DeviceIntPtr dev)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
RemoveEnabledDevice (local->fd);
dev->public.on = FALSE;
return (Success);
}
static Bool
DeviceClose (DeviceIntPtr dev)
{
return (Success);
}
static Bool
DeviceInit (DeviceIntPtr dev)
{
LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
CALCOMPPrivatePtr priv = (CALCOMPPrivatePtr) (local->private);
unsigned char map[] =
{0, 1};
if (InitButtonClassDeviceStruct (dev, 1, map) == FALSE)
{
ErrorF ("Unable to allocate CALCOMP ButtonClassDeviceStruct\n");
return !Success;
}
if (InitFocusClassDeviceStruct (dev) == FALSE) {
ErrorF ("Unable to allocate CALCOMP focus class device\n");
return !Success;
}
if (InitValuatorClassDeviceStruct (dev, 3, xf86GetMotionEvents,
local->history_size, Absolute) == FALSE)
{
ErrorF ("Unable to allocate CALCOMP ValuatorClassDeviceStruct\n");
return !Success;
}
else
{
InitValuatorAxisStruct (dev, 0, priv->min_x, priv->max_x,
39400,
0 ,
12000 );
InitValuatorAxisStruct (dev, 1, priv->min_y, priv->max_y,
39400,
0 ,
39400 );
InitValuatorAxisStruct (dev, 2, priv->min_z, priv->max_z,
32,
0 ,
32 );
}
if (InitProximityClassDeviceStruct (dev) == FALSE)
{
ErrorF ("unable to allocate CALCOMP ProximityClassDeviceStruct\n");
return !Success;
}
if (InitPtrFeedbackClassDeviceStruct(dev,
ControlProc) == FALSE) {
ErrorF("unable to init ptr feedback\n");
return !Success;
}
xf86MotionHistoryAllocate (local);
return (Success);
}
static void
ReadInput (LocalDevicePtr local)
{
int x=0, y=0 , z=0;
int prox,buttons;
Bool is_absolute = TRUE;
CALCOMPPrivatePtr priv = (CALCOMPPrivatePtr) (local->private);
XisbBlockDuration (priv->buffer, -1);
while (CALCOMPGetPacket (priv) == Success)
{
x = priv->packet[2] + priv->packet[1] * 128
+(priv->packet[0] & 0x03) *128*128;
y = priv->packet[5] + priv->packet[4]*128 +priv->packet[3]*128*128;
y = priv->max_y -y;
prox = ((int)priv->packet[3] & PROXIMITY_BIT)? 0: 1;
buttons = (((int)priv->packet[0] & BUTTON_BITS) >>2);
if (buttons && ! priv->pressure ) {
if (buttons >15) {
buttons = buttons -15;
}else{
buttons = buttons /2;
if (buttons <4 ) buttons = buttons +1;
}
}else{
z = buttons;
if (z >= priv->button_threshold) buttons = 1;
#if 0
xf86Msg(X_INFO,"Tablett pressurebutton = %d >= %d\n",z,priv->button_threshold);
#endif
}
#if 0
xf86Msg(X_INFO,"Tablett x y prox buttons = %d %d %d %d\n",x,y,prox,buttons);
#endif
if (prox) {
if (!(priv->prox)) {
xf86PostProximityEvent(local->dev, 1, 0, 2, x, y);
}
if ((is_absolute && ((priv->x != x) || (priv->y != y)))
|| (!is_absolute && (x || y))) {
priv->x = x;
priv->y = y;
if (is_absolute || priv->prox) {
xf86PostMotionEvent(local->dev, is_absolute, 0, 3, x, y, z);
}
}
if (priv->buttons != buttons) {
int delta;
int button;
delta = buttons - priv->buttons;
button = (delta > 0)? delta: ((delta == 0)? priv->buttons : -delta);
if (priv->buttons != buttons) {
xf86PostButtonEvent(local->dev, is_absolute, button,
(delta > 0), 0, 2, x, y);
}
}
priv->buttons = buttons;
priv->x = x;
priv->y = y;
priv->prox = prox;
} else {
if (priv->prox) xf86PostProximityEvent(local->dev, 0, 0, 2, x, y);
priv->prox = 0;
}
}
}
static void
ControlProc (DeviceIntPtr device, PtrCtrl * control)
{
}
static int
ChangeControlProc(LocalDevicePtr local, xDeviceCtl *control)
{
return(Success);
}
static void
CloseProc (LocalDevicePtr local)
{
}
static int
SwitchMode (ClientPtr client, DeviceIntPtr dev, int mode)
{
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)
{
CALCOMPPrivatePtr priv=(CALCOMPPrivatePtr) local->private;
double factorX,factorY;
xf86Msg(X_INFO,"Calcomp ConvertProc called\n");
if (first !=0 || num == 1) return FALSE;
factorX= ((double) priv->screen_width)
/(priv->max_x - priv->min_x);
factorY= ((double) priv->screen_height)
/(priv->max_y - priv->min_y);
*x = v0*factorX;
*y = v1*factorY;
return (Success);
}
static Bool
QueryHardware (int fd, CALCOMPPrivatePtr priv)
{
char buffer[255];
int err;
SYSCALL(err = write(fd, DB_COMM_SETUP, strlen(DB_COMM_SETUP)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
SYSCALL(err = write(fd, DB_UPPER_ORIGIN, strlen(DB_UPPER_ORIGIN)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
SYSCALL(err = write(fd, DB_BINARY_FMT, strlen(DB_BINARY_FMT)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
SYSCALL(err = write(fd, DB_XINCREMENT, strlen(DB_XINCREMENT)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
SYSCALL(err = write(fd, DB_YINCREMENT, strlen(DB_YINCREMENT)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
SYSCALL(err = write(fd, DB_1000LPI, strlen(DB_1000LPI)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
SYSCALL(err = write(fd, DB_STREAM_MODE, strlen(DB_STREAM_MODE)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
if (priv->pressure)
SYSCALL(err = write(fd, DB_PRESSURE_ON, strlen(DB_PRESSURE_ON)));
else
SYSCALL(err = write(fd, DB_PRESSURE_OFF, strlen(DB_PRESSURE_OFF)));
if (err<0) return !Success;
xf86WaitForInput(-1,500);
if (!xf86CalWriteAndRead(fd, DB_FIRMID, buffer, 35, 1))
return !Success;
xf86Msg(X_INFO,"Calcomp firmware ID : %s\n", buffer);
memset(buffer,32,35);
xf86WaitForInput(-1,500);
if (!xf86CalWriteAndRead(fd, DB_PRODID, buffer, 20, 1))
return !Success;
xf86Msg(X_INFO,"Product ID : %s\n", buffer);
memset(buffer,32,20);
xf86WaitForInput(-1,500);
if (!xf86CalWriteAndRead(fd, DB_CONFIG, buffer, 6, 1))
return !Success;
priv->max_x = (int)buffer[2] + ((int)buffer[1] << 7)
+ (((int)buffer[0]&0x03)<<14);
priv->max_y = (int)buffer[5] + ((int)buffer[4] << 7);
xf86Msg(X_INFO,"Tablet size : %d x %d \n", priv->max_x,priv->max_y);
xf86WaitForInput(-1,500);
SYSCALL(err = write(fd, DB_ABSOLUTE, strlen(DB_ABSOLUTE)));
if (err<0) return !Success;
return (Success);
}
static InputInfoPtr
CalcompPreInit( InputDriverPtr drv,
IDevPtr dev, int flags)
{
InputInfoPtr local;
CALCOMPPrivatePtr priv = xcalloc (1, sizeof (CALCOMPPrivateRec));
char *s;
if (!(local = xf86AllocateInput(drv, 0)))
return NULL;
xf86Msg (X_INFO,"Calcomp SetupProc called\n");
if ((!local) || (!priv))
goto SetupProc_fail;
local->conf_idev = dev;
xf86CollectInputOptions(local, default_options, NULL);
xf86OptionListReport( local->options );
local->fd = xf86OpenSerial (local->options);
if (local->fd == -1)
{
xf86Msg (X_ERROR,"CALCOMP driver unable to open device\n");
goto SetupProc_fail;
} else {
xf86Msg( X_INFO,"CALCOMP driver: Serial device opened\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->min_z = xf86SetIntOption( local->options, "MinZ", 0 );
priv->max_z = xf86SetIntOption( local->options, "MaxZ", 32 );
priv->button_threshold = xf86SetIntOption (local->options, "ButtonThreshold", 16 );
priv->pressure = xf86SetIntOption (local->options, "Pressure", 0);
priv->untouch_delay = xf86SetIntOption( local->options, "UntouchDelay", 10 );
priv->report_delay = xf86SetIntOption( local->options, "ReportDelay", 40 );
priv->screen_num = xf86SetIntOption( local->options, "ScreenNumber", 0 );
priv->button_number = xf86SetIntOption( local->options, "ButtonNumber", 1 );
xf86Msg(X_INFO,"options read MaxX=%d, MaxY=%d\n",priv->max_x,priv->max_y);
s = xf86FindOptionValue (local->options, "ReportingMode");
if ((s) && (xf86NameCmp (s, "raw") == 0))
priv->reporting_mode = TS_Raw;
else
priv->reporting_mode = TS_Scaled;
priv->checksum = 0;
priv->buffer = XisbNew (local->fd, 200);
DBG (9, XisbTrace (priv->buffer, 1));
if (QueryHardware (local->fd, priv) != Success)
{
xf86Msg (X_ERROR,"Unable to query/initialize CALCOMP hardware.\n");
goto SetupProc_fail;
}else
xf86Msg (X_INFO,"Calcomp tablet queried OK\n");
local->name = xf86SetStrOption( local->options, "DeviceName", "CALCOMP XInput Device");
xf86Msg(X_CONFIG," Calcomp device name is %s\n",local->name);
local->type_name = XI_TABLET;
local->device_control = DeviceControl;
local->read_input = ReadInput;
local->control_proc = ChangeControlProc;
local->close_proc = CloseProc;
local->switch_mode = SwitchMode;
local->conversion_proc = ConvertProc;
local->dev = NULL;
local->private = priv;
local->private_flags = 0;
local->conf_idev = dev;
local->history_size = xf86SetIntOption( local->options, "HistorySize", 0 );
local->flags |= XI86_CONFIGURED;
xf86Msg(X_INFO,"Calcomp base setup finished\n");
return (local);
SetupProc_fail:
xf86Msg (X_ERROR,"Calcomp setup failed, unloading tablet driver\n");
xfree (priv);
xf86DeleteInput(local, 0);
return (NULL);
}
static Bool
CALCOMPGetPacket (CALCOMPPrivatePtr priv)
{
int count = 0;
int c;
while ((c = XisbRead (priv->buffer)) >= 0)
{
if (count++ > 500)
return (!Success);
if (c > 127)
{
priv->packeti=0;
priv->packet[priv->packeti++] = (unsigned char) c;
}
else {
if (priv->packeti >0 && priv->packeti < CALCOMP_BODY_LEN)
priv->packet[priv->packeti++] = (unsigned char) c;
if (priv->packeti == CALCOMP_BODY_LEN)
{
priv->packeti=0;
return (Success);
}
}
}
return (!Success);
}
static char *
xf86CalWriteAndRead(int fd, char *data, char *buffer, int len, int cr_term)
{
int err, numread = 0;
int retries = 5;
xf86FlushInput(fd);
SYSCALL(err = write(fd, data, strlen(data)));
if (err == -1) {
xf86Msg(X_ERROR,"Calcomp write");
return NULL;
}
do {
err=xf86WaitForInput(fd, 2000);
if (err < 0 ) {
xf86Msg(X_ERROR,"Calcomp select failed\n");
return NULL;
}
retries--;
}
while (err<1 && retries >0);
if (retries<=0) {
xf86Msg(X_WARNING,"Timeout while reading Calcomp tablet. No tablet connected ???\n");
return NULL;
}
while (numread < len) {
if (err == -1) {
xf86Msg(X_ERROR,"Calcomp select");
return NULL;
}
SYSCALL(err = read(fd, buffer + numread++, 1));
if (err == -1) {
xf86Msg(X_ERROR,"Calcomp read");
return NULL;
}
if (!err) {
--numread;
break;
}
if (cr_term && buffer[numread - 1] == '\r') {
buffer[numread - 1] = 0;
break;
}
}
buffer[numread] = 0;
return buffer;
}