diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-10-10 21:31:30 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-10-10 21:35:18 -0400 |
commit | 8c1c10d5706bbb3b41cb4a5578339d67d3eeffc2 (patch) | |
tree | d6769f259626c171c7941f85a4d00d65a74fb39c /drivers/input/serio | |
parent | 85f5b35da86bcd63dd27f0976176169727f96da4 (diff) |
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 <gaowanlong@cn.fujitsu.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/serio')
-rw-r--r-- | drivers/input/serio/serio_raw.c | 29 |
1 files 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) | |||
232 | { | 232 | { |
233 | struct serio_raw_client *client = file->private_data; | 233 | struct serio_raw_client *client = file->private_data; |
234 | struct serio_raw *serio_raw = client->serio_raw; | 234 | struct serio_raw *serio_raw = client->serio_raw; |
235 | unsigned int mask; | ||
235 | 236 | ||
236 | poll_wait(file, &serio_raw->wait, wait); | 237 | poll_wait(file, &serio_raw->wait, wait); |
237 | 238 | ||
239 | mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM; | ||
238 | if (serio_raw->head != serio_raw->tail) | 240 | if (serio_raw->head != serio_raw->tail) |
239 | return POLLIN | POLLRDNORM; | 241 | return POLLIN | POLLRDNORM; |
240 | 242 | ||
@@ -359,22 +361,37 @@ static int serio_raw_reconnect(struct serio *serio) | |||
359 | return 0; | 361 | return 0; |
360 | } | 362 | } |
361 | 363 | ||
364 | /* | ||
365 | * Wake up users waiting for IO so they can disconnect from | ||
366 | * dead device. | ||
367 | */ | ||
368 | static void serio_raw_hangup(struct serio_raw *serio_raw) | ||
369 | { | ||
370 | struct serio_raw_client *client; | ||
371 | |||
372 | serio_pause_rx(serio_raw->serio); | ||
373 | list_for_each_entry(client, &serio_raw->client_list, node) | ||
374 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
375 | serio_continue_rx(serio_raw->serio); | ||
376 | |||
377 | wake_up_interruptible(&serio_raw->wait); | ||
378 | } | ||
379 | |||
380 | |||
362 | static void serio_raw_disconnect(struct serio *serio) | 381 | static void serio_raw_disconnect(struct serio *serio) |
363 | { | 382 | { |
364 | struct serio_raw *serio_raw; | 383 | struct serio_raw *serio_raw = serio_get_drvdata(serio); |
365 | 384 | ||
366 | mutex_lock(&serio_raw_mutex); | 385 | mutex_lock(&serio_raw_mutex); |
367 | 386 | ||
368 | serio_raw = serio_get_drvdata(serio); | ||
369 | |||
370 | serio_close(serio); | 387 | serio_close(serio); |
371 | serio_set_drvdata(serio, NULL); | ||
372 | |||
373 | serio_raw->dead = true; | 388 | serio_raw->dead = true; |
374 | wake_up_interruptible(&serio_raw->wait); | 389 | serio_raw_hangup(serio_raw); |
375 | kref_put(&serio_raw->kref, serio_raw_cleanup); | 390 | kref_put(&serio_raw->kref, serio_raw_cleanup); |
376 | 391 | ||
377 | mutex_unlock(&serio_raw_mutex); | 392 | mutex_unlock(&serio_raw_mutex); |
393 | |||
394 | serio_set_drvdata(serio, NULL); | ||
378 | } | 395 | } |
379 | 396 | ||
380 | static struct serio_device_id serio_raw_serio_ids[] = { | 397 | static struct serio_device_id serio_raw_serio_ids[] = { |