linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
       [not found] <m2smqhqk4k.fsf@p4.localdomain>
@ 2003-06-11 15:02 ` Vojtech Pavlik
  2003-06-11 18:16   ` Peter Osterlund
  2003-06-14 22:19 ` Vojtech Pavlik
  1 sibling, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-11 15:02 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin

On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:
> [ I'm resending this because the previous message never showed up on
> the list. Maybe it was too big. ]
> 
> Hi!
> 
> Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> based on the XFree86 driver. This driver operates the touchpad in
> absolute mode and emulates a three button mouse with two scroll
> wheels. Features include:
> 
> * Multi finger tapping.
> * Vertical and horizontal scrolling.
> * Edge scrolling during drag operations.
> * Palm detection.
> * Corner tapping.
> 
> The only major missing feature is runtime configuration of driver
> parameters. What is the best way to implement that?

sysfs, of course.

> I was thinking of
> sending EV_MSC events to the driver using the /dev/input/event*
> interface and define my own codes for the different driver parameters.

No, not that ... 

> The patch is available here:
> 
>         http://w1.894.telia.com/~u89404340/patches/synaptics_driver.patch
> 
> Comments?

IMO it should use ABS_ events and the relativization should be done in
the XFree86 driver. Other than that, it looks quite OK.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 15:02 ` [PATCH] Synaptics TouchPad driver for 2.5.70 Vojtech Pavlik
@ 2003-06-11 18:16   ` Peter Osterlund
  2003-06-11 18:26     ` Vojtech Pavlik
                       ` (2 more replies)
  0 siblings, 3 replies; 49+ messages in thread
From: Peter Osterlund @ 2003-06-11 18:16 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin

Vojtech Pavlik <vojtech@ucw.cz> writes:

> On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:
> > 
> > Here is a driver for the Synaptics TouchPad for 2.5.70.
...
> > The only major missing feature is runtime configuration of driver
> > parameters. What is the best way to implement that?
> 
> sysfs, of course.

Actually, the runtime configuration may not be needed at all if we do
the ABS -> REL conversion in user space, because all parameters
control different aspects of this conversion.

> > The patch is available here:
> > 
> >         http://w1.894.telia.com/~u89404340/patches/synaptics_driver.patch
> > 
> > Comments?
> 
> IMO it should use ABS_ events and the relativization should be done in
> the XFree86 driver. Other than that, it looks quite OK.

OK, the hardware state consists of 4 "axes" and 4 buttons, as defined
in the synaptics_hw_state struct:

        struct synaptics_hw_state {
        	int x;
        	int y;
        	int z;
        	int w;
        	int left;
        	int right;
        	int up;
        	int down;
        };

x and y are the finger position, z is the finger pressure and w
contains information about multifinger taps and finger width (for palm
detection.) Left, right, up and down contain the state of the
corresponding physical buttons.

Is this mapping reasonable?

        x     -> ABS_X
        y     -> ABS_Y
        z     -> ABS_PRESSURE
        w     -> ABS_MISC
        left  -> BTN_LEFT
        right -> BTN_RIGHT
        up    -> BTN_FORWARD
        down  -> BTN_BACK

The w value is somewhat special and not really a real axis. According
to the Synaptics TouchPad Interfacing Guide
(http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
follows:

Value		Needed capability	Interpretation
W = 0		capMultiFinger		Two fingers on the pad.
W = 1		capMultiFinger		Three or more fingers on the pad.
W = 2		capPen			Pen (instead of finger) on the pad.
W = 3		Reserved.
W = 4-7		capPalmDetect		Finger of normal width.
W = 8-14	capPalmDetect		Very wide finger or palm.
W = 15		capPalmDetect		Maximum reportable width; extremely
					wide contact.

Is there a better way than using ABS_MISC to pass the W information to
user space?

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 18:16   ` Peter Osterlund
@ 2003-06-11 18:26     ` Vojtech Pavlik
  2003-06-11 18:29     ` AlberT
  2003-06-11 18:34     ` Vojtech Pavlik
  2 siblings, 0 replies; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-11 18:26 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin

On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:

> Actually, the runtime configuration may not be needed at all if we do
> the ABS -> REL conversion in user space, because all parameters
> control different aspects of this conversion.

That'd be very nice.

> > > The patch is available here:
> > > 
> > >         http://w1.894.telia.com/~u89404340/patches/synaptics_driver.patch
> > > 
> > > Comments?
> > 
> > IMO it should use ABS_ events and the relativization should be done in
> > the XFree86 driver. Other than that, it looks quite OK.
> 
> OK, the hardware state consists of 4 "axes" and 4 buttons, as defined
> in the synaptics_hw_state struct:
> 
>         struct synaptics_hw_state {
>         	int x;
>         	int y;
>         	int z;
>         	int w;
>         	int left;
>         	int right;
>         	int up;
>         	int down;
>         };
> 
> x and y are the finger position, z is the finger pressure and w
> contains information about multifinger taps and finger width (for palm
> detection.) Left, right, up and down contain the state of the
> corresponding physical buttons.
> 
> Is this mapping reasonable?
> 
>         x     -> ABS_X
>         y     -> ABS_Y
>         z     -> ABS_PRESSURE
>         w     -> ABS_MISC
>         left  -> BTN_LEFT
>         right -> BTN_RIGHT
>         up    -> BTN_FORWARD
>         down  -> BTN_BACK

Yes, this is fine.

> The w value is somewhat special and not really a real axis. According
> to the Synaptics TouchPad Interfacing Guide
> (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> follows:
> 
> Value		Needed capability	Interpretation
> W = 0		capMultiFinger		Two fingers on the pad.
> W = 1		capMultiFinger		Three or more fingers on the pad.
> W = 2		capPen			Pen (instead of finger) on the pad.
> W = 3		Reserved.
> W = 4-7		capPalmDetect		Finger of normal width.
> W = 8-14	capPalmDetect		Very wide finger or palm.
> W = 15		capPalmDetect		Maximum reportable width; extremely
> 					wide contact.
> 
> Is there a better way than using ABS_MISC to pass the W information to
> user space?

I think ABS_MISC is perfectly okay for this.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 18:16   ` Peter Osterlund
  2003-06-11 18:26     ` Vojtech Pavlik
@ 2003-06-11 18:29     ` AlberT
  2003-06-11 18:34     ` Vojtech Pavlik
  2 siblings, 0 replies; 49+ messages in thread
From: AlberT @ 2003-06-11 18:29 UTC (permalink / raw)
  To: Peter Osterlund, Vojtech Pavlik
  Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin

On Wednesday 11 June 2003 20:16, Peter Osterlund wrote:

> The w value is somewhat special and not really a real axis. According
> to the Synaptics TouchPad Interfacing Guide
> (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> follows:
>
> Value		Needed capability	Interpretation
> W = 0		capMultiFinger		Two fingers on the pad.
> W = 1		capMultiFinger		Three or more fingers on the pad.
> W = 2		capPen			Pen (instead of finger) on the pad.
> W = 3		Reserved.
> W = 4-7		capPalmDetect		Finger of normal width.
> W = 8-14	capPalmDetect		Very wide finger or palm.
> W = 15		capPalmDetect		Maximum reportable width; extremely
> 					wide contact.
>
> Is there a better way than using ABS_MISC to pass the W information to
> user space?

may be W stays for Width ??  

ASB_WIDTH  would be something more significant !??

-- 
<?php echo '       Emiliano `AlberT` Gabrielli       '."\n".
           '  E-Mail: AlberT@SuperAlberT.it  '."\n".
           '  Web:    http://SuperAlberT.it  '."\n".
'  IRC:    #php,#AES azzurra.com '."\n".'ICQ: 158591185'; ?>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 18:16   ` Peter Osterlund
  2003-06-11 18:26     ` Vojtech Pavlik
  2003-06-11 18:29     ` AlberT
@ 2003-06-11 18:34     ` Vojtech Pavlik
  2003-06-11 21:23       ` Peter Osterlund
  2003-06-13 21:15       ` [PATCH] Synaptics TouchPad driver for 2.5.70 Peter Osterlund
  2 siblings, 2 replies; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-11 18:34 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin

On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:

> The w value is somewhat special and not really a real axis. According
> to the Synaptics TouchPad Interfacing Guide
> (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> follows:
> 
> Value		Needed capability	Interpretation
> W = 0		capMultiFinger		Two fingers on the pad.
> W = 1		capMultiFinger		Three or more fingers on the pad.
> W = 2		capPen			Pen (instead of finger) on the pad.
> W = 3		Reserved.
> W = 4-7		capPalmDetect		Finger of normal width.
> W = 8-14	capPalmDetect		Very wide finger or palm.
> W = 15		capPalmDetect		Maximum reportable width; extremely
> 					wide contact.
> 
> Is there a better way than using ABS_MISC to pass the W information to
> user space?

We should probably add an EV_MSC, MSC_GESTURE event type for this.
That'll be the cleanest solution.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 18:34     ` Vojtech Pavlik
@ 2003-06-11 21:23       ` Peter Osterlund
  2003-06-12  2:48         ` Joseph Fannin
                           ` (2 more replies)
  2003-06-13 21:15       ` [PATCH] Synaptics TouchPad driver for 2.5.70 Peter Osterlund
  1 sibling, 3 replies; 49+ messages in thread
From: Peter Osterlund @ 2003-06-11 21:23 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin

Vojtech Pavlik <vojtech@ucw.cz> writes:

> On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:
> 
> > The w value is somewhat special and not really a real axis. According
> > to the Synaptics TouchPad Interfacing Guide
> > (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> > follows:
> > 
> > Value		Needed capability	Interpretation
> > W = 0		capMultiFinger		Two fingers on the pad.
> > W = 1		capMultiFinger		Three or more fingers on the pad.
> > W = 2		capPen			Pen (instead of finger) on the pad.
> > W = 3		Reserved.
> > W = 4-7		capPalmDetect		Finger of normal width.
> > W = 8-14	capPalmDetect		Very wide finger or palm.
> > W = 15		capPalmDetect		Maximum reportable width; extremely
> > 					wide contact.
> > 
> > Is there a better way than using ABS_MISC to pass the W information to
> > user space?
> 
> We should probably add an EV_MSC, MSC_GESTURE event type for this.
> That'll be the cleanest solution.

Here is a new patch that sends ABS_ events to user space. I haven't
modified the XFree86 driver to handle this format yet, but I used
/dev/input/event* to verify that the driver generates correct data.


diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/Kconfig linux/drivers/input/mouse/Kconfig
--- ../../linus/main/linux/drivers/input/mouse/Kconfig	Sat Jun  7 21:40:38 2003
+++ linux/drivers/input/mouse/Kconfig	Wed Jun 11 22:56:41 2003
@@ -28,6 +28,19 @@
 	  The module will be called psmouse. If you want to compile it as a
 	  module, say M here and read <file:Documentation/modules.txt>.
 
+config MOUSE_PS2_SYNAPTICS
+	bool "Synaptics TouchPad"
+	default n
+	depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2
+	---help---
+	  Say Y here if you have a Synaptics TouchPad connected to your system.
+	  This touchpad is found on many modern laptop computers.
+	  Note that you also need a user space driver to interpret the data
+	  generated by the kernel. A compatible driver for XFree86 is available
+	  from http://...
+
+	  If unsure, say Y.
+
 config MOUSE_SERIAL
 	tristate "Serial mouse"
 	depends on INPUT && INPUT_MOUSE && SERIO
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/psmouse.c linux/drivers/input/mouse/psmouse.c
--- ../../linus/main/linux/drivers/input/mouse/psmouse.c	Sat Jun  7 21:40:38 2003
+++ linux/drivers/input/mouse/psmouse.c	Wed Jun 11 23:05:25 2003
@@ -41,6 +41,7 @@
 #define PSMOUSE_RET_NAK		0xfe
 
 struct psmouse {
+	void *private;
 	struct input_dev dev;
 	struct serio *serio;
 	char *vendor;
@@ -65,8 +66,11 @@
 #define PSMOUSE_GENPS	4
 #define PSMOUSE_IMPS	5
 #define PSMOUSE_IMEX	6
+#define PSMOUSE_SYNAPTICS 7
 
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" };
+#include "synaptics.c"
+
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
 
 /*
  * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
@@ -209,6 +213,16 @@
 		goto out;
 	}
 
+	if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+		/*
+		 * The synaptics driver has its own resync logic,
+		 * so it needs to receive all bytes one at a time.
+		 */
+		synaptics_process_byte(psmouse, regs);
+		psmouse->pktcnt = 0;
+		goto out;
+	}
+
 	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
 		serio_rescan(serio);
 		goto out;
@@ -343,12 +357,12 @@
        psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
 
        if (param[1] == 0x47) {
-               /* We could do more here. But it's sufficient just
-                  to stop the subsequent probes from screwing the
-                  thing up. */
-               psmouse->vendor = "Synaptics";
-               psmouse->name = "TouchPad";
-               return PSMOUSE_PS2;
+		int type = PSMOUSE_PS2;
+		psmouse->vendor = "Synaptics";
+		psmouse->name = "TouchPad";
+		if (synaptics_init(psmouse) == 0)
+			type = PSMOUSE_SYNAPTICS;
+		return type;
        }
 
 /*
@@ -598,6 +612,7 @@
 	struct psmouse *psmouse = serio->private;
 	input_unregister_device(&psmouse->dev);
 	serio_close(serio);
+	synaptics_disconnect(psmouse);
 	kfree(psmouse);
 }
 
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.c linux/drivers/input/mouse/synaptics.c
--- ../../linus/main/linux/drivers/input/mouse/synaptics.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/input/mouse/synaptics.c	Wed Jun 11 23:04:59 2003
@@ -0,0 +1,400 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ *   2003 Peter Osterlund <petero2@telia.com>
+ *     Ported to 2.5 input device infrastructure.
+ *
+ *   Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
+ *     start merging tpconfig and gpm code to a xfree-input module
+ *     adding some changes and extensions (ex. 3rd and 4th button)
+ *
+ *   Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
+ *   Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
+ *     code for the special synaptics commands (from the tpconfig-source)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+
+static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {}
+static inline int synaptics_init(struct psmouse *psmouse) { return -1; }
+static inline void synaptics_disconnect(struct psmouse *psmouse) {}
+
+#else
+
+#include "synaptics.h"
+
+
+static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+
+/*****************************************************************************
+ *	Synaptics communications functions
+ ****************************************************************************/
+
+/*
+ * Use the Synaptics extended ps/2 syntax to write a special command byte.
+ * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
+ *                  is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
+ *                  and synaptics_set_mode)
+ */
+static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+	int i;
+
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+		return -1;
+
+	for (i = 6; i >= 0; i -= 2) {
+		unsigned char d = (command >> i) & 3;
+		if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Send a command to the synpatics touchpad by special commands
+ */
+static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
+{
+	if (synaptics_special_cmd(psmouse, c))
+		return -1;
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+		return -1;
+	return 0;
+}
+
+/*
+ * Set the synaptics touchpad mode byte by special commands
+ */
+static int synaptics_set_mode(struct psmouse *psmouse, unsigned char mode)
+{
+	unsigned char param[1];
+
+	if (synaptics_special_cmd(psmouse, mode))
+		return -1;
+	param[0] = 0x14;
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+		return -1;
+	return 0;
+}
+
+static int synaptics_reset(struct psmouse *psmouse)
+{
+	unsigned char r[2];
+
+	if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
+		return -1;
+	if (r[0] == 0xAA && r[1] == 0x00)
+		return 0;
+	return -1;
+}
+
+/*
+ * Read the model-id bytes from the touchpad
+ * see also SYN_MODEL_* macros
+ */
+static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_id)
+{
+	unsigned char mi[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
+		return -1;
+	*model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
+	return 0;
+}
+
+/*
+ * Read the capability-bits from the touchpad
+ * see also the SYN_CAP_* macros
+ */
+static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
+{
+	unsigned char cap[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
+		return -1;
+	*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+	if (SYN_CAP_VALID(*capability))
+		return 0;
+	return -1;
+}
+
+/*
+ * Identify Touchpad
+ * See also the SYN_ID_* macros
+ */
+static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident)
+{
+	unsigned char id[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
+		return -1;
+	*ident = (id[0]<<16) | (id[1]<<8) | id[2];
+	if (SYN_ID_IS_SYNAPTICS(*ident))
+		return 0;
+	return -1;
+}
+
+static int synaptics_enable_device(struct psmouse *psmouse)
+{
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
+		return -1;
+	return 0;
+}
+
+static void print_ident(struct synaptics_data *priv)
+{
+	printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
+	printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
+	       SYN_ID_MINOR(priv->identity));
+
+	if (SYN_MODEL_ROT180(priv->model_id))
+		printk(KERN_INFO " 180 degree mounted touchpad\n");
+	if (SYN_MODEL_PORTRAIT(priv->model_id))
+		printk(KERN_INFO " portrait touchpad\n");
+	printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
+	if (SYN_MODEL_NEWABS(priv->model_id))
+		printk(KERN_INFO " new absolute packet format\n");
+	if (SYN_MODEL_PEN(priv->model_id))
+		printk(KERN_INFO " pen detection\n");
+
+	if (SYN_CAP_EXTENDED(priv->capabilities)) {
+		printk(KERN_INFO " Touchpad has extended capability bits\n");
+		if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+			printk(KERN_INFO " -> four buttons\n");
+		if (SYN_CAP_MULTIFINGER(priv->capabilities))
+			printk(KERN_INFO " -> multifinger detection\n");
+		if (SYN_CAP_PALMDETECT(priv->capabilities))
+			printk(KERN_INFO " -> palm detection\n");
+	}
+}
+
+static int query_hardware(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	int retries = 3;
+
+	while ((retries++ <= 3) && synaptics_reset(psmouse))
+		printk(KERN_ERR "synaptics reset failed\n");
+
+	if (synaptics_identify(psmouse, &priv->identity))
+		return -1;
+	if (synaptics_model_id(psmouse, &priv->model_id))
+		return -1;
+	if (synaptics_capability(psmouse, &priv->capabilities))
+		return -1;
+	if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+					 SYN_BIT_HIGH_RATE |
+					 SYN_BIT_DISABLE_GESTURE |
+					 SYN_BIT_W_MODE)))
+		return -1;
+
+	synaptics_enable_device(psmouse);
+
+	print_ident(priv);
+
+	return 0;
+}
+
+/*****************************************************************************
+ *	Driver initialization/cleanup functions
+ ****************************************************************************/
+
+static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
+{
+	dev->absmin[axis] = min;
+	dev->absmax[axis] = max;
+	dev->absfuzz[axis] = fuzz;
+	dev->absflat[axis] = flat;
+
+	set_bit(axis, dev->absbit);
+}
+
+static int synaptics_init(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv;
+
+	psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+	if (!priv)
+		return -1;
+	memset(priv, 0, sizeof(struct synaptics_data));
+
+	priv->inSync = 1;
+
+	if (query_hardware(psmouse)) {
+		printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
+		goto init_fail;
+	}
+
+	/*
+	 * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
+	 * which says that they should be valid regardless of the actual size of
+	 * the senser.
+	 */
+	set_bit(EV_ABS, psmouse->dev.evbit);
+	set_abs_params(&psmouse->dev, ABS_X, 1472, 5472, 0, 0);
+	set_abs_params(&psmouse->dev, ABS_Y, 1408, 4448, 0, 0);
+	set_abs_params(&psmouse->dev, ABS_PRESSURE, 0, 255, 0, 0);
+
+	set_bit(EV_MSC, psmouse->dev.evbit);
+	set_bit(MSC_GESTURE, psmouse->dev.mscbit);
+
+	set_bit(EV_KEY, psmouse->dev.evbit);
+	set_bit(BTN_LEFT, psmouse->dev.keybit);
+	set_bit(BTN_RIGHT, psmouse->dev.keybit);
+	set_bit(BTN_FORWARD, psmouse->dev.keybit);
+	set_bit(BTN_BACK, psmouse->dev.keybit);
+
+	clear_bit(EV_REL, psmouse->dev.evbit);
+	clear_bit(REL_X, psmouse->dev.relbit);
+	clear_bit(REL_Y, psmouse->dev.relbit);
+
+	return 0;
+
+ init_fail:
+	kfree(priv);
+	return -1;
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	kfree(priv);
+}
+
+/*****************************************************************************
+ *	Functions to interpret the absolute mode packets
+ ****************************************************************************/
+
+static void synaptics_parse_hw_state(struct synaptics_data *priv,
+				     struct synaptics_hw_state *hw)
+{
+	unsigned char *buf = priv->proto_buf;
+
+	hw->x = (((buf[3] & 0x10) << 8) |
+		 ((buf[1] & 0x0f) << 8) |
+		 buf[4]);
+	hw->y = (((buf[3] & 0x20) << 7) |
+		 ((buf[1] & 0xf0) << 4) |
+		 buf[5]);
+
+	hw->z = buf[2];
+	hw->w = (((buf[0] & 0x30) >> 2) |
+		 ((buf[0] & 0x04) >> 1) |
+		 ((buf[3] & 0x04) >> 2));
+
+	hw->left  = (buf[0] & 0x01) ? 1 : 0;
+	hw->right = (buf[0] & 0x2) ? 1 : 0;
+	hw->up    = 0;
+	hw->down  = 0;
+
+	if (SYN_CAP_EXTENDED(priv->capabilities) &&
+	    (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
+		hw->up = ((buf[3] & 0x01)) ? 1 : 0;
+		if (hw->left)
+			hw->up = !hw->up;
+		hw->down = ((buf[3] & 0x02)) ? 1 : 0;
+		if (hw->right)
+			hw->down = !hw->down;
+	}
+}
+
+/*
+ *  called for each full received packet from the touchpad
+ */
+static void synaptics_process_packet(struct psmouse *psmouse)
+{
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+	struct synaptics_hw_state hw;
+
+	synaptics_parse_hw_state(priv, &hw);
+
+	if (hw.z > 0) {
+		int w_ok = 0;
+		/*
+		 * Use capability bits to decide if the w value is valid.
+		 * If not, set it to 5, which corresponds to a finger of
+		 * normal width.
+		 */
+		if (SYN_CAP_EXTENDED(priv->capabilities)) {
+			switch (hw.w) {
+			case 0 ... 1:
+				w_ok = SYN_CAP_MULTIFINGER(priv->capabilities);
+				break;
+			case 2:
+				w_ok = SYN_MODEL_PEN(priv->model_id);
+				break;
+			case 4 ... 15:
+				w_ok = SYN_CAP_PALMDETECT(priv->capabilities);
+				break;
+			}
+		}
+		if (!w_ok)
+			hw.w = 5;
+	}
+
+	/* Post events */
+	input_report_abs(dev, ABS_X,        hw.x);
+	input_report_abs(dev, ABS_Y,        hw.y);
+	input_report_abs(dev, ABS_PRESSURE, hw.z);
+
+	if (hw.w != priv->old_w) {
+		input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
+		priv->old_w = hw.w;
+	}
+
+	input_report_key(dev, BTN_LEFT,    hw.left);
+	input_report_key(dev, BTN_RIGHT,   hw.right);
+	input_report_key(dev, BTN_FORWARD, hw.up);
+	input_report_key(dev, BTN_BACK,    hw.down);
+
+	input_sync(dev);
+}
+
+static void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+	unsigned char *pBuf = priv->proto_buf;
+	unsigned char u = psmouse->packet[0];
+
+	input_regs(dev, regs);
+
+	pBuf[priv->proto_buf_tail++] = u;
+
+	/* check first byte */
+	if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
+		priv->inSync = 0;
+		priv->proto_buf_tail = 0;
+		printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+		return;
+	}
+
+	/* check 4th byte */
+	if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
+		priv->inSync = 0;
+		priv->proto_buf_tail = 0;
+		printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+		return;
+	}
+
+	if (priv->proto_buf_tail >= 6) { /* Full packet received */
+		if (!priv->inSync) {
+			priv->inSync = 1;
+			printk(KERN_NOTICE "Synaptics driver resynced.\n");
+		}
+		synaptics_process_packet(psmouse);
+		priv->proto_buf_tail = 0;
+	}
+}
+
+#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.h linux/drivers/input/mouse/synaptics.h
--- ../../linus/main/linux/drivers/input/mouse/synaptics.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/input/mouse/synaptics.h	Wed Jun 11 23:04:50 2003
@@ -0,0 +1,90 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _SYNAPTICS_H
+#define _SYNAPTICS_H
+
+/* synaptics queries */
+#define SYN_QUE_IDENTIFY		0x00
+#define SYN_QUE_MODES			0x01
+#define SYN_QUE_CAPABILITIES		0x02
+#define SYN_QUE_MODEL			0x03
+#define SYN_QUE_SERIAL_NUMBER_PREFIX	0x06
+#define SYN_QUE_SERIAL_NUMBER_SUFFIX	0x07
+#define SYN_QUE_RESOLUTION		0x08
+
+/* synatics modes */
+#define SYN_BIT_ABSOLUTE_MODE		(1 << 7)
+#define SYN_BIT_HIGH_RATE		(1 << 6)
+#define SYN_BIT_SLEEP_MODE		(1 << 3)
+#define SYN_BIT_DISABLE_GESTURE		(1 << 2)
+#define SYN_BIT_W_MODE			(1 << 0)
+
+/* synaptics model ID bits */
+#define SYN_MODEL_ROT180(m)		((m) & (1 << 23))
+#define SYN_MODEL_PORTRAIT(m)		((m) & (1 << 22))
+#define SYN_MODEL_SENSOR(m)		(((m) >> 16) & 0x3f)
+#define SYN_MODEL_HARDWARE(m)		(((m) >> 9) & 0x7f)
+#define SYN_MODEL_NEWABS(m)		((m) & (1 << 7))
+#define SYN_MODEL_PEN(m)		((m) & (1 << 6))
+#define SYN_MODEL_SIMPLIC(m)		((m) & (1 << 5))
+#define SYN_MODEL_GEOMETRY(m)		((m) & 0x0f)
+
+/* synaptics capability bits */
+#define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_SLEEP(c)		((c) & (1 << 4))
+#define SYN_CAP_FOUR_BUTTON(c)		((c) & (1 << 3))
+#define SYN_CAP_MULTIFINGER(c)		((c) & (1 << 1))
+#define SYN_CAP_PALMDETECT(c)		((c) & (1 << 0))
+#define SYN_CAP_VALID(c)		((((c) & 0x00ff00) >> 8) == 0x47)
+
+/* synaptics modes query bits */
+#define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
+#define SYN_MODE_RATE(m)		((m) & (1 << 6))
+#define SYN_MODE_BAUD_SLEEP(m)		((m) & (1 << 3))
+#define SYN_MODE_DISABLE_GESTURE(m)	((m) & (1 << 2))
+#define SYN_MODE_PACKSIZE(m)		((m) & (1 << 1))
+#define SYN_MODE_WMODE(m)		((m) & (1 << 0))
+
+/* synaptics identify query bits */
+#define SYN_ID_MODEL(i) 		(((i) >> 4) & 0x0f)
+#define SYN_ID_MAJOR(i) 		((i) & 0x0f)
+#define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
+#define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
+
+
+/*
+ * A structure to describe the state of the touchpad hardware (buttons and pad)
+ */
+struct synaptics_hw_state {
+	int x;
+	int y;
+	int z;
+	int w;
+	int left;
+	int right;
+	int up;
+	int down;
+};
+
+struct synaptics_data {
+	/* Data read from the touchpad */
+	unsigned long int model_id;		/* Model-ID */
+	unsigned long int capabilities; 	/* Capabilities */
+	unsigned long int identity;		/* Identification */
+
+	/* Data for normal processing */
+	unsigned char proto_buf[6];		/* Buffer for Packet */
+	unsigned char last_byte;		/* last received byte */
+	int inSync;				/* Packets in sync */
+	int proto_buf_tail;
+
+	int old_w;				/* Previous w value */
+};
+
+#endif /* _SYNAPTICS_H */
diff -u -r -N --exclude='[ampvc]*' --exclude='*~' ../../linus/main/linux/include/linux/input.h linux/include/linux/input.h
--- ../../linus/main/linux/include/linux/input.h	Sat Jun  7 21:43:09 2003
+++ linux/include/linux/input.h	Wed Jun 11 21:56:04 2003
@@ -523,6 +523,7 @@
 
 #define MSC_SERIAL		0x00
 #define MSC_PULSELED		0x01
