diff mbox

[RFC,04/36,Driver,Qualcomm,1070,EC_KB] Adding new qci keyboard driver

Message ID 1280133045-25945-4-git-send-email-wayne.lin@quantatw.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wayne Lin July 26, 2010, 8:30 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/input/keyboard/qci_kbd.c b/drivers/input/keyboard/qci_kbd.c
index aa7a64a..0cf2f7e 100755
--- a/drivers/input/keyboard/qci_kbd.c
+++ b/drivers/input/keyboard/qci_kbd.c
@@ -1,550 +1,551 @@ 
-/* Quanta I2C Keyboard Driver
- *
- * Copyright (C) 2009 Quanta Computer Inc.
- * Author: Hsin Wu <hsin.wu@quantatw.com>
- * Author: Austin Lai <austin.lai@quantatw.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
- /*
- *
- *  The Driver with I/O communications via the I2C Interface for ON2 of AP BU.
- *  And it is only working on the nuvoTon WPCE775x Embedded Controller.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/keyboard.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-
-/* Keyboard special scancode */
-#define RC_KEY_FN          0x70
-#define RC_KEY_BREAK       0x80
-#define KEY_ACK_FA      0xFA
-
-/* Keyboard keycodes */
-#define NOKEY           KEY_RESERVED
-#define KEY_LEFTWIN     KEY_LEFTMETA
-#define KEY_RIGHTWIN    KEY_RIGHTMETA
-#define KEY_APPS        KEY_COMPOSE
-#define KEY_PRINTSCR    KEY_SYSRQ
-
-#define KEYBOARD_ID_NAME          "qci-i2ckbd"
-#define KEYBOARD_NAME                "Quanta Keyboard"
-#define KEYBOARD_DEVICE             "/i2c/input0"
-#define KEYBOARD_CMD_ENABLE             0xF4
-
-/*-----------------------------------------------------------------------------
- * Keyboard scancode to linux keycode translation table
- *---------------------------------------------------------------------------*/
-
-static const unsigned char on2_keycode[256] = {
-	[0]   = NOKEY,
-	[1]   = NOKEY,
-	[2]   = NOKEY,
-	[3]   = KEY_5,
-	[4]   = KEY_7,
-	[5]   = KEY_9,
-	[6]   = KEY_MINUS,
-	[7]   = NOKEY,
-	[8]   = NOKEY,
-	[9]   = NOKEY,
-	[10]  = NOKEY,
-	[11]  = KEY_LEFTBRACE,
-	[12]  = KEY_F10,
-	[13]  = KEY_INSERT,
-	[14]  = KEY_F11,
-	[15]  = KEY_ESC,
-	[16]  = NOKEY,
-	[17]  = NOKEY,
-	[18]  = NOKEY,
-	[19]  = KEY_4,
-	[20]  = KEY_6,
-	[21]  = KEY_8,
-	[22]  = KEY_0,
-	[23]  = KEY_EQUAL,
-	[24]  = NOKEY,
-	[25]  = NOKEY,
-	[26]  = NOKEY,
-	[27]  = KEY_P,
-	[28]  = KEY_F9,
-	[29]  = KEY_DELETE,
-	[30]  = KEY_F12,
-	[31]  = KEY_GRAVE,
-	[32]  = KEY_W,
-	[33]  = NOKEY,
-	[34]  = NOKEY,
-	[35]  = KEY_R,
-	[36]  = KEY_T,
-	[37]  = KEY_U,
-	[38]  = KEY_O,
-	[39]  = KEY_RIGHTBRACE,
-	[40]  = NOKEY,
-	[41]  = NOKEY,
-	[42]  = NOKEY,
-	[43]  = KEY_APOSTROPHE,
-	[44]  = KEY_BACKSPACE,
-	[45]  = NOKEY,
-	[46]  = KEY_F8,
-	[47]  = KEY_F5,
-	[48]  = KEY_S,
-	[49]  = NOKEY,
-	[50]  = NOKEY,
-	[51]  = KEY_E,
-	[52]  = KEY_H,
-	[53]  = KEY_Y,
-	[54]  = KEY_I,
-	[55]  = KEY_ENTER,
-	[56]  = NOKEY,
-	[57]  = NOKEY,
-	[58]  = NOKEY,
-	[59]  = KEY_SEMICOLON,
-	[60]  = KEY_3,
-	[61]  = KEY_PAGEUP,
-	[62]  = KEY_Q,
-	[63]  = KEY_TAB,
-	[64]  = KEY_A,
-	[65]  = NOKEY,
-	[66]  = NOKEY,
-	[67]  = KEY_F,
-	[68]  = KEY_G,
-	[69]  = KEY_J,
-	[70]  = KEY_L,
-	[71]  = NOKEY,
-	[72]  = KEY_RIGHTSHIFT,
-	[73]  = NOKEY,
-	[74]  = NOKEY,
-	[75]  = KEY_SLASH,
-	[76]  = KEY_2,
-	[77]  = KEY_PAGEDOWN,
-	[78]  = KEY_F4,
-	[79]  = KEY_F1,
-	[80]  = KEY_Z,
-	[81]  = NOKEY,
-	[82]  = NOKEY,
-	[83]  = KEY_D,
-	[84]  = KEY_V,
-	[85]  = KEY_N,
-	[86]  = KEY_K,
-	[87]  = NOKEY,
-	[88]  = KEY_LEFTSHIFT,
-	[89]  = KEY_RIGHTCTRL,
-	[90]  = NOKEY,
-	[91]  = KEY_DOT,
-	[92]  = KEY_UP,
-	[93]  = KEY_RIGHT,
-	[94]  = KEY_F3,
-	[95]  = KEY_F2,
-	[96]  = NOKEY,
-	[97]  = NOKEY,
-	[98]  = KEY_RIGHTALT,
-	[99]  = KEY_X,
-	[100] = KEY_C,
-	[101] = KEY_B,
-	[102] = KEY_COMMA,
-	[103] = NOKEY,
-	[104] = NOKEY,
-	[105] = NOKEY,
-	[106] = NOKEY,
-	[107] = NOKEY,
-	[108] = KEY_PRINTSCR,
-	[109] = KEY_DOWN,
-	[110] = KEY_1,
-	[111] = KEY_CAPSLOCK,
-	[112] = KEY_F24,
-	[113] = KEY_HOME,
-	[114] = KEY_LEFTALT,
-	[115] = NOKEY,
-	[116] = KEY_SPACE,
-	[117] = KEY_BACKSLASH,
-	[118] = KEY_M,
-	[119] = KEY_COMPOSE,
-	[120] = NOKEY,
-	[121] = KEY_LEFTCTRL,
-	[122] = NOKEY,
-	[123] = NOKEY,
-	[124] = KEY_PAUSE,
-	[125] = KEY_LEFT,
-	[126] = KEY_F7,
-	[127] = KEY_F6,
-	[128] = NOKEY,
-	[129] = NOKEY,
-	[130] = NOKEY,
-	[131] = NOKEY,
-	[132] = NOKEY,
-	[133] = NOKEY,
-	[134] = NOKEY,
-	[135] = NOKEY,
-	[136] = NOKEY,
-	[137] = NOKEY,
-	[138] = NOKEY,
-	[139] = NOKEY,
-	[140] = NOKEY,
-	[141] = NOKEY,
-	[142] = NOKEY,
-	[143] = NOKEY,
-	[144] = NOKEY,
-	[145] = NOKEY,
-	[146] = NOKEY,
-	[147] = NOKEY,
-	[148] = NOKEY,
-	[149] = NOKEY,
-	[150] = NOKEY,
-	[151] = NOKEY,
-	[152] = NOKEY,
-	[153] = NOKEY,
-	[154] = NOKEY,
-	[155] = NOKEY,
-	[156] = NOKEY,
-	[157] = NOKEY,
-	[158] = NOKEY,
-	[159] = NOKEY,
-	[160] = NOKEY,
-	[161] = NOKEY,
-	[162] = NOKEY,
-	[163] = NOKEY,
-	[164] = NOKEY,
-	[165] = NOKEY,
-	[166] = NOKEY,
-	[167] = NOKEY,
-	[168] = NOKEY,
-	[169] = NOKEY,
-	[170] = NOKEY,
-	[171] = NOKEY,
-	[172] = NOKEY,
-	[173] = NOKEY,
-	[174] = NOKEY,
-	[175] = NOKEY,
-	[176] = NOKEY,
-	[177] = NOKEY,
-	[178] = NOKEY,
-	[179] = NOKEY,
-	[180] = NOKEY,
-	[181] = NOKEY,
-	[182] = NOKEY,
-	[183] = NOKEY,
-	[184] = NOKEY,
-	[185] = NOKEY,
-	[186] = NOKEY,
-	[187] = NOKEY,
-	[188] = NOKEY,
-	[189] = KEY_HOME,
-	[190] = NOKEY,
-	[191] = NOKEY,
-	[192] = NOKEY,
-	[193] = NOKEY,
-	[194] = NOKEY,
-	[195] = NOKEY,
-	[196] = NOKEY,
-	[197] = NOKEY,
-	[198] = NOKEY,
-	[199] = NOKEY,
-	[200] = NOKEY,
-	[201] = NOKEY,
-	[202] = NOKEY,
-	[203] = NOKEY,
-	[204] = NOKEY,
-	[205] = KEY_END,
-	[206] = NOKEY,
-	[207] = NOKEY,
-	[208] = NOKEY,
-	[209] = NOKEY,
-	[210] = NOKEY,
-	[211] = NOKEY,
-	[212] = NOKEY,
-	[213] = NOKEY,
-	[214] = NOKEY,
-	[215] = NOKEY,
-	[216] = NOKEY,
-	[217] = NOKEY,
-	[218] = NOKEY,
-	[219] = NOKEY,
-	[220] = KEY_VOLUMEUP,
-	[221] = KEY_BRIGHTNESSUP,
-	[222] = NOKEY,
-	[223] = NOKEY,
-	[224] = NOKEY,
-	[225] = NOKEY,
-	[226] = NOKEY,
-	[227] = NOKEY,
-	[228] = NOKEY,
-	[229] = NOKEY,
-	[230] = NOKEY,
-	[231] = NOKEY,
-	[232] = NOKEY,
-	[233] = NOKEY,
-	[234] = NOKEY,
-	[235] = NOKEY,
-	[236] = NOKEY,
-	[237] = KEY_VOLUMEDOWN,
-	[238] = NOKEY,
-	[239] = NOKEY,
-	[240] = NOKEY,
-	[241] = NOKEY,
-	[242] = NOKEY,
-	[243] = NOKEY,
-	[244] = NOKEY,
-	[245] = NOKEY,
-	[246] = NOKEY,
-	[247] = NOKEY,
-	[248] = NOKEY,
-	[249] = NOKEY,
-	[250] = NOKEY,
-	[251] = NOKEY,
-	[252] = NOKEY,
-	[253] = KEY_BRIGHTNESSDOWN,
-	[254] = NOKEY,
-	[255] = NOKEY,
-};
-/*-----------------------------------------------------------------------------
- * Global variables
- *---------------------------------------------------------------------------*/
-
-struct input_dev *g_qci_keyboard_dev;
-
-/* General structure to hold the driver data */
-struct i2ckbd_drv_data {
-	struct i2c_client *ki2c_client;
-	struct work_struct work;
-	struct input_dev *qcikbd_dev;
-	unsigned int qcikbd_gpio; /* GPIO used for interrupt */
-	unsigned int qcikbd_irq;
-	unsigned int key_down;
-	unsigned int escape;
-	unsigned int pause_seq;
-	unsigned int fn;
-};
-#ifdef CONFIG_PM
-static int qcikbd_suspend(struct device *dev)
-{
-	return 0;
-}
-
-static int qcikbd_resume(struct device *dev)
-{
-	return 0;
-}
-#endif
-static int __devinit qcikbd_probe(struct i2c_client *client,
-	const struct i2c_device_id *id);
-static int __devexit qcikbd_remove(struct i2c_client *kbd);
-
-static const struct i2c_device_id qcikbd_idtable[] = {
-	{ KEYBOARD_ID_NAME, 0 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(i2c, qcikbd_idtable);
-
-#ifdef CONFIG_PM
-static struct dev_pm_ops qcikbd_pm_ops = {
-	.suspend  = qcikbd_suspend,
-	.resume   = qcikbd_resume,
-};
-#endif
-static struct i2c_driver i2ckbd_driver = {
-	.driver = {
-		.owner = THIS_MODULE,
-		.name  = KEYBOARD_ID_NAME,
-#ifdef CONFIG_PM
-		.pm = &qcikbd_pm_ops,
-#endif
-	},
-	.probe	  = qcikbd_probe,
-	.remove = __devexit_p(qcikbd_remove),
-	.id_table = qcikbd_idtable,
-};
-
-/*-----------------------------------------------------------------------------
- * Driver functions
- *---------------------------------------------------------------------------*/
-
-static irqreturn_t qcikbd_interrupt(int irq, void *dev_id)
-{
-	struct i2ckbd_drv_data *ikbd_drv_data = dev_id;
-	schedule_work(&ikbd_drv_data->work);
-	return IRQ_HANDLED;
-}
-
-static void qcikbd_work_handler(struct work_struct *_work)
-{
-	unsigned char scancode;
-	unsigned int  keycode;
-
-	struct i2ckbd_drv_data *ikbd_drv_data =
-		container_of(_work, struct i2ckbd_drv_data, work);
-
-	struct i2c_client *ikbdclient = ikbd_drv_data->ki2c_client;
-	struct input_dev *ikbdev = ikbd_drv_data->qcikbd_dev;
-
-	scancode = i2c_smbus_read_byte(ikbdclient);
-
-	if (scancode == KEY_ACK_FA) {
-		return;
-	} else if (scancode == RC_KEY_FN) {
-		ikbd_drv_data->fn = 0x80;     /* select keycode table  > 0x7F */
-	} else {
-		ikbd_drv_data->key_down = 1;
-		if (scancode & RC_KEY_BREAK) {
-			ikbd_drv_data->key_down = 0;
-			if ((scancode & 0x7F) == RC_KEY_FN)
-				ikbd_drv_data->fn = 0;
-		}
-		keycode = on2_keycode[(scancode & 0x7F) | ikbd_drv_data->fn];
-		if (keycode != NOKEY) {
-			input_report_key(ikbdev,
-					 keycode,
-					 ikbd_drv_data->key_down);
-			input_sync(ikbdev);
-		}
-	}
-}
-
-
-static int qcikbd_open(struct input_dev *dev)
-{
-	struct i2ckbd_drv_data *ikbd_drv_data = input_get_drvdata(dev);
-	struct i2c_client *ikbdclient = ikbd_drv_data->ki2c_client;
-
-	/* Send F4h - enable keyboard */
-	i2c_smbus_write_byte(ikbdclient, KEYBOARD_CMD_ENABLE);
-	return 0;
-}
-
-static int __devinit qcikbd_probe(struct i2c_client *client,
-				    const struct i2c_device_id *id)
-{
-	int err;
-	int i;
-	struct i2ckbd_drv_data *context;
-	context = kzalloc(sizeof(struct i2ckbd_drv_data), GFP_KERNEL);
-	if (!context)
-		return -ENOMEM;
-	i2c_set_clientdata(client, context);
-	context->ki2c_client = client;
-	context->qcikbd_gpio = client->irq;
-	client->driver = &i2ckbd_driver;
-
-	INIT_WORK(&context->work, qcikbd_work_handler);
-
-	err = gpio_request(context->qcikbd_gpio, "qci-kbd");
-	if (err) {
-		pr_err("[KBD] err gpio request\n");
-		goto gpio_request_fail;
-	}
-
-	context->qcikbd_irq = gpio_to_irq(context->qcikbd_gpio);
-	err = request_irq(context->qcikbd_irq,
-			  qcikbd_interrupt,
-			  IRQF_TRIGGER_FALLING,
-			  KEYBOARD_ID_NAME,
-			  context);
-	if (err) {
-		pr_err("[KBD] err unable to get IRQ\n");
-		goto request_irq_fail;
-	}
-
-	context->qcikbd_dev = input_allocate_device();
-	if (!context->qcikbd_dev) {
-		pr_err("[KBD]allocting memory err\n");
-		err = -ENOMEM;
-		goto allocate_fail;
-	}
-
-	context->qcikbd_dev->name       = KEYBOARD_NAME;
-	context->qcikbd_dev->phys       = KEYBOARD_DEVICE;
-	context->qcikbd_dev->id.bustype = BUS_I2C;
-	context->qcikbd_dev->id.vendor  = 0x1050;
-	context->qcikbd_dev->id.product = 0x0006;
-	context->qcikbd_dev->id.version = 0x0004;
-	context->qcikbd_dev->open       = qcikbd_open;
-	set_bit(EV_KEY, context->qcikbd_dev->evbit);
-	set_bit(EV_REP, context->qcikbd_dev->evbit);
-
-	/* Enable all supported keys */
-	for (i = 1; i < ARRAY_SIZE(on2_keycode) ; i++)
-		set_bit(on2_keycode[i], context->qcikbd_dev->keybit);
-
-	set_bit(KEY_POWER, context->qcikbd_dev->keybit);
-	set_bit(KEY_END, context->qcikbd_dev->keybit);
-	set_bit(KEY_VOLUMEUP, context->qcikbd_dev->keybit);
-	set_bit(KEY_VOLUMEDOWN, context->qcikbd_dev->keybit);
-	set_bit(KEY_ZOOMIN, context->qcikbd_dev->keybit);
-	set_bit(KEY_ZOOMOUT, context->qcikbd_dev->keybit);
-
-	input_set_drvdata(context->qcikbd_dev, context);
-	err = input_register_device(context->qcikbd_dev);
-	if (err) {
-		pr_err("[KBD] err input register device\n");
-		goto register_fail;
-	}
-	g_qci_keyboard_dev = context->qcikbd_dev;
-	return 0;
-register_fail:
-	input_free_device(context->qcikbd_dev);
-
-allocate_fail:
-	free_irq(context->qcikbd_irq, context);
-
-request_irq_fail:
-	gpio_free(context->qcikbd_gpio);
-
-gpio_request_fail:
-	i2c_set_clientdata(client, NULL);
-	kfree(context);
-	return err;
-}
-
-static int __devexit qcikbd_remove(struct i2c_client *dev)
-{
-	struct i2ckbd_drv_data *context = i2c_get_clientdata(dev);
-
-	free_irq(context->qcikbd_irq, context);
-	gpio_free(context->qcikbd_gpio);
-	input_free_device(context->qcikbd_dev);
-	input_unregister_device(context->qcikbd_dev);
-	kfree(context);
-
-	return 0;
-}
-
-static int __init qcikbd_init(void)
-{
-	return i2c_add_driver(&i2ckbd_driver);
-}
-
-static void __exit qcikbd_exit(void)
-{
-	i2c_del_driver(&i2ckbd_driver);
-}
-
-struct input_dev *nkbc_keypad_get_input_dev(void)
-{
-	return g_qci_keyboard_dev;
-}
-EXPORT_SYMBOL(nkbc_keypad_get_input_dev);
-module_init(qcikbd_init);
-module_exit(qcikbd_exit);
-
-MODULE_AUTHOR("Quanta Computer Inc.");
-MODULE_DESCRIPTION("Quanta Embedded Controller I2C Keyboard Driver");
-MODULE_LICENSE("GPL v2");
-
+/* Quanta I2C Keyboard Driver
+ *
+ * Copyright (C) 2009 Quanta Computer Inc.
+ * Author: Hsin Wu <hsin.wu@quantatw.com>
+ * Author: Austin Lai <austin.lai@quantatw.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+ /*
+ *
+ *  The Driver with I/O communications via the I2C Interface for ON2 of AP BU.
+ *  And it is only working on the nuvoTon WPCE775x Embedded Controller.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/keyboard.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+/* Keyboard special scancode */
+#define RC_KEY_FN          0x70
+#define RC_KEY_BREAK       0x80
+#define KEY_ACK_FA      0xFA
+
+/* Keyboard keycodes */
+#define NOKEY           KEY_RESERVED
+#define KEY_LEFTWIN     KEY_LEFTMETA
+#define KEY_RIGHTWIN    KEY_RIGHTMETA
+#define KEY_APPS        KEY_COMPOSE
+#define KEY_PRINTSCR    KEY_SYSRQ
+
+#define KEYBOARD_ID_NAME          "qci-i2ckbd"
+#define KEYBOARD_NAME                "Quanta Keyboard"
+#define KEYBOARD_DEVICE             "/i2c/input0"
+#define KEYBOARD_CMD_ENABLE             0xF4
+
+/*-----------------------------------------------------------------------------
+ * Keyboard scancode to linux keycode translation table
+ *---------------------------------------------------------------------------*/
+
+static const unsigned char on2_keycode[256] = {
+        [0]   = KEY_RESERVED,
+        [1]   = KEY_ESC,
+        [2]   = KEY_1,
+        [3]   = KEY_2,
+        [4]   = KEY_3,
+        [5]   = KEY_4,
+        [6]   = KEY_5,
+        [7]   = KEY_6,
+        [8]   = KEY_7,
+        [9]   = KEY_8,
+        [10]  = KEY_9,
+        [11]  = KEY_0,
+        [12]  = KEY_MINUS,
+        [13]  = KEY_EQUAL,
+        [14]  = KEY_BACKSPACE,
+        [15]  = KEY_TAB,
+        [16]  = KEY_Q,
+        [17]  = KEY_W,
+        [18]  = KEY_E,
+        [19]  = KEY_R,
+        [20]  = KEY_T,
+        [21]  = KEY_Y,
+        [22]  = KEY_U,
+        [23]  = KEY_I,
+        [24]  = KEY_O,
+        [25]  = KEY_P,
+        [26]  = KEY_LEFTBRACE,
+        [27]  = KEY_RIGHTBRACE,
+        [28]  = KEY_ENTER,
+        [29]  = KEY_LEFTCTRL,
+        [30]  = KEY_A,
+        [31]  = KEY_S,
+        [32]  = KEY_D,
+        [33]  = KEY_F,
+        [34]  = KEY_G,
+        [35]  = KEY_H,
+        [36]  = KEY_J,
+        [37]  = KEY_K,
+        [38]  = KEY_L,
+        [39]  = KEY_SEMICOLON,
+        [40]  = KEY_APOSTROPHE,
+        [41]  = KEY_GRAVE,
+        [42]  = KEY_LEFTSHIFT,
+        [43]  = KEY_BACKSLASH,
+        [44]  = KEY_Z,
+        [45]  = KEY_X,
+        [46]  = KEY_C,
+        [47]  = KEY_V,
+        [48]  = KEY_B,
+        [49]  = KEY_N,
+        [50]  = KEY_M,
+        [51]  = KEY_COMMA,
+        [52]  = KEY_DOT,
+        [53]  = KEY_SLASH,
+        [54]  = KEY_RIGHTSHIFT,
+        [55]  = KEY_KPASTERISK,
+        [56]  = KEY_LEFTALT,
+        [57]  = KEY_SPACE,
+        [58]  = KEY_CAPSLOCK,
+        [59]  = KEY_F1,
+        [60]  = KEY_F2,
+        [61]  = KEY_F3,
+        [62]  = KEY_F4,
+        [63]  = KEY_F5,
+        [64]  = KEY_F6,
+        [65]  = KEY_F7,
+        [66]  = KEY_F8,
+        [67]  = KEY_F9,
+        [68]  = KEY_F10,
+        [69]  = KEY_NUMLOCK,
+        [70]  = KEY_SCROLLLOCK,
+        [71]  = KEY_KP7,
+        [72]  = KEY_KP8,
+        [73]  = KEY_KP9,
+        [74]  = KEY_KPMINUS,
+        [75]  = KEY_KP4,
+        [76]  = KEY_KP5,
+        [77]  = KEY_KP6,
+        [78]  = KEY_KPPLUS,
+        [79]  = KEY_KP1,
+        [80]  = KEY_KP2,
+        [81]  = KEY_KP3,
+        [82]  = KEY_KP0,
+        [83]  = KEY_KPDOT,
+        [84]  = KEY_RESERVED,
+        [85]  = KEY_ZENKAKUHANKAKU,
+        [86]  = KEY_102ND,
+        [87]  = KEY_F11,
+        [88]  = KEY_F12,
+        [89]  = KEY_RO,
+        [90]  = KEY_KATAKANA,
+        [91]  = KEY_HIRAGANA,
+        [92]  = KEY_HENKAN,
+        [93]  = KEY_KATAKANAHIRAGANA,
+        [94]  = KEY_MUHENKAN,
+        [95]  = KEY_KPJPCOMMA,
+        [96]  = KEY_KPENTER,
+        [97]  = KEY_RIGHTCTRL,
+        [98]  = KEY_KPSLASH,
+        [99]  = KEY_SYSRQ,
+        [100] = KEY_RIGHTALT,
+        [101] = KEY_LINEFEED,
+        [102] = KEY_HOME,
+        [103] = KEY_UP,
+        [104] = KEY_PAGEUP,
+        [105] = KEY_LEFT,
+        [106] = KEY_RIGHT,
+        [107] = KEY_END,
+        [108] = KEY_DOWN,
+        [109] = KEY_PAGEDOWN,
+        [110] = KEY_INSERT,
+        [111] = KEY_DELETE,
+        [112] = KEY_MACRO,
+        [113] = KEY_MUTE,
+        [114] = KEY_VOLUMEDOWN,
+        [115] = KEY_VOLUMEUP,
+        [116] = KEY_POWER,
+        [117] = KEY_KPEQUAL,
+        [118] = KEY_KPPLUSMINUS,
+        [119] = KEY_PAUSE,
+        [120] = KEY_SCALE,
+        [121] = KEY_KPCOMMA,
+        [122] = KEY_HANGEUL,
+        [123] = KEY_HANGUEL,
+        [124] = KEY_HANJA,
+        [125] = KEY_YEN,
+        [126] = KEY_LEFTMETA,
+        [127] = KEY_RIGHTMETA,
+        [128] = KEY_COMPOSE,
+        [129] = NOKEY,
+        [130] = NOKEY,
+        [131] = NOKEY,
+        [132] = NOKEY,
+        [133] = NOKEY,
+        [134] = NOKEY,
+        [135] = NOKEY,
+        [136] = NOKEY,
+        [137] = NOKEY,
+        [138] = NOKEY,
+        [139] = NOKEY,
+        [140] = NOKEY,
+        [141] = NOKEY,
+        [142] = NOKEY,
+        [143] = NOKEY,
+        [144] = NOKEY,
+        [145] = NOKEY,
+        [146] = NOKEY,
+        [147] = NOKEY,
+        [148] = NOKEY,
+        [149] = NOKEY,
+        [150] = NOKEY,
+        [151] = NOKEY,
+        [152] = NOKEY,
+        [153] = NOKEY,
+        [154] = NOKEY,
+        [155] = NOKEY,
+        [156] = NOKEY,
+        [157] = NOKEY,
+        [158] = NOKEY,
+        [159] = NOKEY,
+        [160] = NOKEY,
+        [161] = NOKEY,
+        [162] = NOKEY,
+        [163] = NOKEY,
+        [164] = NOKEY,
+        [165] = NOKEY,
+        [166] = NOKEY,
+        [167] = NOKEY,
+        [168] = NOKEY,
+        [169] = NOKEY,
+        [170] = NOKEY,
+        [171] = NOKEY,
+        [172] = NOKEY,
+        [173] = NOKEY,
+        [174] = NOKEY,
+        [175] = NOKEY,
+        [176] = NOKEY,
+        [177] = NOKEY,
+        [178] = NOKEY,
+        [179] = NOKEY,
+        [180] = NOKEY,
+        [181] = NOKEY,
+        [182] = NOKEY,
+        [183] = NOKEY,
+        [184] = NOKEY,
+        [185] = NOKEY,
+        [186] = NOKEY,
+        [187] = NOKEY,
+        [188] = NOKEY,
+        [189] = KEY_HOME,
+        [190] = NOKEY,
+        [191] = NOKEY,
+        [192] = NOKEY,
+        [193] = NOKEY,
+        [194] = NOKEY,
+        [195] = NOKEY,
+        [196] = NOKEY,
+        [197] = NOKEY,
+        [198] = NOKEY,
+        [199] = NOKEY,
+        [200] = NOKEY,
+        [201] = NOKEY,
+        [202] = NOKEY,
+        [203] = NOKEY,
+        [204] = NOKEY,
+        [205] = KEY_END,
+        [206] = NOKEY,
+        [207] = NOKEY,
+        [208] = NOKEY,
+        [209] = NOKEY,
+        [210] = NOKEY,
+        [211] = NOKEY,
+        [212] = NOKEY,
+        [213] = NOKEY,
+        [214] = NOKEY,
+        [215] = NOKEY,
+        [216] = NOKEY,
+        [217] = NOKEY,
+        [218] = NOKEY,
+        [219] = NOKEY,
+        [220] = KEY_VOLUMEUP,
+        [221] = KEY_BRIGHTNESSUP,
+        [222] = NOKEY,
+        [223] = NOKEY,
+        [224] = NOKEY,
+        [225] = NOKEY,
+        [226] = NOKEY,
+        [227] = NOKEY,
+        [228] = NOKEY,
+        [229] = NOKEY,
+        [230] = NOKEY,
+        [231] = NOKEY,
+        [232] = NOKEY,
+        [233] = NOKEY,
+        [234] = NOKEY,
+        [235] = NOKEY,
+        [236] = NOKEY,
+        [237] = KEY_VOLUMEDOWN,
+        [238] = NOKEY,
+        [239] = NOKEY,
+        [240] = NOKEY,
+        [241] = NOKEY,
+        [242] = NOKEY,
+        [243] = NOKEY,
+        [244] = NOKEY,
+        [245] = NOKEY,
+        [246] = NOKEY,
+        [247] = NOKEY,
+        [248] = NOKEY,
+        [249] = NOKEY,
+        [250] = NOKEY,
+        [251] = NOKEY,
+        [252] = NOKEY,
+        [253] = KEY_BRIGHTNESSDOWN,
+        [254] = NOKEY,
+        [255] = NOKEY,
+};
+/*-----------------------------------------------------------------------------
+ * Global variables
+ *---------------------------------------------------------------------------*/
+
+struct input_dev *g_qci_keyboard_dev;
+
+/* General structure to hold the driver data */
+struct i2ckbd_drv_data {
+        struct i2c_client *ki2c_client;
+        struct work_struct work;
+        struct input_dev *qcikbd_dev;
+        unsigned int qcikbd_gpio; /* GPIO used for interrupt */
+        unsigned int qcikbd_irq;
+        unsigned int key_down;
+        unsigned int escape;
+        unsigned int pause_seq;
+        unsigned int fn;
+};
+#ifdef CONFIG_PM
+static int qcikbd_suspend(struct device *dev)
+{
+        return 0;
+}
+
+static int qcikbd_resume(struct device *dev)
+{
+        return 0;
+}
+#endif
+static int __devinit qcikbd_probe(struct i2c_client *client,
+        const struct i2c_device_id *id);
+static int __devexit qcikbd_remove(struct i2c_client *kbd);
+
+static const struct i2c_device_id qcikbd_idtable[] = {
+        { KEYBOARD_ID_NAME, 0 },
+        { }
+};
+
+MODULE_DEVICE_TABLE(i2c, qcikbd_idtable);
+
+#ifdef CONFIG_PM
+static struct dev_pm_ops qcikbd_pm_ops = {
+        .suspend  = qcikbd_suspend,
+        .resume   = qcikbd_resume,
+};
+#endif
+static struct i2c_driver i2ckbd_driver = {
+        .driver = {
+                .owner = THIS_MODULE,
+                .name  = KEYBOARD_ID_NAME,
+#ifdef CONFIG_PM
+                .pm = &qcikbd_pm_ops,
+#endif
+        },
+        .probe    = qcikbd_probe,
+        .remove = __devexit_p(qcikbd_remove),
+        .id_table = qcikbd_idtable,
+};
+
+/*-----------------------------------------------------------------------------
+ * Driver functions
+ *---------------------------------------------------------------------------*/
+
+static irqreturn_t qcikbd_interrupt(int irq, void *dev_id)
+{
+        struct i2ckbd_drv_data *ikbd_drv_data = dev_id;
+        schedule_work(&ikbd_drv_data->work);
+        return IRQ_HANDLED;
+}
+
+static void qcikbd_work_handler(struct work_struct *_work)
+{
+        unsigned char scancode;
+        unsigned int  keycode;
+
+        struct i2ckbd_drv_data *ikbd_drv_data =
+                container_of(_work, struct i2ckbd_drv_data, work);
+
+        struct i2c_client *ikbdclient = ikbd_drv_data->ki2c_client;
+        struct input_dev *ikbdev = ikbd_drv_data->qcikbd_dev;
+
+        scancode = i2c_smbus_read_byte(ikbdclient);
+      printk("   scancode = %x\n", scancode);
+
+        if (scancode == 0xFA)
+        {
+                return;
+        } else {
+                ikbd_drv_data->key_down = 1;
+                if (scancode & 0x80) {
+                        ikbd_drv_data->key_down = 0;
+                }
+                keycode = on2_keycode[(scancode & 0x7F)];
+                if (keycode != NOKEY) {
+
+                        input_event(ikbdev, EV_MSC, MSC_SCAN, scancode);
+
+                        input_report_key(ikbdev,
+                                         keycode,
+                                         ikbd_drv_data->key_down);
+                        input_sync(ikbdev);
+                }
+        }
+}
+
+
+static int qcikbd_open(struct input_dev *dev)
+{
+        struct i2ckbd_drv_data *ikbd_drv_data = input_get_drvdata(dev);
+        struct i2c_client *ikbdclient = ikbd_drv_data->ki2c_client;
+
+        /* Send F4h - enable keyboard */
+        i2c_smbus_write_byte(ikbdclient, KEYBOARD_CMD_ENABLE);
+        return 0;
+}
+
+static int __devinit qcikbd_probe(struct i2c_client *client,
+                                    const struct i2c_device_id *id)
+{
+        int err;
+        int i;
+        struct i2ckbd_drv_data *context;
+        context = kzalloc(sizeof(struct i2ckbd_drv_data), GFP_KERNEL);
+        if (!context)
+                return -ENOMEM;
+        i2c_set_clientdata(client, context);
+        context->ki2c_client = client;
+        context->qcikbd_gpio = client->irq;
+        client->driver = &i2ckbd_driver;
+
+        INIT_WORK(&context->work, qcikbd_work_handler);
+
+        err = gpio_request(context->qcikbd_gpio, "qci-kbd");
+        if (err) {
+                pr_err("[KBD] err gpio request\n");
+                goto gpio_request_fail;
+        }
+
+        context->qcikbd_irq = gpio_to_irq(context->qcikbd_gpio);
+        err = request_irq(context->qcikbd_irq,
+                          qcikbd_interrupt,
+                          IRQF_TRIGGER_FALLING,
+                          KEYBOARD_ID_NAME,
+                          context);
+        if (err) {
+                pr_err("[KBD] err unable to get IRQ\n");
+                goto request_irq_fail;
+        }
+
+        context->qcikbd_dev = input_allocate_device();
+        if (!context->qcikbd_dev) {
+                pr_err("[KBD]allocting memory err\n");
+                err = -ENOMEM;
+                goto allocate_fail;
+        }
+
+        context->qcikbd_dev->name       = KEYBOARD_NAME;
+        context->qcikbd_dev->phys       = KEYBOARD_DEVICE;
+        context->qcikbd_dev->id.bustype = BUS_I2C;
+        context->qcikbd_dev->id.vendor  = 0x1050;
+        context->qcikbd_dev->id.product = 0x0006;
+        context->qcikbd_dev->id.version = 0x0004;
+        context->qcikbd_dev->open       = qcikbd_open;
+        context->qcikbd_dev->evbit[0]   = BIT_MASK(EV_KEY);
+
+        /* Enable all supported keys */
+        for (i = 1; i < ARRAY_SIZE(on2_keycode) ; i++)
+                set_bit(on2_keycode[i], context->qcikbd_dev->keybit);
+
+        set_bit(KEY_POWER, context->qcikbd_dev->keybit);
+        set_bit(KEY_END, context->qcikbd_dev->keybit);
+        set_bit(KEY_VOLUMEUP, context->qcikbd_dev->keybit);
+        set_bit(KEY_VOLUMEDOWN, context->qcikbd_dev->keybit);
+        set_bit(KEY_ZOOMIN, context->qcikbd_dev->keybit);
+        set_bit(KEY_ZOOMOUT, context->qcikbd_dev->keybit);
+
+        input_set_drvdata(context->qcikbd_dev, context);
+        err = input_register_device(context->qcikbd_dev);
+        if (err) {
+                pr_err("[KBD] err input register device\n");
+                goto register_fail;
+        }
+        g_qci_keyboard_dev = context->qcikbd_dev;
+	printk("QCI_KBD PROBE\n");
+        return 0;
+register_fail:
+        input_free_device(context->qcikbd_dev);
+
+allocate_fail:
+        free_irq(context->qcikbd_irq, context);
+
+request_irq_fail:
+        gpio_free(context->qcikbd_gpio);
+
+gpio_request_fail:
+        i2c_set_clientdata(client, NULL);
+        kfree(context);
+        return err;
+}
+
+static int __devexit qcikbd_remove(struct i2c_client *dev)
+{
+        struct i2ckbd_drv_data *context = i2c_get_clientdata(dev);
+
+        free_irq(context->qcikbd_irq, context);
+        gpio_free(context->qcikbd_gpio);
+        input_free_device(context->qcikbd_dev);
+        input_unregister_device(context->qcikbd_dev);
+        kfree(context);
+
+        return 0;
+}
+
+static int __init qcikbd_init(void)
+{
+        return i2c_add_driver(&i2ckbd_driver);
+}
+
+static void __exit qcikbd_exit(void)
+{
+        i2c_del_driver(&i2ckbd_driver);
+}
+
+struct input_dev *nkbc_keypad_get_input_dev(void)
+{
+        return g_qci_keyboard_dev;
+}
+EXPORT_SYMBOL(nkbc_keypad_get_input_dev);
+module_init(qcikbd_init);
+module_exit(qcikbd_exit);
+
+MODULE_AUTHOR("Quanta Computer Inc.");
+MODULE_DESCRIPTION("Quanta Embedded Controller I2C Keyboard Driver");
+MODULE_LICENSE("GPL v2");
+