Input: add start() method to input handlers

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>
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 056ebe8..38de44b 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -988,7 +988,7 @@
  * 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 @@
 
 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 @@
 	handle->name = "kbd";
 
 	input_open_device(handle);
-	kbd_refresh_leds(handle);
 
 	return handle;
 }
@@ -1318,6 +1300,24 @@
 	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 @@
 	.event		= kbd_event,
 	.connect	= kbd_connect,
 	.disconnect	= kbd_disconnect,
+	.start		= kbd_start,
 	.name		= "kbd",
 	.id_table	= kbd_ids,
 };
diff --git a/drivers/input/input.c b/drivers/input/input.c
index c2e4d9b..7aeebb9 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -209,8 +209,13 @@
 
 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 @@
 	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();