+#define MSC_GESTURE		0x02
 #define MSC_MAX			0x07
 
 /*


-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 21:23       ` Peter Osterlund
@ 2003-06-12  2:48         ` Joseph Fannin
  2003-06-12  2:54           ` CaT
  2003-06-12 19:11           ` Peter Osterlund
  2003-06-12  6:31         ` Vojtech Pavlik
  2003-06-12  8:36         ` James H. Cloos Jr.
  2 siblings, 2 replies; 49+ messages in thread
From: Joseph Fannin @ 2003-06-12  2:48 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 446 bytes --]

On Wed, Jun 11, 2003 at 11:23:48PM +0200, Peter Osterlund wrote:

> Here is a new patch that sends ABS_ events to user space. I haven't
> modified the XFree86 driver to handle this format yet, but I used
> /dev/input/event* to verify that the driver generates correct data.

    How well will GPM (for example) work with this?

-- 
Joseph Fannin
jhf@rivenstone.net

"Anyone who quotes me in their sig is an idiot." -- Rusty Russell.

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12  2:48         ` Joseph Fannin
@ 2003-06-12  2:54           ` CaT
  2003-06-12 18:58             ` Peter Osterlund
  2003-06-12 19:11           ` Peter Osterlund
  1 sibling, 1 reply; 49+ messages in thread
From: CaT @ 2003-06-12  2:54 UTC (permalink / raw)
  To: Peter Osterlund, linux-kernel

On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > Here is a new patch that sends ABS_ events to user space. I haven't
> > modified the XFree86 driver to handle this format yet, but I used
> > /dev/input/event* to verify that the driver generates correct data.
> 
>     How well will GPM (for example) work with this?

Aaaand... will I be able to transparently use my ps2 mouse and touchpad
without having to worry about what's plugged in at any one time?

(not trying to whinge, I just got used to having a ps2 mouse plugged in
but want to use a synaptics driver to configure certain aspects of the
touchpaf and would like the best of both worlds. :)

-- 
Martin's distress was in contrast to the bitter satisfaction of some
of his fellow marines as they surveyed the scene. "The Iraqis are sick
people and we are the chemotherapy," said Corporal Ryan Dupre. "I am
starting to hate this country. Wait till I get hold of a friggin' Iraqi.
No, I won't get hold of one. I'll just kill him."
	- http://www.informationclearinghouse.info/article2479.htm

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 21:23       ` Peter Osterlund
  2003-06-12  2:48         ` Joseph Fannin
@ 2003-06-12  6:31         ` Vojtech Pavlik
  2003-06-12  8:36         ` James H. Cloos Jr.
  2 siblings, 0 replies; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-12  6:31 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin

On Wed, Jun 11, 2003 at 11:23:48PM +0200, Peter Osterlund wrote:

> Vojtech Pavlik <vojtech@ucw.cz> writes:
> 
> > On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:
> > 
> > > The w value is somewhat special and not really a real axis. According
> > > to the Synaptics TouchPad Interfacing Guide
> > > (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> > > follows:
> > > 
> > > Value		Needed capability	Interpretation
> > > W = 0		capMultiFinger		Two fingers on the pad.
> > > W = 1		capMultiFinger		Three or more fingers on the pad.
> > > W = 2		capPen			Pen (instead of finger) on the pad.
> > > W = 3		Reserved.
> > > W = 4-7		capPalmDetect		Finger of normal width.
> > > W = 8-14	capPalmDetect		Very wide finger or palm.
> > > W = 15		capPalmDetect		Maximum reportable width; extremely
> > > 					wide contact.
> > > 
> > > Is there a better way than using ABS_MISC to pass the W information to
> > > user space?
> > 
> > We should probably add an EV_MSC, MSC_GESTURE event type for this.
> > That'll be the cleanest solution.
> 
> Here is a new patch that sends ABS_ events to user space. I haven't
> modified the XFree86 driver to handle this format yet, but I used
> /dev/input/event* to verify that the driver generates correct data.

I like this one. I'm merging it now. Thanks!

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 21:23       ` Peter Osterlund
  2003-06-12  2:48         ` Joseph Fannin
  2003-06-12  6:31         ` Vojtech Pavlik
@ 2003-06-12  8:36         ` James H. Cloos Jr.
  2003-06-15 21:42           ` [PATCH] Synaptics Client/Passthrough (for Inspiron...) Arne Koewing
  2 siblings, 1 reply; 49+ messages in thread
From: James H. Cloos Jr. @ 2003-06-12  8:36 UTC (permalink / raw)
  To: linux-kernel

Have you tested with Arne Koewing <ark@gmx.net>'s synaptics_reset patch:

diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
--- a/drivers/input/mouse/psmouse.c     Thu Jun 12 04:26:48 2003
+++ b/drivers/input/mouse/psmouse.c     Thu Jun 12 04:26:48 2003
@@ -345,6 +345,7 @@
                   thing up. */
                psmouse->vendor = "Synaptics";
                psmouse->name = "TouchPad";
+              psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT);
                return PSMOUSE_PS2;
        }


w/o that patch, using 2.5 on a dell laptop disables the track point
until something else causes a rest on the ps/2 bus, such as hot-
plugging an external ps2 mouse or suspending and resuming the box.

For that matter, does running the touchpad in absolute mode affect
the track point at all?

