> -----Original Message----- > From: linux-input-owner@xxxxxxxxxxxxxxx [mailto:linux-input- > owner@xxxxxxxxxxxxxxx] On Behalf Of Wayne Lin > Sent: Monday, July 26, 2010 2:00 PM > To: linux-input@xxxxxxxxxxxxxxx > Cc: wayne > Subject: [RFC 04/36] [Driver][Qualcomm 1070][EC_KB] Adding new qci > keyboard driver > > From: wayne <wayne.lin@xxxxxxxxxxxx> > > --- > drivers/input/keyboard/qci_kbd.c | 1101 +++++++++++++++++++-------------- > ----- > 1 files changed, 551 insertions(+), 550 deletions(-) > > 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@xxxxxxxxxxxx> > - * Author: Austin Lai <austin.lai@xxxxxxxxxxxx> > - * > - * 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@xxxxxxxxxxxx> > + * Author: Austin Lai <austin.lai@xxxxxxxxxxxx> > + * > + * 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; > +} If the functions are empty you may consider adding later > +#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); May consider use and KERN_XXX ? or may be pr_xx func > + > + 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); You may want to see the return val of the write? Else the return 0 may be misleading. > + 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); Free and then unregister ? Is it safe? > + 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"); > + > -- > 1.7.0.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-input" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html