linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Synaptics: support for pass-through port (stick)
@ 2003-07-06  7:23 Dmitry Torokhov
  2003-07-06 13:23 ` Peter Berg Larsen
  0 siblings, 1 reply; 10+ messages in thread
From: Dmitry Torokhov @ 2003-07-06  7:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Vojtech Pavlik

Hi,

Here is my attempt to add support for pass-through port to the Synaptics 
touchpad driver so the track stick would work when the touchpad is in
absolute mode.

After synaptics driver and the rest of psmouse is fully initialized and
is about to enable reporting of motion data the new code creates and 
registers a new serio structure that does encapsulation of PS/2 commands
so touchpad would pass them to the stick. Synaptics' interrupt routine 
recognizes stick's packets and passes them to that new serio. The rest of 
the processing is done again by psmouse driver that binds on that new
pass-through serio and doesn't even notice anything unusual.

In order to register that pass-though serio I had to add 2 new functions
to the serio interface - serio_register/unregister_slave_port. These
functions do not try to acquire serio semaphore as it has already been 
downed. If this isn't appropriate I'm open to any suggestions.

The driver's output is like this:

Synaptics Touchpad, model: 1
 Firmware: 5.7
 180 degree mounted touchpad
 Sensor: 1
 new absolute packet format
 Touchpad has extended capability bits
 -> multifinger detection
 -> palm detection
 -> pass-through port
input: Synaptics Synaptics TouchPad on isa0060/serio1
serio: Synaptics pass-through port at isa0060/serio1/input0
input: PS/2 Generic Mouse on synaptics-pt/serio0


What you think?

Dmitry

diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/psmouse-base.c linux-2.5.74/drivers/input/mouse/psmouse-base.c
--- 2.5.74-vanilla/drivers/input/mouse/psmouse-base.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/psmouse-base.c	2003-07-06 01:41:18.000000000 -0500
@@ -132,31 +132,33 @@
 	}
 
 	if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
-		printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+		printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", 
+		       psmouse->name, psmouse->phys, psmouse->pktcnt);
 		psmouse->pktcnt = 0;
 	}
 	
 	psmouse->last = jiffies;
 	psmouse->packet[psmouse->pktcnt++] = data;
-
-	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
-		psmouse_process_packet(psmouse, regs);
-		psmouse->pktcnt = 0;
+	
+	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
+		serio_rescan(serio);
 		goto out;
 	}
 
-	if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+	if (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;
+		if (synaptics_process_byte(psmouse, regs))
+			psmouse->pktcnt = 0;
+		
 		goto out;
 	}
 
-	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
-		serio_rescan(serio);
+	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+		psmouse_process_packet(psmouse, regs);
+		psmouse->pktcnt = 0;
 		goto out;
 	}
 out:
@@ -450,14 +452,18 @@
  */
 
 	psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+}
 
 /*
- * Last, we enable the mouse so that we get reports from it.
+ * psmouse_activate() enables the mouse so that we get motion reports from it.
  */
 
+static void psmouse_activate(struct psmouse *psmouse)
+{
 	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
 		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
 
+	psmouse->init_done = 1;
 }
 
 /*
@@ -478,9 +484,10 @@
 static void psmouse_disconnect(struct serio *serio)
 {
 	struct psmouse *psmouse = serio->private;
+
 	input_unregister_device(&psmouse->dev);
-	serio_close(serio);
 	synaptics_disconnect(psmouse);
+	serio_close(serio);
 	kfree(psmouse);
 }
 
@@ -493,7 +500,8 @@
 {
 	struct psmouse *psmouse;
 	
-	if ((serio->type & SERIO_TYPE) != SERIO_8042)
+	if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
+	    (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
 		return;
 
 	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
@@ -539,6 +547,10 @@
 	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 
 	psmouse_initialize(psmouse);
+
+	synaptics_pt_init(psmouse);
+
+	psmouse_activate(psmouse);
 }
 
 static struct serio_dev psmouse_dev = {
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/psmouse.h linux-2.5.74/drivers/input/mouse/psmouse.h
--- 2.5.74-vanilla/drivers/input/mouse/psmouse.h	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/psmouse.h	2003-07-05 00:42:51.000000000 -0500
@@ -31,18 +31,19 @@
 	unsigned long last;
 	char acking;
 	volatile char ack;
+	char init_done;
 	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
+#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);
 
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/synaptics.c linux-2.5.74/drivers/input/mouse/synaptics.c
--- 2.5.74-vanilla/drivers/input/mouse/synaptics.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/synaptics.c	2003-07-05 19:23:11.000000000 -0500
@@ -1,6 +1,9 @@
 /*
  * Synaptics TouchPad PS/2 mouse driver
  *
+ *   2003 Dmitry Torokhov <dtor@mail.ru>
+ *     Added support for pass-through port
+ *     
  *   2003 Peter Osterlund <petero2@telia.com>
  *     Ported to 2.5 input device infrastructure.
  *
@@ -21,6 +24,7 @@
 
 #include <linux/module.h>
 #include <linux/input.h>
+#include <linux/serio.h>
 #include "psmouse.h"
 #include "synaptics.h"
 
@@ -134,17 +138,10 @@
 	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),
+	printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
 	       SYN_ID_MINOR(priv->identity));
 
 	if (SYN_MODEL_ROT180(priv->model_id))
@@ -165,6 +162,8 @@
 			printk(KERN_INFO " -> multifinger detection\n");
 		if (SYN_CAP_PALMDETECT(priv->capabilities))
 			printk(KERN_INFO " -> palm detection\n");
+		if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+			printk(KERN_INFO " -> pass-through port\n");
 	}
 }
 
@@ -188,13 +187,88 @@
 					 SYN_BIT_W_MODE)))
 		return -1;
 
-	synaptics_enable_device(psmouse);
+	return 0;
+}
 
-	print_ident(priv);
+/*****************************************************************************
+ *	Synaptics pass-through PS/2 port support
+ ****************************************************************************/
+static int synaptics_pt_open(struct serio *port)
+{
+	return 0;
+}
+
+static void synaptics_pt_close(struct serio *port)
+{
+}
+
+static int synaptics_pt_write(struct serio *port, unsigned char c)
+{
+	struct psmouse *parent = port->driver;
+	char client_cmd = 0x28; // indicates that we want pass-through port
 
+	if (synaptics_special_cmd(parent, c))
+		return -1;
+	if (psmouse_command(parent, &client_cmd, PSMOUSE_CMD_SETRATE))
+		return -1;
 	return 0;
 }
 
+static inline int synaptics_is_pt_packet(unsigned char *buf)
+{
+	return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
+}
+
+static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+{
+	struct psmouse *child = ptport->private;
+
+	if (child) {
+		if (child->init_done) {
+			serio_interrupt(ptport, packet[1], 0, NULL);
+			if (child->type >= PSMOUSE_GENPS)	
+				serio_interrupt(ptport, packet[2], 0, NULL);
+			serio_interrupt(ptport, packet[4], 0, NULL);
+			serio_interrupt(ptport, packet[5], 0, NULL);
+		} else {
+			serio_interrupt(ptport, packet[1], 0, NULL);
+		}
+	}
+}
+
+int synaptics_pt_init(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct serio *port;
+	
+	if (psmouse->type != PSMOUSE_SYNAPTICS)
+		return -1;
+	if (!SYN_CAP_EXTENDED(priv->capabilities))
+		return -1;
+	if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
+		return -1;
+
+	priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	if (unlikely(!port)) {
+		printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");	
+		return -1;
+	}
+	
+	memset(port, 0, sizeof(struct serio));
+	port->type = SERIO_PS_PSTHRU;
+	port->name = "Synaptics pass-through";
+	port->phys = "synaptics-pt/serio0";
+	port->write = synaptics_pt_write;
+	port->open = synaptics_pt_open;
+	port->close = synaptics_pt_close;
+	port->driver = psmouse;
+	
+	printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
+	serio_register_slave_port(port);
+	
+	return 0;	
+}
+
 /*****************************************************************************
  *	Driver initialization/cleanup functions
  ****************************************************************************/
@@ -225,6 +299,8 @@
 		goto init_fail;
 	}
 
+	print_ident(priv);
+
 	/*
 	 * 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
@@ -259,17 +335,24 @@
 {
 	struct synaptics_data *priv = psmouse->private;
 
-	kfree(priv);
+	if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
+		synaptics_set_mode(psmouse, 0);
+		if (priv->ptport) {
+			serio_unregister_slave_port(priv->ptport);
+			kfree(priv->ptport);
+		} 
+		kfree(priv);
+	}
 }
 
 /*****************************************************************************
  *	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(unsigned char buf[],
+				     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]);
@@ -283,7 +366,7 @@
 		 ((buf[3] & 0x04) >> 2));
 
 	hw->left  = (buf[0] & 0x01) ? 1 : 0;
-	hw->right = (buf[0] & 0x2) ? 1 : 0;
+	hw->right = (buf[0] & 0x02) ? 1 : 0;
 	hw->up    = 0;
 	hw->down  = 0;
 
@@ -307,7 +390,7 @@
 	struct synaptics_data *priv = psmouse->private;
 	struct synaptics_hw_state hw;
 
-	synaptics_parse_hw_state(priv, &hw);
+	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
 	if (hw.z > 0) {
 		int w_ok = 0;
@@ -351,39 +434,42 @@
 	input_sync(dev);
 }
 
-void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+int 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];
+	unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
 
 	input_regs(dev, regs);
 
-	pBuf[priv->proto_buf_tail++] = u;
-
 	/* check first byte */
-	if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
+	if (psmouse->pktcnt == 1 && (data & 0xC8) != 0x80) {
 		priv->inSync = 0;
-		priv->proto_buf_tail = 0;
 		printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
-		return;
+		return 1;
 	}
 
 	/* check 4th byte */
-	if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
+	if (psmouse->pktcnt == 4 && (data & 0xC8) != 0xC0) {
 		priv->inSync = 0;
-		priv->proto_buf_tail = 0;
 		printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
-		return;
+		return 1;
 	}
 
-	if (priv->proto_buf_tail >= 6) { /* Full packet received */
+	if (psmouse->pktcnt >= 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;
+		
+		if (priv->ptport && synaptics_is_pt_packet(psmouse->packet)) 
+			synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
+		else
+			synaptics_process_packet(psmouse);
+		
+		return 1;	
 	}
+	
+	return 0;
 }
+
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/synaptics.h linux-2.5.74/drivers/input/mouse/synaptics.h
--- 2.5.74-vanilla/drivers/input/mouse/synaptics.h	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/synaptics.h	2003-07-05 00:44:41.000000000 -0500
@@ -10,8 +10,9 @@
 #define _SYNAPTICS_H
 
 
-extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
+extern int synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
 extern int synaptics_init(struct psmouse *psmouse);
+extern int synaptics_pt_init(struct psmouse *psmouse);
 extern void synaptics_disconnect(struct psmouse *psmouse);
 
 /* synaptics queries */
@@ -42,6 +43,7 @@
 
 /* synaptics capability bits */
 #define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_PASS_THROUGH(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))
@@ -62,6 +64,9 @@
 #define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
 #define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
 
+#define SYN_REL_DECEL_FACTOR		8
+#define SYN_REL_PRESSURE_THRESHOLD	30
+
 /*
  * A structure to describe the state of the touchpad hardware (buttons and pad)
  */
@@ -84,12 +89,10 @@
 	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 */
+	
+	struct serio *ptport;			/* pass-through port */
 };
 
 #endif /* _SYNAPTICS_H */
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/serio/serio.c linux-2.5.74/drivers/input/serio/serio.c
--- 2.5.74-vanilla/drivers/input/serio/serio.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/serio/serio.c	2003-07-05 19:21:35.000000000 -0500
@@ -45,7 +45,9 @@
 
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_register_slave_port);
 EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_slave_port);
 EXPORT_SYMBOL(serio_register_device);
 EXPORT_SYMBOL(serio_unregister_device);
 EXPORT_SYMBOL(serio_open);
@@ -162,6 +164,16 @@
 	up(&serio_sem);
 }
 
+/* Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when registering a serio from other input device's
+ * connect() function.
+ */
+void serio_register_slave_port(struct serio *serio)
+{
+	list_add_tail(&serio->node, &serio_list);
+	serio_find_dev(serio);
+}
+
 void serio_unregister_port(struct serio *serio)
 {
 	down(&serio_sem);
@@ -171,6 +183,17 @@
 	up(&serio_sem);
 }
 
+/* Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when unregistering a serio from other input device's
+ * disconnect() function.
+ */
+void serio_unregister_slave_port(struct serio *serio)
+{
+	list_del_init(&serio->node);
+	if (serio->dev && serio->dev->disconnect)
+		serio->dev->disconnect(serio);
+}
+
 void serio_register_device(struct serio_dev *dev)
 {
 	struct serio *serio;
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/include/linux/serio.h linux-2.5.74/include/linux/serio.h
--- 2.5.74-vanilla/include/linux/serio.h	2003-07-05 00:29:02.000000000 -0500
+++ linux-2.5.74/include/linux/serio.h	2003-07-05 19:17:56.000000000 -0500
@@ -65,7 +65,9 @@
 irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
 
 void serio_register_port(struct serio *serio);
+void serio_register_slave_port(struct serio *serio);
 void serio_unregister_port(struct serio *serio);
+void serio_unregister_slave_port(struct serio *serio);
 void serio_register_device(struct serio_dev *dev);
 void serio_unregister_device(struct serio_dev *dev);
 
@@ -104,6 +106,7 @@
 #define SERIO_RS232	0x02000000UL
 #define SERIO_HIL_MLC	0x03000000UL
 #define SERIO_PC9800	0x04000000UL
+#define SERIO_PS_PSTHRU	0x05000000UL
 
 #define SERIO_PROTO	0xFFUL
 #define SERIO_MSC	0x01

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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-06  7:23 [PATCH] Synaptics: support for pass-through port (stick) Dmitry Torokhov
@ 2003-07-06 13:23 ` Peter Berg Larsen
  2003-07-07  3:48   ` Dmitry Torokhov
  0 siblings, 1 reply; 10+ messages in thread
From: Peter Berg Larsen @ 2003-07-06 13:23 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, Vojtech Pavlik


On Sun, 6 Jul 2003, Dmitry Torokhov wrote:


> -		psmouse_process_packet(psmouse, regs);
> -		psmouse->pktcnt = 0;
> +
> +	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
> +		serio_rescan(serio);
>  		goto out;
>  	}
>
> -	if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
> +	if (psmouse->type == PSMOUSE_SYNAPTICS) {


Why did you move the rescan up above the synaptics test? if the synaptics
is out of sync, any byte can be recieved.


> +static int synaptics_pt_write(struct serio *port, unsigned char c)
> +{
> +	struct psmouse *parent = port->driver;
> +	char client_cmd = 0x28; // indicates that we want pass-through port

Could client_cmd be renamed to f.ex. rate_param?


> +		if (child->init_done) {
> +			serio_interrupt(ptport, packet[1], 0, NULL);
> +			if (child->type >= PSMOUSE_GENPS)
> +				serio_interrupt(ptport, packet[2], 0, NULL);
> +			serio_interrupt(ptport, packet[4], 0, NULL);
> +			serio_interrupt(ptport, packet[5], 0, NULL);

The 4th protocol byte from a guest is the 3rd byte in the encapsulated
packet from the pad. So I would move "if (..." last.

There might be a (de)multiplexing problem here. The button information
(pressed/released) in byte 0 and 3 is lost, and are not repeated in the
guest protocol.


> +	port->type = SERIO_PS_PSTHRU;
> +	port->name = "Synaptics pass-through";
> +	port->phys = "synaptics-pt/serio0";
> +	port->write = synaptics_pt_write;
> +	port->open = synaptics_pt_open;
> +	port->close = synaptics_pt_close;
> +	port->driver = psmouse;
> +
> +	printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
> +	serio_register_slave_port(port);
> +
> +	return 0;
> +}
> +

Bit 2 in the pads second mode byte must be set if the guest uses a 4 bytes
protocol. So you need to check which protocol is negotiated on the slave
port.


Peter



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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-06 13:23 ` Peter Berg Larsen
@ 2003-07-07  3:48   ` Dmitry Torokhov
  2003-07-07 11:44     ` Peter Berg Larsen
  0 siblings, 1 reply; 10+ messages in thread
