summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2009-12-11 10:58:20 -0800
committerGary King <gking@nvidia.com>2009-12-11 15:02:13 -0800
commite550e3fd26c036ec1fcb55928fd7606d7e1daedb (patch)
treee907d6e4f1dcb7e840459392471df109adf8aa3b /drivers/input
parent87a5fbc7a8ff6cb6109dc88e93c6a255fa83010c (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/Kconfig7
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/tegra-nvec.c442
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);
+