diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/i8042.c | 90 | ||||
-rw-r--r-- | drivers/input/input.c | 104 |
2 files changed, 167 insertions, 27 deletions
diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c index c3bc536..26958aa 100644 --- a/drivers/input/i8042.c +++ b/drivers/input/i8042.c @@ -26,6 +26,7 @@ /* includes */ #include <common.h> +#include <linux/compiler.h> #ifdef CONFIG_USE_CPCIDVI extern u8 gt_cpcidvi_in8(u32 offset); @@ -320,6 +321,54 @@ static int kbd_controller_present(void) return in8(I8042_STATUS_REG) != 0xff; } +/* + * Implement a weak default function for boards that optionally + * need to skip the i8042 initialization. + */ +int __weak board_i8042_skip(void) +{ + /* As default, don't skip */ + return 0; +} + +void i8042_flush(void) +{ + int timeout; + + /* + * The delay is to give the keyboard controller some time to fill the + * next byte. + */ + while (1) { + timeout = 100; /* wait for no longer than 100us */ + while (timeout > 0 && !(in8(I8042_STATUS_REG) & 0x01)) { + udelay(1); + timeout--; + } + + /* Try to pull next byte if not timeout. */ + if (in8(I8042_STATUS_REG) & 0x01) + in8(I8042_DATA_REG); + else + break; + } +} + +int i8042_disable(void) +{ + if (kbd_input_empty() == 0) + return -1; + + /* Disable keyboard */ + out8(I8042_COMMAND_REG, 0xad); + + if (kbd_input_empty() == 0) + return -1; + + return 0; +} + + /******************************************************************************* * * i8042_kbd_init - reset keyboard and init state flags @@ -329,7 +378,7 @@ int i8042_kbd_init(void) int keymap, try; char *penv; - if (!kbd_controller_present()) + if (!kbd_controller_present() || board_i8042_skip()) return -1; #ifdef CONFIG_USE_CPCIDVI @@ -607,11 +656,22 @@ static void kbd_led_set(void) static int kbd_input_empty(void) { - int kbdTimeout = KBD_TIMEOUT; + int kbdTimeout = KBD_TIMEOUT * 1000; + + while ((in8(I8042_STATUS_REG) & I8042_STATUS_IN_DATA) && kbdTimeout--) + udelay(1); + + return kbdTimeout != -1; +} + +/******************************************************************************/ + +static int wait_until_kbd_output_full(void) +{ + int kbdTimeout = KBD_TIMEOUT * 1000; - /* wait for input buf empty */ - while ((in8(I8042_STATUS_REG) & 0x02) && kbdTimeout--) - udelay(1000); + while (((in8(I8042_STATUS_REG) & 0x01) == 0) && kbdTimeout--) + udelay(1); return kbdTimeout != -1; } @@ -620,31 +680,39 @@ static int kbd_input_empty(void) static int kbd_reset(void) { + /* KB Reset */ if (kbd_input_empty() == 0) return -1; out8(I8042_DATA_REG, 0xff); - udelay(250000); + if (wait_until_kbd_output_full() == 0) + return -1; + + if (in8(I8042_DATA_REG) != 0xfa) /* ACK */ + return -1; + + if (wait_until_kbd_output_full() == 0) + return -1; + + if (in8(I8042_DATA_REG) != 0xaa) /* Test Pass*/ + return -1; if (kbd_input_empty() == 0) return -1; -#ifdef CONFIG_USE_CPCIDVI + /* Set KBC mode */ out8(I8042_COMMAND_REG, 0x60); -#else - out8(I8042_DATA_REG, 0x60); -#endif if (kbd_input_empty() == 0) return -1; out8(I8042_DATA_REG, 0x45); - if (kbd_input_empty() == 0) return -1; + /* Enable Keyboard */ out8(I8042_COMMAND_REG, 0xae); if (kbd_input_empty() == 0) diff --git a/drivers/input/input.c b/drivers/input/input.c index 5b2b4b0..04fa5f0 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -93,8 +93,24 @@ static unsigned char kbd_ctrl_xlate[] = { '\r', 0xff, 0xff }; +/* + * Scan key code to ANSI 3.64 escape sequence table. This table is + * incomplete in that it does not include all possible extra keys. + */ +static struct { + int kbd_scan_code; + char *escape; +} kbd_to_ansi364[] = { + { KEY_UP, "\033[A"}, + { KEY_DOWN, "\033[B"}, + { KEY_RIGHT, "\033[C"}, + { KEY_LEFT, "\033[D"}, +}; + +/* Maximum number of output characters that an ANSI sequence expands to */ +#define ANSI_CHAR_MAX 3 -int input_queue_ascii(struct input_config *config, int ch) +static int input_queue_ascii(struct input_config *config, int ch) { if (config->fifo_in + 1 == INPUT_BUFFER_LEN) { if (!config->fifo_out) @@ -289,24 +305,67 @@ static int input_check_keycodes(struct input_config *config, } /** + * Checks and converts a special key code into ANSI 3.64 escape sequence. + * + * @param config Input state + * @param keycode Key code to examine + * @param output_ch Buffer to place output characters into. It should + * be at least ANSI_CHAR_MAX bytes long, to allow for + * an ANSI sequence. + * @param max_chars Maximum number of characters to add to output_ch + * @return number of characters output, if the key was converted, otherwise 0. + * This may be larger than max_chars, in which case the overflow + * characters are not output. + */ +static int input_keycode_to_ansi364(struct input_config *config, + int keycode, char output_ch[], int max_chars) +{ + const char *escape; + int ch_count; + int i; + + for (i = ch_count = 0; i < ARRAY_SIZE(kbd_to_ansi364); i++) { + if (keycode != kbd_to_ansi364[i].kbd_scan_code) + continue; + for (escape = kbd_to_ansi364[i].escape; *escape; escape++) { + if (ch_count < max_chars) + output_ch[ch_count] = *escape; + ch_count++; + } + return ch_count; + } + + return 0; +} + +/** + * Converts and queues a list of key codes in escaped ASCII string form * Convert a list of key codes into ASCII * * You must call input_check_keycodes() before this. It turns the keycode - * list into a list of ASCII characters which are ready to send to the - * input layer. + * list into a list of ASCII characters and sends them to the input layer. * * Characters which were seen last time do not generate fresh ASCII output. + * The output (calls to queue_ascii) may be longer than num_keycodes, if the + * keycode contains special keys that was encoded to longer escaped sequence. * * @param config Input state * @param keycode List of key codes to examine * @param num_keycodes Number of key codes + * @param output_ch Buffer to place output characters into. It should + * be at last ANSI_CHAR_MAX * num_keycodes, to allow for + * ANSI sequences. + * @param max_chars Maximum number of characters to add to output_ch * @param same Number of key codes which are the same + * @return number of characters written into output_ch, or -1 if we would + * exceed max_chars chars. */ static int input_keycodes_to_ascii(struct input_config *config, - int keycode[], int num_keycodes, char output_ch[], int same) + int keycode[], int num_keycodes, char output_ch[], + int max_chars, int same) { struct input_key_xlate *table; - int ch_count; + int ch_count = 0; int i; table = &config->table[0]; @@ -321,19 +380,31 @@ static int input_keycodes_to_ascii(struct input_config *config, } } - /* now find normal keys */ - for (i = ch_count = 0; i < num_keycodes; i++) { + /* Start conversion by looking for the first new keycode (by same). */ + for (i = same; i < num_keycodes; i++) { int key = keycode[i]; + int ch = (key < table->num_entries) ? table->xlate[key] : 0xff; - if (key < table->num_entries && i >= same) { - int ch = table->xlate[key]; - - /* If a normal key with an ASCII value, add it! */ - if (ch != 0xff) - output_ch[ch_count++] = (uchar)ch; + /* + * For a normal key (with an ASCII value), add it; otherwise + * translate special key to escape sequence if possible. + */ + if (ch != 0xff) { + if (ch_count < max_chars) + output_ch[ch_count] = (uchar)ch; + ch_count++; + } else { + ch_count += input_keycode_to_ansi364(config, key, + output_ch, max_chars); } } + if (ch_count > max_chars) { + debug("%s: Output char buffer overflow size=%d, need=%d\n", + __func__, max_chars, ch_count); + return -1; + } + /* ok, so return keys */ return ch_count; } @@ -341,7 +412,7 @@ static int input_keycodes_to_ascii(struct input_config *config, int input_send_keycodes(struct input_config *config, int keycode[], int num_keycodes) { - char ch[num_keycodes]; + char ch[num_keycodes * ANSI_CHAR_MAX]; int count, i, same = 0; int is_repeat = 0; unsigned delay_ms; @@ -363,7 +434,7 @@ int input_send_keycodes(struct input_config *config, } count = input_keycodes_to_ascii(config, keycode, num_keycodes, - ch, is_repeat ? 0 : same); + ch, sizeof(ch), is_repeat ? 0 : same); for (i = 0; i < count; i++) input_queue_ascii(config, ch[i]); delay_ms = is_repeat ? @@ -371,7 +442,8 @@ int input_send_keycodes(struct input_config *config, config->repeat_delay_ms; config->next_repeat_ms = get_timer(0) + delay_ms; - return 0; + + return count; } int input_add_table(struct input_config *config, int left_keycode, |