(I'm primarily just interested in stopping the unintended mouse button
events I get from the pad's default config....)

-JimC


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12  2:54           ` CaT
@ 2003-06-12 18:58             ` Peter Osterlund
  2003-06-12 22:01               ` Peter Berg Larsen
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Osterlund @ 2003-06-12 18:58 UTC (permalink / raw)
  To: CaT; +Cc: linux-kernel

CaT <cat@zip.com.au> writes:

> On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > > Here is a new patch that sends ABS_ events to user space. I haven't
> > > modified the XFree86 driver to handle this format yet, but I used
> > > /dev/input/event* to verify that the driver generates correct data.
> > 
> >     How well will GPM (for example) work with this?
> 
> Aaaand... will I be able to transparently use my ps2 mouse and touchpad
> without having to worry about what's plugged in at any one time?

It works on my computer at least. When loading the psmouse module I
get this:

        input: PS/2 Logitech Mouse on isa0060/serio2
        Synaptics Touchpad, model: 1
         Firware: 5.6
         180 degree mounted touchpad
         Sensor: 18
         new absolute packet format
         Touchpad has extended capability bits
         -> four buttons
         -> multifinger detection
         -> palm detection
        input: Synaptics Synaptics TouchPad on isa0060/serio4

The touchpad and the mouse operates independently of each other. The
mouse generates relative events as usual and the touchpad generates
absolute events as defined by my previous patch.

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12  2:48         ` Joseph Fannin
  2003-06-12  2:54           ` CaT
@ 2003-06-12 19:11           ` Peter Osterlund
  1 sibling, 0 replies; 49+ messages in thread
From: Peter Osterlund @ 2003-06-12 19:11 UTC (permalink / raw)
  To: Joseph Fannin; +Cc: linux-kernel

"Joseph Fannin" <jhf@rivenstone.net> writes:

> On Wed, Jun 11, 2003 at 11:23:48PM +0200, Peter Osterlund wrote:
> 
> > Here is a new patch that sends ABS_ events to user space. I haven't
> > modified the XFree86 driver to handle this format yet, but I used
> > /dev/input/event* to verify that the driver generates correct data.
> 
>     How well will GPM (for example) work with this?

GPM will need some changes to support the new ABS format, but I think
it will be quite easy to make those changes.

This driver will also make it possible to run GPM and the XFree86
driver simultaneously, something that didn't work before.

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12 18:58             ` Peter Osterlund
@ 2003-06-12 22:01               ` Peter Berg Larsen
  2003-06-12 22:57                 ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Berg Larsen @ 2003-06-12 22:01 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: CaT, linux-kernel


> > On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > > > Here is a new patch that sends ABS_ events to user space. I haven't
> > > > modified the XFree86 driver to handle this format yet, but I used
> > > > /dev/input/event* to verify that the driver generates correct data.

> > CaT <cat@zip.com.au> writes:
> > Aaaand... will I be able to transparently use my ps2 mouse and touchpad
> > without having to worry about what's plugged in at any one time?

The short answer is no, if you still have the gateway laptop.


On 12 Jun 2003, Peter Osterlund wrote:
> It works on my computer at least. When loading the psmouse module I
> get this:

>         input: PS/2 Logitech Mouse on isa0060/serio2
>         input: Synaptics Synaptics TouchPad on isa0060/serio4

It works for you because it (your laptop) has active multiplexing. Without
active multiplexing I see no way of demultiplexing different mouse
protocols in mousedev.

A guestdevice behind the touchpad also needs demultiplexing even with
activ multiplexing. This could be done in the synaptics driver but as the
guestdevice can be any device, the synaptics driver needs to know every
mouse protocol there is to demultiplex it. The synaptics driver sent does
not demultiplex a guestdevice.


Peter



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12 22:01               ` Peter Berg Larsen
@ 2003-06-12 22:57                 ` Vojtech Pavlik
  2003-06-12 23:17                   ` Peter Berg Larsen
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-12 22:57 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: Peter Osterlund, CaT, linux-kernel

On Fri, Jun 13, 2003 at 12:01:35AM +0200, Peter Berg Larsen wrote:
> 
> > > On Wed, Jun 11, 2003 at 10:48:14PM -0400, Joseph Fannin wrote:
> > > > > Here is a new patch that sends ABS_ events to user space. I haven't
> > > > > modified the XFree86 driver to handle this format yet, but I used
> > > > > /dev/input/event* to verify that the driver generates correct data.
> 
> > > CaT <cat@zip.com.au> writes:
> > > Aaaand... will I be able to transparently use my ps2 mouse and touchpad
> > > without having to worry about what's plugged in at any one time?
> 
> The short answer is no, if you still have the gateway laptop.
> 
> 
> On 12 Jun 2003, Peter Osterlund wrote:
> > It works on my computer at least. When loading the psmouse module I
> > get this:
> 
> >         input: PS/2 Logitech Mouse on isa0060/serio2
> >         input: Synaptics Synaptics TouchPad on isa0060/serio4
> 
> It works for you because it (your laptop) has active multiplexing. Without
> active multiplexing I see no way of demultiplexing different mouse
> protocols in mousedev.
> 
> A guestdevice behind the touchpad also needs demultiplexing even with
> activ multiplexing. This could be done in the synaptics driver but as the
> guestdevice can be any device, the synaptics driver needs to know every
> mouse protocol there is to demultiplex it. The synaptics driver sent does
> not demultiplex a guestdevice.

The synaptics driver, if it wished to demultiplex a true mouse protocol
behind the pad without an active multiplexing controller, could easily
create a new serio port, to which the psmouse driver would attach,
detect, and drive the mouse. It's a bit crazy, but it should work.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12 22:57                 ` Vojtech Pavlik
@ 2003-06-12 23:17                   ` Peter Berg Larsen
  2003-06-12 23:27                     ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Berg Larsen @ 2003-06-12 23:17 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: linux-kernel


On Fri, 13 Jun 2003, Vojtech Pavlik wrote:

> > A guestdevice behind the touchpad also needs demultiplexing even with
> > activ multiplexing. This could be done in the synaptics driver but as the
> > guestdevice can be any device, the synaptics driver needs to know every
> > mouse protocol there is to demultiplex it. The synaptics driver sent does
> > not demultiplex a guestdevice.
>
> The synaptics driver, if it wished to demultiplex a true mouse protocol
> behind the pad without an active multiplexing controller, could easily
> create a new serio port, to which the psmouse driver would attach,
> detect, and drive the mouse. It's a bit crazy, but it should work.

hmm, that is clever. But I am afraid it will not work: the master (the
touchpad) must be told how many bytes the guest protocol uses. So it can
not just sent the bytes back and forth. If set wrong the guest is ignored.
(This was probably what was happening a while back when many reported that
the stick did not work: probing for imps2, exps2 etc. is forwarded to the
guest and if the guest knew fx. imps2 it switch protocol, but the master
was not told and ignored the guest)

Peter



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12 23:17                   ` Peter Berg Larsen
@ 2003-06-12 23:27                     ` Vojtech Pavlik
  2003-06-12 23:42                       ` Peter Berg Larsen
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-12 23:27 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: linux-kernel

On Fri, Jun 13, 2003 at 01:17:43AM +0200, Peter Berg Larsen wrote:
> 
> On Fri, 13 Jun 2003, Vojtech Pavlik wrote:
> 
> > > A guestdevice behind the touchpad also needs demultiplexing even with
> > > activ multiplexing. This could be done in the synaptics driver but as the
> > > guestdevice can be any device, the synaptics driver needs to know every
> > > mouse protocol there is to demultiplex it. The synaptics driver sent does
> > > not demultiplex a guestdevice.
> >
> > The synaptics driver, if it wished to demultiplex a true mouse protocol
> > behind the pad without an active multiplexing controller, could easily
> > create a new serio port, to which the psmouse driver would attach,
> > detect, and drive the mouse. It's a bit crazy, but it should work.
> 
> hmm, that is clever. But I am afraid it will not work: the master (the
> touchpad) must be told how many bytes the guest protocol uses. So it can
> not just sent the bytes back and forth. If set wrong the guest is ignored.
> (This was probably what was happening a while back when many reported that
> the stick did not work: probing for imps2, exps2 etc. is forwarded to the
> guest and if the guest knew fx. imps2 it switch protocol, but the master
> was not told and ignored the guest)

That's sad. Anyway, we'll have to find a solution for this. Either the
synaptics driver parsing the communication on the new serio port (which
isn't as complex as it looks) and detecting the packet length from that,
or some way the psmouse driver can tell it what packet size it uses.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12 23:27                     ` Vojtech Pavlik
@ 2003-06-12 23:42                       ` Peter Berg Larsen
  2003-06-13  7:44                         ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Berg Larsen @ 2003-06-12 23:42 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: linux-kernel


On Fri, 13 Jun 2003, Vojtech Pavlik wrote:

> > > The synaptics driver, if it wished to demultiplex a true mouse protocol
> > > behind the pad without an active multiplexing controller, could easily
> > > create a new serio port, to which the psmouse driver would attach,
> > > detect, and drive the mouse. It's a bit crazy, but it should work.

> > hmm, that is clever. But I am afraid it will not work: the master (the

> That's sad. Anyway, we'll have to find a solution for this. Either the
> synaptics driver parsing the communication on the new serio port (which
> isn't as complex as it looks) and detecting the packet length from that,
> or some way the psmouse driver can tell it what packet size it uses.

If the synaptic driver can deduce the protocol by listning to the probing
communication, it might as well just sent it itself.

Peter
--
E-Mail:       pebl@math.ku.dk
Real name:    Peter Berg Larsen
Where:        Department of Computer Science, Copenhagen Uni., Denmark



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-12 23:42                       ` Peter Berg Larsen
@ 2003-06-13  7:44                         ` Vojtech Pavlik
  2003-06-13  8:58                           ` Peter Berg Larsen
  2003-06-13 20:25                           ` James Simmons
  0 siblings, 2 replies; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-13  7:44 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: linux-kernel

On Fri, Jun 13, 2003 at 01:42:40AM +0200, Peter Berg Larsen wrote:

> On Fri, 13 Jun 2003, Vojtech Pavlik wrote:
> 
> > > > The synaptics driver, if it wished to demultiplex a true mouse protocol
> > > > behind the pad without an active multiplexing controller, could easily
> > > > create a new serio port, to which the psmouse driver would attach,
> > > > detect, and drive the mouse. It's a bit crazy, but it should work.
> 
> > > hmm, that is clever. But I am afraid it will not work: the master (the
> 
> > That's sad. Anyway, we'll have to find a solution for this. Either the
> > synaptics driver parsing the communication on the new serio port (which
> > isn't as complex as it looks) and detecting the packet length from that,
> > or some way the psmouse driver can tell it what packet size it uses.
> 
> If the synaptic driver can deduce the protocol by listning to the probing
> communication, it might as well just sent it itself.

Not the protocol. Just the number of bytes per packet. That's quite a
different amount of understanding of the data passed through.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13  7:44                         ` Vojtech Pavlik
@ 2003-06-13  8:58                           ` Peter Berg Larsen
  2003-06-13 20:25                           ` James Simmons
  1 sibling, 0 replies; 49+ messages in thread
From: Peter Berg Larsen @ 2003-06-13  8:58 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: linux-kernel


On Fri, 13 Jun 2003, Vojtech Pavlik wrote:

> > > > hmm, that is clever. But I am afraid it will not work: the master (the

> > If the synaptic driver can deduce the protocol by listning to the probing
> > communication, it might as well just sent it itself.
>
> Not the protocol. Just the number of bytes per packet. That's quite a
> different amount of understanding of the data passed through.

Ahh, that would not work either. The description of master/guest was
probably not the best: The protocolbytes from the guest do not even
reach the KBC because the master (touchpad) is ignoring them. So as soon
the guest accepts an protocol more advanced than ps/2 the master must be
told how many bytes is used in the protocol.


Peter





^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13  7:44                         ` Vojtech Pavlik
  2003-06-13  8:58                           ` Peter Berg Larsen
@ 2003-06-13 20:25                           ` James Simmons
  2003-06-13 20:38                             ` Vojtech Pavlik
  1 sibling, 1 reply; 49+ messages in thread
From: James Simmons @ 2003-06-13 20:25 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Peter Berg Larsen, linux-kernel


Just as a idea for API. How about ABS_AREA or REL_AREA instead of 
ABS_MISC. The idea is the pressure value returned should be about 
the same if one presses hard with one finger or softly with a whole 
hand. So to tell the difference between the two we can report the 
pressure and the area over which it acted. Say in virtual reality 
environment simulation poking a object hard with your finger would
have a very different effect than placing your hand lightly on the 
object even tho they might register about the same pressure.


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 20:25                           ` James Simmons
@ 2003-06-13 20:38                             ` Vojtech Pavlik
  2003-06-13 20:51                               ` James Simmons
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-13 20:38 UTC (permalink / raw)
  To: James Simmons; +Cc: Peter Berg Larsen, linux-kernel

On Fri, Jun 13, 2003 at 09:25:09PM +0100, James Simmons wrote:

> Just as a idea for API. How about ABS_AREA or REL_AREA instead of 
> ABS_MISC. The idea is the pressure value returned should be about 
> the same if one presses hard with one finger or softly with a whole 
> hand.

Huh? Force = Pressure x Area ... I think you're mixing up force and
pressure here.

> So to tell the difference between the two we can report the 
> pressure and the area over which it acted. Say in virtual reality 
> environment simulation poking a object hard with your finger would
> have a very different effect than placing your hand lightly on the 
> object even tho they might register about the same pressure.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 20:38                             ` Vojtech Pavlik
@ 2003-06-13 20:51                               ` James Simmons
  2003-06-13 22:08                                 ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: James Simmons @ 2003-06-13 20:51 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Peter Berg Larsen, linux-kernel


> > Just as a idea for API. How about ABS_AREA or REL_AREA instead of 
> > ABS_MISC. The idea is the pressure value returned should be about 
> > the same if one presses hard with one finger or softly with a whole 
> > hand.
> 
> Huh? Force = Pressure x Area ... I think you're mixing up force and
> pressure here.

OOps. Your right. I'm thinking the hardware returns a force value. What I 
meant is since we have the hardware returning the pressure and the area 
this data can be used. Knowing the area over which a pressure is applied 
is a good thing. What do you think?



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 18:34     ` Vojtech Pavlik
  2003-06-11 21:23       ` Peter Osterlund
@ 2003-06-13 21:15       ` Peter Osterlund
  2003-06-13 21:49         ` James Simmons
  2003-06-13 22:08         ` Vojtech Pavlik
  1 sibling, 2 replies; 49+ messages in thread
From: Peter Osterlund @ 2003-06-13 21:15 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Kernel Mailing List, Vojtech Pavlik, Peter Berg Larsen

Vojtech Pavlik <vojtech@ucw.cz> writes:

> On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:
> 
> > The w value is somewhat special and not really a real axis. According
> > to the Synaptics TouchPad Interfacing Guide
> > (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> > follows:
> > 
> > Value		Needed capability	Interpretation
> > W = 0		capMultiFinger		Two fingers on the pad.
> > W = 1		capMultiFinger		Three or more fingers on the pad.
> > W = 2		capPen			Pen (instead of finger) on the pad.
> > W = 3		Reserved.
> > W = 4-7		capPalmDetect		Finger of normal width.
> > W = 8-14	capPalmDetect		Very wide finger or palm.
> > W = 15		capPalmDetect		Maximum reportable width; extremely
> > 					wide contact.
> > 
> > Is there a better way than using ABS_MISC to pass the W information to
> > user space?
> 
> We should probably add an EV_MSC, MSC_GESTURE event type for this.
> That'll be the cleanest solution.

Peter Berg Larsen suggested in a private email that we shouldn't
export W directly, because it is too synaptics specific. Better split
it in "number of fingers" and "finger width", so that other touchpads
could use the same format.

What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
maybe?

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 21:15       ` [PATCH] Synaptics TouchPad driver for 2.5.70 Peter Osterlund
@ 2003-06-13 21:49         ` James Simmons
  2003-06-13 22:08         ` Vojtech Pavlik
  1 sibling, 0 replies; 49+ messages in thread
From: James Simmons @ 2003-06-13 21:49 UTC (permalink / raw)
  To: Peter Osterlund
  Cc: Vojtech Pavlik, Kernel Mailing List, Vojtech Pavlik, Peter Berg Larsen


> > > to the Synaptics TouchPad Interfacing Guide
> > > (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> > > follows:
> > > 
> > > Value		Needed capability	Interpretation
> > > W = 0		capMultiFinger		Two fingers on the pad.
> > > W = 1		capMultiFinger		Three or more fingers on the pad.
> > > W = 2		capPen			Pen (instead of finger) on the pad.
> > > W = 3		Reserved.
> > > W = 4-7		capPalmDetect		Finger of normal width.
> > > W = 8-14	capPalmDetect		Very wide finger or palm.
> > > W = 15		capPalmDetect		Maximum reportable width; extremely
> > > 					wide contact.
> > > 
> > > Is there a better way than using ABS_MISC to pass the W information to
> > > user space?
> > 
> > We should probably add an EV_MSC, MSC_GESTURE event type for this.
> > That'll be the cleanest solution.
> 
> Peter Berg Larsen suggested in a private email that we shouldn't
> export W directly, because it is too synaptics specific. Better split
> it in "number of fingers" and "finger width", so that other touchpads
> could use the same format.
> 
> What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> maybe?

ABS_AREA



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 21:15       ` [PATCH] Synaptics TouchPad driver for 2.5.70 Peter Osterlund
  2003-06-13 21:49         ` James Simmons
@ 2003-06-13 22:08         ` Vojtech Pavlik
  2003-06-13 22:55           ` Peter Berg Larsen
  1 sibling, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-13 22:08 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: Kernel Mailing List, Vojtech Pavlik, Peter Berg Larsen

On Fri, Jun 13, 2003 at 11:15:57PM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <vojtech@ucw.cz> writes:
> 
> > On Wed, Jun 11, 2003 at 08:16:13PM +0200, Peter Osterlund wrote:
> > 
> > > The w value is somewhat special and not really a real axis. According
> > > to the Synaptics TouchPad Interfacing Guide
> > > (http://www.synaptics.com/decaf/utilities/ACF126.pdf), W is defined as
> > > follows:
> > > 
> > > Value		Needed capability	Interpretation
> > > W = 0		capMultiFinger		Two fingers on the pad.
> > > W = 1		capMultiFinger		Three or more fingers on the pad.
> > > W = 2		capPen			Pen (instead of finger) on the pad.
> > > W = 3		Reserved.
> > > W = 4-7		capPalmDetect		Finger of normal width.
> > > W = 8-14	capPalmDetect		Very wide finger or palm.
> > > W = 15		capPalmDetect		Maximum reportable width; extremely
> > > 					wide contact.
> > > 
> > > Is there a better way than using ABS_MISC to pass the W information to
> > > user space?
> > 
> > We should probably add an EV_MSC, MSC_GESTURE event type for this.
> > That'll be the cleanest solution.
> 
> Peter Berg Larsen suggested in a private email that we shouldn't
> export W directly, because it is too synaptics specific. Better split
> it in "number of fingers" and "finger width", so that other touchpads
> could use the same format.
> 
> What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> maybe?

Could work. Or as James Simmons suggested ABS_AREA.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 20:51                               ` James Simmons
@ 2003-06-13 22:08                                 ` Vojtech Pavlik
  2003-06-13 23:57                                   ` James Simmons
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-13 22:08 UTC (permalink / raw)
  To: James Simmons; +Cc: Peter Berg Larsen, linux-kernel

On Fri, Jun 13, 2003 at 09:51:29PM +0100, James Simmons wrote:
> 
> > > Just as a idea for API. How about ABS_AREA or REL_AREA instead of 
> > > ABS_MISC. The idea is the pressure value returned should be about 
> > > the same if one presses hard with one finger or softly with a whole 
> > > hand.
> > 
> > Huh? Force = Pressure x Area ... I think you're mixing up force and
> > pressure here.
> 
> OOps. Your right. I'm thinking the hardware returns a force value. What I 
> meant is since we have the hardware returning the pressure and the area 
> this data can be used. Knowing the area over which a pressure is applied 
> is a good thing. What do you think?

Definitely. Still it doesn't cover the multi-tap/gesture stuff.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 22:08         ` Vojtech Pavlik
@ 2003-06-13 22:55           ` Peter Berg Larsen
  2003-06-14  8:42             ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Berg Larsen @ 2003-06-13 22:55 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Peter Osterlund, Kernel Mailing List


On Sat, 14 Jun 2003, Vojtech Pavlik wrote:

> > What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> > maybe?

> Could work. Or as James Simmons suggested ABS_AREA.

ABS_NR_FINGERS and ABS_AREA ? I find ABS_FINGER_WIDTH to more telling.

The important part is that the driver must know when there is added or
removed a finger as touchpads sends the avarage positions of the fingers.
Adding or removing a finger moves the mouse if the driver does nothing.

There are other questions, if the API is to be used by a general user
touchpad driver. Is there a way to communicate the resolution of the x,y
and z coordinates to the user driver? (not only min/max). How do I tell
that the y coordinate is reversed (gliderpointer) ?


Peter







^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 22:08                                 ` Vojtech Pavlik
@ 2003-06-13 23:57                                   ` James Simmons
  2003-06-14  8:55                                     ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: James Simmons @ 2003-06-13 23:57 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Peter Berg Larsen, linux-kernel


> > > > Just as a idea for API. How about ABS_AREA or REL_AREA instead of 
> > > > ABS_MISC. The idea is the pressure value returned should be about 
> > > > the same if one presses hard with one finger or softly with a whole 
> > > > hand.
> > > 
> > > Huh? Force = Pressure x Area ... I think you're mixing up force and
> > > pressure here.
> > 
> > OOps. Your right. I'm thinking the hardware returns a force value. What I 
> > meant is since we have the hardware returning the pressure and the area 
> > this data can be used. Knowing the area over which a pressure is applied 
> > is a good thing. What do you think?
> 
> Definitely. Still it doesn't cover the multi-tap/gesture stuff.

How about EV_AREA
codes = "which area"  1, 2, 3
value = "How big of a area" 

struct input_event {
        struct timeval time;
        __u16 type;               EV_AREA
        __u16 code;	          AREA_1
        __s32 value;		  20
};




^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 22:55           ` Peter Berg Larsen
@ 2003-06-14  8:42             ` Vojtech Pavlik
  0 siblings, 0 replies; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-14  8:42 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: Peter Osterlund, Kernel Mailing List

On Sat, Jun 14, 2003 at 12:55:32AM +0200, Peter Berg Larsen wrote:
> 
> On Sat, 14 Jun 2003, Vojtech Pavlik wrote:
> 
> > > What do we call these things? ABS_FINGER_WIDTH and ABS_NR_FINGERS
> > > maybe?
> 
> > Could work. Or as James Simmons suggested ABS_AREA.
> 
> ABS_NR_FINGERS and ABS_AREA ? I find ABS_FINGER_WIDTH to more telling.

I'm now considering a yet different approach that's more along the lines
how digitizers (tablets) are handled:

BTN_TOOL_FINGER
BTN_TOOL_DOUBLETAP
BTN_TOOL_TRIPLETAP

for telling what the user used to point ... and

ABS_AREA or ABS_WIDTH or ABS_TOOL_WIDTH

to tell how the touched area is large. 

> The important part is that the driver must know when there is added or
> removed a finger as touchpads sends the avarage positions of the fingers.
> Adding or removing a finger moves the mouse if the driver does nothing.
> 
> There are other questions, if the API is to be used by a general user
> touchpad driver.

I hope it could, but not many touchpad drivers report all the stuff they
know like the Synaptics ones. Most do all the processing straight
within the pad processor.

> Is there a way to communicate the resolution of the x,y
> and z coordinates to the user driver? 

Not at the moment. We could add physical range values it if it becomes
needed, though. From this the userspace portion of the driver can
compute the resolution.

> (not only min/max). How do I tell
> that the y coordinate is reversed (gliderpointer) ?

The direction of the coordinates is defined to be constant in the API,
so you should reverse it in the driver if you detect a pad with a
reversed Y coordinate.
 

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-13 23:57                                   ` James Simmons
@ 2003-06-14  8:55                                     ` Vojtech Pavlik
  2003-06-16 21:28                                       ` James Simmons
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-14  8:55 UTC (permalink / raw)
  To: James Simmons; +Cc: Peter Berg Larsen, linux-kernel

On Sat, Jun 14, 2003 at 12:57:14AM +0100, James Simmons wrote:
> 
> > > > > Just as a idea for API. How about ABS_AREA or REL_AREA instead of 
> > > > > ABS_MISC. The idea is the pressure value returned should be about 
> > > > > the same if one presses hard with one finger or softly with a whole 
> > > > > hand.
> > > > 
> > > > Huh? Force = Pressure x Area ... I think you're mixing up force and
> > > > pressure here.
> > > 
> > > OOps. Your right. I'm thinking the hardware returns a force value. What I 
> > > meant is since we have the hardware returning the pressure and the area 
> > > this data can be used. Knowing the area over which a pressure is applied 
> > > is a good thing. What do you think?
> > 
> > Definitely. Still it doesn't cover the multi-tap/gesture stuff.
> 
> How about EV_AREA
> codes = "which area"  1, 2, 3
> value = "How big of a area" 
> 
> struct input_event {
>         struct timeval time;
>         __u16 type;               EV_AREA
>         __u16 code;	          AREA_1
>         __s32 value;		  20
> };

Nice, but no devices are reporting such detailed info. If you have a
multi-finger tap, then the area reported is the area between the
fingers. 

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
       [not found] <m2smqhqk4k.fsf@p4.localdomain>
  2003-06-11 15:02 ` [PATCH] Synaptics TouchPad driver for 2.5.70 Vojtech Pavlik
@ 2003-06-14 22:19 ` Vojtech Pavlik
  2003-06-15 12:18   ` Peter Osterlund
  1 sibling, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-14 22:19 UTC (permalink / raw)
  To: Peter Osterlund
  Cc: Kernel Mailing List, Vojtech Pavlik, Joseph Fannin, Jens Taprogge

[-- Attachment #1: Type: text/plain, Size: 1024 bytes --]

On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:

> [ I'm resending this because the previous message never showed up on
> the list. Maybe it was too big. ]
> 
> Hi!
> 
> Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> based on the XFree86 driver. This driver operates the touchpad in
> absolute mode and emulates a three button mouse with two scroll
> wheels. Features include:
> 
> * Multi finger tapping.
> * Vertical and horizontal scrolling.
> * Edge scrolling during drag operations.
> * Palm detection.
> * Corner tapping.

... you may want to put these nice features into the mousedev.c driver
for now, so that the touchpad works with standard XFree without the
event based driver.

Also, I'm attaching Jens Taprogge synaptics work, which you may want to
integrate ...

To Jens: Sorry for me not using your driver. It's very good, too.
Hopefully you'll be able to work together with Peter to bring the best
out of the two to the kernel.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

[-- Attachment #2: 2.5.59_mousedev_touchpad.diff --]
[-- Type: text/plain, Size: 6391 bytes --]

--- linux-2.5.59/drivers/input/mousedev.c	2003-01-17 03:22:43.000000000 +0100
+++ linux-2.5.59_jlt/drivers/input/mousedev.c	2003-02-02 14:27:36.000000000 +0100
@@ -36,6 +36,12 @@
 #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
 #define CONFIG_INPUT_MOUSEDEV_SCREEN_Y	768
 #endif
+#ifndef CONFIG_INPUT_MOUSEDEV_TAPFRACT
+#define CONFIG_INPUT_MOUSEDEV_TAPFRACT 12
+#endif
+#ifndef CONFIG_INPUT_MOUSEDEV_DRAGFRACT
+#define CONFIG_INPUT_MOUSEDEV_DRAGFRACT 8
+#endif
 
 struct mousedev {
 	int exist;
@@ -53,7 +59,9 @@
 	struct fasync_struct *fasync;
 	struct mousedev *mousedev;
 	struct list_head node;
-	int dx, dy, dz, oldx, oldy;
+	int dx, dy, dz, oldx, oldy, touchx, touchy;
+	char touched, tapped;
+	unsigned long tstamp;
 	signed char ps2[6];
 	unsigned long buttons;
 	unsigned char ready, buffer, bufsiz;
@@ -62,6 +70,13 @@
 
 #define MOUSEDEV_SEQ_LEN	6
 
+#define TAPSTATE_NONE		0
+#define TAPSTATE_TAPPED		1
+#define TAPSTATE_DRAGORDOUBLE	2
+#define TAPSTATE_DRAG		3
+#define TAPSTATE_DOUBLE		4
+#define TAPSTATE_DOUBLE2	5	
+
 static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
 static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 
@@ -72,6 +87,43 @@
 
 static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
 static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
+static int taptimeout = HZ/CONFIG_INPUT_MOUSEDEV_TAPFRACT;
+static int dragtimeout = HZ/CONFIG_INPUT_MOUSEDEV_DRAGFRACT;
+
+static inline void mousedev_touch(struct mousedev_list *list)
+{
+	list->touched = 1;
+	
+	if (list->tapped == TAPSTATE_TAPPED) 
+		/* drag or double tap */
+		list->tapped++;
+
+	list->tstamp = jiffies;
+	list->touchx = list->oldx;
+	list->touchy = list->oldy;
+}
+
+static inline void mousedev_touch_release(struct input_handle *handle, struct mousedev_list *list)
+{
+	list->touched = 0;
+
+	if (((list->tapped == 0) || (list->tapped == TAPSTATE_DRAGORDOUBLE)) && 
+			(!time_after(jiffies, list->tstamp + taptimeout)) && 
+			(abs(list->oldx - list->touchx) < (handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]) * xres / 40) &&
+			(abs(list->oldy - list->touchy) < (handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]) * yres / 40)) {
+		if (list->tapped == TAPSTATE_DRAGORDOUBLE)
+			/* double */
+			list->tapped += 2;
+		else
+			list->tapped++;
+
+		list->dx = 0;
+		list->dy = 0;
+	} else 
+		list->tapped = TAPSTATE_NONE;
+		
+	list->tstamp = jiffies;
+}
 
 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
@@ -99,6 +151,8 @@
 								list->dx += value - list->oldx;
 								list->oldx += list->dx;
 							}
+							if (!list->touched || (list->tapped == 1))
+								list->dx = 0;
 							break;
 
 						case ABS_Y:
@@ -110,6 +164,16 @@
 								list->dy -= value - list->oldy;
 								list->oldy -= list->dy;
 							}
+							if (!list->touched || (list->tapped == 1))
+								list->dy = 0;
+							break;
+
+						case ABS_PRESSURE:
+							if (!list->touched) {
+								if (value > 30) 
+									mousedev_touch(list);
+							} else if (value < 25)
+								mousedev_touch_release(handle, list);
 							break;
 					}
 					break;
@@ -235,6 +299,8 @@
 	memset(list, 0, sizeof(struct mousedev_list));
 
 	list->mousedev = mousedev_table[i];
+	list->touched = 1;
+	list->tapped = 0;
 	list_add_tail(&list->node, &mousedev_table[i]->list);
 	file->private_data = list;
 
@@ -255,28 +321,70 @@
 
 static void mousedev_packet(struct mousedev_list *list, unsigned char off)
 {
-	list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
-	list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
-	list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
-	list->dx -= list->ps2[off + 1];
-	list->dy -= list->ps2[off + 2];
-	list->bufsiz = off + 3;
-
-	if (list->mode == 2) {
-		list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz));
-		list->dz -= list->ps2[off + 3];
-		list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
-		list->bufsiz++;
-	}
-	
-	if (list->mode == 1) {
-		list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
-		list->dz -= list->ps2[off + 3];
-		list->bufsiz++;
+    	/* Dont move during taps. But accumulate dx, dy etc. - we might drag. */
+	if (!list->tapped || (list->tapped == TAPSTATE_DRAG)) {
+		list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
+		list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
+		list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
+		list->dx -= list->ps2[off + 1];
+		list->dy -= list->ps2[off + 2];
+		list->bufsiz = off + 3;
+
+		if (list->mode == 2) {
+			list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz));
+			list->dz -= list->ps2[off + 3];
+			list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
+			list->bufsiz++;
+		}
+		
+		if (list->mode == 1) {
+			list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
+			list->dz -= list->ps2[off + 3];
+			list->bufsiz++;
+		}
+	} else {
+		list->ps2[off] = 0x08 | (list->buttons & 0x07);
+		list->ps2[off + 1] = 0;
+		list->ps2[off + 2] = 0;
+		list->bufsiz = off + 3;
+		
+		if (list->mode == 2) {
+			list->ps2[off + 3] = (list->buttons & 0x18) << 1;
+			list->bufsiz++;
+		}
 	}
 
 	if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
 	list->buffer = list->bufsiz;
+
+	switch (list->tapped) {
+		case TAPSTATE_TAPPED:
+		    	/* tap -> press and hold until we know if it is a drag */
+			if (!time_after(jiffies, list->tstamp + dragtimeout))
+			    	list->ps2[off] |= 0x01;
+			else
+				list->tapped = TAPSTATE_NONE;
+			break;
+		case TAPSTATE_DRAGORDOUBLE:
+			/* drag or doubletap -> hold button */
+			list->ps2[off] |= 0x01;
+			if (time_after(jiffies, list->tstamp + taptimeout))
+			    	list->tapped++;
+			break;
+		case TAPSTATE_DRAG:
+			/* drag -> hold button */
+			list->ps2[off] |= 0x01;
+			break;
+		case TAPSTATE_DOUBLE:
+			/* double tap (part 1) -> release button */
+			list->tapped++;
+			break;
+		case TAPSTATE_DOUBLE2:
+			/* double tap (part 2) -> click button */
+			list->ps2[off] |= 0x01;
+			list->tapped = TAPSTATE_NONE;
+			break;
+	}
 }
 
 

[-- Attachment #3: synaptics.c --]
[-- Type: text/plain, Size: 14420 bytes --]

/*
 * Synaptics touchpad driver
 *
 * Copyright (c) 2003 Jens Taprogge
 *
 * based on psmouse.c by Vojetech Pavlik,
 * http://
 * and the Synaptics XFree86 driver by Stefan Gmeiner et. al.
 */

/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 */

#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>

MODULE_AUTHOR("Jens Taprogge <jens.taprogge@rwth-aachen.de");
MODULE_DESCRIPTION("Synaptics touchpad driver");
MODULE_LICENSE("GPL");

#define PSMOUSE_CMD_SETSCALE11	0x00e6
#define PSMOUSE_CMD_SETRES	0x10e8
#define PSMOUSE_CMD_GETINFO	0x03e9
#define PSMOUSE_CMD_SETSTREAM	0x00ea
#define PSMOUSE_CMD_POLL	0x03eb	
#define PSMOUSE_CMD_GETID	0x01f2
#define PSMOUSE_CMD_GETID2	0x0100
#define PSMOUSE_CMD_SETRATE	0x10f3
#define PSMOUSE_CMD_ENABLE	0x00f4
#define PSMOUSE_CMD_RESET_DIS	0x00f6
#define PSMOUSE_CMD_RESET_BAT	0x02ff

#define PSMOUSE_RET_BAT		0xaa
#define PSMOUSE_RET_ACK		0xfa
#define PSMOUSE_RET_NAK		0xfe

#define SYN_QUE_IDENTIFY	0x00
#define SYN_QUE_CAPABILITIES	0x02
#define SYN_QUE_MODEL		0x03

#define SYN_MODE_WMODE			(1 << 0)
#define SYN_MODE_DISABLE_GESTURE	(1 << 2)
#define SYN_MODE_HIGH_RATE		(1 << 6)
#define SYN_MODE_ABSOLUTE		(1 << 7)

#define SYN_ECAP_PALMDETECT		(1 << 0)
#define SYN_ECAP_MULTIFINGER		(1 << 1)
#define SYN_ECAP_4BUTTON		(1 << 3)

#define SYN_CAP_PEN			(1 << 5)

#define SYN_MAXCOORD			0x1fff
	
struct synap {
	struct input_dev dev;
	struct serio *serio;
	char *vendor;
	char *name;
	unsigned char cmdbuf[8];
	unsigned char packet[8];
	unsigned char cmdcnt;
	unsigned char pktcnt;
	unsigned char type;
	unsigned int  model;
	unsigned int  version;
	unsigned int  caps;
	unsigned long last;
	char acking;
	char ack;
	char error;
	char devname[64];
	char phys[32];
	int  hindex;
	int finger;
	unsigned int buttons;
	int x, y;
	char w, z;
};

#define PSMOUSE_PS2	1
#define PSMOUSE_PS2PP	2
#define PSMOUSE_PS2TPP	3
#define PSMOUSE_GENPS	4
#define PSMOUSE_IMPS	5
#define PSMOUSE_IMEX	6
#define PSMOUSE_SYNAPTICS	7

static char *synap_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics" };


/*
 * check_buttons checks if buttons are pressed.
 * returns 0 if nothing else needs to be done
 */

inline static int check_buttons(struct synap *synap) 
{
	unsigned char *packet = synap->packet;

	synap->buttons |= packet[0] & 1;
	synap->buttons |= (packet[0] << 1) & (1 << 2);

	if (synap->caps & SYN_ECAP_4BUTTON) {
		if (packet[3] == 0xc2) {
		    	/* 6 buttons. not in doc */
			synap->buttons |= (packet[4] << 2) & (1 << 3);
			synap->buttons |= (packet[5] << 3) & (1 << 4);
			synap->buttons |= (packet[4] << 5) & (1 << 5);
			synap->buttons |= (packet[5] << 6) & (1 << 6);
			return 0;
		} else {
			synap->buttons |=
				(((packet[3] & 1) && 
				(packet[0]   & 1)) << 3) & (1 << 3);
			synap->buttons |=
				(((packet[3] & 2) && 
				(packet[0]   & 2)) << 3) & (1 << 4);
		}
	}
	return 1;
}

inline static void read_pos(struct synap *synap) 
{
	unsigned char *packet = synap->packet;
	
	synap->x = ((packet[3] & 0x10) << 8) |
		   ((packet[1] & 0x0f) << 8) |
		     packet[4];

	synap->y = ((packet[3] & 0x20) << 7) |
		   ((packet[1] & 0xf0) << 4) |
		     packet[5];
	
	synap->z =   packet[2];
	
	synap->w = ((packet[0] & 0x30) >> 2) |
		   ((packet[0] & 0x04) >> 1) |
		   ((packet[3] & 0x04) >> 2);
}

#if 0
inline static void check_multifinger(struct synap *synap)
{
	switch (synap->w) {
		case 0: 
			/* two fingers */
			if (synap->caps & SYN_ECAP_MULTIFINGER)
				input_report_abs(&(synap->dev), ABS_GESTURE, GES_TWOFINGER);
			break;
		case 1:
			/* three or more fingers */
			if (synap->caps & SYN_ECAP_MULTIFINGER)
				input_report_abs(&(synap->dev), ABS_GESTURE, GES_THREEFINGER);
			break;
		case 2:
			/* pen */
			if (synap->model & SYN_CAP_PEN)
				input_report_abs(&(synap->dev), ABS_GESTURE, GES_PEN);
			break;
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		        /* finger normal width */
			if (synap->caps & SYN_ECAP_PALMDETECT)
				input_report_abs(&(synap->dev), ABS_GESTURE, GES_ONEFINGER);
		/* FIXME: 9..14 */
		case 15:
			/* palm */
			if (synap->caps & SYN_ECAP_PALMDETECT)
				input_report_abs(&(synap->dev), ABS_GESTURE, GES_PALM);
	}
}
#endif

inline static void report_pos(struct synap *synap) 
{
	input_report_abs(&(synap->dev), ABS_X, synap->x);
	input_report_abs(&(synap->dev), ABS_Y, SYN_MAXCOORD - synap->y);
	input_report_abs(&(synap->dev), ABS_PRESSURE, synap->z);
}


/*
 * try to send as few events as possible
 */

static void do_buttons(struct synap *synap)
{
	struct input_dev *dev = &synap->dev;
	static int oldbuttons = 0;
	int i;
	int mask;

	for (i = 0; i < 5; i++) {
	    	mask = 1 << i;
		if ((synap->buttons) & mask) {
		    	if (!(oldbuttons & mask)) 
				input_report_key(dev, BTN_MOUSE + i, 1);
		}
		else if (oldbuttons & mask)
	                input_report_key(dev, BTN_MOUSE + i, 0);
	}
	
	oldbuttons = synap->buttons;
}


/*
 * synap_process_packet() anlyzes the PS/2 mouse packet contents and
 * reports relevant events to the input module.
 */

static void synap_process_packet(struct synap *synap)
{
	struct input_dev *dev = &synap->dev;

	synap->buttons = synap->buttons >> 8;

	if (check_buttons(synap)) {
		read_pos(synap);
//		check_multifinger(synap);
		report_pos(synap);
	}

	do_buttons(synap);
	input_sync(dev);
}

/*
 * synap_interrupt() handles incoming characters, either gathering them into
 * packets or passing them to the command routine as command output.
 */

static void synap_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
	struct synap *synap = serio->private;

	if (synap->acking) {
		switch (data) {
			case PSMOUSE_RET_ACK:
				synap->ack = 1;
				break;
			case PSMOUSE_RET_NAK:
				synap->ack = -1;
				break;
			default:
				synap->ack = 1;	/* Workaround for mice which don't ACK the Get ID command */
				if (synap->cmdcnt)
					synap->cmdbuf[--synap->cmdcnt] = data;
				break;
		}
		synap->acking = 0;
		return;
	}

	if (synap->cmdcnt) {
		synap->cmdbuf[--synap->cmdcnt] = data;
		return;
	}

	if (synap->pktcnt && time_after(jiffies, synap->last + HZ/2)) {
		printk(KERN_WARNING "synap.c: Lost synchronization, throwing %d bytes away.\n", synap->pktcnt);
		synap->pktcnt = 0;
	}
	
	synap->last = jiffies;
	synap->packet[synap->pktcnt++] = data;

	if (synap->pktcnt == 6) {
		synap_process_packet(synap);
		synap->pktcnt = 0;
		return;
	}

	if (synap->pktcnt == 1 && synap->packet[0] == PSMOUSE_RET_BAT) {
		serio_rescan(serio);
		return;
	}	
}

/*
 * synap_sendbyte() sends a byte to the mouse, and waits for acknowledge.
 * It doesn't handle retransmission, though it could - because when there would
 * be need for retransmissions, the mouse has to be replaced anyway.
 */

static int synap_sendbyte(struct synap *synap, unsigned char byte)
{
	int timeout = 10000; /* 100 msec */
	synap->ack = 0;
	synap->acking = 1;

	if (serio_write(synap->serio, byte)) {
		synap->acking = 0;
		return -1;
	}

	while (!synap->ack && timeout--) udelay(10);

	return -(synap->ack <= 0);
}

/*
 * synap_command() sends a command and its parameters to the mouse,
 * then waits for the response and puts it in the param array.
 */

static int synap_command(struct synap *synap, unsigned char *param, int command)
{
	int timeout = 500000; /* 500 msec */
	int send = (command >> 12) & 0xf;
	int receive = (command >> 8) & 0xf;
	int i;

	synap->cmdcnt = receive;

	if (command & 0xff)
		if (synap_sendbyte(synap, command & 0xff))
			return (synap->cmdcnt = 0) - 1;

	for (i = 0; i < send; i++)
		if (synap_sendbyte(synap, param[i]))
			return (synap->cmdcnt = 0) - 1;

	while (synap->cmdcnt && timeout--) udelay(1);

	for (i = 0; i < receive; i++)
		param[i] = synap->cmdbuf[(receive - 1) - i];

	if (synap->cmdcnt) 
		return (synap->cmdcnt = 0) - 1;

	return 0;
}

/*
 * synap_ps2pp_cmd() sends a PS2++ command, sliced into two bit
 * pieces through the SETRES command. This is needed to send extended
 * commands to mice on notebooks that try to understand the PS/2 protocol
 * Ugly.
 */

static int synap_syn_cmd(struct synap *synap, unsigned char *param, unsigned char command)
{
	unsigned char d;
	int i;

	if (synap_command(synap,  NULL, PSMOUSE_CMD_SETSCALE11))
		return -1;

	for (i = 6; i >= 0; i -= 2) {
		d = (command >> i) & 3;
		
		if (synap_command(synap, &d, PSMOUSE_CMD_SETRES))
			return -1;
	}

	return 0;
}


/*
 * synap_probe() probes for a PS/2 mouse.
 */

static int synaptics_probe(struct synap *synap)
{
	unsigned char param[4];

/*
 * First, we check if it's a mouse. It should send 0x00 or 0x03
 * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
 */

	param[0] = param[1] = 0xa5;

	if (synap_command(synap, param, PSMOUSE_CMD_GETID))
		return -1;

	if (param[0] == 0xab || param[0] == 0xac) {
		synap_command(synap, param, PSMOUSE_CMD_GETID2);
		return -1;
	}

	if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
		return -1;

/*
 * Then we reset and disable the mouse so that it doesn't generate events.
 */

	if (synap_command(synap, NULL, PSMOUSE_CMD_RESET_DIS))
		return -1;

        param[0] = 0;
        synap_syn_cmd(synap, param, SYN_QUE_IDENTIFY);
        synap_command(synap, param, PSMOUSE_CMD_GETINFO);

        if (param[1] == 0x47) {
		synap->vendor = "Synaptics";
		synap->name = "TouchPad ";
		synap->version = param[0] | ((param[2] & 0xf) << 8);
	        printk(KERN_INFO "synaptics: version %d.%d\n", param[2] & 0xf,
			param[0]);
	       
		synap_syn_cmd(synap, param, SYN_QUE_MODEL);
		synap_command(synap, param, PSMOUSE_CMD_GETINFO);
		synap->model = param[0] << 16 | param[1] << 8 | param[2];
		if (param[1] == 0x47) {
			/* Synaptics prior to V3.2 */
		        synap->model = 0;
		} else if (param[1] & 1)
		        /* no Synaptics at all */
			return -1;
	        printk(KERN_INFO "synaptics: model %x\n", synap->model);
		
		/* Starting with version 3.0 it is safe to query the
		 * capabilities. If bit 7 of the first byte is set capabilities
		 * are supported. */
		if (synap->version > 0x0300) {
			synap_syn_cmd(synap, param, SYN_QUE_CAPABILITIES);
			synap_command(synap, param, PSMOUSE_CMD_GETINFO);
			if (param[0] & (1<<7))
				synap->caps = param[0] << 8 | param[2];
			else
				synap->caps = 0;
		} else
			synap->caps = 0;
		
	        printk(KERN_INFO "synaptics: caps %x\n", synap->caps);
		return PSMOUSE_SYNAPTICS;
	}
	else
		return -1;
}

/*
 * synap_initialize() initializes the mouse to a sane state.
 */

static void synaptics_initialize(struct synap *synap)
{
	unsigned char param[2];
	
      
/*
 * We set the mouse report rate to a highest possible value.
 * We try 100 first in case mouse fails to set 200.
 */

	param[0] = 100;
	synap_command(synap, param, PSMOUSE_CMD_SETRATE);

	param[0] = 200;
	synap_command(synap, param, PSMOUSE_CMD_SETRATE);

/*
 * We also set the resolution and scaling.
 */

	param[0] = 3;
	synap_command(synap, param, PSMOUSE_CMD_SETRES);
	synap_command(synap,  NULL, PSMOUSE_CMD_SETSCALE11);

/*
 * special synaptics initilaization
 */
	
	synap_syn_cmd(synap, param, SYN_MODE_HIGH_RATE | SYN_MODE_WMODE |
		SYN_MODE_ABSOLUTE | SYN_MODE_DISABLE_GESTURE);
        param[0] = 0x14;
        synap_command(synap, param, PSMOUSE_CMD_SETRATE);
	
/*
 * We set the mouse into streaming mode.
 */

	synap_command(synap, param, PSMOUSE_CMD_SETSTREAM);

/*
 * Last, we enable the mouse so that we get reports from it.
 */

	if (synap_command(synap, NULL, PSMOUSE_CMD_ENABLE))
		printk(KERN_WARNING "synap.c: Failed to enable mouse on %s\n", synap->serio->phys);

}

/*
 * synap_cleanup() resets the mouse into power-on state.
 */

static void synap_cleanup(struct serio *serio)
{
	struct synap *synap = serio->private;
	unsigned char param[2];
	synap_command(synap, param, PSMOUSE_CMD_RESET_BAT);
}

/*
 * synap_disconnect() closes and frees.
 */

static void synap_disconnect(struct serio *serio)
{
	struct synap *synap = serio->private;
	input_unregister_device(&synap->dev);
	serio_close(serio);
	kfree(synap);
}

/*
 * synap_connect() is a callback form the serio module when
 * an unhandled serio port is found.
 */

static void synaptics_connect(struct serio *serio, struct serio_dev *dev)
{
	struct synap *synap;
	
	if ((serio->type & SERIO_TYPE) != SERIO_8042)
		return;

	if (!(synap = kmalloc(sizeof(struct synap), GFP_KERNEL)))
		return;

	memset(synap, 0, sizeof(struct synap));

	init_input_dev(&synap->dev);
	synap->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
	synap->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
	//| BIT(BTN_EXTRA) | BIT(BTN_SIDE);
	synap->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
	synap->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y);
	synap->dev.absbit[LONG(ABS_PRESSURE)] |= BIT(ABS_PRESSURE);
	
	synap->dev.absmin[ABS_X] =  0;
	synap->dev.absmax[ABS_X] =  SYN_MAXCOORD;
	synap->dev.absfuzz[ABS_X] = 0x2f;
	
	synap->dev.absmin[ABS_Y] =  0;
	synap->dev.absmax[ABS_Y] =  SYN_MAXCOORD;
	synap->dev.absfuzz[ABS_Y] = 0x2f;
	
	synap->dev.absmin[ABS_PRESSURE] = 0x0;
	synap->dev.absmax[ABS_PRESSURE] = 0xff;
	

	synap->serio = serio;
	synap->dev.private = synap;

	serio->private = synap;

	if (serio_open(serio, dev)) {
		kfree(synap);
		return;
	}

	if (synaptics_probe(synap) <= 0) {
		serio_close(serio);
		kfree(synap);
		return;
	}
	
	sprintf(synap->devname, "%s %s %s",
		synap_protocols[synap->type], synap->vendor, synap->name);
	sprintf(synap->phys, "%s/input0",
		serio->phys);

	synap->dev.name = synap->devname;
	synap->dev.phys = synap->phys;
	synap->dev.id.bustype = BUS_I8042;
	synap->dev.id.vendor = 0x0002;
	synap->dev.id.product = synap->type;
	synap->dev.id.version = synap->model;

	input_register_device(&synap->dev);
	
	printk(KERN_INFO "input: %s on %s\n", synap->devname, serio->phys);

	synaptics_initialize(synap);
}

static struct serio_dev synap_dev = {
	.interrupt =	synap_interrupt,
	.connect =	synaptics_connect,
	.disconnect =	synap_disconnect,
	.cleanup =	synap_cleanup,
};

#ifndef MODULE
static int __init synap_setup(char *str)
{
	return 1;
}
#endif

int __init synap_init(void)
{
	serio_register_device(&synap_dev);
	return 0;
}

void __exit synap_exit(void)
{
	serio_unregister_device(&synap_dev);
}

module_init(synap_init);
module_exit(synap_exit);

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-14 22:19 ` Vojtech Pavlik
@ 2003-06-15 12:18   ` Peter Osterlund
  2003-06-15 12:28     ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Osterlund @ 2003-06-15 12:18 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Kernel Mailing List, Joseph Fannin, Jens Taprogge

Vojtech Pavlik <vojtech@suse.cz> writes:

> On Wed, Jun 11, 2003 at 07:05:31AM +0200, Peter Osterlund wrote:
> 
> > [ I'm resending this because the previous message never showed up on
> > the list. Maybe it was too big. ]
> > 
> > Hi!
> > 
> > Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> > based on the XFree86 driver. This driver operates the touchpad in
> > absolute mode and emulates a three button mouse with two scroll
> > wheels. Features include:
> > 
> > * Multi finger tapping.
> > * Vertical and horizontal scrolling.
> > * Edge scrolling during drag operations.
> > * Palm detection.
> > * Corner tapping.
> 
> ... you may want to put these nice features into the mousedev.c driver
> for now, so that the touchpad works with standard XFree without the
> event based driver.

No need. There is now a working XFree86 driver here:

        http://w1.894.telia.com/~u89404340/touchpad/index.html

It needs the following incremental kernel patch though.


diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/Kconfig linux/drivers/input/mouse/Kconfig
--- ../../linus/main/linux/drivers/input/mouse/Kconfig	Sun Jun 15 14:10:15 2003
+++ linux/drivers/input/mouse/Kconfig	Sun Jun 15 13:53:38 2003
@@ -37,7 +37,7 @@
 	  This touchpad is found on many modern laptop computers.
 	  Note that you also need a user space driver to interpret the data
 	  generated by the kernel. A compatible driver for XFree86 is available
-	  from http://...
+	  from http://w1.894.telia.com/~u89404340/touchpad/index.html
 
 	  If unsure, say Y.
 
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.c linux/drivers/input/mouse/synaptics.c
--- ../../linus/main/linux/drivers/input/mouse/synaptics.c	Sun Jun 15 14:10:15 2003
+++ linux/drivers/input/mouse/synaptics.c	Sun Jun 15 11:39:46 2003
@@ -179,9 +179,9 @@
 static int query_hardware(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv = psmouse->private;
-	int retries = 3;
+	int retries = 0;
 
-	while ((retries++ <= 3) && synaptics_reset(psmouse))
+	while ((retries++ < 3) && synaptics_reset(psmouse))
 		printk(KERN_ERR "synaptics reset failed\n");
 
 	if (synaptics_identify(psmouse, &priv->identity))
@@ -274,8 +274,7 @@
  *	Functions to interpret the absolute mode packets
  ****************************************************************************/
 
-static void synaptics_parse_hw_state(struct synaptics_data *priv,
-				     struct synaptics_hw_state *hw)
+static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
 {
 	unsigned char *buf = priv->proto_buf;
 
@@ -347,10 +346,12 @@
 	input_report_abs(dev, ABS_Y,        hw.y);
 	input_report_abs(dev, ABS_PRESSURE, hw.z);
 
-	if (hw.w != priv->old_w) {
-		input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
-		priv->old_w = hw.w;
-	}
+	/*
+	 * This will generate an event even if w is unchanged, but that is
+	 * exactly what we want, because user space drivers may depend on
+	 * this for gesture decoding.
+	 */
+	input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
 
 	input_report_key(dev, BTN_LEFT,    hw.left);
 	input_report_key(dev, BTN_RIGHT,   hw.right);
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/synaptics.h linux/drivers/input/mouse/synaptics.h
--- ../../linus/main/linux/drivers/input/mouse/synaptics.h	Sun Jun 15 14:10:15 2003
+++ linux/drivers/input/mouse/synaptics.h	Sun Jun 15 11:40:14 2003
@@ -83,8 +83,6 @@
 	unsigned char last_byte;		/* last received byte */
 	int inSync;				/* Packets in sync */
 	int proto_buf_tail;
-
-	int old_w;				/* Previous w value */
 };
 
 #endif /* _SYNAPTICS_H */

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-15 12:18   ` Peter Osterlund
@ 2003-06-15 12:28     ` Vojtech Pavlik
  2003-06-15 15:47       ` Peter Osterlund
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-15 12:28 UTC (permalink / raw)
  To: Peter Osterlund
  Cc: Vojtech Pavlik, Kernel Mailing List, Joseph Fannin, Jens Taprogge

On Sun, Jun 15, 2003 at 02:18:57PM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <vojtech@suse.cz> writes:
> 
> > > * Multi finger tapping.
> > > * Vertical and horizontal scrolling.
> > > * Edge scrolling during drag operations.
> > > * Palm detection.
> > > * Corner tapping.
> > 
> > ... you may want to put these nice features into the mousedev.c driver
> > for now, so that the touchpad works with standard XFree without the
> > event based driver.
> 
> No need. There is now a working XFree86 driver here:
> 
>         http://w1.894.telia.com/~u89404340/touchpad/index.html

Cool.

> diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*.ko' --exclude='*~' ../../linus/main/linux/drivers/input/mouse/Kconfig linux/drivers/input/mouse/Kconfig
> --- ../../linus/main/linux/drivers/input/mouse/Kconfig	Sun Jun 15 14:10:15 2003
> +++ linux/drivers/input/mouse/Kconfig	Sun Jun 15 13:53:38 2003
> @@ -37,7 +37,7 @@
>  	  This touchpad is found on many modern laptop computers.
>  	  Note that you also need a user space driver to interpret the data
>  	  generated by the kernel. A compatible driver for XFree86 is available
> -	  from http://...
> +	  from http://w1.894.telia.com/~u89404340/touchpad/index.html

Perfect.

>>  
> -	if (hw.w != priv->old_w) {
> -		input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> -		priv->old_w = hw.w;
> -	}
> +	/*
> +	 * This will generate an event even if w is unchanged, but that is
> +	 * exactly what we want, because user space drivers may depend on
> +	 * this for gesture decoding.
> +	 */
> +	input_event(dev, EV_MSC, MSC_GESTURE, hw.w);

This assumption is not nice. It should instead rely on input_sync() /
EV_SYN, SYN_REPORT events for complete packet decoding. Can you do
something about that?

---

By the way, obviously you're skilled in X driver programming. Could you
possibly also implement an /dev/input/event mouse and tablet/touchscreen
drivers so that mousedev.c would be replaced completely?

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-15 12:28     ` Vojtech Pavlik
@ 2003-06-15 15:47       ` Peter Osterlund
  2003-06-15 17:27         ` Vojtech Pavlik
  0 siblings, 1 reply; 49+ messages in thread
From: Peter Osterlund @ 2003-06-15 15:47 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Kernel Mailing List, Joseph Fannin, Jens Taprogge

Vojtech Pavlik <vojtech@suse.cz> writes:

> On Sun, Jun 15, 2003 at 02:18:57PM +0200, Peter Osterlund wrote:
> > 
> > -	if (hw.w != priv->old_w) {
> > -		input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> > -		priv->old_w = hw.w;
> > -	}
> > +	/*
> > +	 * This will generate an event even if w is unchanged, but that is
> > +	 * exactly what we want, because user space drivers may depend on
> > +	 * this for gesture decoding.
> > +	 */
> > +	input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> 
> This assumption is not nice. It should instead rely on input_sync() /
> EV_SYN, SYN_REPORT events for complete packet decoding. Can you do
> something about that?

The X driver already relies on EV_SYN to decide when it should act on
the data from the kernel. The problem is that the packet stream is
used as a time base for gesture decoding, because the touchpad was
designed like that to make driver implementation simpler. From the
Synaptics manual:

        (Specifically, the TouchPad begins sending packets when Z is 8
        or more.) The TouchPad also begins sending packets whenever
        any button is pressed or released. Once the TouchPad begins
        transmitting, it continues to send packets for one second
        after Z falls below 8 and the buttons stop changing. The
        TouchPad does this partly to allow host software to use the
        packet stream as a time base for gesture decoding, and also to
        minimize the impact if the system occasionally drops a packet.

For example, if I press the left button, the X driver can not
immediately generate a left button down event, because maybe I will
press the right button real soon, in which case the middle mouse
button emulation will be activated and generate a middle button down
event. This and similar things are easy to implement by just counting
packets.

I guess it would be possible to rewrite the driver so that it doesn't
rely on the packet stream for timing, but it would make the driver
more complicated.

If I could generate only EV_SYN events from the kernel without the
EV_MSC events, that would of course be OK too, but I don't know if
that is possible.

The event parsing code int the X driver currently looks like this:

static Bool
SynapticsParseEventData(LocalDevicePtr local, SynapticsPrivatePtr priv,
			struct SynapticsHwState *hw)
{
    struct input_event ev;

    while (SynapticsReadEvent(priv, &ev) == Success) {
	switch (ev.type) {
	case 0x00:			    /* SYN */
	    *hw = priv->hwState;
	    return Success;
	case 0x01:			    /* KEY */
	    switch (ev.code) {
	    case 0x110:			    /* BTN_LEFT */
		priv->hwState.left = (ev.value ? TRUE : FALSE);
		break;
	    case 0x111:			    /* BTN_RIGHT */
		priv->hwState.right = (ev.value ? TRUE : FALSE);
		break;
	    case 0x115:			    /* BTN_FORWARD */
		priv->hwState.up = (ev.value ? TRUE : FALSE);
		break;
	    case 0x116:			    /* BTN_BACK */
		priv->hwState.down = (ev.value ? TRUE : FALSE);
		break;
	    }
	    break;
	case 0x03:			    /* ABS */
	    switch (ev.code) {
	    case 0x00:			    /* ABS_X */
		priv->hwState.x = ev.value;
		break;
	    case 0x01:			    /* ABS_Y */
		priv->hwState.y = ev.value;
		break;
	    case 0x18:			    /* ABS_PRESSURE */
		priv->hwState.z = ev.value;
		break;
	    }
	    break;
	case 0x04:			    /* MSC */
	    switch (ev.code) {
	    case 0x02:			    /* MSC_GESTURE */
		priv->hwState.w = ev.value;
		break;
	    }
	    break;
	}
    }
    return !Success;
}

static Bool
SynapticsReadEvent(SynapticsPrivatePtr priv, struct input_event *ev)
{
    int i, c;
    unsigned char *pBuf, u;

    for (i = 0; i < sizeof(struct input_event); i++) {
	if ((c = XisbRead(priv->buffer)) < 0)
	    return !Success;
	u = (unsigned char)c;
	pBuf = (unsigned char *)ev;
	pBuf[i] = u;
    }
    return Success;
}

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-15 15:47       ` Peter Osterlund
@ 2003-06-15 17:27         ` Vojtech Pavlik
  2003-06-18 23:41           ` Peter Osterlund
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-15 17:27 UTC (permalink / raw)
  To: Peter Osterlund
  Cc: Vojtech Pavlik, Kernel Mailing List, Joseph Fannin, Jens Taprogge

On Sun, Jun 15, 2003 at 05:47:57PM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <vojtech@suse.cz> writes:
> 
> > On Sun, Jun 15, 2003 at 02:18:57PM +0200, Peter Osterlund wrote:
> > > 
> > > -	if (hw.w != priv->old_w) {
> > > -		input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> > > -		priv->old_w = hw.w;
> > > -	}
> > > +	/*
> > > +	 * This will generate an event even if w is unchanged, but that is
> > > +	 * exactly what we want, because user space drivers may depend on
> > > +	 * this for gesture decoding.
> > > +	 */
> > > +	input_event(dev, EV_MSC, MSC_GESTURE, hw.w);
> > 
> > This assumption is not nice. It should instead rely on input_sync() /
> > EV_SYN, SYN_REPORT events for complete packet decoding. Can you do
> > something about that?
> 
> The X driver already relies on EV_SYN to decide when it should act on
> the data from the kernel. The problem is that the packet stream is
> used as a time base for gesture decoding, because the touchpad was
> designed like that to make driver implementation simpler.

We may switch to using some ABS_ or BNT_TOOL_ values for the gesture
reporting if some other than Synaptics pad is reporting those, so that
we can have one common driver. That other pad may not only not be
sending data in a different format, but most likely will also not be
sending the data one second after last real event.

> From the
> Synaptics manual:
> 
>         (Specifically, the TouchPad begins sending packets when Z is 8
>         or more.) The TouchPad also begins sending packets whenever
>         any button is pressed or released. Once the TouchPad begins
>         transmitting, it continues to send packets for one second
>         after Z falls below 8 and the buttons stop changing. The
>         TouchPad does this partly to allow host software to use the
>         packet stream as a time base for gesture decoding, and also to
>         minimize the impact if the system occasionally drops a packet.
> 
> For example, if I press the left button, the X driver can not
> immediately generate a left button down event, because maybe I will
> press the right button real soon, in which case the middle mouse
> button emulation will be activated and generate a middle button down
> event. This and similar things are easy to implement by just counting
> packets.

Well, I'd suggest using the timestamp on the packets and not just
counting them, but the decision is yours, of course. The timestamp is
very exact.

> I guess it would be possible to rewrite the driver so that it doesn't
> rely on the packet stream for timing, but it would make the driver
> more complicated.

A switch from read() to select() shouldn't be that hard ... but that
really depends on the X driver infrastructure.

> If I could generate only EV_SYN events from the kernel without the
> EV_MSC events, that would of course be OK too, but I don't know if
> that is possible.

That's unfortunately not possible. Second and following SYN_REPORT
events are filtered.

> The event parsing code int the X driver currently looks like this:
> 
> static Bool
> SynapticsParseEventData(LocalDevicePtr local, SynapticsPrivatePtr priv,
> 			struct SynapticsHwState *hw)
> {
>     struct input_event ev;
> 
>     while (SynapticsReadEvent(priv, &ev) == Success) {
> 	switch (ev.type) {
> 	case 0x00:			    /* SYN */
> 	    *hw = priv->hwState;
> 	    return Success;

Please check for SYN_REPORT, since SYN_CONFIG is pretty much different.

> 	case 0x01:			    /* KEY */
> 	    switch (ev.code) {
> 	    case 0x110:			    /* BTN_LEFT */
> 		priv->hwState.left = (ev.value ? TRUE : FALSE);
> 		break;
> 	    case 0x111:			    /* BTN_RIGHT */
> 		priv->hwState.right = (ev.value ? TRUE : FALSE);
> 		break;
> 	    case 0x115:			    /* BTN_FORWARD */
> 		priv->hwState.up = (ev.value ? TRUE : FALSE);
> 		break;
> 	    case 0x116:			    /* BTN_BACK */
> 		priv->hwState.down = (ev.value ? TRUE : FALSE);
> 		break;
> 	    }
> 	    break;
> 	case 0x03:			    /* ABS */
> 	    switch (ev.code) {
> 	    case 0x00:			    /* ABS_X */
> 		priv->hwState.x = ev.value;
> 		break;
> 	    case 0x01:			    /* ABS_Y */
> 		priv->hwState.y = ev.value;
> 		break;
> 	    case 0x18:			    /* ABS_PRESSURE */
> 		priv->hwState.z = ev.value;
> 		break;
> 	    }
> 	    break;
> 	case 0x04:			    /* MSC */
> 	    switch (ev.code) {
> 	    case 0x02:			    /* MSC_GESTURE */
> 		priv->hwState.w = ev.value;
> 		break;
> 	    }
> 	    break;
> 	}
>     }
>     return !Success;
> }
> 
> static Bool
> SynapticsReadEvent(SynapticsPrivatePtr priv, struct input_event *ev)
> {
>     int i, c;
>     unsigned char *pBuf, u;
> 
>     for (i = 0; i < sizeof(struct input_event); i++) {
> 	if ((c = XisbRead(priv->buffer)) < 0)
> 	    return !Success;
> 	u = (unsigned char)c;
> 	pBuf = (unsigned char *)ev;
> 	pBuf[i] = u;
>     }
>     return Success;
> }
> 
> -- 
> Peter Osterlund - petero2@telia.com
> http://w1.894.telia.com/~u89404340

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH] Synaptics Client/Passthrough (for Inspiron...)
  2003-06-12  8:36         ` James H. Cloos Jr.
@ 2003-06-15 21:42           ` Arne Koewing
  0 siblings, 0 replies; 49+ messages in thread
From: Arne Koewing @ 2003-06-15 21:42 UTC (permalink / raw)
  To: linux-kernel, Vojtech Pavlik

[-- Attachment #1: Type: text/plain, Size: 328 bytes --]


I've written some code for the synaptics-client-pasthroug thing
for the synaptics driver.
it's just working now, but may not be perfect/ready in any sense.


synaptics-client-full.patch
-includes the synsptics patch

synaptics-client-incremental.patch
-for kernels with synaptics-patch already applied

happy testing!!

Arne



[-- Attachment #2: synaptics-client-full.patch --]
[-- Type: text/x-patch, Size: 32353 bytes --]

Index: linux/drivers/input/mouse/synaptics.h
===================================================================
--- linux/drivers/input/mouse/synaptics.h	(revision 4)
+++ linux/drivers/input/mouse/synaptics.h	(revision 10)
@@ -0,0 +1,163 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _SYNAPTICS_H
+#define _SYNAPTICS_H
+
+/* synaptics queries */
+#define SYN_QUE_IDENTIFY		0x00
+#define SYN_QUE_MODES			0x01
+#define SYN_QUE_CAPABILITIES		0x02
+#define SYN_QUE_MODEL			0x03
+#define SYN_QUE_SERIAL_NUMBER_PREFIX	0x06
+#define SYN_QUE_SERIAL_NUMBER_SUFFIX	0x07
+#define SYN_QUE_RESOLUTION		0x08
+
+/* synatics modes */
+#define SYN_BIT_ABSOLUTE_MODE		(1 << 7)
+#define SYN_BIT_HIGH_RATE		(1 << 6)
+#define SYN_BIT_SLEEP_MODE		(1 << 3)
+#define SYN_BIT_DISABLE_GESTURE		(1 << 2)
+#define SYN_BIT_W_MODE			(1 << 0)
+
+/* synaptics model ID bits */
+#define SYN_MODEL_ROT180(m)		((m) & (1 << 23))
+#define SYN_MODEL_PORTRAIT(m)		((m) & (1 << 22))
+#define SYN_MODEL_SENSOR(m)		(((m) >> 16) & 0x3f)
+#define SYN_MODEL_HARDWARE(m)		(((m) >> 9) & 0x7f)
+#define SYN_MODEL_NEWABS(m)		((m) & (1 << 7))
+#define SYN_MODEL_PEN(m)		((m) & (1 << 6))
+#define SYN_MODEL_SIMPLIC(m)		((m) & (1 << 5))
+#define SYN_MODEL_GEOMETRY(m)		((m) & 0x0f)
+
+/* synaptics capability bits */
+#define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_CLIENT(c)               ((c) & (1 << 7))
+#define SYN_CAP_SLEEP(c)		((c) & (1 << 4))
+#define SYN_CAP_FOUR_BUTTON(c)		((c) & (1 << 3))
+#define SYN_CAP_MULTIFINGER(c)		((c) & (1 << 1))
+#define SYN_CAP_PALMDETECT(c)		((c) & (1 << 0))
+#define SYN_CAP_VALID(c)		((((c) & 0x00ff00) >> 8) == 0x47)
+
+/* synaptics modes query bits */
+#define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
+#define SYN_MODE_RATE(m)		((m) & (1 << 6))
+#define SYN_MODE_BAUD_SLEEP(m)		((m) & (1 << 3))
+#define SYN_MODE_DISABLE_GESTURE(m)	((m) & (1 << 2))
+#define SYN_MODE_PACKSIZE(m)		((m) & (1 << 1))
+#define SYN_MODE_WMODE(m)		((m) & (1 << 0))
+
+/* synaptics identify query bits */
+#define SYN_ID_MODEL(i) 		(((i) >> 4) & 0x0f)
+#define SYN_ID_MAJOR(i) 		((i) & 0x0f)
+#define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
+#define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
+
+/* client commands*/
+
+
+struct synaptics_parameters {
+	int left_edge;				/* Edge coordinates, absolute */
+	int right_edge;
+	int top_edge;
+	int bottom_edge;
+
+	int finger_low, finger_high;		/* finger detection values in Z-values */
+	int tap_time, tap_move;			/* max. tapping-time and movement in packets and coord. */
+	int emulate_mid_button_time;		/* Max time between left and right button presses to
+						   emulate a middle button press. */
+	int scroll_dist_vert;			/* Scrolling distance in absolute coordinates */
+	int scroll_dist_horiz;			/* Scrolling distance in absolute coordinates */
+	int speed;				/* Pointer motion speed */
+	int client_speed;				/* Client Pointer motion speed */
+	int edge_motion_speed;			/* Edge motion speed when dragging */
+	int updown_button_scrolling;		/* Up/Down-Button scrolling or middle/double-click */
+};
+
+/*
+ * A structure to describe the state of the touchpad hardware (buttons and pad)
+ */
+struct synaptics_hw_state {
+	int x;
+	int y;
+	int z;
+	int w;
+	int left;
+	int right;
+	int up;
+	int down;
+        int client;
+};
+
+#define SYNAPTICS_MOVE_HISTORY	5
+
+struct SynapticsTapRec {
+	int x, y;
+	unsigned int packet;
+};
+
+struct SynapticsMoveHist {
+	int x, y;
+};
+
+enum MidButtonEmulation {
+	MBE_OFF,			/* No button pressed */
+	MBE_LEFT,			/* Left button pressed, waiting for right button or timeout */
+	MBE_RIGHT,			/* Right button pressed, waiting for left button or timeout */
+	MBE_MID				/* Left and right buttons pressed, waiting for both buttons
+					   to be released */
+};
+
+struct synaptics_data {
+	struct synaptics_parameters params;
+
+	/* Data read from the touchpad */
+	unsigned long int model_id;		/* Model-ID */
+	unsigned long int capabilities; 	/* Capabilities */
+	unsigned long int identity;		/* Identification */
+
+	/* Data for normal processing */
+	unsigned char proto_buf[6];		/* Buffer for Packet */
+	unsigned char last_byte;		/* last received byte */
+	int inSync;				/* Packets in sync */
+	int proto_buf_tail;
+
+	struct SynapticsTapRec touch_on;	/* data when the touchpad is touched */
+	struct SynapticsMoveHist move_hist[SYNAPTICS_MOVE_HISTORY];
+						/* movement history */
+	int accum_dx;				/* Accumulated fractional pointer motion */
+	int accum_dy;
+	int scroll_x;				/* last x-scroll position */
+	int scroll_y;				/* last y-scroll position */
+	unsigned int count_packet_finger;	/* packet counter with finger on the touchpad */
+	unsigned int count_packet;		/* packet counter */
+	unsigned int count_packet_tapping;	/* packet counter for tapping */
+	unsigned int count_button_delay;	/* button delay for 3rd button emulation */
+	unsigned int prev_up;			/* Previous up button value, for double click emulation */
+	int finger_flag;			/* previous finger */
+	int tap, drag, doubletap;		/* feature flags */
+	int tap_left, tap_mid, tap_right;	/* tapping buttons */
+	int vert_scroll_on;			/* scrolling flag */
+	int horiz_scroll_on;			/* scrolling flag */
+	enum MidButtonEmulation mid_emu_state;	/* emulated 3rd button */
+
+	atomic_t timer_active;
+	struct timer_list timer;		/* for up/down-button repeat */
+	int repeat_buttons;			/* buttons for repeat */
+	int last_up, last_down;			/* Previous value of up/down buttons */
+
+	int finger_count;			/* tap counter for fingers */
+
+	/* For palm detection */
+	int palm;				/* Set to true when palm detected, reset to false when
+						 * palm/finger contact disappears */
+	int prev_z;				/* previous z value, for palm detection */
+	int avg_w;				/* weighted average of previous w values */
+};
+
+#endif /* _SYNAPTICS_H */
Index: linux/drivers/input/mouse/synaptics.c
===================================================================
--- linux/drivers/input/mouse/synaptics.c	(revision 4)
+++ linux/drivers/input/mouse/synaptics.c	(revision 10)
@@ -0,0 +1,939 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ *   2003 Peter Osterlund <petero2@telia.com>
+ *     Ported to 2.5 input device infrastructure.
+ *
+ *   2002 Peter Osterlund <petero2@telia.com>
+ *     patches for fast scrolling, palm detection, edge motion,
+ *     horizontal scrolling
+ *
+ *   Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
+ *     start merging tpconfig and gpm code to a xfree-input module
+ *     adding some changes and extensions (ex. 3rd and 4th button)
+ *
+ *   Copyright (c) 1999 Henry Davies <hdavies@ameritech.net> for the
+ *     absolute to relative translation code (from the gpm-source)
+ *     and some other ideas
+ *
+ *   Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
+ *   Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
+ *     code for the special synaptics commands (from the tpconfig-source)
+ *
+ *   2003 Arne Köwing <Arne.Koewing@informatik.uni-oldenburg.de>
+ *     Code for Synaptics client/passthrough  (from gpm source)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+
+static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {}
+static inline int synaptics_init(struct psmouse *psmouse) { return -1; }
+static inline void synaptics_disconnect(struct psmouse *psmouse) {}
+
+#else
+
+#include "synaptics.h"
+
+
+static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+
+/*
+ * Use the Synaptics extended ps/2 syntax to write a special command byte.
+ * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
+ *                  is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
+ *                  and synaptics_set_mode)
+ */
+static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+	int i;
+
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+		return -1;
+
+	for (i = 6; i >= 0; i -= 2) {
+		unsigned char d = (command >> i) & 3;
+		if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Send a command to the synpatics touchpad by special commands
+ */
+static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
+{
+	if (synaptics_special_cmd(psmouse, c))
+		return -1;
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+		return -1;
+	return 0;
+}
+
+static int synaptics_client_sendbyte(struct psmouse *psmouse, unsigned char c)
+{
+  unsigned char param[4];
+  synaptics_special_cmd(psmouse, c);
+  param[0]=40;
+  if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+    return -1;
+  return 0;
+}
+
+static int synaptics_client_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+  int timeout = 500000; /* 500 msec */
+  int send = (command >> 12) & 0xf;
+  int receive = (command >> 8) & 0xf;
+  int i;
+  
+  psmouse->cmdcnt = receive;
+  
+	if (command == PSMOUSE_CMD_RESET_BAT)
+                timeout = 2000000; /* 2 sec */
+
+	if (command & 0xff)
+		if (synaptics_client_sendbyte(psmouse, command & 0xff))
+			return (psmouse->cmdcnt = 0) - 1;
+
+	for (i = 0; i < send; i++)
+		if (synaptics_client_sendbyte(psmouse, param[i]))
+			return (psmouse->cmdcnt = 0) - 1;
+
+	while (psmouse->cmdcnt && timeout--) {
+	
+		if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT)
+			timeout = 100000;
+
+		if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
+		    psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
+			psmouse->cmdcnt = 0;
+			break;
+		}
+
+		udelay(1);
+	}
+
+	for (i = 0; i < receive; i++)
+		param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+	if (psmouse->cmdcnt) 
+		return (psmouse->cmdcnt = 0) - 1;
+
+	return 0;
+}
+
+/*
+static int synaptics_client_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+	int i;
+
+	if (synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_SETSCALE11))
+		return -1;
+
+	for (i = 6; i >= 0; i -= 2) {
+		unsigned char d = (command >> i) & 3;
+		if (synaptics_client_command(psmouse,&d, PSMOUSE_CMD_SETRES))
+			return -1;
+	}
+	return 0;
+}
+*/
+static int synaptics_client_reset(struct psmouse *psmouse)
+{
+  unsigned char param[2];
+  if(synaptics_client_command(psmouse,param,PSMOUSE_CMD_RESET_BAT))
+    return -1;
+  if (param[0] == 0xAA && param[1] == 0x00)
+    return 0;
+  return -1;
+}
+ 
+/*****************************************************************************
+ *	Synaptics communications functions
+ ****************************************************************************/
+
+/*
+ * Set the synaptics touchpad mode byte by special commands
+ */
+static int synaptics_set_mode(struct psmouse *psmouse, unsigned char mode)
+{
+	unsigned char param[1];
+
+	if (synaptics_special_cmd(psmouse, mode))
+		return -1;
+	param[0] = 0x14;
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+		return -1;
+	return 0;
+}
+
+static int synaptics_reset(struct psmouse *psmouse)
+{
+	unsigned char r[2];
+
+	if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
+		return -1;
+	if (r[0] == 0xAA && r[1] == 0x00)
+		return 0;
+	return -1;
+}
+
+
+/*
+ * Read the model-id bytes from the touchpad
+ * see also SYN_MODEL_* macros
+ */
+static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_id)
+{
+	unsigned char mi[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
+		return -1;
+	*model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
+	return 0;
+}
+
+/*
+ * Read the capability-bits from the touchpad
+ * see also the SYN_CAP_* macros
+ */
+static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
+{
+	unsigned char cap[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
+		return -1;
+	*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+	if (SYN_CAP_VALID(*capability))
+		return 0;
+	return -1;
+}
+
+/*
+ * Identify Touchpad
+ * See also the SYN_ID_* macros
+ */
+static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident)
+{
+	unsigned char id[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
+		return -1;
+	*ident = (id[0]<<16) | (id[1]<<8) | id[2];
+	if (SYN_ID_IS_SYNAPTICS(*ident))
+		return 0;
+	return -1;
+}
+
+static int synaptics_enable_device(struct psmouse *psmouse)
+{
+  struct synaptics_data *priv = psmouse->private;  
+  if (SYN_CAP_CLIENT(priv->capabilities))
+    {
+      if(synaptics_client_reset(psmouse))
+	return -1;
+      if(synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_ENABLE))
+	 return -1;
+    }
+  if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
+    return -1;
+  return 0;
+}
+
+static void print_ident(struct synaptics_data *priv)
+{
+	printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
+	printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
+	       SYN_ID_MINOR(priv->identity));
+
+	if (SYN_MODEL_ROT180(priv->model_id))
+		printk(KERN_INFO " 180 degree mounted touchpad\n");
+	if (SYN_MODEL_PORTRAIT(priv->model_id))
+		printk(KERN_INFO " portrait touchpad\n");
+	printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
+	if (SYN_MODEL_NEWABS(priv->model_id))
+		printk(KERN_INFO " new absolute packet format\n");
+	if (SYN_MODEL_PEN(priv->model_id))
+		printk(KERN_INFO " pen detection\n");
+
+	if (SYN_CAP_EXTENDED(priv->capabilities)) {
+		printk(KERN_INFO " Touchpad has extended capability bits\n");
+		if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+			printk(KERN_INFO " -> four buttons\n");
+		if (SYN_CAP_MULTIFINGER(priv->capabilities))
+			printk(KERN_INFO " -> multifinger detection\n");
+		if (SYN_CAP_PALMDETECT(priv->capabilities))
+			printk(KERN_INFO " -> palm detection\n");
+		if (SYN_CAP_CLIENT(priv->capabilities))
+			printk(KERN_INFO " -> client detection\n");
+	}
+}
+
+static int query_hardware(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	int retries = 3;
+
+	while ((retries++ <= 3) && synaptics_reset(psmouse))
+		printk(KERN_ERR "synaptics reset failed\n");
+
+	if (synaptics_identify(psmouse, &priv->identity))
+		return -1;
+	if (synaptics_model_id(psmouse, &priv->model_id))
+		return -1;
+	if (synaptics_capability(psmouse, &priv->capabilities))
+		return -1;
+	if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+					 SYN_BIT_HIGH_RATE |
+					 SYN_BIT_DISABLE_GESTURE |
+					 SYN_BIT_W_MODE)))
+		return -1;
+
+	synaptics_enable_device(psmouse);
+
+	print_ident(priv);
+
+	return 0;
+}
+
+static void synaptics_repeat_timer(unsigned long data)
+{
+	struct psmouse *psmouse = (void *) data;
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+
+	if (priv->repeat_buttons & 0x01)
+		input_report_rel(dev, REL_WHEEL, 1);
+	if (priv->repeat_buttons & 0x02)
+		input_report_rel(dev, REL_WHEEL, -1);
+	input_sync(dev);
+
+	if (atomic_read(&priv->timer_active))
+		mod_timer(&priv->timer, jiffies + 100 * HZ / 1000);
+}
+
+static struct synaptics_parameters default_params = {
+	.left_edge			= 1800,
+	.right_edge			= 5400,
+	.top_edge			= 4200,
+	.bottom_edge			= 1500,
+	.finger_low			= 25,
+	.finger_high			= 30,
+	.tap_time			= 15,
+	.tap_move			= 220,
+	.emulate_mid_button_time	= 6,
+	.scroll_dist_vert		= 100,
+	.scroll_dist_horiz		= 100,
+	.speed				= 25,
+	.client_speed			= 200,
+	.edge_motion_speed		= 40,
+	.updown_button_scrolling	= 1
+};
+
+static int synaptics_init(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv;
+
+	psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+	if (!priv)
+		return -1;
+	memset(priv, 0, sizeof(struct synaptics_data));
+
+	priv->inSync = 1;
+
+	/* Set default parameters */
+	priv->params = default_params;
+
+	if (query_hardware(psmouse)) {
+		printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
+		goto init_fail;
+	}
+
+	set_bit(REL_WHEEL, psmouse->dev.relbit);
+	set_bit(REL_HWHEEL, psmouse->dev.relbit);
+
+	init_timer(&priv->timer);
+	priv->timer.data = (unsigned long)psmouse;
+	priv->timer.function = synaptics_repeat_timer;
+	atomic_set(&priv->timer_active, 0);
+
+	return 0;
+
+ init_fail:
+	kfree(priv);
+	return -1;
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	atomic_set(&priv->timer_active, 0);
+	priv->repeat_buttons = 0;
+	del_timer_sync(&priv->timer);
+
+	kfree(priv);
+}
+
+/*****************************************************************************
+ *	Functions to interpret the absolute mode packets
+ ****************************************************************************/
+
+#define DIFF_TIME(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
+
+typedef enum {
+	BOTTOM_EDGE = 1,
+	TOP_EDGE = 2,
+	LEFT_EDGE = 4,
+	RIGHT_EDGE = 8,
+	LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
+	RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
+	RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
+	LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE
+} edge_type;
+
+static edge_type
+edge_detection(struct synaptics_data *priv, int x, int y)
+{
+	edge_type edge = 0;
+
+	if (x > priv->params.right_edge)
+		edge |= RIGHT_EDGE;
+	else if (x < priv->params.left_edge)
+		edge |= LEFT_EDGE;
+
+	if (y > priv->params.top_edge)
+		edge |= TOP_EDGE;
+	else if (y < priv->params.bottom_edge)
+		edge |= BOTTOM_EDGE;
+
+	return edge;
+}
+
+#define MOVE_HIST(a) ((priv->count_packet_finger-(a))%SYNAPTICS_MOVE_HISTORY)
+
+static inline int clamp(int val, int min, int max)
+{
+	if (val < min)
+		return min;
+	else if (val < max)
+		return val;
+	else
+		return max;
+}
+
+static void synaptics_parse_hw_state(struct synaptics_data *priv,
+				     struct synaptics_hw_state *hw)
+{
+	unsigned char *buf = priv->proto_buf;
+	hw->w = (((buf[0] & 0x30) >> 2) |
+		 ((buf[0] & 0x04) >> 1) |
+		 ((buf[3] & 0x04) >> 2));
+	hw->client =0;
+	if (SYN_CAP_EXTENDED(priv->capabilities) &&
+	    (SYN_CAP_CLIENT(priv->capabilities))) {
+	  if(hw->w == 0x03)
+	    {
+	      printk(KERN_DEBUG "SYN client pkg.\n");
+	      hw->client=1;
+	    }
+	}
+	if (hw->client){
+	  if (buf[4])
+	    hw->x = (buf[1] & 0x10) ? buf[4]-256:buf[4];
+	  else
+	    hw->x = 0;
+	  if (buf[5])
+	    hw->y = -((buf[1] & 0x20) ? buf[5]-256:buf[5]);
+	  else
+	    hw->y = 0;
+	}
+
+	else {
+	  hw->x = (((buf[3] & 0x10) << 8) |
+		 ((buf[1] & 0x0f) << 8) |
+		 buf[4]);
+	  hw->y = (((buf[3] & 0x20) << 7) |
+		 ((buf[1] & 0xf0) << 4) |
+		 buf[5]);
+	}
+	hw->z = buf[2];
+	
+	hw->left  = (buf[0] & 0x01) ? 1 : 0;
+	hw->right = (buf[0] & 0x2) ? 1 : 0;
+	hw->up    = 0;
+	hw->down  = 0;
+	if (SYN_CAP_EXTENDED(priv->capabilities) &&
+	    (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
+		hw->up = ((buf[3] & 0x01)) ? 1 : 0;
+		if (hw->left)
+			hw->up = !hw->up;
+		hw->down = ((buf[3] & 0x02)) ? 1 : 0;
+		if (hw->right)
+			hw->down = !hw->down;
+	}
+
+}
+
+static int synaptics_emulate_mid_button(struct synaptics_data *priv,
+					struct synaptics_hw_state *hw)
+{
+	int timeout = (DIFF_TIME(priv->count_packet, priv->count_button_delay) >=
+		       priv->params.emulate_mid_button_time);
+	int mid = 0;
+
+	for (;;) {
+		switch (priv->mid_emu_state) {
+		case MBE_OFF:
+			if (hw->left) {
+				priv->mid_emu_state = MBE_LEFT;
+			} else if (hw->right) {
+				priv->mid_emu_state = MBE_RIGHT;
+			} else {
+				priv->count_button_delay = priv->count_packet;
+				goto done;
+			}
+			break;
+		case MBE_LEFT:
+			if (!hw->left || timeout) {
+				hw->left = 1;
+				priv->mid_emu_state = MBE_OFF;
+				goto done;
+			} else if (hw->right) {
+				priv->mid_emu_state = MBE_MID;
+			} else {
+				hw->left = 0;
+				goto done;
+			}
+			break;
+		case MBE_RIGHT:
+			if (!hw->right || timeout) {
+				hw->right = 1;
+				priv->mid_emu_state = MBE_OFF;
+				goto done;
+			} else if (hw->left) {
+				priv->mid_emu_state = MBE_MID;
+			} else {
+				hw->right = 0;
+				goto done;
+			}
+			break;
+		case MBE_MID:
+			if (!hw->left && !hw->right) {
+				priv->mid_emu_state = MBE_OFF;
+			} else {
+				mid = 1;
+				hw->left = hw->right = 0;
+				goto done;
+			}
+			break;
+		}
+	}
+ done:
+	return mid;
+}
+
+static int synaptics_detect_finger(struct synaptics_data *priv,
+				   const struct synaptics_hw_state *hw)
+{
+	const struct synaptics_parameters *para = &priv->params;
+	int finger;
+
+	/* finger detection thru pressure and threshold */
+	finger = (((hw->z > para->finger_high) && !priv->finger_flag) ||
+		  ((hw->z > para->finger_low)  &&  priv->finger_flag));
+
+	/* palm detection */
+	if (!SYN_CAP_EXTENDED(priv->capabilities) || !SYN_CAP_PALMDETECT(priv->capabilities))
+		return finger;
+
+	if (finger) {
+		if ((hw->z > 200) && (hw->w > 10))
+			priv->palm = 1;
+	} else {
+		priv->palm = 0;
+	}
+	if (hw->x == 0)
+		priv->avg_w = 0;
+	else
+		priv->avg_w += (hw->w - priv->avg_w + 1) / 2;
+	if (finger && !priv->finger_flag) {
+		int safe_w = max_t(int, hw->w, priv->avg_w);
+		if (hw->w < 2)
+			finger = 1;		/* more than one finger -> not a palm */
+		else if ((safe_w < 6) && (priv->prev_z < para->finger_high))
+			finger = 1;		/* thin finger, distinct touch -> not a palm */
+		else if ((safe_w < 7) && (priv->prev_z < para->finger_high / 2))
+			finger = 1;		/* thin finger, distinct touch -> not a palm */
+		else if (hw->z > priv->prev_z + 1)
+			finger = 0;		/* z not stable, may be a palm */
+		else if (hw->z < priv->prev_z - 5)
+			finger = 0;		/* z not stable, may be a palm */
+		else if (hw->z > 200)
+			finger = 0;		/* z too large -> probably palm */
+		else if (hw->w > 10)
+			finger = 0;		/* w too large -> probably palm */
+	}
+	priv->prev_z = hw->z;
+
+	return finger;
+}
+
+/*
+ *  called for each full received packet from the touchpad
+ */
+static void synaptics_process_packet(struct psmouse *psmouse)
+{
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+	const struct synaptics_parameters *para = &priv->params;
+	struct synaptics_hw_state hw;
+	int dx, dy;
+	edge_type edge;
+	int scroll_up, scroll_down, scroll_left, scroll_right;
+	int double_click;
+
+	int finger;
+	int mid;
+
+	synaptics_parse_hw_state(priv, &hw);
+
+	edge = edge_detection(priv, hw.x, hw.y);
+
+	/*
+	 * client-mouse handling
+	 */
+	
+	
+	mid = synaptics_emulate_mid_button(priv, &hw);
+
+	/* Up/Down-button scrolling or middle/double-click */
+	double_click = 0;
+	if (!para->updown_button_scrolling) {
+		if (down) {
+			/* map down-button to middle-button */
+			mid = 1;
+		}
+
+		if (hw.up) {
+			/* up-button generates double-click */
+			if (!priv->prev_up)
+				double_click = 1;
+		}
+		priv->prev_up = hw.up;
+
+		/* reset up/down button events */
+		hw.up = hw.down = 0;
+	}
+
+	if(hw.client)
+	  finger=0;
+	else 
+	  finger = synaptics_detect_finger(priv, &hw);
+	       
+	/* tap and drag detection */
+	if (priv->palm) {
+		/* Palm detected, skip tap/drag processing */
+	} else if (finger && !priv->finger_flag) {
+		/* touched */
+		if (priv->tap) {
+			priv->drag = 1; /* drag gesture */
+		}
+		priv->touch_on.x = hw.x;
+		priv->touch_on.y = hw.y;
+		priv->touch_on.packet = priv->count_packet;
+	} else if (!finger && priv->finger_flag) {
+		/* untouched */
+		/* check if
+		   1. the tap is in tap_time
+		   2. the max movement is in tap_move or more than one finger is tapped */
+		if ((DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) &&
+		    (((abs(hw.x - priv->touch_on.x) < para->tap_move) &&
+		      (abs(hw.y - priv->touch_on.y) < para->tap_move)) ||
+		     priv->finger_count)) {
+			if (priv->drag) {
+				priv->doubletap = 1;
+				priv->tap = 0;
+			} else {
+				priv->count_packet_tapping = priv->count_packet;
+				priv->tap = 1;
+				switch (priv->finger_count) {
+				case 0:
+					switch (edge) {
+					case RIGHT_TOP_EDGE:
+						priv->tap_mid = 1;
+						break;
+					case RIGHT_BOTTOM_EDGE:
+						priv->tap_right = 1;
+						break;
+					case LEFT_TOP_EDGE:
+						break;
+					case LEFT_BOTTOM_EDGE:
+						break;
+					default:
+						priv->tap_left = 1;
+					}
+					break;
+				case 2:
+					priv->tap_mid = 1;
+					break;
+				case 3: 
+					priv->tap_right = 1;
+					break;
+				default:
+					priv->tap_left = 1;
+				}
+			}
+		}
+		priv->drag = 0;
+	}
+
+	/* detecting 2 and 3 fingers */
+	if (finger && /* finger is on the surface */
+	    (DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) &&
+	    SYN_CAP_MULTIFINGER(priv->capabilities)) {
+		/* count fingers when reported */
+		if ((hw.w == 0) && (priv->finger_count == 0))
+			priv->finger_count = 2;
+		if (hw.w == 1)
+			priv->finger_count = 3;
+	} else {
+		priv->finger_count = 0;
+	}
+
+	/* reset tapping button flags */
+	if (!priv->tap && !priv->drag && !priv->doubletap) {
+		priv->tap_left = priv->tap_mid = priv->tap_right = 0;
+	}
+
+	/* tap processing */
+	if (priv->tap &&
+	    (DIFF_TIME(priv->count_packet, priv->count_packet_tapping) < para->tap_time)) {
+		hw.left  |= priv->tap_left;
+		mid      |= priv->tap_mid;
+		hw.right |= priv->tap_right;
+	} else {
+		priv->tap = 0;
+	}
+	
+	/* drag processing */
+	if (priv->drag) {
+		hw.left  |= priv->tap_left;
+		mid      |= priv->tap_mid;
+		hw.right |= priv->tap_right;
+	}
+
+	/* double tap processing */
+	if (priv->doubletap && !priv->finger_flag) {
+		hw.left  |= priv->tap_left;
+		mid      |= priv->tap_mid;
+		hw.right |= priv->tap_right;
+		priv->doubletap = 0;
+	}
+
+	/* scroll detection */
+	if (finger && !priv->finger_flag) {
+		if (edge & RIGHT_EDGE) {
+			priv->vert_scroll_on = 1;
+			priv->scroll_y = hw.y;
+		}
+		if (edge & BOTTOM_EDGE) {
+			priv->horiz_scroll_on = 1;
+			priv->scroll_x = hw.x;
+		}
+	}
+	if (priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger || priv->palm)) {
+		priv->vert_scroll_on = 0;
+	}
+	if (priv->horiz_scroll_on && (!(edge & BOTTOM_EDGE) || !finger || priv->palm)) {
+		priv->horiz_scroll_on = 0;
+	}
+
+	/* scroll processing */
+	scroll_up = 0;
+	scroll_down = 0;
+	if (priv->vert_scroll_on) {
+		/* + = up, - = down */
+		while (hw.y - priv->scroll_y > para->scroll_dist_vert) {
+			scroll_up++;
+			priv->scroll_y += para->scroll_dist_vert;
+		}
+		while (hw.y - priv->scroll_y < -para->scroll_dist_vert) {
+			scroll_down++;
+			priv->scroll_y -= para->scroll_dist_vert;
+		}
+	}
+	scroll_left = 0;
+	scroll_right = 0;
+	if (priv->horiz_scroll_on) {
+		/* + = right, - = left */
+		while (hw.x - priv->scroll_x > para->scroll_dist_horiz) {
+			scroll_right++;
+			priv->scroll_x += para->scroll_dist_horiz;
+		}
+		while (hw.x - priv->scroll_x < -para->scroll_dist_horiz) {
+			scroll_left++;
+			priv->scroll_x -= para->scroll_dist_horiz;
+		}
+	}
+
+	/* client movement */
+	dx = dy = 0;
+	if (hw.client){
+	  dx=hw.x;
+	  dy=hw.y;
+	  priv->accum_dx += dx * para->client_speed ;
+	  priv->accum_dy += dy * para->client_speed ;
+	  
+	  dx = priv->accum_dx / 256;
+	  dy = priv->accum_dy / 256;
+	  
+	  priv->accum_dx -= dx * 256;
+	  priv->accum_dy -= dy * 256;
+	}
+
+	/* movement */
+	if (finger&& !priv->vert_scroll_on && !priv->horiz_scroll_on &&
+	    !priv->finger_count && !priv->palm) {
+		if (priv->count_packet_finger > 3) { /* min. 3 packets */
+			int h2x = priv->move_hist[MOVE_HIST(2)].x;
+			int h2y = priv->move_hist[MOVE_HIST(2)].y;
+
+			dx =  ((hw.x - h2x) / 2);
+			dy = -((hw.y - h2y) / 2);
+
+			if (priv->drag) {
+				if (edge & RIGHT_EDGE) {
+					dx += clamp(para->edge_motion_speed - dx,
+						    0, para->edge_motion_speed);
+				} else if (edge & LEFT_EDGE) {
+					dx -= clamp(para->edge_motion_speed + dx,
+						    0, para->edge_motion_speed);
+				}
+				if (edge & TOP_EDGE) {
+					dy -= clamp(para->edge_motion_speed + dy,
+						    0, para->edge_motion_speed);
+				} else if (edge & BOTTOM_EDGE) {
+					dy += clamp(para->edge_motion_speed - dy,
+						    0, para->edge_motion_speed);
+				}
+			}
+
+			/* Scale dx and dy to get pointer motion values */
+			priv->accum_dx += dx * para->speed;
+			priv->accum_dy += dy * para->speed;
+
+			dx = priv->accum_dx / 256;
+			dy = priv->accum_dy / 256;
+
+			priv->accum_dx -= dx * 256;
+			priv->accum_dy -= dy * 256;
+		}
+
+		priv->count_packet_finger++;
+	} else {
+		priv->count_packet_finger = 0;
+	}
+
+	priv->count_packet++;
+
+	/* Flags */
+	priv->finger_flag = finger;
+
+	/* generate a history of the absolute positions */
+	if(!hw.client){
+	  priv->move_hist[MOVE_HIST(0)].x = hw.x;
+	  priv->move_hist[MOVE_HIST(0)].y = hw.y;
+	}
+	/* repeat timer for up/down buttons */
+	/* when you press a button the packets will only send for a second, so
+	   we have to use a timer for repeating */
+	if ((hw.up || hw.down) && para->updown_button_scrolling) {
+		if (!atomic_read(&priv->timer_active)) {
+			priv->repeat_buttons = ((hw.up    ? 0x01 : 0) |
+						(hw.down  ? 0x02 : 0));
+			atomic_set(&priv->timer_active, 1);
+			mod_timer(&priv->timer, jiffies + 200 * HZ / 1000);
+		}
+	} else if (atomic_read(&priv->timer_active)) {
+		atomic_set(&priv->timer_active, 0);
+		priv->repeat_buttons = 0;
+		del_timer_sync(&priv->timer);
+	}
+
+	/* Post events */
+	input_report_rel(dev, REL_X, dx);
+	input_report_rel(dev, REL_Y, dy);
+
+	input_report_key(dev, BTN_LEFT,   hw.left);
+	input_report_key(dev, BTN_MIDDLE, mid);
+	input_report_key(dev, BTN_RIGHT,  hw.right);
+
+	if (hw.up && !priv->last_up)
+		input_report_rel(dev, REL_WHEEL, 1);
+	if (hw.down && !priv->last_down)
+		input_report_rel(dev, REL_WHEEL, -1);
+	priv->last_up = hw.up;
+	priv->last_down = hw.down;
+
+	input_report_rel(dev, REL_WHEEL, scroll_up - scroll_down);
+	input_report_rel(dev, REL_HWHEEL, scroll_right - scroll_left);
+
+	if (double_click) {
+		int i;
+		for (i = 0; i < 2; i++) {
+			input_report_key(dev, BTN_LEFT, !hw.left);
+			input_report_key(dev, BTN_LEFT, hw.left);
+		}
+	}
+
+	input_sync(dev);
+}
+
+static void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+	unsigned char *pBuf = priv->proto_buf;
+	unsigned char u = psmouse->packet[0];
+
+	input_regs(dev, regs);
+
+	pBuf[priv->proto_buf_tail++] = u;
+
+	/* check first byte */
+	if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
+		priv->inSync = 0;
+		priv->proto_buf_tail = 0;
+		printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+		return;
+	}
+
+	/* check 4th byte */
+	if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
+		priv->inSync = 0;
+		priv->proto_buf_tail = 0;
+		printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+		return;
+	}
+
+	if (priv->proto_buf_tail >= 6) { /* Full packet received */
+		if (!priv->inSync) {
+			priv->inSync = 1;
+			printk(KERN_NOTICE "Synaptics driver resynced.\n");
+		}
+		synaptics_process_packet(psmouse);
+		priv->proto_buf_tail = 0;
+	}
+}
+
+#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */

