linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [HP Jornada 6XX] - Onboard Keyboard support
       [not found] <20070721181549.9d118414.Kristoffer.Ericson@Gmail.com>
@ 2007-07-22  5:45 ` Dmitry Torokhov
  2007-07-22 15:59   ` Kristoffer Ericson
  2007-07-27  5:34   ` Kristoffer Ericson
  0 siblings, 2 replies; 14+ messages in thread
From: Dmitry Torokhov @ 2007-07-22  5:45 UTC (permalink / raw)
  To: Kristoffer Ericson; +Cc: linux-input

On Saturday 21 July 2007 21:15, Kristoffer Ericson wrote:
> Greetings,
> 
> Here we go again with another keyboard patch (this time for hp6xx).
> It consists of three files, where one contains the generic scan_keyb
> routines with needed header and the third is the specific hp6xx driver.

Please do not use scan_keyb. It goes around input core and directly into
legacy keyboard driver. For drivers that periodically poll/scan their
device input_polldev might be of interest.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-07-22  5:45 ` [HP Jornada 6XX] - Onboard Keyboard support Dmitry Torokhov
@ 2007-07-22 15:59   ` Kristoffer Ericson
  2007-07-27  5:34   ` Kristoffer Ericson
  1 sibling, 0 replies; 14+ messages in thread
From: Kristoffer Ericson @ 2007-07-22 15:59 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

Ah, I'll look into that then. Thx

On Sun, 22 Jul 2007 01:45:10 -0400
Dmitry Torokhov <dtor@insightbb.com> wrote:

> On Saturday 21 July 2007 21:15, Kristoffer Ericson wrote:
> > Greetings,
> > 
> > Here we go again with another keyboard patch (this time for hp6xx).
> > It consists of three files, where one contains the generic scan_keyb
> > routines with needed header and the third is the specific hp6xx driver.
> 
> Please do not use scan_keyb. It goes around input core and directly into
> legacy keyboard driver. For drivers that periodically poll/scan their
> device input_polldev might be of interest.
> 
> -- 
> Dmitry


-- 
Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-07-22  5:45 ` [HP Jornada 6XX] - Onboard Keyboard support Dmitry Torokhov
  2007-07-22 15:59   ` Kristoffer Ericson
@ 2007-07-27  5:34   ` Kristoffer Ericson
  2007-07-30 12:39     ` Dmitry Torokhov
  1 sibling, 1 reply; 14+ messages in thread
From: Kristoffer Ericson @ 2007-07-27  5:34 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

Dmitry,

Ive merged scan_keyb and started to minimize it for just one keyboard, just want to hear from you if this is an acceptable approach. 
Its a work in progress, just want to know if im on the right path.


Best wishes
Kristoffer


diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
new file mode 100644
index 0000000..0191628
--- /dev/null
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,283 @@
+/*
+ * drivers/input/keyboard/jornada680_keyb.c
+ *
+ * HP Jornada 680/690 Scan keyboard
+ *
+ *  Copyright (C) 2007  Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *
+ * Based on jornada680_keyb.c
+ */
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define SCANHZ (HZ/20)
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+/***************************************************************
+HP Jornada 680(SWEDISH version) keyboard
+[!] indicates Special Characters
+______________________________________________________________________
+| ESC     F1  F2   F3   F4   F5   F6   F7   F8   F9   F10        POWER|
+|  1    2    3    4    5    6    7    8    9    0    +   `    BKPSPACE|
+|*    Q    W    E    R    T    Y    U    I    O    P    !    ^   ENTER|
+| TAB   A    S    D    F    G    H    J    K    L    !    !   '  ENTER|
+| SHIFT   Z    X    C    V    B    N    M    ,    .    -     UP  SHIFT|
+| CTRL  WIN  ALT  ?  =======SPACE========  ALTG  DEL    LEF  DO  RI   ]
+-----------------------------------------------------------------------
+****************************************************************/
+
+static const unsigned char jornada_scancodes[] = {
+	/* PTD1 */
+	KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0,
+	0, 0, KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2,
+	KEY_F4, KEY_F5,
+	/* PTD5 */
+	KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0,
+	0, 0, KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA,
+	KEY_M, KEY_B, KEY_N,
+	/* PTD7 */
+	KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, KEY_KP4,
+	0, 0, KEY_LEFTALT, KEY_HANJA,
+	/* PTE0 */
+	0, 0, 0, 0, KEY_FINANCE, 0,
+	0, 0, KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT,
+	KEY_VOLUMEUP, 249, 0, 0,
+	/* PTE1 */
+	KEY_SEMICOLO, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0,
+	0, 0, KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,
+	/* PTE3 */
+	KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,
+	0, 0, KEY_LEFTSHIFT, 0, 0, 0,
+	0, 0, 0,
+	/* PTE6 */
+	KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0,
+	0, KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,
+	/* PTE7 */
+	KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0,
+	0, KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6,
+	/* **** */
+	0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0,
+};
+
+struct jornadakbd {
+	unsigned char jornada_keymap[ARRAY_SIZE(jornada_keycodes)];
+	struct input_dev *input;
+	int length = 16;
+	int s0[16], s1[16];
+};
+
+/* Our global structures */
+struct jornadakbd *jornadakbd;
+struct timer_list scan_timer;
+static int scan_jiffies;
+
+static check_kbd(unsigned char *new, unsigned char *old)
+{
+    unsigned char *table = jornadakbd->jornada_keymap;
+    unsigned length = jornadakbd->length;
+    unsigned int xor,bit;
+
+    while (lenght-- > 0) {
+	/* if 0 (false) then they are both true or both false */
+	if ((xor = *new ^ *old) == 0)
+	    table += 8;
+	/* if 1 (true) then one is true and other is false */
+	else {
+		for (bit = 0x01; bit < 0x100; bit <<= 1) {
+		    if (xor & bit) {
+				input_report_key(jornadakbd->input, *table, !(*new & bit));
+				need_tasklet_schedule = 1;
+		    }
+		    table++;
+		}
+	}
+
+	new++;
+	old++;
+    }
+
+    if (need_tasklet_schedule) {
+	    input_sync(jornadakbd->input);
+	    tasklet_schedule(&keyboard_tasklet);
+    }
+}
+
+static void jornada_scan(unsigned long dummy)
+{
+    scan_jiffies++;
+
+    if (scan_jiffies & 1) {
+	/* This is always false */
+	if (!jornada_scan_keyb(jornadakbd->s0))
+	        check_kbd(jornadakbd->s0, jornadakbd->s1);
+	else
+		memcpy(jornadakbd->s0, jornadakbd->s1, jornadakbd->length);
+    } else {
+	/* This is always false? */
+	if (!jornada_scan_keyb(jornadakbd->s1))
+		check_kbd(jornadakbd->s1, jornadakbd->s0);
+	else
+		memcpy(jornadakbd->s1, jornadakbd->s2, jornadakbd->length);
+    }
+
+    mod_timer(&scan_timer, jiffies + SCANHZ);
+}
+
+static int jornada_scan_keyb(unsigned char *s)
+{
+	int i;
+	unsigned short ec_static, dc_static; /* = UINT16_t */
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,   /* PTD1 PD(1) */
+		0xdf, 0xff,   /* PTD5 PD(5) */
+		0x7f, 0xff,   /* PTD7 PD(7) */
+		0xff, 0xfe,   /* PTE0 PE(0) */
+		0xff, 0xfd,   /* PTE1 PE(1) */
+		0xff, 0xf7,   /* PTE3 PE(3) */
+		0xff, 0xbf,   /* PTE6 PE(6) */
+		0xff, 0x7f,   /* PTE7 PE(7) */
+	}, *t = matrix_switch;
+	/* PD(x) :
+	1.   0xcc0c & (1~(1 << (2*(x)+1)))))
+	2.   (0xf0cf & 0xfffff) */
+	/* PE(x) :
+	1.   0xcc0c & 0xffff
+	2.   0xf0cf & (1~(1 << (2*(x)+1))))) */
+	unsigned short matrix_PDE[] = {
+		0xcc04, 0xf0cf,  /* PD(1) */
+		0xc40c, 0xf0cf,	 /* PD(5) */
+		0x4c0c, 0xf0cf,  /* PD(7) */
+		0xcc0c, 0xf0cd,  /* PE(0) */
+		0xcc0c, 0xf0c7,	 /* PE(1) */
+		0xcc0c, 0xf04f,  /* PE(3) */
+		0xcc0c, 0xd0cf,	 /* PE(6) */
+		0xcc0c, 0x70cf,	 /* PE(7) */
+	}, *y = matrix_PDE;
+	/* Save these control reg bits */
+	dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+	ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+	for (i = 0; i < 8; i++) {
+		/* disable output for all but the one we want to scan */
+		ctrl_outw((dc_static | *y++), PDCR);
+		ctrl_outw((ec_static | *y++), PECR);
+		udelay(5);
+
+		/* Get scanline row */
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+
+		/* Read data */
+		*s++ = ctrl_inb(PCDR);
+		*s++ = ctrl_inb(PFDR);
+	}
+	/* Scan no lines */
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
+
+	/* Enable all scanlines */
+	ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+	ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+	/* Ignore extra keys and events */
+	*s++ = ctrl_inb(PGDR);
+	*s++ = ctrl_inb(PHDR);
+
+	return 0;
+}
+
+static struct platform_driver jornada680_kbd_driver = {
+	.driver		= {
+			    .name	= "jornada680_kbd",
+			},
+	.probe		= jornada680_kbd_probe,
+	.remove		= jornada680_kbd_remove,
+};
+
+static int __init jornada680_kbd_probe(struct platform_device *pdev)
+{
+	struct input_dev *input_dev;
+	int i, err, ret;
+
+	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+	if (!jornadakbd)
+	    return -ENOMEM;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+	    goto failed;
+
+	platform_set_drvdata(pdev, jornadakbd);
+
+	input_dev->dev.parent = &pdev.dev;
+	jornadakbd->input = input_dev;
+
+	memcpy(jornadakbd->jornada_keymap, jornada_normal_keymap, sizeof(jornadakbd->jornada_keymap));
+
+	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->jornada_keymap;
+	input_dev->keycodesize = sizeof(unsigned char);
+	input_dev->keycodemax = ARRAY_SIZE(jornada_normal_keymap);
+
+	for (i = 0; i < ARRAY_SIZE(jornada_scancodes); i++)
+		set_bit(jornadakbd->jornada_keymap[i], input_dev->keybit);
+
+	input_register_device(jornadakbd->input);
+
+	init_timer(&scan_timer);
+	scan_timer.expires = jiffies + SCANHZ;
+	scan_timer.data	   = 0;
+	scan_timer.function = scan_kbd;
+	add_timer(&scan_timer);
+
+	return 0;
+
+failed:
+	kfree(jornadakbd);
+
+}
+
+static int jornada680_kbd_remove(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+	del_timer_sync(&scan_timer);
+	input_unregister_device(jornadakbd->input);
+	kfree(jornadakbd);
+}
+
+static int __devinit jornada680_kbd_init(void)
+{
+	return platform_driver_register(&jornada680_kbd_driver);
+}
+
+static void __exit hp680_kbd_exit(void)
+{
+	platform_driver_unregister(&jornada680_kbd_driver);
+}
+
+module_init(hp680_kbd_init_hw);
+module_exit(hp680_kbd_exit_hw);
+MODULE_LICENSE("GPL");



