diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-02 21:35:17 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-02 21:35:17 -0400 |
| commit | d01d0756f75e7a5b4b43764ad45b83c4340f11d6 (patch) | |
| tree | 90db2ff7ccb35a8fdcf98366e6404afe1f845bc4 /drivers/input/evdev.c | |
| parent | b326b853dca2f410b254198ee89abad71a2f4668 (diff) | |
| parent | 0d87c7228a49e8342d60dd552892e470e0b291fa (diff) | |
Merge branch 'next' into for-linus
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); |
