Browse Source

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>
Hans de Goede 8 years ago
parent
commit
83e4947a56
1 changed files with 28 additions and 12 deletions
  1. 28 12
      drivers/input/keyboard/gpio_keys.c

+ 28 - 12
drivers/input/keyboard/gpio_keys.c

@@ -36,6 +36,8 @@ struct gpio_button_data {
 	struct input_dev *input;
 	struct input_dev *input;
 	struct gpio_desc *gpiod;
 	struct gpio_desc *gpiod;
 
 
+	unsigned short *code;
+
 	struct timer_list release_timer;
 	struct timer_list release_timer;
 	unsigned int release_delay;	/* in msecs, for IRQ-only buttons */
 	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;
 	const struct gpio_keys_platform_data *pdata;
 	struct input_dev *input;
 	struct input_dev *input;
 	struct mutex disable_lock;
 	struct mutex disable_lock;
+	unsigned short *keymap;
 	struct gpio_button_data data[0];
 	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)
 		if (only_disabled && !bdata->disabled)
 			continue;
 			continue;
 
 
-		__set_bit(bdata->button->code, bits);
+		__set_bit(*bdata->code, bits);
 	}
 	}
 
 
 	ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, 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)
 		if (bdata->button->type != type)
 			continue;
 			continue;
 
 
-		if (test_bit(bdata->button->code, bits) &&
+		if (test_bit(*bdata->code, bits) &&
 		    !bdata->button->can_disable) {
 		    !bdata->button->can_disable) {
 			error = -EINVAL;
 			error = -EINVAL;
 			goto out;
 			goto out;
@@ -269,7 +272,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
 		if (bdata->button->type != type)
 		if (bdata->button->type != type)
 			continue;
 			continue;
 
 
-		if (test_bit(bdata->button->code, bits))
+		if (test_bit(*bdata->code, bits))
 			gpio_keys_disable_button(bdata);
 			gpio_keys_disable_button(bdata);
 		else
 		else
 			gpio_keys_enable_button(bdata);
 			gpio_keys_enable_button(bdata);
@@ -371,7 +374,7 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
 		if (state)
 		if (state)
 			input_event(input, type, button->code, button->value);
 			input_event(input, type, button->code, button->value);
 	} else {
 	} else {
-		input_event(input, type, button->code, state);
+		input_event(input, type, *bdata->code, state);
 	}
 	}
 	input_sync(input);
 	input_sync(input);
 }
 }
@@ -411,7 +414,7 @@ static void gpio_keys_irq_timer(unsigned long _data)
 
 
 	spin_lock_irqsave(&bdata->lock, flags);
 	spin_lock_irqsave(&bdata->lock, flags);
 	if (bdata->key_pressed) {
 	if (bdata->key_pressed) {
-		input_event(input, EV_KEY, bdata->button->code, 0);
+		input_event(input, EV_KEY, *bdata->code, 0);
 		input_sync(input);
 		input_sync(input);
 		bdata->key_pressed = false;
 		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)
 static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
 {
 {
 	struct gpio_button_data *bdata = dev_id;
 	struct gpio_button_data *bdata = dev_id;
-	const struct gpio_keys_button *button = bdata->button;
 	struct input_dev *input = bdata->input;
 	struct input_dev *input = bdata->input;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -433,11 +435,11 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
 		if (bdata->button->wakeup)
 		if (bdata->button->wakeup)
 			pm_wakeup_event(bdata->input->dev.parent, 0);
 			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);
 		input_sync(input);
 
 
 		if (!bdata->release_delay) {
 		if (!bdata->release_delay) {
-			input_event(input, EV_KEY, button->code, 0);
+			input_event(input, EV_KEY, *bdata->code, 0);
 			input_sync(input);
 			input_sync(input);
 			goto out;
 			goto out;
 		}
 		}
@@ -465,12 +467,14 @@ static void gpio_keys_quiesce_key(void *data)
 
 
 static int gpio_keys_setup_key(struct platform_device *pdev,
 static int gpio_keys_setup_key(struct platform_device *pdev,
 				struct input_dev *input,
 				struct input_dev *input,
-				struct gpio_button_data *bdata,
+				struct gpio_keys_drvdata *ddata,
 				const struct gpio_keys_button *button,
 				const struct gpio_keys_button *button,
+				int idx,
 				struct fwnode_handle *child)
 				struct fwnode_handle *child)
 {
 {
 	const char *desc = button->desc ? button->desc : "gpio_keys";
 	const char *desc = button->desc ? button->desc : "gpio_keys";
 	struct device *dev = &pdev->dev;
 	struct device *dev = &pdev->dev;
+	struct gpio_button_data *bdata = &ddata->data[idx];
 	irq_handler_t isr;
 	irq_handler_t isr;
 	unsigned long irqflags;
 	unsigned long irqflags;
 	int irq;
 	int irq;
@@ -577,7 +581,9 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 		irqflags = 0;
 		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
 	 * Install custom action to cancel release timer and
@@ -750,6 +756,12 @@ static int gpio_keys_probe(struct platform_device *pdev)
 		return -ENOMEM;
 		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);
 	input = devm_input_allocate_device(dev);
 	if (!input) {
 	if (!input) {
 		dev_err(dev, "failed to allocate input device\n");
 		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.product = 0x0001;
 	input->id.version = 0x0100;
 	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 */
 	/* Enable auto repeat feature of Linux input subsystem */
 	if (pdata->rep)
 	if (pdata->rep)
 		__set_bit(EV_REP, input->evbit);
 		__set_bit(EV_REP, input->evbit);
 
 
 	for (i = 0; i < pdata->nbuttons; i++) {
 	for (i = 0; i < pdata->nbuttons; i++) {
 		const struct gpio_keys_button *button = &pdata->buttons[i];
 		const struct gpio_keys_button *button = &pdata->buttons[i];
-		struct gpio_button_data *bdata = &ddata->data[i];
 
 
 		if (!dev_get_platdata(dev)) {
 		if (!dev_get_platdata(dev)) {
 			child = device_get_next_child_node(&pdev->dev, child);
 			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) {
 		if (error) {
 			fwnode_handle_put(child);
 			fwnode_handle_put(child);
 			return error;
 			return error;