From: Dmitry Torokhov @ 2003-07-07  3:48 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: linux-kernel, Vojtech Pavlik

On Sunday 06 July 2003 08:23 am, Peter Berg Larsen wrote:
> On Sun, 6 Jul 2003, Dmitry Torokhov wrote:
> > -	if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
> > +	if (psmouse->type == PSMOUSE_SYNAPTICS) {
>
> Why did you move the rescan up above the synaptics test? if the synaptics
> is out of sync, any byte can be recieved.
>

Yes, any byte can be received but it is unlikely that we will receive 0xAA.
On the other hand by moving rescan there it will actually work if somehow 
the device gets reset. (What happens on resume for example? I am not sure as
I didn't get to play with suspending/resuming my laptop yet.)

> > +static int synaptics_pt_write(struct serio *port, unsigned char c)
> > +{
> > +	struct psmouse *parent = port->driver;
> > +	char client_cmd = 0x28; // indicates that we want pass-through port
>
> Could client_cmd be renamed to f.ex. rate_param?

Ok... although it has nothing to do with setting rate...

What you think about the patch below? I fixed the client's protocol order,
button reporting (only left and right as I am not sure to which buttons
up/down should be mapped), and switching to 4-byte protocol for master.
Unfortunately my stick reports as generic PS/2 mouse so I can't test the 
4 byte protocol.

Dmitry

diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/psmouse-base.c linux-2.5.74/drivers/input/mouse/psmouse-base.c
--- 2.5.74-vanilla/drivers/input/mouse/psmouse-base.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/psmouse-base.c	2003-07-06 01:41:18.000000000 -0500
@@ -132,31 +132,33 @@
 	}
 
 	if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
-		printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+		printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", 
+		       psmouse->name, psmouse->phys, psmouse->pktcnt);
 		psmouse->pktcnt = 0;
 	}
 	
 	psmouse->last = jiffies;
 	psmouse->packet[psmouse->pktcnt++] = data;
