Skip to contentSkip to conversation

3/3 Serio: support reconnecting keeping same input device

PATCH New Dmitry Torokhov 1 participant 1 message Aug 23, 2003 Input drivers

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 3/3 Serio: support reconnecting keeping same input device

The patch below introduces a new serio_dev method "reconnect". It's purpose is to re-initialize attached hardware while keeping the same input device.

Reconnect can be used for example during resume or with somewhat broken hardware like my laptop/docking station which resets the touchpad back in relative mode without telling anyone whenever I dock or un-dock. The regular disconnect/connect solution is not working because clients (like XFree) like to keep the original input device open so after connecting the touchpad it will create a brand new input device. With reconnect the driver has an option to re-initialize hardware but keep the same input device (given that hardware didn't change).

If reconnect fails serio automatically fall back to disconnect/reconnect scheme.

What you think?

Dmitry

P.S. I have a new patch for Synaptics touchpad that makes use of this new functionality that I will sent to the LKML shortly

drivers/input/serio/serio.c +24 -7
diff -urN --exclude-from=/usr/src/exclude 2.6.0-test4/drivers/input/serio/serio.c linux-2.6.0-test4/drivers/input/serio/serio.c
@@ -55,6 +55,7 @@
 EXPORT_SYMBOL(serio_open);
 EXPORT_SYMBOL(serio_close);
 EXPORT_SYMBOL(serio_rescan);
+EXPORT_SYMBOL(serio_reconnect);
 
 struct serio_event {
 	int type;
@@ -81,6 +82,7 @@
 }
 
 #define SERIO_RESCAN	1
+#define SERIO_RECONNECT	2
 
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
 static DECLARE_COMPLETION(serio_exited);
@@ -108,6 +110,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);
@@ -142,18 +150,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,
include/linux/serio.h +2 -0
diff -urN --exclude-from=/usr/src/exclude 2.6.0-test4/include/linux/serio.h linux-2.6.0-test4/include/linux/serio.h
@@ -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);