From 112b51cfa21714d001e5b3e3f7c1f13146906a5d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 29 Jul 2012 22:25:51 -0700 Subject: Input: twl4030-pwrbutton - report a wakeup_event on button press As the power button causes a wake from suspend, we need to register the event with the pm sustem to avoid racing with suspend. As the input event is reported in the interrupt handler, as simple pm_wakeup_event() is sufficient. Signed-off-by: NeilBrown Signed-off-by: Dmitry Torokhov --- drivers/input/misc/twl4030-pwrbutton.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index 38e4b507b94..b3dd96d6448 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -42,6 +42,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr) err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS); if (!err) { + pm_wakeup_event(pwr->dev.parent, 0); input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); input_sync(pwr); } else { -- cgit v1.2.3-70-g09d2 From a78769b80d73468d53d0ad70c5a9e3fd9ff9dc54 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 31 Jul 2012 22:08:47 -0700 Subject: Input: rotary-encoder - defer calls gpio_to_irq() Don't call gpio_to_irq() on GPIOs before gpio_request() succeeded on them. This avoids Ooopses with incorrect DT bindings. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index f07f784198b..00a7bdabb0b 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -163,8 +163,6 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) encoder->input = input; encoder->pdata = pdata; - encoder->irq_a = gpio_to_irq(pdata->gpio_a); - encoder->irq_b = gpio_to_irq(pdata->gpio_b); /* create and register the input driver */ input->name = pdev->name; @@ -215,6 +213,9 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) goto exit_free_gpio_a; } + encoder->irq_a = gpio_to_irq(pdata->gpio_a); + encoder->irq_b = gpio_to_irq(pdata->gpio_b); + /* request the IRQs */ if (pdata->half_period) { handler = &rotary_encoder_half_period_irq; -- cgit v1.2.3-70-g09d2 From 429a34d7477bb7071d37dd98b89f000ee6f0193b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 31 Jul 2012 22:08:48 -0700 Subject: Input: rotary-encoder - use gpio_request_one() Use gpio_request_one() instead of separate calls to gpio_request() and gpio_direction_input() to simplify the code. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 00a7bdabb0b..e261ad4e6c6 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -145,6 +145,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; struct rotary_encoder *encoder; struct input_dev *input; + struct device *dev = &pdev->dev; irq_handler_t handler; int err; @@ -180,36 +181,20 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) err = input_register_device(input); if (err) { - dev_err(&pdev->dev, "failed to register input device\n"); + dev_err(dev, "failed to register input device\n"); goto exit_free_mem; } /* request the GPIOs */ - err = gpio_request(pdata->gpio_a, DRV_NAME); + err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); if (err) { - dev_err(&pdev->dev, "unable to request GPIO %d\n", - pdata->gpio_a); + dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); goto exit_unregister_input; } - err = gpio_direction_input(pdata->gpio_a); + err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); if (err) { - dev_err(&pdev->dev, "unable to set GPIO %d for input\n", - pdata->gpio_a); - goto exit_unregister_input; - } - - err = gpio_request(pdata->gpio_b, DRV_NAME); - if (err) { - dev_err(&pdev->dev, "unable to request GPIO %d\n", - pdata->gpio_b); - goto exit_free_gpio_a; - } - - err = gpio_direction_input(pdata->gpio_b); - if (err) { - dev_err(&pdev->dev, "unable to set GPIO %d for input\n", - pdata->gpio_b); + dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b); goto exit_free_gpio_a; } @@ -228,8 +213,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, DRV_NAME, encoder); if (err) { - dev_err(&pdev->dev, "unable to request IRQ %d\n", - encoder->irq_a); + dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a); goto exit_free_gpio_b; } @@ -237,8 +221,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, DRV_NAME, encoder); if (err) { - dev_err(&pdev->dev, "unable to request IRQ %d\n", - encoder->irq_b); + dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b); goto exit_free_irq_a; } -- cgit v1.2.3-70-g09d2 From ce9195378299ff2f3d703937de46bdd338e780eb Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 31 Jul 2012 22:08:49 -0700 Subject: Input: rotary-encoder - constify platform data pointers Drivers should not be changing platform data attached to the device because they do not own it. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/rotary_encoder.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index e261ad4e6c6..ea51265d4e0 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -29,7 +29,7 @@ struct rotary_encoder { struct input_dev *input; - struct rotary_encoder_platform_data *pdata; + const struct rotary_encoder_platform_data *pdata; unsigned int axis; unsigned int pos; @@ -43,7 +43,7 @@ struct rotary_encoder { char last_stable; }; -static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) +static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata) { int a = !!gpio_get_value(pdata->gpio_a); int b = !!gpio_get_value(pdata->gpio_b); @@ -56,7 +56,7 @@ static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata) static void rotary_encoder_report_event(struct rotary_encoder *encoder) { - struct rotary_encoder_platform_data *pdata = encoder->pdata; + const struct rotary_encoder_platform_data *pdata = encoder->pdata; if (pdata->relative_axis) { input_report_rel(encoder->input, @@ -142,10 +142,10 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) static int __devinit rotary_encoder_probe(struct platform_device *pdev) { - struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev); struct rotary_encoder *encoder; struct input_dev *input; - struct device *dev = &pdev->dev; irq_handler_t handler; int err; @@ -247,7 +247,7 @@ exit_free_mem: static int __devexit rotary_encoder_remove(struct platform_device *pdev) { struct rotary_encoder *encoder = platform_get_drvdata(pdev); - struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data; + const struct rotary_encoder_platform_data *pdata = encoder->pdata; free_irq(encoder->irq_a, encoder); free_irq(encoder->irq_b, encoder); -- cgit v1.2.3-70-g09d2 From 80c99bcd28617bd534b6f9489857235ee613c797 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 31 Jul 2012 22:08:50 -0700 Subject: Input: rotary-encoder - add DT bindings This adds devicetree bindings to the rotary encoder driver and some documentation about how to use them. Tested on a PXA3xx platform. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/rotary-encoder.txt | 36 ++++++++ drivers/input/misc/rotary_encoder.c | 96 ++++++++++++++++++---- 2 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/rotary-encoder.txt (limited to 'drivers/input/misc') diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt new file mode 100644 index 00000000000..331549593ed --- /dev/null +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt @@ -0,0 +1,36 @@ +Rotary encoder DT bindings + +Required properties: +- gpios: a spec for two GPIOs to be used + +Optional properties: +- linux,axis: the input subsystem axis to map to this rotary encoder. + Defaults to 0 (ABS_X / REL_X) +- rotary-encoder,steps: Number of steps in a full turnaround of the + encoder. Only relevant for absolute axis. Defaults to 24 which is a + typical value for such devices. +- rotary-encoder,relative-axis: register a relative axis rather than an + absolute one. Relative axis will only generate +1/-1 events on the input + device, hence no steps need to be passed. +- rotary-encoder,rollover: Automatic rollove when the rotary value becomes + greater than the specified steps or smaller than 0. For absolute axis only. +- rotary-encoder,half-period: Makes the driver work on half-period mode. + +See Documentation/input/rotary-encoder.txt for more information. + +Example: + + rotary@0 { + compatible = "rotary-encoder"; + gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */ + linux,axis = <0>; /* REL_X */ + rotary-encoder,relative-axis; + }; + + rotary@1 { + compatible = "rotary-encoder"; + gpios = <&gpio 21 0>, <&gpio 22 0>; + linux,axis = <1>; /* ABS_Y */ + rotary-encoder,steps = <24>; + rotary-encoder,rollover; + }; diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index ea51265d4e0..99a49e4968d 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #define DRV_NAME "rotary-encoder" @@ -140,6 +142,56 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_OF +static struct of_device_id rotary_encoder_of_match[] = { + { .compatible = "rotary-encoder", }, + { }, +}; +MODULE_DEVICE_TABLE(of, rotary_encoder_of_match); + +static struct rotary_encoder_platform_data * __devinit +rotary_encoder_parse_dt(struct device *dev) +{ + const struct of_device_id *of_id = + of_match_device(rotary_encoder_of_match, dev); + struct device_node *np = dev->of_node; + struct rotary_encoder_platform_data *pdata; + enum of_gpio_flags flags; + + if (!of_id || !np) + return NULL; + + pdata = kzalloc(sizeof(struct rotary_encoder_platform_data), + GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps); + of_property_read_u32(np, "linux,axis", &pdata->axis); + + pdata->gpio_a = of_get_gpio_flags(np, 0, &flags); + pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW; + + pdata->gpio_b = of_get_gpio_flags(np, 1, &flags); + pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW; + + pdata->relative_axis = !!of_get_property(np, + "rotary-encoder,relative-axis", NULL); + pdata->rollover = !!of_get_property(np, + "rotary-encoder,rollover", NULL); + pdata->half_period = !!of_get_property(np, + "rotary-encoder,half-period", NULL); + + return pdata; +} +#else +static inline struct rotary_encoder_platform_data * +rotary_encoder_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int __devinit rotary_encoder_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -150,14 +202,19 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) int err; if (!pdata) { - dev_err(&pdev->dev, "missing platform data\n"); - return -ENOENT; + pdata = rotary_encoder_parse_dt(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + + if (!pdata) { + dev_err(dev, "missing platform data\n"); + return -EINVAL; + } } encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL); input = input_allocate_device(); if (!encoder || !input) { - dev_err(&pdev->dev, "failed to allocate memory for device\n"); err = -ENOMEM; goto exit_free_mem; } @@ -165,10 +222,9 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) encoder->input = input; encoder->pdata = pdata; - /* create and register the input driver */ input->name = pdev->name; input->id.bustype = BUS_HOST; - input->dev.parent = &pdev->dev; + input->dev.parent = dev; if (pdata->relative_axis) { input->evbit[0] = BIT_MASK(EV_REL); @@ -179,17 +235,11 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) pdata->axis, 0, pdata->steps, 0, 1); } - err = input_register_device(input); - if (err) { - dev_err(dev, "failed to register input device\n"); - goto exit_free_mem; - } - /* request the GPIOs */ err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev)); if (err) { dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a); - goto exit_unregister_input; + goto exit_free_mem; } err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev)); @@ -225,22 +275,30 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) goto exit_free_irq_a; } + err = input_register_device(input); + if (err) { + dev_err(dev, "failed to register input device\n"); + goto exit_free_irq_b; + } + platform_set_drvdata(pdev, encoder); return 0; +exit_free_irq_b: + free_irq(encoder->irq_b, encoder); exit_free_irq_a: free_irq(encoder->irq_a, encoder); exit_free_gpio_b: gpio_free(pdata->gpio_b); exit_free_gpio_a: gpio_free(pdata->gpio_a); -exit_unregister_input: - input_unregister_device(input); - input = NULL; /* so we don't try to free it */ exit_free_mem: input_free_device(input); kfree(encoder); + if (!dev_get_platdata(&pdev->dev)) + kfree(pdata); + return err; } @@ -253,10 +311,15 @@ static int __devexit rotary_encoder_remove(struct platform_device *pdev) free_irq(encoder->irq_b, encoder); gpio_free(pdata->gpio_a); gpio_free(pdata->gpio_b); + input_unregister_device(encoder->input); - platform_set_drvdata(pdev, NULL); kfree(encoder); + if (!dev_get_platdata(&pdev->dev)) + kfree(pdata); + + platform_set_drvdata(pdev, NULL); + return 0; } @@ -266,6 +329,7 @@ static struct platform_driver rotary_encoder_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rotary_encoder_of_match), } }; module_platform_driver(rotary_encoder_driver); -- cgit v1.2.3-70-g09d2 From 929d1af5478dec82903e05aa9662a4ec12ad655b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Jul 2012 22:48:31 -0700 Subject: Input: uinput - take event lock when fetching events from buffer When fetching events form device's buffer in uinput_read() we need to take input device's event_lock to avoid racing with new event delivery. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 736056897e5..1b4ee4a5c49 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -452,9 +452,28 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t return retval; } +static bool uinput_fetch_next_event(struct uinput_device *udev, + struct input_event *event) +{ + bool have_event; + + spin_lock_irq(&udev->dev->event_lock); + + have_event = udev->head != udev->tail; + if (have_event) { + *event = udev->buff[udev->tail]; + udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; + } + + spin_unlock_irq(&udev->dev->event_lock); + + return have_event; +} + static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct uinput_device *udev = file->private_data; + struct input_event event; int retval = 0; if (udev->state != UIST_CREATED) @@ -477,12 +496,14 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, goto out; } - while (udev->head != udev->tail && retval + input_event_size() <= count) { - if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) { + while (retval + input_event_size() <= count && + uinput_fetch_next_event(udev, &event)) { + + if (input_event_to_user(buffer + retval, &event)) { retval = -EFAULT; goto out; } - udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; + retval += input_event_size(); } -- cgit v1.2.3-70-g09d2 From f40033acc2d14acecd1b27a79dc8a0ad437e619a Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 29 Jul 2012 22:48:31 -0700 Subject: Input: uinput - return -EINVAL when read buffer size is too small Let's check whether the user-supplied buffer is actually big enough and return -EINVAL if it is not. This differs from current behavior, which caused 0 to be returned and actually does not make any sense, as broken application will simply repeat the read getting into endless loop. Note that we treat 0 as a special case, according to the standard: "Before any action described below is taken, and if nbyte is zero, the read() function may detect and return errors as described below. In the absence of errors, or if error detection is not performed, the read() function shall return zero and have no other results." Signed-off-by: David Herrmann Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 1b4ee4a5c49..e74ed9cc637 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -476,6 +476,9 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, struct input_event event; int retval = 0; + if (count != 0 && count < input_event_size()) + return -EINVAL; + if (udev->state != UIST_CREATED) return -ENODEV; -- cgit v1.2.3-70-g09d2 From 22ae19c6e3c22b390952e90f452f26adad9b8687 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Jul 2012 22:48:31 -0700 Subject: Input: uinput - fix race that can block nonblocking read Consider two threads calling read() on the same uinput-fd, both non-blocking. Assume there is data-available so both will simultaneously pass: udev->head == udev->tail Then the first thread goes to sleep and the second one pops the message from the queue. Now assume udev->head == udev->tail. If the first thread wakes up it will call wait_event_*() and sleep in the waitq. This effectively turns the non-blocking FD into a blocking one. We fix this by attempting to fetch events from the queue first and only if we fail to retrieve any events we either return -EAGAIN (in case of non-blocing read) or wait until there are more events. This also fixes incorrect return code (we were returning 0 instead of -EAGAIN for non-blocking reads) when an event is "stolen" by another thread. Blocking reads will now continue to wait instead of returning 0 in this scenario. Count of 0 continues to be a special case, as per spec: we will check for device existence and whether there are events in the queue, but no events will be actually retrieved. Reported-by: David Herrmann Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 74 +++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 30 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index e74ed9cc637..1719554fe19 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -439,6 +439,9 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t struct uinput_device *udev = file->private_data; int retval; + if (count == 0) + return 0; + retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; @@ -470,48 +473,59 @@ static bool uinput_fetch_next_event(struct uinput_device *udev, return have_event; } -static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t uinput_events_to_user(struct uinput_device *udev, + char __user *buffer, size_t count) { - struct uinput_device *udev = file->private_data; struct input_event event; - int retval = 0; + size_t read = 0; + int error = 0; - if (count != 0 && count < input_event_size()) - return -EINVAL; + while (read + input_event_size() <= count && + uinput_fetch_next_event(udev, &event)) { - if (udev->state != UIST_CREATED) - return -ENODEV; + if (input_event_to_user(buffer + read, &event)) { + error = -EFAULT; + break; + } - if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; + read += input_event_size(); + } - retval = wait_event_interruptible(udev->waitq, - udev->head != udev->tail || udev->state != UIST_CREATED); - if (retval) - return retval; + return read ?: error; +} - retval = mutex_lock_interruptible(&udev->mutex); - if (retval) - return retval; +static ssize_t uinput_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct uinput_device *udev = file->private_data; + ssize_t retval; - if (udev->state != UIST_CREATED) { - retval = -ENODEV; - goto out; - } + if (count != 0 && count < input_event_size()) + return -EINVAL; - while (retval + input_event_size() <= count && - uinput_fetch_next_event(udev, &event)) { + do { + retval = mutex_lock_interruptible(&udev->mutex); + if (retval) + return retval; - if (input_event_to_user(buffer + retval, &event)) { - retval = -EFAULT; - goto out; - } + if (udev->state != UIST_CREATED) + retval = -ENODEV; + else if (udev->head == udev->tail && + (file->f_flags & O_NONBLOCK)) + retval = -EAGAIN; + else + retval = uinput_events_to_user(udev, buffer, count); - retval += input_event_size(); - } + mutex_unlock(&udev->mutex); - out: - mutex_unlock(&udev->mutex); + if (retval || count == 0) + break; + + if (!(file->f_flags & O_NONBLOCK)) + retval = wait_event_interruptible(udev->waitq, + udev->head != udev->tail || + udev->state != UIST_CREATED); + } while (retval == 0); return retval; } -- cgit v1.2.3-70-g09d2 From 00ce756ce53acdb82d408346e6a7b734ca9e5bad Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Jul 2012 22:48:32 -0700 Subject: Input: uinput - mark failed submission requests as free If uinput_request_submit() fails after new request ID was allocated we need to mark that request ID as free, otherwise it will always stay occupied and we may run out of available IDs. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 78 +++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 38 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 1719554fe19..6099365102d 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -56,10 +56,11 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i } /* 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) +static bool uinput_request_alloc_id(struct uinput_device *udev, + struct uinput_request *request) { int id; - int err = -1; + bool reserved = false; spin_lock(&udev->requests_lock); @@ -67,13 +68,13 @@ static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_req if (!udev->requests[id]) { request->id = id; udev->requests[id] = request; - err = 0; + reserved = true; break; } } spin_unlock(&udev->requests_lock); - return err; + return reserved; } static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) @@ -85,11 +86,12 @@ static struct uinput_request *uinput_request_find(struct uinput_device *udev, in return udev->requests[id]; } -static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) +static int uinput_request_reserve_slot(struct uinput_device *udev, + struct uinput_request *request) { /* Allocate slot. If none are available right away, wait. */ return wait_event_interruptible(udev->requests_waitq, - !uinput_request_alloc_id(udev, request)); + uinput_request_alloc_id(udev, request)); } static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) @@ -101,14 +103,11 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques complete(&request->done); } -static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) +static int uinput_request_send(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; @@ -118,7 +117,12 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque goto out; } - /* Tell our userspace app about this new request by queueing an input event */ + init_completion(&request->done); + + /* + * Tell our userspace application about this new request + * by queueing an input event. + */ uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); out: @@ -126,6 +130,25 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque return retval; } +static int uinput_request_submit(struct uinput_device *udev, + struct uinput_request *request) +{ + int error; + + error = uinput_request_reserve_slot(udev, request); + if (error) + return error; + + error = uinput_request_send(udev, request); + if (error) { + uinput_request_done(udev, request); + return error; + } + + wait_for_completion(&request->done); + return request->retval; +} + /* * Fail all ouitstanding requests so handlers don't wait for the userspace * to finish processing them. @@ -167,7 +190,6 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff { struct uinput_device *udev = input_get_drvdata(dev); struct uinput_request request; - int retval; /* * uinput driver does not currently support periodic effects with @@ -180,42 +202,25 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff effect->u.periodic.waveform == FF_CUSTOM) return -EINVAL; - request.id = -1; - init_completion(&request.done); request.code = UI_FF_UPLOAD; request.u.upload.effect = effect; request.u.upload.old = old; - retval = uinput_request_submit(udev, &request); - if (!retval) { - wait_for_completion(&request.done); - retval = request.retval; - } - - return retval; + return uinput_request_submit(udev, &request); } 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; if (!test_bit(EV_FF, dev->evbit)) return -ENOSYS; - request.id = -1; - init_completion(&request.done); request.code = UI_FF_ERASE; request.u.effect_id = effect_id; - retval = uinput_request_submit(udev, &request); - if (!retval) { - wait_for_completion(&request.done); - retval = request.retval; - } - - return retval; + return uinput_request_submit(udev, &request); } static void uinput_destroy_device(struct uinput_device *udev) @@ -478,20 +483,17 @@ static ssize_t uinput_events_to_user(struct uinput_device *udev, { struct input_event event; size_t read = 0; - int error = 0; while (read + input_event_size() <= count && uinput_fetch_next_event(udev, &event)) { - if (input_event_to_user(buffer + read, &event)) { - error = -EFAULT; - break; - } + if (input_event_to_user(buffer + read, &event)) + return -EFAULT; read += input_event_size(); } - return read ?: error; + return read; } static ssize_t uinput_read(struct file *file, char __user *buffer, -- cgit v1.2.3-70-g09d2 From c5b3533a82ef4b6ceae81b7675f8d6dadcc6f3ab Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Jul 2012 22:48:32 -0700 Subject: Input: uinput - specify exact bit sizes on userspace APIs Switch to using __u32/__s32 instead of ordinary 'int' in structures forming userspace API. Also internally make request_id unsigned int. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 11 ++++++----- include/linux/uinput.h | 27 ++++++++++++++------------- 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 6099365102d..b247e1c8e8f 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -59,7 +59,7 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i static bool uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) { - int id; + unsigned int id; bool reserved = false; spin_lock(&udev->requests_lock); @@ -77,10 +77,11 @@ static bool uinput_request_alloc_id(struct uinput_device *udev, return reserved; } -static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) +static struct uinput_request *uinput_request_find(struct uinput_device *udev, + unsigned int id) { /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ - if (id >= UINPUT_NUM_REQUESTS || id < 0) + if (id >= UINPUT_NUM_REQUESTS) return NULL; return udev->requests[id]; @@ -556,8 +557,8 @@ static int uinput_release(struct inode *inode, struct file *file) #ifdef CONFIG_COMPAT struct uinput_ff_upload_compat { - int request_id; - int retval; + __u32 request_id; + __s32 retval; struct ff_effect_compat effect; struct ff_effect_compat old; }; diff --git a/include/linux/uinput.h b/include/linux/uinput.h index 2aa2881b0df..c454bbe39ee 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h @@ -32,6 +32,7 @@ * - first public version */ +#include #include #define UINPUT_VERSION 3 @@ -44,14 +45,14 @@ enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED }; struct uinput_request { - int id; - int code; /* UI_FF_UPLOAD, UI_FF_ERASE */ + unsigned int id; + unsigned int code; /* UI_FF_UPLOAD, UI_FF_ERASE */ int retval; struct completion done; union { - int effect_id; + unsigned int effect_id; struct { struct ff_effect *effect; struct ff_effect *old; @@ -77,16 +78,16 @@ struct uinput_device { #endif /* __KERNEL__ */ struct uinput_ff_upload { - int request_id; - int retval; + __u32 request_id; + __s32 retval; struct ff_effect effect; struct ff_effect old; }; struct uinput_ff_erase { - int request_id; - int retval; - int effect_id; + __u32 request_id; + __s32 retval; + __u32 effect_id; }; /* ioctl */ @@ -166,11 +167,11 @@ struct uinput_ff_erase { struct uinput_user_dev { char name[UINPUT_MAX_NAME_SIZE]; struct input_id id; - int ff_effects_max; - int absmax[ABS_CNT]; - int absmin[ABS_CNT]; - int absfuzz[ABS_CNT]; - int absflat[ABS_CNT]; + __u32 ff_effects_max; + __s32 absmax[ABS_CNT]; + __s32 absmin[ABS_CNT]; + __s32 absfuzz[ABS_CNT]; + __s32 absflat[ABS_CNT]; }; #endif /* __UINPUT_H_ */ -- cgit v1.2.3-70-g09d2 From 54ce165ebd9d9494b64149e0d1ab4ddbf5ea908b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 29 Jul 2012 22:48:32 -0700 Subject: Input: uinput - fix formatting Reformat the code to keep it within 80 columns. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index b247e1c8e8f..86328e9c984 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -40,7 +40,8 @@ #include #include "../input-compat.h" -static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +static int uinput_dev_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) { struct uinput_device *udev = input_get_drvdata(dev); @@ -95,7 +96,8 @@ static int uinput_request_reserve_slot(struct uinput_device *udev, uinput_request_alloc_id(udev, request)); } -static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) +static void uinput_request_done(struct uinput_device *udev, + struct uinput_request *request) { /* Mark slot as available */ udev->requests[request->id] = NULL; @@ -151,7 +153,7 @@ static int uinput_request_submit(struct uinput_device *udev, } /* - * Fail all ouitstanding requests so handlers don't wait for the userspace + * Fail all outstanding requests so handlers don't wait for the userspace * to finish processing them. */ static void uinput_flush_requests(struct uinput_device *udev) @@ -187,7 +189,9 @@ static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) return uinput_dev_event(dev, EV_FF, effect_id, value); } -static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) +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; @@ -353,7 +357,8 @@ static int uinput_allocate_device(struct uinput_device *udev) return 0; } -static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count) +static int uinput_setup_device(struct uinput_device *udev, + const char __user *buffer, size_t count) { struct uinput_user_dev *user_dev; struct input_dev *dev; @@ -425,7 +430,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu return retval; } -static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count) +static ssize_t uinput_inject_event(struct uinput_device *udev, + const char __user *buffer, size_t count) { struct input_event ev; @@ -440,7 +446,8 @@ static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char return input_event_size(); } -static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t uinput_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { struct uinput_device *udev = file->private_data; int retval; @@ -744,7 +751,8 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, break; req = uinput_request_find(udev, ff_up.request_id); - if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { + if (!req || req->code != UI_FF_UPLOAD || + !req->u.upload.effect) { retval = -EINVAL; break; } @@ -827,7 +835,8 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT -static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long uinput_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); } @@ -872,4 +881,3 @@ MODULE_VERSION("0.3"); module_init(uinput_init); module_exit(uinput_exit); - -- cgit v1.2.3-70-g09d2