From 8c1c10d5706bbb3b41cb4a5578339d67d3eeffc2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 10 Oct 2011 18:31:30 -0700 Subject: [PATCH] Input: serio_raw - kick clients when disconnecting port Send SIGIO/POLL_HUP and otherwise wake up waiters when corresponding serio port is being disconnected. Also check if port is dead in serio_raw_poll and signal POLLHUP|POLLERR. This should speed up process of releasing dead devices by userspace applications. Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio_raw.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 30ff96388198..830e2fe70a66 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -232,9 +232,11 @@ static unsigned int serio_raw_poll(struct file *file, poll_table *wait) { struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; + unsigned int mask; poll_wait(file, &serio_raw->wait, wait); + mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM; if (serio_raw->head != serio_raw->tail) return POLLIN | POLLRDNORM; @@ -359,22 +361,37 @@ static int serio_raw_reconnect(struct serio *serio) return 0; } +/* + * Wake up users waiting for IO so they can disconnect from + * dead device. + */ +static void serio_raw_hangup(struct serio_raw *serio_raw) +{ + struct serio_raw_client *client; + + serio_pause_rx(serio_raw->serio); + list_for_each_entry(client, &serio_raw->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + serio_continue_rx(serio_raw->serio); + + wake_up_interruptible(&serio_raw->wait); +} + + static void serio_raw_disconnect(struct serio *serio) { - struct serio_raw *serio_raw; + struct serio_raw *serio_raw = serio_get_drvdata(serio); mutex_lock(&serio_raw_mutex); - serio_raw = serio_get_drvdata(serio); - serio_close(serio); - serio_set_drvdata(serio, NULL); - serio_raw->dead = true; - wake_up_interruptible(&serio_raw->wait); + serio_raw_hangup(serio_raw); kref_put(&serio_raw->kref, serio_raw_cleanup); mutex_unlock(&serio_raw_mutex); + + serio_set_drvdata(serio, NULL); } static struct serio_device_id serio_raw_serio_ids[] = { -- 2.20.1