linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/6] serio: rename serio_[un]register_slave_port to __serio_[un]register_port
  2003-09-30  6:24 2.6: New set of input patches Dmitry Torokhov
@ 2003-09-30  6:06 ` Dmitry Torokhov
  2003-09-30  6:15   ` [PATCH 2/6] serio: possible race between port removal and kseriod Dmitry Torokhov
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-09-30  6:06 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: akpm, petero2, linux-kernel

Input: rename serio_{register|unregister}_slave_port to 
       __serio_{register|unregister}_port to better follow
       locked/lockless naming convention


 drivers/input/mouse/synaptics.c |    4 ++--
 drivers/input/serio/serio.c     |   23 ++++++++++-------------
 include/linux/serio.h           |    4 ++--
 3 files changed, 14 insertions(+), 17 deletions(-)

===================================================================

diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c	Tue Sep 30 01:02:23 2003
+++ b/drivers/input/mouse/synaptics.c	Tue Sep 30 01:02:23 2003
@@ -294,7 +294,7 @@
 	port->driver = psmouse;
 
 	printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
-	serio_register_slave_port(port);
+	__serio_register_port(port);	/* already have serio_sem */
 
 	/* adjust the touchpad to child's choice of protocol */
 	child = port->private;
@@ -406,7 +406,7 @@
 	if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
 		synaptics_mode_cmd(psmouse, 0);
 		if (priv->ptport) {
-			serio_unregister_slave_port(priv->ptport);
+			__serio_unregister_port(priv->ptport); /* already have serio_sem */
 			kfree(priv->ptport);
 		}
 		kfree(priv);
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	Tue Sep 30 01:02:23 2003
+++ b/drivers/input/serio/serio.c	Tue Sep 30 01:02:23 2003
@@ -49,9 +49,9 @@
 
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(serio_register_port);
-EXPORT_SYMBOL(serio_register_slave_port);
+EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
-EXPORT_SYMBOL(serio_unregister_slave_port);
+EXPORT_SYMBOL(__serio_unregister_port);
 EXPORT_SYMBOL(serio_register_device);
 EXPORT_SYMBOL(serio_unregister_device);
 EXPORT_SYMBOL(serio_open);
