[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