summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-02-08 08:26:35 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2016-02-08 08:26:35 +0100
commit05261801e9cde103b3c4df843472027c007531da (patch)
tree1c138878a228f93e22ec1c8d729ef6915586b587 /drivers
parent6435fb09d8af3aeae7c6f8428f5e7ade15aca6f5 (diff)
parent253fb33bb81b0e88bcfa0184ef29206598fbb5d4 (diff)
downloadbarebox-05261801e9cde103b3c4df843472027c007531da.tar.gz
barebox-05261801e9cde103b3c4df843472027c007531da.tar.xz
Merge branch 'for-next/input'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/Kconfig10
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/input/gpio_keys.c71
-rw-r--r--drivers/input/imx_keypad.c92
-rw-r--r--drivers/input/input.c202
-rw-r--r--drivers/input/keymap.c173
-rw-r--r--drivers/input/matrix-keymap.c89
-rw-r--r--drivers/input/usb_kbd.c296
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);
}