@@ -163,17 +163,16 @@
 void serio_register_port(struct serio *serio)
 {
 	down(&serio_sem);
-	list_add_tail(&serio->node, &serio_list);
-	serio_find_dev(serio);
+	__serio_register_port(serio);
 	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
+ * Should only be called directly if serio_sem has already been taken,
+ * for example when unregistering a serio from other input device's 
  * connect() function.
  */
-void serio_register_slave_port(struct serio *serio)
+void __serio_register_port(struct serio *serio)
 {
 	list_add_tail(&serio->node, &serio_list);
 	serio_find_dev(serio);
@@ -182,18 +181,16 @@
 void serio_unregister_port(struct serio *serio)
 {
 	down(&serio_sem);
-	list_del_init(&serio->node);
-	if (serio->dev && serio->dev->disconnect)
-		serio->dev->disconnect(serio);
+	__serio_unregister_port(serio);
 	up(&serio_sem);
 }
 
 /*
- * Same as serio_unregister_port but does not try to acquire serio_sem.
- * Should be used when unregistering a serio from other input device's
+ * Should only be called directly if serio_sem has already been taken,
+ * for example when unregistering a serio from other input device's 
  * disconnect() function.
  */
-void serio_unregister_slave_port(struct serio *serio)
+void __serio_unregister_port(struct serio *serio)
 {
 	list_del_init(&serio->node);
 	if (serio->dev && serio->dev->disconnect)
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	Tue Sep 30 01:02:23 2003
+++ b/include/linux/serio.h	Tue Sep 30 01:02:23 2003
@@ -65,9 +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_register_port(struct serio *serio);
 void serio_unregister_port(struct serio *serio);
-void serio_unregister_slave_port(struct serio *serio);
+void __serio_unregister_port(struct serio *serio);
 void serio_register_device(struct serio_dev *dev);
 void serio_unregister_device(struct serio_dev *dev);
 


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

* [PATCH 2/6] serio: possible race between port removal and kseriod
  2003-09-30  6:06 ` [PATCH 1/6] serio: rename serio_[un]register_slave_port to __serio_[un]register_port Dmitry Torokhov
@ 2003-09-30  6:15   ` Dmitry Torokhov
  2003-09-30  6:15     ` [PATCH 3/6] Add black list to handler<->device matching Dmitry Torokhov
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-09-30  6:15 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: akpm, petero2, linux-kernel

Input: There is a possibility that serio might get deleted while there
       are outstanding events involving that serio waiting for kseriod
       to process them. Invalidate them so kseriod thread will just
       drop dead events.


 serio.c |   18 ++++++++++++++++--
 1 files changed, 16 insertions(+), 2 deletions(-)

===================================================================

diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	Tue Sep 30 01:07:17 2003
+++ b/drivers/input/serio/serio.c	Tue Sep 30 01:07:17 2003
@@ -87,6 +87,15 @@
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
 static DECLARE_COMPLETION(serio_exited);
 
+static void serio_invalidate_pending_events(struct serio *serio)
+{
+	struct serio_event *event;
+	
+	list_for_each_entry(event, &serio_event_list, node)
+		if (event->serio == serio)
+			event->serio = NULL;
+}
+
 void serio_handle_events(void)
 {
 	struct list_head *node, *next;
@@ -95,17 +104,21 @@
 	list_for_each_safe(node, next, &serio_event_list) {
 		event = container_of(node, struct serio_event, node);	
 
+		down(&serio_sem);
+		if (event->serio == NULL)
+			goto event_done;
+		
 		switch (event->type) {
 			case SERIO_RESCAN :
-				down(&serio_sem);
 				if (event->serio->dev && event->serio->dev->disconnect)
 					event->serio->dev->disconnect(event->serio);
 				serio_find_dev(event->serio);
-				up(&serio_sem);
 				break;
 			default:
 				break;
 		}
+event_done:
+		up(&serio_sem);
 		list_del_init(node);
 		kfree(event);
 	}
@@ -192,6 +205,7 @@
  */
 void __serio_unregister_port(struct serio *serio)
 {
+	serio_invalidate_pending_events(serio);
 	list_del_init(&serio->node);
 	if (serio->dev && serio->dev->disconnect)
 		serio->dev->disconnect(serio);


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

* [PATCH 3/6] Add black list to handler<->device matching
  2003-09-30  6:15   ` [PATCH 2/6] serio: possible race between port removal and kseriod Dmitry Torokhov
@ 2003-09-30  6:15     ` Dmitry Torokhov
  2003-09-30  6:20       ` [PATCH 4/6] Synaptics: code cleanup Dmitry Torokhov
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-09-30  6:15 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: akpm, petero2, linux-kernel

Input: Introduce an optional blacklist field in input_handler structure.
       When loading a new device or a new handler try to match device
       against handler's black list before doing match on required 
       attributes.
       This allows to get rid of "surprises" in connect functions, IMO
       connect should only fail when it physically can not connect, not
       because it decides it does not like device.


 drivers/input/input.c  |   14 ++++++++------
 drivers/input/joydev.c |   14 ++++++++++----
 include/linux/input.h  |    1 +
 3 files changed, 19 insertions(+), 10 deletions(-)

===================================================================

diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Tue Sep 30 01:13:54 2003
+++ b/drivers/input/input.c	Tue Sep 30 01:13:54 2003
@@ -447,9 +447,10 @@
 	list_add_tail(&dev->node, &input_dev_list);
 
 	list_for_each_entry(handler, &input_handler_list, node)
-		if ((id = input_match_device(handler->id_table, dev)))
-			if ((handle = handler->connect(handler, dev, id)))
-				input_link_handle(handle);
+		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
+			if ((id = input_match_device(handler->id_table, dev)))
+				if ((handle = handler->connect(handler, dev, id)))
+					input_link_handle(handle);
 
 #ifdef CONFIG_HOTPLUG
 	input_call_hotplug("add", dev);
@@ -507,9 +508,10 @@
 	list_add_tail(&handler->node, &input_handler_list);
 	
 	list_for_each_entry(dev, &input_dev_list, node)
-		if ((id = input_match_device(handler->id_table, dev)))
-			if ((handle = handler->connect(handler, dev, id)))
-				input_link_handle(handle);
+		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
+			if ((id = input_match_device(handler->id_table, dev)))
+				if ((handle = handler->connect(handler, dev, id)))
+					input_link_handle(handle);
 
 #ifdef CONFIG_PROC_FS
 	input_devices_state++;
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	Tue Sep 30 01:13:54 2003
+++ b/drivers/input/joydev.c	Tue Sep 30 01:13:54 2003
@@ -380,10 +380,6 @@
 	struct joydev *joydev;
 	int i, j, t, minor;
 
-	/* Avoid tablets */
-        if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
-		return NULL;
-
 	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
 	if (minor == JOYDEV_MINORS) {
 		printk(KERN_ERR "joydev: no more free joydev devices\n");
@@ -464,6 +460,15 @@
 		joydev_free(joydev);
 }
 
+static struct input_device_id joydev_blacklist[] = {
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+		.evbit = { BIT(EV_KEY) },
+		.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+	}, 	/* Avoid itouchpads, touchscreens and tablets */
+	{ }, 	/* Terminating entry */
+};
+
 static struct input_device_id joydev_ids[] = {
 	{
 		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
@@ -493,6 +498,7 @@
 	.minor =	JOYDEV_MINOR_BASE,
 	.name =		"joydev",
 	.id_table =	joydev_ids,
+	.blacklist = 	joydev_blacklist,
 };
 
 static int __init joydev_init(void)
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	Tue Sep 30 01:13:54 2003
+++ b/include/linux/input.h	Tue Sep 30 01:13:54 2003
@@ -870,6 +870,7 @@
 	char *name;
 
 	struct input_device_id *id_table;
+	struct input_device_id *blacklist;
 
 	struct list_head	h_list;
 	struct list_head	node;


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

* [PATCH 4/6] Synaptics: code cleanup
  2003-09-30  6:15     ` [PATCH 3/6] Add black list to handler<->device matching Dmitry Torokhov
@ 2003-09-30  6:20       ` Dmitry Torokhov
  2003-09-30  6:23         ` [PATCH 5/6] serio: reconnect facility Dmitry Torokhov
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-09-30  6:20 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: akpm, petero2, linux-kernel

Input: Synaptics code cleanup and credit update.


 synaptics.c |   79 ++++++++++++++++++++----------------------------------------
 1 files changed, 27 insertions(+), 52 deletions(-)

===================================================================

diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c	Tue Sep 30 01:17:52 2003
+++ b/drivers/input/mouse/synaptics.c	Tue Sep 30 01:17:52 2003
@@ -2,7 +2,8 @@
  * Synaptics TouchPad PS/2 mouse driver
  *
  *   2003 Dmitry Torokhov <dtor@mail.ru>
- *     Added support for pass-through port
+ *     Added support for pass-through port. Special thanks to Peter Berg Larsen
+ *     for explaining various Synaptics quirks.
  *
  *   2003 Peter Osterlund <petero2@telia.com>
  *     Ported to 2.5 input device infrastructure.
@@ -419,16 +420,7 @@
 
 static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
 {
-	hw->up    = 0;
-	hw->down  = 0;
-	hw->b0    = 0;
-	hw->b1    = 0;
-	hw->b2    = 0;
-	hw->b3    = 0;
-	hw->b4    = 0;
-	hw->b5    = 0;
-	hw->b6    = 0;
-	hw->b7    = 0;
+	memset(hw, 0, sizeof(struct synaptics_hw_state));
 
 	if (SYN_MODEL_NEWABS(priv->model_id)) {
 		hw->x = (((buf[3] & 0x10) << 8) |
@@ -570,44 +562,29 @@
 	input_sync(dev);
 }
 
+static int synaptics_validate_byte(struct psmouse *psmouse)
+{
+	static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
+	static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
+	static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
+	static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
+	struct synaptics_data *priv = psmouse->private;
+	int idx = psmouse->pktcnt - 1;
+
+	if (SYN_MODEL_NEWABS(priv->model_id))
+		return (psmouse->packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
+	else
+		return (psmouse->packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
+}
+
 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 data = psmouse->packet[psmouse->pktcnt - 1];
-	int newabs = SYN_MODEL_NEWABS(priv->model_id);
 
 	input_regs(dev, regs);
 
-	switch (psmouse->pktcnt) {
-	case 1:
-		if (newabs ? ((data & 0xC8) != 0x80) : ((data & 0xC0) != 0xC0)) {
-			printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
-			goto bad_sync;
-		}
-		break;
-	case 2:
-		if (!newabs && ((data & 0x60) != 0x00)) {
-			printk(KERN_WARNING "Synaptics driver lost sync at 2nd byte\n");
-			goto bad_sync;
-		}
-		break;
-	case 4:
-		if (newabs ? ((data & 0xC8) != 0xC0) : ((data & 0xC0) != 0x80)) {
-			printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
-			goto bad_sync;
-		}
-		break;
-	case 5:
-		if (!newabs && ((data & 0x60) != 0x00)) {
-			printk(KERN_WARNING "Synaptics driver lost sync at 5th byte\n");
-			goto bad_sync;
-		}
-		break;
-	default:
-		if (psmouse->pktcnt < 6)
-			break;		    /* Wait for full packet */
-
+	if (psmouse->pktcnt >= 6) { /* Full packet received */
 		if (priv->out_of_sync) {
 			priv->out_of_sync = 0;
 			printk(KERN_NOTICE "Synaptics driver resynced.\n");
@@ -617,17 +594,15 @@
 			synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
 		else
 			synaptics_process_packet(psmouse);
-
 		psmouse->pktcnt = 0;
-		break;
-	}
-	return;
 
- bad_sync:
-	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);
+	} else if (psmouse->pktcnt && !synaptics_validate_byte(psmouse)) {
+		printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt);
+		psmouse->pktcnt = 0;
+		if (++priv->out_of_sync == psmouse_resetafter) {
+			psmouse->state = PSMOUSE_IGNORE;
+			printk(KERN_NOTICE "synaptics: issuing rescan request\n");
+			serio_rescan(psmouse->serio);
+		}
 	}
 }


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

* [PATCH 5/6] serio: reconnect facility
  2003-09-30  6:20       ` [PATCH 4/6] Synaptics: code cleanup Dmitry Torokhov
@ 2003-09-30  6:23         ` Dmitry Torokhov
  2003-09-30  6:27           ` [PATCH 6/6] Synaptics: use serio_reconnect Dmitry Torokhov
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-09-30  6:23 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: akpm, petero2, linux-kernel

Input: serio_reconnect added. Similar to serio_rescan but gives driver
       a chance to re-initialize keeping the same input device.


 drivers/input/serio/serio.c |   31 ++++++++++++++++++++++++-------
 include/linux/serio.h       |    2 ++
 2 files changed, 26 insertions(+), 7 deletions(-)

===================================================================

diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	Tue Sep 30 01:22:43 2003
+++ b/drivers/input/serio/serio.c	Tue Sep 30 01:22:43 2003
@@ -57,6 +57,7 @@
 EXPORT_SYMBOL(serio_open);
 EXPORT_SYMBOL(serio_close);
 EXPORT_SYMBOL(serio_rescan);
+EXPORT_SYMBOL(serio_reconnect);
 
 struct serio_event {
 	int type;
@@ -83,6 +84,7 @@
 }
 
 #define SERIO_RESCAN	1
+#define SERIO_RECONNECT	2
 
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
 static DECLARE_COMPLETION(serio_exited);
@@ -109,6 +111,12 @@
 			goto event_done;
 		
 		switch (event->type) {
+			case SERIO_RECONNECT :
+				if (event->serio->dev && event->serio->dev->reconnect)
+					if (event->serio->dev->reconnect(event->serio) == 0)
+						break;
+				/* reconnect failed - fall through to rescan */
+				
 			case SERIO_RESCAN :
 				if (event->serio->dev && event->serio->dev->disconnect)
 					event->serio->dev->disconnect(event->serio);
@@ -143,18 +151,27 @@
 	complete_and_exit(&serio_exited, 0);
 }
 
-void serio_rescan(struct serio *serio)
+static void serio_queue_event(struct serio *serio, int event_type)
 {
 	struct serio_event *event;
 
-	if (!(event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC)))
-		return;
+	if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
+		event->type = event_type;
+		event->serio = serio;
+
+		list_add_tail(&event->node, &serio_event_list);
+		wake_up(&serio_wait);
+	}
+}
 
-	event->type = SERIO_RESCAN;
-	event->serio = serio;
+void serio_rescan(struct serio *serio)
+{
+	serio_queue_event(serio, SERIO_RESCAN);
+}
 
-	list_add_tail(&event->node, &serio_event_list);
-	wake_up(&serio_wait);
+void serio_reconnect(struct serio *serio)
+{
+	serio_queue_event(serio, SERIO_RECONNECT);
 }
 
 irqreturn_t serio_interrupt(struct serio *serio,
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	Tue Sep 30 01:22:43 2003
+++ b/include/linux/serio.h	Tue Sep 30 01:22:43 2003
@@ -53,6 +53,7 @@
 	irqreturn_t (*interrupt)(struct serio *, unsigned char,
 			unsigned int, struct pt_regs *);
 	void (*connect)(struct serio *, struct serio_dev *dev);
+	int  (*reconnect)(struct serio *);
 	void (*disconnect)(struct serio *);
 	void (*cleanup)(struct serio *);
 
@@ -62,6 +63,7 @@
 int serio_open(struct serio *serio, struct serio_dev *dev);
 void serio_close(struct serio *serio);
 void serio_rescan(struct serio *serio);
+void serio_reconnect(struct serio *serio);
 irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
 
 void serio_register_port(struct serio *serio);


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

* 2.6: New set of input patches
@ 2003-09-30  6:24 Dmitry Torokhov
  2003-09-30  6:06 ` [PATCH 1/6] serio: rename serio_[un]register_slave_port to __serio_[un]register_port Dmitry Torokhov
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-09-30  6:24 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: akpm, petero2, linux-kernel

Hi Vojtech,

I have a bunch of input patches that work quite nicely on my laptop, 
would you please consider taking them?

1. SERIO: rename serio_{register|unregister}_slave_port to
          __serio_{register|unregister}_port to better follow
          locked/lockless naming convention.

2. SERIO: There is a possibility that serio might get deleted while there
     	  are outstanding events involving that serio waiting for kseriod
          to process them. Invalidate them so kseriod thread will just
          drop dead events. (Resend)

3. Input: Introduce an optional blacklist field in input_handler structure.
          When loading a new device or a new handler try to match device
          against handler's black list before doing match on required
          attributes.
          This allows to get rid of "surprises" in connect functions, IMO
          connect should only fail when it physically can not connect, not
          because it decides it does not like device.

4. Input: Synaptics code cleanup and credit update. The switch in 
          synaptics_process_packet() was quite ugly.

5. SERIO: serio_reconnect added. Similar to serio_rescan but gives driver
          a chance to re-initialize keeping the same input device. (Resend)

6. Input/Synaptics:
   - Support for pass-through port moved from Synaptics driver to psmouse
     itself, it is cleaner and should allow using it in other drivers if
     needed.
   - The driver makes use of new reconnect functionality in serio. It will
     try to keep the same input device after resume or when it resets itself.
   - If mouse is disconnected or other mouse plugged in while sleeping the
     driver should correctly recognize that and create a new serio/input
     device. (Resend, original patch split into 2 - #4 & #6) 

Dmitry

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

* [PATCH 6/6] Synaptics: use serio_reconnect
  2003-09-30  6:23         ` [PATCH 5/6] serio: reconnect facility Dmitry Torokhov
@ 2003-09-30  6:27           ` Dmitry Torokhov
  0 siblings, 0 replies; 7+ messages in thread
From: Dmitry Torokhov @ 2003-09-30  6:27 UTC (permalink / raw)
  To: Vojtech Pavlik; +Cc: akpm, petero2, linux-kernel

Input/Synaptics:
  1. Support for pass-through port moved from Synaptics driver to psmouse
     itself, it is cleaner and should allow using it in other drivers if
     needed.
  2. The driver makes use of new reconnect functionality in serio. It will
     try to keep the same input device after resume or when it resets itself.
  3. If mouse is disconnected or other mouse plugged in while sleeping the
     driver should correctly recognize that and create a new serio/input 
     device.


 logips2pp.c    |    1 
 psmouse-base.c |  124 +++++++++++++++++++++++++++++++--------------
 psmouse.h      |   13 ++++
 synaptics.c    |  157 ++++++++++++++++++++++++++++++++++-----------------------
 synaptics.h    |    6 --
 5 files changed, 199 insertions(+), 102 deletions(-)

===================================================================

diff -Nru a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
--- a/drivers/input/mouse/logips2pp.c	Tue Sep 30 01:26:06 2003
+++ b/drivers/input/mouse/logips2pp.c	Tue Sep 30 01:26:06 2003
@@ -10,6 +10,7 @@
  */
 
 #include <linux/input.h>
+#include <linux/serio.h>
 #include "psmouse.h"
 #include "logips2pp.h"
 
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c	Tue Sep 30 01:26:06 2003
+++ b/drivers/input/mouse/psmouse-base.c	Tue Sep 30 01:26:06 2003
@@ -141,7 +141,8 @@
 		goto out;
 	}
 
-	if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
+	if (psmouse->state == PSMOUSE_ACTIVATED && 
+	    psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
 		printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
 		       psmouse->name, psmouse->phys, psmouse->pktcnt);
 		psmouse->pktcnt = 0;
@@ -276,24 +277,18 @@
 		return PSMOUSE_PS2;
 
 /*
- * Try Synaptics TouchPad magic ID
+ * Try Synaptics TouchPad
  */
-
-       param[0] = 0;
-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-       psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
-       psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
-
-       if (param[1] == 0x47) {
+	if (synaptics_detect(psmouse) == 0) {
 		psmouse->vendor = "Synaptics";
 		psmouse->name = "TouchPad";
-		if (!synaptics_init(psmouse))
+
+#if CONFIG_MOUSE_PS2_SYNAPTICS
+		if (synaptics_init(psmouse) == 0)
 			return PSMOUSE_SYNAPTICS;
-		else
-			return PSMOUSE_PS2;
-       }
+#endif
+		return PSMOUSE_PS2;
+	}
 
 /*
  * Try Genius NetMouse magic init.
@@ -519,7 +514,18 @@
 	struct psmouse *psmouse = serio->private;
 
 	psmouse->state = PSMOUSE_IGNORE;
-	synaptics_disconnect(psmouse);
+	
+	if (psmouse->ptport) {
+		if (psmouse->ptport->deactivate)
+			psmouse->ptport->deactivate(psmouse);
+		__serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */
+		kfree(psmouse->ptport);
+		psmouse->ptport = NULL;
+	}
+		
+	if (psmouse->disconnect)
+		psmouse->disconnect(psmouse);
+	
 	input_unregister_device(&psmouse->dev);
 	serio_close(serio);
 	kfree(psmouse);
@@ -532,20 +538,10 @@
 static int psmouse_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
 {
 	struct psmouse *psmouse = dev->data;
-	struct serio_dev *ser_dev = psmouse->serio->dev;
-
-	synaptics_disconnect(psmouse);
-
-	/* We need to reopen the serio port to reinitialize the i8042 controller */
-	serio_close(psmouse->serio);
-	serio_open(psmouse->serio, ser_dev);
-
-	/* Probe and re-initialize the mouse */
-	psmouse_probe(psmouse);
-	psmouse_initialize(psmouse);
-	synaptics_pt_init(psmouse);
-	psmouse_activate(psmouse);
 
+	psmouse->state = PSMOUSE_IGNORE;
+	serio_reconnect(psmouse->serio);
+	
 	return 0;
 }
 
@@ -553,7 +549,6 @@
  * psmouse_connect() is a callback from the serio module when
  * an unhandled serio port is found.
  */
-
 static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
 {
 	struct psmouse *psmouse;
@@ -578,7 +573,6 @@
 	psmouse->dev.private = psmouse;
 
 	serio->private = psmouse;
-
 	if (serio_open(serio, dev)) {
 		kfree(psmouse);
 		return;
@@ -590,10 +584,12 @@
 		return;
 	}
 	
-	pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
-	if (pmdev) {
-		psmouse->dev.pm_dev = pmdev;
-		pmdev->data = psmouse;
+	if (serio->type != SERIO_PS_PSTHRU) {
+		pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
+		if (pmdev) {
+			psmouse->dev.pm_dev = pmdev;
+			pmdev->data = psmouse;
+		}
 	}
 
 	sprintf(psmouse->devname, "%s %s %s",
@@ -614,14 +610,70 @@
 
 	psmouse_initialize(psmouse);
 
-	synaptics_pt_init(psmouse);
+	if (psmouse->ptport) {
+		printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys);
+		__serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */
+		if (psmouse->ptport->activate)
+			psmouse->ptport->activate(psmouse);
+	}
+	
+	psmouse_activate(psmouse);
+}
+
+
+static int psmouse_reconnect(struct serio *serio)
+{
+	struct psmouse *psmouse = serio->private;
+	struct serio_dev *dev = serio->dev;
+	int old_type = psmouse->type;
+	
+	if (!dev) {
+		printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
+		return -1;
+	}
+	
+	/* We need to reopen the serio port to reinitialize the i8042 controller */
+	serio_close(serio);
+	if (serio_open(serio, dev)) {
+		/* do a disconnect here as serio_open leaves dev as NULL so disconnect 
+		 * will not be called automatically later
+		 */
+		psmouse_disconnect(serio);
+		return -1;
+	}
+	
+	psmouse->state = PSMOUSE_NEW_DEVICE;
+	psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
+	if (psmouse->reconnect) {
+	       if (psmouse->reconnect(psmouse))
+			return -1;
+	} else if (psmouse_probe(psmouse) != old_type)
+		return -1;
+	
+	/* ok, the device type (and capabilities) match the old one,
+	 * we can continue using it, complete intialization
+	 */ 
+	psmouse->type = old_type;
+	psmouse_initialize(psmouse);
 
+	if (psmouse->ptport) {
+       		if (psmouse_reconnect(&psmouse->ptport->serio)) {
+			__serio_unregister_port(&psmouse->ptport->serio);
+			__serio_register_port(&psmouse->ptport->serio);
+			if (psmouse->ptport->activate)
+				psmouse->ptport->activate(psmouse);
+		}
+	}
+	
 	psmouse_activate(psmouse);
+	return 0;
 }
 
+
 static struct serio_dev psmouse_dev = {
 	.interrupt =	psmouse_interrupt,
 	.connect =	psmouse_connect,
+	.reconnect =	psmouse_reconnect,
 	.disconnect =	psmouse_disconnect,
 	.cleanup =	psmouse_cleanup,
 };
diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h	Tue Sep 30 01:26:06 2003
+++ b/drivers/input/mouse/psmouse.h	Tue Sep 30 01:26:06 2003
@@ -22,10 +22,20 @@
 #define PSMOUSE_ACTIVATED	1
 #define PSMOUSE_IGNORE		2
 
+struct psmouse;
+
+struct psmouse_ptport {
+	struct serio serio;
+
+	void (*activate)(struct psmouse *parent);
+	void (*deactivate)(struct psmouse *parent);
+};
+
 struct psmouse {
 	void *private;
 	struct input_dev dev;
 	struct serio *serio;
+	struct psmouse_ptport *ptport;
 	char *vendor;
 	char *name;
 	unsigned char cmdbuf[8];
@@ -41,6 +51,9 @@
 	char error;
 	char devname[64];
 	char phys[32];
+	
+	int (*reconnect)(struct psmouse *psmouse);
+	void (*disconnect)(struct psmouse *psmouse);
 };
 
 #define PSMOUSE_PS2		1
diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c	Tue Sep 30 01:26:06 2003
+++ b/drivers/input/mouse/synaptics.c	Tue Sep 30 01:26:06 2003
@@ -195,9 +195,7 @@
 
 static int synaptics_query_hardware(struct psmouse *psmouse)
 {
-	struct synaptics_data *priv = psmouse->private;
 	int retries = 0;
-	int mode;
 
 	while ((retries++ < 3) && synaptics_reset(psmouse))
 		printk(KERN_ERR "synaptics reset failed\n");
@@ -208,8 +206,15 @@
 		return -1;
 	if (synaptics_capability(psmouse))
 		return -1;
+	
+	return 0;
+}
 
-	mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
+static int synaptics_set_mode(struct psmouse *psmouse, int mode)
+{
+	struct synaptics_data *priv = psmouse->private;
+
+	mode |= SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
 	if (SYN_ID_MAJOR(priv->identity) >= 4)
 		mode |= SYN_BIT_DISABLE_GESTURE;
 	if (SYN_CAP_EXTENDED(priv->capabilities))
@@ -266,49 +271,38 @@
 	}
 }
 
-int synaptics_pt_init(struct psmouse *psmouse)
+static void synaptics_pt_activate(struct psmouse *psmouse)
 {
-	struct synaptics_data *priv = psmouse->private;
-	struct serio *port;
-	struct psmouse *child;
+	struct psmouse *child = psmouse->ptport->serio.private;
+	
+	/* adjust the touchpad to child's choice of protocol */
+	if (child && child->type >= PSMOUSE_GENPS) {
+		if (synaptics_set_mode(psmouse, SYN_BIT_FOUR_BYTE_CLIENT))
+			printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+	}
+}
 
-	if (psmouse->type != PSMOUSE_SYNAPTICS)
-		return -1;
-	if (!SYN_CAP_EXTENDED(priv->capabilities))
-		return -1;
-	if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
-		return -1;
+static void synaptics_pt_create(struct psmouse *psmouse)
+{
+	struct psmouse_ptport *port;
 
-	priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL);
 	if (!port) {
-		printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");
-		return -1;
+		printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
+		return;
 	}
 
-	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;
+	memset(port, 0, sizeof(struct psmouse_ptport));
 
-	printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
-	__serio_register_port(port);	/* already have serio_sem */
+	port->serio.type = SERIO_PS_PSTHRU;
+	port->serio.name = "Synaptics pass-through";
+	port->serio.phys = "synaptics-pt/serio0";
+	port->serio.write = synaptics_pt_write;
+	port->serio.open = synaptics_pt_open;
+	port->serio.close = synaptics_pt_close;
+	port->serio.driver = psmouse;
 
-	/* adjust the touchpad to child's choice of protocol */
-	child = port->private;
-	if (child && child->type >= PSMOUSE_GENPS) {
-		if (synaptics_mode_cmd(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;
+	port->activate = synaptics_pt_activate;
 }
 
 /*****************************************************************************
@@ -372,27 +366,82 @@
 	clear_bit(REL_Y, dev->relbit);
 }
 
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+	synaptics_mode_cmd(psmouse, 0);
+	kfree(psmouse->private);
+}
+
+static int synaptics_reconnect(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct synaptics_data old_priv = *priv;
+
+	if (synaptics_detect(psmouse))
+		return -1;
+
+	if (synaptics_query_hardware(psmouse)) {
+		printk(KERN_ERR "Unable to query Synaptics hardware.\n");
+		return -1;
+	}
+	
+	if (old_priv.identity != priv->identity ||
+	    old_priv.model_id != priv->model_id ||
+	    old_priv.capabilities != priv->capabilities ||
+    	    old_priv.ext_cap != priv->ext_cap)
+    		return -1;
+	
+	if (synaptics_set_mode(psmouse, 0)) {
+		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int synaptics_detect(struct psmouse *psmouse)
+{
+	unsigned char param[4];
+	
+	param[0] = 0;
+	
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+	psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+	
+	return param[1] == 0x47 ? 0 : -1;
+}
+
 int synaptics_init(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv;
 
-#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
-	return -1;
-#endif
-
 	psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
 	if (!priv)
 		return -1;
 	memset(priv, 0, sizeof(struct synaptics_data));
 
 	if (synaptics_query_hardware(psmouse)) {
-		printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
+		printk(KERN_ERR "Unable to query Synaptics hardware.\n");
+		goto init_fail;
+	}
+	
+	if (synaptics_set_mode(psmouse, 0)) {
+		printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
 		goto init_fail;
 	}
 
+	if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
+       		synaptics_pt_create(psmouse);
+	
 	print_ident(priv);
 	set_input_params(&psmouse->dev, priv);
 
+	psmouse->disconnect = synaptics_disconnect;
+	psmouse->reconnect = synaptics_reconnect;
+	
 	return 0;
 
  init_fail:
@@ -400,20 +449,6 @@
 	return -1;
 }
 
-void synaptics_disconnect(struct psmouse *psmouse)
-{
-	struct synaptics_data *priv = psmouse->private;
-
-	if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
-		synaptics_mode_cmd(psmouse, 0);
-		if (priv->ptport) {
-			__serio_unregister_port(priv->ptport); /* already have serio_sem */
-			kfree(priv->ptport);
-		}
-		kfree(priv);
-	}
-}
-
 /*****************************************************************************
  *	Functions to interpret the absolute mode packets
  ****************************************************************************/
@@ -590,8 +625,8 @@
 			printk(KERN_NOTICE "Synaptics driver resynced.\n");
 		}
 
-		if (priv->ptport && synaptics_is_pt_packet(psmouse->packet))
-			synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
+		if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet))
+			synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
 		else
 			synaptics_process_packet(psmouse);
 		psmouse->pktcnt = 0;
@@ -601,8 +636,8 @@
 		psmouse->pktcnt = 0;
 		if (++priv->out_of_sync == psmouse_resetafter) {
 			psmouse->state = PSMOUSE_IGNORE;
-			printk(KERN_NOTICE "synaptics: issuing rescan request\n");
-			serio_rescan(psmouse->serio);
+			printk(KERN_NOTICE "synaptics: issuing reconnect request\n");
+			serio_reconnect(psmouse->serio);
 		}
 	}
 }
diff -Nru a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
--- a/drivers/input/mouse/synaptics.h	Tue Sep 30 01:26:06 2003
+++ b/drivers/input/mouse/synaptics.h	Tue Sep 30 01:26:06 2003
@@ -9,11 +9,9 @@
 #ifndef _SYNAPTICS_H
 #define _SYNAPTICS_H
 
-
 extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
+extern int synaptics_detect(struct psmouse *psmouse);
 extern int synaptics_init(struct psmouse *psmouse);
-extern int synaptics_pt_init(struct psmouse *psmouse);
-extern void synaptics_disconnect(struct psmouse *psmouse);
 
 /* synaptics queries */
 #define SYN_QUE_IDENTIFY		0x00
@@ -105,8 +103,6 @@
 	/* Data for normal processing */
 	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 */


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

end of thread, other threads:[~2003-09-30  6:32 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-09-30  6:24 2.6: New set of input patches Dmitry Torokhov
2003-09-30  6:06 ` [PATCH 1/6] serio: rename serio_[un]register_slave_port to __serio_[un]register_port Dmitry Torokhov
2003-09-30  6:15   ` [PATCH 2/6] serio: possible race between port removal and kseriod Dmitry Torokhov
2003-09-30  6:15     ` [PATCH 3/6] Add black list to handler<->device matching Dmitry Torokhov
2003-09-30  6:20       ` [PATCH 4/6] Synaptics: code cleanup Dmitry Torokhov
2003-09-30  6:23         ` [PATCH 5/6] serio: reconnect facility Dmitry Torokhov
2003-09-30  6:27           ` [PATCH 6/6] Synaptics: use serio_reconnect 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).