-
-	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
-		psmouse_process_packet(psmouse, regs);
-		psmouse->pktcnt = 0;
+	
+	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
+		serio_rescan(serio);
 		goto out;
 	}
 
-	if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+	if (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;
+		if (synaptics_process_byte(psmouse, regs))
+			psmouse->pktcnt = 0;
+		
 		goto out;
 	}
 
-	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
-		serio_rescan(serio);
+	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+		psmouse_process_packet(psmouse, regs);
+		psmouse->pktcnt = 0;
 		goto out;
 	}
 out:
@@ -450,14 +452,18 @@
  */
 
 	psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+}
 
 /*
- * Last, we enable the mouse so that we get reports from it.
+ * psmouse_activate() enables the mouse so that we get motion reports from it.
  */
 
+static void psmouse_activate(struct psmouse *psmouse)
+{
 	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
 		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
 
+	psmouse->init_done = 1;
 }
 
 /*
@@ -478,9 +484,10 @@
 static void psmouse_disconnect(struct serio *serio)
 {
 	struct psmouse *psmouse = serio->private;
+
 	input_unregister_device(&psmouse->dev);
-	serio_close(serio);
 	synaptics_disconnect(psmouse);
+	serio_close(serio);
 	kfree(psmouse);
 }
 
@@ -493,7 +500,8 @@
 {
 	struct psmouse *psmouse;
 	
-	if ((serio->type & SERIO_TYPE) != SERIO_8042)
+	if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
+	    (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
 		return;
 
 	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
@@ -539,6 +547,10 @@
 	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 
 	psmouse_initialize(psmouse);
+
+	synaptics_pt_init(psmouse);
+
+	psmouse_activate(psmouse);
 }
 
 static struct serio_dev psmouse_dev = {
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/psmouse.h linux-2.5.74/drivers/input/mouse/psmouse.h
--- 2.5.74-vanilla/drivers/input/mouse/psmouse.h	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/psmouse.h	2003-07-05 00:42:51.000000000 -0500
@@ -31,18 +31,19 @@
 	unsigned long last;
 	char acking;
 	volatile char ack;
+	char init_done;
 	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
+#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);
 
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/synaptics.c linux-2.5.74/drivers/input/mouse/synaptics.c
--- 2.5.74-vanilla/drivers/input/mouse/synaptics.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/synaptics.c	2003-07-06 22:01:27.000000000 -0500
@@ -1,6 +1,9 @@
 /*
  * Synaptics TouchPad PS/2 mouse driver
  *
+ *   2003 Dmitry Torokhov <dtor@mail.ru>
+ *     Added support for pass-through port
+ *     
  *   2003 Peter Osterlund <petero2@telia.com>
  *     Ported to 2.5 input device infrastructure.
  *
@@ -21,6 +24,7 @@
 
 #include <linux/module.h>
 #include <linux/input.h>
+#include <linux/serio.h>
 #include "psmouse.h"
 #include "synaptics.h"
 
@@ -71,7 +75,7 @@
 
 	if (synaptics_special_cmd(psmouse, mode))
 		return -1;
-	param[0] = 0x14;
+	param[0] = SYN_PS_SET_MODE2;
 	if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
 		return -1;
 	return 0;
@@ -134,17 +138,10 @@
 	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),
+	printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
 	       SYN_ID_MINOR(priv->identity));
 
 	if (SYN_MODEL_ROT180(priv->model_id))
@@ -165,6 +162,8 @@
 			printk(KERN_INFO " -> multifinger detection\n");
 		if (SYN_CAP_PALMDETECT(priv->capabilities))
 			printk(KERN_INFO " -> palm detection\n");
+		if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+			printk(KERN_INFO " -> pass-through port\n");
 	}
 }
 
@@ -188,13 +187,105 @@
 					 SYN_BIT_W_MODE)))
 		return -1;
 
-	synaptics_enable_device(psmouse);
+	return 0;
+}
 
-	print_ident(priv);
+/*****************************************************************************
+ *	Synaptics pass-through PS/2 port support
+ ****************************************************************************/
+static int synaptics_pt_open(struct serio *port)
+{
+	return 0;
+}
+
+static void synaptics_pt_close(struct serio *port)
+{
+}
+
+static int synaptics_pt_write(struct serio *port, unsigned char c)
+{
+	struct psmouse *parent = port->driver;
+	char rate_param = SYN_PS_CLIENT_CMD; // indicates that we want pass-through port
 
+	if (synaptics_special_cmd(parent, c))
+		return -1;
+	if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
+		return -1;
 	return 0;
 }
 
