aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/keyboard/jornada680_kbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/keyboard/jornada680_kbd.c')
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c182
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;
}