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 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