+static inline int synaptics_is_pt_packet(unsigned char *buf)
+{
+	return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
+}
+
+static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+{
+	struct psmouse *child = ptport->private;
+
+	if (child) {
+		if (child->init_done) {
+			/* mix in parent's button information into the packet 
+			 * in case stick does not have its own connected
+			 */
+			packet[1] |= packet[0] & 3;
+			
+			serio_interrupt(ptport, packet[1], 0, NULL);
+			serio_interrupt(ptport, packet[4], 0, NULL);
+			serio_interrupt(ptport, packet[5], 0, NULL);
+			if (child->type >= PSMOUSE_GENPS)	
+				serio_interrupt(ptport, packet[2], 0, NULL);
+		} else {
+			serio_interrupt(ptport, packet[1], 0, NULL);
+		}
+	}
+}
+
+int synaptics_pt_init(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct serio *port;
+	struct psmouse *child;
+	
+	if (psmouse->type != PSMOUSE_SYNAPTICS)
+		return -1;
+	if (!SYN_CAP_EXTENDED(priv->capabilities))
+		return -1;
+	if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
+		return -1;
+
+	priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	if (unlikely(!port)) {
+		printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");	
+		return -1;
+	}
+	
+	memset(port, 0, sizeof(struct serio));
+	port->type = SERIO_PS_PSTHRU;
+	port->name = "Synaptics pass-through";
+	port->phys = "synaptics-pt/serio0";
+	port->write = synaptics_pt_write;
+	port->open = synaptics_pt_open;
+	port->close = synaptics_pt_close;
+	port->driver = psmouse;
+	
+	printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
+	serio_register_slave_port(port);
+
+	/* adjust the touchpad to child's choice of protocol */
+	child = port->private;
+	if (child && child->type >= PSMOUSE_GENPS) {
+		if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+					 	 SYN_BIT_HIGH_RATE |
+					 	 SYN_BIT_DISABLE_GESTURE |
+						 SYN_BIT_FOUR_BYTE_CLIENT |
+					 	 SYN_BIT_W_MODE)))
+			printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+	}
+	
+	return 0;	
+}
+
 /*****************************************************************************
  *	Driver initialization/cleanup functions
  ****************************************************************************/
@@ -225,6 +316,8 @@
 		goto init_fail;
 	}
 
+	print_ident(priv);
+
 	/*
 	 * 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
@@ -259,17 +352,24 @@
 {
 	struct synaptics_data *priv = psmouse->private;
 
-	kfree(priv);
+	if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
+		synaptics_set_mode(psmouse, 0);
+		if (priv->ptport) {
+			serio_unregister_slave_port(priv->ptport);
+			kfree(priv->ptport);
+		} 
+		kfree(priv);
+	}
 }
 
 /*****************************************************************************
  *	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(unsigned char buf[],
+				     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]);
@@ -283,7 +383,7 @@
 		 ((buf[3] & 0x04) >> 2));
 
 	hw->left  = (buf[0] & 0x01) ? 1 : 0;
-	hw->right = (buf[0] & 0x2) ? 1 : 0;
+	hw->right = (buf[0] & 0x02) ? 1 : 0;
 	hw->up    = 0;
 	hw->down  = 0;
 
@@ -307,7 +407,7 @@
 	struct synaptics_data *priv = psmouse->private;
 	struct synaptics_hw_state hw;
 
-	synaptics_parse_hw_state(priv, &hw);
+	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
 	if (hw.z > 0) {
 		int w_ok = 0;
@@ -351,39 +451,42 @@
 	input_sync(dev);
 }
 
-void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+int 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];
+	unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
 
 	input_regs(dev, regs);
 
-	pBuf[priv->proto_buf_tail++] = u;
-
 	/* check first byte */
-	if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
+	if (psmouse->pktcnt == 1 && (data & 0xC8) != 0x80) {
 		priv->inSync = 0;
-		priv->proto_buf_tail = 0;
 		printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
-		return;
+		return 1;
 	}
 
 	/* check 4th byte */
-	if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
+	if (psmouse->pktcnt == 4 && (data & 0xC8) != 0xC0) {
 		priv->inSync = 0;
-		priv->proto_buf_tail = 0;
 		printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
-		return;
+		return 1;
 	}
 
-	if (priv->proto_buf_tail >= 6) { /* Full packet received */
+	if (psmouse->pktcnt >= 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;
+		
+		if (priv->ptport && synaptics_is_pt_packet(psmouse->packet)) 
+			synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
+		else
+			synaptics_process_packet(psmouse);
+		
+		return 1;	
 	}
+	
+	return 0;
 }
+
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/synaptics.h linux-2.5.74/drivers/input/mouse/synaptics.h
--- 2.5.74-vanilla/drivers/input/mouse/synaptics.h	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/synaptics.h	2003-07-06 22:01:41.000000000 -0500
@@ -10,8 +10,9 @@
 #define _SYNAPTICS_H
 
 
-extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
+extern int synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
 extern int synaptics_init(struct psmouse *psmouse);
+extern int synaptics_pt_init(struct psmouse *psmouse);
 extern void synaptics_disconnect(struct psmouse *psmouse);
 
 /* synaptics queries */
@@ -28,6 +29,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_FOUR_BYTE_CLIENT	(1 << 1)
 #define SYN_BIT_W_MODE			(1 << 0)
 
 /* synaptics model ID bits */
@@ -42,6 +44,7 @@
 
 /* synaptics capability bits */
 #define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_PASS_THROUGH(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))
@@ -62,6 +65,10 @@
 #define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
 #define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
 
+/* synaptics special commands */
+#define SYN_PS_SET_MODE2		0x14
+#define SYN_PS_CLIENT_CMD		0x28
+
 /*
  * A structure to describe the state of the touchpad hardware (buttons and pad)
  */
@@ -84,12 +91,10 @@
 	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 */
+	
+	struct serio *ptport;			/* pass-through port */
 };
 
 #endif /* _SYNAPTICS_H */
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/serio/serio.c linux-2.5.74/drivers/input/serio/serio.c
--- 2.5.74-vanilla/drivers/input/serio/serio.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/serio/serio.c	2003-07-05 19:21:35.000000000 -0500
@@ -45,7 +45,9 @@
 
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_register_slave_port);
 EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_slave_port);
 EXPORT_SYMBOL(serio_register_device);
 EXPORT_SYMBOL(serio_unregister_device);
 EXPORT_SYMBOL(serio_open);
@@ -162,6 +164,16 @@
 	up(&serio_sem);
 }
 
