diff options
-rw-r--r-- | drivers/input/evdev.c | 37 | ||||
-rw-r--r-- | include/uapi/linux/input.h | 1 |
2 files changed, 32 insertions, 6 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index d2b34fbbc42e..b6ded17b3be3 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -48,6 +48,7 @@ struct evdev_client { | |||
48 | struct evdev *evdev; | 48 | struct evdev *evdev; |
49 | struct list_head node; | 49 | struct list_head node; |
50 | int clkid; | 50 | int clkid; |
51 | bool revoked; | ||
51 | unsigned int bufsize; | 52 | unsigned int bufsize; |
52 | struct input_event buffer[]; | 53 | struct input_event buffer[]; |
53 | }; | 54 | }; |
@@ -164,6 +165,9 @@ static void evdev_pass_values(struct evdev_client *client, | |||
164 | struct input_event event; | 165 | struct input_event event; |
165 | bool wakeup = false; | 166 | bool wakeup = false; |
166 | 167 | ||
168 | if (client->revoked) | ||
169 | return; | ||
170 | |||
167 | event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | 171 | event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? |
168 | mono : real); | 172 | mono : real); |
169 | 173 | ||
@@ -240,7 +244,7 @@ static int evdev_flush(struct file *file, fl_owner_t id) | |||
240 | if (retval) | 244 | if (retval) |
241 | return retval; | 245 | return retval; |
242 | 246 | ||
243 | if (!evdev->exist) | 247 | if (!evdev->exist || client->revoked) |
244 | retval = -ENODEV; | 248 | retval = -ENODEV; |
245 | else | 249 | else |
246 | retval = input_flush_device(&evdev->handle, file); | 250 | retval = input_flush_device(&evdev->handle, file); |
@@ -429,7 +433,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, | |||
429 | if (retval) | 433 | if (retval) |
430 | return retval; | 434 | return retval; |
431 | 435 | ||
432 | if (!evdev->exist) { | 436 | if (!evdev->exist || client->revoked) { |
433 | retval = -ENODEV; | 437 | retval = -ENODEV; |
434 | goto out; | 438 | goto out; |
435 | } | 439 | } |
@@ -482,7 +486,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, | |||
482 | return -EINVAL; | 486 | return -EINVAL; |
483 | 487 | ||
484 | for (;;) { | 488 | for (;;) { |
485 | if (!evdev->exist) | 489 | if (!evdev->exist || client->revoked) |
486 | return -ENODEV; | 490 | return -ENODEV; |
487 | 491 | ||
488 | if (client->packet_head == client->tail && | 492 | if (client->packet_head == client->tail && |
@@ -511,7 +515,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, | |||
511 | if (!(file->f_flags & O_NONBLOCK)) { | 515 | if (!(file->f_flags & O_NONBLOCK)) { |
512 | error = wait_event_interruptible(evdev->wait, | 516 | error = wait_event_interruptible(evdev->wait, |
513 | client->packet_head != client->tail || | 517 | client->packet_head != client->tail || |
514 | !evdev->exist); | 518 | !evdev->exist || client->revoked); |
515 | if (error) | 519 | if (error) |
516 | return error; | 520 | return error; |
517 | } | 521 | } |
@@ -529,7 +533,11 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait) | |||
529 | 533 | ||
530 | poll_wait(file, &evdev->wait, wait); | 534 | poll_wait(file, &evdev->wait, wait); |
531 | 535 | ||
532 | mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR; | 536 | if (evdev->exist && !client->revoked) |
537 | mask = POLLOUT | POLLWRNORM; | ||
538 | else | ||
539 | mask = POLLHUP | POLLERR; | ||
540 | |||
533 | if (client->packet_head != client->tail) | 541 | if (client->packet_head != client->tail) |
534 | mask |= POLLIN | POLLRDNORM; | 542 | mask |= POLLIN | POLLRDNORM; |
535 | 543 | ||
@@ -795,6 +803,17 @@ static int evdev_handle_mt_request(struct input_dev *dev, | |||
795 | return 0; | 803 | return 0; |
796 | } | 804 | } |
797 | 805 | ||
806 | static int evdev_revoke(struct evdev *evdev, struct evdev_client *client, | ||
807 | struct file *file) | ||
808 | { | ||
809 | client->revoked = true; | ||
810 | evdev_ungrab(evdev, client); | ||
811 | input_flush_device(&evdev->handle, file); | ||
812 | wake_up_interruptible(&evdev->wait); | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | |||
798 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, | 817 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, |
799 | void __user *p, int compat_mode) | 818 | void __user *p, int compat_mode) |
800 | { | 819 | { |
@@ -857,6 +876,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
857 | else | 876 | else |
858 | return evdev_ungrab(evdev, client); | 877 | return evdev_ungrab(evdev, client); |
859 | 878 | ||
879 | case EVIOCREVOKE: | ||
880 | if (p) | ||
881 | return -EINVAL; | ||
882 | else | ||
883 | return evdev_revoke(evdev, client, file); | ||
884 | |||
860 | case EVIOCSCLOCKID: | 885 | case EVIOCSCLOCKID: |
861 | if (copy_from_user(&i, p, sizeof(unsigned int))) | 886 | if (copy_from_user(&i, p, sizeof(unsigned int))) |
862 | return -EFAULT; | 887 | return -EFAULT; |
@@ -1002,7 +1027,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |||
1002 | if (retval) | 1027 | if (retval) |
1003 | return retval; | 1028 | return retval; |
1004 | 1029 | ||
1005 | if (!evdev->exist) { | 1030 | if (!evdev->exist || client->revoked) { |
1006 | retval = -ENODEV; | 1031 | retval = -ENODEV; |
1007 | goto out; | 1032 | goto out; |
1008 | } | 1033 | } |
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 2fb6fae50e90..d61c61c6d98f 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h | |||
@@ -152,6 +152,7 @@ struct input_keymap_entry { | |||
152 | #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ | 152 | #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ |
153 | 153 | ||
154 | #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ | 154 | #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ |
155 | #define EVIOCREVOKE _IOW('E', 0x91, int) /* Revoke device access */ | ||
155 | 156 | ||
156 | #define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ | 157 | #define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ |
157 | 158 | ||