[-- Attachment #3: synaptics-client-incremental.patch --]
[-- Type: text/x-patch, Size: 8983 bytes --]

Index: linux/drivers/input/mouse/synaptics.h
===================================================================
--- linux/drivers/input/mouse/synaptics.h	(revision 5)
+++ linux/drivers/input/mouse/synaptics.h	(revision 10)
@@ -37,6 +37,7 @@
 
 /* synaptics capability bits */
 #define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_CLIENT(c)               ((c) & (1 << 7))
 #define SYN_CAP_SLEEP(c)		((c) & (1 << 4))
 #define SYN_CAP_FOUR_BUTTON(c)		((c) & (1 << 3))
 #define SYN_CAP_MULTIFINGER(c)		((c) & (1 << 1))
@@ -57,7 +58,9 @@
 #define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
 #define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
 
+/* client commands*/
 
+
 struct synaptics_parameters {
 	int left_edge;				/* Edge coordinates, absolute */
 	int right_edge;
@@ -71,6 +74,7 @@
 	int scroll_dist_vert;			/* Scrolling distance in absolute coordinates */
 	int scroll_dist_horiz;			/* Scrolling distance in absolute coordinates */
 	int speed;				/* Pointer motion speed */
+	int client_speed;				/* Client Pointer motion speed */
 	int edge_motion_speed;			/* Edge motion speed when dragging */
 	int updown_button_scrolling;		/* Up/Down-Button scrolling or middle/double-click */
 };
@@ -87,6 +91,7 @@
 	int right;
 	int up;
 	int down;
+        int client;
 };
 
 #define SYNAPTICS_MOVE_HISTORY	5
