diff options
author | Gary King <gking@nvidia.com> | 2009-12-11 10:58:20 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2009-12-11 15:02:13 -0800 |
commit | e550e3fd26c036ec1fcb55928fd7606d7e1daedb (patch) | |
tree | e907d6e4f1dcb7e840459392471df109adf8aa3b /drivers/input | |
parent | 87a5fbc7a8ff6cb6109dc88e93c6a255fa83010c (diff) |
keyboard: adds a driver for NvEc keyboard support
adds a keyboard driver for keyboards connected to NVIDIA Tegra NvEc-compliant
embedded controllers
Change-Id: I3426ec0de0dbdba63dfc03738f6c0c38905b0a5b
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/keyboard/Kconfig | 7 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/tegra-nvec.c | 442 |
3 files changed, 450 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index d1d6bf4f9597..1c415c4dcc95 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -340,4 +340,11 @@ config KEYBOARD_TEGRA Say Y here if you want to use a matrix keyboard connected directly to the internal keyboard controller on Tegra SoCs +config KEYBOARD_TEGRA_NVEC + boolean "NVIDIA Tegra NvEc-compliant embedded controller keyboard" + depends on ARCH_TEGRA && TEGRA_NVEC + help + Say Y here to enable keyboard input for keyboards attached to an + NvEc-compliant embedded controller + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 5cd8af240ae1..301a409a33ed 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o +obj-$(CONFIG_KEYBOARD_TEGRA_NVEC) += tegra-nvec.o diff --git a/drivers/input/keyboard/tegra-nvec.c b/drivers/input/keyboard/tegra-nvec.c new file mode 100644 index 000000000000..cf30c42cd7f5 --- /dev/null +++ b/drivers/input/keyboard/tegra-nvec.c @@ -0,0 +1,442 @@ +/* + * drivers/input/keyboard/tegra-nvec.c + * + * Keyboard class input driver for keyboards connected to an NvEc compliant + * embedded controller + * + * Copyright (c) 2009, NVIDIA Corporation. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/kthread.h> + +#include "nvos.h" +#include "nvec.h" +#include "nvodm_services.h" +#include "nvodm_keyboard.h" + +#define DRIVER_DESC "NvEc keyboard driver" +#define DRIVER_LICENSE "GPL" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + +#define NVEC_PAYLOAD 32 + +/* The total number of scan codes will be (first - last) */ +#define EC_FIRST_CODE 0x00 +#define EC_LAST_CODE 0x58 +#define EC_TOTAL_CODES (EC_LAST_CODE - EC_FIRST_CODE + 1) + +/** + * @brief This is the actual Scan-code-to-VKey mapping table. For new layouts + * this is the only structure which needs to be modified to return the + * proper vkey depending on the scan code. + */ +NvU8 code_tab_102us[EC_TOTAL_CODES] = { + KEY_GRAVE, // 0x00 + KEY_BACK, + 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, + KEY_TAB, + KEY_Q, // 0x10 + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_LEFTBRACE, + KEY_RIGHTBRACE, + KEY_ENTER, + KEY_LEFTCTRL, + KEY_A, + KEY_S, + KEY_D, // 0x20 + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_GRAVE, + KEY_LEFTSHIFT, + KEY_BACKSLASH, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, // 0x30 + KEY_N, + KEY_M, + KEY_COMMA, + KEY_DOT, + KEY_SLASH, + KEY_RIGHTSHIFT, + KEY_KPASTERISK, + KEY_LEFTALT, + KEY_SPACE, + KEY_CAPSLOCK, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, // 0x40 + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_NUMLOCK, + 0, //VK_SCROLL + KEY_KP7, + KEY_KP8, + KEY_KP9, + KEY_KPMINUS, + KEY_KP4, + KEY_KP5, + KEY_KP6, + KEY_KPPLUS, + KEY_KP1, + KEY_KP2, // 0x50 + KEY_KP3, + KEY_KP0, + KEY_KPDOT + 0, //VK_SNAPSHOT + 0, + 0, //VK_OEM_102 + 0, //VK_F11 + 0, //VK_F12 +}; + +/* The total number of scan codes will be (first - last) */ +#define EC_EXT_CODE_FIRST 0xE010 +#define EC_EXT_CODE_LAST 0xE06D +#define EC_EXT_TOTAL_CODES (EC_EXT_CODE_LAST - EC_EXT_CODE_FIRST + 1) + +/** + * @brief This table consists of the scan codes which were added after the + * original scan codes were designed. + * To avoid moving the already designed buttons to accomodate these + * new buttons, the new scan codes are preceded by 'E0'. + */ +NvU8 extcode_tab_us102[EC_EXT_TOTAL_CODES] = { + 0, // 0xE0 0x10 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, //VK_MEDIA_NEXT_TRACK, + 0, + 0, + 0, //VK_RETURN, + 0, //VK_RCONTROL, + 0, + 0, + KEY_MUTE, // 0xE0 0x20 + 0, //VK_LAUNCH_APP1 + 0, //VK_MEDIA_PLAY_PAUSE + 0, + 0, //VK_MEDIA_STOP + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + KEY_VOLUMEDOWN, + 0, + KEY_VOLUMEUP, // 0xE0 0x30 + 0, + 0, //VK_BROWSER_HOME + 0, + 0, + KEY_KPSLASH, //VK_DIVIDE + 0, + 0, //VK_SNAPSHOT + 0, //VK_RMENU + 0, //VK_OEM_NV_BACKLIGHT_UP + 0, //VK_OEM_NV_BACKLIGHT_DN + 0, //VK_OEM_NV_BACKLIGHT_AUTOTOGGLE + 0, //VK_OEM_NV_POWER_INFO + 0, //VK_OEM_NV_WIFI_TOGGLE + 0, //VK_OEM_NV_DISPLAY_SELECT + 0, //VK_OEM_NV_AIRPLANE_TOGGLE + 0, //0xE0 0x40 + 0, //VK_OEM_NV_RESERVED + 0, //VK_OEM_NV_RESERVED + 0, //VK_OEM_NV_RESERVED + 0, //VK_OEM_NV_RESERVED + 0, //VK_OEM_NV_RESERVED + KEY_CANCEL, + KEY_HOME, + KEY_UP, + 0, //VK_PRIOR + 0, + KEY_LEFT, + 0, + KEY_RIGHT, + 0, + KEY_END, + KEY_DOWN, // 0xE0 0x50 + 0, //VK_NEXT + KEY_INSERT, + KEY_DELETE, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + KEY_MENU, //VK_LWIN + 0, //VK_RWIN + KEY_BACK, //VK_APPS + 0, + 0, + 0, // 0xE0 0x60 + 0, + 0, + 0, + 0, + 0, //VK_BROWSER_SEARCH + 0, //VK_BROWSER_FAVORITES + 0, //VK_BROWSER_REFRESH + 0, //VK_BROWSER_STOP + 0, //VK_BROWSER_FORWARD + 0, //VK_BROWSER_BACK + 0, //VK_LAUNCH_APP2 + 0, //VK_LAUNCH_MAIL + 0, //VK_LAUNCH_MEDIA_SELECT +}; + +struct nvec_keyboard +{ + struct input_dev *input_dev; + struct task_struct *task; + char name[128]; + unsigned short keycode[512]; + NvEcHandle hNvec; + NvEcEventRegistrationHandle hEvent; +}; + +static struct platform_device *nvec_keyboard_device; + +static int nvec_keyboard_recv(void *arg) +{ + struct input_dev *input_dev = (struct input_dev *)arg; + struct nvec_keyboard *keyboard = input_get_drvdata(input_dev); + + while (!kthread_should_stop()) { + unsigned int pressed; + NvU32 code; + NvU8 flags; + + if (!NvOdmKeyboardGetKeyData(&code, &flags, 0)) { + printk(KERN_INFO "nvec_keyboard: unhandled " + "scancode %x\n", code); + continue; + } + + /* Check for the thread terminaiton request */ + if (kthread_should_stop()) + return 0; + + pressed = (flags & NV_ODM_SCAN_CODE_FLAG_MAKE); + + + if ((code >= EC_FIRST_CODE) && (code <= EC_LAST_CODE)) { + code -= EC_FIRST_CODE; + code = code_tab_102us[code]; + input_report_key(keyboard->input_dev, code, pressed); + } + else if ((code >= EC_EXT_CODE_FIRST) && + (code <= EC_EXT_CODE_LAST)) { + + code -= EC_EXT_CODE_FIRST; + code = extcode_tab_us102[code]; + input_report_key(keyboard->input_dev, code, pressed); + } + } + + return 0; +} + +static int nvec_keyboard_open(struct input_dev *dev) +{ + return 0; +} + +static void nvec_keyboard_close(struct input_dev *dev) +{ + return; +} + + +static int __devinit nvec_keyboard_probe(struct platform_device *pdev) +{ + int error; + NvError nverr; + struct nvec_keyboard *keyboard; + struct input_dev *input_dev; + int i; + + keyboard = kzalloc(sizeof(struct nvec_keyboard), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!keyboard || !input_dev) { + error = -ENOMEM; + goto fail; + } + + keyboard->input_dev = input_dev; + input_set_drvdata(input_dev, keyboard); + platform_set_drvdata(pdev, input_dev); + + if (!NvOdmKeyboardInit()) { + error = -ENODEV; + pr_err("tegra_keyboard_probe: no keyboard\n"); + goto fail_keyboard_init; + } + + keyboard->task = kthread_create(nvec_keyboard_recv, input_dev, + "nvec_keyboard_thread"); + if (keyboard->task == NULL) { + error = -ENOMEM; + goto fail_thread_create; + } + wake_up_process(keyboard->task); + + if (!strlen(keyboard->name)) + snprintf(keyboard->name, sizeof(keyboard->name), + "nvec keyboard"); + + input_dev->name = keyboard->name; + input_dev->open = nvec_keyboard_open; + input_dev->close = nvec_keyboard_close; + + __set_bit(EV_KEY, input_dev->evbit); + for (i=1; i<EC_TOTAL_CODES; i++) { + __set_bit(code_tab_102us[i], input_dev->keybit); + } + for (i=1; i<EC_EXT_TOTAL_CODES; i++) { + __set_bit(extcode_tab_us102[i], input_dev->keybit); + } + + error = input_register_device(keyboard->input_dev); + if (error) + goto fail_input_register; + + return 0; + +fail_input_register: + (void)kthread_stop(keyboard->task); +fail_thread_create: + NvOdmKeyboardDeInit(); +fail_keyboard_init: +fail: + input_free_device(input_dev); + kfree(keyboard); + + return error; +} + +static int __devexit nvec_keyboard_remove(struct platform_device *dev) +{ + struct input_dev *input_dev = platform_get_drvdata(dev); + struct nvec_keyboard *keyboard = platform_get_drvdata(dev); + + (void)kthread_stop(keyboard->task); + NvOdmKeyboardDeInit(); + input_free_device(input_dev); + kfree(keyboard); + + return 0; +} + +static struct platform_driver nvec_keyboard_driver = { + .driver = { + .name = "nvec_keyboard", + .owner = THIS_MODULE, + }, + .probe = nvec_keyboard_probe, + .remove = __devexit_p(nvec_keyboard_remove), +}; + + +static int __init nvec_keyboard_init(void) +{ + int err; + + err = platform_driver_register(&nvec_keyboard_driver); + if (err) { + goto error; + } + + nvec_keyboard_device = platform_device_alloc("nvec_keyboard", -1); + if (!nvec_keyboard_device) { + err = -ENOMEM; + goto error_unregister_driver; + } + + err = platform_device_add(nvec_keyboard_device); + if (err) + goto error_free_device; + + return 0; + +error_free_device: + platform_device_put(nvec_keyboard_device); +error_unregister_driver: + platform_driver_unregister(&nvec_keyboard_driver); +error: + return err; +} + +static void __exit nvec_keyboard_exit(void) +{ + platform_device_unregister(nvec_keyboard_device); + platform_driver_unregister(&nvec_keyboard_driver); +} + +module_init(nvec_keyboard_init); +module_exit(nvec_keyboard_exit); + |