[PATCH Xorg hw/xfree86/input/penmount 1/1] DMC9000 input driver
jayakumar.xorg at gmail.com
jayakumar.xorg at gmail.com
Fri Sep 16 21:40:39 PDT 2005
Hi David, Mayk, xorg folk,
Appended is my patch adding support for the DMC9000 touch controller to
the penmount driver. I tried to keep to the same style as the original
driver and minimize the changes to the 8910+etc code. Please let me
know if it looks okay and if you have any feedback or suggestions.
Thanks,
Jaya Kumar
Signed-off-by: Jaya Kumar <jayakumar.xorg at gmail.com>
---
xf86PM.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
xf86PM.h | 4
2 files changed, 331 insertions(+), 68 deletions(-)
diff -uprN penmount.orig/xf86PM.c penmount/xf86PM.c
--- penmount.orig/xf86PM.c 2005-09-17 12:23:44.885689232 +0800
+++ penmount/xf86PM.c 2005-09-17 12:17:05.744367936 +0800
@@ -2,6 +2,12 @@
* Copyright (c) 1999 Machine Vision Holdings Incorporated
* Author: David Woodhouse <David.Woodhouse at mvhi.com>
* CoAuthor: Mayk Langer <langer at vsys.de>
+ *
+ * History:
+ * 09/16/2005: Jaya Kumar <jayakumar.xorg at gmail.com>
+ * - Added DMC9000 controller protocol support
+ * - DMC9000 support work was sponsored by CIS(M) Sdn Bhd
+ * 09/15/2005: Original code from David and Mayk
*
* Template driver used: Copyright (c) 1998 Metro Link Incorporated
*
@@ -156,7 +162,155 @@ static const char *default_options[] =
* Function Definitions
****************************************************************************/
+static Bool
+ProcessDeviceInit(PenMountPrivatePtr priv, DeviceIntPtr dev, InputInfoPtr pInfo)
+{
+ unsigned char map[] =
+ {0, 1};
+ /*
+ * these have to be here instead of in the SetupProc, because when the
+ * SetupProc is run at server startup, screenInfo is not setup yet
+ */
+ priv->screen_width = screenInfo.screens[priv->screen_num]->width;
+ priv->screen_height = screenInfo.screens[priv->screen_num]->height;
+
+ /*
+ * Device reports button press for 1 button.
+ */
+ if (InitButtonClassDeviceStruct (dev, 1, map) == FALSE)
+ {
+ ErrorF ("Unable to allocate PenMount ButtonClassDeviceStruct\n");
+ return !Success;
+ }
+
+ /*
+ * Device reports motions on 2 axes in absolute coordinates.
+ * Axes min and max values are reported in raw coordinates.
+ */
+ if (InitValuatorClassDeviceStruct (dev, 2, xf86GetMotionEvents,
+ pInfo->history_size, Absolute) == FALSE)
+ {
+ ErrorF ("Unable to allocate PenMount ValuatorClassDeviceStruct\n");
+ return !Success;
+ }
+ else
+ {
+ InitValuatorAxisStruct (dev, 0, priv->min_x, priv->max_x,
+ 9500,
+ 0 /* min_res */ ,
+ 9500 /* max_res */ );
+ InitValuatorAxisStruct (dev, 1, priv->min_y, priv->max_y,
+ 10500,
+ 0 /* min_res */ ,
+ 10500 /* max_res */ );
+ }
+
+ if (InitProximityClassDeviceStruct (dev) == FALSE)
+ {
+ ErrorF ("unable to allocate PenMount ProximityClassDeviceStruct\n");
+ return !Success;
+ }
+
+ if (InitPtrFeedbackClassDeviceStruct(dev, PenMountPtrCtrl) == FALSE)
+ {
+ ErrorF ("unable to allocate PenMount PtrFeedbackClassDeviceStruct\n");
+ return !Success;
+ }
+
+ /*
+ * Allocate the motion events buffer.
+ */
+ xf86MotionHistoryAllocate (pInfo);
+ return (Success);
+}
+
+static Bool
+DMC9000_ProcessDeviceOn(PenMountPrivatePtr priv, DeviceIntPtr dev, InputInfoPtr pInfo)
+{
+ unsigned char buf[5] = { 0xF2, 0x00, 0x00, 0x00, 0x00 };
+ pInfo->fd = xf86OpenSerial(pInfo->options);
+ if (pInfo->fd == -1)
+ {
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
+ return (!Success);
+ }
+
+ priv->buffer = XisbNew(pInfo->fd, 64);
+ if (!priv->buffer)
+ {
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ return (!Success);
+ }
+
+ XisbBlockDuration (priv->buffer, 500000);
+ if ( PenMountSendPacket(priv, buf, 5) == Success )
+ {
+ /* wait for right response */
+ priv->lex_mode = PenMount_Response0;
+ if (DMC9000_PenMountGetPacket (priv) == Success )
+ {
+ if ((priv->packet[0] == 0xF2) &&
+ (priv->packet[1] == 0xD9) &&
+ (priv->packet[2] == 0x0A))
+ {
+ /* enable the DMC9000 */
+ buf[0] = 0xF1;
+ buf[1] = 0x00;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+ buf[4] = 0x00;
+ PenMountSendPacket(priv,buf,5);
+ }
+ }
+ }
+
+ XisbBlockDuration (priv->buffer, -1);
+ priv->lex_mode = PenMount_byte0;
+
+ xf86FlushInput(pInfo->fd);
+ AddEnabledDevice (pInfo->fd);
+ dev->public.on = TRUE;
+ return (Success);
+}
+
+static Bool
+ProcessDeviceClose(PenMountPrivatePtr priv, DeviceIntPtr dev, InputInfoPtr pInfo)
+{
+ if (pInfo->fd != -1)
+ {
+ RemoveEnabledDevice (pInfo->fd);
+ if (priv->buffer)
+ {
+ XisbFree(priv->buffer);
+ priv->buffer = NULL;
+ }
+ xf86CloseSerial(pInfo->fd);
+ }
+ dev->public.on = FALSE;
+ return (Success);
+}
+
+static Bool
+DMC9000_DeviceControl (DeviceIntPtr dev, int mode)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ PenMountPrivatePtr priv = (PenMountPrivatePtr) (pInfo->private);
+
+ switch (mode)
+ {
+ case DEVICE_INIT:
+ return ProcessDeviceInit(priv, dev, pInfo);
+ case DEVICE_ON:
+ return DMC9000_ProcessDeviceOn(priv, dev, pInfo);
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ return ProcessDeviceClose(priv, dev, pInfo);
+ default:
+ return (BadValue);
+ }
+}
static InputInfoPtr
PenMountPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
@@ -222,6 +376,7 @@ PenMountPreInit(InputDriverPtr drv, IDev
priv->screen_num = xf86SetIntOption( pInfo->options, "ScreenNumber", 0 );
priv->button_number = xf86SetIntOption( pInfo->options, "ButtonNumber", 1 );
priv->swap_xy = xf86SetIntOption( pInfo->options, "SwapXY", 0 );
+ priv->invert_y = xf86SetIntOption( pInfo->options, "InvertY", 1 );
priv->buffer = NULL;
s = xf86FindOptionValue (pInfo->options, "ReportingMode");
if ((s) && (xf86NameCmp (s, "raw") == 0))
@@ -229,6 +384,13 @@ PenMountPreInit(InputDriverPtr drv, IDev
else
priv->reporting_mode = TS_Scaled;
+ s = xf86FindOptionValue (pInfo->options, "ControllerModel");
+ if ((s) && (xf86NameCmp (s, "DMC9000") == 0)) {
+ priv->chip = DMC9000;
+ pInfo->device_control = DMC9000_DeviceControl;
+ pInfo->read_input = DMC9000_ReadInput;
+ }
+
priv->proximity = FALSE;
priv->button_down = FALSE;
priv->lex_mode = PenMount_byte0;
@@ -270,62 +432,7 @@ DeviceControl (DeviceIntPtr dev, int mod
switch (mode)
{
case DEVICE_INIT:
- /*
- * these have to be here instead of in the SetupProc, because when the
- * SetupProc is run at server startup, screenInfo is not setup yet
- */
- priv->screen_width = screenInfo.screens[priv->screen_num]->width;
- priv->screen_height = screenInfo.screens[priv->screen_num]->height;
-
- /*
- * Device reports button press for 1 button.
- */
- if (InitButtonClassDeviceStruct (dev, 1, map) == FALSE)
- {
- ErrorF ("Unable to allocate PenMount ButtonClassDeviceStruct\n");
- return !Success;
- }
-
- /*
- * Device reports motions on 2 axes in absolute coordinates.
- * Axes min and max values are reported in raw coordinates.
- */
- if (InitValuatorClassDeviceStruct (dev, 2, xf86GetMotionEvents,
- pInfo->history_size, Absolute) == FALSE)
- {
- ErrorF ("Unable to allocate PenMount ValuatorClassDeviceStruct\n");
- return !Success;
- }
- else
- {
- InitValuatorAxisStruct (dev, 0, priv->min_x, priv->max_x,
- 9500,
- 0 /* min_res */ ,
- 9500 /* max_res */ );
- InitValuatorAxisStruct (dev, 1, priv->min_y, priv->max_y,
- 10500,
- 0 /* min_res */ ,
- 10500 /* max_res */ );
- }
-
- if (InitProximityClassDeviceStruct (dev) == FALSE)
- {
- ErrorF ("unable to allocate PenMount ProximityClassDeviceStruct\n");
- return !Success;
- }
-
- if (InitPtrFeedbackClassDeviceStruct(dev, PenMountPtrCtrl) == FALSE)
- {
- ErrorF ("unable to allocate PenMount PtrFeedbackClassDeviceStruct\n");
- return !Success;
- }
-
- /*
- * Allocate the motion events buffer.
- */
- xf86MotionHistoryAllocate (pInfo);
- return (Success);
-
+ return ProcessDeviceInit(priv, dev, pInfo);
case DEVICE_ON:
pInfo->fd = xf86OpenSerial(pInfo->options);
if (pInfo->fd == -1)
@@ -403,18 +510,7 @@ DeviceControl (DeviceIntPtr dev, int mod
case DEVICE_OFF:
case DEVICE_CLOSE:
- if (pInfo->fd != -1)
- {
- RemoveEnabledDevice (pInfo->fd);
- if (priv->buffer)
- {
- XisbFree(priv->buffer);
- priv->buffer = NULL;
- }
- xf86CloseSerial(pInfo->fd);
- }
- dev->public.on = FALSE;
- return (Success);
+ return ProcessDeviceClose(priv, dev, pInfo);
default:
return (BadValue);
}
@@ -546,6 +642,103 @@ ReadInput (InputInfoPtr pInfo)
}
}
+static void
+DMC9000_ReadInput (InputInfoPtr pInfo)
+{
+ PenMountPrivatePtr priv = (PenMountPrivatePtr) (pInfo->private);
+ int x,y;
+ unsigned char opck[ PENMOUNT_PACKET_SIZE ];
+
+ /*
+ * set blocking to -1 on the first call because we know there is data to
+ * read. Xisb automatically clears it after one successful read so that
+ * succeeding reads are preceeded buy a select with a 0 timeout to prevent
+ * read from blocking indefinately.
+ */
+ XisbBlockDuration (priv->buffer, -1);
+ while (1)
+ {
+ unsigned int tmp;
+ memcpy(opck,priv->packet,5);
+ if ( DMC9000_PenMountGetPacket (priv) != Success )
+ break;
+ if ( priv->packet[0] == 0xff )
+ {
+ priv->pen_down = 1;
+ }
+ if ( priv->packet[0] == 0xbf )
+ {
+ priv->pen_down = 0;
+ }
+ x = ((((unsigned int) (priv->packet[1]&0x07)) << 7) | (priv->packet[2]&0x7F));
+ y = ((((unsigned int) (priv->packet[3]&0x07)) << 7) | (priv->packet[4]&0x7F));
+ if (priv->invert_y)
+ {
+ y = priv->max_y - y;
+ }
+ if ( priv->swap_xy)
+ {
+ tmp = y;
+ y = x;
+ x = tmp;
+ }
+ priv->packet[0] = priv->pen_down ? 0x01 : 0x00;
+
+ 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 (pInfo, priv->screen_num, x, y);
+
+ if ((priv->proximity == FALSE) && (priv->packet[0] & 0x01))
+ {
+ priv->proximity = TRUE;
+ xf86PostProximityEvent (pInfo->dev, 1, 0, 2, x, y);
+ }
+
+ /*
+ * Send events.
+ *
+ * We *must* generate a motion before a button change if pointer
+ * location has changed as DIX assumes this. This is why we always
+ * emit a motion, regardless of the kind of packet processed.
+ */
+
+ xf86PostMotionEvent (pInfo->dev, TRUE, 0, 2, x, y);
+
+ /*
+ * Emit a button press or release.
+ */
+ if ((priv->button_down == FALSE) && (priv->packet[0] & 0x01))
+
+ {
+ xf86PostButtonEvent (pInfo->dev, TRUE,
+ priv->button_number, 1, 0, 2, x, y);
+ priv->button_down = TRUE;
+ }
+ if ((priv->button_down == TRUE) && !(priv->packet[0] & 0x01))
+ {
+ xf86PostButtonEvent (pInfo->dev, TRUE,
+ priv->button_number, 0, 0, 2, x, y);
+ priv->button_down = FALSE;
+ }
+ /*
+ * the untouch should always come after the button release
+ */
+ if ((priv->proximity == TRUE) && !(priv->packet[0] & 0x01))
+ {
+ priv->proximity = FALSE;
+ xf86PostProximityEvent (pInfo->dev, 0, 0, 2, x, y);
+ }
+ }
+}
+
+
/*
* The ControlProc function may need to be tailored for your device
*/
@@ -730,6 +923,72 @@ PenMountGetPacket (PenMountPrivatePtr pr
}
static Bool
+DMC9000_PenMountGetPacket (PenMountPrivatePtr priv)
+{
+ int count = 0;
+ int c;
+
+ while ((c = XisbRead (priv->buffer)) >= 0)
+ {
+ /*
+ * fail after 500 bytes so the server doesn't hang forever if a
+ * device sends bad data.
+ */
+ if (count++ > 500)
+ return (!Success);
+
+ switch (priv->lex_mode)
+ {
+ case PenMount_byte0:
+ if (( c != 0xff ) && ( c != 0xbf))
+ return (!Success);
+ priv->packet[0] = (unsigned char) c;
+ priv->lex_mode = PenMount_byte1;
+ break;
+
+ case PenMount_byte1:
+ priv->packet[1] = (unsigned char) c;
+ priv->lex_mode = PenMount_byte2;
+ break;
+
+ case PenMount_byte2:
+ priv->packet[2] = (unsigned char) c;
+ priv->lex_mode = PenMount_byte3;
+ break;
+
+ case PenMount_byte3:
+ priv->packet[3] = (unsigned char) c;
+ priv->lex_mode = PenMount_byte4;
+ break;
+
+ case PenMount_byte4:
+ priv->packet[4] = (unsigned char) c;
+ priv->lex_mode = PenMount_byte0;
+ return (Success);
+ break;
+
+ case PenMount_Response0:
+ if ( c == 0xf2 )
+ priv->lex_mode = PenMount_Response1;
+ priv->packet[0] = (unsigned char) c;
+ break;
+
+ case PenMount_Response1:
+ priv->packet[1] = (unsigned char) c;
+ priv->lex_mode = PenMount_Response2;
+ break;
+ case PenMount_Response2:
+ priv->packet[2] = (unsigned char) c;
+ priv->lex_mode = PenMount_byte0;
+ return (Success);
+ break;
+ }
+ }
+ return (!Success);
+}
+
+
+static Bool
PenMountSendPacket (PenMountPrivatePtr priv, unsigned char *buf, int len)
{
int count = 0;
diff -uprN penmount.orig/xf86PM.h penmount/xf86PM.h
--- penmount.orig/xf86PM.h 2005-09-17 12:23:46.900382952 +0800
+++ penmount/xf86PM.h 2005-09-17 10:41:26.073930472 +0800
@@ -62,6 +62,7 @@ typedef struct _PenMountPrivateRec
int screen_height; /* Height of the screen */
int proximity;
int swap_xy;
+ int invert_y;
XISBuffer *buffer;
unsigned char packet[PENMOUNT_PACKET_SIZE]; /* packet being/just read */
PenMountState lex_mode;
@@ -72,6 +73,7 @@ PenMountPrivateRec, *PenMountPrivatePtr;
#define CHIP_UNKNOWN 0
#define DMC8910 1
+#define DMC9000 2
/******************************************************************************
@@ -80,12 +82,14 @@ PenMountPrivateRec, *PenMountPrivatePtr;
static Bool DeviceControl (DeviceIntPtr, int);
static void ReadInput (InputInfoPtr);
+static void DMC9000_ReadInput (InputInfoPtr);
static int ControlProc (InputInfoPtr, xDeviceCtl *);
static void CloseProc (InputInfoPtr);
static int SwitchMode (ClientPtr, DeviceIntPtr, int);
static Bool ConvertProc (InputInfoPtr, int, int, int, int, int, int, int, int, int *, int *);
static Bool QueryHardware (PenMountPrivatePtr);
static Bool PenMountGetPacket (PenMountPrivatePtr priv);
+static Bool DMC9000_PenMountGetPacket (PenMountPrivatePtr priv);
static Bool PenMountSendPacket (PenMountPrivatePtr priv, unsigned char *buf, int len );
static InputInfoPtr
More information about the xorg
mailing list