Input: add start() method to input handlers
authorDmitry Torokhov <dtor@insightbb.com>
Thu, 6 Jul 2006 04:21:03 +0000 (00:21 -0400)
committerDmitry Torokhov <dtor@insightbb.com>
Thu, 6 Jul 2006 04:21:03 +0000 (00:21 -0400)
The new start() method is called immediately after connect() and also
when "grabbed" device is released by its owner. This will allow input
handlers to re-synchronize state of once-grabbed device with the rest
of devices.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/char/keyboard.c
drivers/input/input.c
include/linux/input.h

index 056ebe8..38de44b 100644 (file)
@@ -988,7 +988,7 @@ static inline unsigned char getleds(void)
  * interrupt routines for this thing allows us to easily mask
  * this when we don't want any of the above to happen.
  * This allows for easy and efficient race-condition prevention
- * for kbd_refresh_leds => input_event(dev, EV_LED, ...) => ...
+ * for kbd_start => input_event(dev, EV_LED, ...) => ...
  */
 
 static void kbd_bh(unsigned long dummy)
@@ -1011,23 +1011,6 @@ static void kbd_bh(unsigned long dummy)
 
 DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 
-/*
- * This allows a newly plugged keyboard to pick the LED state.
- */
-static void kbd_refresh_leds(struct input_handle *handle)
-{
-       unsigned char leds = ledstate;
-
-       tasklet_disable(&keyboard_tasklet);
-       if (leds != 0xff) {
-               input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-               input_event(handle->dev, EV_LED, LED_NUML,    !!(leds & 0x02));
-               input_event(handle->dev, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-               input_sync(handle->dev);
-       }
-       tasklet_enable(&keyboard_tasklet);
-}
-
 #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
     defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
     defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
@@ -1307,7 +1290,6 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
        handle->name = "kbd";
 
        input_open_device(handle);
-       kbd_refresh_leds(handle);
 
        return handle;
 }
@@ -1318,6 +1300,24 @@ static void kbd_disconnect(struct input_handle *handle)
        kfree(handle);
 }
 
+/*
+ * Start keyboard handler on the new keyboard by refreshing LED state to
+ * match the rest of the system.
+ */
+static void kbd_start(struct input_handle *handle)
+{
+       unsigned char leds = ledstate;
+
+       tasklet_disable(&keyboard_tasklet);
+       if (leds != 0xff) {
+               input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+               input_event(handle->dev, EV_LED, LED_NUML,    !!(leds & 0x02));
+               input_event(handle->dev, EV_LED, LED_CAPSL,   !!(leds & 0x04));
+               input_sync(handle->dev);
+       }
+       tasklet_enable(&keyboard_tasklet);
+}
+
 static struct input_device_id kbd_ids[] = {
        {
                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
@@ -1338,6 +1338,7 @@ static struct input_handler kbd_handler = {
        .event          = kbd_event,
        .connect        = kbd_connect,
        .disconnect     = kbd_disconnect,
+       .start          = kbd_start,
        .name           = "kbd",
        .id_table       = kbd_ids,
 };
index c2e4d9b..7aeebb9 100644 (file)
@@ -209,8 +209,13 @@ EXPORT_SYMBOL(input_grab_device);
 
 void input_release_device(struct input_handle *handle)
 {
-       if (handle->dev->grab == handle)
+       if (handle->dev->grab == handle) {
                handle->dev->grab = NULL;
+
+               list_for_each_entry(handle, &handle->dev->h_list, d_node)
+                       if (handle->handler->start)
+                               handle->handler->start(handle);
+       }
 }
 EXPORT_SYMBOL(input_release_device);
 
@@ -954,8 +959,11 @@ int input_register_device(struct input_dev *dev)
        list_for_each_entry(handler, &input_handler_list, node)
                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)))
+                               if ((handle = handler->connect(handler, dev, id))) {
                                        input_link_handle(handle);
+                                       if (handler->start)
+                                               handler->start(handle);
+                               }
 
        input_wakeup_procfs_readers();
 
index 6e3afad..55e628e 100644 (file)
@@ -960,6 +960,26 @@ struct input_dev {
 
 struct input_handle;
 
+/**
+ * struct input_handler - implements one of interfaces for input devices
+ * @private: driver-specific data
+ * @event: event handler
+ * @connect: called when attaching a handler to an input device
+ * @disconnect: disconnects a handler from input device
+ * @start: starts handler for given handle. This function is called by
+ *     input core right after connect() method and also when a process
+ *     that "grabbed" a device releases it
+ * @fops: file operations this driver implements
+ * @minor: beginning of range of 32 minors for devices this driver
+ *     can provide
+ * @name: name of the handler, to be shown in /proc/bus/input/handlers
+ * @id_table: pointer to a table of input_device_ids this driver can
+ *     handle
+ * @blacklist: prointer to a table of input_device_ids this driver should
+ *     ignore even if they match @id_table
+ * @h_list: list of input handles associated with the handler
+ * @node: for placing the driver onto input_handler_list
+ */
 struct input_handler {
 
        void *private;
@@ -967,6 +987,7 @@ struct input_handler {
        void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
        struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
        void (*disconnect)(struct input_handle *handle);
+       void (*start)(struct input_handle *handle);
 
        const struct file_operations *fops;
        int minor;