Commit c7e8dc6e authored by Dmitry Torokhov's avatar Dmitry Torokhov

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: default avatarDmitry Torokhov <dtor@mail.ru>
parent e9c8862f
......@@ -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,
};
......
......@@ -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();
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment