diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-09-13 21:16:56 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-09-13 21:16:56 -0700 |
commit | fc8e1ead9314cf0e0f1922e661428b93d3a50d88 (patch) | |
tree | f3cb97c4769b74f6627a59769f1ed5c92a13c58a /drivers/input/keyboard | |
parent | 2bcaa6a4238094c5695d5b1943078388d82d3004 (diff) | |
parent | 9de48cc300fb10f7d9faa978670becf5e352462a (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/Kconfig | 26 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 43 | ||||
-rw-r--r-- | drivers/input/keyboard/bf54x-keys.c | 26 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 19 | ||||
-rw-r--r-- | drivers/input/keyboard/hil_kbd.c | 607 | ||||
-rw-r--r-- | drivers/input/keyboard/lkkbd.c | 62 | ||||
-rw-r--r-- | drivers/input/keyboard/matrix_keypad.c | 15 | ||||
-rw-r--r-- | drivers/input/keyboard/pxa27x_keypad.c | 217 | ||||
-rw-r--r-- | drivers/input/keyboard/sh_keysc.c | 22 | ||||
-rw-r--r-- | drivers/input/keyboard/sunkbd.c | 142 | ||||
-rw-r--r-- | drivers/input/keyboard/tosakbd.c | 18 | ||||
-rw-r--r-- | drivers/input/keyboard/twl4030_keypad.c | 480 | ||||
-rw-r--r-- | drivers/input/keyboard/w90p910_keypad.c | 281 |
14 files changed, 1496 insertions, 464 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a6b989a9dc0..3525c19be42 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -187,7 +187,7 @@ config KEYBOARD_HIL_OLD submenu. config KEYBOARD_HIL - tristate "HP HIL keyboard support" + tristate "HP HIL keyboard/pointer support" depends on GSC || HP300 default y select HP_SDC @@ -196,7 +196,8 @@ config KEYBOARD_HIL help The "Human Interface Loop" is a older, 8-channel USB-like controller used in several Hewlett Packard models. - This driver implements support for HIL-keyboards attached + This driver implements support for HIL-keyboards and pointing + devices (mice, tablets, touchscreens) attached to your machine, so normally you should say Y here. config KEYBOARD_HP6XX @@ -329,6 +330,17 @@ config KEYBOARD_OMAP To compile this driver as a module, choose M here: the module will be called omap-keypad. +config KEYBOARD_TWL4030 + tristate "TI TWL4030/TWL5030/TPS659x0 keypad support" + depends on TWL4030_CORE + help + Say Y here if your board use the keypad controller on + TWL4030 family chips. It's safe to say enable this + even on boards that don't use the keypad controller. + + To compile this driver as a module, choose M here: the + module will be called twl4030_keypad. + config KEYBOARD_TOSA tristate "Tosa keyboard" depends on MACH_TOSA @@ -361,4 +373,14 @@ config KEYBOARD_XTKBD To compile this driver as a module, choose M here: the module will be called xtkbd. +config KEYBOARD_W90P910 + tristate "W90P910 Matrix Keypad support" + depends on ARCH_W90X900 + help + Say Y here to enable the matrix keypad on evaluation board + based on W90P910. + + To compile this driver as a module, choose M here: the + module will be called w90p910_keypad. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b5b5eae9724..8a7a22b3026 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -30,4 +30,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o +obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o +obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 6c6a09b1c0f..c9523e48c6a 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -68,7 +68,9 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and * are loadable via a userland utility. */ -static const unsigned short atkbd_set2_keycode[512] = { +#define ATKBD_KEYMAP_SIZE 512 + +static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES @@ -99,7 +101,7 @@ static const unsigned short atkbd_set2_keycode[512] = { #endif }; -static const unsigned short atkbd_set3_keycode[512] = { +static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, @@ -200,8 +202,8 @@ struct atkbd { char phys[32]; unsigned short id; - unsigned short keycode[512]; - DECLARE_BITMAP(force_release_mask, 512); + unsigned short keycode[ATKBD_KEYMAP_SIZE]; + DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE); unsigned char set; unsigned char translated; unsigned char extra; @@ -253,6 +255,7 @@ static struct device_attribute atkbd_attr_##_name = \ __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); ATKBD_DEFINE_ATTR(extra); +ATKBD_DEFINE_ATTR(force_release); ATKBD_DEFINE_ATTR(scroll); ATKBD_DEFINE_ATTR(set); ATKBD_DEFINE_ATTR(softrepeat); @@ -272,6 +275,7 @@ ATKBD_DEFINE_RO_ATTR(err_count); static struct attribute *atkbd_attributes[] = { &atkbd_attr_extra.attr, + &atkbd_attr_force_release.attr, &atkbd_attr_scroll.attr, &atkbd_attr_set.attr, &atkbd_attr_softrepeat.attr, @@ -934,7 +938,7 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd) int i, j; memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); - bitmap_zero(atkbd->force_release_mask, 512); + bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); if (atkbd->translated) { for (i = 0; i < 128; i++) { @@ -1041,7 +1045,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) input_dev->keycodesize = sizeof(unsigned short); input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); - for (i = 0; i < 512; i++) + for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL) __set_bit(atkbd->keycode[i], input_dev->keybit); } @@ -1309,6 +1313,33 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun return count; } +static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf) +{ + size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, + atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); + + buf[len++] = '\n'; + buf[len] = '\0'; + + return len; +} + +static ssize_t atkbd_set_force_release(struct atkbd *atkbd, + const char *buf, size_t count) +{ + /* 64 bytes on stack should be acceptable */ + DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE); + int err; + + err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE); + if (err) + return err; + + memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask)); + return count; +} + + static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) { return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index d427f322e20..fe376a27fe5 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -184,14 +184,13 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) int i, error; if (!pdata->rows || !pdata->cols || !pdata->keymap) { - printk(KERN_ERR DRV_NAME - ": No rows, cols or keymap from pdata\n"); + dev_err(&pdev->dev, "no rows, cols or keymap from pdata\n"); return -EINVAL; } if (!pdata->keymapsize || pdata->keymapsize > (pdata->rows * pdata->cols)) { - printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n"); + dev_err(&pdev->dev, "invalid keymapsize\n"); return -EINVAL; } @@ -211,8 +210,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT || !pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) { - printk(KERN_WARNING DRV_NAME - ": Invalid Debounce/Columndrive Time in platform data\n"); + dev_warn(&pdev->dev, + "invalid platform debounce/columndrive time\n"); bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */ } else { bfin_write_KPAD_MSEL( @@ -231,16 +230,14 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows], DRV_NAME)) { - printk(KERN_ERR DRV_NAME - ": Requesting Peripherals failed\n"); + dev_err(&pdev->dev, "requesting peripherals failed\n"); error = -EFAULT; goto out0; } if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols], DRV_NAME)) { - printk(KERN_ERR DRV_NAME - ": Requesting Peripherals failed\n"); + dev_err(&pdev->dev, "requesting peripherals failed\n"); error = -EFAULT; goto out1; } @@ -254,9 +251,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) error = request_irq(bf54x_kpad->irq, bfin_kpad_isr, 0, DRV_NAME, pdev); if (error) { - printk(KERN_ERR DRV_NAME - ": unable to claim irq %d; error %d\n", - bf54x_kpad->irq, error); + dev_err(&pdev->dev, "unable to claim irq %d\n", + bf54x_kpad->irq); goto out2; } @@ -297,8 +293,7 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) error = input_register_device(input); if (error) { - printk(KERN_ERR DRV_NAME - ": Unable to register input device (%d)\n", error); + dev_err(&pdev->dev, "unable to register input device\n"); goto out4; } @@ -316,9 +311,6 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - printk(KERN_ERR DRV_NAME - ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq); - return 0; out4: diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index efed0c9e242..a88aff3816a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -216,8 +216,9 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) #ifdef CONFIG_PM -static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) +static int gpio_keys_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; @@ -234,8 +235,9 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int gpio_keys_resume(struct platform_device *pdev) +static int gpio_keys_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; @@ -251,19 +253,22 @@ static int gpio_keys_resume(struct platform_device *pdev) return 0; } -#else -#define gpio_keys_suspend NULL -#define gpio_keys_resume NULL + +static const struct dev_pm_ops gpio_keys_pm_ops = { + .suspend = gpio_keys_suspend, + .resume = gpio_keys_resume, +}; #endif static struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, .remove = __devexit_p(gpio_keys_remove), - .suspend = gpio_keys_suspend, - .resume = gpio_keys_resume, .driver = { .name = "gpio-keys", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &gpio_keys_pm_ops, +#endif } }; diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 6f356705ee3..c83f4b2ec7d 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -37,19 +37,19 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/semaphore.h> +#include <linux/completion.h> #include <linux/slab.h> #include <linux/pci_ids.h> -#define PREFIX "HIL KEYB: " -#define HIL_GENERIC_NAME "HIL keyboard" +#define PREFIX "HIL: " MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); -MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); +MODULE_DESCRIPTION("HIL keyboard/mouse driver"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("serio:ty03pr25id00ex*"); +MODULE_ALIAS("serio:ty03pr25id00ex*"); /* HIL keyboard */ +MODULE_ALIAS("serio:ty03pr25id0Fex*"); /* HIL mouse */ -#define HIL_KBD_MAX_LENGTH 16 +#define HIL_PACKET_MAX_LENGTH 16 #define HIL_KBD_SET1_UPBIT 0x01 #define HIL_KBD_SET1_SHIFT 1 @@ -67,308 +67,497 @@ static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly = static const char hil_language[][16] = { HIL_LOCALE_MAP }; -struct hil_kbd { +struct hil_dev { struct input_dev *dev; struct serio *serio; /* Input buffer and index for packets from HIL bus. */ - hil_packet data[HIL_KBD_MAX_LENGTH]; + hil_packet data[HIL_PACKET_MAX_LENGTH]; int idx4; /* four counts per packet */ /* Raw device info records from HIL bus, see hil.h for fields. */ - char idd[HIL_KBD_MAX_LENGTH]; /* DID byte and IDD record */ - char rsc[HIL_KBD_MAX_LENGTH]; /* RSC record */ - char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */ - char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */ + char idd[HIL_PACKET_MAX_LENGTH]; /* DID byte and IDD record */ + char rsc[HIL_PACKET_MAX_LENGTH]; /* RSC record */ + char exd[HIL_PACKET_MAX_LENGTH]; /* EXD record */ + char rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */ - /* Something to sleep around with. */ - struct semaphore sem; + struct completion cmd_done; + + bool is_pointer; + /* Extra device details needed for pointing devices. */ + unsigned int nbtn, naxes; + unsigned int btnmap[7]; }; -/* Process a complete packet after transfer from the HIL */ -static void hil_kbd_process_record(struct hil_kbd *kbd) +static bool hil_dev_is_command_response(hil_packet p) { - struct input_dev *dev = kbd->dev; - hil_packet *data = kbd->data; - hil_packet p; - int idx, i, cnt; + if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) + return false; - idx = kbd->idx4/4; - p = data[idx - 1]; + if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) + return false; - if ((p & ~HIL_CMDCT_POL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - goto report; - if ((p & ~HIL_CMDCT_RPL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) - goto report; + return true; +} + +static void hil_dev_handle_command_response(struct hil_dev *dev) +{ + hil_packet p; + char *buf; + int i, idx; + + idx = dev->idx4 / 4; + p = dev->data[idx - 1]; - /* Not a poll response. See if we are loading config records. */ switch (p & HIL_PKT_DATA_MASK) { case HIL_CMD_IDD: - for (i = 0; i < idx; i++) - kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->idd[i] = 0; + buf = dev->idd; break; case HIL_CMD_RSC: - for (i = 0; i < idx; i++) - kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->rsc[i] = 0; + buf = dev->rsc; break; case HIL_CMD_EXD: - for (i = 0; i < idx; i++) - kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->exd[i] = 0; + buf = dev->exd; break; case HIL_CMD_RNM: - for (i = 0; i < idx; i++) - kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH + 1; i++) - kbd->rnm[i] = '\0'; + dev->rnm[HIL_PACKET_MAX_LENGTH] = 0; + buf = dev->rnm; break; default: /* These occur when device isn't present */ - if (p == (HIL_ERR_INT | HIL_PKT_CMD)) - break; - /* Anything else we'd like to know about. */ - printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); - break; + if (p != (HIL_ERR_INT | HIL_PKT_CMD)) { + /* Anything else we'd like to know about. */ + printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); + } + goto out; } - goto out; - report: - cnt = 1; + for (i = 0; i < idx; i++) + buf[i] = dev->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_PACKET_MAX_LENGTH; i++) + buf[i] = 0; + out: + complete(&dev->cmd_done); +} + +static void hil_dev_handle_kbd_events(struct hil_dev *kbd) +{ + struct input_dev *dev = kbd->dev; + int idx = kbd->idx4 / 4; + int i; + switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { case HIL_POL_CHARTYPE_NONE: - break; + return; case HIL_POL_CHARTYPE_ASCII: - while (cnt < idx - 1) - input_report_key(dev, kbd->data[cnt++] & 0x7f, 1); + for (i = 1; i < idx - 1; i++) + input_report_key(dev, kbd->data[i] & 0x7f, 1); break; case HIL_POL_CHARTYPE_RSVD1: case HIL_POL_CHARTYPE_RSVD2: case HIL_POL_CHARTYPE_BINARY: - while (cnt < idx - 1) - input_report_key(dev, kbd->data[cnt++], 1); + for (i = 1; i < idx - 1; i++) + input_report_key(dev, kbd->data[i], 1); break; case HIL_POL_CHARTYPE_SET1: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET1_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET1_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT]; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; case HIL_POL_CHARTYPE_SET2: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET2_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET2_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = key >> HIL_KBD_SET2_SHIFT; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; case HIL_POL_CHARTYPE_SET3: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET3_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET3_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT]; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; } - out: - kbd->idx4 = 0; - up(&kbd->sem); + + input_sync(dev); } -static void hil_kbd_process_err(struct hil_kbd *kbd) +static void hil_dev_handle_ptr_events(struct hil_dev *ptr) +{ + struct input_dev *dev = ptr->dev; + int idx = ptr->idx4 / 4; + hil_packet p = ptr->data[idx - 1]; + int i, cnt, laxis; + bool absdev, ax16; + + if ((p & HIL_CMDCT_POL) != idx - 1) { + printk(KERN_WARNING PREFIX + "Malformed poll packet %x (idx = %i)\n", p, idx); + return; + } + + i = (p & HIL_POL_AXIS_ALT) ? 3 : 0; + laxis = (p & HIL_POL_NUM_AXES_MASK) + i; + + ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ + absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; + + for (cnt = 1; i < laxis; i++) { + unsigned int lo, hi, val; + + lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; + hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; + + if (absdev) { + val = lo + (hi << 8); +#ifdef TABLET_AUTOADJUST + if (val < dev->absmin[ABS_X + i]) + dev->absmin[ABS_X + i] = val; + if (val > dev->absmax[ABS_X + i]) + dev->absmax[ABS_X + i] = val; +#endif + if (i%3) val = dev->absmax[ABS_X + i] - val; + input_report_abs(dev, ABS_X + i, val); + } else { + val = (int) (((int8_t)lo) | ((int8_t)hi << 8)); + if (i % 3) + val *= -1; + input_report_rel(dev, REL_X + i, val); + } + } + + while (cnt < idx - 1) { + unsigned int btn = ptr->data[cnt++]; + int up = btn & 1; + + btn &= 0xfe; + if (btn == 0x8e) + continue; /* TODO: proximity == touch? */ + if (btn > 0x8c || btn < 0x80) + continue; + btn = (btn - 0x80) >> 1; + btn = ptr->btnmap[btn]; + input_report_key(dev, btn, !up); + } + + input_sync(dev); +} + +static void hil_dev_process_err(struct hil_dev *dev) { printk(KERN_WARNING PREFIX "errored HIL packet\n"); - kbd->idx4 = 0; - up(&kbd->sem); + dev->idx4 = 0; + complete(&dev->cmd_done); /* just in case somebody is waiting */ } -static irqreturn_t hil_kbd_interrupt(struct serio *serio, +static irqreturn_t hil_dev_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { - struct hil_kbd *kbd; + struct hil_dev *dev; hil_packet packet; int idx; - kbd = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + dev = serio_get_drvdata(serio); + BUG_ON(dev == NULL); - if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) { - hil_kbd_process_err(kbd); - return IRQ_HANDLED; + if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) { + hil_dev_process_err(dev); + goto out; } - idx = kbd->idx4/4; - if (!(kbd->idx4 % 4)) - kbd->data[idx] = 0; - packet = kbd->data[idx]; - packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8); - kbd->data[idx] = packet; + + idx = dev->idx4 / 4; + if (!(dev->idx4 % 4)) + dev->data[idx] = 0; + packet = dev->data[idx]; + packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8); + dev->data[idx] = packet; /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++(kbd->idx4)) % 4) - return IRQ_HANDLED; - if ((packet & 0xffff0000) != HIL_ERR_INT) { - hil_kbd_process_err(kbd); - return IRQ_HANDLED; + if ((++dev->idx4 % 4) == 0) { + if ((packet & 0xffff0000) != HIL_ERR_INT) { + hil_dev_process_err(dev); + } else if (packet & HIL_PKT_CMD) { + if (hil_dev_is_command_response(packet)) + hil_dev_handle_command_response(dev); + else if (dev->is_pointer) + hil_dev_handle_ptr_events(dev); + else + hil_dev_handle_kbd_events(dev); + dev->idx4 = 0; + } } - if (packet & HIL_PKT_CMD) - hil_kbd_process_record(kbd); + out: return IRQ_HANDLED; } -static void hil_kbd_disconnect(struct serio *serio) +static void hil_dev_disconnect(struct serio *serio) { - struct hil_kbd *kbd; + struct hil_dev *dev = serio_get_drvdata(serio); - kbd = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + BUG_ON(dev == NULL); serio_close(serio); - input_unregister_device(kbd->dev); - kfree(kbd); + input_unregister_device(dev->dev); + serio_set_drvdata(serio, NULL); + kfree(dev); +} + +static void hil_dev_keyboard_setup(struct hil_dev *kbd) +{ + struct input_dev *input_dev = kbd->dev; + uint8_t did = kbd->idd[0]; + int i; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | + BIT_MASK(LED_SCROLLL); + + for (i = 0; i < 128; i++) { + __set_bit(hil_kbd_set1[i], input_dev->keybit); + __set_bit(hil_kbd_set3[i], input_dev->keybit); + } + __clear_bit(KEY_RESERVED, input_dev->keybit); + + input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; + input_dev->keycodesize = sizeof(hil_kbd_set1[0]); + input_dev->keycode = hil_kbd_set1; + + input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard"; + input_dev->phys = "hpkbd/input0"; + + printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", + did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); } -static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) +static void hil_dev_pointer_setup(struct hil_dev *ptr) { - struct hil_kbd *kbd; - uint8_t did, *idd; - int i; + struct input_dev *input_dev = ptr->dev; + uint8_t did = ptr->idd[0]; + uint8_t *idd = ptr->idd + 1; + unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd); + unsigned int i, btntype; + const char *txt; + + ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); + + switch (did & HIL_IDD_DID_TYPE_MASK) { + case HIL_IDD_DID_TYPE_REL: + input_dev->evbit[0] = BIT_MASK(EV_REL); - kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); - if (!kbd) - return -ENOMEM; + for (i = 0; i < ptr->naxes; i++) + __set_bit(REL_X + i, input_dev->relbit); - kbd->dev = input_allocate_device(); - if (!kbd->dev) + for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) + __set_bit(REL_X + i, input_dev->relbit); + + txt = "relative"; + break; + + case HIL_IDD_DID_TYPE_ABS: + input_dev->evbit[0] = BIT_MASK(EV_ABS); + + for (i = 0; i < ptr->naxes; i++) + input_set_abs_params(input_dev, ABS_X + i, + 0, HIL_IDD_AXIS_MAX(idd, i), 0, 0); + + for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) + input_set_abs_params(input_dev, ABS_X + i, + 0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0); + +#ifdef TABLET_AUTOADJUST + for (i = 0; i < ABS_MAX; i++) { + int diff = input_dev->absmax[ABS_X + i] / 10; + input_dev->absmin[ABS_X + i] += diff; + input_dev->absmax[ABS_X + i] -= diff; + } +#endif + + txt = "absolute"; + break; + + default: + BUG(); + } + + ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); + if (ptr->nbtn) + input_dev->evbit[0] |= BIT_MASK(EV_KEY); + + btntype = BTN_MISC; + if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) +#ifdef TABLET_SIMULATES_MOUSE + btntype = BTN_TOUCH; +#else + btntype = BTN_DIGI; +#endif + if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) + btntype = BTN_TOUCH; + + if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) + btntype = BTN_MOUSE; + + for (i = 0; i < ptr->nbtn; i++) { + __set_bit(btntype | i, input_dev->keybit); + ptr->btnmap[i] = btntype | i; + } + + if (btntype == BTN_MOUSE) { + /* Swap buttons 2 and 3 */ + ptr->btnmap[1] = BTN_MIDDLE; + ptr->btnmap[2] = BTN_RIGHT; + } + + input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device"; + + printk(KERN_INFO PREFIX + "HIL pointer device found (did: 0x%02x, axis: %s)\n", + did, txt); + printk(KERN_INFO PREFIX + "HIL pointer has %i buttons and %i sets of %i axes\n", + ptr->nbtn, naxsets, ptr->naxes); +} + +static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) +{ + struct hil_dev *dev; + struct input_dev *input_dev; + uint8_t did, *idd; + int error; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!dev || !input_dev) { + error = -ENOMEM; goto bail0; + } - if (serio_open(serio, drv)) - goto bail1; + dev->serio = serio; + dev->dev = input_dev; - serio_set_drvdata(serio, kbd); - kbd->serio = serio; + error = serio_open(serio, drv); + if (error) + goto bail0; - init_MUTEX_LOCKED(&kbd->sem); + serio_set_drvdata(serio, dev); /* Get device info. MLC driver supplies devid/status/etc. */ - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_IDD); - down(&kbd->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RSC); - down(&kbd->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RNM); - down(&kbd->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_EXD); - down(&kbd->sem); - - up(&kbd->sem); - - did = kbd->idd[0]; - idd = kbd->idd + 1; + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_IDD); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RSC); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RNM); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_EXD); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + did = dev->idd[0]; + idd = dev->idd + 1; + switch (did & HIL_IDD_DID_TYPE_MASK) { case HIL_IDD_DID_TYPE_KB_INTEGRAL: case HIL_IDD_DID_TYPE_KB_ITF: case HIL_IDD_DID_TYPE_KB_RSVD: case HIL_IDD_DID_TYPE_CHAR: - printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", - did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); - break; - default: - goto bail2; - } + if (HIL_IDD_NUM_BUTTONS(idd) || + HIL_IDD_NUM_AXES_PER_SET(*idd)) { + printk(KERN_INFO PREFIX + "combo devices are not supported.\n"); + goto bail1; + } - if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { - printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); - goto bail2; - } + dev->is_pointer = false; + hil_dev_keyboard_setup(dev); + break; - kbd->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - kbd->dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | - BIT_MASK(LED_SCROLLL); - kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; - kbd->dev->keycodesize = sizeof(hil_kbd_set1[0]); - kbd->dev->keycode = hil_kbd_set1; - kbd->dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; - kbd->dev->phys = "hpkbd/input0"; /* XXX */ - - kbd->dev->id.bustype = BUS_HIL; - kbd->dev->id.vendor = PCI_VENDOR_ID_HP; - kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ - kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ - kbd->dev->dev.parent = &serio->dev; + case HIL_IDD_DID_TYPE_REL: + case HIL_IDD_DID_TYPE_ABS: + dev->is_pointer = true; + hil_dev_pointer_setup(dev); + break; - for (i = 0; i < 128; i++) { - set_bit(hil_kbd_set1[i], kbd->dev->keybit); - set_bit(hil_kbd_set3[i], kbd->dev->keybit); + default: + goto bail1; } - clear_bit(0, kbd->dev->keybit); - input_register_device(kbd->dev); - printk(KERN_INFO "input: %s, ID: %d\n", - kbd->dev->name, did); + input_dev->id.bustype = BUS_HIL; + input_dev->id.vendor = PCI_VENDOR_ID_HP; + input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ + input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ + input_dev->dev.parent = &serio->dev; + + if (!dev->is_pointer) { + |