
From: Dmitry Torokhov <dtor_core@ameritech.net>

Add serio_[un]register_port_delayed to allow delayed execution of
register/unregister code (via kseriod) when it is not clear whether
serio_sem has been taken or not.  Use in i8042.c to avoid deadlock



 drivers/input/serio/i8042.c |    2 +-
 drivers/input/serio/serio.c |   36 ++++++++++++++++++++++++++++++++++--
 include/linux/serio.h       |    2 ++
 3 files changed, 37 insertions(+), 3 deletions(-)

diff -puN drivers/input/serio/i8042.c~input-06-serio_unregister_port_delayed drivers/input/serio/i8042.c
--- 25/drivers/input/serio/i8042.c~input-06-serio_unregister_port_delayed	2003-12-16 22:47:41.000000000 -0800
+++ 25-akpm/drivers/input/serio/i8042.c	2003-12-16 22:47:41.000000000 -0800
@@ -283,7 +283,7 @@ activate_fail:
 
 irq_fail:
 	values->exists = 0;
-	serio_unregister_port(port);
+	serio_unregister_port_delayed(port);
 
 	return -1;
 }
diff -puN drivers/input/serio/serio.c~input-06-serio_unregister_port_delayed drivers/input/serio/serio.c
--- 25/drivers/input/serio/serio.c~input-06-serio_unregister_port_delayed	2003-12-16 22:47:41.000000000 -0800
+++ 25-akpm/drivers/input/serio/serio.c	2003-12-16 22:47:41.000000000 -0800
@@ -49,8 +49,10 @@ MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_register_port_delayed);
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_port_delayed);
 EXPORT_SYMBOL(__serio_unregister_port);
 EXPORT_SYMBOL(serio_register_device);
 EXPORT_SYMBOL(serio_unregister_device);
@@ -83,8 +85,10 @@ static void serio_find_dev(struct serio 
 	}
 }
 
-#define SERIO_RESCAN	1
-#define SERIO_RECONNECT	2
+#define SERIO_RESCAN		1
+#define SERIO_RECONNECT		2
+#define SERIO_REGISTER_PORT	3
+#define SERIO_UNREGISTER_PORT	4
 
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
 static DECLARE_COMPLETION(serio_exited);
@@ -111,6 +115,14 @@ void serio_handle_events(void)
 			goto event_done;
 
 		switch (event->type) {
+			case SERIO_REGISTER_PORT :
+				__serio_register_port(event->serio);
+				break;
+
+			case SERIO_UNREGISTER_PORT :
+				__serio_unregister_port(event->serio);
+				break;
+
 			case SERIO_RECONNECT :
 				if (event->serio->dev && event->serio->dev->reconnect)
 					if (event->serio->dev->reconnect(event->serio) == 0)
@@ -198,6 +210,16 @@ void serio_register_port(struct serio *s
 }
 
 /*
+ * Submits register request to kseriod for subsequent execution.
+ * Can be used when it is not obvious whether the serio_sem is
+ * taken or not and when delayed execution is feasible.
+ */
+void serio_register_port_delayed(struct serio *serio)
+{
+	serio_queue_event(serio, SERIO_REGISTER_PORT);
+}
+
+/*
  * 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.
@@ -216,6 +238,16 @@ void serio_unregister_port(struct serio 
 }
 
 /*
+ * Submits unregister request to kseriod for subsequent execution.
+ * Can be used when it is not obvious whether the serio_sem is
+ * taken or not and when delayed execution is feasible.
+ */
+void serio_unregister_port_delayed(struct serio *serio)
+{
+	serio_queue_event(serio, SERIO_UNREGISTER_PORT);
+}
+
+/*
  * 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.
diff -puN include/linux/serio.h~input-06-serio_unregister_port_delayed include/linux/serio.h
--- 25/include/linux/serio.h~input-06-serio_unregister_port_delayed	2003-12-16 22:47:41.000000000 -0800
+++ 25-akpm/include/linux/serio.h	2003-12-16 22:47:41.000000000 -0800
@@ -63,8 +63,10 @@ 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);
+void serio_register_port_delayed(struct serio *serio);
 void __serio_register_port(struct serio *serio);
 void serio_unregister_port(struct serio *serio);
+void serio_unregister_port_delayed(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);

_