Index: linux/drivers/input/mouse/synaptics.c
===================================================================
--- linux/drivers/input/mouse/synaptics.c	(revision 5)
+++ linux/drivers/input/mouse/synaptics.c	(revision 10)
@@ -20,6 +20,9 @@
  *   Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
  *     code for the special synaptics commands (from the tpconfig-source)
  *
+ *   2003 Arne Köwing <Arne.Koewing@informatik.uni-oldenburg.de>
+ *     Code for Synaptics client/passthrough  (from gpm source)
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published by
  * the Free Software Foundation.
@@ -62,6 +65,7 @@
 	return 0;
 }
 
+
 /*
  * Send a command to the synpatics touchpad by special commands
  */
@@ -74,6 +78,85 @@
 	return 0;
 }
 
+static int synaptics_client_sendbyte(struct psmouse *psmouse, unsigned char c)
+{
+  unsigned char param[4];
+  synaptics_special_cmd(psmouse, c);
+  param[0]=40;
+  if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+    return -1;
+  return 0;
+}
+
+static int synaptics_client_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+  int timeout = 500000; /* 500 msec */
+  int send = (command >> 12) & 0xf;
+  int receive = (command >> 8) & 0xf;
+  int i;
+  
+  psmouse->cmdcnt = receive;
+  
+	if (command == PSMOUSE_CMD_RESET_BAT)
+                timeout = 2000000; /* 2 sec */
+
+	if (command & 0xff)
+		if (synaptics_client_sendbyte(psmouse, command & 0xff))
+			return (psmouse->cmdcnt = 0) - 1;
+
+	for (i = 0; i < send; i++)
+		if (synaptics_client_sendbyte(psmouse, param[i]))
+			return (psmouse->cmdcnt = 0) - 1;
+
+	while (psmouse->cmdcnt && timeout--) {
+	
+		if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT)
+			timeout = 100000;
+
+		if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
+		    psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
+			psmouse->cmdcnt = 0;
+			break;
+		}
+
+		udelay(1);
+	}
+
+	for (i = 0; i < receive; i++)
+		param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+	if (psmouse->cmdcnt) 
+		return (psmouse->cmdcnt = 0) - 1;
+
+	return 0;
+}
+
+/*
+static int synaptics_client_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+	int i;
+
+	if (synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_SETSCALE11))
+		return -1;
+
+	for (i = 6; i >= 0; i -= 2) {
+		unsigned char d = (command >> i) & 3;
+		if (synaptics_client_command(psmouse,&d, PSMOUSE_CMD_SETRES))
+			return -1;
+	}
+	return 0;
+}
+*/
+static int synaptics_client_reset(struct psmouse *psmouse)
+{
+  unsigned char param[2];
+  if(synaptics_client_command(psmouse,param,PSMOUSE_CMD_RESET_BAT))
+    return -1;
+  if (param[0] == 0xAA && param[1] == 0x00)
+    return 0;
+  return -1;
+}
+ 
 /*****************************************************************************
  *	Synaptics communications functions
  ****************************************************************************/
