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>
This commit is contained in:
Родитель
5c4fa2a6da
Коммит
83e4947a56
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче