diff options
author | Hans de Goede <hdegoede@redhat.com> | 2017-01-21 11:16:47 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-01-21 11:46:53 -0800 |
commit | 83e4947a569f4d544ef4a1361f51c91d73a9c915 (patch) | |
tree | 372e8f937497f5a28ab49e13d39849571d25f7fe /drivers/input/keyboard | |
parent | 5c4fa2a6da7fbc76290d1cb54a7e35633517a522 (diff) | |
download | blackbird-op-linux-83e4947a569f4d544ef4a1361f51c91d73a9c915.tar.gz blackbird-op-linux-83e4947a569f4d544ef4a1361f51c91d73a9c915.zip |
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>
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 582462d0af75..858bbc16b900 100644 --- 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_helper(struct gpio_keys_drvdata *ddata, 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_helper(struct gpio_keys_drvdata *ddata, 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_helper(struct gpio_keys_drvdata *ddata, 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(struct gpio_button_data *bdata) 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 long _data) 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 long _data) 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 irq, void *dev_id) 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 *data) 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 platform_device *pdev, 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 platform_device *pdev) 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 platform_device *pdev) 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 platform_device *pdev) } } - 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; |