On Sun, 22 Jul 2007 01:45:10 -0400
Dmitry Torokhov <dtor@insightbb.com> wrote:

> On Saturday 21 July 2007 21:15, Kristoffer Ericson wrote:
> > Greetings,
> > 
> > Here we go again with another keyboard patch (this time for hp6xx).
> > It consists of three files, where one contains the generic scan_keyb
> > routines with needed header and the third is the specific hp6xx driver.
> 
> Please do not use scan_keyb. It goes around input core and directly into
> legacy keyboard driver. For drivers that periodically poll/scan their
> device input_polldev might be of interest.
> 
> -- 
> Dmitry


-- 
Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-07-27  5:34   ` Kristoffer Ericson
@ 2007-07-30 12:39     ` Dmitry Torokhov
  2007-08-01  5:50       ` Kristoffer Ericson
                         ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Dmitry Torokhov @ 2007-07-30 12:39 UTC (permalink / raw)
  To: Kristoffer Ericson; +Cc: linux-input

Hi Kristoffer,

On 7/27/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> Dmitry,
>
> Ive merged scan_keyb and started to minimize it for just one keyboard, just want to hear from you if this is an acceptable approach.
> Its a work in progress, just want to know if im on the right path.
>

Like I said, please look at input-polldev
(drivers/input/input-polldev.c). It takes care of setting up workqueue
used for polling and will only poll if there are users so the driver
only needs to provide miplementation of scan function. Take a look at
drivers/input/keyboard/aaed2000_kbd.c to see how it is used.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-07-30 12:39     ` Dmitry Torokhov
@ 2007-08-01  5:50       ` Kristoffer Ericson
  2007-08-26  3:57       ` Kristoffer Ericson
  2007-09-10 21:58       ` Kristoffer Ericson
  2 siblings, 0 replies; 14+ messages in thread
From: Kristoffer Ericson @ 2007-08-01  5:50 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

Greetings,

Ive added polldev now and the driver is mostly finished.
My questions :
The old driver used HZ/20 as timing frequency should I simply translate this to ms instead?

It needs some minor cleanup, but feels good. Anything I've missed?

Best wishes
Kristoffer



diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
new file mode 100644
index 0000000..21bdc4b
--- /dev/null
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,252 @@
+/*
+ * drivers/input/keyboard/jornada680_keyb.c
+ *
+ * HP Jornada 680/690 Scan keyboard
+ *
+ *  Copyright (C) 2007  Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *
+ * Based on jornada680_keyb.c
+ *
+ *
+ *
+ *
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define SCANHZ (HZ/20)
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static unsigned char jornada_scancodes[] = {
+/* PTD1 */	KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0, KEY_F1, KEY_F2,
+		KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5,
+/* PTD5 */	KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0, KEY_X, KEY_C, KEY_V,
+		KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,
+/* PTD7 */	KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT,
+		KEY_HANJA,
+/* PTE0 */	0, 0, 0, 0, KEY_FINANCE, 0, 0, 0, KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT,
+		KEY_VOLUMEUP, 249, 0, 0,
+/* PTE1 */	KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0, KEY_S, KEY_D,
+		KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,
+/* PTE3 */	KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,
+		0, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,
+/* PTE6 */	KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0,
+		0, KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,
+/* PTE7 */	KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0,
+		0, KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6,
+/* **** */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0
+};
+
+struct jornadakbd {
+	unsigned char jornada_keymap[ARRAY_SIZE(jornada_scancodes)];
+	struct input_polled_dev *poll_dev;
+	unsigned char length;
+	unsigned char s0[16], s1[16];
+};
+
+unsigned int scan_jiffies;
+
+void jornada_check_kbd(struct jornadakbd *jornadakbd, unsigned char *new, unsigned char *old)
+{
+	const unsigned char *table = jornadakbd->jornada_keymap;
+	unsigned char length = jornadakbd->length;
+	unsigned int bit, xor;
+
+	while (length-- > 0) {
+		if ((xor = *new ^ *old) == 0)
+		table += 8;
+		else {
+			for(bit = 0x01; bit < 0x100;bit <<= 1) {
+				if (xor & bit) {
+					input_report_key(jornadakbd->poll_dev, *table, !(*new & bit));
+					input_sync(jornadakbd->poll_dev);
+				}
+			}
+		}
+		new++;
+		old++;
+	}
+}
+
+int jornada_scan_keyb(unsigned char *s)
+{
+	int i;
+	unsigned short ec_static, dc_static; /* = UINT16_t */
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,   /* PTD1 PD(1) */
+		0xdf, 0xff,   /* PTD5 PD(5) */
+		0x7f, 0xff,   /* PTD7 PD(7) */
+		0xff, 0xfe,   /* PTE0 PE(0) */
+		0xff, 0xfd,   /* PTE1 PE(1) */
+		0xff, 0xf7,   /* PTE3 PE(3) */
+		0xff, 0xbf,   /* PTE6 PE(6) */
+		0xff, 0x7f,   /* PTE7 PE(7) */
+	}, *t = matrix_switch;
+	/* PD(x) :
+	1.   0xcc0c & (1~(1 << (2*(x)+1)))))
+	2.   (0xf0cf & 0xfffff) */
+	/* PE(x) :
+	1.   0xcc0c & 0xffff
+	2.   0xf0cf & (1~(1 << (2*(x)+1))))) */
+	unsigned short matrix_PDE[] = {
+		0xcc04, 0xf0cf,  /* PD(1) */
+		0xc40c, 0xf0cf,	 /* PD(5) */
+		0x4c0c, 0xf0cf,  /* PD(7) */
+		0xcc0c, 0xf0cd,  /* PE(0) */
+		0xcc0c, 0xf0c7,	 /* PE(1) */
+		0xcc0c, 0xf04f,  /* PE(3) */
+		0xcc0c, 0xd0cf,	 /* PE(6) */
+		0xcc0c, 0x70cf,	 /* PE(7) */
+	}, *y = matrix_PDE;
+	/* Save these control reg bits */
+	dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+	ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+	for (i = 0; i < 8; i++) {
+		/* disable output for all but the one we want to scan */
+		ctrl_outw((dc_static | *y++), PDCR);
+		ctrl_outw((ec_static | *y++), PECR);
+		udelay(5);
+
+		/* Get scanline row */
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+
+		/* Read data */
+		*s++ = ctrl_inb(PCDR);
+		*s++ = ctrl_inb(PFDR);
+	}
+	/* Scan no lines */
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
+
+	/* Enable all scanlines */
+	ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+	ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+	/* Ignore extra keys and events */
+	*s++ = ctrl_inb(PGDR);
+	*s++ = ctrl_inb(PHDR);
+
+	return 0;
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+    struct jornadakbd *jornadakbd = dev->private;
+    scan_jiffies++;
+
+    if (scan_jiffies & 1) {
+	if (!jornada_scan_keyb(jornadakbd->s0))
+	        jornada_check_kbd(jornadakbd, jornadakbd->s0, jornadakbd->s1);
+	else
+		memcpy(jornadakbd->s0, jornadakbd->s1, jornadakbd->length);
+    } else {
+	if (!jornada_scan_keyb(jornadakbd->s1))
+		jornada_check_kbd(jornadkbd, jornadakbd->s1, jornadakbd->s0);
+	else
+		memcpy(jornadakbd->s1, jornadakbd->s0, jornadakbd->length);
+    }
+}
+
+static int __devinit jornada680kbd_probe(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input_dev;
+	int i, error;
+
+	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+	if (!jornadakbd)
+	    return -ENOMEM;
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev)
+	    goto failed;
+
+	platform_set_drvdata(pdev, jornadakbd);
+
+	jornadakbd->poll_dev = poll_dev;
+
+	memcpy(jornadakbd->jornada_keymap, jornada_scancodes, sizeof(jornadakbd->jornada_keymap));
+
+	poll_dev->private = jornadakbd;
+	poll_dev->poll = jornadakbd680_poll;
+	poll_dev->poll_interval = SCAN_INTERVALL;
+
+	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->jornada_keymap;
+	input_dev->keycodesize = sizeof(unsigned char);
+	input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+	input_dev->dev.parent = &pdev->dev;
+
+	for (i = 0; i < ARRAY_SIZE(jornada_scancodes); i++)
+		set_bit(jornadakbd->jornada_keymap[i], input_dev->keybit);
+	clear_bit(0, input_dev->keybit);
+
+	error = input_register_polled_device(jornadakbd->poll_dev);
+	if (error)
+	    goto failed;
+
+	return 0;
+
+failed:
+	kfree(jornadakbd);
+	return -ENOMEM;
+
+}
+
+static int jornada680_kbd_remove(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+	input_unregister_polled_device(jornadakbd->poll_dev);
+	input_free_polled_device(jornadakbd->poll_dev);
+	kfree(jornadakbd);
+	return 0;
+}
+
+static struct platform_driver jornada680_kbd_driver = {
+	.driver	= {
+		    .name = "jornada680_kbd",
+		},
+	.probe = jornada680_kbd_probe,
+	.remove = jornada680_kbd_remove,
+};
+
+static int __init jornada680kbd_init(void)
+{
+	return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+	platform_driver_unregister(&jornada680kbd_driver);
+}



On Mon, 30 Jul 2007 08:39:20 -0400
"Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:

> Hi Kristoffer,
> 
> On 7/27/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > Dmitry,
> >
> > Ive merged scan_keyb and started to minimize it for just one keyboard, just want to hear from you if this is an acceptable approach.
> > Its a work in progress, just want to know if im on the right path.
> >
> 
> Like I said, please look at input-polldev
> (drivers/input/input-polldev.c). It takes care of setting up workqueue
> used for polling and will only poll if there are users so the driver
> only needs to provide miplementation of scan function. Take a look at
> drivers/input/keyboard/aaed2000_kbd.c to see how it is used.
> 
> -- 
> Dmitry


-- 
Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-07-30 12:39     ` Dmitry Torokhov
  2007-08-01  5:50       ` Kristoffer Ericson
@ 2007-08-26  3:57       ` Kristoffer Ericson
  2007-09-10 21:58       ` Kristoffer Ericson
  2 siblings, 0 replies; 14+ messages in thread
From: Kristoffer Ericson @ 2007-08-26  3:57 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

[-- Attachment #1: Type: text/plain, Size: 10614 bytes --]

Hey Dmitry,

Here's the new driver for HP Jornada onboard keyboard (HP6XX). It compiles cleanly and works perfectly. It uses the polldev that you
suggested.

On Mon, 30 Jul 2007 08:39:20 -0400
"Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:

> Hi Kristoffer,
> 
> On 7/27/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > Dmitry,
> >
> > Ive merged scan_keyb and started to minimize it for just one keyboard, just want to hear from you if this is an acceptable approach.
> > Its a work in progress, just want to know if im on the right path.
> >
> 
> Like I said, please look at input-polldev
> (drivers/input/input-polldev.c). It takes care of setting up workqueue
> used for polling and will only poll if there are users so the driver
> only needs to provide miplementation of scan function. Take a look at
> drivers/input/keyboard/aaed2000_kbd.c to see how it is used.
> 
> -- 
> Dmitry

diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
new file mode 100644
index 0000000..2575d88
--- /dev/null
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,276 @@
+/*
+ * 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>
+ *
+ * Based on hp680_keyb.c
+ *  Copyright (C) 2006 Paul Mundt
+ *  Copyright (C) 2005 Andriy Skulysh
+ * Splited from drivers/input/keyboard/hp600_keyb.c
+ *  Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
+ *  Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
+ *
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of the GNU General Public License version 2 as 
+ * published by the Free Software Foundation.
+ * 
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define SCANHZ (HZ/20)
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static unsigned char jornada_scancodes[] = {
+/* PTD1 */	KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0,	/*  1  -> 8   */
+		KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5,	/*  9  -> 16  */
+/* PTD5 */	KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0,	/*  17 -> 24  */
+		KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,	/*  25 -> 32  */
+/* PTD7 */	KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0,				/*  33 -> 40  */
+		0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA,			/*  41 -> 48  */
+/* PTE0 */	0, 0, 0, 0, KEY_FINANCE, 0, 0, 0,				/*  49 -> 56  */
+		KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /*  57 -> 64  */
+/* PTE1 */	KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/*  65 -> 72  */
+		KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,		/*  73 -> 80  */
+/* PTE3 */	KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0,	/*  81 -> 88  */
+		0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,				/*  89 -> 96  */
+/* PTE6 */	KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0,		/*  97 -> 104 */
+		KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,		/* 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
+};
+
+struct jornadakbd {
+	unsigned char jornada_keymap[ARRAY_SIZE(jornada_scancodes)];
+	struct input_polled_dev *poll_dev;
+	unsigned char length;
+	unsigned char s0[18], s1[18];
+};
+
+unsigned int scan_jiffies;
+
+void jornada_check_kbd(struct jornadakbd *jornadakbd, unsigned char *new, unsigned char *old)
+{
+	unsigned char *table = jornadakbd->jornada_keymap;
+	unsigned char length = jornadakbd->length;
+	unsigned int bit, xor;
+	unsigned int sync_me = 0;
+
+	while (length-- > 0) {
+		if ((xor = *new ^ *old) == 0)
+			table += 8;
+		else {
+			for (bit = 0x01; bit < 0x100;bit <<= 1) {
+				if (xor & bit) {
+					input_report_key(jornadakbd->poll_dev->input, *table, !(*new & bit));
+					sync_me = 1;
+				}
+
+				table++;
+			}
+		}
+
+		new++;
+		old++;
+	}
+	if (sync_me)
+	    input_sync(jornadakbd->poll_dev->input);
+
+}
+
+int jornada_scan_keyb(unsigned char *s)
+{
+	int i;
+	unsigned short ec_static, dc_static; /* = UINT16_t */
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,   /* PTD1 PD(1) */
+		0xdf, 0xff,   /* PTD5 PD(5) */
+		0x7f, 0xff,   /* PTD7 PD(7) */
+		0xff, 0xfe,   /* PTE0 PE(0) */
+		0xff, 0xfd,   /* PTE1 PE(1) */
+		0xff, 0xf7,   /* PTE3 PE(3) */
+		0xff, 0xbf,   /* PTE6 PE(6) */
+		0xff, 0x7f,   /* PTE7 PE(7) */
+	}, *t = matrix_switch;
+	/* PD(x) :
+	1.   0xcc0c & (1~(1 << (2*(x)+1)))))
+	2.   (0xf0cf & 0xfffff) */
+	/* PE(x) :
+	1.   0xcc0c & 0xffff
+	2.   0xf0cf & (1~(1 << (2*(x)+1))))) */
+	unsigned short matrix_PDE[] = {
+		0xcc04, 0xf0cf,  /* PD(1) */
+		0xc40c, 0xf0cf,	 /* PD(5) */
+		0x4c0c, 0xf0cf,  /* PD(7) */
+		0xcc0c, 0xf0cd,  /* PE(0) */
+		0xcc0c, 0xf0c7,	 /* PE(1) */
+		0xcc0c, 0xf04f,  /* PE(3) */
+		0xcc0c, 0xd0cf,	 /* PE(6) */
+		0xcc0c, 0x70cf,	 /* PE(7) */
+	}, *y = matrix_PDE;
+	/* Save these control reg bits */
+	dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+	ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+	for (i = 0; i < 8; i++) {
+		/* disable output for all but the one we want to scan */
+		ctrl_outw((dc_static | *y++), PDCR);
+		ctrl_outw((ec_static | *y++), PECR);
+		udelay(5);
+
+		/* Get scanline row */
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+
+		/* Read data */
+		*s++ = ctrl_inb(PCDR);
+		*s++ = ctrl_inb(PFDR);
+	}
+	/* Scan no lines */
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
+
+	/* Enable all scanlines */
+	ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+	ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+	/* Ignore extra keys and events */
+	*s++ = ctrl_inb(PGDR);
+	*s++ = ctrl_inb(PHDR);
+
+	return 0;
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+    struct jornadakbd *jornadakbd = dev->private;
+    scan_jiffies++;
+
+	if (scan_jiffies & 1) {
+		if (!jornada_scan_keyb(jornadakbd->s0))
+			jornada_check_kbd(jornadakbd, jornadakbd->s0, jornadakbd->s1);
+		else
+			memcpy(jornadakbd->s0, jornadakbd->s1, jornadakbd->length);
+	} else {
+		if (!jornada_scan_keyb(jornadakbd->s1))
+			jornada_check_kbd(jornadakbd, jornadakbd->s1, jornadakbd->s0);
+		else
+			memcpy(jornadakbd->s1, jornadakbd->s0, jornadakbd->length);
+		}
+}
+
+static int __init jornada680kbd_probe(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input_dev;
+	int i, error;
+
+	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+	if (!jornadakbd)
+		return -ENOMEM;
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev)
+		goto failed;
+
+	platform_set_drvdata(pdev, jornadakbd);
+
+	jornadakbd->poll_dev = poll_dev;
+	jornadakbd->length   = 18;
+
+	memcpy(jornadakbd->jornada_keymap, jornada_scancodes, sizeof(jornadakbd->jornada_keymap));
+
+	poll_dev->private = jornadakbd;
+	poll_dev->poll = jornadakbd680_poll;
+	poll_dev->poll_interval = (HZ/20);
+
+	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->jornada_keymap;
+	input_dev->keycodesize = sizeof(unsigned char);
+	input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+	input_dev->dev.parent = &pdev->dev;
+
+	for (i = 0; i < 128; i++)
+		if (jornadakbd->jornada_keymap[i])
+		    set_bit(jornadakbd->jornada_keymap[i], jornadakbd->poll_dev->input->keybit);
+
+	clear_bit(0, jornadakbd->poll_dev->input->keybit);
+
+	error = input_register_polled_device(jornadakbd->poll_dev);
+	if (error)
+	    goto failed;
+
+	printk(KERN_INFO "We have successfully registerd the keyboard driver\n");
+	return 0;
+
+failed:
+	printk(KERN_INFO "Jornadakbd: failed to register driver, bailing\n");
+	kfree(jornadakbd);
+	return -ENOMEM;
+
+}
+
+static int jornada680kbd_remove(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+	input_unregister_polled_device(jornadakbd->poll_dev);
+	input_free_polled_device(jornadakbd->poll_dev);
+	kfree(jornadakbd);
+	return 0;
+}
+
+static struct platform_driver jornada680kbd_driver = {
+	.driver	= {
+		    .name = "jornada680_kbd",
+		},
+	.probe = jornada680kbd_probe,
+	.remove = jornada680kbd_remove,
+};
+
+static int __devinit jornada680kbd_init(void)
+{
+	return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+	platform_driver_unregister(&jornada680kbd_driver);
+}
+
+module_init(jornada680kbd_init);
+module_exit(jornada680kbd_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 28d211b..7ecd2b0 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
+obj-$(CONFIG_KEYBOARD_HP6XX)		+= jornada680_kbd.o
 
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index c97d5eb..99fa19b 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -208,6 +208,14 @@ config KEYBOARD_HIL
 	  This driver implements support for HIL-keyboards attached
 	  to your machine, so normally you should say Y here.
 
+config KEYBOARD_HP6XX
+       tristate "HP Jornada 6XX Keyboard support"
+       depends on SH_HP6XX
+       select INPUT_POLLDEV
+       help
+    	   This adds support for the onboard keyboard found on
+	   HP Jornada 620/660/680/690.
+
 config KEYBOARD_OMAP
 	tristate "TI OMAP keypad support"
 	depends on (ARCH_OMAP1 || ARCH_OMAP2)

-- 
Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>

[-- Attachment #2: hp6xx-keyboard.patch --]
[-- Type: application/octet-stream, Size: 9648 bytes --]

diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
new file mode 100644
index 0000000..2575d88
--- /dev/null
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,276 @@
+/*
+ * 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>
+ *
+ * Based on hp680_keyb.c
+ *  Copyright (C) 2006 Paul Mundt
+ *  Copyright (C) 2005 Andriy Skulysh
+ * Splited from drivers/input/keyboard/hp600_keyb.c
+ *  Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
+ *  Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
+ *
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of the GNU General Public License version 2 as 
+ * published by the Free Software Foundation.
+ * 
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define SCANHZ (HZ/20)
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static unsigned char jornada_scancodes[] = {
+/* PTD1 */	KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0,	/*  1  -> 8   */
+		KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5,	/*  9  -> 16  */
+/* PTD5 */	KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0,	/*  17 -> 24  */
+		KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,	/*  25 -> 32  */
+/* PTD7 */	KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0,				/*  33 -> 40  */
+		0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA,			/*  41 -> 48  */
+/* PTE0 */	0, 0, 0, 0, KEY_FINANCE, 0, 0, 0,				/*  49 -> 56  */
+		KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /*  57 -> 64  */
+/* PTE1 */	KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/*  65 -> 72  */
+		KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,		/*  73 -> 80  */
+/* PTE3 */	KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0,	/*  81 -> 88  */
+		0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,				/*  89 -> 96  */
+/* PTE6 */	KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0,		/*  97 -> 104 */
+		KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,		/* 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
+};
+
+struct jornadakbd {
+	unsigned char jornada_keymap[ARRAY_SIZE(jornada_scancodes)];
+	struct input_polled_dev *poll_dev;
+	unsigned char length;
+	unsigned char s0[18], s1[18];
+};
+
+unsigned int scan_jiffies;
+
+void jornada_check_kbd(struct jornadakbd *jornadakbd, unsigned char *new, unsigned char *old)
+{
+	unsigned char *table = jornadakbd->jornada_keymap;
+	unsigned char length = jornadakbd->length;
+	unsigned int bit, xor;
+	unsigned int sync_me = 0;
+
+	while (length-- > 0) {
+		if ((xor = *new ^ *old) == 0)
+			table += 8;
+		else {
+			for (bit = 0x01; bit < 0x100;bit <<= 1) {
+				if (xor & bit) {
+					input_report_key(jornadakbd->poll_dev->input, *table, !(*new & bit));
+					sync_me = 1;
+				}
+
+				table++;
+			}
+		}
+
+		new++;
+		old++;
+	}
+	if (sync_me)
+	    input_sync(jornadakbd->poll_dev->input);
+
+}
+
+int jornada_scan_keyb(unsigned char *s)
+{
+	int i;
+	unsigned short ec_static, dc_static; /* = UINT16_t */
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,   /* PTD1 PD(1) */
+		0xdf, 0xff,   /* PTD5 PD(5) */
+		0x7f, 0xff,   /* PTD7 PD(7) */
+		0xff, 0xfe,   /* PTE0 PE(0) */
+		0xff, 0xfd,   /* PTE1 PE(1) */
+		0xff, 0xf7,   /* PTE3 PE(3) */
+		0xff, 0xbf,   /* PTE6 PE(6) */
+		0xff, 0x7f,   /* PTE7 PE(7) */
+	}, *t = matrix_switch;
+	/* PD(x) :
+	1.   0xcc0c & (1~(1 << (2*(x)+1)))))
+	2.   (0xf0cf & 0xfffff) */
+	/* PE(x) :
+	1.   0xcc0c & 0xffff
+	2.   0xf0cf & (1~(1 << (2*(x)+1))))) */
+	unsigned short matrix_PDE[] = {
+		0xcc04, 0xf0cf,  /* PD(1) */
+		0xc40c, 0xf0cf,	 /* PD(5) */
+		0x4c0c, 0xf0cf,  /* PD(7) */
+		0xcc0c, 0xf0cd,  /* PE(0) */
+		0xcc0c, 0xf0c7,	 /* PE(1) */
+		0xcc0c, 0xf04f,  /* PE(3) */
+		0xcc0c, 0xd0cf,	 /* PE(6) */
+		0xcc0c, 0x70cf,	 /* PE(7) */
+	}, *y = matrix_PDE;
+	/* Save these control reg bits */
+	dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+	ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+	for (i = 0; i < 8; i++) {
+		/* disable output for all but the one we want to scan */
+		ctrl_outw((dc_static | *y++), PDCR);
+		ctrl_outw((ec_static | *y++), PECR);
+		udelay(5);
+
+		/* Get scanline row */
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+
+		/* Read data */
+		*s++ = ctrl_inb(PCDR);
+		*s++ = ctrl_inb(PFDR);
+	}
+	/* Scan no lines */
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
+
+	/* Enable all scanlines */
+	ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+	ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+	/* Ignore extra keys and events */
+	*s++ = ctrl_inb(PGDR);
+	*s++ = ctrl_inb(PHDR);
+
+	return 0;
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+    struct jornadakbd *jornadakbd = dev->private;
+    scan_jiffies++;
+
+	if (scan_jiffies & 1) {
+		if (!jornada_scan_keyb(jornadakbd->s0))
+			jornada_check_kbd(jornadakbd, jornadakbd->s0, jornadakbd->s1);
+		else
+			memcpy(jornadakbd->s0, jornadakbd->s1, jornadakbd->length);
+	} else {
+		if (!jornada_scan_keyb(jornadakbd->s1))
+			jornada_check_kbd(jornadakbd, jornadakbd->s1, jornadakbd->s0);
+		else
+			memcpy(jornadakbd->s1, jornadakbd->s0, jornadakbd->length);
+		}
+}
+
+static int __init jornada680kbd_probe(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input_dev;
+	int i, error;
+
+	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+	if (!jornadakbd)
+		return -ENOMEM;
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev)
+		goto failed;
+
+	platform_set_drvdata(pdev, jornadakbd);
+
+	jornadakbd->poll_dev = poll_dev;
+	jornadakbd->length   = 18;
+
+	memcpy(jornadakbd->jornada_keymap, jornada_scancodes, sizeof(jornadakbd->jornada_keymap));
+
+	poll_dev->private = jornadakbd;
+	poll_dev->poll = jornadakbd680_poll;
+	poll_dev->poll_interval = (HZ/20);
+
+	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->jornada_keymap;
+	input_dev->keycodesize = sizeof(unsigned char);
+	input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+	input_dev->dev.parent = &pdev->dev;
+
+	for (i = 0; i < 128; i++)
+		if (jornadakbd->jornada_keymap[i])
+		    set_bit(jornadakbd->jornada_keymap[i], jornadakbd->poll_dev->input->keybit);
+
+	clear_bit(0, jornadakbd->poll_dev->input->keybit);
+
+	error = input_register_polled_device(jornadakbd->poll_dev);
+	if (error)
+	    goto failed;
+
+	printk(KERN_INFO "We have successfully registerd the keyboard driver\n");
+	return 0;
+
+failed:
+	printk(KERN_INFO "Jornadakbd: failed to register driver, bailing\n");
+	kfree(jornadakbd);
+	return -ENOMEM;
+
+}
+
+static int jornada680kbd_remove(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+	input_unregister_polled_device(jornadakbd->poll_dev);
+	input_free_polled_device(jornadakbd->poll_dev);
+	kfree(jornadakbd);
+	return 0;
+}
+
+static struct platform_driver jornada680kbd_driver = {
+	.driver	= {
+		    .name = "jornada680_kbd",
+		},
+	.probe = jornada680kbd_probe,
+	.remove = jornada680kbd_remove,
+};
+
+static int __devinit jornada680kbd_init(void)
+{
+	return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+	platform_driver_unregister(&jornada680kbd_driver);
+}
+
+module_init(jornada680kbd_init);
+module_exit(jornada680kbd_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 28d211b..7ecd2b0 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
+obj-$(CONFIG_KEYBOARD_HP6XX)		+= jornada680_kbd.o
 
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index c97d5eb..99fa19b 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -208,6 +208,14 @@ config KEYBOARD_HIL
 	  This driver implements support for HIL-keyboards attached
 	  to your machine, so normally you should say Y here.
 
+config KEYBOARD_HP6XX
+       tristate "HP Jornada 6XX Keyboard support"
+       depends on SH_HP6XX
+       select INPUT_POLLDEV
+       help
+    	   This adds support for the onboard keyboard found on
+	   HP Jornada 620/660/680/690.
+
 config KEYBOARD_OMAP
 	tristate "TI OMAP keypad support"
 	depends on (ARCH_OMAP1 || ARCH_OMAP2)

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-09-10 21:58       ` Kristoffer Ericson
@ 2007-09-10 13:01         ` Dmitry Torokhov
  2007-09-11  8:22           ` Kristoffer Ericson
  0 siblings, 1 reply; 14+ messages in thread