@@ -104,6 +187,7 @@
 	return -1;
 }
 
+
 /*
  * Read the model-id bytes from the touchpad
  * see also SYN_MODEL_* macros
@@ -152,9 +236,17 @@
 
 static int synaptics_enable_device(struct psmouse *psmouse)
 {
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
-		return -1;
-	return 0;
+  struct synaptics_data *priv = psmouse->private;  
+  if (SYN_CAP_CLIENT(priv->capabilities))
+    {
+      if(synaptics_client_reset(psmouse))
+	return -1;
+      if(synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_ENABLE))
+	 return -1;
+    }
+  if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
+    return -1;
+  return 0;
 }
 
 static void print_ident(struct synaptics_data *priv)
@@ -181,6 +273,8 @@
 			printk(KERN_INFO " -> multifinger detection\n");
 		if (SYN_CAP_PALMDETECT(priv->capabilities))
 			printk(KERN_INFO " -> palm detection\n");
+		if (SYN_CAP_CLIENT(priv->capabilities))
+			printk(KERN_INFO " -> client detection\n");
 	}
 }
 
@@ -240,6 +334,7 @@
 	.scroll_dist_vert		= 100,
 	.scroll_dist_horiz		= 100,
 	.speed				= 25,
+	.client_speed			= 200,
 	.edge_motion_speed		= 40,
 	.updown_button_scrolling	= 1
 };
@@ -340,24 +435,43 @@
 				     struct synaptics_hw_state *hw)
 {
 	unsigned char *buf = priv->proto_buf;
+	hw->w = (((buf[0] & 0x30) >> 2) |
+		 ((buf[0] & 0x04) >> 1) |
+		 ((buf[3] & 0x04) >> 2));
+	hw->client =0;
+	if (SYN_CAP_EXTENDED(priv->capabilities) &&
+	    (SYN_CAP_CLIENT(priv->capabilities))) {
+	  if(hw->w == 0x03)
+	    {
+	      printk(KERN_DEBUG "SYN client pkg.\n");
+	      hw->client=1;
+	    }
+	}
+	if (hw->client){
+	  if (buf[4])
+	    hw->x = (buf[1] & 0x10) ? buf[4]-256:buf[4];
+	  else
+	    hw->x = 0;
+	  if (buf[5])
+	    hw->y = -((buf[1] & 0x20) ? buf[5]-256:buf[5]);
+	  else
+	    hw->y = 0;
+	}
 
-	hw->x = (((buf[3] & 0x10) << 8) |
+	else {
+	  hw->x = (((buf[3] & 0x10) << 8) |
 		 ((buf[1] & 0x0f) << 8) |
 		 buf[4]);
-	hw->y = (((buf[3] & 0x20) << 7) |
+	  hw->y = (((buf[3] & 0x20) << 7) |
 		 ((buf[1] & 0xf0) << 4) |
 		 buf[5]);
-
+	}
 	hw->z = buf[2];
-	hw->w = (((buf[0] & 0x30) >> 2) |
-		 ((buf[0] & 0x04) >> 1) |
-		 ((buf[3] & 0x04) >> 2));
-
+	
 	hw->left  = (buf[0] & 0x01) ? 1 : 0;
 	hw->right = (buf[0] & 0x2) ? 1 : 0;
 	hw->up    = 0;
 	hw->down  = 0;
-
 	if (SYN_CAP_EXTENDED(priv->capabilities) &&
 	    (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
 		hw->up = ((buf[3] & 0x01)) ? 1 : 0;
@@ -367,6 +481,7 @@
 		if (hw->right)
 			hw->down = !hw->down;
 	}
+
 }
 
 static int synaptics_emulate_mid_button(struct synaptics_data *priv,
@@ -494,6 +609,11 @@
 
 	edge = edge_detection(priv, hw.x, hw.y);
 
+	/*
+	 * client-mouse handling
+	 */
+	
+	
 	mid = synaptics_emulate_mid_button(priv, &hw);
 
 	/* Up/Down-button scrolling or middle/double-click */
@@ -515,8 +635,11 @@
 		hw.up = hw.down = 0;
 	}
 
-	finger = synaptics_detect_finger(priv, &hw);
-
+	if(hw.client)
+	  finger=0;
+	else 
+	  finger = synaptics_detect_finger(priv, &hw);
+	       
 	/* tap and drag detection */
 	if (priv->palm) {
 		/* Palm detected, skip tap/drag processing */
@@ -601,7 +724,7 @@
 	} else {
 		priv->tap = 0;
 	}
-
+	
 	/* drag processing */
 	if (priv->drag) {
 		hw.left  |= priv->tap_left;
@@ -663,9 +786,23 @@
 		}
 	}
 
+	/* client movement */
+	dx = dy = 0;
+	if (hw.client){
+	  dx=hw.x;
+	  dy=hw.y;
+	  priv->accum_dx += dx * para->client_speed ;
+	  priv->accum_dy += dy * para->client_speed ;
+	  
+	  dx = priv->accum_dx / 256;
+	  dy = priv->accum_dy / 256;
+	  
+	  priv->accum_dx -= dx * 256;
+	  priv->accum_dy -= dy * 256;
+	}
+
 	/* movement */
