mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 22:56:27 +08:00
Input: serio - clear pending rescans after sysfs driver rebind
When rebinding a serio driver via sysfs drvctl interface it is possible for an interrupt to trigger after the disconnect of the existing driver and before the binding of the new driver. This will cause the serio interrupt handler to queue a rescan event which will disconnect the new driver immediately after it is attached. This change removes pending rescans from the serio event queue after processing the drvctl request but before releasing the serio mutex. Reproduction involves issuing a rebind of device port from psmouse driver to serio_raw driver while generating input to trigger interrupts. Then checking to see if the corresponding i8042/serio4/driver is correctly attached to the serio_raw driver instead of psmouse. Signed-off-by: Duncan Laurie <dlaurie@chromium.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
parent
e0d5f4c31d
commit
19e9554153
@ -188,7 +188,8 @@ static void serio_free_event(struct serio_event *event)
|
||||
kfree(event);
|
||||
}
|
||||
|
||||
static void serio_remove_duplicate_events(struct serio_event *event)
|
||||
static void serio_remove_duplicate_events(void *object,
|
||||
enum serio_event_type type)
|
||||
{
|
||||
struct serio_event *e, *next;
|
||||
unsigned long flags;
|
||||
@ -196,13 +197,13 @@ static void serio_remove_duplicate_events(struct serio_event *event)
|
||||
spin_lock_irqsave(&serio_event_lock, flags);
|
||||
|
||||
list_for_each_entry_safe(e, next, &serio_event_list, node) {
|
||||
if (event->object == e->object) {
|
||||
if (object == e->object) {
|
||||
/*
|
||||
* If this event is of different type we should not
|
||||
* look further - we only suppress duplicate events
|
||||
* that were sent back-to-back.
|
||||
*/
|
||||
if (event->type != e->type)
|
||||
if (type != e->type)
|
||||
break;
|
||||
|
||||
list_del_init(&e->node);
|
||||
@ -245,7 +246,7 @@ static void serio_handle_event(struct work_struct *work)
|
||||
break;
|
||||
}
|
||||
|
||||
serio_remove_duplicate_events(event);
|
||||
serio_remove_duplicate_events(event->object, event->type);
|
||||
serio_free_event(event);
|
||||
}
|
||||
|
||||
@ -436,10 +437,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
|
||||
} else if (!strncmp(buf, "rescan", count)) {
|
||||
serio_disconnect_port(serio);
|
||||
serio_find_driver(serio);
|
||||
serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
|
||||
} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
|
||||
serio_disconnect_port(serio);
|
||||
error = serio_bind_driver(serio, to_serio_driver(drv));
|
||||
put_driver(drv);
|
||||
serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
|
||||
} else {
|
||||
error = -EINVAL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user