| From 1a3a2b379659d6b4f9c6113f227d33fb1f7c3161 Mon Sep 17 00:00:00 2001 |
| From: Hans de Goede <hdegoede@redhat.com> |
| Date: Sat, 21 Jan 2017 11:16:47 -0800 |
| Subject: [PATCH 048/255] Input: gpio-keys - add support for setkeycode |
| |
| gpio-keys input devices created by the soc_button_array driver are |
| configured with key-codes based on ACPI provided information. |
| |
| Unfortunately on some tablets this info is wrong, and we need to have |
| a quirk to fix things up. |
| |
| Add support for input_setkeycode to the gpio-keys driver, so that |
| the existing udev hwdb mechanism can be used to fix things up on these |
| tablets. |
| |
| Signed-off-by: Hans de Goede <hdegoede@redhat.com> |
| Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| (cherry picked from commit 83e4947a569f4d544ef4a1361f51c91d73a9c915) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/input/keyboard/gpio_keys.c | 40 +++++++++++++++++++++++++------------ |
| 1 file changed, 28 insertions(+), 12 deletions(-) |
| |
| --- a/drivers/input/keyboard/gpio_keys.c |
| +++ b/drivers/input/keyboard/gpio_keys.c |
| @@ -36,6 +36,8 @@ struct gpio_button_data { |
| struct input_dev *input; |
| struct gpio_desc *gpiod; |
| |
| + unsigned short *code; |
| + |
| struct timer_list release_timer; |
| unsigned int release_delay; /* in msecs, for IRQ-only buttons */ |
| |
| @@ -52,6 +54,7 @@ struct gpio_keys_drvdata { |
| const struct gpio_keys_platform_data *pdata; |
| struct input_dev *input; |
| struct mutex disable_lock; |
| + unsigned short *keymap; |
| struct gpio_button_data data[0]; |
| }; |
| |
| @@ -203,7 +206,7 @@ static ssize_t gpio_keys_attr_show_helpe |
| if (only_disabled && !bdata->disabled) |
| continue; |
| |
| - __set_bit(bdata->button->code, bits); |
| + __set_bit(*bdata->code, bits); |
| } |
| |
| ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits); |
| @@ -254,7 +257,7 @@ static ssize_t gpio_keys_attr_store_help |
| if (bdata->button->type != type) |
| continue; |
| |
| - if (test_bit(bdata->button->code, bits) && |
| + if (test_bit(*bdata->code, bits) && |
| !bdata->button->can_disable) { |
| error = -EINVAL; |
| goto out; |
| @@ -269,7 +272,7 @@ static ssize_t gpio_keys_attr_store_help |
| if (bdata->button->type != type) |
| continue; |
| |
| - if (test_bit(bdata->button->code, bits)) |
| + if (test_bit(*bdata->code, bits)) |
| gpio_keys_disable_button(bdata); |
| else |
| gpio_keys_enable_button(bdata); |
| @@ -371,7 +374,7 @@ static void gpio_keys_gpio_report_event( |
| if (state) |
| input_event(input, type, button->code, button->value); |
| } else { |
| - input_event(input, type, button->code, state); |
| + input_event(input, type, *bdata->code, state); |
| } |
| input_sync(input); |
| } |
| @@ -411,7 +414,7 @@ static void gpio_keys_irq_timer(unsigned |
| |
| spin_lock_irqsave(&bdata->lock, flags); |
| if (bdata->key_pressed) { |
| - input_event(input, EV_KEY, bdata->button->code, 0); |
| + input_event(input, EV_KEY, *bdata->code, 0); |
| input_sync(input); |
| bdata->key_pressed = false; |
| } |
| @@ -421,7 +424,6 @@ static void gpio_keys_irq_timer(unsigned |
| static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) |
| { |
| struct gpio_button_data *bdata = dev_id; |
| - const struct gpio_keys_button *button = bdata->button; |
| struct input_dev *input = bdata->input; |
| unsigned long flags; |
| |
| @@ -433,11 +435,11 @@ static irqreturn_t gpio_keys_irq_isr(int |
| if (bdata->button->wakeup) |
| pm_wakeup_event(bdata->input->dev.parent, 0); |
| |
| - input_event(input, EV_KEY, button->code, 1); |
| + input_event(input, EV_KEY, *bdata->code, 1); |
| input_sync(input); |
| |
| if (!bdata->release_delay) { |
| - input_event(input, EV_KEY, button->code, 0); |
| + input_event(input, EV_KEY, *bdata->code, 0); |
| input_sync(input); |
| goto out; |
| } |
| @@ -465,12 +467,14 @@ static void gpio_keys_quiesce_key(void * |
| |
| static int gpio_keys_setup_key(struct platform_device *pdev, |
| struct input_dev *input, |
| - struct gpio_button_data *bdata, |
| + struct gpio_keys_drvdata *ddata, |
| const struct gpio_keys_button *button, |
| + int idx, |
| struct fwnode_handle *child) |
| { |
| const char *desc = button->desc ? button->desc : "gpio_keys"; |
| struct device *dev = &pdev->dev; |
| + struct gpio_button_data *bdata = &ddata->data[idx]; |
| irq_handler_t isr; |
| unsigned long irqflags; |
| int irq; |
| @@ -577,7 +581,9 @@ static int gpio_keys_setup_key(struct pl |
| irqflags = 0; |
| } |
| |
| - input_set_capability(input, button->type ?: EV_KEY, button->code); |
| + bdata->code = &ddata->keymap[idx]; |
| + *bdata->code = button->code; |
| + input_set_capability(input, button->type ?: EV_KEY, *bdata->code); |
| |
| /* |
| * Install custom action to cancel release timer and |
| @@ -750,6 +756,12 @@ static int gpio_keys_probe(struct platfo |
| return -ENOMEM; |
| } |
| |
| + ddata->keymap = devm_kcalloc(dev, |
| + pdata->nbuttons, sizeof(ddata->keymap[0]), |
| + GFP_KERNEL); |
| + if (!ddata->keymap) |
| + return -ENOMEM; |
| + |
| input = devm_input_allocate_device(dev); |
| if (!input) { |
| dev_err(dev, "failed to allocate input device\n"); |
| @@ -774,13 +786,16 @@ static int gpio_keys_probe(struct platfo |
| input->id.product = 0x0001; |
| input->id.version = 0x0100; |
| |
| + input->keycode = ddata->keymap; |
| + input->keycodesize = sizeof(ddata->keymap[0]); |
| + input->keycodemax = pdata->nbuttons; |
| + |
| /* Enable auto repeat feature of Linux input subsystem */ |
| if (pdata->rep) |
| __set_bit(EV_REP, input->evbit); |
| |
| for (i = 0; i < pdata->nbuttons; i++) { |
| const struct gpio_keys_button *button = &pdata->buttons[i]; |
| - struct gpio_button_data *bdata = &ddata->data[i]; |
| |
| if (!dev_get_platdata(dev)) { |
| child = device_get_next_child_node(&pdev->dev, child); |
| @@ -792,7 +807,8 @@ static int gpio_keys_probe(struct platfo |
| } |
| } |
| |
| - error = gpio_keys_setup_key(pdev, input, bdata, button, child); |
| + error = gpio_keys_setup_key(pdev, input, ddata, |
| + button, i, child); |
| if (error) { |
| fwnode_handle_put(child); |
| return error; |