From: Dmitry Torokhov @ 2007-09-10 13:01 UTC (permalink / raw)
  To: Kristoffer Ericson; +Cc: linux-input

[-- Attachment #1: Type: text/plain, Size: 1057 bytes --]

On 9/10/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> Greetings,
>
> I've sent this patch a couple of times now without receiving any response, so here goes again.

Argh, that's what I needed to do over the weekend... Sorry...

OK, I looked over the patch and it is in a pretty decent shape, here
is the only thing that bothers me:
> +
> +static void jornadakbd680_poll(struct input_polled_dev *dev)
> +{
> +    struct jornadakbd *jornadakbd = dev->private;
> +    scan_jiffies++;
> +
> +       if (scan_jiffies & 1) {
> +               if (!jornada_scan_keyb(jornadakbd->s0))
> +                       jornada_check_kbd(jornadakbd, jornadakbd->s0, jornadakbd->s1);
> +               else
> +                       memcpy(jornadakbd->s0, jornadakbd->s1, jornadakbd->length);

jornada_scan_keyb appears to always return 0 so this copy never takes
place. Overall I find this poll routine a bit complicated. I am
attaching a patch that has it impoemented a bit differently, could you
tell me if it is still works for you?

Thanks!

-- 
Dmitry

[-- Attachment #2: hp6xx-keyboard.patch --]
[-- Type: application/octet-stream, Size: 9939 bytes --]

From: Kristoffer Ericson <kristoffer.ericson@gmail.com>

Input: add support for HP Jornada onboard keyboard (HP6XX)

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
 drivers/input/keyboard/Kconfig          |   11 +
 drivers/input/keyboard/Makefile         |    1 
 drivers/input/keyboard/jornada680_kbd.c |  272 ++++++++++++++++++++++++++++++++
 3 files changed, 284 insertions(+)

Index: linux/drivers/input/keyboard/jornada680_kbd.c
===================================================================
--- /dev/null
+++ linux/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,272 @@
+/*
+ * 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>
+ *
+ * Based on hp680_keyb.c
+ *  Copyright (C) 2006 Paul Mundt
+ *  Copyright (C) 2005 Andriy Skulysh
+ * Split from drivers/input/keyboard/hp600_keyb.c
+ *  Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
+ *  Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static const unsigned char jornada_scancodes[] = {
+/* PTD1 */	KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0,	/*  1  -> 8   */
+		KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5,	/*  9  -> 16  */
+/* PTD5 */	KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0,	/*  17 -> 24  */
+		KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,	/*  25 -> 32  */
+/* PTD7 */	KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0,				/*  33 -> 40  */
+		0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA,			/*  41 -> 48  */
+/* PTE0 */	0, 0, 0, 0, KEY_FINANCE, 0, 0, 0,				/*  49 -> 56  */
+		KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /*  57 -> 64  */
+/* PTE1 */	KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/*  65 -> 72  */
+		KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,		/*  73 -> 80  */
+/* PTE3 */	KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0,	/*  81 -> 88  */
+		0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,				/*  89 -> 96  */
+/* PTE6 */	KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0,		/*  97 -> 104 */
+		KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,		/* 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
+
+struct jornadakbd {
+	struct input_polled_dev *poll_dev;
+	unsigned char keymap[ARRAY_SIZE(jornada_scancodes)];
+	unsigned char length;
+	unsigned char old_scan[JORNADA_SCAN_SIZE];
+	unsigned char new_scan[JORNADA_SCAN_SIZE];
+};
+
+static void jornada_parse_kbd(struct jornadakbd *jornadakbd)
+{
+	struct input_dev *input_dev = jornadakbd->poll_dev->input;
+	unsigned char *keymap = jornadakbd->keymap;
+	unsigned int sync_me = 0;
+	int i;
+
+	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;
+		unsigned int bit;
+
+		if (xor == 0)
+			continue;
+
+		for (bit = 0x01; bit < 0x100; bit <<= 1) {
+			if (xor & bit) {
+				input_report_key(input_dev,
+						 keymap[(i << 3) + bit],
+						 !(new & bit));
+				sync_me = 1;
+			}
+		}
+	}
+
+	if (sync_me)
+	    input_sync(input_dev);
+}
+
+static void jornada_scan_keyb(unsigned char *s)
+{
+	int i;
+	unsigned short ec_static, dc_static; /* = UINT16_t */
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,   /* PTD1 PD(1) */
+		0xdf, 0xff,   /* PTD5 PD(5) */
+		0x7f, 0xff,   /* PTD7 PD(7) */
+		0xff, 0xfe,   /* PTE0 PE(0) */
+		0xff, 0xfd,   /* PTE1 PE(1) */
+		0xff, 0xf7,   /* PTE3 PE(3) */
+		0xff, 0xbf,   /* PTE6 PE(6) */
+		0xff, 0x7f,   /* PTE7 PE(7) */
+	}, *t = matrix_switch;
+	/* PD(x) :
+	1.   0xcc0c & (1~(1 << (2*(x)+1)))))
+	2.   (0xf0cf & 0xfffff) */
+	/* PE(x) :
+	1.   0xcc0c & 0xffff
+	2.   0xf0cf & (1~(1 << (2*(x)+1))))) */
+	unsigned short matrix_PDE[] = {
+		0xcc04, 0xf0cf,  /* PD(1) */
+		0xc40c, 0xf0cf,	 /* PD(5) */
+		0x4c0c, 0xf0cf,  /* PD(7) */
+		0xcc0c, 0xf0cd,  /* PE(0) */
+		0xcc0c, 0xf0c7,	 /* PE(1) */
+		0xcc0c, 0xf04f,  /* PE(3) */
+		0xcc0c, 0xd0cf,	 /* PE(6) */
+		0xcc0c, 0x70cf,	 /* PE(7) */
+	}, *y = matrix_PDE;
+
+	/* Save these control reg bits */
+	dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+	ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+	for (i = 0; i < 8; i++) {
+		/* disable output for all but the one we want to scan */
+		ctrl_outw((dc_static | *y++), PDCR);
+		ctrl_outw((ec_static | *y++), PECR);
+		udelay(5);
+
+		/* Get scanline row */
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+
+		/* Read data */
+		*s++ = ctrl_inb(PCDR);
+		*s++ = ctrl_inb(PFDR);
+	}
+	/* Scan no lines */
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
+
+	/* Enable all scanlines */
+	ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+	ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+
+	/* Ignore extra keys and events */
+	*s++ = ctrl_inb(PGDR);
+	*s++ = ctrl_inb(PHDR);
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+	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);
+}
+
+static int __devinit jornada680kbd_probe(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input_dev;
+	int i, error;
+
+	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+	if (!jornadakbd)
+		return -ENOMEM;
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev) {
+		error = -ENOMEM;
+		goto failed;
+	}
+
+	platform_set_drvdata(pdev, jornadakbd);
+
+	jornadakbd->poll_dev = poll_dev;
+
+	memcpy(jornadakbd->keymap, jornada_scancodes,
+		sizeof(jornadakbd->keymap));
+
+	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 char);
+	input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->id.bustype = BUS_HOST;
+
+	for (i = 0; i < 128; i++)
+		if (jornadakbd->keymap[i])
+			__set_bit(jornadakbd->keymap[i], input_dev->keybit);
+	__clear_bit(0, input_dev->keybit);
+
+	error = input_register_polled_device(jornadakbd->poll_dev);
+	if (error)
+		goto failed;
+
+	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);
+	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);
+
+	return 0;
+}
+
+static struct platform_driver jornada680kbd_driver = {
+	.driver	= {
+		.name	= "jornada680_kbd",
+	},
+	.probe	= jornada680kbd_probe,
+	.remove	= __devexit_p(jornada680kbd_remove),
+};
+
+static int __init jornada680kbd_init(void)
+{
+	return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+	platform_driver_unregister(&jornada680kbd_driver);
+}
+
+module_init(jornada680kbd_init);
+module_exit(jornada680kbd_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
Index: linux/drivers/input/keyboard/Makefile
===================================================================
--- linux.orig/drivers/input/keyboard/Makefile
+++ linux/drivers/input/keyboard/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-key
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
+obj-$(CONFIG_KEYBOARD_HP6XX)		+= jornada680_kbd.o
 
Index: linux/drivers/input/keyboard/Kconfig
===================================================================
--- linux.orig/drivers/input/keyboard/Kconfig
+++ linux/drivers/input/keyboard/Kconfig
@@ -208,6 +208,17 @@ config KEYBOARD_HIL
 	  This driver implements support for HIL-keyboards attached
 	  to your machine, so normally you should say Y here.
 
+config KEYBOARD_HP6XX
+	tristate "HP Jornada 6XX Keyboard support"
+	depends on SH_HP6XX
+	select INPUT_POLLDEV
+	help
+	  This adds support for the onboard keyboard found on
+	  HP Jornada 620/660/680/690.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called jornada680_kbd.
+
 config KEYBOARD_OMAP
 	tristate "TI OMAP keypad support"
 	depends on (ARCH_OMAP1 || ARCH_OMAP2)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-07-30 12:39     ` Dmitry Torokhov
  2007-08-01  5:50       ` Kristoffer Ericson
  2007-08-26  3:57       ` Kristoffer Ericson
@ 2007-09-10 21:58       ` Kristoffer Ericson
  2007-09-10 13:01         ` Dmitry Torokhov
  2 siblings, 1 reply; 14+ messages in thread
From: Kristoffer Ericson @ 2007-09-10 21:58 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

Greetings,

I've sent this patch a couple of times now without receiving any response, so here goes again.
Driver compiles and works.

Shortlog:
This patch adds support to the onboard hp jornada 620/660/680/690 keyboard. 
The patch is based on old LinuxSH keyboard code but have been recoded to get rid of dependance on
scan_keyb.c/.h, it also uses polldev.
Bugs fixed in this verses the old driver is that it no longer produces 'dead' keys.

signed-off-by: Kristoffer Ericson <Kristoffer.ericson@gmail.com>

diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
new file mode 100644
index 0000000..2575d88
--- /dev/null
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,276 @@
+/*
+ * 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>
+ *
+ * Based on hp680_keyb.c
+ *  Copyright (C) 2006 Paul Mundt
+ *  Copyright (C) 2005 Andriy Skulysh
+ * Splited from drivers/input/keyboard/hp600_keyb.c
+ *  Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
+ *  Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
+ *
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of the GNU General Public License version 2 as 
+ * published by the Free Software Foundation.
+ * 
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define SCANHZ (HZ/20)
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static unsigned char jornada_scancodes[] = {
+/* PTD1 */	KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0,	/*  1  -> 8   */
+		KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5,	/*  9  -> 16  */
+/* PTD5 */	KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0,	/*  17 -> 24  */
+		KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,	/*  25 -> 32  */
+/* PTD7 */	KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0,				/*  33 -> 40  */
+		0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA,			/*  41 -> 48  */
+/* PTE0 */	0, 0, 0, 0, KEY_FINANCE, 0, 0, 0,				/*  49 -> 56  */
+		KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /*  57 -> 64  */
+/* PTE1 */	KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/*  65 -> 72  */
+		KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,		/*  73 -> 80  */
+/* PTE3 */	KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0,	/*  81 -> 88  */
+		0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,				/*  89 -> 96  */
+/* PTE6 */	KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0,		/*  97 -> 104 */
+		KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,		/* 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
+};
+
+struct jornadakbd {
+	unsigned char jornada_keymap[ARRAY_SIZE(jornada_scancodes)];
+	struct input_polled_dev *poll_dev;
+	unsigned char length;
+	unsigned char s0[18], s1[18];
+};
+
+unsigned int scan_jiffies;
+
+void jornada_check_kbd(struct jornadakbd *jornadakbd, unsigned char *new, unsigned char *old)
+{
+	unsigned char *table = jornadakbd->jornada_keymap;
+	unsigned char length = jornadakbd->length;
+	unsigned int bit, xor;
+	unsigned int sync_me = 0;
+
+	while (length-- > 0) {
+		if ((xor = *new ^ *old) == 0)
+			table += 8;
+		else {
+			for (bit = 0x01; bit < 0x100;bit <<= 1) {
+				if (xor & bit) {
+					input_report_key(jornadakbd->poll_dev->input, *table, !(*new & bit));
+					sync_me = 1;
+				}
+
+				table++;
+			}
+		}
+
+		new++;
+		old++;
+	}
+	if (sync_me)
+	    input_sync(jornadakbd->poll_dev->input);
+
+}
+
+int jornada_scan_keyb(unsigned char *s)
+{
+	int i;
+	unsigned short ec_static, dc_static; /* = UINT16_t */
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,   /* PTD1 PD(1) */
+		0xdf, 0xff,   /* PTD5 PD(5) */
+		0x7f, 0xff,   /* PTD7 PD(7) */
+		0xff, 0xfe,   /* PTE0 PE(0) */
+		0xff, 0xfd,   /* PTE1 PE(1) */
+		0xff, 0xf7,   /* PTE3 PE(3) */
+		0xff, 0xbf,   /* PTE6 PE(6) */
+		0xff, 0x7f,   /* PTE7 PE(7) */
+	}, *t = matrix_switch;
+	/* PD(x) :
+	1.   0xcc0c & (1~(1 << (2*(x)+1)))))
+	2.   (0xf0cf & 0xfffff) */
+	/* PE(x) :
+	1.   0xcc0c & 0xffff
+	2.   0xf0cf & (1~(1 << (2*(x)+1))))) */
+	unsigned short matrix_PDE[] = {
+		0xcc04, 0xf0cf,  /* PD(1) */
+		0xc40c, 0xf0cf,	 /* PD(5) */
+		0x4c0c, 0xf0cf,  /* PD(7) */
+		0xcc0c, 0xf0cd,  /* PE(0) */
+		0xcc0c, 0xf0c7,	 /* PE(1) */
+		0xcc0c, 0xf04f,  /* PE(3) */
+		0xcc0c, 0xd0cf,	 /* PE(6) */
+		0xcc0c, 0x70cf,	 /* PE(7) */
+	}, *y = matrix_PDE;
+	/* Save these control reg bits */
+	dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+	ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+	for (i = 0; i < 8; i++) {
+		/* disable output for all but the one we want to scan */
+		ctrl_outw((dc_static | *y++), PDCR);
+		ctrl_outw((ec_static | *y++), PECR);
+		udelay(5);
+
+		/* Get scanline row */
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+
+		/* Read data */
+		*s++ = ctrl_inb(PCDR);
+		*s++ = ctrl_inb(PFDR);
+	}
+	/* Scan no lines */
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
+
+	/* Enable all scanlines */
+	ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+	ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+	/* Ignore extra keys and events */
+	*s++ = ctrl_inb(PGDR);
+	*s++ = ctrl_inb(PHDR);
+
+	return 0;
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+    struct jornadakbd *jornadakbd = dev->private;
+    scan_jiffies++;
+
+	if (scan_jiffies & 1) {
+		if (!jornada_scan_keyb(jornadakbd->s0))
+			jornada_check_kbd(jornadakbd, jornadakbd->s0, jornadakbd->s1);
+		else
+			memcpy(jornadakbd->s0, jornadakbd->s1, jornadakbd->length);
+	} else {
+		if (!jornada_scan_keyb(jornadakbd->s1))
+			jornada_check_kbd(jornadakbd, jornadakbd->s1, jornadakbd->s0);
+		else
+			memcpy(jornadakbd->s1, jornadakbd->s0, jornadakbd->length);
+		}
+}
+
+static int __init jornada680kbd_probe(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input_dev;
+	int i, error;
+
+	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+	if (!jornadakbd)
+		return -ENOMEM;
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev)
+		goto failed;
+
+	platform_set_drvdata(pdev, jornadakbd);
+
+	jornadakbd->poll_dev = poll_dev;
+	jornadakbd->length   = 18;
+
+	memcpy(jornadakbd->jornada_keymap, jornada_scancodes, sizeof(jornadakbd->jornada_keymap));
+
+	poll_dev->private = jornadakbd;
+	poll_dev->poll = jornadakbd680_poll;
+	poll_dev->poll_interval = (HZ/20);
+
+	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->jornada_keymap;
+	input_dev->keycodesize = sizeof(unsigned char);
+	input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+	input_dev->dev.parent = &pdev->dev;
+
+	for (i = 0; i < 128; i++)
+		if (jornadakbd->jornada_keymap[i])
+		    set_bit(jornadakbd->jornada_keymap[i], jornadakbd->poll_dev->input->keybit);
+
+	clear_bit(0, jornadakbd->poll_dev->input->keybit);
+
+	error = input_register_polled_device(jornadakbd->poll_dev);
+	if (error)
+	    goto failed;
+
+	printk(KERN_INFO "We have successfully registerd the keyboard driver\n");
+	return 0;
+
+failed:
+	printk(KERN_INFO "Jornadakbd: failed to register driver, bailing\n");
+	kfree(jornadakbd);
+	return -ENOMEM;
+
+}
+
+static int jornada680kbd_remove(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+	input_unregister_polled_device(jornadakbd->poll_dev);
+	input_free_polled_device(jornadakbd->poll_dev);
+	kfree(jornadakbd);
+	return 0;
+}
+
+static struct platform_driver jornada680kbd_driver = {
+	.driver	= {
+		    .name = "jornada680_kbd",
+		},
+	.probe = jornada680kbd_probe,
+	.remove = jornada680kbd_remove,
+};
+
+static int __devinit jornada680kbd_init(void)
+{
+	return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+	platform_driver_unregister(&jornada680kbd_driver);
+}
+
+module_init(jornada680kbd_init);
+module_exit(jornada680kbd_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 28d211b..7ecd2b0 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
+obj-$(CONFIG_KEYBOARD_HP6XX)		+= jornada680_kbd.o
 
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index c97d5eb..99fa19b 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -208,6 +208,14 @@ config KEYBOARD_HIL
 	  This driver implements support for HIL-keyboards attached
 	  to your machine, so normally you should say Y here.
 
+config KEYBOARD_HP6XX
+       tristate "HP Jornada 6XX Keyboard support"
+       depends on SH_HP6XX
+       select INPUT_POLLDEV
+       help
+    	   This adds support for the onboard keyboard found on
+	   HP Jornada 620/660/680/690.
+
 config KEYBOARD_OMAP
 	tristate "TI OMAP keypad support"
 	depends on (ARCH_OMAP1 || ARCH_OMAP2)




On Mon, 30 Jul 2007 08:39:20 -0400
"Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:

> Hi Kristoffer,
> 
> On 7/27/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > Dmitry,
> >
> > Ive merged scan_keyb and started to minimize it for just one keyboard, just want to hear from you if this is an acceptable approach.
> > Its a work in progress, just want to know if im on the right path.
> >
> 
> Like I said, please look at input-polldev
> (drivers/input/input-polldev.c). It takes care of setting up workqueue
> used for polling and will only poll if there are users so the driver
> only needs to provide miplementation of scan function. Take a look at
> drivers/input/keyboard/aaed2000_kbd.c to see how it is used.
> 
> -- 
> Dmitry


-- 
Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-09-10 13:01         ` Dmitry Torokhov
@ 2007-09-11  8:22           ` Kristoffer Ericson
  2007-09-11 15:14             ` Dmitry Torokhov
  0 siblings, 1 reply; 14+ messages in thread
From: Kristoffer Ericson @ 2007-09-11  8:22 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

On Mon, 10 Sep 2007 09:01:51 -0400
"Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:

> On 9/10/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > Greetings,
> >
> > I've sent this patch a couple of times now without receiving any response, so here goes again.
> 
> Argh, that's what I needed to do over the weekend... Sorry...
No worries,

> 
> OK, I looked over the patch and it is in a pretty decent shape, here
> is the only thing that bothers me:
> > +
> > +static void jornadakbd680_poll(struct input_polled_dev *dev)
> > +{
> > +    struct jornadakbd *jornadakbd = dev->private;
> > +    scan_jiffies++;
> > +
> > +       if (scan_jiffies & 1) {
> > +               if (!jornada_scan_keyb(jornadakbd->s0))
> > +                       jornada_check_kbd(jornadakbd, jornadakbd->s0, jornadakbd->s1);
> > +               else
> > +                       memcpy(jornadakbd->s0, jornadakbd->s1, jornadakbd->length);
> 
> jornada_scan_keyb appears to always return 0 so this copy never takes
> place. Overall I find this poll routine a bit complicated.

Couldnt agree with you more, I came to the same conclusion but after the driver started working it slipped my mind.
Generally the driver was too complicated than it needed too, I've sorted out some of its 'lets see how I can make a simple check complicated' routines, but not all.

> I am
> attaching a patch that has it impoemented a bit differently, could you
> tell me if it is still works for you?

It works, but the keys it returns are wrong. For instance enter returns 'z'. Somehow the *table must be off. I havent looked at it more closely, but will tommorow.

> 
> Thanks!
> 
> -- 
> Dmitry
> 


-- 
Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-09-11  8:22           ` Kristoffer Ericson
@ 2007-09-11 15:14             ` Dmitry Torokhov
  2007-09-12  1:42               ` Kristoffer Ericson
  0 siblings, 1 reply; 14+ messages in thread
From: Dmitry Torokhov @ 2007-09-11 15:14 UTC (permalink / raw)
  To: Kristoffer Ericson; +Cc: linux-input

[-- Attachment #1: Type: text/plain, Size: 526 bytes --]

On 9/11/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> On Mon, 10 Sep 2007 09:01:51 -0400
> "Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:
>
> > I am
> > attaching a patch that has it impoemented a bit differently, could you
> > tell me if it is still works for you?
>
> It works, but the keys it returns are wrong. For instance enter returns 'z'. Somehow the *table must be off. I havent looked at it more closely, but will tommorow.
>

Yes, I messed up the inner loop. What about this one?

-- 
Dmitry

[-- Attachment #2: hp6xx-keyboard.patch --]
[-- Type: application/octet-stream, Size: 9933 bytes --]

From: Kristoffer Ericson <kristoffer.ericson@gmail.com>

Input: add support for HP Jornada onboard keyboard (HP6XX)

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
 drivers/input/keyboard/Kconfig          |   11 +
 drivers/input/keyboard/Makefile         |    1 
 drivers/input/keyboard/jornada680_kbd.c |  272 ++++++++++++++++++++++++++++++++
 3 files changed, 284 insertions(+)

Index: linux/drivers/input/keyboard/jornada680_kbd.c
===================================================================
--- /dev/null
+++ linux/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,272 @@
+/*
+ * 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>
+ *
+ * Based on hp680_keyb.c
+ *  Copyright (C) 2006 Paul Mundt
+ *  Copyright (C) 2005 Andriy Skulysh
+ * Split from drivers/input/keyboard/hp600_keyb.c
+ *  Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
+ *  Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static const unsigned char jornada_scancodes[] = {
+/* PTD1 */	KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0,	/*  1  -> 8   */
+		KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5,	/*  9  -> 16  */
+/* PTD5 */	KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0,	/*  17 -> 24  */
+		KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N,	/*  25 -> 32  */
+/* PTD7 */	KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0,				/*  33 -> 40  */
+		0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA,			/*  41 -> 48  */
+/* PTE0 */	0, 0, 0, 0, KEY_FINANCE, 0, 0, 0,				/*  49 -> 56  */
+		KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /*  57 -> 64  */
+/* PTE1 */	KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/*  65 -> 72  */
+		KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H,		/*  73 -> 80  */
+/* PTE3 */	KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0,	/*  81 -> 88  */
+		0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0,				/*  89 -> 96  */
+/* PTE6 */	KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0,		/*  97 -> 104 */
+		KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R,		/* 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
+
+struct jornadakbd {
+	struct input_polled_dev *poll_dev;
+	unsigned char keymap[ARRAY_SIZE(jornada_scancodes)];
+	unsigned char length;
+	unsigned char old_scan[JORNADA_SCAN_SIZE];
+	unsigned char new_scan[JORNADA_SCAN_SIZE];
+};
+
+static void jornada_parse_kbd(struct jornadakbd *jornadakbd)
+{
+	struct input_dev *input_dev = jornadakbd->poll_dev->input;
+	unsigned char *keymap = jornadakbd->keymap;
+	unsigned int sync_me = 0;
+	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) {
+				input_report_key(input_dev,
+						 keymap[(i << 3) + j],
+						 !(new & bit));
+				sync_me = 1;
+			}
+		}
+	}
+
+	if (sync_me)
+	    input_sync(input_dev);
+}
+
+static void jornada_scan_keyb(unsigned char *s)
+{
+	int i;
+	unsigned short ec_static, dc_static; /* = UINT16_t */
+	unsigned char matrix_switch[] = {
+		0xfd, 0xff,   /* PTD1 PD(1) */
+		0xdf, 0xff,   /* PTD5 PD(5) */
+		0x7f, 0xff,   /* PTD7 PD(7) */
+		0xff, 0xfe,   /* PTE0 PE(0) */
+		0xff, 0xfd,   /* PTE1 PE(1) */
+		0xff, 0xf7,   /* PTE3 PE(3) */
+		0xff, 0xbf,   /* PTE6 PE(6) */
+		0xff, 0x7f,   /* PTE7 PE(7) */
+	}, *t = matrix_switch;
+	/* PD(x) :
+	1.   0xcc0c & (1~(1 << (2*(x)+1)))))
+	2.   (0xf0cf & 0xfffff) */
+	/* PE(x) :
+	1.   0xcc0c & 0xffff
+	2.   0xf0cf & (1~(1 << (2*(x)+1))))) */
+	unsigned short matrix_PDE[] = {
+		0xcc04, 0xf0cf,  /* PD(1) */
+		0xc40c, 0xf0cf,	 /* PD(5) */
+		0x4c0c, 0xf0cf,  /* PD(7) */
+		0xcc0c, 0xf0cd,  /* PE(0) */
+		0xcc0c, 0xf0c7,	 /* PE(1) */
+		0xcc0c, 0xf04f,  /* PE(3) */
+		0xcc0c, 0xd0cf,	 /* PE(6) */
+		0xcc0c, 0x70cf,	 /* PE(7) */
+	}, *y = matrix_PDE;
+
+	/* Save these control reg bits */
+	dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+	ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+	for (i = 0; i < 8; i++) {
+		/* disable output for all but the one we want to scan */
+		ctrl_outw((dc_static | *y++), PDCR);
+		ctrl_outw((ec_static | *y++), PECR);
+		udelay(5);
+
+		/* Get scanline row */
+		ctrl_outb(*t++, PDDR);
+		ctrl_outb(*t++, PEDR);
+		udelay(50);
+
+		/* Read data */
+		*s++ = ctrl_inb(PCDR);
+		*s++ = ctrl_inb(PFDR);
+	}
+	/* Scan no lines */
+	ctrl_outb(0xff, PDDR);
+	ctrl_outb(0xff, PEDR);
+
+	/* Enable all scanlines */
+	ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+	ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+
+	/* Ignore extra keys and events */
+	*s++ = ctrl_inb(PGDR);
+	*s++ = ctrl_inb(PHDR);
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+	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);
+}
+
+static int __devinit jornada680kbd_probe(struct platform_device *pdev)
+{
+	struct jornadakbd *jornadakbd;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input_dev;
+	int i, error;
+
+	jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+	if (!jornadakbd)
+		return -ENOMEM;
+
+	poll_dev = input_allocate_polled_device();
+	if (!poll_dev) {
+		error = -ENOMEM;
+		goto failed;
+	}
+
+	platform_set_drvdata(pdev, jornadakbd);
+
+	jornadakbd->poll_dev = poll_dev;
+
+	memcpy(jornadakbd->keymap, jornada_scancodes,
+		sizeof(jornadakbd->keymap));
+
+	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 char);
+	input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->id.bustype = BUS_HOST;
+
+	for (i = 0; i < 128; i++)
+		if (jornadakbd->keymap[i])
+			__set_bit(jornadakbd->keymap[i], input_dev->keybit);
+	__clear_bit(0, input_dev->keybit);
+
+	error = input_register_polled_device(jornadakbd->poll_dev);
+	if (error)
+		goto failed;
+
+	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);
+	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);
+
+	return 0;
+}
+
+static struct platform_driver jornada680kbd_driver = {
+	.driver	= {
+		.name	= "jornada680_kbd",
+	},
+	.probe	= jornada680kbd_probe,
+	.remove	= __devexit_p(jornada680kbd_remove),
+};
+
+static int __init jornada680kbd_init(void)
+{
+	return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+	platform_driver_unregister(&jornada680kbd_driver);
+}
+
+module_init(jornada680kbd_init);
+module_exit(jornada680kbd_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
Index: linux/drivers/input/keyboard/Makefile
===================================================================
--- linux.orig/drivers/input/keyboard/Makefile
+++ linux/drivers/input/keyboard/Makefile
@@ -21,4 +21,5 @@ obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-key
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
+obj-$(CONFIG_KEYBOARD_HP6XX)		+= jornada680_kbd.o
 
Index: linux/drivers/input/keyboard/Kconfig
===================================================================
--- linux.orig/drivers/input/keyboard/Kconfig
+++ linux/drivers/input/keyboard/Kconfig
@@ -208,6 +208,17 @@ config KEYBOARD_HIL
 	  This driver implements support for HIL-keyboards attached
 	  to your machine, so normally you should say Y here.
 
+config KEYBOARD_HP6XX
+	tristate "HP Jornada 6XX Keyboard support"
+	depends on SH_HP6XX
+	select INPUT_POLLDEV
+	help
+	  This adds support for the onboard keyboard found on
+	  HP Jornada 620/660/680/690.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called jornada680_kbd.
+
 config KEYBOARD_OMAP
 	tristate "TI OMAP keypad support"
 	depends on (ARCH_OMAP1 || ARCH_OMAP2)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-09-12  1:42               ` Kristoffer Ericson
@ 2007-09-11 18:32                 ` Dmitry Torokhov
  2007-09-14  0:25                   ` Kristoffer Ericson
  0 siblings, 1 reply; 14+ messages in thread
From: Dmitry Torokhov @ 2007-09-11 18:32 UTC (permalink / raw)
  To: Kristoffer Ericson; +Cc: linux-input

On 9/11/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> On Tue, 11 Sep 2007 11:14:37 -0400
> "Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:
>
> > On 9/11/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > > On Mon, 10 Sep 2007 09:01:51 -0400
> > > "Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:
> > >
> > > > I am
> > > > attaching a patch that has it impoemented a bit differently, could you
> > > > tell me if it is still works for you?
> > >
> > > It works, but the keys it returns are wrong. For instance enter returns 'z'. Somehow the *table must be off. I havent looked at it more closely, but will tommorow.
> > >
> >
> > Yes, I messed up the inner loop. What about this one?
>
> That seems to work according to my tester. So if you are satisfied, please go ahead and commit it.
>

Ok, will do. Thank you for testing.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-09-11 15:14             ` Dmitry Torokhov
@ 2007-09-12  1:42               ` Kristoffer Ericson
  2007-09-11 18:32                 ` Dmitry Torokhov
  0 siblings, 1 reply; 14+ messages in thread
From: Kristoffer Ericson @ 2007-09-12  1:42 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

On Tue, 11 Sep 2007 11:14:37 -0400
"Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:

> On 9/11/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > On Mon, 10 Sep 2007 09:01:51 -0400
> > "Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:
> >
> > > I am
> > > attaching a patch that has it impoemented a bit differently, could you
> > > tell me if it is still works for you?
> >
> > It works, but the keys it returns are wrong. For instance enter returns 'z'. Somehow the *table must be off. I havent looked at it more closely, but will tommorow.
> >
> 
> Yes, I messed up the inner loop. What about this one?

That seems to work according to my tester. So if you are satisfied, please go ahead and commit it.

Loop looks alot better now btw :)

Best wishes
Kristoffer

> 
> -- 
> Dmitry
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-09-11 18:32                 ` Dmitry Torokhov
@ 2007-09-14  0:25                   ` Kristoffer Ericson
  2007-09-14  5:19                     ` Dmitry Torokhov
  0 siblings, 1 reply; 14+ messages in thread
From: Kristoffer Ericson @ 2007-09-14  0:25 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Kristoffer Ericson, linux-input

btw Any git-repository available?


On Tue, 11 Sep 2007 14:32:41 -0400
"Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:

> On 9/11/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > On Tue, 11 Sep 2007 11:14:37 -0400
> > "Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:
> >
> > > On 9/11/07, Kristoffer Ericson <kristoffer.ericson@gmail.com> wrote:
> > > > On Mon, 10 Sep 2007 09:01:51 -0400
> > > > "Dmitry Torokhov" <dmitry.torokhov@gmail.com> wrote:
> > > >
> > > > > I am
> > > > > attaching a patch that has it impoemented a bit differently, could you
> > > > > tell me if it is still works for you?
> > > >
> > > > It works, but the keys it returns are wrong. For instance enter returns 'z'. Somehow the *table must be off. I havent looked at it more closely, but will tommorow.
> > > >
> > >
> > > Yes, I messed up the inner loop. What about this one?
> >
> > That seems to work according to my tester. So if you are satisfied, please go ahead and commit it.
> >
> 
> Ok, will do. Thank you for testing.
> 
> -- 
> Dmitry

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [HP Jornada 6XX] - Onboard Keyboard support
  2007-09-14  0:25                   ` Kristoffer Ericson
@ 2007-09-14  5:19                     ` Dmitry Torokhov
  0 siblings, 0 replies; 14+ messages in thread
From: Dmitry Torokhov @ 2007-09-14  5:19 UTC (permalink / raw)
  To: Kristoffer Ericson; +Cc: linux-input

On Thursday 13 September 2007 20:25, Kristoffer Ericson wrote:
> btw Any git-repository available?
> 

Yep:

	git://git.kenel.org/pub/scm/linux/kernel/git/dtor/input.git

Branch 'for-linus' has changes that I am trying to get into current release,
'devel' is for next merge window stuff, 'master' contains everything and
Andrew Morton pulls from it for -mm.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2007-09-14  5:19 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20070721181549.9d118414.Kristoffer.Ericson@Gmail.com>
2007-07-22  5:45 ` [HP Jornada 6XX] - Onboard Keyboard support Dmitry Torokhov
2007-07-22 15:59   ` Kristoffer Ericson
2007-07-27  5:34   ` Kristoffer Ericson
2007-07-30 12:39     ` Dmitry Torokhov
2007-08-01  5:50       ` Kristoffer Ericson
2007-08-26  3:57       ` Kristoffer Ericson
2007-09-10 21:58       ` Kristoffer Ericson
2007-09-10 13:01         ` Dmitry Torokhov
2007-09-11  8:22           ` Kristoffer Ericson
2007-09-11 15:14             ` Dmitry Torokhov
2007-09-12  1:42               ` Kristoffer Ericson
2007-09-11 18:32                 ` Dmitry Torokhov
2007-09-14  0:25                   ` Kristoffer Ericson
2007-09-14  5:19                     ` Dmitry Torokhov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).