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 d08abf9101d2..a3726275876d 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 | ||