+/* Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when registering a serio from other input device's
+ * connect() function.
+ */
+void serio_register_slave_port(struct serio *serio)
+{
+	list_add_tail(&serio->node, &serio_list);
+	serio_find_dev(serio);
+}
+
 void serio_unregister_port(struct serio *serio)
 {
 	down(&serio_sem);
@@ -171,6 +183,17 @@
 	up(&serio_sem);
 }
 
+/* Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when unregistering a serio from other input device's
+ * disconnect() function.
+ */
+void serio_unregister_slave_port(struct serio *serio)
+{
+	list_del_init(&serio->node);
+	if (serio->dev && serio->dev->disconnect)
+		serio->dev->disconnect(serio);
+}
+
 void serio_register_device(struct serio_dev *dev)
 {
 	struct serio *serio;
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/include/linux/serio.h linux-2.5.74/include/linux/serio.h
--- 2.5.74-vanilla/include/linux/serio.h	2003-07-05 00:29:02.000000000 -0500
+++ linux-2.5.74/include/linux/serio.h	2003-07-05 19:17:56.000000000 -0500
@@ -65,7 +65,9 @@
 irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
 
 void serio_register_port(struct serio *serio);
+void serio_register_slave_port(struct serio *serio);
 void serio_unregister_port(struct serio *serio);
+void serio_unregister_slave_port(struct serio *serio);
 void serio_register_device(struct serio_dev *dev);
 void serio_unregister_device(struct serio_dev *dev);
 
@@ -104,6 +106,7 @@
 #define SERIO_RS232	0x02000000UL
 #define SERIO_HIL_MLC	0x03000000UL
 #define SERIO_PC9800	0x04000000UL
+#define SERIO_PS_PSTHRU	0x05000000UL
 
 #define SERIO_PROTO	0xFFUL
 #define SERIO_MSC	0x01

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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-07  3:48   ` Dmitry Torokhov
@ 2003-07-07 11:44     ` Peter Berg Larsen
  2003-07-07 12:09       ` Peter Berg Larsen
  2003-07-07 17:34       ` Dmitry Torokhov
  0 siblings, 2 replies; 10+ messages in thread
From: Peter Berg Larsen @ 2003-07-07 11:44 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, Vojtech Pavlik


On Sun, 6 Jul 2003, Dmitry Torokhov wrote:
> On Sunday 06 July 2003 08:23 am, Peter Berg Larsen wrote:

> > Why did you move the rescan up above the synaptics test? if the synaptics
> > is out of sync, any byte can be recieved.

> Yes, any byte can be received but it is unlikely that we will receive 0xAA.

Are you sure that it is unlikely for all type >= PSMOUSE_GENPS? How about
looking for the 0x00 also.

> +	if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
...
> +	if (psmouse->type == PSMOUSE_SYNAPTICS) {
...
> +	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {


> the device gets reset. (What happens on resume for example? I am not sure as
> I didn't get to play with suspending/resuming my laptop yet.)

The mode byte is cleared to default.


> What you think about the patch below? I fixed the client's protocol order,
> ... and switching to 4-byte protocol for master.

ok.

> button reporting (only left and right as I am not sure to which buttons
> up/down should be mapped),

hmm. You dont know what the guest protocol, so you can't just | the
button information. However, reallity is that this will work for nearly
anybody now.


> +	/* adjust the touchpad to child's choice of protocol */
> +	child = port->private;
> +	if (child && child->type >= PSMOUSE_GENPS) {

Not type > PSMOUSE_GENPS ?


Peter



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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-07 11:44     ` Peter Berg Larsen
@ 2003-07-07 12:09       ` Peter Berg Larsen
  2003-07-07 17:31         ` Dmitry Torokhov
  2003-07-08  5:59         ` Dmitry Torokhov
  2003-07-07 17:34       ` Dmitry Torokhov
  1 sibling, 2 replies; 10+ messages in thread
From: Peter Berg Larsen @ 2003-07-07 12:09 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, Vojtech Pavlik


On Mon, 7 Jul 2003, Peter Berg Larsen wrote:

Replying to myself.

> > button reporting (only left and right as I am not sure to which buttons
> > up/down should be mapped),
>
> hmm. You dont know what the guest protocol, so you can't just | the
> button information. However, reallity is that this will work for nearly
> anybody now.

This is not the greatest idea as the guest sometimes does not recieve the
button release. This is bad only if the userdriver multiplex the
micebuttons from different mice, because it would then seem as the user
holds the button down.


Peter




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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-07 12:09       ` Peter Berg Larsen
@ 2003-07-07 17:31         ` Dmitry Torokhov
  2003-07-08  5:59         ` Dmitry Torokhov
  1 sibling, 0 replies; 10+ messages in thread
From: Dmitry Torokhov @ 2003-07-07 17:31 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: linux-kernel, Vojtech Pavlik

On Monday 07 July 2003 07:09 am, Peter Berg Larsen wrote:
> On Mon, 7 Jul 2003, Peter Berg Larsen wrote:
>
> Replying to myself.
>
> > > button reporting (only left and right as I am not sure to which buttons
> > > up/down should be mapped),
> >
> > hmm. You dont know what the guest protocol, so you can't just | the
> > button information. However, reallity is that this will work for nearly
> > anybody now.
>
> This is not the greatest idea as the guest sometimes does not recieve the
> button release. This is bad only if the userdriver multiplex the
> micebuttons from different mice, because it would then seem as the user
> holds the button down.
>

So should we just get rid of all button multiplexing in kernel module and 
leave it to the userland (gpm/XFree)? Not trying to bail out, just want to 
find the best solution...

Dmitry

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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-07 11:44     ` Peter Berg Larsen
  2003-07-07 12:09       ` Peter Berg Larsen
@ 2003-07-07 17:34       ` Dmitry Torokhov
  2003-07-07 18:35         ` Peter Berg Larsen
  1 sibling, 1 reply; 10+ messages in thread
From: Dmitry Torokhov @ 2003-07-07 17:34 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: linux-kernel, Vojtech Pavlik

On Monday 07 July 2003 06:44 am, Peter Berg Larsen wrote:
> On Sun, 6 Jul 2003, Dmitry Torokhov wrote:
> > +	/* adjust the touchpad to child's choice of protocol */
> > +	child = port->private;
> > +	if (child && child->type >= PSMOUSE_GENPS) {
>
> Not type > PSMOUSE_GENPS ?
>

We have this code in psmouse-base.c ...

        if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
                psmouse_process_packet(psmouse, regs);
                psmouse->pktcnt = 0;
                goto out;
        }

..or am I misreading it?

I will check what can be done with 0xAA 0x00 before we decide to rescan 
later this evening.

Dmitry




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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-07 17:34       ` Dmitry Torokhov
@ 2003-07-07 18:35         ` Peter Berg Larsen
  2003-07-07 22:51           ` Dmitry Torokhov
  0 siblings, 1 reply; 10+ messages in thread
From: Peter Berg Larsen @ 2003-07-07 18:35 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, Vojtech Pavlik


On Mon, 7 Jul 2003, Dmitry Torokhov wrote:

> > > +	if (child && child->type >= PSMOUSE_GENPS) {
> > Not type > PSMOUSE_GENPS ?

> We have this code in psmouse-base.c ...
  ...
> ..or am I misreading it?

No, you are right. I misread it as generic ps2 protocol.

A complete different problem that might be a problem is that even though
the master(pad) says it has passthough capabilities, there might not be
any guest attached. The bit only tells that it is capable of handling one.
I asked synaptics about this some time ago and they replyed that the only
way to find out is to send a byte and look for a returnbyte or a timeout.



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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-07 18:35         ` Peter Berg Larsen
@ 2003-07-07 22:51           ` Dmitry Torokhov
  0 siblings, 0 replies; 10+ messages in thread
From: Dmitry Torokhov @ 2003-07-07 22:51 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: linux-kernel, Vojtech Pavlik

On Monday 07 July 2003 01:35 pm, Peter Berg Larsen wrote:
>
> A complete different problem that might be a problem is that even though
> the master(pad) says it has passthough capabilities, there might not be
> any guest attached. The bit only tells that it is capable of handling one.
> I asked synaptics about this some time ago and they replyed that the only
> way to find out is to send a byte and look for a returnbyte or a timeout.

I think this won't be a problem - if there is no guest attached then, when
we register pass-through serio port, psmouse_probe will run. The very first
thing it to tries identify attached device and bails out if something
goes wrong. In our case it should time out. This will leave us with a serio
without input device attached - a perfectly valid scenario I think.

Dmitry



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

* Re: [PATCH] Synaptics: support for pass-through port (stick)
  2003-07-07 12:09       ` Peter Berg Larsen
  2003-07-07 17:31         ` Dmitry Torokhov
@ 2003-07-08  5:59         ` Dmitry Torokhov
  1 sibling, 0 replies; 10+ messages in thread
From: Dmitry Torokhov @ 2003-07-08  5:59 UTC (permalink / raw)
  To: Peter Berg Larsen; +Cc: linux-kernel, Vojtech Pavlik

On Monday 07 July 2003 07:09 am, Peter Berg Larsen wrote:
> On Mon, 7 Jul 2003, Peter Berg Larsen wrote:
>
> Replying to myself.
>
> > > button reporting (only left and right as I am not sure to which buttons
> > > up/down should be mapped),
> >
> > hmm. You dont know what the guest protocol, so you can't just | the
> > button information. However, reallity is that this will work for nearly
> > anybody now.
>
> This is not the greatest idea as the guest sometimes does not recieve the
> button release. This is bad only if the userdriver multiplex the
> micebuttons from different mice, because it would then seem as the user
> holds the button down.
>

Ok, here is hopefully the final version:

- no button multiplexing is done in kernel, this task is left for the 
userland (gpm/XFree);

- the driver looks for both 0xAA and 0x00 before attempting rescan;

- there is a new module parameter - psmouse_resetafter - which specifies 
how many bad packets synaptics will receive before attempting to rescan
(plugging my laptop into a docking station causes synaptics to be silently
reset back into relative mode, having this parameter set to let's say 10 
allows quickly restore it). 0 - never.

Dmitry

diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/Documentation/kernel-parameters.txt linux-2.5.74/Documentation/kernel-parameters.txt
--- 2.5.74-vanilla/Documentation/kernel-parameters.txt	2003-06-14 14:18:52.000000000 -0500
+++ linux-2.5.74/Documentation/kernel-parameters.txt	2003-07-08 00:14:07.000000000 -0500
@@ -780,6 +780,10 @@
 
 	psmouse_noext	[HW,MOUSE] Disable probing for PS2 mouse protocol extensions
 
+	psmouse_resetafter= 
+			[HW,MOUSE] Try to reset Synaptics Touchpad after so many
+			bad packets (0 = never).
+
 	pss=		[HW,OSS] Personal Sound System (ECHO ESC614)
 			Format: <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
 
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/psmouse-base.c linux-2.5.74/drivers/input/mouse/psmouse-base.c
--- 2.5.74-vanilla/drivers/input/mouse/psmouse-base.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/psmouse-base.c	2003-07-08 00:14:15.000000000 -0500
@@ -29,18 +29,20 @@
 MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
 MODULE_PARM(psmouse_smartscroll, "i");
 MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
+MODULE_PARM(psmouse_resetafter, "i");
+MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
 MODULE_LICENSE("GPL");
 
 #define PSMOUSE_LOGITECH_SMARTSCROLL	1
-
 static int psmouse_noext;
 int psmouse_resolution;
 int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL;
+unsigned int psmouse_resetafter;
 
 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
+ * psmouse_process_packet() analyzes the PS/2 mouse packet contents and
  * reports relevant events to the input module.
  */
 
@@ -108,6 +110,9 @@
 {
 	struct psmouse *psmouse = serio->private;
 
+	if (psmouse->state == PSMOUSE_IGNORE)
+		goto out;
+	
 	if (psmouse->acking) {
 		switch (data) {
 			case PSMOUSE_RET_ACK:
@@ -132,31 +137,46 @@
 	}
 
 	if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
-		printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+		printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", 
+		       psmouse->name, psmouse->phys, psmouse->pktcnt);
 		psmouse->pktcnt = 0;
 	}
 	
 	psmouse->last = jiffies;
 	psmouse->packet[psmouse->pktcnt++] = data;
-
-	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
-		psmouse_process_packet(psmouse, regs);
-		psmouse->pktcnt = 0;
-		goto out;
+	
+	if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
+		if (psmouse->pktcnt == 1) 
+			goto out;
+		
+		if (psmouse->pktcnt == 2) {
+			if (psmouse->packet[1] == PSMOUSE_RET_ID) {
+				psmouse->state = PSMOUSE_IGNORE;
+				serio_rescan(serio);
+				goto out;
+			}
+			if (psmouse->type == PSMOUSE_SYNAPTICS) {
+				/* neither 0xAA nor 0x00 are valid first bytes
+				 * for a packet in absolute mode
+				 */
+				psmouse->pktcnt = 0;
+				goto out;
+			}
+		}
 	}
-
-	if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+	
+	if (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);
+	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+		psmouse_process_packet(psmouse, regs);
+		psmouse->pktcnt = 0;
 		goto out;
 	}
 out:
@@ -450,14 +470,18 @@
  */
 
 	psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+}
 
 /*
- * Last, we enable the mouse so that we get reports from it.
+ * psmouse_activate() enables the mouse so that we get motion reports from it.
  */
 
+static void psmouse_activate(struct psmouse *psmouse)
+{
 	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
 		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
 
+	psmouse->state = PSMOUSE_ACTIVATED;
 }
 
 /*
@@ -478,9 +502,11 @@
 static void psmouse_disconnect(struct serio *serio)
 {
 	struct psmouse *psmouse = serio->private;
+
+	psmouse->state = PSMOUSE_IGNORE;
 	input_unregister_device(&psmouse->dev);
-	serio_close(serio);
 	synaptics_disconnect(psmouse);
+	serio_close(serio);
 	kfree(psmouse);
 }
 
@@ -493,7 +519,8 @@
 {
 	struct psmouse *psmouse;
 	
-	if ((serio->type & SERIO_TYPE) != SERIO_8042)
+	if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
+	    (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
 		return;
 
 	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
@@ -506,6 +533,7 @@
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 
+	psmouse->state = PSMOUSE_NEW_DEVICE;
 	psmouse->serio = serio;
 	psmouse->dev.private = psmouse;
 
@@ -539,6 +567,10 @@
 	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 
 	psmouse_initialize(psmouse);
+
+	synaptics_pt_init(psmouse);
+
+	psmouse_activate(psmouse);
 }
 
 static struct serio_dev psmouse_dev = {
@@ -567,9 +599,16 @@
 	return 1;
 }
 
+static int __init psmouse_resetafter_setup(char *str)
+{
+	get_option(&str, &psmouse_resetafter);
+	return 1;
+}
+
 __setup("psmouse_noext", psmouse_noext_setup);
 __setup("psmouse_resolution=", psmouse_resolution_setup);
 __setup("psmouse_smartscroll=", psmouse_smartscroll_setup);
+__setup("psmouse_resetafter=", psmouse_resetafter_setup);
 
 #endif
 
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/psmouse.h linux-2.5.74/drivers/input/mouse/psmouse.h
--- 2.5.74-vanilla/drivers/input/mouse/psmouse.h	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/psmouse.h	2003-07-08 00:52:55.000000000 -0500
@@ -13,9 +13,15 @@
 #define PSMOUSE_CMD_RESET_BAT	0x02ff
 
 #define PSMOUSE_RET_BAT		0xaa
+#define PSMOUSE_RET_ID		0x00
 #define PSMOUSE_RET_ACK		0xfa
 #define PSMOUSE_RET_NAK		0xfe
 
+/* psmouse states */
+#define PSMOUSE_NEW_DEVICE	0
+#define PSMOUSE_ACTIVATED	1
+#define PSMOUSE_IGNORE		2
+
 struct psmouse {
 	void *private;
 	struct input_dev dev;
@@ -29,6 +35,7 @@
 	unsigned char type;
 	unsigned char model;
 	unsigned long last;
+	unsigned char state;
 	char acking;
 	volatile char ack;
 	char error;
@@ -36,16 +43,17 @@
 	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
+#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);
 
 extern int psmouse_smartscroll;
+extern unsigned int psmouse_resetafter;
 
 #endif /* _PSMOUSE_H */
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/synaptics.c linux-2.5.74/drivers/input/mouse/synaptics.c
--- 2.5.74-vanilla/drivers/input/mouse/synaptics.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/synaptics.c	2003-07-08 00:41:39.000000000 -0500
@@ -1,6 +1,9 @@
 /*
  * Synaptics TouchPad PS/2 mouse driver
  *
+ *   2003 Dmitry Torokhov <dtor@mail.ru>
+ *     Added support for pass-through port
+ *     
  *   2003 Peter Osterlund <petero2@telia.com>
  *     Ported to 2.5 input device infrastructure.
  *
@@ -21,6 +24,7 @@
 
 #include <linux/module.h>
 #include <linux/input.h>
+#include <linux/serio.h>
 #include "psmouse.h"
 #include "synaptics.h"
 
@@ -71,7 +75,7 @@
 
 	if (synaptics_special_cmd(psmouse, mode))
 		return -1;
-	param[0] = 0x14;
+	param[0] = SYN_PS_SET_MODE2;
 	if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
 		return -1;
 	return 0;
@@ -83,7 +87,7 @@
 
 	if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
 		return -1;
-	if (r[0] == 0xAA && r[1] == 0x00)
+	if (r[0] == PSMOUSE_RET_BAT && r[1] == PSMOUSE_RET_ID)
 		return 0;
 	return -1;
 }
@@ -134,17 +138,10 @@
 	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),
+	printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
 	       SYN_ID_MINOR(priv->identity));
 
 	if (SYN_MODEL_ROT180(priv->model_id))
@@ -165,6 +162,8 @@
 			printk(KERN_INFO " -> multifinger detection\n");
 		if (SYN_CAP_PALMDETECT(priv->capabilities))
 			printk(KERN_INFO " -> palm detection\n");
+		if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+			printk(KERN_INFO " -> pass-through port\n");
 	}
 }
 
@@ -188,13 +187,100 @@
 					 SYN_BIT_W_MODE)))
 		return -1;
 
-	synaptics_enable_device(psmouse);
+	return 0;
+}
 
-	print_ident(priv);
+/*****************************************************************************
+ *	Synaptics pass-through PS/2 port support
+ ****************************************************************************/
+static int synaptics_pt_open(struct serio *port)
+{
+	return 0;
+}
 
+static void synaptics_pt_close(struct serio *port)
+{
+}
+
+static int synaptics_pt_write(struct serio *port, unsigned char c)
+{
+	struct psmouse *parent = port->driver;
+	char rate_param = SYN_PS_CLIENT_CMD; // indicates that we want pass-through port
+
+	if (synaptics_special_cmd(parent, c))
+		return -1;
+	if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
+		return -1;
 	return 0;
 }
 
+static inline int synaptics_is_pt_packet(unsigned char *buf)
+{
+	return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
+}
+
+static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+{
+	struct psmouse *child = ptport->private;
+
+	if (child) {
+		if (child->state == PSMOUSE_ACTIVATED) {
+			serio_interrupt(ptport, packet[1], 0, NULL);
+			serio_interrupt(ptport, packet[4], 0, NULL);
+			serio_interrupt(ptport, packet[5], 0, NULL);
+			if (child->type >= PSMOUSE_GENPS)	
+				serio_interrupt(ptport, packet[2], 0, NULL);
+		} else if (child->state != PSMOUSE_IGNORE) {
+			serio_interrupt(ptport, packet[1], 0, NULL);
+		}
+	}
+}
+
+int synaptics_pt_init(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct serio *port;
+	struct psmouse *child;
+	
+	if (psmouse->type != PSMOUSE_SYNAPTICS)
+		return -1;
+	if (!SYN_CAP_EXTENDED(priv->capabilities))
+		return -1;
+	if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
+		return -1;
+
+	priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	if (unlikely(!port)) {
+		printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");	
+		return -1;
+	}
+	
+	memset(port, 0, sizeof(struct serio));
+	port->type = SERIO_PS_PSTHRU;
+	port->name = "Synaptics pass-through";
+	port->phys = "synaptics-pt/serio0";
+	port->write = synaptics_pt_write;
+	port->open = synaptics_pt_open;
+	port->close = synaptics_pt_close;
+	port->driver = psmouse;
+	
+	printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
+	serio_register_slave_port(port);
+
+	/* adjust the touchpad to child's choice of protocol */
+	child = port->private;
+	if (child && child->type >= PSMOUSE_GENPS) {
+		if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+					 	 SYN_BIT_HIGH_RATE |
+					 	 SYN_BIT_DISABLE_GESTURE |
+						 SYN_BIT_FOUR_BYTE_CLIENT |
+					 	 SYN_BIT_W_MODE)))
+			printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+	}
+	
+	return 0;	
+}
+
 /*****************************************************************************
  *	Driver initialization/cleanup functions
  ****************************************************************************/
