aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/misc/uinput.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-06-20 10:17:02 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-20 10:17:02 -0700
commit93db6294958f62643a917e44d1abc85440e600cf (patch)
tree33de2c41b0f70d209d64487d1a2bba6d673015ef /drivers/input/misc/uinput.c
parent43813f399c72aa22e01a680559c1cb5274bf2140 (diff)
parenteef3e4cab72eaf5345e3c73b2975c194a714f6cd (diff)
downloadkernel_samsung_espresso10-93db6294958f62643a917e44d1abc85440e600cf.zip
kernel_samsung_espresso10-93db6294958f62643a917e44d1abc85440e600cf.tar.gz
kernel_samsung_espresso10-93db6294958f62643a917e44d1abc85440e600cf.tar.bz2
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (35 commits) Input: add driver for Synaptics I2C touchpad Input: synaptics - add support for reporting x/y resolution Input: ALPS - handle touchpoints buttons correctly Input: gpio-keys - change timer to workqueue Input: ads7846 - pin change interrupt support Input: add support for touchscreen on W90P910 ARM platform Input: appletouch - improve finger detection Input: wacom - clear Intuos4 wheel data when finger leaves proximity Input: ucb1400 - move static function from header into core Input: add driver for EETI touchpanels Input: ads7846 - more detailed model name in sysfs Input: ads7846 - support swapping x and y axes Input: ati_remote2 - use non-atomic bitops Input: introduce lm8323 keypad driver Input: psmouse - ESD workaround fix for OLPC XO touchpad Input: tsc2007 - make sure platform provides get_pendown_state() Input: uinput - flush all pending ff effects before destroying device Input: simplify name handling for certain input handles Input: serio - do not use deprecated dev.power.power_state Input: wacom - add support for Intuos4 tablets ...
Diffstat (limited to 'drivers/input/misc/uinput.c')
-rw-r--r--drivers/input/misc/uinput.c94
1 files changed, 71 insertions, 23 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 46b7cae..c5a49ab 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -54,27 +54,28 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i
return 0;
}
+/* Atomically allocate an ID for the given request. Returns 0 on success. */
static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
{
- /* Atomically allocate an ID for the given request. Returns 0 on success. */
int id;
int err = -1;
spin_lock(&udev->requests_lock);
- for (id = 0; id < UINPUT_NUM_REQUESTS; id++)
+ for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {
if (!udev->requests[id]) {
request->id = id;
udev->requests[id] = request;
err = 0;
break;
}
+ }
spin_unlock(&udev->requests_lock);
return err;
}
-static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id)
+static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id)
{
/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
if (id >= UINPUT_NUM_REQUESTS || id < 0)
@@ -99,14 +100,51 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques
complete(&request->done);
}
-static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request)
+static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request)
{
+ int retval;
+
+ retval = uinput_request_reserve_slot(udev, request);
+ if (retval)
+ return retval;
+
+ retval = mutex_lock_interruptible(&udev->mutex);
+ if (retval)
+ return retval;
+
+ if (udev->state != UIST_CREATED) {
+ retval = -ENODEV;
+ goto out;
+ }
+
/* Tell our userspace app about this new request by queueing an input event */
- uinput_dev_event(dev, EV_UINPUT, request->code, request->id);
+ uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
+
+ out:
+ mutex_unlock(&udev->mutex);
+ return retval;
+}
+
+/*
+ * Fail all ouitstanding requests so handlers don't wait for the userspace
+ * to finish processing them.
+ */
+static void uinput_flush_requests(struct uinput_device *udev)
+{
+ struct uinput_request *request;
+ int i;
+
+ spin_lock(&udev->requests_lock);
+
+ for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {
+ request = udev->requests[i];
+ if (request) {
+ request->retval = -ENODEV;
+ uinput_request_done(udev, request);
+ }
+ }
- /* Wait for the request to complete */
- wait_for_completion(&request->done);
- return request->retval;
+ spin_unlock(&udev->requests_lock);
}
static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
@@ -126,6 +164,7 @@ static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{
+ struct uinput_device *udev = input_get_drvdata(dev);
struct uinput_request request;
int retval;
@@ -146,15 +185,18 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
request.u.upload.effect = effect;
request.u.upload.old = old;
- retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
- if (!retval)
- retval = uinput_request_submit(dev, &request);
+ retval = uinput_request_submit(udev, &request);
+ if (!retval) {
+ wait_for_completion(&request.done);
+ retval = request.retval;
+ }
return retval;
}
static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
{
+ struct uinput_device *udev = input_get_drvdata(dev);
struct uinput_request request;
int retval;
@@ -166,9 +208,11 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
request.code = UI_FF_ERASE;
request.u.effect_id = effect_id;
- retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
- if (!retval)
- retval = uinput_request_submit(dev, &request);
+ retval = uinput_request_submit(udev, &request);
+ if (!retval) {
+ wait_for_completion(&request.done);
+ retval = request.retval;
+ }
return retval;
}
@@ -176,20 +220,24 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
static void uinput_destroy_device(struct uinput_device *udev)
{
const char *name, *phys;
+ struct input_dev *dev = udev->dev;
+ enum uinput_state old_state = udev->state;
- if (udev->dev) {
- name = udev->dev->name;
- phys = udev->dev->phys;
- if (udev->state == UIST_CREATED)
- input_unregister_device(udev->dev);
- else
- input_free_device(udev->dev);
+ udev->state = UIST_NEW_DEVICE;
+
+ if (dev) {
+ name = dev->name;
+ phys = dev->phys;
+ if (old_state == UIST_CREATED) {
+ uinput_flush_requests(udev);
+ input_unregister_device(dev);
+ } else {
+ input_free_device(dev);
+ }
kfree(name);
kfree(phys);
udev->dev = NULL;
}
-
- udev->state = UIST_NEW_DEVICE;
}
static int uinput_create_device(struct uinput_device *udev)