-	dx = dy = 0;
-	if (finger && !priv->vert_scroll_on && !priv->horiz_scroll_on &&
+	if (finger&& !priv->vert_scroll_on && !priv->horiz_scroll_on &&
 	    !priv->finger_count && !priv->palm) {
 		if (priv->count_packet_finger > 3) { /* min. 3 packets */
 			int h2x = priv->move_hist[MOVE_HIST(2)].x;
@@ -713,9 +850,10 @@
 	priv->finger_flag = finger;
 
 	/* generate a history of the absolute positions */
-	priv->move_hist[MOVE_HIST(0)].x = hw.x;
-	priv->move_hist[MOVE_HIST(0)].y = hw.y;
-
+	if(!hw.client){
+	  priv->move_hist[MOVE_HIST(0)].x = hw.x;
+	  priv->move_hist[MOVE_HIST(0)].y = hw.y;
+	}
 	/* repeat timer for up/down buttons */
 	/* when you press a button the packets will only send for a second, so
 	   we have to use a timer for repeating */

[-- Attachment #4: Type: text/plain, Size: 1261 bytes --]



> Have you tested with Arne Koewing <ark@gmx.net>'s synaptics_reset patch:
>
> diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
> --- a/drivers/input/mouse/psmouse.c     Thu Jun 12 04:26:48 2003
> +++ b/drivers/input/mouse/psmouse.c     Thu Jun 12 04:26:48 2003
> @@ -345,6 +345,7 @@
>                    thing up. */
>                 psmouse->vendor = "Synaptics";
>                 psmouse->name = "TouchPad";
> +              psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT);
>                 return PSMOUSE_PS2;
>         }
>
>
> w/o that patch, using 2.5 on a dell laptop disables the track point
> until something else causes a rest on the ps/2 bus, such as hot-
> plugging an external ps2 mouse or suspending and resuming the box.
>
> For that matter, does running the touchpad in absolute mode affect
> the track point at all?
>
> (I'm primarily just interested in stopping the unintended mouse button
> events I get from the pad's default config....)
>
> -JimC
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-14  8:55                                     ` Vojtech Pavlik
@ 2003-06-16 21:28                                       ` James Simmons
  0 siblings, 0 replies; 49+ messages in thread
From: James Simmons @ 2003-06-16 21:28 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Peter Berg Larsen, linux-kernel

> > > Definitely. Still it doesn't cover the multi-tap/gesture stuff.
> > 
> > How about EV_AREA
> > codes = "which area"  1, 2, 3
> > value = "How big of a area" 
> > 
> > struct input_event {
> >         struct timeval time;
> >         __u16 type;               EV_AREA
> >         __u16 code;	          AREA_1
> >         __s32 value;		  20
> > };
> 
> Nice, but no devices are reporting such detailed info. If you have a
> multi-finger tap, then the area reported is the area between the
> fingers. 

:-(


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-15 17:27         ` Vojtech Pavlik
@ 2003-06-18 23:41           ` Peter Osterlund
  2003-06-19  6:03             ` Vojtech Pavlik
  2003-06-23 16:30             ` Andreas Jellinghaus
  0 siblings, 2 replies; 49+ messages in thread
From: Peter Osterlund @ 2003-06-18 23:41 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Kernel Mailing List, Joseph Fannin, Jens Taprogge

Vojtech Pavlik <vojtech@suse.cz> writes:

> On Sun, Jun 15, 2003 at 05:47:57PM +0200, Peter Osterlund wrote:
> > 
> > The X driver already relies on EV_SYN to decide when it should act on
> > the data from the kernel. The problem is that the packet stream is
> > used as a time base for gesture decoding, because the touchpad was
> > designed like that to make driver implementation simpler.
> 
> We may switch to using some ABS_ or BNT_TOOL_ values for the gesture
> reporting if some other than Synaptics pad is reporting those, so that
> we can have one common driver. That other pad may not only not be
> sending data in a different format, but most likely will also not be
> sending the data one second after last real event.
...
> Well, I'd suggest using the timestamp on the packets and not just
> counting them, but the decision is yours, of course. The timestamp is
> very exact.

I have modified the X driver now, so that it doesn't depend on packets
arriving one second after the last event, and so that it uses wall
clock time instead of counting packets. This version therefore works
with an unpatched 2.5.72 kernel. It is available here:

        http://w1.894.telia.com/~u89404340/touchpad/index.html

I think the following patch should be applied anyway. It adds a link
to the html page, fixes bogus reset retry logic and fixes a deviation
from the coding style preferred by Linus.


diff -u -r linux/drivers/input/mouse.orig/Kconfig linux/drivers/input/mouse/Kconfig
--- linux/drivers/input/mouse.orig/Kconfig	2003-06-19 01:30:39.000000000 +0200
+++ linux/drivers/input/mouse/Kconfig	2003-06-17 22:03:17.000000000 +0200
@@ -37,7 +37,7 @@
 	  This touchpad is found on many modern laptop computers.
 	  Note that you also need a user space driver to interpret the data
 	  generated by the kernel. A compatible driver for XFree86 is available
-	  from http://...
+	  from http://w1.894.telia.com/~u89404340/touchpad/index.html
 
 	  If unsure, say Y.
 
diff -u -r linux/drivers/input/mouse.orig/synaptics.c linux/drivers/input/mouse/synaptics.c
--- linux/drivers/input/mouse.orig/synaptics.c	2003-06-19 01:30:47.000000000 +0200
+++ linux/drivers/input/mouse/synaptics.c	2003-06-17 22:06:48.000000000 +0200
@@ -171,9 +171,9 @@
 static int query_hardware(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv = psmouse->private;
-	int retries = 3;
+	int retries = 0;
 
-	while ((retries++ <= 3) && synaptics_reset(psmouse))
+	while ((retries++ < 3) && synaptics_reset(psmouse))
 		printk(KERN_ERR "synaptics reset failed\n");
 
 	if (synaptics_identify(psmouse, &priv->identity))
@@ -266,8 +266,7 @@
  *	Functions to interpret the absolute mode packets
  ****************************************************************************/
 
-static void synaptics_parse_hw_state(struct synaptics_data *priv,
-				     struct synaptics_hw_state *hw)
+static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
 {
 	unsigned char *buf = priv->proto_buf;
 

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-18 23:41           ` Peter Osterlund
@ 2003-06-19  6:03             ` Vojtech Pavlik
  2003-06-23 16:30             ` Andreas Jellinghaus
  1 sibling, 0 replies; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-19  6:03 UTC (permalink / raw)
  To: Peter Osterlund
  Cc: Vojtech Pavlik, Kernel Mailing List, Joseph Fannin, Jens Taprogge

On Thu, Jun 19, 2003 at 01:41:31AM +0200, Peter Osterlund wrote:
> Vojtech Pavlik <vojtech@suse.cz> writes:
> 
> > On Sun, Jun 15, 2003 at 05:47:57PM +0200, Peter Osterlund wrote:
> > > 
> > > The X driver already relies on EV_SYN to decide when it should act on
> > > the data from the kernel. The problem is that the packet stream is
> > > used as a time base for gesture decoding, because the touchpad was
> > > designed like that to make driver implementation simpler.
> > 
> > We may switch to using some ABS_ or BNT_TOOL_ values for the gesture
> > reporting if some other than Synaptics pad is reporting those, so that
> > we can have one common driver. That other pad may not only not be
> > sending data in a different format, but most likely will also not be
> > sending the data one second after last real event.
> ...
> > Well, I'd suggest using the timestamp on the packets and not just
> > counting them, but the decision is yours, of course. The timestamp is
> > very exact.
> 
> I have modified the X driver now, so that it doesn't depend on packets
> arriving one second after the last event, and so that it uses wall
> clock time instead of counting packets. This version therefore works
> with an unpatched 2.5.72 kernel.

Thanks!

> It is available here:
> 
>         http://w1.894.telia.com/~u89404340/touchpad/index.html
> 
> I think the following patch should be applied anyway. It adds a link
> to the html page, fixes bogus reset retry logic and fixes a deviation
> from the coding style preferred by Linus.
> 
> 
> diff -u -r linux/drivers/input/mouse.orig/Kconfig linux/drivers/input/mouse/Kconfig
> --- linux/drivers/input/mouse.orig/Kconfig	2003-06-19 01:30:39.000000000 +0200
> +++ linux/drivers/input/mouse/Kconfig	2003-06-17 22:03:17.000000000 +0200
> @@ -37,7 +37,7 @@
>  	  This touchpad is found on many modern laptop computers.
>  	  Note that you also need a user space driver to interpret the data
>  	  generated by the kernel. A compatible driver for XFree86 is available
> -	  from http://...
> +	  from http://w1.894.telia.com/~u89404340/touchpad/index.html
>  
>  	  If unsure, say Y.
>  
> diff -u -r linux/drivers/input/mouse.orig/synaptics.c linux/drivers/input/mouse/synaptics.c
> --- linux/drivers/input/mouse.orig/synaptics.c	2003-06-19 01:30:47.000000000 +0200
> +++ linux/drivers/input/mouse/synaptics.c	2003-06-17 22:06:48.000000000 +0200
> @@ -171,9 +171,9 @@
>  static int query_hardware(struct psmouse *psmouse)
>  {
>  	struct synaptics_data *priv = psmouse->private;
> -	int retries = 3;
> +	int retries = 0;
>  
> -	while ((retries++ <= 3) && synaptics_reset(psmouse))
> +	while ((retries++ < 3) && synaptics_reset(psmouse))
>  		printk(KERN_ERR "synaptics reset failed\n");
>  
>  	if (synaptics_identify(psmouse, &priv->identity))
> @@ -266,8 +266,7 @@
>   *	Functions to interpret the absolute mode packets
>   ****************************************************************************/
>  
> -static void synaptics_parse_hw_state(struct synaptics_data *priv,
> -				     struct synaptics_hw_state *hw)
> +static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
>  {
>  	unsigned char *buf = priv->proto_buf;
>  
> 
> -- 
> Peter Osterlund - petero2@telia.com
> http://w1.894.telia.com/~u89404340

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-18 23:41           ` Peter Osterlund
  2003-06-19  6:03             ` Vojtech Pavlik
@ 2003-06-23 16:30             ` Andreas Jellinghaus
  2003-06-23 19:04               ` Peter Osterlund
  1 sibling, 1 reply; 49+ messages in thread
From: Andreas Jellinghaus @ 2003-06-23 16:30 UTC (permalink / raw)
  To: linux-kernel

On Wed, 18 Jun 2003 23:44:45 +0000, Peter Osterlund wrote:
> I have modified the X driver now, so that it doesn't depend on packets
> arriving one second after the last event, and so that it uses wall
> clock time instead of counting packets. This version therefore works
> with an unpatched 2.5.72 kernel. It is available here:
> 
>         http://w1.894.telia.com/~u89404340/touchpad/index.html

Hi,

I tried that driver with 2.5.73. The synaptics option is gone, so it is
always on by default? No way to turn it off?

My XF86Config-4 is:

Section "InputDevice"
        Identifier  "Mouse1"
        Driver      "synaptics"
        Option      "Protocol" "event"
        Option      "Device" "/dev/input/event1"
        Option      "Emulate3Buttons" "on"
EndSection

it's debian unstable and hardware is a dell latitude c600 laptop.

the trackpoint (or how it is called?) does not work: nothing happends.
The touchpad is working ok, but the mouse is moving either slow or too
fast. I guess there is a way I can configure that?

a bigger problem is: X froze once, but I could login via network and
kill -9 it. No idea why, there is nothing special in the log file.


kernel messages:
mice: PS/2 mouse device common for all mice
input: PC Speaker
synaptics reset failed
synaptics reset failed
synaptics reset failed
Synaptics Touchpad, model: 1
 Firware: 5.5
 180 degree mounted touchpad
 Sensor: 27
 new absolute packet format
 Touchpad has extended capability bits
 -> multifinger detection
 -> palm detection
input: Synaptics Synaptics TouchPad on isa0060/serio1
serio: i8042 AUX port at 0x60,0x64 irq 12

xfree log:

(II) LoadModule: "synaptics"
(II) Loading /usr/X11R6/lib/modules/input/synaptics_drv.o
(II) Module synaptics: vendor="The XFree86 Project"
        compiled for 4.2.0, module version = 1.0.0
        Module class: XFree86 XInput Driver
        ABI class: XFree86 XInput driver, version 0.3
...
(**) Option "Device" "/dev/input/event1"
(II) xfree driver for the synaptics touchpad 0.11.3p3
(**) Option "CorePointer"
(**) Mouse1: Core Pointer
(II) Keyboard "Keyboard0" handled by legacy driver
(II) XINPUT: Adding extended input device "Mouse1" (type: MOUSE)
Synaptics DeviceInit called
SynapticsCtrl called.
Synaptics DeviceOn called
(II) xfree driver for the synaptics touchpad 0.11.3p3
Could not init font path element /usr/X11R6/lib/X11/fonts/Speedo/, removing from
 list!
Could not init font path element /usr/X11R6/lib/X11/fonts/Type1/, removing from 
list!
SynapticsCtrl called.

so far it's working fine.

btw: I'm used to tip twice on the touchpad to get a left click. 
That doesn't work anymore (I might have stopped a few kernel or 
xfree versions before). Is there a way to enable that again?

Thanks. Regards, Andreas


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-23 16:30             ` Andreas Jellinghaus
@ 2003-06-23 19:04               ` Peter Osterlund
  2003-06-26 20:01                 ` Vojtech Pavlik
  2003-07-07 23:06                 ` Peter Osterlund
  0 siblings, 2 replies; 49+ messages in thread
From: Peter Osterlund @ 2003-06-23 19:04 UTC (permalink / raw)
  To: Andreas Jellinghaus; +Cc: linux-kernel

Andreas Jellinghaus <aj@dungeon.inka.de> writes:

> I tried that driver with 2.5.73. The synaptics option is gone, so it is
> always on by default? No way to turn it off?

Correct. I don't know if it was an accident or if it was an
intentional decision, but there doesn't seem to be a way to make the
touchpad operate in relative (compatibility) mode any more.

On the other hand, I don't think there will be any reason to use
relative mode once we have X and gpm support for absolute mode, and
when guest devices are supported.

> The touchpad is working ok, but the mouse is moving either slow or too
> fast. I guess there is a way I can configure that?

Yes, use the synclient program to tweak parameters until you find a
setting you like. (I use MinSpeed=0.08 and MaxSpeed=0.10). Then put
them in the XF86Config file. The INSTALL file has an example
InputDevice section that you may want to start from.

> a bigger problem is: X froze once, but I could login via network and
> kill -9 it. No idea why, there is nothing special in the log file.

I've seen X freeze too. I'll debug it, but it will have to wait a week
until I get back from my vacation.

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-23 19:04               ` Peter Osterlund
@ 2003-06-26 20:01                 ` Vojtech Pavlik
  2003-07-07 23:06                 ` Peter Osterlund
  1 sibling, 0 replies; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-26 20:01 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: Andreas Jellinghaus, linux-kernel

On Mon, Jun 23, 2003 at 09:04:06PM +0200, Peter Osterlund wrote:
> Andreas Jellinghaus <aj@dungeon.inka.de> writes:
> 
> > I tried that driver with 2.5.73. The synaptics option is gone, so it is
> > always on by default? No way to turn it off?
> 
> Correct. I don't know if it was an accident or if it was an
> intentional decision, but there doesn't seem to be a way to make the
> touchpad operate in relative (compatibility) mode any more.

It was an intention, because we need the full support to make the
secondary (passthrough) devices work properly. However, now that I've
seen all the bug reports I think it probably wasn't a good decision.

> On the other hand, I don't think there will be any reason to use
> relative mode once we have X and gpm support for absolute mode, and
> when guest devices are supported.

We need GPM support very soon.

> Yes, use the synclient program to tweak parameters until you find a
> setting you like. (I use MinSpeed=0.08 and MaxSpeed=0.10). Then put
> them in the XF86Config file. The INSTALL file has an example
> InputDevice section that you may want to start from.
> 
> I've seen X freeze too. I'll debug it, but it will have to wait a week
> until I get back from my vacation.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-23 19:04               ` Peter Osterlund
  2003-06-26 20:01                 ` Vojtech Pavlik
@ 2003-07-07 23:06                 ` Peter Osterlund
  2003-07-12 10:51                   ` Andreas Jellinghaus
  1 sibling, 1 reply; 49+ messages in thread
From: Peter Osterlund @ 2003-07-07 23:06 UTC (permalink / raw)
  To: Andreas Jellinghaus; +Cc: linux-kernel

Peter Osterlund <petero2@telia.com> writes:

> Andreas Jellinghaus <aj@dungeon.inka.de> writes:
> 
> > a bigger problem is: X froze once, but I could login via network and
> > kill -9 it. No idea why, there is nothing special in the log file.
> 
> I've seen X freeze too. I'll debug it, but it will have to wait a week
> until I get back from my vacation.

I think this bug is fixed in version 0.11.3p5, which is available from
the usual place:

        http://w1.894.telia.com/~u89404340/touchpad/index.html

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-07-07 23:06                 ` Peter Osterlund
@ 2003-07-12 10:51                   ` Andreas Jellinghaus
  0 siblings, 0 replies; 49+ messages in thread
From: Andreas Jellinghaus @ 2003-07-12 10:51 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: linux-kernel

Hi Peter,

thanks. I'm using it now for a few hours with kernel 2.5.75
and no problems at all. Thank you very much !

Regards, Andreas

On Die, 2003-07-08 at 01:06, Peter Osterlund wrote:
> I think this bug is fixed in version 0.11.3p5, which is available from
> the usual place:
> 
>         http://w1.894.telia.com/~u89404340/touchpad/index.html


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 20:29   ` Vojtech Pavlik
@ 2003-06-11 22:12     ` Peter Osterlund
  0 siblings, 0 replies; 49+ messages in thread
From: Peter Osterlund @ 2003-06-11 22:12 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: Andrew Morton, Joseph Fannin, linux-kernel, vojtech

Vojtech Pavlik <vojtech@ucw.cz> writes:

> On Wed, Jun 11, 2003 at 01:17:42PM -0700, Andrew Morton wrote:
> 
> > "Joseph Fannin" <jhf@rivenstone.net> wrote:
> > >
> > > Here is a driver for the Synaptics TouchPad for 2.5.70.
> > 
> > The code looks nice.
> > 
> > > +#include "synaptics.c"
> > 
> > But why on earth do we need to do this?
> 
> I'm sure we don't. That will be fixed easily.

No we don't. That was just a hack to keep the size of the patch down.
Something like the patch below (applies on top of my previous patch)
would take care of this, except that it renames the psmouse module to
psmouse2. To fix this I think we have to rename the psmouse.c file,
and I didn't want to do that in the original patch, because that would
have made it much harder to review the patch.


diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/Makefile linux/drivers/input/mouse/Makefile
--- linux/drivers/input/mouse.absolute/Makefile	Wed Jun 11 23:05:11 2003
+++ linux/drivers/input/mouse/Makefile	Wed Jun 11 23:53:01 2003
@@ -11,5 +11,7 @@
 obj-$(CONFIG_MOUSE_MAPLE)	+= maplemouse.o
 obj-$(CONFIG_MOUSE_PC110PAD)	+= pc110pad.o
 obj-$(CONFIG_MOUSE_PC9800)	+= 98busmouse.o
-obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
+obj-$(CONFIG_MOUSE_PS2)		+= psmouse2.o
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
+
+psmouse2-objs	:= psmouse.o synaptics.o
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/psmouse.c linux/drivers/input/mouse/psmouse.c
--- linux/drivers/input/mouse.absolute/psmouse.c	Wed Jun 11 23:05:25 2003
+++ linux/drivers/input/mouse/psmouse.c	Wed Jun 11 23:56:46 2003
@@ -17,6 +17,8 @@
 #include <linux/input.h>
 #include <linux/serio.h>
 #include <linux/init.h>
+#include "psmouse.h"
+#include "synaptics.h"
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("PS/2 mouse driver");
@@ -25,50 +27,6 @@
 
 static int psmouse_noext;
 
-#define PSMOUSE_CMD_SETSCALE11	0x00e6
-#define PSMOUSE_CMD_SETRES	0x10e8
-#define PSMOUSE_CMD_GETINFO	0x03e9
-#define PSMOUSE_CMD_SETSTREAM	0x00ea
-#define PSMOUSE_CMD_POLL	0x03eb	
-#define PSMOUSE_CMD_GETID	0x02f2
-#define PSMOUSE_CMD_SETRATE	0x10f3
-#define PSMOUSE_CMD_ENABLE	0x00f4
-#define PSMOUSE_CMD_RESET_DIS	0x00f6
-#define PSMOUSE_CMD_RESET_BAT	0x02ff
-
-#define PSMOUSE_RET_BAT		0xaa
-#define PSMOUSE_RET_ACK		0xfa
-#define PSMOUSE_RET_NAK		0xfe
-
-struct psmouse {
-	void *private;
-	struct input_dev dev;
-	struct serio *serio;
-	char *vendor;
-	char *name;
-	unsigned char cmdbuf[8];
-	unsigned char packet[8];
-	unsigned char cmdcnt;
-	unsigned char pktcnt;
-	unsigned char type;
-	unsigned char model;
-	unsigned long last;
-	char acking;
-	volatile char ack;
-	char error;
-	char devname[64];
-	char phys[32];
-};
-
-#define PSMOUSE_PS2	1
-#define PSMOUSE_PS2PP	2
-#define PSMOUSE_PS2TPP	3
-#define PSMOUSE_GENPS	4
-#define PSMOUSE_IMPS	5
-#define PSMOUSE_IMEX	6
-#define PSMOUSE_SYNAPTICS 7
-
-#include "synaptics.c"
 
 static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
 
@@ -258,7 +216,7 @@
  * then waits for the response and puts it in the param array.
  */
 
-static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
+int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
 {
 	int timeout = 500000; /* 500 msec */
 	int send = (command >> 12) & 0xf;
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/psmouse.h linux/drivers/input/mouse/psmouse.h
--- linux/drivers/input/mouse.absolute/psmouse.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/input/mouse/psmouse.h	Wed Jun 11 23:56:41 2003
@@ -0,0 +1,49 @@
+#ifndef _PSMOUSE_H
+#define _PSMOUSE_H
+
+#define PSMOUSE_CMD_SETSCALE11	0x00e6
+#define PSMOUSE_CMD_SETRES	0x10e8
+#define PSMOUSE_CMD_GETINFO	0x03e9
+#define PSMOUSE_CMD_SETSTREAM	0x00ea
+#define PSMOUSE_CMD_POLL	0x03eb	
+#define PSMOUSE_CMD_GETID	0x02f2
+#define PSMOUSE_CMD_SETRATE	0x10f3
+#define PSMOUSE_CMD_ENABLE	0x00f4
+#define PSMOUSE_CMD_RESET_DIS	0x00f6
+#define PSMOUSE_CMD_RESET_BAT	0x02ff
+
+#define PSMOUSE_RET_BAT		0xaa
+#define PSMOUSE_RET_ACK		0xfa
+#define PSMOUSE_RET_NAK		0xfe
+
+struct psmouse {
+	void *private;
+	struct input_dev dev;
+	struct serio *serio;
+	char *vendor;
+	char *name;
+	unsigned char cmdbuf[8];
+	unsigned char packet[8];
+	unsigned char cmdcnt;
+	unsigned char pktcnt;
+	unsigned char type;
+	unsigned char model;
+	unsigned long last;
+	char acking;
+	volatile char ack;
+	char error;
+	char devname[64];
+	char phys[32];
+};
+
+#define PSMOUSE_PS2	1
+#define PSMOUSE_PS2PP	2
+#define PSMOUSE_PS2TPP	3
+#define PSMOUSE_GENPS	4
+#define PSMOUSE_IMPS	5
+#define PSMOUSE_IMEX	6
+#define PSMOUSE_SYNAPTICS 7
+
+int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+
+#endif /* _PSMOUSE_H */
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/synaptics.c linux/drivers/input/mouse/synaptics.c
--- linux/drivers/input/mouse.absolute/synaptics.c	Wed Jun 11 23:04:59 2003
+++ linux/drivers/input/mouse/synaptics.c	Wed Jun 11 23:56:32 2003
@@ -19,19 +19,15 @@
  * Trademarks are the property of their respective owners.
  */
 
-#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+#include <linux/module.h>
 
-static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {}
-static inline int synaptics_init(struct psmouse *psmouse) { return -1; }
-static inline void synaptics_disconnect(struct psmouse *psmouse) {}
-
-#else
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
 
+#include <linux/input.h>
+#include "psmouse.h"
 #include "synaptics.h"
 
 
-static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
-
 /*****************************************************************************
  *	Synaptics communications functions
  ****************************************************************************/
@@ -217,7 +213,7 @@
 	set_bit(axis, dev->absbit);
 }
 
-static int synaptics_init(struct psmouse *psmouse)
+int synaptics_init(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv;
 
@@ -263,7 +259,7 @@
 	return -1;
 }
 
-static void synaptics_disconnect(struct psmouse *psmouse)
+void synaptics_disconnect(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv = psmouse->private;
 
@@ -360,7 +356,7 @@
 	input_sync(dev);
 }
 
-static void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 {
 	struct input_dev *dev = &psmouse->dev;
 	struct synaptics_data *priv = psmouse->private;
diff -u -r -N --exclude='.*' --exclude='*.o' --exclude='*~' linux/drivers/input/mouse.absolute/synaptics.h linux/drivers/input/mouse/synaptics.h
--- linux/drivers/input/mouse.absolute/synaptics.h	Wed Jun 11 23:04:50 2003
+++ linux/drivers/input/mouse/synaptics.h	Wed Jun 11 23:49:42 2003
@@ -9,6 +9,21 @@
 #ifndef _SYNAPTICS_H
 #define _SYNAPTICS_H
 
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+
+extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
+extern int synaptics_init(struct psmouse *psmouse);
+extern void synaptics_disconnect(struct psmouse *psmouse);
+
+#else
+
+static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {}
+static inline int synaptics_init(struct psmouse *psmouse) { return -1; }
+static inline void synaptics_disconnect(struct psmouse *psmouse) {}
+
+#endif
+
+
 /* synaptics queries */
 #define SYN_QUE_IDENTIFY		0x00
 #define SYN_QUE_MODES			0x01

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-11 20:17 ` Andrew Morton
@ 2003-06-11 20:29   ` Vojtech Pavlik
  2003-06-11 22:12     ` Peter Osterlund
  0 siblings, 1 reply; 49+ messages in thread
From: Vojtech Pavlik @ 2003-06-11 20:29 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Joseph Fannin, linux-kernel, vojtech, petero2

On Wed, Jun 11, 2003 at 01:17:42PM -0700, Andrew Morton wrote:

> "Joseph Fannin" <jhf@rivenstone.net> wrote:
> >
> > Here is a driver for the Synaptics TouchPad for 2.5.70.
> 
> The code looks nice.
> 
> > +#include "synaptics.c"
> 
> But why on earth do we need to do this?

I'm sure we don't. That will be fixed easily.

-- 
Vojtech Pavlik
SuSE Labs, SuSE CR

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-10 22:52 Joseph Fannin
  2003-06-11 15:30 ` Joseph Fannin
@ 2003-06-11 20:17 ` Andrew Morton
  2003-06-11 20:29   ` Vojtech Pavlik
  1 sibling, 1 reply; 49+ messages in thread
From: Andrew Morton @ 2003-06-11 20:17 UTC (permalink / raw)
  To: Joseph Fannin; +Cc: linux-kernel, vojtech, jhf, petero2

"Joseph Fannin" <jhf@rivenstone.net> wrote:
>
> Here is a driver for the Synaptics TouchPad for 2.5.70.

The code looks nice.

> +#include "synaptics.c"

But why on earth do we need to do this?



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH] Synaptics TouchPad driver for 2.5.70
  2003-06-10 22:52 Joseph Fannin
@ 2003-06-11 15:30 ` Joseph Fannin
  2003-06-11 20:17 ` Andrew Morton
  1 sibling, 0 replies; 49+ messages in thread
From: Joseph Fannin @ 2003-06-11 15:30 UTC (permalink / raw)
  To: Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 1187 bytes --]

On Wed, Jun 11, 2003 at 12:52:06AM +0200, Joseph Fannin wrote:

Please note that I did not write this driver -- Peter Osterlund
<petero2@telia.com> did.  I meant only to forward this here, since the
original sender seems to have problems getting through to the list.


> Hi!
> 
> Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
> based on the XFree86 driver. This driver operates the touchpad in
> absolute mode and emulates a three button mouse with two scroll
> wheels. Features include:
> 
> * Multi finger tapping.
> * Vertical and horizontal scrolling.
> * Edge scrolling during drag operations.
> * Palm detection.
> * Corner tapping.
> 
> The only major missing feature is runtime configuration of driver
> parameters. What is the best way to implement that? I was thinking of
> sending EV_MSC events to the driver using the /dev/input/event*
> interface and define my own codes for the different driver parameters.
> 
> Comments?

-- 
Joseph Fannin
jhf@rivenstone.net

Rothchild's Rule -- "For every phenomenon, however complex, someone will
eventually come up with a simple and elegant theory. This theory will
be wrong."

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH] Synaptics TouchPad driver for 2.5.70
@ 2003-06-10 22:52 Joseph Fannin
  2003-06-11 15:30 ` Joseph Fannin
  2003-06-11 20:17 ` Andrew Morton
  0 siblings, 2 replies; 49+ messages in thread
From: Joseph Fannin @ 2003-06-10 22:52 UTC (permalink / raw)
  To: Kernel Mailing List; +Cc: Vojtech Pavlik, Joseph Fannin

Hi!

Here is a driver for the Synaptics TouchPad for 2.5.70. It is largely
based on the XFree86 driver. This driver operates the touchpad in
absolute mode and emulates a three button mouse with two scroll
wheels. Features include:

* Multi finger tapping.
* Vertical and horizontal scrolling.
* Edge scrolling during drag operations.
* Palm detection.
* Corner tapping.

The only major missing feature is runtime configuration of driver
parameters. What is the best way to implement that? I was thinking of
sending EV_MSC events to the driver using the /dev/input/event*
interface and define my own codes for the different driver parameters.

Comments?


diff -u -r -N ../../linus/main/linux/drivers/input/mouse/Kconfig linux/drivers/input/mouse/Kconfig
--- ../../linus/main/linux/drivers/input/mouse/Kconfig	Sat Jun  7 21:40:38 2003
+++ linux/drivers/input/mouse/Kconfig	Tue Jun 10 00:08:14 2003
@@ -28,6 +28,16 @@
 	  The module will be called psmouse. If you want to compile it as a
 	  module, say M here and read <file:Documentation/modules.txt>.
 
+config MOUSE_PS2_SYNAPTICS
+	bool "Synaptics TouchPad"
+	default n
+	depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2
+	---help---
+	  Say Y here if you have a Synaptics TouchPad connected to your system.
+	  This touchpad is found on many modern laptop computers.
+
+	  If unsure, say Y.
+
 config MOUSE_SERIAL
 	tristate "Serial mouse"
 	depends on INPUT && INPUT_MOUSE && SERIO
diff -u -r -N ../../linus/main/linux/drivers/input/mouse/psmouse.c linux/drivers/input/mouse/psmouse.c
--- ../../linus/main/linux/drivers/input/mouse/psmouse.c	Sat Jun  7 21:40:38 2003
+++ linux/drivers/input/mouse/psmouse.c	Tue Jun 10 00:11:37 2003
@@ -41,6 +41,7 @@
 #define PSMOUSE_RET_NAK		0xfe
 
 struct psmouse {
+	void *private;
 	struct input_dev dev;
 	struct serio *serio;
 	char *vendor;
@@ -65,8 +66,11 @@
 #define PSMOUSE_GENPS	4
 #define PSMOUSE_IMPS	5
 #define PSMOUSE_IMEX	6
+#define PSMOUSE_SYNAPTICS 7
 
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" };
+#include "synaptics.c"
+
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
 
 /*
  * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
@@ -209,6 +213,16 @@
 		goto out;
 	}
 
+	if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+		/*
+		 * The synaptics driver has its own resync logic,
+		 * so it needs to receive all bytes one at a time.
+		 */
+		synaptics_process_byte(psmouse, regs);
+		psmouse->pktcnt = 0;
+		goto out;
+	}
+
 	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
 		serio_rescan(serio);
 		goto out;
@@ -343,12 +357,12 @@
        psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
 
        if (param[1] == 0x47) {
-               /* We could do more here. But it's sufficient just
-                  to stop the subsequent probes from screwing the
-                  thing up. */
-               psmouse->vendor = "Synaptics";
-               psmouse->name = "TouchPad";
-               return PSMOUSE_PS2;
+		int type = PSMOUSE_PS2;
+		psmouse->vendor = "Synaptics";
+		psmouse->name = "TouchPad";
+		if (synaptics_init(psmouse) == 0)
+			type = PSMOUSE_SYNAPTICS;
+		return type;
        }
 
 /*
@@ -598,6 +612,7 @@
 	struct psmouse *psmouse = serio->private;
 	input_unregister_device(&psmouse->dev);
 	serio_close(serio);
+	synaptics_disconnect(psmouse);
 	kfree(psmouse);
 }
 
diff -u -r -N ../../linus/main/linux/drivers/input/mouse/synaptics.c linux/drivers/input/mouse/synaptics.c
--- ../../linus/main/linux/drivers/input/mouse/synaptics.c	Thu Jan  1 01:00:00 1970
+++ linux/drivers/input/mouse/synaptics.c	Wed Jun 11 00:34:54 2003
@@ -0,0 +1,801 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ *   2003 Peter Osterlund <petero2@telia.com>
+ *     Ported to 2.5 input device infrastructure.
+ *
+ *   2002 Peter Osterlund <petero2@telia.com>
+ *     patches for fast scrolling, palm detection, edge motion,
+ *     horizontal scrolling
+ *
+ *   Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
+ *     start merging tpconfig and gpm code to a xfree-input module
+ *     adding some changes and extensions (ex. 3rd and 4th button)
+ *
+ *   Copyright (c) 1999 Henry Davies <hdavies@ameritech.net> for the
+ *     absolute to relative translation code (from the gpm-source)
+ *     and some other ideas
+ *
+ *   Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
+ *   Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
+ *     code for the special synaptics commands (from the tpconfig-source)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+
+static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {}
+static inline int synaptics_init(struct psmouse *psmouse) { return -1; }
+static inline void synaptics_disconnect(struct psmouse *psmouse) {}
+
+#else
+
+#include "synaptics.h"
+
+
+static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+
+/*
+ * Use the Synaptics extended ps/2 syntax to write a special command byte.
+ * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
+ *                  is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
+ *                  and synaptics_set_mode)
+ */
+static int synaptics_special_cmd(struct psmouse *psmouse, unsigned char command)
+{
+	int i;
+
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+		return -1;
+
+	for (i = 6; i >= 0; i -= 2) {
+		unsigned char d = (command >> i) & 3;
+		if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Send a command to the synpatics touchpad by special commands
+ */
+static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
+{
+	if (synaptics_special_cmd(psmouse, c))
+		return -1;
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+		return -1;
+	return 0;
+}
+
+/*****************************************************************************
+ *	Synaptics communications functions
+ ****************************************************************************/
+
+/*
+ * Set the synaptics touchpad mode byte by special commands
+ */
+static int synaptics_set_mode(struct psmouse *psmouse, unsigned char mode)
+{
+	unsigned char param[1];
+
+	if (synaptics_special_cmd(psmouse, mode))
+		return -1;
+	param[0] = 0x14;
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+		return -1;
+	return 0;
+}
+
+static int synaptics_reset(struct psmouse *psmouse)
+{
+	unsigned char r[2];
+
+	if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
+		return -1;
+	if (r[0] == 0xAA && r[1] == 0x00)
+		return 0;
+	return -1;
+}
+
+/*
+ * Read the model-id bytes from the touchpad
+ * see also SYN_MODEL_* macros
+ */
+static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_id)
+{
+	unsigned char mi[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
+		return -1;
+	*model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
+	return 0;
+}
+
+/*
+ * Read the capability-bits from the touchpad
+ * see also the SYN_CAP_* macros
+ */
+static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
+{
+	unsigned char cap[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
+		return -1;
+	*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+	if (SYN_CAP_VALID(*capability))
+		return 0;
+	return -1;
+}
+
+/*
+ * Identify Touchpad
+ * See also the SYN_ID_* macros
+ */
+static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident)
+{
+	unsigned char id[3];
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
+		return -1;
+	*ident = (id[0]<<16) | (id[1]<<8) | id[2];
+	if (SYN_ID_IS_SYNAPTICS(*ident))
+		return 0;
+	return -1;
+}
+
+static int synaptics_enable_device(struct psmouse *psmouse)
+{
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
+		return -1;
+	return 0;
+}
+
+static void print_ident(struct synaptics_data *priv)
+{
+	printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
+	printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
+	       SYN_ID_MINOR(priv->identity));
+
+	if (SYN_MODEL_ROT180(priv->model_id))
+		printk(KERN_INFO " 180 degree mounted touchpad\n");
+	if (SYN_MODEL_PORTRAIT(priv->model_id))
+		printk(KERN_INFO " portrait touchpad\n");
+	printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
+	if (SYN_MODEL_NEWABS(priv->model_id))
+		printk(KERN_INFO " new absolute packet format\n");
+	if (SYN_MODEL_PEN(priv->model_id))
+		printk(KERN_INFO " pen detection\n");
+
+	if (SYN_CAP_EXTENDED(priv->capabilities)) {
+		printk(KERN_INFO " Touchpad has extended capability bits\n");
+		if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+			printk(KERN_INFO " -> four buttons\n");
+		if (SYN_CAP_MULTIFINGER(priv->capabilities))
+			printk(KERN_INFO " -> multifinger detection\n");
+		if (SYN_CAP_PALMDETECT(priv->capabilities))
+			printk(KERN_INFO " -> palm detection\n");
+	}
+}
+
+static int query_hardware(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	int retries = 3;
+
+	while ((retries++ <= 3) && synaptics_reset(psmouse))
+		printk(KERN_ERR "synaptics reset failed\n");
+
+	if (synaptics_identify(psmouse, &priv->identity))
+		return -1;
+	if (synaptics_model_id(psmouse, &priv->model_id))
+		return -1;
+	if (synaptics_capability(psmouse, &priv->capabilities))
+		return -1;
+	if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+					 SYN_BIT_HIGH_RATE |
+					 SYN_BIT_DISABLE_GESTURE |
+					 SYN_BIT_W_MODE)))
+		return -1;
+
+	synaptics_enable_device(psmouse);
+
+	print_ident(priv);
+
+	return 0;
+}
+
+static void synaptics_repeat_timer(unsigned long data)
+{
+	struct psmouse *psmouse = (void *) data;
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+
+	if (priv->repeat_buttons & 0x01)
+		input_report_rel(dev, REL_WHEEL, 1);
+	if (priv->repeat_buttons & 0x02)
+		input_report_rel(dev, REL_WHEEL, -1);
+	input_sync(dev);
+
+	if (atomic_read(&priv->timer_active))
+		mod_timer(&priv->timer, jiffies + 100 * HZ / 1000);
+}
+
+static struct synaptics_parameters default_params = {
+	.left_edge			= 1800,
+	.right_edge			= 5400,
+	.top_edge			= 4200,
+	.bottom_edge			= 1500,
+	.finger_low			= 25,
+	.finger_high			= 30,
+	.tap_time			= 15,
+	.tap_move			= 220,
+	.emulate_mid_button_time	= 6,
+	.scroll_dist_vert		= 100,
+	.scroll_dist_horiz		= 100,
+	.speed				= 25,
+	.edge_motion_speed		= 40,
+	.updown_button_scrolling	= 1
+};
+
+static int synaptics_init(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv;
+
+	psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+	if (!priv)
+		return -1;
+	memset(priv, 0, sizeof(struct synaptics_data));
+
+	priv->inSync = 1;
+
+	/* Set default parameters */
+	priv->params = default_params;
+
+	if (query_hardware(psmouse)) {
+		printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
+		goto init_fail;
+	}
+
+	set_bit(REL_WHEEL, psmouse->dev.relbit);
+	set_bit(REL_HWHEEL, psmouse->dev.relbit);
+
+	init_timer(&priv->timer);
+	priv->timer.data = (unsigned long)psmouse;
+	priv->timer.function = synaptics_repeat_timer;
+	atomic_set(&priv->timer_active, 0);
+
+	return 0;
+
+ init_fail:
+	kfree(priv);
+	return -1;
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	atomic_set(&priv->timer_active, 0);
+	priv->repeat_buttons = 0;
+	del_timer_sync(&priv->timer);
+
+	kfree(priv);
+}
+
+/*****************************************************************************
+ *	Functions to interpret the absolute mode packets
+ ****************************************************************************/
+
+#define DIFF_TIME(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
+
+typedef enum {
+	BOTTOM_EDGE = 1,
+	TOP_EDGE = 2,
+	LEFT_EDGE = 4,
+	RIGHT_EDGE = 8,
+	LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
+	RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
+	RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
+	LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE
+} edge_type;
+
+static edge_type
+edge_detection(struct synaptics_data *priv, int x, int y)
+{
+	edge_type edge = 0;
+
+	if (x > priv->params.right_edge)
+		edge |= RIGHT_EDGE;
+	else if (x < priv->params.left_edge)
+		edge |= LEFT_EDGE;
+
+	if (y > priv->params.top_edge)
+		edge |= TOP_EDGE;
+	else if (y < priv->params.bottom_edge)
+		edge |= BOTTOM_EDGE;
+
+	return edge;
+}
+
+#define MOVE_HIST(a) ((priv->count_packet_finger-(a))%SYNAPTICS_MOVE_HISTORY)
+
+static inline int clamp(int val, int min, int max)
+{
+	if (val < min)
+		return min;
+	else if (val < max)
+		return val;
+	else
+		return max;
+}
+
+static void synaptics_parse_hw_state(struct synaptics_data *priv,
+				     struct synaptics_hw_state *hw)
+{
+	unsigned char *buf = priv->proto_buf;
+
+	hw->x = (((buf[3] & 0x10) << 8) |
+		 ((buf[1] & 0x0f) << 8) |
+		 buf[4]);
+	hw->y = (((buf[3] & 0x20) << 7) |
+		 ((buf[1] & 0xf0) << 4) |
+		 buf[5]);
+
+	hw->z = buf[2];
+	hw->w = (((buf[0] & 0x30) >> 2) |
+		 ((buf[0] & 0x04) >> 1) |
+		 ((buf[3] & 0x04) >> 2));
+
+	hw->left  = (buf[0] & 0x01) ? 1 : 0;
+	hw->right = (buf[0] & 0x2) ? 1 : 0;
+	hw->up    = 0;
+	hw->down  = 0;
+
+	if (SYN_CAP_EXTENDED(priv->capabilities) &&
+	    (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
+		hw->up = ((buf[3] & 0x01)) ? 1 : 0;
+		if (hw->left)
+			hw->up = !hw->up;
+		hw->down = ((buf[3] & 0x02)) ? 1 : 0;
+		if (hw->right)
+			hw->down = !hw->down;
+	}
+}
+
+static int synaptics_emulate_mid_button(struct synaptics_data *priv,
+					struct synaptics_hw_state *hw)
+{
+	int timeout = (DIFF_TIME(priv->count_packet, priv->count_button_delay) >=
+		       priv->params.emulate_mid_button_time);
+	int mid = 0;
+
+	for (;;) {
+		switch (priv->mid_emu_state) {
+		case MBE_OFF:
+			if (hw->left) {
+				priv->mid_emu_state = MBE_LEFT;
+			} else if (hw->right) {
+				priv->mid_emu_state = MBE_RIGHT;
+			} else {
+				priv->count_button_delay = priv->count_packet;
+				goto done;
+			}
+			break;
+		case MBE_LEFT:
+			if (!hw->left || timeout) {
+				hw->left = 1;
+				priv->mid_emu_state = MBE_OFF;
+				goto done;
+			} else if (hw->right) {
+				priv->mid_emu_state = MBE_MID;
+			} else {
+				hw->left = 0;
+				goto done;
+			}
+			break;
+		case MBE_RIGHT:
+			if (!hw->right || timeout) {
+				hw->right = 1;
+				priv->mid_emu_state = MBE_OFF;
+				goto done;
+			} else if (hw->left) {
+				priv->mid_emu_state = MBE_MID;
+			} else {
+				hw->right = 0;
+				goto done;
+			}
+			break;
+		case MBE_MID:
+			if (!hw->left && !hw->right) {
+				priv->mid_emu_state = MBE_OFF;
+			} else {
+				mid = 1;
+				hw->left = hw->right = 0;
+				goto done;
+			}
+			break;
+		}
+	}
+ done:
+	return mid;
+}
+
+static int synaptics_detect_finger(struct synaptics_data *priv,
+				   const struct synaptics_hw_state *hw)
+{
+	const struct synaptics_parameters *para = &priv->params;
+	int finger;
+
+	/* finger detection thru pressure and threshold */
+	finger = (((hw->z > para->finger_high) && !priv->finger_flag) ||
+		  ((hw->z > para->finger_low)  &&  priv->finger_flag));
+
+	/* palm detection */
+	if (!SYN_CAP_EXTENDED(priv->capabilities) || !SYN_CAP_PALMDETECT(priv->capabilities))
+		return finger;
+
+	if (finger) {
+		if ((hw->z > 200) && (hw->w > 10))
+			priv->palm = 1;
+	} else {
+		priv->palm = 0;
+	}
+	if (hw->x == 0)
+		priv->avg_w = 0;
+	else
+		priv->avg_w += (hw->w - priv->avg_w + 1) / 2;
+	if (finger && !priv->finger_flag) {
+		int safe_w = max_t(int, hw->w, priv->avg_w);
+		if (hw->w < 2)
+			finger = 1;		/* more than one finger -> not a palm */
+		else if ((safe_w < 6) && (priv->prev_z < para->finger_high))
+			finger = 1;		/* thin finger, distinct touch -> not a palm */
+		else if ((safe_w < 7) && (priv->prev_z < para->finger_high / 2))
+			finger = 1;		/* thin finger, distinct touch -> not a palm */
+		else if (hw->z > priv->prev_z + 1)
+			finger = 0;		/* z not stable, may be a palm */
+		else if (hw->z < priv->prev_z - 5)
+			finger = 0;		/* z not stable, may be a palm */
+		else if (hw->z > 200)
+			finger = 0;		/* z too large -> probably palm */
+		else if (hw->w > 10)
+			finger = 0;		/* w too large -> probably palm */
+	}
+	priv->prev_z = hw->z;
+
+	return finger;
+}
+
+/*
+ *  called for each full received packet from the touchpad
+ */
+static void synaptics_process_packet(struct psmouse *psmouse)
+{
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+	const struct synaptics_parameters *para = &priv->params;
+	struct synaptics_hw_state hw;
+	int dx, dy;
+	edge_type edge;
+	int scroll_up, scroll_down, scroll_left, scroll_right;
+	int double_click;
+
+	int finger;
+	int mid;
+
+	synaptics_parse_hw_state(priv, &hw);
+
+	edge = edge_detection(priv, hw.x, hw.y);
+
+	mid = synaptics_emulate_mid_button(priv, &hw);
+
+	/* Up/Down-button scrolling or middle/double-click */
+	double_click = 0;
+	if (!para->updown_button_scrolling) {
+		if (down) {
+			/* map down-button to middle-button */
+			mid = 1;
+		}
+
+		if (hw.up) {
+			/* up-button generates double-click */
+			if (!priv->prev_up)
+				double_click = 1;
+		}
+		priv->prev_up = hw.up;
+
+		/* reset up/down button events */
+		hw.up = hw.down = 0;
+	}
+
+	finger = synaptics_detect_finger(priv, &hw);
+
+	/* tap and drag detection */
+	if (priv->palm) {
+		/* Palm detected, skip tap/drag processing */
+	} else if (finger && !priv->finger_flag) {
+		/* touched */
+		if (priv->tap) {
+			priv->drag = 1; /* drag gesture */
+		}
+		priv->touch_on.x = hw.x;
+		priv->touch_on.y = hw.y;
+		priv->touch_on.packet = priv->count_packet;
+	} else if (!finger && priv->finger_flag) {
+		/* untouched */
+		/* check if
+		   1. the tap is in tap_time
+		   2. the max movement is in tap_move or more than one finger is tapped */
+		if ((DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) &&
+		    (((abs(hw.x - priv->touch_on.x) < para->tap_move) &&
+		      (abs(hw.y - priv->touch_on.y) < para->tap_move)) ||
+		     priv->finger_count)) {
+			if (priv->drag) {
+				priv->doubletap = 1;
+				priv->tap = 0;
+			} else {
+				priv->count_packet_tapping = priv->count_packet;
+				priv->tap = 1;
+				switch (priv->finger_count) {
+				case 0:
+					switch (edge) {
+					case RIGHT_TOP_EDGE:
+						priv->tap_mid = 1;
+						break;
+					case RIGHT_BOTTOM_EDGE:
+						priv->tap_right = 1;
+						break;
+					case LEFT_TOP_EDGE:
+						break;
+					case LEFT_BOTTOM_EDGE:
+						break;
+					default:
+						priv->tap_left = 1;
+					}
+					break;
+				case 2:
+					priv->tap_mid = 1;
+					break;
+				case 3: 
+					priv->tap_right = 1;
+					break;
+				default:
+					priv->tap_left = 1;
+				}
+			}
+		}
+		priv->drag = 0;
+	}
+
+	/* detecting 2 and 3 fingers */
+	if (finger && /* finger is on the surface */
+	    (DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) &&
+	    SYN_CAP_MULTIFINGER(priv->capabilities)) {
+		/* count fingers when reported */
+		if ((hw.w == 0) && (priv->finger_count == 0))
+			priv->finger_count = 2;
+		if (hw.w == 1)
+			priv->finger_count = 3;
+	} else {
+		priv->finger_count = 0;
+	}
+
+	/* reset tapping button flags */
+	if (!priv->tap && !priv->drag && !priv->doubletap) {
+		priv->tap_left = priv->tap_mid = priv->tap_right = 0;
+	}
+
+	/* tap processing */
+	if (priv->tap &&
+	    (DIFF_TIME(priv->count_packet, priv->count_packet_tapping) < para->tap_time)) {
+		hw.left  |= priv->tap_left;
+		mid      |= priv->tap_mid;
+		hw.right |= priv->tap_right;
+	} else {
+		priv->tap = 0;
+	}
+
+	/* drag processing */
+	if (priv->drag) {
+		hw.left  |= priv->tap_left;
+		mid      |= priv->tap_mid;
+		hw.right |= priv->tap_right;
+	}
+
+	/* double tap processing */
+	if (priv->doubletap && !priv->finger_flag) {
+		hw.left  |= priv->tap_left;
+		mid      |= priv->tap_mid;
+		hw.right |= priv->tap_right;
+		priv->doubletap = 0;
+	}
+
+	/* scroll detection */
+	if (finger && !priv->finger_flag) {
+		if (edge & RIGHT_EDGE) {
+			priv->vert_scroll_on = 1;
+			priv->scroll_y = hw.y;
+		}
+		if (edge & BOTTOM_EDGE) {
+			priv->horiz_scroll_on = 1;
+			priv->scroll_x = hw.x;
+		}
+	}
+	if (priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger || priv->palm)) {
+		priv->vert_scroll_on = 0;
+	}
+	if (priv->horiz_scroll_on && (!(edge & BOTTOM_EDGE) || !finger || priv->palm)) {
+		priv->horiz_scroll_on = 0;
+	}
+
+	/* scroll processing */
+	scroll_up = 0;
+	scroll_down = 0;
+	if (priv->vert_scroll_on) {
+		/* + = up, - = down */
+		while (hw.y - priv->scroll_y > para->scroll_dist_vert) {
+			scroll_up++;
+			priv->scroll_y += para->scroll_dist_vert;
+		}
+		while (hw.y - priv->scroll_y < -para->scroll_dist_vert) {
+			scroll_down++;
+			priv->scroll_y -= para->scroll_dist_vert;
+		}
+	}
+	scroll_left = 0;
+	scroll_right = 0;
+	if (priv->horiz_scroll_on) {
+		/* + = right, - = left */
+		while (hw.x - priv->scroll_x > para->scroll_dist_horiz) {
+			scroll_right++;
+			priv->scroll_x += para->scroll_dist_horiz;
+		}
+		while (hw.x - priv->scroll_x < -para->scroll_dist_horiz) {
+			scroll_left++;
+			priv->scroll_x -= para->scroll_dist_horiz;
+		}
+	}
+
+	/* movement */
+	dx = dy = 0;
+	if (finger && !priv->vert_scroll_on && !priv->horiz_scroll_on &&
+	    !priv->finger_count && !priv->palm) {
+		if (priv->count_packet_finger > 3) { /* min. 3 packets */
+			int h2x = priv->move_hist[MOVE_HIST(2)].x;
+			int h2y = priv->move_hist[MOVE_HIST(2)].y;
+
+			dx =  ((hw.x - h2x) / 2);
+			dy = -((hw.y - h2y) / 2);
+
+			if (priv->drag) {
+				if (edge & RIGHT_EDGE) {
+					dx += clamp(para->edge_motion_speed - dx,
+						    0, para->edge_motion_speed);
+				} else if (edge & LEFT_EDGE) {
+					dx -= clamp(para->edge_motion_speed + dx,
+						    0, para->edge_motion_speed);
+				}
+				if (edge & TOP_EDGE) {
+					dy -= clamp(para->edge_motion_speed + dy,
+						    0, para->edge_motion_speed);
+				} else if (edge & BOTTOM_EDGE) {
+					dy += clamp(para->edge_motion_speed - dy,
+						    0, para->edge_motion_speed);
+				}
+			}
+
+			/* Scale dx and dy to get pointer motion values */
+			priv->accum_dx += dx * para->speed;
+			priv->accum_dy += dy * para->speed;
+
+			dx = priv->accum_dx / 256;
+			dy = priv->accum_dy / 256;
+
+			priv->accum_dx -= dx * 256;
+			priv->accum_dy -= dy * 256;
+		}
+
+		priv->count_packet_finger++;
+	} else {
+		priv->count_packet_finger = 0;
+	}
+
+	priv->count_packet++;
+
+	/* Flags */
+	priv->finger_flag = finger;
+
+	/* generate a history of the absolute positions */
+	priv->move_hist[MOVE_HIST(0)].x = hw.x;
+	priv->move_hist[MOVE_HIST(0)].y = hw.y;
+
+	/* repeat timer for up/down buttons */
+	/* when you press a button the packets will only send for a second, so
+	   we have to use a timer for repeating */
+	if ((hw.up || hw.down) && para->updown_button_scrolling) {
+		if (!atomic_read(&priv->timer_active)) {
+			priv->repeat_buttons = ((hw.up    ? 0x01 : 0) |
+						(hw.down  ? 0x02 : 0));
+			atomic_set(&priv->timer_active, 1);
+			mod_timer(&priv->timer, jiffies + 200 * HZ / 1000);
+		}
+	} else if (atomic_read(&priv->timer_active)) {
+		atomic_set(&priv->timer_active, 0);
+		priv->repeat_buttons = 0;
+		del_timer_sync(&priv->timer);
+	}
+
+	/* Post events */
+	input_report_rel(dev, REL_X, dx);
+	input_report_rel(dev, REL_Y, dy);
+
+	input_report_key(dev, BTN_LEFT,   hw.left);
+	input_report_key(dev, BTN_MIDDLE, mid);
+	input_report_key(dev, BTN_RIGHT,  hw.right);
+
+	if (hw.up && !priv->last_up)
+		input_report_rel(dev, REL_WHEEL, 1);
+	if (hw.down && !priv->last_down)
+		input_report_rel(dev, REL_WHEEL, -1);
+	priv->last_up = hw.up;
+	priv->last_down = hw.down;
+
+	input_report_rel(dev, REL_WHEEL, scroll_up - scroll_down);
+	input_report_rel(dev, REL_HWHEEL, scroll_right - scroll_left);
+
+	if (double_click) {
+		int i;
+		for (i = 0; i < 2; i++) {
+			input_report_key(dev, BTN_LEFT, !hw.left);
+			input_report_key(dev, BTN_LEFT, hw.left);
+		}
+	}
+
+	input_sync(dev);
+}
+
+static void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+	struct input_dev *dev = &psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+	unsigned char *pBuf = priv->proto_buf;
+	unsigned char u = psmouse->packet[0];
+
+	input_regs(dev, regs);
+
+	pBuf[priv->proto_buf_tail++] = u;
+
+	/* check first byte */
+	if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
+		priv->inSync = 0;
+		priv->proto_buf_tail = 0;
+		printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+		return;
+	}
+
+	/* check 4th byte */
+	if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
+		priv->inSync = 0;
+		priv->proto_buf_tail = 0;
+		printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+		return;
+	}
+
+	if (priv->proto_buf_tail >= 6) { /* Full packet received */
+		if (!priv->inSync) {
+			priv->inSync = 1;
+			printk(KERN_NOTICE "Synaptics driver resynced.\n");
+		}
+		synaptics_process_packet(psmouse);
+		priv->proto_buf_tail = 0;
+	}
+}
+
+#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff -u -r -N ../../linus/main/linux/drivers/input/mouse/synaptics.h linux/drivers/input/mouse/synaptics.h
--- ../../linus/main/linux/drivers/input/mouse/synaptics.h	Thu Jan  1 01:00:00 1970
+++ linux/drivers/input/mouse/synaptics.h	Wed Jun 11 00:08:41 2003
@@ -0,0 +1,158 @@
+/*
+ * Synaptics TouchPad PS/2 mouse driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _SYNAPTICS_H
+#define _SYNAPTICS_H
+
+/* synaptics queries */
+#define SYN_QUE_IDENTIFY		0x00
+#define SYN_QUE_MODES			0x01
+#define SYN_QUE_CAPABILITIES		0x02
+#define SYN_QUE_MODEL			0x03
+#define SYN_QUE_SERIAL_NUMBER_PREFIX	0x06
+#define SYN_QUE_SERIAL_NUMBER_SUFFIX	0x07
+#define SYN_QUE_RESOLUTION		0x08
+
+/* synatics modes */
+#define SYN_BIT_ABSOLUTE_MODE		(1 << 7)
+#define SYN_BIT_HIGH_RATE		(1 << 6)
+#define SYN_BIT_SLEEP_MODE		(1 << 3)
+#define SYN_BIT_DISABLE_GESTURE		(1 << 2)
+#define SYN_BIT_W_MODE			(1 << 0)
+
+/* synaptics model ID bits */
+#define SYN_MODEL_ROT180(m)		((m) & (1 << 23))
+#define SYN_MODEL_PORTRAIT(m)		((m) & (1 << 22))
+#define SYN_MODEL_SENSOR(m)		(((m) >> 16) & 0x3f)
+#define SYN_MODEL_HARDWARE(m)		(((m) >> 9) & 0x7f)
+#define SYN_MODEL_NEWABS(m)		((m) & (1 << 7))
+#define SYN_MODEL_PEN(m)		((m) & (1 << 6))
+#define SYN_MODEL_SIMPLIC(m)		((m) & (1 << 5))
+#define SYN_MODEL_GEOMETRY(m)		((m) & 0x0f)
+
+/* synaptics capability bits */
+#define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_SLEEP(c)		((c) & (1 << 4))
+#define SYN_CAP_FOUR_BUTTON(c)		((c) & (1 << 3))
+#define SYN_CAP_MULTIFINGER(c)		((c) & (1 << 1))
+#define SYN_CAP_PALMDETECT(c)		((c) & (1 << 0))
+#define SYN_CAP_VALID(c)		((((c) & 0x00ff00) >> 8) == 0x47)
+
+/* synaptics modes query bits */
+#define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
+#define SYN_MODE_RATE(m)		((m) & (1 << 6))
+#define SYN_MODE_BAUD_SLEEP(m)		((m) & (1 << 3))
+#define SYN_MODE_DISABLE_GESTURE(m)	((m) & (1 << 2))
+#define SYN_MODE_PACKSIZE(m)		((m) & (1 << 1))
+#define SYN_MODE_WMODE(m)		((m) & (1 << 0))
+
+/* synaptics identify query bits */
+#define SYN_ID_MODEL(i) 		(((i) >> 4) & 0x0f)
+#define SYN_ID_MAJOR(i) 		((i) & 0x0f)
+#define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
+#define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
+
+
+struct synaptics_parameters {
+	int left_edge;				/* Edge coordinates, absolute */
+	int right_edge;
+	int top_edge;
+	int bottom_edge;
+
+	int finger_low, finger_high;		/* finger detection values in Z-values */
+	int tap_time, tap_move;			/* max. tapping-time and movement in packets and coord. */
+	int emulate_mid_button_time;		/* Max time between left and right button presses to
+						   emulate a middle button press. */
+	int scroll_dist_vert;			/* Scrolling distance in absolute coordinates */
+	int scroll_dist_horiz;			/* Scrolling distance in absolute coordinates */
+	int speed;				/* Pointer motion speed */
+	int edge_motion_speed;			/* Edge motion speed when dragging */
+	int updown_button_scrolling;		/* Up/Down-Button scrolling or middle/double-click */
+};
+
+/*
+ * A structure to describe the state of the touchpad hardware (buttons and pad)
+ */
+struct synaptics_hw_state {
+	int x;
+	int y;
+	int z;
+	int w;
+	int left;
+	int right;
+	int up;
+	int down;
+};
+
+#define SYNAPTICS_MOVE_HISTORY	5
+
+struct SynapticsTapRec {
+	int x, y;
+	unsigned int packet;
+};
+
+struct SynapticsMoveHist {
+	int x, y;
+};
+
+enum MidButtonEmulation {
+	MBE_OFF,			/* No button pressed */
+	MBE_LEFT,			/* Left button pressed, waiting for right button or timeout */
+	MBE_RIGHT,			/* Right button pressed, waiting for left button or timeout */
+	MBE_MID				/* Left and right buttons pressed, waiting for both buttons
+					   to be released */
+};
+
+struct synaptics_data {
+	struct synaptics_parameters params;
+
+	/* Data read from the touchpad */
+	unsigned long int model_id;		/* Model-ID */
+	unsigned long int capabilities; 	/* Capabilities */
+	unsigned long int identity;		/* Identification */
+
+	/* Data for normal processing */
+	unsigned char proto_buf[6];		/* Buffer for Packet */
+	unsigned char last_byte;		/* last received byte */
+	int inSync;				/* Packets in sync */
+	int proto_buf_tail;
+
+	struct SynapticsTapRec touch_on;	/* data when the touchpad is touched */
+	struct SynapticsMoveHist move_hist[SYNAPTICS_MOVE_HISTORY];
+						/* movement history */
+	int accum_dx;				/* Accumulated fractional pointer motion */
+	int accum_dy;
+	int scroll_x;				/* last x-scroll position */
+	int scroll_y;				/* last y-scroll position */
+	unsigned int count_packet_finger;	/* packet counter with finger on the touchpad */
+	unsigned int count_packet;		/* packet counter */
+	unsigned int count_packet_tapping;	/* packet counter for tapping */
+	unsigned int count_button_delay;	/* button delay for 3rd button emulation */
+	unsigned int prev_up;			/* Previous up button value, for double click emulation */
+	int finger_flag;			/* previous finger */
+	int tap, drag, doubletap;		/* feature flags */
+	int tap_left, tap_mid, tap_right;	/* tapping buttons */
+	int vert_scroll_on;			/* scrolling flag */
+	int horiz_scroll_on;			/* scrolling flag */
+	enum MidButtonEmulation mid_emu_state;	/* emulated 3rd button */
+
+	atomic_t timer_active;
+	struct timer_list timer;		/* for up/down-button repeat */
+	int repeat_buttons;			/* buttons for repeat */
+	int last_up, last_down;			/* Previous value of up/down buttons */
+
+	int finger_count;			/* tap counter for fingers */
+
+	/* For palm detection */
+	int palm;				/* Set to true when palm detected, reset to false when
+						 * palm/finger contact disappears */
+	int prev_z;				/* previous z value, for palm detection */
+	int avg_w;				/* weighted average of previous w values */
+};
+
+#endif /* _SYNAPTICS_H */

