diff options
author | Arve Hjønnevåg <arve@android.com> | 2009-07-24 15:19:56 -0700 |
---|---|---|
committer | Arve Hjønnevåg <arve@android.com> | 2009-07-29 14:29:32 -0700 |
commit | c7b88835d33184838b25b785d31ff4af612fbb6a (patch) | |
tree | 73ed925407df06b298cce3aff9898a2491bd0bc3 /drivers/input | |
parent | e73bc4a9c2dd2d8f9f8188ebf9a5aeca302e2a23 (diff) |
Input: gpio_event: Allow multiple input devices per gpio_event device
This is needed to support devices that put non-keyboard buttons in
the keyboard matrix. For instance several devices put the trackball
button in the keyboard matrix. In this case BTN_MOUSE should be
reported from the same input device as REL_X/Y.
It is also useful for devices that have multiple logical keyboard in
the same matrix. The HTC dream has a menu key on the external keyboard
and another menu key on the slide-out keyboard. With a single input
device only one of these menu keys can be mapped to KEY_MENU.
Signed-off-by: Arve Hjønnevåg <arve@android.com>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/misc/gpio_axis.c | 29 | ||||
-rw-r--r-- | drivers/input/misc/gpio_event.c | 89 | ||||
-rw-r--r-- | drivers/input/misc/gpio_input.c | 29 | ||||
-rw-r--r-- | drivers/input/misc/gpio_matrix.c | 43 | ||||
-rw-r--r-- | drivers/input/misc/gpio_output.c | 27 |
5 files changed, 152 insertions, 65 deletions
diff --git a/drivers/input/misc/gpio_axis.c b/drivers/input/misc/gpio_axis.c index c801172aa9ee..30b9f5681ce9 100644 --- a/drivers/input/misc/gpio_axis.c +++ b/drivers/input/misc/gpio_axis.c @@ -19,7 +19,7 @@ #include <linux/interrupt.h> struct gpio_axis_state { - struct input_dev *input_dev; + struct gpio_event_input_devs *input_devs; struct gpio_event_axis_info *info; uint32_t pos; }; @@ -87,14 +87,16 @@ static void gpio_event_update_axis(struct gpio_axis_state *as, int report) if (ai->flags & GPIOEAF_PRINT_EVENT) pr_info("axis %d-%d change %d\n", ai->type, ai->code, change); - input_report_rel(as->input_dev, ai->code, change); + input_report_rel(as->input_devs->dev[ai->dev], + ai->code, change); } else { if (ai->flags & GPIOEAF_PRINT_EVENT) pr_info("axis %d-%d now %d\n", ai->type, ai->code, pos); - input_event(as->input_dev, ai->type, ai->code, pos); + input_event(as->input_devs->dev[ai->dev], + ai->type, ai->code, pos); } - input_sync(as->input_dev); + input_sync(as->input_devs->dev[ai->dev]); } as->pos = pos; } @@ -106,7 +108,7 @@ static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -int gpio_event_axis_func(struct input_dev *input_dev, +int gpio_event_axis_func(struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, void **data, int func) { int ret; @@ -133,13 +135,21 @@ int gpio_event_axis_func(struct input_dev *input_dev, ret = -ENOMEM; goto err_alloc_axis_state_failed; } - as->input_dev = input_dev; + as->input_devs = input_devs; as->info = ai; + if (ai->dev >= input_devs->count) { + pr_err("gpio_event_axis: bad device index %d >= %d " + "for %d:%d\n", ai->dev, input_devs->count, + ai->type, ai->code); + ret = -EINVAL; + goto err_bad_device_index; + } - input_set_capability(input_dev, ai->type, ai->code); + input_set_capability(input_devs->dev[ai->dev], + ai->type, ai->code); if (ai->type == EV_ABS) { - input_set_abs_params(input_dev, ai->code, 0, - ai->decoded_size - 1, 0, 0); + input_set_abs_params(input_devs->dev[ai->dev], ai->code, + 0, ai->decoded_size - 1, 0, 0); } for (i = 0; i < ai->count; i++) { ret = gpio_request(ai->gpio[i], "gpio_event_axis"); @@ -173,6 +183,7 @@ err_gpio_direction_input_failed: err_request_gpio_failed: ; } +err_bad_device_index: kfree(as); *data = NULL; err_alloc_axis_state_failed: diff --git a/drivers/input/misc/gpio_event.c b/drivers/input/misc/gpio_event.c index 8b64c1e579ba..139b3600ed7e 100644 --- a/drivers/input/misc/gpio_event.c +++ b/drivers/input/misc/gpio_event.c @@ -21,7 +21,7 @@ #include <linux/platform_device.h> struct gpio_event { - struct input_dev *input_dev; + struct gpio_event_input_devs *input_devs; const struct gpio_event_platform_data *info; struct early_suspend early_suspend; void *state[0]; @@ -31,15 +31,25 @@ static int gpio_input_event( struct input_dev *dev, unsigned int type, unsigned int code, int value) { int i; + int devnr; int ret = 0; int tmp_ret; struct gpio_event_info **ii; struct gpio_event *ip = input_get_drvdata(dev); + for (devnr = 0; devnr < ip->input_devs->count; devnr++) + if (ip->input_devs->dev[devnr] == dev) + break; + if (devnr == ip->input_devs->count) { + pr_err("gpio_input_event: unknown device %p\n", dev); + return -EIO; + } + for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) { if ((*ii)->event) { - tmp_ret = (*ii)->event(ip->input_dev, *ii, - &ip->state[i], type, code, value); + tmp_ret = (*ii)->event(ip->input_devs, *ii, + &ip->state[i], + devnr, type, code, value); if (tmp_ret) ret = tmp_ret; } @@ -62,7 +72,9 @@ static int gpio_event_call_all_func(struct gpio_event *ip, int func) "no function\n"); goto err_no_func; } - ret = (*ii)->func(ip->input_dev, *ii, &ip->state[i], + if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend) + continue; + ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i], func); if (ret) { pr_err("gpio_event_probe: function failed\n"); @@ -78,7 +90,9 @@ static int gpio_event_call_all_func(struct gpio_event *ip, int func) while (i > 0) { i--; ii--; - (*ii)->func(ip->input_dev, *ii, &ip->state[i], func & ~1); + if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend) + continue; + (*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1); err_func_failed: err_no_func: ; @@ -108,37 +122,51 @@ static int __init gpio_event_probe(struct platform_device *pdev) { int err; struct gpio_event *ip; - struct input_dev *input_dev; struct gpio_event_platform_data *event_info; + int dev_count = 1; + int i; + int registered = 0; event_info = pdev->dev.platform_data; if (event_info == NULL) { pr_err("gpio_event_probe: No pdata\n"); return -ENODEV; } - if (event_info->name == NULL || - event_info->info == NULL || - event_info->info_count == 0) { + if ((!event_info->name && !event_info->names[0]) || + !event_info->info || !event_info->info_count) { pr_err("gpio_event_probe: Incomplete pdata\n"); return -ENODEV; } + if (!event_info->name) + while (event_info->names[dev_count]) + dev_count++; ip = kzalloc(sizeof(*ip) + - sizeof(ip->state[0]) * event_info->info_count, GFP_KERNEL); + sizeof(ip->state[0]) * event_info->info_count + + sizeof(*ip->input_devs) + + sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL); if (ip == NULL) { err = -ENOMEM; pr_err("gpio_event_probe: Failed to allocate private data\n"); goto err_kp_alloc_failed; } + ip->input_devs = (void*)&ip->state[event_info->info_count]; platform_set_drvdata(pdev, ip); - input_dev = input_allocate_device(); - if (input_dev == NULL) { - err = -ENOMEM; - pr_err("gpio_event_probe: Failed to allocate input device\n"); - goto err_input_dev_alloc_failed; + for (i = 0; i < dev_count; i++) { + struct input_dev *input_dev = input_allocate_device(); + if (input_dev == NULL) { + err = -ENOMEM; + pr_err("gpio_event_probe: " + "Failed to allocate input device\n"); + goto err_input_dev_alloc_failed; + } + input_set_drvdata(input_dev, ip); + input_dev->name = event_info->name ? + event_info->name : event_info->names[i]; + input_dev->event = gpio_input_event; + ip->input_devs->dev[i] = input_dev; } - input_set_drvdata(input_dev, ip); - ip->input_dev = input_dev; + ip->input_devs->count = dev_count; ip->info = event_info; if (event_info->power) { #ifdef CONFIG_HAS_EARLYSUSPEND @@ -150,18 +178,18 @@ static int __init gpio_event_probe(struct platform_device *pdev) ip->info->power(ip->info, 1); } - input_dev->name = ip->info->name; - input_dev->event = gpio_input_event; - err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT); if (err) goto err_call_all_func_failed; - err = input_register_device(input_dev); - if (err) { - pr_err("gpio_event_probe: Unable to register %s input device\n", - input_dev->name); - goto err_input_register_device_failed; + for (i = 0; i < dev_count; i++) { + err = input_register_device(ip->input_devs->dev[i]); + if (err) { + pr_err("gpio_event_probe: Unable to register %s " + "input device\n", ip->input_devs->dev[i]->name); + goto err_input_register_device_failed; + } + registered++; } return 0; @@ -175,8 +203,13 @@ err_call_all_func_failed: #endif ip->info->power(ip->info, 0); } - input_free_device(input_dev); + for (i = 0; i < registered; i++) + input_unregister_device(ip->input_devs->dev[i]); + for (i = dev_count - 1; i >= registered; i--) { + input_free_device(ip->input_devs->dev[i]); err_input_dev_alloc_failed: + ; + } kfree(ip); err_kp_alloc_failed: return err; @@ -185,6 +218,7 @@ err_kp_alloc_failed: static int gpio_event_remove(struct platform_device *pdev) { struct gpio_event *ip = platform_get_drvdata(pdev); + int i; gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); if (ip->info->power) { @@ -193,7 +227,8 @@ static int gpio_event_remove(struct platform_device *pdev) #endif ip->info->power(ip->info, 0); } - input_unregister_device(ip->input_dev); + for (i = 0; i < ip->input_devs->count; i++) + input_unregister_device(ip->input_devs->dev[i]); kfree(ip); return 0; } diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c index 7e307f267a2a..0d5c5bdbe14a 100644 --- a/drivers/input/misc/gpio_input.c +++ b/drivers/input/misc/gpio_input.c @@ -38,7 +38,7 @@ struct gpio_key_state { }; struct gpio_input_state { - struct input_dev *input_dev; + struct gpio_event_input_devs *input_devs; const struct gpio_event_input_info *info; struct hrtimer timer; int use_irq; @@ -126,7 +126,7 @@ static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer) pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) " "changed to %d\n", ds->info->type, key_entry->code, i, key_entry->gpio, pressed); - input_event(ds->input_dev, ds->info->type, + input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, key_entry->code, pressed); } @@ -193,7 +193,7 @@ static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id) "(%d) changed to %d\n", ds->info->type, key_entry->code, keymap_index, key_entry->gpio, pressed); - input_event(ds->input_dev, ds->info->type, + input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, key_entry->code, pressed); } return IRQ_HANDLED; @@ -232,7 +232,7 @@ err_gpio_get_irq_num_failed: return err; } -int gpio_event_input_func(struct input_dev *input_dev, +int gpio_event_input_func(struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, void **data, int func) { int ret; @@ -275,13 +275,22 @@ int gpio_event_input_func(struct input_dev *input_dev, goto err_ds_alloc_failed; } ds->debounce_count = di->keymap_size; - ds->input_dev = input_dev; + ds->input_devs = input_devs; ds->info = di; wake_lock_init(&ds->wake_lock, WAKE_LOCK_SUSPEND, "gpio_input"); spin_lock_init(&ds->irq_lock); for (i = 0; i < di->keymap_size; i++) { - input_set_capability(input_dev, di->type, + int dev = di->keymap[i].dev; + if (dev >= input_devs->count) { + pr_err("gpio_event_input_func: bad device " + "index %d >= %d for key code %d\n", + dev, input_devs->count, + di->keymap[i].code); + ret = -EINVAL; + goto err_bad_keymap; + } + input_set_capability(input_devs->dev[dev], di->type, di->keymap[i].code); ds->key_state[i].ds = ds; ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; @@ -308,9 +317,10 @@ int gpio_event_input_func(struct input_dev *input_dev, spin_lock_irqsave(&ds->irq_lock, irqflags); ds->use_irq = ret == 0; - pr_info("GPIO Input Driver: Start gpio inputs for %s in %s " - "mode\n", - input_dev->name, ret == 0 ? "interrupt" : "polling"); + pr_info("GPIO Input Driver: Start gpio inputs for %s%s in %s " + "mode\n", input_devs->dev[0]->name, + (input_devs->count > 1) ? "..." : "", + ret == 0 ? "interrupt" : "polling"); hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ds->timer.function = gpio_event_input_timer_func; @@ -336,6 +346,7 @@ err_gpio_configure_failed: err_gpio_request_failed: ; } +err_bad_keymap: wake_lock_destroy(&ds->wake_lock); kfree(ds); err_ds_alloc_failed: diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c index 671ebb0ce1c6..6d1c1a7ff67d 100644 --- a/drivers/input/misc/gpio_matrix.c +++ b/drivers/input/misc/gpio_matrix.c @@ -21,7 +21,7 @@ #include <linux/wakelock.h> struct gpio_kp { - struct input_dev *input_dev; + struct gpio_event_input_devs *input_devs; struct gpio_event_matrix_info *keypad_info; struct hrtimer timer; struct wake_lock wake_lock; @@ -37,9 +37,11 @@ static void clear_phantom_key(struct gpio_kp *kp, int out, int in) { struct gpio_event_matrix_info *mi = kp->keypad_info; int key_index = out * mi->ninputs + in; - unsigned short keycode = mi->keymap[key_index];; + unsigned short keyentry = mi->keymap[key_index]; + unsigned short keycode = keyentry & MATRIX_KEY_MASK; + unsigned short dev = keyentry >> MATRIX_CODE_BITS; - if (!test_bit(keycode, kp->input_dev->key)) { + if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) { if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " "cleared\n", keycode, out, in, @@ -104,8 +106,11 @@ static void report_key(struct gpio_kp *kp, int key_index, int out, int in) { struct gpio_event_matrix_info *mi = kp->keypad_info; int pressed = test_bit(key_index, kp->keys_pressed); - unsigned short keycode = mi->keymap[key_index]; - if (pressed != test_bit(keycode, kp->input_dev->key)) { + unsigned short keyentry = mi->keymap[key_index]; + unsigned short keycode = keyentry & MATRIX_KEY_MASK; + unsigned short dev = keyentry >> MATRIX_CODE_BITS; + + if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) { if (keycode == KEY_RESERVED) { if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) pr_info("gpiomatrix: unmapped key, %d-%d " @@ -118,7 +123,7 @@ static void report_key(struct gpio_kp *kp, int key_index, int out, int in) "changed to %d\n", keycode, out, in, mi->output_gpios[out], mi->input_gpios[in], pressed); - input_report_key(kp->input_dev, keycode, pressed); + input_report_key(kp->input_devs->dev[dev], keycode, pressed); } } } @@ -279,7 +284,7 @@ err_gpio_get_irq_num_failed: return err; } -int gpio_event_matrix_func(struct input_dev *input_dev, +int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, void **data, int func) { int i; @@ -311,12 +316,22 @@ int gpio_event_matrix_func(struct input_dev *input_dev, pr_err("gpiomatrix: Failed to allocate private data\n"); goto err_kp_alloc_failed; } - kp->input_dev = input_dev; + kp->input_devs = input_devs; kp->keypad_info = mi; - set_bit(EV_KEY, input_dev->evbit); for (i = 0; i < key_count; i++) { - if (mi->keymap[i] && mi->keymap[i] <= KEY_MAX) - set_bit(mi->keymap[i], input_dev->keybit); + unsigned short keyentry = mi->keymap[i]; + unsigned short keycode = keyentry & MATRIX_KEY_MASK; + unsigned short dev = keyentry >> MATRIX_CODE_BITS; + if (dev >= input_devs->count) { + pr_err("gpiomatrix: bad device index %d >= " + "%d for key code %d\n", + dev, input_devs->count, keycode); + err = -EINVAL; + goto err_bad_keymap; + } + if (keycode && keycode <= KEY_MAX) + input_set_capability(input_devs->dev[dev], + EV_KEY, keycode); } for (i = 0; i < mi->noutputs; i++) { @@ -366,8 +381,9 @@ int gpio_event_matrix_func(struct input_dev *input_dev, err = gpio_keypad_request_irqs(kp); kp->use_irq = err == 0; - pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for %s " - "in %s mode\n", input_dev->name, + pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for " + "%s%s in %s mode\n", input_devs->dev[0]->name, + (input_devs->count > 1) ? "..." : "", kp->use_irq ? "interrupt" : "polling"); if (kp->use_irq) @@ -398,6 +414,7 @@ err_output_gpio_configure_failed: err_request_output_gpio_failed: ; } +err_bad_keymap: kfree(kp); err_kp_alloc_failed: err_invalid_platform_data: diff --git a/drivers/input/misc/gpio_output.c b/drivers/input/misc/gpio_output.c index 6f8453c97bd2..2aac2fad0a17 100644 --- a/drivers/input/misc/gpio_output.c +++ b/drivers/input/misc/gpio_output.c @@ -18,8 +18,9 @@ #include <linux/gpio_event.h> int gpio_event_output_event( - struct input_dev *input_dev, struct gpio_event_info *info, void **data, - unsigned int type, unsigned int code, int value) + struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, + void **data, unsigned int dev, unsigned int type, + unsigned int code, int value) { int i; struct gpio_event_output_info *oi; @@ -29,14 +30,14 @@ int gpio_event_output_event( if (!(oi->flags & GPIOEDF_ACTIVE_HIGH)) value = !value; for (i = 0; i < oi->keymap_size; i++) - if (code == oi->keymap[i].code) + if (dev == oi->keymap[i].dev && code == oi->keymap[i].code) gpio_set_value(oi->keymap[i].gpio, value); return 0; } int gpio_event_output_func( - struct input_dev *input_dev, struct gpio_event_info *info, void **data, - int func) + struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, + void **data, int func) { int ret; int i; @@ -48,9 +49,20 @@ int gpio_event_output_func( if (func == GPIO_EVENT_FUNC_INIT) { int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH); - for (i = 0; i < oi->keymap_size; i++) - input_set_capability(input_dev, oi->type, + + for (i = 0; i < oi->keymap_size; i++) { + int dev = oi->keymap[i].dev; + if (dev >= input_devs->count) { + pr_err("gpio_event_output_func: bad device " + "index %d >= %d for key code %d\n", + dev, input_devs->count, + oi->keymap[i].code); + ret = -EINVAL; + goto err_bad_keymap; + } + input_set_capability(input_devs->dev[dev], oi->type, oi->keymap[i].code); + } for (i = 0; i < oi->keymap_size; i++) { ret = gpio_request(oi->keymap[i].gpio, @@ -79,6 +91,7 @@ err_gpio_direction_output_failed: err_gpio_request_failed: ; } +err_bad_keymap: return ret; } |