diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 19:34:29 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 19:34:29 +0200 |
commit | 2c01e7bc46f10e9190818437e564f7e0db875ae9 (patch) | |
tree | 8b06c85d69754f7df27f7fb42520f6e2ceaea907 /drivers/input/evdev.c | |
parent | Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git... (diff) | |
parent | Merge branch 'next' into for-linus (diff) | |
download | linux-2c01e7bc46f10e9190818437e564f7e0db875ae9.tar.xz linux-2c01e7bc46f10e9190818437e564f7e0db875ae9.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input layer updates from Dmitry Torokhov:
- a bunch of new drivers (DA9052/53 touchscreenn controller, Synaptics
Navpoint, LM8333 keypads, Wacom I2C touhscreen);
- updates to existing touchpad drivers (ALPS, Sntelic);
- Wacom driver now supports Intuos5;
- device-tree bindings in numerous drivers;
- other cleanups and fixes.
Fix annoying conflict in drivers/input/tablet/wacom_wac.c that I think
implies that the input layer device naming is broken, but let's see. I
brough it up with Dmitry.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (57 commits)
Input: matrix-keymap - fix building keymaps
Input: spear-keyboard - document DT bindings
Input: spear-keyboard - add device tree bindings
Input: matrix-keymap - wire up device tree support
Input: matrix-keymap - uninline and prepare for device tree support
Input: adp5588 - add support for gpio names
Input: omap-keypad - dynamically handle register offsets
Input: synaptics - fix compile warning
MAINTAINERS: adjust input-related patterns
Input: ALPS - switch to using input_mt_report_finger_count
Input: ALPS - add semi-MT support for v4 protocol
Input: Add Synaptics NavPoint (PXA27x SSP/SPI) driver
Input: atmel_mxt_ts - dump each message on just 1 line
Input: atmel_mxt_ts - do not read extra (checksum) byte
Input: atmel_mxt_ts - verify object size in mxt_write_object
Input: atmel_mxt_ts - only allow root to update firmware
Input: atmel_mxt_ts - use CONFIG_PM_SLEEP
Input: sentelic - report device's production serial number
Input: tl6040-vibra - Device Tree support
Input: evdev - properly handle read/write with count 0
...
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 69 |
1 files changed, 43 insertions, 26 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 4b2e10d5d641..6c58bfff01a3 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -180,7 +180,10 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client) static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) { - if (evdev->grab != client) + struct evdev_client *grab = rcu_dereference_protected(evdev->grab, + lockdep_is_held(&evdev->mutex)); + + if (grab != client) return -EINVAL; rcu_assign_pointer(evdev->grab, NULL); @@ -259,8 +262,7 @@ static int evdev_release(struct inode *inode, struct file *file) struct evdev *evdev = client->evdev; mutex_lock(&evdev->mutex); - if (evdev->grab == client) - evdev_ungrab(evdev, client); + evdev_ungrab(evdev, client); mutex_unlock(&evdev->mutex); evdev_detach_client(evdev, client); @@ -343,7 +345,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, struct input_event event; int retval = 0; - if (count < input_event_size()) + if (count != 0 && count < input_event_size()) return -EINVAL; retval = mutex_lock_interruptible(&evdev->mutex); @@ -355,7 +357,8 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, goto out; } - do { + while (retval + input_event_size() <= count) { + if (input_event_from_user(buffer + retval, &event)) { retval = -EFAULT; goto out; @@ -364,7 +367,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, input_inject_event(&evdev->handle, event.type, event.code, event.value); - } while (retval + input_event_size() <= count); + } out: mutex_unlock(&evdev->mutex); @@ -395,35 +398,49 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; - int retval = 0; + size_t read = 0; + int error; - if (count < input_event_size()) + if (count != 0 && count < input_event_size()) return -EINVAL; - if (!(file->f_flags & O_NONBLOCK)) { - retval = wait_event_interruptible(evdev->wait, - client->packet_head != client->tail || - !evdev->exist); - if (retval) - return retval; - } + for (;;) { + if (!evdev->exist) + return -ENODEV; - if (!evdev->exist) - return -ENODEV; + if (client->packet_head == client->tail && + (file->f_flags & O_NONBLOCK)) + return -EAGAIN; - while (retval + input_event_size() <= count && - evdev_fetch_next_event(client, &event)) { + /* + * count == 0 is special - no IO is done but we check + * for error conditions (see above). + */ + if (count == 0) + break; - if (input_event_to_user(buffer + retval, &event)) - return -EFAULT; + while (read + input_event_size() <= count && + evdev_fetch_next_event(client, &event)) { - retval += input_event_size(); - } + if (input_event_to_user(buffer + read, &event)) + return -EFAULT; - if (retval == 0 && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; + read += input_event_size(); + } - return retval; + if (read) + break; + + if (!(file->f_flags & O_NONBLOCK)) { + error = wait_event_interruptible(evdev->wait, + client->packet_head != client->tail || + !evdev->exist); + if (error) + return error; + } + } + + return read; } /* No kernel lock - fine */ |