diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 2ee6c7a68bdc..054edf346e0b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -10,7 +10,8 @@ | |||
10 | 10 | ||
11 | #define EVDEV_MINOR_BASE 64 | 11 | #define EVDEV_MINOR_BASE 64 |
12 | #define EVDEV_MINORS 32 | 12 | #define EVDEV_MINORS 32 |
13 | #define EVDEV_BUFFER_SIZE 64 | 13 | #define EVDEV_MIN_BUFFER_SIZE 64U |
14 | #define EVDEV_BUF_PACKETS 8 | ||
14 | 15 | ||
15 | #include <linux/poll.h> | 16 | #include <linux/poll.h> |
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
@@ -23,7 +24,6 @@ | |||
23 | #include "input-compat.h" | 24 | #include "input-compat.h" |
24 | 25 | ||
25 | struct evdev { | 26 | struct evdev { |
26 | int exist; | ||
27 | int open; | 27 | int open; |
28 | int minor; | 28 | int minor; |
29 | struct input_handle handle; | 29 | struct input_handle handle; |
@@ -33,16 +33,18 @@ struct evdev { | |||
33 | spinlock_t client_lock; /* protects client_list */ | 33 | spinlock_t client_lock; /* protects client_list */ |
34 | struct mutex mutex; | 34 | struct mutex mutex; |
35 | struct device dev; | 35 | struct device dev; |
36 | bool exist; | ||
36 | }; | 37 | }; |
37 | 38 | ||
38 | struct evdev_client { | 39 | struct evdev_client { |
39 | struct input_event buffer[EVDEV_BUFFER_SIZE]; | ||
40 | int head; | 40 | int head; |
41 | int tail; | 41 | int tail; |
42 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | 42 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ |
43 | struct fasync_struct *fasync; | 43 | struct fasync_struct *fasync; |
44 | struct evdev *evdev; | 44 | struct evdev *evdev; |
45 | struct list_head node; | 45 | struct list_head node; |
46 | int bufsize; | ||
47 | struct input_event buffer[]; | ||
46 | }; | 48 | }; |
47 | 49 | ||
48 | static struct evdev *evdev_table[EVDEV_MINORS]; | 50 | static struct evdev *evdev_table[EVDEV_MINORS]; |
@@ -52,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client, | |||
52 | struct input_event *event) | 54 | struct input_event *event) |
53 | { | 55 | { |
54 | /* | 56 | /* |
55 | * Interrupts are disabled, just acquire the lock | 57 | * Interrupts are disabled, just acquire the lock. |
58 | * Make sure we don't leave with the client buffer | ||
59 | * "empty" by having client->head == client->tail. | ||
56 | */ | 60 | */ |
57 | spin_lock(&client->buffer_lock); | 61 | spin_lock(&client->buffer_lock); |
58 | client->buffer[client->head++] = *event; | 62 | do { |
59 | client->head &= EVDEV_BUFFER_SIZE - 1; | 63 | client->buffer[client->head++] = *event; |
64 | client->head &= client->bufsize - 1; | ||
65 | } while (client->head == client->tail); | ||
60 | spin_unlock(&client->buffer_lock); | 66 | spin_unlock(&client->buffer_lock); |
61 | 67 | ||
62 | if (event->type == EV_SYN) | 68 | if (event->type == EV_SYN) |
@@ -242,11 +248,21 @@ static int evdev_release(struct inode *inode, struct file *file) | |||
242 | return 0; | 248 | return 0; |
243 | } | 249 | } |
244 | 250 | ||
251 | static unsigned int evdev_compute_buffer_size(struct input_dev *dev) | ||
252 | { | ||
253 | unsigned int n_events = | ||
254 | max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS, | ||
255 | EVDEV_MIN_BUFFER_SIZE); | ||
256 | |||
257 | return roundup_pow_of_two(n_events); | ||
258 | } | ||
259 | |||
245 | static int evdev_open(struct inode *inode, struct file *file) | 260 | static int evdev_open(struct inode *inode, struct file *file) |
246 | { | 261 | { |
247 | struct evdev *evdev; | 262 | struct evdev *evdev; |
248 | struct evdev_client *client; | 263 | struct evdev_client *client; |
249 | int i = iminor(inode) - EVDEV_MINOR_BASE; | 264 | int i = iminor(inode) - EVDEV_MINOR_BASE; |
265 | unsigned int bufsize; | ||
250 | int error; | 266 | int error; |
251 | 267 | ||
252 | if (i >= EVDEV_MINORS) | 268 | if (i >= EVDEV_MINORS) |
@@ -263,12 +279,17 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
263 | if (!evdev) | 279 | if (!evdev) |
264 | return -ENODEV; | 280 | return -ENODEV; |
265 | 281 | ||
266 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); | 282 | bufsize = evdev_compute_buffer_size(evdev->handle.dev); |
283 | |||
284 | client = kzalloc(sizeof(struct evdev_client) + | ||
285 | bufsize * sizeof(struct input_event), | ||
286 | GFP_KERNEL); | ||
267 | if (!client) { | 287 | if (!client) { |
268 | error = -ENOMEM; | 288 | error = -ENOMEM; |
269 | goto err_put_evdev; | 289 | goto err_put_evdev; |
270 | } | 290 | } |
271 | 291 | ||
292 | client->bufsize = bufsize; | ||
272 | spin_lock_init(&client->buffer_lock); | 293 | spin_lock_init(&client->buffer_lock); |
273 | client->evdev = evdev; | 294 | client->evdev = evdev; |
274 | evdev_attach_client(evdev, client); | 295 | evdev_attach_client(evdev, client); |
@@ -334,7 +355,7 @@ static int evdev_fetch_next_event(struct evdev_client *client, | |||
334 | have_event = client->head != client->tail; | 355 | have_event = client->head != client->tail; |
335 | if (have_event) { | 356 | if (have_event) { |
336 | *event = client->buffer[client->tail++]; | 357 | *event = client->buffer[client->tail++]; |
337 | client->tail &= EVDEV_BUFFER_SIZE - 1; | 358 | client->tail &= client->bufsize - 1; |
338 | } | 359 | } |
339 | 360 | ||
340 | spin_unlock_irq(&client->buffer_lock); | 361 | spin_unlock_irq(&client->buffer_lock); |
@@ -382,10 +403,15 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait) | |||
382 | { | 403 | { |
383 | struct evdev_client *client = file->private_data; | 404 | struct evdev_client *client = file->private_data; |
384 | struct evdev *evdev = client->evdev; | 405 | struct evdev *evdev = client->evdev; |
406 | unsigned int mask; | ||
385 | 407 | ||
386 | poll_wait(file, &evdev->wait, wait); | 408 | poll_wait(file, &evdev->wait, wait); |
387 | return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | | 409 | |
388 | (evdev->exist ? 0 : (POLLHUP | POLLERR)); | 410 | mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR; |
411 | if (client->head != client->tail) | ||
412 | mask |= POLLIN | POLLRDNORM; | ||
413 | |||
414 | return mask; | ||
389 | } | 415 | } |
390 | 416 | ||
391 | #ifdef CONFIG_COMPAT | 417 | #ifdef CONFIG_COMPAT |
@@ -665,6 +691,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
665 | sizeof(struct input_absinfo)))) | 691 | sizeof(struct input_absinfo)))) |
666 | return -EFAULT; | 692 | return -EFAULT; |
667 | 693 | ||
694 | /* We can't change number of reserved MT slots */ | ||
695 | if (t == ABS_MT_SLOT) | ||
696 | return -EINVAL; | ||
697 | |||
668 | /* | 698 | /* |
669 | * Take event lock to ensure that we are not | 699 | * Take event lock to ensure that we are not |
670 | * changing device parameters in the middle | 700 | * changing device parameters in the middle |
@@ -768,7 +798,7 @@ static void evdev_remove_chrdev(struct evdev *evdev) | |||
768 | static void evdev_mark_dead(struct evdev *evdev) | 798 | static void evdev_mark_dead(struct evdev *evdev) |
769 | { | 799 | { |
770 | mutex_lock(&evdev->mutex); | 800 | mutex_lock(&evdev->mutex); |
771 | evdev->exist = 0; | 801 | evdev->exist = false; |
772 | mutex_unlock(&evdev->mutex); | 802 | mutex_unlock(&evdev->mutex); |
773 | } | 803 | } |
774 | 804 | ||
@@ -817,7 +847,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
817 | init_waitqueue_head(&evdev->wait); | 847 | init_waitqueue_head(&evdev->wait); |
818 | 848 | ||
819 | dev_set_name(&evdev->dev, "event%d", minor); | 849 | dev_set_name(&evdev->dev, "event%d", minor); |
820 | evdev->exist = 1; | 850 | evdev->exist = true; |
821 | evdev->minor = minor; | 851 | evdev->minor = minor; |
822 | 852 | ||
823 | evdev->handle.dev = input_get_device(dev); | 853 | evdev->handle.dev = input_get_device(dev); |