]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Input: add serio_[un]register_port_delayed to fix deadlock
authorDmitry Torokhov <dtor_core@ameritech.net>
Thu, 18 Dec 2003 13:35:36 +0000 (05:35 -0800)
committerDmitry Torokhov <dtor_core@ameritech.net>
Thu, 18 Dec 2003 13:35:36 +0000 (05:35 -0800)
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
drivers/input/serio/serio.c
include/linux/serio.h

index b603a4db0efe8ad4d9ae80d6aabc7ae52bbe6735..1b0e7a5fd16b4c6ac80ed70b505cc7ccc3e7e039 100644 (file)
@@ -283,7 +283,7 @@ activate_fail:
 
 irq_fail:
        values->exists = 0;
-       serio_unregister_port(port);
+       serio_unregister_port_delayed(port);
 
        return -1;
 }
index 105a5d59a4e7d1aeeae2b23fd5d11482e1d02394..53e77f40e2fe584c249850d9934318ff4f8096ac 100644 (file)
@@ -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 *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)
@@ -197,6 +209,16 @@ void serio_register_port(struct serio *serio)
        up(&serio_sem);
 }
 
+/*
+ * 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
@@ -215,6 +237,16 @@ void serio_unregister_port(struct serio *serio)
        up(&serio_sem);
 }
 
+/*
+ * 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
index 8248b882e28278ea6ea28aaeff6f58da06256f82..d99e973302de948fce4d5eb6497d646d7bb1f73b 100644 (file)
@@ -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);