aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/evdev.c37
-rw-r--r--include/uapi/linux/input.h1
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
806static 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
798static long evdev_do_ioctl(struct file *file, unsigned int cmd, 817static 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