-- 
Peter Osterlund - petero2@telia.com
http://w1.894.telia.com/~u89404340


^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2003-07-12 10:33 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <m2smqhqk4k.fsf@p4.localdomain>
2003-06-11 15:02 ` [PATCH] Synaptics TouchPad driver for 2.5.70 Vojtech Pavlik
2003-06-11 18:16   ` Peter Osterlund
2003-06-11 18:26     ` Vojtech Pavlik
2003-06-11 18:29     ` AlberT
2003-06-11 18:34     ` Vojtech Pavlik
2003-06-11 21:23       ` Peter Osterlund
2003-06-12  2:48         ` Joseph Fannin
2003-06-12  2:54           ` CaT
2003-06-12 18:58             ` Peter Osterlund
2003-06-12 22:01               ` Peter Berg Larsen
2003-06-12 22:57                 ` Vojtech Pavlik
2003-06-12 23:17                   ` Peter Berg Larsen
2003-06-12 23:27                     ` Vojtech Pavlik
2003-06-12 23:42                       ` Peter Berg Larsen
2003-06-13  7:44                         ` Vojtech Pavlik
2003-06-13  8:58                           ` Peter Berg Larsen
2003-06-13 20:25                           ` James Simmons
2003-06-13 20:38                             ` Vojtech Pavlik
2003-06-13 20:51                               ` James Simmons
2003-06-13 22:08                                 ` Vojtech Pavlik
2003-06-13 23:57                                   ` James Simmons
2003-06-14  8:55                                     ` Vojtech Pavlik
2003-06-16 21:28                                       ` James Simmons
2003-06-12 19:11           ` Peter Osterlund
2003-06-12  6:31         ` Vojtech Pavlik
2003-06-12  8:36         ` James H. Cloos Jr.
2003-06-15 21:42           ` [PATCH] Synaptics Client/Passthrough (for Inspiron...) Arne Koewing
2003-06-13 21:15       ` [PATCH] Synaptics TouchPad driver for 2.5.70 Peter Osterlund
2003-06-13 21:49         ` James Simmons
2003-06-13 22:08         ` Vojtech Pavlik
2003-06-13 22:55           ` Peter Berg Larsen
2003-06-14  8:42             ` Vojtech Pavlik
2003-06-14 22:19 ` Vojtech Pavlik
2003-06-15 12:18   ` Peter Osterlund
2003-06-15 12:28     ` Vojtech Pavlik
2003-06-15 15:47       ` Peter Osterlund
2003-06-15 17:27         ` Vojtech Pavlik
2003-06-18 23:41           ` Peter Osterlund
2003-06-19  6:03             ` Vojtech Pavlik
2003-06-23 16:30             ` Andreas Jellinghaus
2003-06-23 19:04               ` Peter Osterlund
2003-06-26 20:01                 ` Vojtech Pavlik
2003-07-07 23:06                 ` Peter Osterlund
2003-07-12 10:51                   ` Andreas Jellinghaus
2003-06-10 22:52 Joseph Fannin
2003-06-11 15:30 ` Joseph Fannin
2003-06-11 20:17 ` Andrew Morton
2003-06-11 20:29   ` Vojtech Pavlik
2003-06-11 22:12     ` Peter Osterlund

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).