diff -ur linux-2.6.27-pandora-r1/arch/arm/mach-omap2/board-omap3pandora-input.c linux-2.6.27-pandora-r1.patched/arch/arm/mach-omap2/board-omap3pandora-input.c --- linux-2.6.27-pandora-r1/arch/arm/mach-omap2/board-omap3pandora-input.c 2010-10-20 22:58:21.000000000 +0400 +++ linux-2.6.27-pandora-r1.patched/arch/arm/mach-omap2/board-omap3pandora-input.c 2010-10-20 23:27:52.000000000 +0400 @@ -57,7 +57,7 @@ KEY(2, 2, KEY_Y), KEY(2, 3, KEY_G), KEY(2, 4, KEY_V), - KEY(2, 5, KEY_FN), + KEY(2, 5, KEY_RIGHTCTRL), KEY(3, 0, KEY_O), KEY(3, 1, KEY_5), KEY(3, 2, KEY_T), @@ -81,7 +81,7 @@ KEY(7, 0, KEY_ENTER), KEY(7, 1, KEY_1), KEY(7, 2, KEY_Q), - KEY(7, 3, KEY_LEFTSHIFT), + KEY(7, 3, KEY_TAB), KEY(7, 4, KEY_COMMA), /* Fn keys */ FNKEY(0, 0, KEY_F9), @@ -95,13 +95,13 @@ FNKEY(1, 2, KEY_BRIGHTNESSDOWN), FNKEY(1, 3, KEY_GRAVE), FNKEY(1, 4, KEY_F14), /* pipe/bar */ - FNKEY(1, 5, KEY_TAB), + FNKEY(1, 5, KEY_SPACE), FNKEY(2, 0, KEY_INSERT), FNKEY(2, 1, KEY_F6), FNKEY(2, 2, KEY_F15), /* dash */ FNKEY(2, 3, KEY_EQUAL), FNKEY(2, 4, KEY_F16), /* # (pound/hash) */ - FNKEY(2, 5, KEY_FN), + FNKEY(2, 5, KEY_RIGHTCTRL), FNKEY(3, 0, KEY_F11), FNKEY(3, 1, KEY_F5), FNKEY(3, 2, KEY_F17), /* ! */ @@ -125,7 +125,7 @@ FNKEY(7, 0, KEY_ENTER), FNKEY(7, 1, KEY_F1), FNKEY(7, 2, KEY_ESC), - FNKEY(7, 3, KEY_CAPSLOCK), + FNKEY(7, 3, KEY_TAB), FNKEY(7, 4, KEY_SEMICOLON), }; @@ -141,50 +141,79 @@ .rep = 1, }; -#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr) \ +#define GPIO_BUTTON(gpio_num, ev_type, ev_code, ev_code_fn, act_low, descr) \ { \ .gpio = gpio_num, \ .type = ev_type, \ .code = ev_code, \ + .code_fn = ev_code_fn, \ .active_low = act_low, \ .desc = "btn " descr, \ } -#define GPIO_BUTTON_LOW(gpio_num, event_code, description) \ - GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description) +#define GPIO_BUTTON_KEY_LOW(gpio_num, description) \ + GPIO_BUTTON(gpio_num, EV_KEY, 0, 0, 1, description) static struct gpio_keys_button gpio_buttons[] = { - GPIO_BUTTON_LOW(110, KEY_UP, "up"), - GPIO_BUTTON_LOW(103, KEY_DOWN, "down"), - GPIO_BUTTON_LOW(96, KEY_LEFT, "left"), - GPIO_BUTTON_LOW(98, KEY_RIGHT, "right"), - GPIO_BUTTON_LOW(109, KEY_PAGEUP, "game 1"), - GPIO_BUTTON_LOW(111, KEY_END, "game 2"), - GPIO_BUTTON_LOW(106, KEY_PAGEDOWN, "game 3"), - GPIO_BUTTON_LOW(101, KEY_HOME, "game 4"), - GPIO_BUTTON_LOW(102, KEY_RIGHTSHIFT, "l"), - GPIO_BUTTON_LOW(97, KEY_KPPLUS, "l2"), - GPIO_BUTTON_LOW(105, KEY_RIGHTCTRL, "r"), - GPIO_BUTTON_LOW(107, KEY_KPMINUS, "r2"), - GPIO_BUTTON_LOW(104, KEY_LEFTCTRL, "ctrl"), - GPIO_BUTTON(100, EV_KEY, KEY_LEFTALT, 0, "alt"), - GPIO_BUTTON_LOW(99, KEY_MENU, "menu"), - GPIO_BUTTON_LOW(176, KEY_COFFEE, "hold"), - GPIO_BUTTON(108, EV_SW, SW_LID, 1, "lid"), -}; - -static const unsigned short buttons_kbd[] = { - KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, - KEY_PAGEUP, KEY_END, KEY_PAGEDOWN, KEY_HOME, - KEY_RIGHTSHIFT, KEY_KPPLUS, KEY_RIGHTCTRL, KEY_KPMINUS, - KEY_LEFTCTRL, KEY_LEFTALT, -}; - -static const unsigned short buttons_joy[] = { - BTN_0, BTN_1, BTN_2, BTN_3, - BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, - BTN_TL, BTN_TL2, BTN_TR, BTN_TR2, - BTN_SELECT, BTN_START, + GPIO_BUTTON_KEY_LOW(110, "up"), + GPIO_BUTTON_KEY_LOW(103, "down"), + GPIO_BUTTON_KEY_LOW(96, "left"), + GPIO_BUTTON_KEY_LOW(98, "right"), + GPIO_BUTTON_KEY_LOW(109, "game 1"), + GPIO_BUTTON_KEY_LOW(111, "game 2"), + GPIO_BUTTON_KEY_LOW(106, "game 3"), + GPIO_BUTTON_KEY_LOW(101, "game 4"), + GPIO_BUTTON_KEY_LOW(102, "l"), + GPIO_BUTTON_KEY_LOW(97, "l2"), + GPIO_BUTTON_KEY_LOW(105, "r"), + GPIO_BUTTON_KEY_LOW(107, "r2"), + GPIO_BUTTON_KEY_LOW(104, "ctrl"), + GPIO_BUTTON(100, EV_KEY, 0, 0, 0, "alt"), + GPIO_BUTTON(99, EV_KEY, KEY_MENU, KEY_HELP, 1, "menu"), + GPIO_BUTTON(176, EV_KEY, KEY_COFFEE, 0, 1, "hold"), + GPIO_BUTTON(108, EV_SW, SW_LID, 0, 1, "lid"), +}; + +#define GPIO_BUTTON_CODES(ev_code, ev_code_fn) \ +{ \ + .code = ev_code, \ + .code_fn = ev_code_fn, \ +} + +#define GPIO_ORD_BUTTON_CODES(ev_code) GPIO_BUTTON_CODES(ev_code, 0) + +static const struct gpio_button_codes buttons_kbd[] = { + GPIO_BUTTON_CODES(KEY_UP, KEY_PAGEUP), + GPIO_BUTTON_CODES(KEY_DOWN, KEY_PAGEDOWN), + GPIO_BUTTON_CODES(KEY_LEFT, KEY_HOME), + GPIO_BUTTON_CODES(KEY_RIGHT, KEY_END), + GPIO_ORD_BUTTON_CODES(KEY_PROG2), + GPIO_ORD_BUTTON_CODES(KEY_PROG3), + GPIO_ORD_BUTTON_CODES(KEY_PROG4), + GPIO_ORD_BUTTON_CODES(KEY_PROG1), + GPIO_ORD_BUTTON_CODES(KEY_RIGHTSHIFT), + GPIO_ORD_BUTTON_CODES(KEY_KPPLUS), + GPIO_ORD_BUTTON_CODES(KEY_FN), + GPIO_ORD_BUTTON_CODES(KEY_KPMINUS), + GPIO_ORD_BUTTON_CODES(KEY_LEFTCTRL), + GPIO_ORD_BUTTON_CODES(KEY_LEFTALT), +}; + +static const struct gpio_button_codes buttons_joy[] = { + GPIO_ORD_BUTTON_CODES(BTN_0), + GPIO_ORD_BUTTON_CODES(BTN_1), + GPIO_ORD_BUTTON_CODES(BTN_2), + GPIO_ORD_BUTTON_CODES(BTN_3), + GPIO_ORD_BUTTON_CODES(BTN_BASE), + GPIO_ORD_BUTTON_CODES(BTN_BASE2), + GPIO_ORD_BUTTON_CODES(BTN_BASE3), + GPIO_ORD_BUTTON_CODES(BTN_BASE4), + GPIO_ORD_BUTTON_CODES(BTN_TL), + GPIO_ORD_BUTTON_CODES(BTN_TL2), + GPIO_ORD_BUTTON_CODES(BTN_TR), + GPIO_ORD_BUTTON_CODES(BTN_TR2), + GPIO_ORD_BUTTON_CODES(BTN_SELECT), + GPIO_ORD_BUTTON_CODES(BTN_START), }; static struct gpio_keys_platform_data gpio_key_info = { @@ -212,11 +241,21 @@ return sprintf(page, "%d\n", pandora_keys_gpio_mode); } +static void set_goip_button_codes(const struct gpio_button_codes *button_codes, + int button_count) +{ + int i; + for (i = 0; i < button_count; i++) { + gpio_buttons[i].code = button_codes[i].code; + gpio_buttons[i].code_fn = button_codes[i].code_fn; + } +} + static int pandora_input_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { - const unsigned short *buttons; - int i, val, button_count; + const struct gpio_button_codes *button_codes; + int val, button_count; char s[32]; if (!count) @@ -230,16 +269,15 @@ return -EINVAL; if (val == 1) { - buttons = buttons_kbd; + button_codes = buttons_kbd; button_count = ARRAY_SIZE(buttons_kbd); } else if (val == 2) { - buttons = buttons_joy; + button_codes = buttons_joy; button_count = ARRAY_SIZE(buttons_joy); } else return -EINVAL; - for (i = 0; i < button_count; i++) - gpio_buttons[i].code = buttons[i]; + set_goip_button_codes(button_codes, button_count); pandora_keys_gpio_mode = val; return count; @@ -277,6 +315,7 @@ } /* kbd mode by default */ + set_goip_button_codes(buttons_kbd, ARRAY_SIZE(buttons_kbd)); pandora_keys_gpio_mode = 1; } diff -ur linux-2.6.27-pandora-r1/arch/arm/plat-omap/include/mach/board-omap3pandora.h linux-2.6.27-pandora-r1.patched/arch/arm/plat-omap/include/mach/board-omap3pandora.h --- linux-2.6.27-pandora-r1/arch/arm/plat-omap/include/mach/board-omap3pandora.h 2010-10-20 22:58:24.000000000 +0400 +++ linux-2.6.27-pandora-r1.patched/arch/arm/plat-omap/include/mach/board-omap3pandora.h 2010-10-20 23:27:16.000000000 +0400 @@ -28,5 +28,6 @@ void __init omap3pandora_input_init(void); #define OMAP3_PANDORA_TS_GPIO 94 +#define OMAP3_PANDORA_FN_GPIO 105 #endif /* __ASM_ARCH_OMAP3_PANDORA_H */ diff -ur linux-2.6.27-pandora-r1/drivers/input/keyboard/gpio_keys.c linux-2.6.27-pandora-r1.patched/drivers/input/keyboard/gpio_keys.c --- linux-2.6.27-pandora-r1/drivers/input/keyboard/gpio_keys.c 2010-10-20 22:59:33.000000000 +0400 +++ linux-2.6.27-pandora-r1.patched/drivers/input/keyboard/gpio_keys.c 2010-10-20 23:27:16.000000000 +0400 @@ -24,6 +24,7 @@ #include #include +#include struct gpio_button_data { struct gpio_keys_button *button; @@ -39,10 +40,28 @@ static void gpio_keys_report_event(struct gpio_keys_button *button, struct input_dev *input) { + int code; unsigned int type = button->type ?: EV_KEY; int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; - input_event(input, type, button->code, !!state); + if (state) { + if (button->code_fn && + !omap_get_gpio_datain(OMAP3_PANDORA_FN_GPIO)) { + code = button->code_fn; + button->fnized = 1; + } else { + code = button->code; + } + } else { + if (button->fnized) { + code = button->code_fn; + button->fnized = 0; + } else { + code = button->code; + } + } + + input_event(input, type, code, !!state); input_sync(input); } @@ -167,10 +186,17 @@ wakeup = 1; input_set_capability(input, type, button->code); + if (button->code_fn) + input_set_capability(input, type, button->code_fn); } - for (i = 0; i < pdata->nbuttons_reserved; i++) - input_set_capability(input, EV_KEY, pdata->buttons_reserved[i]); + for (i = 0; i < pdata->nbuttons_reserved; i++) { + input_set_capability(input, EV_KEY, + pdata->buttons_reserved[i].code); + if (pdata->buttons_reserved[i].code_fn) + input_set_capability(input, EV_KEY, + pdata->buttons_reserved[i].code_fn); + } error = input_register_device(input); if (error) { diff -ur linux-2.6.27-pandora-r1/drivers/input/keyboard/twl4030_keypad.c linux-2.6.27-pandora-r1.patched/drivers/input/keyboard/twl4030_keypad.c --- linux-2.6.27-pandora-r1/drivers/input/keyboard/twl4030_keypad.c 2010-10-20 22:59:33.000000000 +0400 +++ linux-2.6.27-pandora-r1.patched/drivers/input/keyboard/twl4030_keypad.c 2010-10-20 23:27:16.000000000 +0400 @@ -34,6 +34,7 @@ #include #include +#include /* * The TWL4030 family chips include a keypad controller that supports @@ -61,8 +62,7 @@ unsigned n_cols; unsigned irq; - unsigned fn_down:1; - unsigned fn_sticked:1; + unsigned short fnized[TWL4030_KEYMAP_SIZE]; struct device *dbg_dev; struct input_dev *input; @@ -245,26 +245,22 @@ dev_dbg(kp->dbg_dev, "code: %d %d\n", code, kcode); /* Fn handling */ - if (kcode == KEY_FN) { - kp->fn_down = is_down; - kp->fn_sticked |= is_down; - } else if (kp->fn_down || kp->fn_sticked) { - /* make sure other function is up */ - input_event(input, EV_MSC, MSC_SCAN, code); - input_report_key(input, kcode, 0); - - code = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS, - col, TWL4030_ROW_SHIFT); - kcode = kp->keymap[code]; - - kp->fn_sticked = 0; - } else { - code2 = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS, - col, TWL4030_ROW_SHIFT); - input_event(input, EV_MSC, MSC_SCAN, code2); - input_report_key(input, kp->keymap[code2], 0); + if (is_down) { + if (!omap_get_gpio_datain(OMAP3_PANDORA_FN_GPIO)) { + kp->fnized[code] = 1; + code = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS, + col, TWL4030_ROW_SHIFT); + } + } + else { + if (kp->fnized[code]) { + kp->fnized[code] = 0; + code = MATRIX_SCAN_CODE(row + TWL4030_MAX_ROWS, + col, TWL4030_ROW_SHIFT); + } } + kcode = kp->keymap[code]; dev_dbg(kp->dbg_dev, "code(fn): %d %d\n", code, kcode); input_event(input, EV_MSC, MSC_SCAN, code); input_report_key(input, kcode, is_down); diff -ur linux-2.6.27-pandora-r1/include/linux/gpio_keys.h linux-2.6.27-pandora-r1.patched/include/linux/gpio_keys.h --- linux-2.6.27-pandora-r1/include/linux/gpio_keys.h 2010-10-20 23:01:12.000000000 +0400 +++ linux-2.6.27-pandora-r1.patched/include/linux/gpio_keys.h 2010-10-20 23:27:16.000000000 +0400 @@ -4,6 +4,9 @@ struct gpio_keys_button { /* Configuration parameters */ int code; /* input event code (KEY_*, SW_*) */ + int code_fn; /* 0 if key is ordinary */ + int fnized; /* release as code_fn even if fn is no longer + pressed */ int gpio; int active_low; char *desc; @@ -12,11 +15,16 @@ int debounce_interval; /* debounce ticks interval in msecs */ }; +struct gpio_button_codes { + int code; + int code_fn; +}; + struct gpio_keys_platform_data { struct gpio_keys_button *buttons; int nbuttons; unsigned int rep:1; /* enable input subsystem auto repeat */ - const unsigned short *buttons_reserved; + struct gpio_button_codes *buttons_reserved; int nbuttons_reserved; };