diff options
Diffstat (limited to 'drivers/input/keyboard/jornada680_kbd.c')
-rw-r--r-- | drivers/input/keyboard/jornada680_kbd.c | 182 |
1 files changed, 99 insertions, 83 deletions
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index 781fc61028606a..00d6261790be6e 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -2,7 +2,7 @@ * drivers/input/keyboard/jornada680_kbd.c * * HP Jornada 620/660/680/690 scan keyboard platform driver - * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> + * Copyright (C) 2007-2008 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> * * Based on hp680_keyb.c * Copyright (C) 2006 Paul Mundt @@ -18,16 +18,20 @@ #include <linux/init.h> #include <linux/input.h> -#include <linux/input-polldev.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/timer.h> +#include <linux/sched.h> +#include <asm/hp6xx.h> #include <asm/delay.h> #include <asm/io.h> +#define SCANHZ (HZ/20) + #define PCCR 0xa4000104 #define PDCR 0xa4000106 #define PECR 0xa4000108 @@ -42,7 +46,7 @@ #define PKDR 0xa4000132 #define PLDR 0xa4000134 -static const unsigned short jornada_scancodes[] = { +static const unsigned char jornada_scancodes[] = { /* PTD1 */ KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, KEY_KP5, 0, 0, /* 1 -> 8 */ KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F6, KEY_F4, KEY_F5, /* 9 -> 16 */ /* PTD5 */ KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0, /* 17 -> 24 */ @@ -59,56 +63,63 @@ static const unsigned short jornada_scancodes[] = { KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_Y, /* 105 -> 112 */ /* PTE7 */ KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0, /* 113 -> 120 */ KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6, /* 121 -> 128 */ -/* **** */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 }; -#define JORNADA_SCAN_SIZE 18 +#define JORNADA_SCAN_SIZE 16 /* 128 keys */ +#define JORNADA_EXTRN_KEYS 3 /* record / last / next */ + +struct timer_list scan_timer; struct jornadakbd { - struct input_polled_dev *poll_dev; - unsigned short keymap[ARRAY_SIZE(jornada_scancodes)]; - unsigned char length; - unsigned char old_scan[JORNADA_SCAN_SIZE]; - unsigned char new_scan[JORNADA_SCAN_SIZE]; + struct input_dev *jkbd; + unsigned char keymap[ARRAY_SIZE(jornada_scancodes)]; + unsigned char old_scan[JORNADA_SCAN_SIZE + 4]; + unsigned char new_scan[JORNADA_SCAN_SIZE + 4]; + unsigned short status_regs[JORNADA_EXTRN_KEYS]; + unsigned short new_status, old_status; }; -static void jornada_parse_kbd(struct jornadakbd *jornadakbd) +static DEFINE_SPINLOCK(jornada_kbd_lock); +static unsigned long jornada_kbd_flags; + +struct jornadakbd *jornkbd; + +static void jornada_parse_kbd(unsigned char *new, unsigned char *old) { - struct input_dev *input_dev = jornadakbd->poll_dev->input; - unsigned short *keymap = jornadakbd->keymap; + struct input_dev *jkbd = jornkbd->jkbd; + const unsigned char *table = jornkbd->keymap; unsigned int sync_me = 0; - unsigned int i, j; - - for (i = 0; i < JORNADA_SCAN_SIZE; i++) { - unsigned char new = jornadakbd->new_scan[i]; - unsigned char old = jornadakbd->old_scan[i]; - unsigned int xor = new ^ old; - - if (xor == 0) - continue; - - for (j = 0; j < 8; j++) { - unsigned int bit = 1 << j; - if (xor & bit) { - unsigned int scancode = (i << 3) + j; - input_event(input_dev, - EV_MSC, MSC_SCAN, scancode); - input_report_key(input_dev, - keymap[scancode], - !(new & bit)); - sync_me = 1; - } + int length = 16; + unsigned int xor, bit; + + while (length-- > 0) { + /* If both are same, then just skip that line */ + if ((xor = *new ^ *old) == 0) + table += 8; + else { /* here some key/s are changed, so run through bits to determine which line. */ + for (bit = 0x01; bit < 0x100; bit <<= 1) { + if (xor & bit) { + //input_event(jkbd, EV_MSC, MSC_SCAN, *table); + input_report_key(jkbd, *table, !(*new & bit)); + sync_me = 1; + } + + table++; } + } + + new++; + old++; } - + if (sync_me) - input_sync(input_dev); + input_sync(jkbd); } static void jornada_scan_keyb(unsigned char *s) { int i; + unsigned char junk; unsigned short ec_static, dc_static; /* = UINT16_t */ unsigned char matrix_switch[] = { 0xfd, 0xff, /* PTD1 PD(1) */ @@ -165,88 +176,93 @@ static void jornada_scan_keyb(unsigned char *s) ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR); /* Ignore extra keys and events */ - *s++ = ctrl_inb(PGDR); - *s++ = ctrl_inb(PHDR); + junk = ctrl_inb(PGDR); + junk = ctrl_inb(PHDR); } -static void jornadakbd680_poll(struct input_polled_dev *dev) +static void jkbd_poll(unsigned long jkbd_addr) { - struct jornadakbd *jornadakbd = dev->private; - - jornada_scan_keyb(jornadakbd->new_scan); - jornada_parse_kbd(jornadakbd); - memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE); + spin_lock_irqsave(&jornada_kbd_lock, jornada_kbd_flags); + + jornada_scan_keyb(jornkbd->new_scan); + jornada_parse_kbd(jornkbd->new_scan, jornkbd->old_scan); + memcpy(jornkbd->old_scan, jornkbd->new_scan, JORNADA_SCAN_SIZE); + + mod_timer(&scan_timer, jiffies + SCANHZ); + spin_unlock_irqrestore(&jornada_kbd_lock, jornada_kbd_flags); } static int __devinit jornada680kbd_probe(struct platform_device *pdev) { - struct jornadakbd *jornadakbd; - struct input_polled_dev *poll_dev; - struct input_dev *input_dev; + struct input_dev *jkbd; int i, error; + unsigned long jkbd_address; - jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); - if (!jornadakbd) + jornkbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); + if (!jornkbd) return -ENOMEM; - poll_dev = input_allocate_polled_device(); - if (!poll_dev) { + jkbd = input_allocate_device(); + if (!jkbd) { error = -ENOMEM; goto failed; } - platform_set_drvdata(pdev, jornadakbd); + memset(jornkbd->new_scan, -1, JORNADA_SCAN_SIZE); + memset(jornkbd->old_scan, -1, JORNADA_SCAN_SIZE); - jornadakbd->poll_dev = poll_dev; + platform_set_drvdata(pdev, jornkbd); + jornkbd->jkbd = jkbd; - memcpy(jornadakbd->keymap, jornada_scancodes, - sizeof(jornadakbd->keymap)); + memcpy(jornkbd->keymap, jornada_scancodes, + ARRAY_SIZE(jornada_scancodes)); - poll_dev->private = jornadakbd; - poll_dev->poll = jornadakbd680_poll; - poll_dev->poll_interval = 50; /* msec */ - - input_dev = poll_dev->input; - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - input_dev->name = "HP Jornada 680 keyboard"; - input_dev->phys = "jornadakbd/input0"; - input_dev->keycode = jornadakbd->keymap; - input_dev->keycodesize = sizeof(unsigned short); - input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes); - input_dev->dev.parent = &pdev->dev; - input_dev->id.bustype = BUS_HOST; + jkbd->private = jornkbd; + + jkbd->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + jkbd->name = "HP Jornada 680 keyboard"; + jkbd->phys = "jornadakbd/input0"; + jkbd->keycode = (unsigned char*)jornkbd->keymap; + jkbd->keycodesize = sizeof(unsigned char); + jkbd->keycodemax = ARRAY_SIZE(jornada_scancodes); + jkbd->dev.parent = &pdev->dev; + jkbd->id.bustype = BUS_HOST; for (i = 0; i < 128; i++) - if (jornadakbd->keymap[i]) - __set_bit(jornadakbd->keymap[i], input_dev->keybit); - __clear_bit(KEY_RESERVED, input_dev->keybit); - - input_set_capability(input_dev, EV_MSC, MSC_SCAN); - - error = input_register_polled_device(jornadakbd->poll_dev); + if (jornkbd->keymap[i]) + set_bit(jornkbd->keymap[i], jkbd->keybit); + clear_bit(0, jkbd->keybit); + + error = input_register_device(jkbd); if (error) goto failed; + init_timer(&scan_timer); + scan_timer.expires = jiffies + SCANHZ; + jkbd_address = 0; + jkbd_address = &jornkbd; + scan_timer.data = jkbd_address; + scan_timer.function = jkbd_poll; + add_timer(&scan_timer); + return 0; failed: printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n", error); platform_set_drvdata(pdev, NULL); - input_free_polled_device(poll_dev); - kfree(jornadakbd); + input_free_device(jkbd); + kfree(jornkbd); return error; } static int __devexit jornada680kbd_remove(struct platform_device *pdev) { - struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); - input_unregister_polled_device(jornadakbd->poll_dev); - input_free_polled_device(jornadakbd->poll_dev); - kfree(jornadakbd); + input_unregister_device(jornkbd->jkbd); + input_free_device(jornkbd->jkbd); + kfree(jornkbd); return 0; } |