@@ -218,13 +304,15 @@
 		return -1;
 	memset(priv, 0, sizeof(struct synaptics_data));
 
-	priv->inSync = 1;
+	priv->out_of_sync = 0;
 
 	if (query_hardware(psmouse)) {
 		printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
 		goto init_fail;
 	}
 
+	print_ident(priv);
+
 	/*
 	 * 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
@@ -259,17 +347,24 @@
 {
 	struct synaptics_data *priv = psmouse->private;
 
-	kfree(priv);
+	if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
+		synaptics_set_mode(psmouse, 0);
+		if (priv->ptport) {
+			serio_unregister_slave_port(priv->ptport);
+			kfree(priv->ptport);
+		} 
+		kfree(priv);
+	}
 }
 
 /*****************************************************************************
  *	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(unsigned char buf[],
+				     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]);
@@ -283,7 +378,7 @@
 		 ((buf[3] & 0x04) >> 2));
 
 	hw->left  = (buf[0] & 0x01) ? 1 : 0;
-	hw->right = (buf[0] & 0x2) ? 1 : 0;
+	hw->right = (buf[0] & 0x02) ? 1 : 0;
 	hw->up    = 0;
 	hw->down  = 0;
 
@@ -307,7 +402,7 @@
 	struct synaptics_data *priv = psmouse->private;
 	struct synaptics_hw_state hw;
 
-	synaptics_parse_hw_state(priv, &hw);
+	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
 	if (hw.z > 0) {
 		int w_ok = 0;
@@ -355,35 +450,47 @@
 {
 	struct input_dev *dev = &psmouse->dev;
 	struct synaptics_data *priv = psmouse->private;
-	unsigned char *pBuf = priv->proto_buf;
-	unsigned char u = psmouse->packet[0];
+	unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
 
 	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;
+	if (psmouse->pktcnt == 1 && (data & 0xC8) != 0x80) {
 		printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+		priv->out_of_sync++;
+		psmouse->pktcnt = 0;
+	        if (psmouse_resetafter > 0 && priv->out_of_sync	== psmouse_resetafter) {
+			psmouse->state = PSMOUSE_IGNORE;
+			serio_rescan(psmouse->serio);
+		}
 		return;
 	}
 
 	/* check 4th byte */
