On Wed, May 14, 2008 at 09:01:19PM -0700, Tony Lindgren wrote: > This allows using N810 keyboard from console by adding optional > Fn and shift sticky key handling by passing them from platform_data. > > Currently some not so obvious mappings are: > > - Pipe is Fn + Enter > - Delete is Fn + Backspace > - Escape is Fn + Ctrl no tab? :-( Fn + space maybe?? :-p > > Works also with xserver-xorg-video-fbdev. > > Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx> > --- > arch/arm/mach-omap2/board-n800.c | 87 ++++++++++++++++++++++++++++++++++---- > drivers/input/keyboard/lm8323.c | 84 +++++++++++++++++++++++++++++++++---- > include/linux/i2c/lm8323.h | 12 ++---- > 3 files changed, 159 insertions(+), 24 deletions(-) > > diff --git a/arch/arm/mach-omap2/board-n800.c b/arch/arm/mach-omap2/board-n800.c > index ae85c2c..a654886 100644 > --- a/arch/arm/mach-omap2/board-n800.c > +++ b/arch/arm/mach-omap2/board-n800.c > @@ -51,7 +51,16 @@ > #define N800_TSC2301_RESET_GPIO 118 > > #ifdef CONFIG_MACH_NOKIA_N810 > -static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = { > + > +/* > + * Largest keycode that the chip can send, plus one, > + * so keys can be mapped directly at the index of the > + * LM8323 keycode instead of subtracting one. > + */ > +#define N810_HWKEY_SZ (0x7f + 1) > + > +/* Keymap for lm8323. Negative value means Shift + KEY */ > +static s16 rx44_keymap[N810_HWKEY_SZ * 2] = { > [0x01] = KEY_Q, > [0x02] = KEY_K, > [0x03] = KEY_O, > @@ -81,7 +90,7 @@ static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = { > [0x21] = KEY_E, > [0x22] = KEY_SEMICOLON, > [0x23] = KEY_MINUS, > - [0x24] = KEY_EQUAL, > + [0x24] = -KEY_EQUAL, > [0x2b] = KEY_FN, > [0x2c] = KEY_M, > [0x2f] = KEY_F8, > @@ -108,15 +117,77 @@ static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = { > > [0x71] = KEY_I, > [0x75] = KEY_KPENTER, > + > + /* End of hardware key map, Fn + key values below */ > + > + [0x01 + N810_HWKEY_SZ] = KEY_1, /* Fn + KEY_Q */ > + [0x02 + N810_HWKEY_SZ] = -KEY_0, /* Fn + KEY_K */ > + [0x03 + N810_HWKEY_SZ] = KEY_9, /* Fn + KEY_O */ > + [0x04 + N810_HWKEY_SZ] = KEY_0, /* Fn + KEY_P */ > + [0x05 + N810_HWKEY_SZ] = KEY_DELETE, /* Fn + KEY_BACKSPACE */ > + [0x06 + N810_HWKEY_SZ] = -KEY_1, /* Fn + KEY_A */ > + [0x07 + N810_HWKEY_SZ] = -KEY_APOSTROPHE, /* Fn + KEY_S */ > + [0x08 + N810_HWKEY_SZ] = -KEY_2, /* Fn + KEY_D */ > + [0x09 + N810_HWKEY_SZ] = -KEY_3, /* Fn + KEY_F */ > + [0x0a + N810_HWKEY_SZ] = KEY_BACKSLASH, /* Fn + KEY_G */ > + [0x0b + N810_HWKEY_SZ] = KEY_SLASH, /* Fn + KEY_H */ > + [0x0c + N810_HWKEY_SZ] = -KEY_9, /* Fn + KEY_J */ > + > + [0x11 + N810_HWKEY_SZ] = KEY_2, /* Fn + KEY_W */ > + [0x12 + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_F4 */ > + [0x13 + N810_HWKEY_SZ] = -KEY_8, /* Fn + KEY_L */ > + [0x14 + N810_HWKEY_SZ] = -KEY_SLASH, /* Fn + KEY_APOSTROPHE */ > + [0x16 + N810_HWKEY_SZ] = KEY_YEN, /* Fn + KEY_Z */ > + [0x17 + N810_HWKEY_SZ] = -KEY_6, /* Fn + KEY_X */ > + [0x18 + N810_HWKEY_SZ] = -KEY_GRAVE, /* Fn + KEY_C */ > + [0x19 + N810_HWKEY_SZ] = -KEY_5, /* Fn + KEY_V */ > + [0x1a + N810_HWKEY_SZ] = -KEY_7, /* Fn + KEY_B */ > + [0x1b + N810_HWKEY_SZ] = -KEY_4, /* Fn + KEY_N */ > + [0x1c + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_LEFTSHIFT */ > + [0x1f + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_F7 */ > + > + [0x21 + N810_HWKEY_SZ] = KEY_3, /* Fn + KEY_E */ > + [0x22 + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_SEMICOLON */ > + [0x23 + N810_HWKEY_SZ] = -KEY_MINUS, /* Fn + KEY_MINUS */ > + [0x24 + N810_HWKEY_SZ] = KEY_EQUAL, /* Fn + -KEY_EQUAL */ > + [0x2b + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_FN */ > + [0x2c + N810_HWKEY_SZ] = KEY_EURO, /* Fn + KEY_M */ > + [0x2f + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_F8 */ > + > + [0x31 + N810_HWKEY_SZ] = KEY_4, /* Fn + KEY_R */ > + [0x32 + N810_HWKEY_SZ] = KEY_ESC, /* Fn + KEY_RIGHTCTRL */ > + [0x34 + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_SPACE */ > + [0x35 + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_COMMA */ > + [0x37 + N810_HWKEY_SZ] = KEY_PAGEUP, /* Fn + KEY_UP */ > + [0x3c + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_COMPOSE */ > + [0x3f + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_F6 */ > + > + [0x41 + N810_HWKEY_SZ] = KEY_5, /* Fn + KEY_T */ > + [0x44 + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_DOT */ > + [0x46 + N810_HWKEY_SZ] = KEY_TAB, /* Fn + KEY_RIGHT */ > + [0x4f + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_F5 */ > + [0x51 + N810_HWKEY_SZ] = KEY_6, /* Fn + KEY_Y */ > + [0x53 + N810_HWKEY_SZ] = KEY_PAGEDOWN, /* Fn + KEY_DOWN */ > + [0x55 + N810_HWKEY_SZ] = -KEY_BACKSLASH, /* Fn + KEY_ENTER */ > + [0x5f + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_ESC */ > + > + [0x61 + N810_HWKEY_SZ] = KEY_7, /* Fn + KEY_U */ > + [0x64 + N810_HWKEY_SZ] = KEY_ESC, /* Fn + KEY_LEFT */ > + > + [0x71 + N810_HWKEY_SZ] = KEY_8, /* Fn + KEY_I */ > + [0x75 + N810_HWKEY_SZ] = KEY_RESERVED, /* Fn + KEY_KPENTER */ > }; > > static struct lm8323_platform_data lm8323_pdata = { > - .repeat = 0, /* Repeat is handled in userspace for now. */ > - .keymap = rx44_keymap, > - > - .name = "Internal keyboard", > - .pwm1_name = "keyboard", > - .pwm2_name = "cover", > + .repeat = 1, /* Change to 0 if handled in userspace */ > + .keymap = rx44_keymap, > + .keymap_sz = ARRAY_SIZE(rx44_keymap), > + .fn_key = KEY_FN, > + .shift_key = KEY_LEFTSHIFT, > + > + .name = "Internal keyboard", > + .pwm1_name = "keyboard", > + .pwm2_name = "cover", > }; > #endif > > diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c > index d472da0..485c19f 100644 > --- a/drivers/input/keyboard/lm8323.c > +++ b/drivers/input/keyboard/lm8323.c > @@ -155,7 +155,19 @@ struct lm8323_chip { > unsigned pm_suspend : 1; > unsigned keys_down; > char phys[32]; > - s16 keymap[LM8323_KEYMAP_SIZE]; > + > +#define SHIFT_LOCKED (1 << 5) > +#define SHIFT_HELD (1 << 4) > +#define SHIFT_ONE (1 << 3) > +#define FN_LOCKED (1 << 2) > +#define FN_HELD (1 << 1) > +#define FN_ONE (1 << 0) > + u8 sticky; > + > + s16 *keymap; > + u16 keymap_sz; > + u16 fn_key; > + u16 shift_key; > int size_x; > int size_y; > int debounce_time; > @@ -279,6 +291,41 @@ static inline int lm8323_ispress(u8 event) > return (event & 0x80) ? 1 : 0; > } > > +static inline u8 is_sticky(struct lm8323_chip *lm, s16 keycode, int isdown) > +{ > + if (isdown) { > + if (lm->fn_key && keycode == lm->fn_key) { > + if (lm->sticky & FN_LOCKED) > + lm->sticky = 0; > + else if (lm->sticky & FN_ONE) > + lm->sticky = FN_LOCKED; > + else > + lm->sticky = FN_HELD | FN_ONE; > + return 1; > + } > + if (lm->shift_key && keycode == lm->shift_key) { > + if (lm->sticky & SHIFT_LOCKED) > + lm->sticky = 0; > + else if (lm->sticky & SHIFT_ONE) > + lm->sticky = SHIFT_LOCKED; > + else > + lm->sticky = SHIFT_HELD | SHIFT_ONE; > + return 1; > + } > + } else { > + if (lm->fn_key && keycode == lm->fn_key) { > + lm->sticky &= ~FN_HELD; > + return 1; > + } > + if (lm->shift_key && keycode == lm->shift_key) { > + lm->sticky &= ~SHIFT_HELD; > + return 1; > + } > + } > + > + return 0; > +} > + > static void process_keys(struct lm8323_chip *lm) > { > u8 event; > @@ -300,10 +347,29 @@ static void process_keys(struct lm8323_chip *lm) > key_fifo[ret] = 0; > > while ((event = key_fifo[i])) { > - u8 key = lm8323_whichkey(event); > + u16 key = lm8323_whichkey(event); > int isdown = lm8323_ispress(event); > s16 keycode = lm->keymap[key]; > > + if (is_sticky(lm, keycode, isdown)) { > + i++; > + continue; > + } > + > + if (lm->sticky & (FN_LOCKED | FN_HELD | FN_ONE)) { > + keycode = lm->keymap[key + (lm->keymap_sz / 2)]; > + if (keycode < 0) { > + lm->sticky |= SHIFT_ONE; > + keycode = abs(keycode); > + } > + } > + > + if (lm->sticky & (SHIFT_LOCKED | SHIFT_HELD | SHIFT_ONE)) > + input_report_key(lm->idev, KEY_LEFTSHIFT, isdown); > + > + if (lm->sticky && !isdown) > + lm->sticky &= ~(SHIFT_ONE | FN_ONE); > + > if (likely(keycode > 0)) { > debug(&lm->client->dev, "key 0x%02x %s\n", key, > isdown ? "down" : "up"); > @@ -707,8 +773,12 @@ static int lm8323_probe(struct i2c_client *client, > lm->size_y); > lm->size_x = 12; > } > + debug(&client->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y); > > - debug(&c->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y); > + lm->keymap = lm8323_pdata->keymap; > + lm->keymap_sz = lm8323_pdata->keymap_sz; > + lm->fn_key = lm8323_pdata->fn_key; > + lm->shift_key = lm8323_pdata->shift_key; > > lm->debounce_time = lm8323_pdata->debounce_time; > if (lm->debounce_time == 0) /* Default. */ > @@ -789,11 +859,9 @@ static int lm8323_probe(struct i2c_client *client, > > lm->keys_down = 0; > idev->evbit[0] = BIT(EV_KEY); > - for (i = 0; i < LM8323_KEYMAP_SIZE; i++) { > - if (lm8323_pdata->keymap[i] > 0) > - set_bit(lm8323_pdata->keymap[i], idev->keybit); > - > - lm->keymap[i] = lm8323_pdata->keymap[i]; > + for (i = 0; i < lm->keymap_sz; i++) { > + if (lm->keymap[i] != 0) > + set_bit(abs(lm->keymap[i]), idev->keybit); > } > > if (lm8323_pdata->repeat) > diff --git a/include/linux/i2c/lm8323.h b/include/linux/i2c/lm8323.h > index 17d6b33..5ea6cef 100644 > --- a/include/linux/i2c/lm8323.h > +++ b/include/linux/i2c/lm8323.h > @@ -9,13 +9,6 @@ > > #include <linux/types.h> > > -/* > - * Largest keycode that the chip can send, plus one, > - * so keys can be mapped directly at the index of the > - * LM8323 keycode instead of subtracting one. > - */ > -#define LM8323_KEYMAP_SIZE (0x7f + 1) > - > struct lm8323_platform_data { > int debounce_time; /* Time to watch for key bouncing, in ms. */ > int active_time; /* Idle time until sleep, in ms. */ > @@ -23,7 +16,10 @@ struct lm8323_platform_data { > int size_x; > int size_y; > int repeat : 1; > - const s16 *keymap; > + s16 *keymap; > + u16 keymap_sz; > + u16 fn_key; > + u16 shift_key; > > char *pwm1_name; /* Device name for PWM1. */ > char *pwm2_name; /* Device name for PWM2. */ > -- > 1.5.3.6 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Best Regards, Felipe Balbi me@xxxxxxxxxxxxxxx http://blog.felipebalbi.com -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html