diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2016-02-08 08:26:35 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2016-02-08 08:26:35 +0100 |
commit | 05261801e9cde103b3c4df843472027c007531da (patch) | |
tree | 1c138878a228f93e22ec1c8d729ef6915586b587 /drivers | |
parent | 6435fb09d8af3aeae7c6f8428f5e7ade15aca6f5 (diff) | |
parent | 253fb33bb81b0e88bcfa0184ef29206598fbb5d4 (diff) | |
download | barebox-05261801e9cde103b3c4df843472027c007531da.tar.gz barebox-05261801e9cde103b3c4df843472027c007531da.tar.xz |
Merge branch 'for-next/input'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/Kconfig | 10 | ||||
-rw-r--r-- | drivers/input/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/gpio_keys.c | 71 | ||||
-rw-r--r-- | drivers/input/imx_keypad.c | 92 | ||||
-rw-r--r-- | drivers/input/input.c | 202 | ||||
-rw-r--r-- | drivers/input/keymap.c | 173 | ||||
-rw-r--r-- | drivers/input/matrix-keymap.c | 89 | ||||
-rw-r--r-- | drivers/input/usb_kbd.c | 296 |
8 files changed, 512 insertions, 423 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 336b9f5814..1f89ae3892 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -5,10 +5,17 @@ menu "Input device support" depends on !CONSOLE_NONE +config INPUT + bool + +config INPUT_MATRIXKMAP + bool + config KEYBOARD_GPIO bool "GPIO Buttons" depends on GENERIC_GPIO select POLLER + select INPUT help This driver implements support for buttons connected to GPIO pins of various CPUs (and some other chips). @@ -21,7 +28,9 @@ config KEYBOARD_GPIO config KEYBOARD_IMX_KEYPAD bool "IMX Keypad" depends on ARCH_IMX + select INPUT_MATRIXKMAP select POLLER + select INPUT help This driver implements support for buttons connected to the IMX keypad matrix. @@ -51,6 +60,7 @@ config KEYBOARD_USB depends on USB_HOST depends on CONSOLE_FULL select POLLER + select INPUT help This driver implements support for usb keyboard. diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 40b898cd71..7d2c1945f7 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -1,3 +1,5 @@ +obj-$(CONFIG_INPUT) += input.o +obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o obj-$(CONFIG_KEYBOARD_USB) += usb_kbd.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_TWL6030) += twl6030_pwrbtn.o diff --git a/drivers/input/gpio_keys.c b/drivers/input/gpio_keys.c index 5b03fd76cb..38c0f11535 100644 --- a/drivers/input/gpio_keys.c +++ b/drivers/input/gpio_keys.c @@ -12,7 +12,7 @@ #include <poller.h> #include <gpio.h> #include <of_gpio.h> -#include <input/keyboard.h> +#include <input/input.h> struct gpio_key { int code; @@ -30,14 +30,9 @@ struct gpio_keys { struct gpio_key *buttons; int nbuttons; - /* optional */ - int fifo_size; - - struct kfifo *recv_fifo; struct poller_struct poller; - struct console_device cdev; - - int use_keycodes; + struct input_device input; + struct device_d *dev; }; static inline struct gpio_keys * @@ -46,12 +41,6 @@ poller_to_gk_pdata(struct poller_struct *poller) return container_of(poller, struct gpio_keys, poller); } -static inline struct gpio_keys * -cdev_to_gk_pdata(struct console_device *cdev) -{ - return container_of(cdev, struct gpio_keys, cdev); -} - static void gpio_key_poller(struct poller_struct *poller) { struct gpio_keys *gk = poller_to_gk_pdata(poller); @@ -67,36 +56,17 @@ static void gpio_key_poller(struct poller_struct *poller) continue; if (val != gb->previous_state) { + int pressed = val != gb->active_low; + gb->debounce_start = get_time_ns(); - if (val != gb->active_low) { - kfifo_put(gk->recv_fifo, (u_char*)&gb->code, sizeof(int)); - debug("pressed gpio(%d) as %d\n", gb->gpio, gb->code); - } + input_report_key_event(&gk->input, gb->code, pressed); + dev_dbg(gk->dev, "%s gpio(%d) as %d\n", + pressed ? "pressed" : "released", gb->gpio, gb->code); gb->previous_state = val; } } } -static int gpio_keys_tstc(struct console_device *cdev) -{ - struct gpio_keys *gk = cdev_to_gk_pdata(cdev); - - return (kfifo_len(gk->recv_fifo) == 0) ? 0 : 1; -} - -static int gpio_keys_getc(struct console_device *cdev) -{ - int code = 0; - struct gpio_keys *gk = cdev_to_gk_pdata(cdev); - - kfifo_get(gk->recv_fifo, (u_char*)&code, sizeof(int)); - - if (IS_ENABLED(CONFIG_OFDEVICE) && gk->use_keycodes) - return keycode_bb_keys[code]; - else - return code; -} - static int gpio_keys_probe_pdata(struct gpio_keys *gk, struct device_d *dev) { struct gpio_keys_platform_data *pdata; @@ -110,9 +80,6 @@ static int gpio_keys_probe_pdata(struct gpio_keys *gk, struct device_d *dev) return -ENODEV; } - if (pdata->fifo_size) - gk->fifo_size = pdata->fifo_size; - gk->buttons = xzalloc(pdata->nbuttons * sizeof(*gk->buttons)); gk->nbuttons = pdata->nbuttons; @@ -162,19 +129,17 @@ static int gpio_keys_probe_dt(struct gpio_keys *gk, struct device_d *dev) i++; } - gk->use_keycodes = 1; - return 0; } static int __init gpio_keys_probe(struct device_d *dev) { int ret, i, gpio; - struct console_device *cdev; struct gpio_keys *gk; gk = xzalloc(sizeof(*gk)); - gk->fifo_size = 50; + + gk->dev = dev; if (dev->device_node) ret = gpio_keys_probe_dt(gk, dev); @@ -184,8 +149,6 @@ static int __init gpio_keys_probe(struct device_d *dev) if (ret) return ret; - gk->recv_fifo = kfifo_alloc(gk->fifo_size); - for (i = 0; i < gk->nbuttons; i++) { gpio = gk->buttons[i].gpio; ret = gpio_request(gpio, "gpio_keys"); @@ -199,15 +162,15 @@ static int __init gpio_keys_probe(struct device_d *dev) gk->poller.func = gpio_key_poller; - cdev = &gk->cdev; - dev->type_data = cdev; - cdev->dev = dev; - cdev->tstc = gpio_keys_tstc; - cdev->getc = gpio_keys_getc; + ret = input_device_register(&gk->input); + if (ret) + return ret; - console_register(&gk->cdev); + ret = poller_register(&gk->poller); + if (ret) + return ret; - return poller_register(&gk->poller); + return 0; } static struct of_device_id key_gpio_of_ids[] = { diff --git a/drivers/input/imx_keypad.c b/drivers/input/imx_keypad.c index 331eadd75f..000e17626b 100644 --- a/drivers/input/imx_keypad.c +++ b/drivers/input/imx_keypad.c @@ -46,8 +46,9 @@ #include <poller.h> #include <kfifo.h> #include <malloc.h> -#include <matrix_keypad.h> +#include <input/matrix_keypad.h> #include <linux/err.h> +#include <input/input.h> /* * Keypad Controller registers (halfword) @@ -73,15 +74,11 @@ #define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) struct imx_keypad { + struct input_device input; struct clk *clk; struct device_d *dev; - struct console_device cdev; void __iomem *mmio_base; - /* optional */ - int fifo_size; - - struct kfifo *recv_fifo; struct poller_struct poller; /* @@ -112,28 +109,6 @@ poller_to_imx_kp_pdata(struct poller_struct *poller) return container_of(poller, struct imx_keypad, poller); } -static inline struct imx_keypad * -cdev_to_imx_kp_pdata(struct console_device *cdev) -{ - return container_of(cdev, struct imx_keypad, cdev); -} - -static int imx_keypad_tstc(struct console_device *cdev) -{ - struct imx_keypad *kp = cdev_to_imx_kp_pdata(cdev); - - return (kfifo_len(kp->recv_fifo) == 0) ? 0 : 1; -} - -static int imx_keypad_getc(struct console_device *cdev) -{ - int code = 0; - struct imx_keypad *kp = cdev_to_imx_kp_pdata(cdev); - - kfifo_get(kp->recv_fifo, (u_char*)&code, sizeof(int)); - return code; -} - /* Scan the matrix and return the new state in *matrix_volatile_state. */ static void imx_keypad_scan_matrix(struct imx_keypad *keypad, unsigned short *matrix_volatile_state) @@ -226,9 +201,10 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad, code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT); - kfifo_put(keypad->recv_fifo, (u_char*)(&keypad->keycodes[code]), sizeof(int)); + input_report_key_event(&keypad->input, keypad->keycodes[code], + matrix_volatile_state[col] & (1 << row)); - pr_debug("Event code: %d, val: %d", + dev_dbg(keypad->dev, "Event code: %d, val: %d", keypad->keycodes[code], matrix_volatile_state[col] & (1 << row)); } @@ -390,13 +366,7 @@ static int __init imx_keypad_probe(struct device_d *dev) { struct imx_keypad *keypad; const struct matrix_keymap_data *keymap_data = dev->platform_data; - struct console_device *cdev; - int i; - - if (!keymap_data) { - pr_err("no keymap defined\n"); - return -ENODEV; - } + int i, ret, row, col; keypad = xzalloc(sizeof(struct imx_keypad)); @@ -405,28 +375,31 @@ static int __init imx_keypad_probe(struct device_d *dev) if (IS_ERR(keypad->mmio_base)) return PTR_ERR(keypad->mmio_base); - if(!keypad->fifo_size) - keypad->fifo_size = 50; - - keypad->recv_fifo = kfifo_alloc(keypad->fifo_size); + ret = matrix_keypad_build_keymap(dev, keymap_data, MATRIX_ROW_SHIFT, + keypad->keycodes); + if (ret) + return ret; /* Search for rows and cols enabled */ - for (i = 0; i < keymap_data->keymap_size; i++) { - keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]); - keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]); + for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) { + for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) { + i = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT); + if (keypad->keycodes[i] != KEY_RESERVED) { + keypad->rows_en_mask |= 1 << row; + keypad->cols_en_mask |= 1 << col; + } + } } if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) || keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) { - pr_err("invalid key data (too many rows or colums)\n"); + dev_err(dev, "invalid key data (too many rows or colums)\n"); free(keypad); return -EINVAL; } - pr_debug("enabled rows mask: %x\n", keypad->rows_en_mask); - pr_debug("enabled cols mask: %x\n", keypad->cols_en_mask); - matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT, - keypad->keycodes); + dev_dbg(dev, "enabled rows mask: %x\n", keypad->rows_en_mask); + dev_dbg(dev, "enabled cols mask: %x\n", keypad->cols_en_mask); imx_keypad_config(keypad); @@ -435,20 +408,25 @@ static int __init imx_keypad_probe(struct device_d *dev) keypad->poller.func = imx_keypad_check_for_events; - cdev = &keypad->cdev; - dev->type_data = cdev; - cdev->dev = dev; - cdev->tstc = imx_keypad_tstc; - cdev->getc = imx_keypad_getc; - cdev->f_active = CONSOLE_STDIN; + ret = poller_register(&keypad->poller); + if (ret) + return ret; - console_register(&keypad->cdev); + ret = input_device_register(&keypad->input); + if (ret) + return ret; - return poller_register(&keypad->poller); + return 0; } +static __maybe_unused struct of_device_id imx_keypad_dt_ids[] = { + { .compatible = "fsl,imx21-kpp", }, + { } +}; + static struct driver_d imx_keypad_driver = { .name = "imx-kpp", .probe = imx_keypad_probe, + .of_compatible = DRV_OF_COMPAT(imx_keypad_dt_ids), }; device_platform_driver(imx_keypad_driver); diff --git a/drivers/input/input.c b/drivers/input/input.c new file mode 100644 index 0000000000..ad7400fe4a --- /dev/null +++ b/drivers/input/input.c @@ -0,0 +1,202 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <common.h> +#include <init.h> +#include <kfifo.h> +#include <poller.h> +#include <clock.h> +#include <input/input.h> +#include <linux/bitmap.h> +#include <input/keyboard.h> +#include <dt-bindings/input/linux-event-codes.h> + +static LIST_HEAD(input_consumers); + +int input_register_notfier(struct input_notifier *in) +{ + list_add_tail(&in->list, &input_consumers); + + return 0; +} + +void input_unregister_notfier(struct input_notifier *in) +{ + list_del(&in->list); +} + +void input_report_key_event(struct input_device *idev, unsigned int code, int value) +{ + struct input_event event; + struct input_notifier *in; + + if (code > KEY_MAX) + return; + + if (value) + set_bit(code, &idev->keys); + else + clear_bit(code, &idev->keys); + + event.code = code; + event.value = value; + + list_for_each_entry(in, &input_consumers, list) + in->notify(in, &event); +} + +static LIST_HEAD(input_devices); + +int input_device_register(struct input_device *idev) +{ + list_add_tail(&idev->list, &input_devices); + + return 0; +} + +void input_device_unregister(struct input_device *idev) +{ + list_del(&idev->list); +} + +void input_key_get_status(unsigned long *keys, int bits) +{ + struct input_device *idev; + + bitmap_zero(keys, bits); + + if (bits > KEY_MAX) + bits = KEY_MAX; + + list_for_each_entry(idev, &input_devices, list) + bitmap_or(keys, keys, idev->keys, bits); +} + +struct input_console { + struct console_device console; + struct input_notifier notifier; + struct kfifo *fifo; + struct poller_async poller; + uint8_t current_key; + uint8_t modstate[6]; +}; + +static int input_console_tstc(struct console_device *cdev) +{ + struct input_console *ic = container_of(cdev, struct input_console, console); + + return kfifo_len(ic->fifo) ? 1 : 0; +} + +static int input_console_getc(struct console_device *cdev) +{ + struct input_console *ic = container_of(cdev, struct input_console, console); + uint8_t c; + + kfifo_getc(ic->fifo, &c); + + return c; +} + +static void input_console_repeat(void *ctx) +{ + struct input_console *ic = ctx; + + if (ic->current_key) { + kfifo_putc(ic->fifo, ic->current_key); + poller_call_async(&ic->poller, 40 * MSECOND, + input_console_repeat, ic); + } +} + +struct keycode { + unsigned char key; + unsigned char ascii; +}; + +static void input_console_notify(struct input_notifier *in, + struct input_event *ev) +{ + struct input_console *ic = container_of(in, struct input_console, notifier); + uint8_t modstate = 0; + unsigned char ascii; + + switch (ev->code) { + case KEY_LEFTSHIFT: + ic->modstate[0] = ev->value; + return; + case KEY_RIGHTSHIFT: + ic->modstate[1] = ev->value; + return; + case KEY_LEFTCTRL: + ic->modstate[2] = ev->value; + return; + case KEY_RIGHTCTRL: + ic->modstate[3] = ev->value; + return; + case KEY_LEFTALT: + ic->modstate[4] = ev->value; + return; + case KEY_RIGHTALT: + ic->modstate[5] = ev->value; + return; + case KEY_LEFTMETA: + case KEY_RIGHTMETA: + return; + default: + break; + } + + if (ic->modstate[0] || ic->modstate[1]) + modstate |= 1 << 0; + + if (ic->modstate[2] || ic->modstate[3]) + modstate |= 1 << 1; + + if (ic->modstate[4] || ic->modstate[5]) + modstate |= 1 << 2; + + if (modstate & (1 << 0)) + ascii = keycode_bb_shift_keys[ev->code]; + else + ascii = keycode_bb_keys[ev->code]; + + pr_debug("map %02x KEY: 0x%04x code: %d\n", modstate, ascii, ev->code); + + if (ev->value) { + kfifo_putc(ic->fifo, ascii); + ic->current_key = ascii; + poller_call_async(&ic->poller, 400 * MSECOND, + input_console_repeat, ic); + } else { + ic->current_key = 0; + poller_async_cancel(&ic->poller); + } +} + +static struct input_console input_console; + +static int input_init(void) +{ + struct input_console *ic = &input_console; + + ic->console.tstc = input_console_tstc; + ic->console.getc = input_console_getc; + ic->console.f_active = CONSOLE_STDIN; + + ic->fifo = kfifo_alloc(32); + ic->notifier.notify = input_console_notify; + input_register_notfier(&ic->notifier); + poller_async_register(&ic->poller); + + return console_register(&ic->console); +} +console_initcall(input_init); diff --git a/drivers/input/keymap.c b/drivers/input/keymap.c index b9fd6a2cfb..a07b3a8f9d 100644 --- a/drivers/input/keymap.c +++ b/drivers/input/keymap.c @@ -31,10 +31,9 @@ uint8_t keycode_bb_keys[NR_KEYS] = { [KEY_I] = 'i', [KEY_O] = 'o', [KEY_P] = 'p', - [KEY_LEFTBRACE] = '(', - [KEY_RIGHTBRACE] = ')', + [KEY_LEFTBRACE] = '[', + [KEY_RIGHTBRACE] = ']', [KEY_ENTER] = '\n', - [KEY_LEFTCTRL] = 0xff, [KEY_A] = 'a', [KEY_S] = 's', [KEY_D] = 'd', @@ -45,10 +44,9 @@ uint8_t keycode_bb_keys[NR_KEYS] = { [KEY_K] = 'k', [KEY_L] = 'l', [KEY_SEMICOLON] = ';', - [KEY_APOSTROPHE] = 0xff, + [KEY_APOSTROPHE] = '`', [KEY_GRAVE] = '^', - [KEY_LEFTSHIFT] = 0xff, - [KEY_BACKSLASH] = 0xff, + [KEY_BACKSLASH] = '\\', [KEY_Z] = 'z', [KEY_X] = 'x', [KEY_C] = 'c', @@ -59,54 +57,104 @@ uint8_t keycode_bb_keys[NR_KEYS] = { [KEY_COMMA] = ',', [KEY_DOT] = '.', [KEY_SLASH] = '/', - [KEY_RIGHTSHIFT] = 0xff, - [KEY_KPASTERISK] = 0xff, - [KEY_LEFTALT] = 0xff, [KEY_SPACE] = ' ', - [KEY_CAPSLOCK] = 0xff, - [KEY_F1] = 0xff, - [KEY_F2] = 0xff, - [KEY_F3] = 0xff, - [KEY_F4] = 0xff, - [KEY_F5] = 0xff, - [KEY_F6] = 0xff, - [KEY_F7] = 0xff, - [KEY_F8] = 0xff, - [KEY_F9] = 0xff, - [KEY_F10] = 0xff, - [KEY_NUMLOCK] = 0xff, - [KEY_SCROLLLOCK] = 0xff, - [KEY_KP7] = 0xff, - [KEY_KP8] = 0xff, - [KEY_KP9] = 0xff, - [KEY_KPMINUS] = 0xff, - [KEY_KP4] = 0xff, - [KEY_KP5] = 0xff, - [KEY_KP6] = 0xff, - [KEY_KPPLUS] = 0xff, - [KEY_KP1] = 0xff, - [KEY_KP2] = 0xff, - [KEY_KP3] = 0xff, - [KEY_KP0] = 0xff, - [KEY_KPDOT] = 0xff, - [KEY_ZENKAKUHANKAKU] = 0xff, - [KEY_102ND] = 0xff, - [KEY_F11] = 0xff, - [KEY_F12] = 0xff, - [KEY_RO] = 0xff, - [KEY_KATAKANA] = 0xff, - [KEY_HIRAGANA] = 0xff, - [KEY_HENKAN] = 0xff, - [KEY_KATAKANAHIRAGANA] =0xff, - [KEY_MUHENKAN] = 0xff, - [KEY_KPJPCOMMA] = 0xff, - [KEY_KPENTER] = 0xff, - [KEY_RIGHTCTRL] = 0xff, - [KEY_KPSLASH] = 0xff, - [KEY_SYSRQ] = 0xff, - [KEY_RIGHTALT] = 0xff, - [KEY_LINEFEED] = 0xff, - [KEY_HOME] = 0xff, + [KEY_KP7] = '7', + [KEY_KP8] = '8', + [KEY_KP9] = '9', + [KEY_KPMINUS] = '-', + [KEY_KP4] = '4', + [KEY_KP5] = '5', + [KEY_KP6] = '6', + [KEY_KPPLUS] = '+', + [KEY_KP1] = '1', + [KEY_KP2] = '2', + [KEY_KP3] = '3', + [KEY_KP0] = '0', + [KEY_KPDOT] = '.', + [KEY_KPENTER] = '\n', + [KEY_HOME] = BB_KEY_HOME, + [KEY_UP] = BB_KEY_UP, + [KEY_PAGEUP] = BB_KEY_PAGEUP, + [KEY_LEFT] = BB_KEY_LEFT, + [KEY_RIGHT] = BB_KEY_RIGHT, + [KEY_END] = BB_KEY_END, + [KEY_DOWN] = BB_KEY_DOWN, + [KEY_PAGEDOWN] = BB_KEY_PAGEDOWN, + [KEY_INSERT] = BB_KEY_INSERT, + [KEY_DELETE] = BB_KEY_DEL, + [KEY_KPEQUAL] = '=', + [KEY_KPCOMMA] = ',', +}; + +uint8_t keycode_bb_shift_keys[NR_KEYS] = { + [KEY_RESERVED] = 0xff, + [KEY_ESC] = 0x1b, + [KEY_1] = '!', + [KEY_2] = '@', + [KEY_3] = '#', + [KEY_4] = '$', + [KEY_5] = '%', + [KEY_6] = '^', + [KEY_7] = '&', + [KEY_8] = '*', + [KEY_9] = '(', + [KEY_0] = ')', + [KEY_MINUS] = '_', + [KEY_EQUAL] = '+', + [KEY_BACKSPACE] = 0xff, + [KEY_TAB] = '\t', + [KEY_Q] = 'Q', + [KEY_W] = 'W', + [KEY_E] = 'E', + [KEY_R] = 'R', + [KEY_T] = 'T', + [KEY_Y] = 'Y', + [KEY_U] = 'U', + [KEY_I] = 'I', + [KEY_O] = 'O', + [KEY_P] = 'P', + [KEY_LEFTBRACE] = '{', + [KEY_RIGHTBRACE] = '}', + [KEY_ENTER] = '\n', + [KEY_A] = 'A', + [KEY_S] = 'S', + [KEY_D] = 'D', + [KEY_F] = 'F', + [KEY_G] = 'G', + [KEY_H] = 'H', + [KEY_J] = 'J', + [KEY_K] = 'K', + [KEY_L] = 'L', + [KEY_SEMICOLON] = ':', + [KEY_APOSTROPHE] = '~', + [KEY_GRAVE] = '^', + [KEY_BACKSLASH] = '|', + [KEY_Z] = 'Z', + [KEY_X] = 'X', + [KEY_C] = 'C', + [KEY_V] = 'V', + [KEY_B] = 'B', + [KEY_N] = 'N', + [KEY_M] = 'M', + [KEY_COMMA] = '<', + [KEY_DOT] = '>', + [KEY_SLASH] = '?', + [KEY_SPACE] = ' ', + [KEY_KP7] = '7', + [KEY_KP8] = '8', + [KEY_KP9] = '9', + [KEY_KP4] = '4', + [KEY_KP5] = '5', + [KEY_KP6] = '6', + [KEY_KPPLUS] = '+', + [KEY_KP1] = '1', + [KEY_KP2] = '2', + [KEY_KP3] = '3', + [KEY_KP0] = '4', + [KEY_KPDOT] = '.', + [KEY_KPENTER] = '\n', + [KEY_KPSLASH] = '/', + [KEY_HOME] = BB_KEY_HOME, [KEY_UP] = BB_KEY_UP, [KEY_PAGEUP] = BB_KEY_PAGEUP, [KEY_LEFT] = BB_KEY_LEFT, @@ -116,21 +164,6 @@ uint8_t keycode_bb_keys[NR_KEYS] = { [KEY_PAGEDOWN] = BB_KEY_PAGEDOWN, [KEY_INSERT] = BB_KEY_INSERT, [KEY_DELETE] = BB_KEY_DEL7, - [KEY_MACRO] = 0xff, - [KEY_MUTE] = 0xff, - [KEY_VOLUMEDOWN] = 0xff, - [KEY_VOLUMEUP] = 0xff, - [KEY_POWER] = 0xff, - [KEY_KPEQUAL] = 0xff, - [KEY_KPPLUSMINUS] = 0xff, - [KEY_PAUSE] = 0xff, - [KEY_SCALE] = 0xff, - [KEY_KPCOMMA] = 0xff, - [KEY_HANGEUL] = 0xff, - [KEY_HANGUEL] = KEY_HANGEUL, - [KEY_HANJA] = 0xff, - [KEY_YEN] = 0xff, - [KEY_LEFTMETA] = 0xff, - [KEY_RIGHTMETA] = 0xff, - [KEY_COMPOSE] = 0xff, + [KEY_KPEQUAL] = '=', + [KEY_KPCOMMA] = ',', }; diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c new file mode 100644 index 0000000000..288b6a4b53 --- /dev/null +++ b/drivers/input/matrix-keymap.c @@ -0,0 +1,89 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <common.h> +#include <input/matrix_keypad.h> + +static int matrix_keypad_parse_of_keymap(struct device_d *dev, + unsigned int row_shift, + unsigned short *keymap) +{ + unsigned int proplen, i, size; + const __be32 *prop; + struct device_node *np = dev->device_node; + const char *propname = "linux,keymap"; + + prop = of_get_property(np, propname, &proplen); + if (!prop) { + dev_err(dev, "OF: %s property not defined in %s\n", + propname, np->full_name); + return -ENOENT; + } + + if (proplen % sizeof(u32)) { + dev_err(dev, "OF: Malformed keycode property %s in %s\n", + propname, np->full_name); + return -EINVAL; + } + + size = proplen / sizeof(u32); + + for (i = 0; i < size; i++) { + unsigned int key = be32_to_cpup(prop + i); + + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short code = KEY_VAL(key); + + if (row >= MATRIX_MAX_ROWS || col >= MATRIX_MAX_COLS) { + dev_err(dev, "rows/cols out of range\n"); + continue; + } + + keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code; + } + + return 0; +} +/** + * matrix_keypad_build_keymap - convert platform keymap into matrix keymap + * @keymap_data: keymap supplied by the platform code + * @row_shift: number of bits to shift row value by to advance to the next + * line in the keymap + * @keymap: expanded version of keymap that is suitable for use by + * matrix keyboad driver + * This function converts platform keymap (encoded with KEY() macro) into + * an array of keycodes that is suitable for using in a standard matrix + * keyboard driver that uses row and col as indices. + */ +int matrix_keypad_build_keymap(struct device_d *dev, const struct matrix_keymap_data *keymap_data, + unsigned int row_shift, + unsigned short *keymap) +{ + int i; + + if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node) + return matrix_keypad_parse_of_keymap(dev, row_shift, keymap); + + if (!keymap_data) + return -EINVAL; + + for (i = 0; i < keymap_data->keymap_size; i++) { + unsigned int key = keymap_data->keymap[i]; + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short code = KEY_VAL(key); + + keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code; + } + + return 0; +} diff --git a/drivers/input/usb_kbd.c b/drivers/input/usb_kbd.c index 655d0c7b25..74bc11f3bb 100644 --- a/drivers/input/usb_kbd.c +++ b/drivers/input/usb_kbd.c @@ -23,56 +23,7 @@ #include <usb/usb.h> #include <string.h> #include <dma.h> -#include <kfifo.h> - -#define USB_KBD_FIFO_SIZE 50 - -#define REPEAT_RATE 40 /* 40msec -> 25cps */ -#define REPEAT_DELAY 10 /* 10 x REPEAT_RATE = 400msec */ - -#define NUM_LOCK 0x53 -#define CAPS_LOCK 0x39 -#define SCROLL_LOCK 0x47 - -/* Modifier bits */ -#define LEFT_CNTR (1 << 0) -#define LEFT_SHIFT (1 << 1) -#define LEFT_ALT (1 << 2) -#define LEFT_GUI (1 << 3) -#define RIGHT_CNTR (1 << 4) -#define RIGHT_SHIFT (1 << 5) -#define RIGHT_ALT (1 << 6) -#define RIGHT_GUI (1 << 7) - -/* Size of the keyboard buffer */ -#define USB_KBD_BUFFER_LEN 0x20 - -/* Keyboard maps */ -static const unsigned char usb_kbd_numkey[] = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', - '\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']', - '\\', '#', ';', '\'', '`', ',', '.', '/' -}; -static const unsigned char usb_kbd_numkey_shifted[] = { - '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', - '\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}', - '|', '~', ':', '"', '~', '<', '>', '?' -}; - -static const unsigned char usb_kbd_num_keypad[] = { - '/', '*', '-', '+', '\r', - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', - '.', 0, 0, 0, '=' -}; - -/* - * map arrow keys to ^F/^B ^N/^P, can't really use the proper - * ANSI sequence for arrow keys because the queuing code breaks - * when a single keypress expands to 3 queue elements - */ -static const unsigned char usb_kbd_arrow[] = { - 0x6, 0x2, 0xe, 0x10 -}; +#include <input/input.h> /* * NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this @@ -96,21 +47,18 @@ struct usb_kbd_pdata; struct usb_kbd_pdata { uint64_t last_report; - uint64_t last_poll; uint8_t *new; uint8_t old[USB_KBD_BOOT_REPORT_SIZE]; - uint32_t repeat_delay; uint8_t flags; struct poller_struct poller; struct usb_device *usbdev; - struct console_device cdev; - struct kfifo *recv_fifo; int lock; unsigned long intpipe; int intpktsize; int intinterval; struct usb_endpoint_descriptor *ep; int (*do_poll)(struct usb_kbd_pdata *); + struct input_device input; }; static int usb_kbd_int_poll(struct usb_kbd_pdata *data) @@ -127,162 +75,36 @@ static int usb_kbd_cnt_poll(struct usb_kbd_pdata *data) 1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE); } -#define CAPITAL_MASK 0x20 -/* Translate the scancode in ASCII */ -static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode, - unsigned char modifier, int pressed) -{ - int keycode = 0; - - /* Key released */ - if (pressed == 0) { - data->repeat_delay = 0; - return 0; - } - - if (pressed == 2) { - data->repeat_delay++; - if (data->repeat_delay < REPEAT_DELAY) - return 0; - - data->repeat_delay = REPEAT_DELAY; - } - - /* Alphanumeric values */ - if ((scancode > 3) && (scancode <= 0x1d)) { - keycode = scancode - 4 + 'a'; - - if (data->flags & USB_KBD_CAPSLOCK) - keycode &= ~CAPITAL_MASK; - - if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) { - /* Handle CAPSLock + Shift pressed simultaneously */ - if (keycode & CAPITAL_MASK) - keycode &= ~CAPITAL_MASK; - else - keycode |= CAPITAL_MASK; - } - } - - if ((scancode > 0x1d) && (scancode < 0x3a)) { - /* Shift pressed */ - if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) - keycode = usb_kbd_numkey_shifted[scancode - 0x1e]; - else - keycode = usb_kbd_numkey[scancode - 0x1e]; - } - - /* Arrow keys */ - if ((scancode >= 0x4f) && (scancode <= 0x52)) - keycode = usb_kbd_arrow[scancode - 0x4f]; - - /* Numeric keypad */ - if ((scancode >= 0x54) && (scancode <= 0x67)) - keycode = usb_kbd_num_keypad[scancode - 0x54]; - - if (data->flags & USB_KBD_CTRL) - keycode = scancode - 0x3; - - if (pressed == 1) { - if (scancode == NUM_LOCK) { - data->flags ^= USB_KBD_NUMLOCK; - return 1; - } - - if (scancode == CAPS_LOCK) { - data->flags ^= USB_KBD_CAPSLOCK; - return 1; - } - if (scancode == SCROLL_LOCK) { - data->flags ^= USB_KBD_SCROLLLOCK; - return 1; - } - } - - /* Report keycode if any */ - if (keycode) { - pr_debug("%s: key pressed: '%c'\n", __FUNCTION__, keycode); - kfifo_put(data->recv_fifo, (u_char*)&keycode, sizeof(keycode)); - } - - return 0; -} - -static uint32_t usb_kbd_service_key(struct usb_kbd_pdata *data, int i, int up) -{ - uint32_t res = 0; - uint8_t *new; - uint8_t *old; - - if (up) { - new = data->old; - old = data->new; - } else { - new = data->new; - old = data->old; - } - - if ((old[i] > 3) && - (memscan(new + 2, old[i], USB_KBD_BOOT_REPORT_SIZE - 2) == - new + USB_KBD_BOOT_REPORT_SIZE)) { - res |= usb_kbd_translate(data, old[i], data->new[0], up); - } - - return res; -} - -static void usb_kbd_setled(struct usb_kbd_pdata *data) -{ - struct usb_device *usbdev = data->usbdev; - struct usb_interface *iface = &usbdev->config.interface[0]; - uint8_t leds = (uint8_t)(data->flags & USB_KBD_LEDMASK); - - usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), - USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0x200, iface->desc.bInterfaceNumber, &leds, 1, USB_CNTL_TIMEOUT); -} - - -static int usb_kbd_process(struct usb_kbd_pdata *data) -{ - int i, res = 0; - - /* No combo key pressed */ - if (data->new[0] == 0x00) - data->flags &= ~USB_KBD_CTRL; - /* Left or Right Ctrl pressed */ - else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR)) - data->flags |= USB_KBD_CTRL; - - for (i = 2; i < USB_KBD_BOOT_REPORT_SIZE; i++) { - res |= usb_kbd_service_key(data, i, 0); - res |= usb_kbd_service_key(data, i, 1); - } - - /* Key is still pressed */ - if ((data->new[2] > 3) && (data->old[2] == data->new[2])) - res |= usb_kbd_translate(data, data->new[2], data->new[0], 2); - - if (res == 1) - usb_kbd_setled(data); - - return 1; -} +static const unsigned char usb_kbd_keycode[256] = { + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, + 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, + 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, + 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, + 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, + 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, + 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, + 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, + 150,158,159,128,136,177,178,176,142,152,173,140 +}; static void usb_kbd_poll(struct poller_struct *poller) { struct usb_kbd_pdata *data = container_of(poller, struct usb_kbd_pdata, poller); struct usb_device *usbdev = data->usbdev; - int diff, tout, ret; + int ret, i; if (data->lock) return; - data->lock = 1; - if (!is_timeout_non_interruptible(data->last_poll, REPEAT_RATE * MSECOND / 2)) - goto exit; - data->last_poll = get_time_ns(); + data->lock = 1; ret = data->do_poll(data); if (ret == -EAGAIN) @@ -293,40 +115,40 @@ static void usb_kbd_poll(struct poller_struct *poller) "usb_submit_int_msg() failed. Keyboard disconnect?\n"); return; } - diff = memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE); - tout = get_time_ns() > data->last_report + REPEAT_RATE * MSECOND; - if (diff || tout) { - data->last_report = get_time_ns(); - if (diff) { - pr_debug("%s: old report: %016llx\n", - __func__, - *((volatile uint64_t *)data->old)); - pr_debug("%s: new report: %016llx\n\n", - __func__, - *((volatile uint64_t *)data->new)); - } - usb_kbd_process(data); - memcpy(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE); - } -exit: - data->lock = 0; -} + if (!memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) + goto exit; -static int usb_kbd_getc(struct console_device *cdev) -{ - int code = 0; - struct usb_kbd_pdata *data = container_of(cdev, struct usb_kbd_pdata, cdev); + pr_debug("%s: new report: %016llx\n", __func__, *((volatile uint64_t *)data->new)); - kfifo_get(data->recv_fifo, (u_char*)&code, sizeof(int)); - return code; -} + for (i = 0; i < 8; i++) + input_report_key_event(&data->input, usb_kbd_keycode[i + 224], (data->new[0] >> i) & 1); -static int usb_kbd_tstc(struct console_device *cdev) -{ - struct usb_kbd_pdata *data = container_of(cdev, struct usb_kbd_pdata, cdev); + for (i = 2; i < 8; i++) { + + if (data->old[i] > 3 && memscan(data->new + 2, data->old[i], 6) == data->new + 8) { + if (usb_kbd_keycode[data->old[i]]) + input_report_key_event(&data->input, usb_kbd_keycode[data->old[i]], 0); + else + dev_err(&usbdev->dev, + "Unknown key (scancode %#x) released.\n", + data->old[i]); + } + + if (data->new[i] > 3 && memscan(data->old + 2, data->new[i], 6) == data->old + 8) { + if (usb_kbd_keycode[data->new[i]]) + input_report_key_event(&data->input, usb_kbd_keycode[data->new[i]], 1); + else + dev_err(&usbdev->dev, + "Unknown key (scancode %#x) pressed.\n", + data->new[i]); + } + } - return (kfifo_len(data->recv_fifo) == 0) ? 0 : 1; + memcpy(data->old, data->new, 8); + +exit: + data->lock = 0; } static int usb_kbd_probe(struct usb_device *usbdev, @@ -335,7 +157,6 @@ static int usb_kbd_probe(struct usb_device *usbdev, int ret; struct usb_interface *iface = &usbdev->config.interface[0]; struct usb_kbd_pdata *data; - struct console_device *cdev; dev_info(&usbdev->dev, "USB keyboard found\n"); dev_dbg(&usbdev->dev, "Debug enabled\n"); @@ -349,7 +170,6 @@ static int usb_kbd_probe(struct usb_device *usbdev, data = xzalloc(sizeof(struct usb_kbd_pdata)); usbdev->drv_data = data; - data->recv_fifo = kfifo_alloc(USB_KBD_FIFO_SIZE); data->new = dma_alloc(USB_KBD_BOOT_REPORT_SIZE); data->usbdev = usbdev; @@ -371,7 +191,6 @@ static int usb_kbd_probe(struct usb_device *usbdev, ret = data->do_poll(data); if (ret < 0) { /* no luck */ - kfifo_free(data->recv_fifo); dma_free(data->new); free(data); return ret; @@ -380,16 +199,10 @@ static int usb_kbd_probe(struct usb_device *usbdev, } else dev_dbg(&usbdev->dev, "poll keyboard via int ep\n"); - cdev = &data->cdev; - usbdev->dev.type_data = cdev; - cdev->dev = &usbdev->dev; - cdev->tstc = usb_kbd_tstc; - cdev->getc = usb_kbd_getc; - - console_register(cdev); - console_set_active(cdev, CONSOLE_STDIN); + input_device_register(&data->input); data->poller.func = usb_kbd_poll; + return poller_register(&data->poller); } @@ -398,8 +211,7 @@ static void usb_kbd_disconnect(struct usb_device *usbdev) struct usb_kbd_pdata *data = usbdev->drv_data; poller_unregister(&data->poller); - console_unregister(&data->cdev); - kfifo_free(data->recv_fifo); + input_device_unregister(&data->input); dma_free(data->new); free(data); } |