diff options
author | Arve Hjønnevåg <arve@android.com> | 2009-07-24 15:19:56 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-06-14 09:08:48 -0700 |
commit | 0da26bfb4ecea69226775572153fd85e2ab3785f (patch) | |
tree | 0b822ed2172da054bda51a2e3f42fd3400a9fea2 /drivers/input/misc/gpio_matrix.c | |
parent | 8f836aa8da5032979071b1b650b2ab240b60b7f7 (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/misc/gpio_matrix.c')
-rw-r--r-- | drivers/input/misc/gpio_matrix.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c index 10b44110166..adb00ab47b6 100644 --- a/drivers/input/misc/gpio_matrix.c +++ b/drivers/input/misc/gpio_matrix.c @@ -22,7 +22,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; @@ -38,9 +38,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, @@ -105,8 +107,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 " @@ -119,7 +124,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); } } } @@ -280,7 +285,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; @@ -312,12 +317,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++) { @@ -367,8 +382,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) @@ -399,6 +415,7 @@ err_output_gpio_configure_failed: err_request_output_gpio_failed: ; } +err_bad_keymap: kfree(kp); err_kp_alloc_failed: err_invalid_platform_data: |