-	if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
-		priv->inSync = 0;
-		priv->proto_buf_tail = 0;
+	if (psmouse->pktcnt == 4 && (data & 0xC8) != 0xC0) {
 		printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+		priv->out_of_sync++;
+		psmouse->pktcnt = 0;
+	        if (psmouse_resetafter > 0 && priv->out_of_sync	== psmouse_resetafter) {
+			psmouse->state = PSMOUSE_IGNORE;
+			serio_rescan(psmouse->serio);
+		}
 		return;
 	}
 
-	if (priv->proto_buf_tail >= 6) { /* Full packet received */
-		if (!priv->inSync) {
-			priv->inSync = 1;
+	if (psmouse->pktcnt >= 6) { /* Full packet received */
+		if (priv->out_of_sync) {
+			priv->out_of_sync = 0;
 			printk(KERN_NOTICE "Synaptics driver resynced.\n");
 		}
-		synaptics_process_packet(psmouse);
-		priv->proto_buf_tail = 0;
+		
+		if (priv->ptport && synaptics_is_pt_packet(psmouse->packet)) 
+			synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
+		else
+			synaptics_process_packet(psmouse);
+		
+		psmouse->pktcnt = 0;	
 	}
 }
+
+
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/mouse/synaptics.h linux-2.5.74/drivers/input/mouse/synaptics.h
--- 2.5.74-vanilla/drivers/input/mouse/synaptics.h	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/mouse/synaptics.h	2003-07-08 00:03:23.000000000 -0500
@@ -12,6 +12,7 @@
 
 extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
 extern int synaptics_init(struct psmouse *psmouse);
+extern int synaptics_pt_init(struct psmouse *psmouse);
 extern void synaptics_disconnect(struct psmouse *psmouse);
 
 /* synaptics queries */
@@ -28,6 +29,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_FOUR_BYTE_CLIENT	(1 << 1)
 #define SYN_BIT_W_MODE			(1 << 0)
 
 /* synaptics model ID bits */
@@ -42,6 +44,7 @@
 
 /* synaptics capability bits */
 #define SYN_CAP_EXTENDED(c)		((c) & (1 << 23))
+#define SYN_CAP_PASS_THROUGH(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))
@@ -62,6 +65,10 @@
 #define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
 #define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
 
+/* synaptics special commands */
+#define SYN_PS_SET_MODE2		0x14
+#define SYN_PS_CLIENT_CMD		0x28
+
 /*
  * A structure to describe the state of the touchpad hardware (buttons and pad)
  */
@@ -84,12 +91,10 @@
 	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;
-
+	unsigned int out_of_sync;		/* # of packets out of sync */
 	int old_w;				/* Previous w value */
+	
+	struct serio *ptport;			/* pass-through port */
 };
 
 #endif /* _SYNAPTICS_H */
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/drivers/input/serio/serio.c linux-2.5.74/drivers/input/serio/serio.c
--- 2.5.74-vanilla/drivers/input/serio/serio.c	2003-07-05 00:28:41.000000000 -0500
+++ linux-2.5.74/drivers/input/serio/serio.c	2003-07-05 19:21:35.000000000 -0500
@@ -45,7 +45,9 @@
 
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_register_slave_port);
 EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_slave_port);
 EXPORT_SYMBOL(serio_register_device);
 EXPORT_SYMBOL(serio_unregister_device);
 EXPORT_SYMBOL(serio_open);
@@ -162,6 +164,16 @@
 	up(&serio_sem);
 }
 
+/* Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when registering a serio from other input device's
+ * connect() function.
+ */
+void serio_register_slave_port(struct serio *serio)
+{
+	list_add_tail(&serio->node, &serio_list);
+	serio_find_dev(serio);
+}
+
 void serio_unregister_port(struct serio *serio)
 {
 	down(&serio_sem);
@@ -171,6 +183,17 @@
 	up(&serio_sem);
 }
 
+/* Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when unregistering a serio from other input device's
+ * disconnect() function.
+ */
+void serio_unregister_slave_port(struct serio *serio)
+{
+	list_del_init(&serio->node);
+	if (serio->dev && serio->dev->disconnect)
+		serio->dev->disconnect(serio);
+}
+
 void serio_register_device(struct serio_dev *dev)
 {
 	struct serio *serio;
diff -urN --exclude-from=/usr/src/exclude 2.5.74-vanilla/include/linux/serio.h linux-2.5.74/include/linux/serio.h
--- 2.5.74-vanilla/include/linux/serio.h	2003-07-05 00:29:02.000000000 -0500
+++ linux-2.5.74/include/linux/serio.h	2003-07-05 19:17:56.000000000 -0500
@@ -65,7 +65,9 @@
 irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
 
 void serio_register_port(struct serio *serio);
+void serio_register_slave_port(struct serio *serio);
 void serio_unregister_port(struct serio *serio);
+void serio_unregister_slave_port(struct serio *serio);
 void serio_register_device(struct serio_dev *dev);
 void serio_unregister_device(struct serio_dev *dev);
 
@@ -104,6 +106,7 @@
 #define SERIO_RS232	0x02000000UL
 #define SERIO_HIL_MLC	0x03000000UL
 #define SERIO_PC9800	0x04000000UL
+#define SERIO_PS_PSTHRU	0x05000000UL
 
 #define SERIO_PROTO	0xFFUL
 #define SERIO_MSC	0x01

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

end of thread, other threads:[~2003-07-08  5:43 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-06  7:23 [PATCH] Synaptics: support for pass-through port (stick) Dmitry Torokhov
2003-07-06 13:23 ` Peter Berg Larsen
2003-07-07  3:48   ` Dmitry Torokhov
2003-07-07 11:44     ` Peter Berg Larsen
2003-07-07 12:09       ` Peter Berg Larsen
2003-07-07 17:31         ` Dmitry Torokhov
2003-07-08  5:59         ` Dmitry Torokhov
2003-07-07 17:34       ` Dmitry Torokhov
2003-07-07 18:35         ` Peter Berg Larsen
2003-07-07 22:51           ` Dmitry Torokhov

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).