summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Lambert <tlambert@chromium.org>2012-01-13 20:58:18 -0800
committerStefan Reinauer <reinauer@chromium.org>2012-01-17 17:02:40 -0800
commit3f68143724b1f6d94b4605faf514a5a0798b7d46 (patch)
tree5f72a0bcfe63b92b554d9456e3c048994592c0d5
parent5ed4587d170920d7f1836baed6b8553735ebd5cf (diff)
Add generation of ANSI 3.64 escape sequences.
This adds support for generation of ANSI 3.64 escape sequences to the PS/2 keyboard driver. This change significantly refactors the code: o It adds an FSA to support 0xE0 and 0xE1 multibyte PS/2 scan code sequences. o It converts the PS/2 scan codes to USB scan code values to facilitate sharing upper level code in future changes. Reasons to use USB scan codes: o Standard o Simple conversion to ASCII / ANSI 3.64 o Ability to share complex processing / state code o Shared international keymaps in higher level code o It adds an ANSI 3.64 escape sequence generator for USB special keys; the intent of doing this is to allow the transparent use of PS/2, USB, and network or serial devices using the same upper level u-boot clients. o It adds an input FIFO which is an almost verbatim copy of the Tegra matrix keyboard driver; future changes are expected to share the FIFOcode among all keyboard drivers. International keyboard support is expected to be handled at a higher layer in the future, using a much smaller NRCS (National Replacement Character Set) table instead of a duplicat table. Combined, the changes reduce the overall source file size by about 5K, and removes about 4K from the data segment as well. Note: Use of typedef for FSA states allows compiler to prohibit switch statement without default case from omitting states. BUG=chrome-os-partner:6580 TEST=Removed backslash from generated 3.64 sequences, stopped boot at command line, verified character sequence generation. Signed-off-by: tlambert@chromium.org Change-Id: I00200c5ccefd44679335fb643b21794e5d77663a modified: drivers/input/i8042.c modified: include/i8042.h Change-Id: I22c692f7bd65da5848908fc71c6cd7d04753f135 Reviewed-on: https://gerrit.chromium.org/gerrit/14218 Reviewed-by: Stefan Reinauer <reinauer@chromium.org> Reviewed-by: Gabe Black (Do Not Use) <gabeblack@google.com> Tested-by: Terry Lambert <tlambert@chromium.org> Commit-Ready: Terry Lambert <tlambert@chromium.org>
-rw-r--r--drivers/input/i8042.c996
-rw-r--r--include/i8042.h29
2 files changed, 546 insertions, 479 deletions
diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c
index f84a8dace8f..c7b1a7d8852 100644
--- a/drivers/input/i8042.c
+++ b/drivers/input/i8042.c
@@ -45,275 +45,245 @@ static int blinkCount = CONFIG_SYS_CONSOLE_BLINK_COUNT;
static int cursor_state = 0;
#endif
+/*
+ * Use a simple FIFO to convert some keys into escape sequences and to handle
+ * tstc vs getc. The FIFO length must be a power of two. Minimal function
+ * requires that it be large enough to contain the generated escape sequence for
+ * one key.
+ */
+#define KBC_FIFO_LENGTH (1 << 3)
+
+static int kbc_fifo[KBC_FIFO_LENGTH];
+static int kbc_fifo_read;
+static int kbc_fifo_write;
+
+
/* locals */
-static int kbd_input = -1; /* no input yet */
static int kbd_mapping = KBD_US; /* default US keyboard */
static int kbd_flags = NORMAL; /* after reset */
-static int kbd_state = 0; /* unshift code */
-
-static void kbd_conv_char (unsigned char scan_code);
-static void kbd_led_set (void);
-static void kbd_normal (unsigned char scan_code);
-static void kbd_shift (unsigned char scan_code);
-static void kbd_ctrl (unsigned char scan_code);
-static void kbd_num (unsigned char scan_code);
-static void kbd_caps (unsigned char scan_code);
-static void kbd_scroll (unsigned char scan_code);
-static void kbd_alt (unsigned char scan_code);
-static int kbd_input_empty (void);
+static int kbd_state; /* unshift code */
+static int kbd_key_release; /* key release in progress */
+
+static int kbd_conv_usb(unsigned char scan_code);
+static void kbd_led_set(int ps2_leds);
+static int i8042_ready(void);
static int kbd_reset (void);
-static unsigned char kbd_fct_map [144] =
- { /* kbd_fct_map table for scan code */
- 0, AS, AS, AS, AS, AS, AS, AS, /* scan 0- 7 */
- AS, AS, AS, AS, AS, AS, AS, AS, /* scan 8- F */
- AS, AS, AS, AS, AS, AS, AS, AS, /* scan 10-17 */
- AS, AS, AS, AS, AS, CN, AS, AS, /* scan 18-1F */
- AS, AS, AS, AS, AS, AS, AS, AS, /* scan 20-27 */
- AS, AS, SH, AS, AS, AS, AS, AS, /* scan 28-2F */
- AS, AS, AS, AS, AS, AS, SH, AS, /* scan 30-37 */
- AS, AS, CP, 0, 0, 0, 0, 0, /* scan 38-3F */
- 0, 0, 0, 0, 0, NM, ST, ES, /* scan 40-47 */
- ES, ES, ES, ES, ES, ES, ES, ES, /* scan 48-4F */
- ES, ES, ES, ES, 0, 0, AS, 0, /* scan 50-57 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */
- AS, 0, 0, AS, 0, 0, AS, 0, /* scan 70-77 */
- 0, AS, 0, 0, 0, AS, 0, 0, /* scan 78-7F */
- AS, CN, AS, AS, AK, ST, EX, EX, /* enhanced */
- AS, EX, EX, AS, EX, AS, EX, EX /* enhanced */
- };
-
-static unsigned char kbd_key_map [2][5][144] =
- {
- { /* US keyboard */
- { /* unshift code */
- 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */
- '7', '8', '9', '0', '-', '=', 0x08, '\t', /* scan 8- F */
- 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', /* scan 10-17 */
- 'o', 'p', '[', ']', '\r', CN, 'a', 's', /* scan 18-1F */
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* scan 20-27 */
- '\'', '`', SH, '\\', 'z', 'x', 'c', 'v', /* scan 28-2F */
- 'b', 'n', 'm', ',', '.', '/', SH, '*', /* scan 30-37 */
- ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */
- 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */
- '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */
- '2', '3', '0', '.', 0, 0, 0, 0, /* scan 50-57 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */
- 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */
- },
- { /* shift code */
- 0, 0x1b, '!', '@', '#', '$', '%', '^', /* scan 0- 7 */
- '&', '*', '(', ')', '_', '+', 0x08, '\t', /* scan 8- F */
- 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', /* scan 10-17 */
- 'O', 'P', '{', '}', '\r', CN, 'A', 'S', /* scan 18-1F */
- 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* scan 20-27 */
- '"', '~', SH, '|', 'Z', 'X', 'C', 'V', /* scan 28-2F */
- 'B', 'N', 'M', '<', '>', '?', SH, '*', /* scan 30-37 */
- ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */
- 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */
- '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */
- '2', '3', '0', '.', 0, 0, 0, 0, /* scan 50-57 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */
- 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */
- },
- { /* control code */
- 0xff, 0x1b, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, /* scan 0- 7 */
- 0x1e, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, '\t', /* scan 8- F */
- 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* scan 10-17 */
- 0x0f, 0x10, 0x1b, 0x1d, '\r', CN, 0x01, 0x13, /* scan 18-1F */
- 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0xff, /* scan 20-27 */
- 0xff, 0x1c, SH, 0xff, 0x1a, 0x18, 0x03, 0x16, /* scan 28-2F */
- 0x02, 0x0e, 0x0d, 0xff, 0xff, 0xff, SH, 0xff, /* scan 30-37 */
- 0xff, 0xff, CP, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
- 0xff, 0xff, 0xff, 0xff, 0xff, NM, ST, 0xff, /* scan 40-47 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50-57 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 0xff, 0xff, /* extended */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */
- },
- { /* non numeric code */
- 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */
- '7', '8', '9', '0', '-', '=', 0x08, '\t', /* scan 8- F */
- 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', /* scan 10-17 */
- 'o', 'p', '[', ']', '\r', CN, 'a', 's', /* scan 18-1F */
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* scan 20-27 */
- '\'', '`', SH, '\\', 'z', 'x', 'c', 'v', /* scan 28-2F */
- 'b', 'n', 'm', ',', '.', '/', SH, '*', /* scan 30-37 */
- ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */
- 0, 0, 0, 0, 0, NM, ST, 'w', /* scan 40-47 */
- 'x', 'y', 'l', 't', 'u', 'v', 'm', 'q', /* scan 48-4F */
- 'r', 's', 'p', 'n', 0, 0, 0, 0, /* scan 50-57 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */
- 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */
- },
- { /* right alt mode - not used in US keyboard */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 0 - 7 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 8 - F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10 -17 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 18 -1F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20 -27 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28 -2F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30 -37 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38 -3F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40 -47 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48 -4F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50 -57 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58 -5F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60 -67 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68 -6F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70 -77 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78 -7F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* extended */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */
- }
- },
- { /* german keyboard */
- { /* unshift code */
- 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */
- '7', '8', '9', '0', 0xe1, '\'', 0x08, '\t', /* scan 8- F */
- 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', /* scan 10-17 */
- 'o', 'p', 0x81, '+', '\r', CN, 'a', 's', /* scan 18-1F */
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', 0x94, /* scan 20-27 */
- 0x84, '^', SH, '#', 'y', 'x', 'c', 'v', /* scan 28-2F */
- 'b', 'n', 'm', ',', '.', '-', SH, '*', /* scan 30-37 */
- ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */
- 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */
- '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */
- '2', '3', '0', ',', 0, 0, '<', 0, /* scan 50-57 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */
- 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */
- },
- { /* shift code */
- 0, 0x1b, '!', '"', 0x15, '$', '%', '&', /* scan 0- 7 */
- '/', '(', ')', '=', '?', '`', 0x08, '\t', /* scan 8- F */
- 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', /* scan 10-17 */
- 'O', 'P', 0x9a, '*', '\r', CN, 'A', 'S', /* scan 18-1F */
- 'D', 'F', 'G', 'H', 'J', 'K', 'L', 0x99, /* scan 20-27 */
- 0x8e, 0xf8, SH, '\'', 'Y', 'X', 'C', 'V', /* scan 28-2F */
- 'B', 'N', 'M', ';', ':', '_', SH, '*', /* scan 30-37 */
- ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */
- 0, 0, 0, 0, 0, NM, ST, '7', /* scan 40-47 */
- '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */
- '2', '3', '0', ',', 0, 0, '>', 0, /* scan 50-57 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */
- 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */
- },
- { /* control code */
- 0xff, 0x1b, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, /* scan 0- 7 */
- 0x1e, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, '\t', /* scan 8- F */
- 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* scan 10-17 */
- 0x0f, 0x10, 0x1b, 0x1d, '\r', CN, 0x01, 0x13, /* scan 18-1F */
- 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0xff, /* scan 20-27 */
- 0xff, 0x1c, SH, 0xff, 0x1a, 0x18, 0x03, 0x16, /* scan 28-2F */
- 0x02, 0x0e, 0x0d, 0xff, 0xff, 0xff, SH, 0xff, /* scan 30-37 */
- 0xff, 0xff, CP, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
- 0xff, 0xff, 0xff, 0xff, 0xff, NM, ST, 0xff, /* scan 40-47 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 50-57 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 0xff, 0xff, /* extended */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */
- },
- { /* non numeric code */
- 0, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 0- 7 */
- '7', '8', '9', '0', 0xe1, '\'', 0x08, '\t', /* scan 8- F */
- 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', /* scan 10-17 */
- 'o', 'p', 0x81, '+', '\r', CN, 'a', 's', /* scan 18-1F */
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', 0x94, /* scan 20-27 */
- 0x84, '^', SH, 0, 'y', 'x', 'c', 'v', /* scan 28-2F */
- 'b', 'n', 'm', ',', '.', '-', SH, '*', /* scan 30-37 */
- ' ', ' ', CP, 0, 0, 0, 0, 0, /* scan 38-3F */
- 0, 0, 0, 0, 0, NM, ST, 'w', /* scan 40-47 */
- 'x', 'y', 'l', 't', 'u', 'v', 'm', 'q', /* scan 48-4F */
- 'r', 's', 'p', 'n', 0, 0, '<', 0, /* scan 50-57 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 58-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 60-67 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 68-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 70-77 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* scan 78-7F */
- '\r', CN, '/', '*', ' ', ST, 'F', 'A', /* extended */
- 0, 'D', 'C', 0, 'B', 0, '@', 'P' /* extended */
- },
- { /* Right alt mode - is used in German keyboard */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 0 - 7 */
- '{', '[', ']', '}', '\\', 0xff, 0xff, 0xff, /* scan 8 - F */
- '@', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10 -17 */
- 0xff, 0xff, 0xff, '~', 0xff, 0xff, 0xff, 0xff, /* scan 18 -1F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20 -27 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28 -2F */
- 0xff, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30 -37 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38 -3F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40 -47 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48 -4F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '|', 0xff, /* scan 50 -57 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58 -5F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60 -67 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68 -6F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70 -77 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78 -7F */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* extended */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* extended */
- }
- }
- };
-static unsigned char ext_key_map [] =
- {
- 0x1c, /* keypad enter */
- 0x1d, /* right control */
- 0x35, /* keypad slash */
- 0x37, /* print screen */
- 0x38, /* right alt */
- 0x46, /* break */
- 0x47, /* editpad home */
- 0x48, /* editpad up */
- 0x49, /* editpad pgup */
- 0x4b, /* editpad left */
- 0x4d, /* editpad right */
- 0x4f, /* editpad end */
- 0x50, /* editpad dn */
- 0x51, /* editpad pgdn */
- 0x52, /* editpad ins */
- 0x53, /* editpad del */
- 0x00 /* map end */
- };
+/*
+ * Translate PS/2 Keyboard Scan Code Set 1 values into the USB Scan Codes
+ *
+ * Reasons to use USB scan codes:
+ * o Standard
+ * o Simple conversion to ASCII / ANSI 3.64
+ * o Ability to share complex processing / state code
+ * o Shared international keymaps in higher level code
+ *
+ * Extended codes (pseudo PS/2 scan codes >= 0x80) are positionally
+ * translated from "0xE0 + scan code" using a linear table to save
+ * data size; we intentionally do not support odd multibyte sequences.
+ */
+
+/* Scan codes following a 0xE0 scan code... */
+static unsigned char ext_0_key_usb[] = {
+ 0x00, /* UNSUPPORTED: Print Screen (multibyte) */
+ 0x00, /* UNSUPPORTED: Pause (multibyte) */
+ 0x00, /* RESERVED: Keypad 5 (undefined action key) */
+
+ 0x5E, /* Power */
+ 0x5F, /* RESERVED: Sleep (maps to Keyboard Power) */
+ 0x63, /* RESERVED: Wake (maps to Keyboard Power) */
+
+ 0x35, /* Keypad Enter */
+ 0x1C, /* Keypad / */
+ 0x5B, /* Left GUI */
+ 0x1D, /* Right Control */
+ 0x38, /* Right Alt / Alt GR */
+ 0x5C, /* Right GUI */
+
+ 0x52, /* Insert */
+ 0x47, /* Home */
+ 0x49, /* Page Up */
+ 0x53, /* Delete Forward */
+ 0x4F, /* End */
+ 0x51, /* Page Down */
+ 0x4D, /* Right */
+ 0x4B, /* Left */
+ 0x50, /* Down */
+ 0x48 /* Up */
+};
+#define EXT_0_KEY_USB_SIZE ARRAY_SIZE(ext_0_key_usb)
+
+static unsigned char sc_to_usb[0x80 + EXT_0_KEY_USB_SIZE] = {
+ 0x00, 0x29, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, /* scan 00-07 */
+ 0x24, 0x25, 0x26, 0x27, 0x2D, 0x2E, 0x2A, 0x2B, /* scan 08-0F */
+ 0x14, 0x1A, 0x08, 0x15, 0x17, 0x1C, 0x18, 0x0C, /* scan 10-17 */
+ 0x12, 0x13, 0x2F, 0x30, 0x28, 0xE0, 0x04, 0x16, /* scan 18-1F */
+ 0x07, 0x09, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x33, /* scan 20-27 */
+ 0x34, 0x35, 0xE1, 0x31, 0x1D, 0x1B, 0x06, 0x19, /* scan 28-2F */
+ 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xE5, 0x55, /* scan 30-37 */
+ 0xE2, 0x2C, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, /* scan 38-3F */
+ 0x3F, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5F, /* scan 40-47 */
+ 0x60, 0x61, 0x56, 0x5C, 0x5D, 0x5E, 0x57, 0x59, /* scan 48-4F */
+ 0x5A, 0x5B, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, /* scan 50-57 */
+ 0x45, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, /* scan 58-5F */
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* scan 60-67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* scan 68-6F */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* scan 70-77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* scan 78-7F */
+ 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x58, 0x54, /* extended*/
+ 0xE3, 0xE4, 0xE6, 0x5C, 0x49, 0x4A, 0x4B, 0x4C, /* extended*/
+ 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52 /* extended*/
+};
+
+/*
+ * USB scan code to ANSI 3.64 escape sequence table. This table is
+ * incomplete in that it does not include all possible extra keys, nor
+ * the 0xE1 report keys.
+ */
+static struct map364 {
+ unsigned char usb_scan_code;
+ char *string;
+} usb_to_ansi364[] = {
+ { 0x49, "\033[2~"}, /* Insert */
+ { 0x4A, "\033[0H"}, /* Home */
+ { 0x4B, "\033[5~"}, /* Page Up */
+ { 0x4C, "\033[3~"}, /* Delete Forward */
+ { 0x4D, "\033[0F"}, /* End */
+ { 0x4E, "\033[3~"}, /* Page Down */
+ { 0x4F, "\033[C"}, /* Right */
+ { 0x50, "\033[D"}, /* Left */
+ { 0x51, "\033[B"}, /* Down */
+ { 0x52, "\033[A"}, /* Up */
+ { 0x3A, "\033[OP" }, /* F1 */
+ { 0x3B, "\033[OQ" }, /* F2 */
+ { 0x3C, "\033[OR" }, /* F3 */
+ { 0x3D, "\033[OS" }, /* F4 */
+ { 0x3E, "\033[15~" }, /* F5 */
+ { 0x3F, "\033[17~" }, /* F6 */
+ { 0x40, "\033[18~" }, /* F7 */
+ { 0x41, "\033[19~" }, /* F8 */
+ { 0x42, "\033[20~" }, /* F9 */
+ { 0x43, "\033[21~" }, /* F10 */
+ { 0x44, "\033[23~" }, /* F11 */
+ { 0x45, "\033[24~" } /* F12 */
+};
+#define USB_TO_ANSI364_SIZE ARRAY_SIZE(usb_to_ansi364)
+
+/* Modifier bits */
+#define LEFT_CNTR (1 << 0)
+#define LEFT_SHIFT (1 << 1)
+#define LEFT_ALT (1 << 2)
+#define LEFT_GUI (1 << 3)
+#define RIGHT_CNTR (1 << 4)
+#define RIGHT_SHIFT (1 << 5)
+#define RIGHT_ALT (1 << 6)
+#define RIGHT_GUI (1 << 7)
+
+/* USB locking modifier keys */
+#define USB_KEY_NUM_LOCK 0x53
+#define USB_KEY_CAPS_LOCK 0x39
+#define USB_KEY_SCROLL_LOCK 0x47
+
+/* Masking for lower to upper case conversion */
+#define CAPITAL_MASK 0x20
+
+/* USB LED bit order; the mask is to avoid sending unknown bits */
+#define USB_KBD_NUMLOCK (1 << 0)
+#define USB_KBD_CAPSLOCK (1 << 1)
+#define USB_KBD_SCROLLLOCK (1 << 2)
+#define USB_KBD_LEDMASK \
+ (USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK)
+
+/*
+ * Convert from USB "Set LEDs" command bit order to PS/2 Port 0x60
+ * Command 0xED bit order.
+ */
+static unsigned char usb_kbd_led_to_ps2(unsigned char usb_led_bits)
+{
+ return (((usb_led_bits) << 1) & 0x03) |
+ ((usb_led_bits & USB_KBD_SCROLLLOCK) ? 0x01 : 0x00);
+}
+
+
+static unsigned char bits_modifiers; /* individual modifier keys */
+static unsigned char bits_state; /* modifier state (includes LED bits) */
+
+/* States for the FSA that manages input of PS/2 scan codes */
+typedef enum {
+ KS_BASE = 0, /* Base state */
+ KS_EXTENDED_0, /* Extended (E0) scan code byte expected */
+ KS_EXTENDED_1A, /* Extended (E1) scan code first byte expected */
+ KS_EXTENDED_1B, /* Extended (E1) scan code second byte expected */
+} ps2_kbd_state_t;
+
+static ps2_kbd_state_t ps2_kbd_state = KS_BASE;
+
+/* Keyboard maps */
+static const unsigned char usb_kbd_numkey[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ '\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']',
+ '\\', '#', ';', '\'', '`', ',', '.', '/'
+};
+static const unsigned char usb_kbd_numkey_shifted[] = {
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+ '\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}',
+ '|', '~', ':', '"', '~', '<', '>', '?'
+};
+
+
+
+/*
+ * Simple FIFO for conversion of input characters to escape sequences
+ */
+
+/* Return true if there are no characters in the FIFO. */
+static int kbd_fifo_empty(void)
+{
+ return kbc_fifo_read == kbc_fifo_write;
+}
+
+/* Return number of characters of free space in the FIFO. */
+static int kbd_fifo_free_space(void)
+{
+ return KBC_FIFO_LENGTH - (kbc_fifo_write - kbc_fifo_read);
+}
+
+/*
+ * Insert a character into the FIFO. Calling this function when the FIFO is
+ * full will overwrite the oldest character in the FIFO.
+ */
+static void kbd_fifo_insert(int key)
+{
+ int index = kbc_fifo_write & (KBC_FIFO_LENGTH - 1);
+
+ /* Special case for unregocnized keys */
+ if (key == 0x00)
+ return;
+
+ assert(kbd_fifo_free_space() > 0);
+
+ kbc_fifo[index] = key;
+
+ kbc_fifo_write++;
+}
+
+/*
+ * Remove a character from the FIFO, it is an error to call this function when
+ * the FIFO is empty.
+ */
+static int kbd_fifo_remove(void)
+{
+ int index = kbc_fifo_read & (KBC_FIFO_LENGTH - 1);
+ int key = kbc_fifo[index];
+
+ assert(!kbd_fifo_empty());
+
+ kbc_fifo_read++;
+
+ return key;
+}
/******************************************************************************/
@@ -367,7 +337,7 @@ int i8042_kbd_init (void)
kbd_mapping = keymap;
kbd_flags = NORMAL;
kbd_state = 0;
- kbd_led_set();
+ kbd_led_set(0); /* Start with LEDs off */
return 0;
}
}
@@ -383,6 +353,11 @@ int i8042_kbd_init (void)
int i8042_tstc (void)
{
unsigned char scan_code = 0;
+ int kbd_input;
+
+ /* If there's something in the fifo, we're done. */
+ if (!kbd_fifo_empty())
+ return 1;
#ifdef CONFIG_CONSOLE_CURSOR
if (--blinkCount == 0)
@@ -394,36 +369,35 @@ int i8042_tstc (void)
}
#endif
- if ((in8 (I8042_STATUS_REG) & 0x01) == 0)
+ if ((in8(I8042_STATUS_REG) & I8042_STR_OBF) == 0)
return 0;
else
{
- scan_code = in8 (I8042_DATA_REG);
+ scan_code = in8(I8042_DATA_REG);
if (scan_code == 0xfa)
return 0;
- kbd_conv_char(scan_code);
-
- if (kbd_input != -1)
- return 1;
+ kbd_input = kbd_conv_usb(scan_code);
+ if (kbd_input != -1) {
+ kbd_fifo_insert(kbd_input);
+ return 1;
+ }
}
return 0;
}
-/*******************************************************************************
- *
- * i8042_getc - wait till keyboard input is available
- * option: turn on/off cursor while waiting
- */
-int i8042_getc (void)
+/******************************************************************************/
+
+/* option: turn on/off cursor while waiting */
+static void kbd_fetch_char(int test)
{
- int ret_chr;
unsigned char scan_code;
+ int kbd_input = -1;
while (kbd_input == -1)
{
- while ((in8 (I8042_STATUS_REG) & 0x01) == 0)
+ while ((in8(I8042_STATUS_REG) & I8042_STR_OBF) == 0)
{
#ifdef CONFIG_CONSOLE_CURSOR
if (--blinkCount==0)
@@ -436,253 +410,317 @@ int i8042_getc (void)
#endif
}
- scan_code = in8 (I8042_DATA_REG);
+ scan_code = in8(I8042_DATA_REG);
- if (scan_code != 0xfa)
- kbd_conv_char (scan_code);
- }
- ret_chr = kbd_input;
- kbd_input = -1;
- return ret_chr;
-}
-
-
-/******************************************************************************/
-
-static void kbd_conv_char (unsigned char scan_code)
-{
- if (scan_code == 0xe0)
- {
- kbd_flags |= EXT;
- return;
- }
-
- /* if high bit of scan_code, set break flag */
- if (scan_code & 0x80)
- kbd_flags |= BRK;
- else
- kbd_flags &= ~BRK;
-
- if ((scan_code == 0xe1) || (kbd_flags & E1))
- {
- if (scan_code == 0xe1)
- {
- kbd_flags ^= BRK; /* reset the break flag */
- kbd_flags ^= E1; /* bitwise EXOR with E1 flag */
- }
- return;
- }
-
- scan_code &= 0x7f;
-
- if (kbd_flags & EXT)
- {
- int i;
-
- kbd_flags ^= EXT;
- for (i=0; ext_key_map[i]; i++)
- {
- if (ext_key_map[i] == scan_code)
- {
- scan_code = 0x80 + i;
- break;
- }
+ if (scan_code != 0xfa) {
+ kbd_input = kbd_conv_usb(scan_code);
+ if (kbd_input != -1)
+ break;
}
- /* not found ? */
- if (!ext_key_map[i])
- return;
}
- switch (kbd_fct_map [scan_code])
- {
- case AS: kbd_normal (scan_code);
- break;
- case SH: kbd_shift (scan_code);
- break;
- case CN: kbd_ctrl (scan_code);
- break;
- case NM: kbd_num (scan_code);
- break;
- case CP: kbd_caps (scan_code);
- break;
- case ST: kbd_scroll (scan_code);
- break;
- case AK: kbd_alt (scan_code);
- break;
- }
- return;
+ kbd_fifo_insert(kbd_input);
}
-
-/******************************************************************************/
-
-static void kbd_normal (unsigned char scan_code)
+/*******************************************************************************
+ *
+ * i8042_getc - wait till keyboard input is available
+ */
+int i8042_getc(void)
{
- unsigned char chr;
+ if (kbd_fifo_empty())
+ kbd_fetch_char(0);
- if ((kbd_flags & BRK) == NORMAL)
- {
- chr = kbd_key_map [kbd_mapping][kbd_state][scan_code];
- if ((chr == 0xff) || (chr == 0x00))
- {
- return;
- }
-
- /* if caps lock convert upper to lower */
- if (((kbd_flags & CAPS) == CAPS) && (chr >= 'a' && chr <= 'z'))
- {
- chr -= 'a' - 'A';
- }
- kbd_input = chr;
- }
+ return kbd_fifo_remove();
}
/******************************************************************************/
-static void kbd_shift (unsigned char scan_code)
+static unsigned char scan_code_convert_ps2_usb(unsigned char scan_code)
{
- if ((kbd_flags & BRK) == BRK)
- {
- kbd_state = AS;
- kbd_flags &= (~SHIFT);
- }
- else
- {
- kbd_state = SH;
- kbd_flags |= SHIFT;
- }
-}
-
+ unsigned char cooked_scan_code = (scan_code & 0x7F);
+ unsigned char usb_scan_code = 0x00; /* keep compiler happy */
+ int offset;
+
+ /* Reset the FSA on illegal scan codes */
+ if (ps2_kbd_state != KS_BASE &&
+ (scan_code == 0xE0 || scan_code == 0xE1)) {
+ ps2_kbd_state = KS_BASE;
+ return 0x00;
+ }
-/******************************************************************************/
+ /*
+ * If the high bit is set, this is a break code, otherwise it is a
+ * make code.
+ */
+ if (scan_code & 0x80)
+ kbd_key_release = 1;
+ else
+ kbd_key_release = 0;
+
+ /* PS/2 Scan code FSA */
+ switch (ps2_kbd_state) {
+ case KS_BASE:
+ if (scan_code == 0xE0) {
+ ps2_kbd_state = KS_EXTENDED_0;
+ usb_scan_code = 0x00;
+ break;
+ }
+ /* 0xE1 is Only used by the Pause / Break key */
+ if (scan_code == 0xE1) {
+ ps2_kbd_state = KS_EXTENDED_1A;
+ usb_scan_code = 0x00;
+ break;
+ }
+
+ /*
+ * Convert the cooked scan code. For unrecognized scan
+ * codes, we have explicit 0x00 values in the table.
+ */
+ usb_scan_code = sc_to_usb[cooked_scan_code];
+ break;
-static void kbd_ctrl (unsigned char scan_code)
-{
- if ((kbd_flags & BRK) == BRK)
- {
- kbd_state = AS;
- kbd_flags &= (~CTRL);
- }
- else
- {
- kbd_state = CN;
- kbd_flags |= CTRL;
- }
-}
+ case KS_EXTENDED_0:
+
+ for (offset = 0; offset < EXT_0_KEY_USB_SIZE; offset++) {
+ if (cooked_scan_code != ext_0_key_usb[offset])
+ continue;
+ usb_scan_code = sc_to_usb[0x80 + offset];
+ break;
+ }
+
+ /*
+ * Note: Reset to base here precludes parsing Print Screen
+ * sequence 0xE0 0x2A 0xE0 0x37, and inverse sequence
+ * 0xE0 0xB7 0xE0 0xAA (Note inverse break scan code
+ * order if you intend to handle this case!).
+ */
+ ps2_kbd_state = KS_BASE;
+
+ /* Unrecognized scan code following 0xE0 */
+ if (offset == EXT_0_KEY_USB_SIZE)
+ usb_scan_code = 0x00;
+ break;
+ case KS_EXTENDED_1A:
+ case KS_EXTENDED_1B:
+ /* The Pause key sends 2 bytes following the state change */
+ if (ps2_kbd_state == KS_EXTENDED_1A)
+ ps2_kbd_state = KS_EXTENDED_1B;
+ else
+ ps2_kbd_state = KS_BASE;
+
+ /*
+ * Note: The Pause key make sequence is 0xE1 0x1D 0x45; it
+ * is always immediately followed by its break sequence
+ * of 0xE1, 0x9D, 0xC5; there is no persistent make
+ * state duration for the Pause key, for which reason
+ * it is normally treated as a toggle by upper level
+ * software. Handling is not recommended.
+ */
+ usb_scan_code = 0x00;
+ break;
+ }
-/******************************************************************************/
+ /* Locking modifier keys notify on press and again on release. */
+ if (!kbd_key_release) {
+ unsigned char old_bits_state = bits_state;
+
+ switch (usb_scan_code) {
+ case USB_KEY_NUM_LOCK:
+ bits_state ^= USB_KBD_NUMLOCK;
+ break;
+ case USB_KEY_CAPS_LOCK:
+ bits_state ^= USB_KBD_CAPSLOCK;
+ break;
+ case USB_KEY_SCROLL_LOCK:
+ bits_state ^= USB_KBD_SCROLLLOCK;
+ break;
+ }
+ /* If we changed any bits, poke the LEDs. */
+ if (old_bits_state != bits_state)
+ kbd_led_set(usb_kbd_led_to_ps2(bits_state));
+ }
-static void kbd_caps (unsigned char scan_code)
-{
- if ((kbd_flags & BRK) == NORMAL)
- {
- kbd_flags ^= CAPS;
- kbd_led_set (); /* update keyboard LED */
- }
+ return usb_scan_code;
}
+/*
+ * For a given USB scan code, cook the value into zero or more character
+ * codes. Because Ctrl-Space is NUL, we return an integer value which may
+ * be -1 in the case that the key doesn't result in a character code.
+ */
+static int usb_cook_scan_code(unsigned char usb_scan_code)
+{
+ int index;
+
+ /*
+ * Handle in-band modifier keys.
+ *
+ * Note: These are not generated by USB keyboards with working
+ * USB 1.1 HID compliant firmware, but broken firmware
+ * exists. This conversion is therefore safe for all keyboards.
+ */
+ if (usb_scan_code >= 0xE0 && usb_scan_code <= 0xE7) {
+ unsigned char bit = (1 << (usb_scan_code - 0xE0));
+
+ if (kbd_key_release)
+ bits_modifiers &= ~bit;
+ else
+ bits_modifiers |= bit;
+
+ return -1;
+ }
-/******************************************************************************/
+ /*
+ * Key up only changes modifier state.
+ *
+ * LATER: Add shadow matrix support so u-boot clients can query the
+ * state of keys. This will allow the upper level code to
+ * implement things like continuing to hold the power button
+ * to enter DFU mode, or use Ctrl-Alt-T to enter target disk
+ * node, etc..
+ */
+ if (kbd_key_release)
+ return -1;
+
+ /* Handle special sequence keys; this doesn't need performance */
+ for (index = 0; index < USB_TO_ANSI364_SIZE; index++) {
+ char *p;
+ if (usb_scan_code != usb_to_ansi364[index].usb_scan_code)
+ continue;
+ /* Stuff the FIFO ourselves; sign coerce static strings */
+ for (p = usb_to_ansi364[index].string; *p; p++)
+ kbd_fifo_insert((unsigned char)*p);
+ /* If not, this is an unsupported key */
+ return -1;
+ }
-static void kbd_num (unsigned char scan_code)
-{
- if ((kbd_flags & BRK) == NORMAL)
- {
- kbd_flags ^= NUM;
- kbd_state = (kbd_flags & NUM) ? AS : NM;
- kbd_led_set (); /* update keyboard LED */
- }
-}
+ /* Handle numeric keypad keys */
+ if ((usb_scan_code > 0x1d) && (usb_scan_code < 0x3a)) {
+ int shifted;
+ /* Shift inverts Num Lock state */
+ shifted = (bits_modifiers & (LEFT_SHIFT | RIGHT_SHIFT)) != 0;
+ if (bits_state & USB_KBD_NUMLOCK)
+ shifted = !shifted;
-/******************************************************************************/
+ if (shifted)
+ return usb_kbd_numkey_shifted[usb_scan_code - 0x1e];
+ else
+ return usb_kbd_numkey[usb_scan_code - 0x1e];
+ }
-static void kbd_scroll (unsigned char scan_code)
-{
- if ((kbd_flags & BRK) == NORMAL)
- {
- kbd_flags ^= STP;
- kbd_led_set (); /* update keyboard LED */
- if (kbd_flags & STP)
- kbd_input = 0x13;
- else
- kbd_input = 0x11;
- }
+ /* Handle control keys */
+ /*
+ * Note: This is a compromise; it gets the right values for the
+ * right keys, but for unexpected keys, the control character
+ * sent will depend on the usb_scan_code. This approximates
+ * PS/2 historical behaviour.
+ */
+ if (bits_modifiers & (LEFT_CNTR | RIGHT_CNTR))
+ return (usb_scan_code - 0x03) & 0x1F;
+
+ /* Handle ordinary alphanumerics */
+ if ((usb_scan_code > 0x03) && (usb_scan_code <= 0x1D)) {
+ int keycode = usb_scan_code - 0x04 + 'a';
+
+ /* Caps Lock */
+ if (bits_state & USB_KBD_CAPSLOCK)
+ keycode &= ~CAPITAL_MASK;
+
+ /* Shift inverts Caps Lock state */
+ if (bits_modifiers & (LEFT_SHIFT | RIGHT_SHIFT)) {
+ if (keycode & CAPITAL_MASK)
+ keycode &= ~CAPITAL_MASK;
+ else
+ keycode |= CAPITAL_MASK;
+ }
+ return keycode;
+ }
+ return -1;
}
-/******************************************************************************/
-
-static void kbd_alt (unsigned char scan_code)
+static int kbd_conv_usb(unsigned char scan_code)
{
- if ((kbd_flags & BRK) == BRK)
- {
- kbd_state = AS;
- kbd_flags &= (~ALT);
- }
- else
- {
- kbd_state = AK;
- kbd_flags &= ALT;
- }
+ unsigned char usbcode;
+
+ usbcode = scan_code_convert_ps2_usb(scan_code);
+ return usb_cook_scan_code(usbcode);
}
/******************************************************************************/
-static void kbd_led_set (void)
+static void kbd_led_set(int ps2_leds)
{
- kbd_input_empty();
- out8 (I8042_DATA_REG, 0xed); /* SET LED command */
- kbd_input_empty();
- out8 (I8042_DATA_REG, (kbd_flags & 0x7)); /* LED bits only */
+ i8042_ready();
+ out8(I8042_DATA_REG, I8042_DATA_LED_WRITE); /* SET LED command */
+ i8042_ready();
+ out8(I8042_DATA_REG, (ps2_leds & I8042_LED_MASK)); /* LED bits only */
}
-/******************************************************************************/
-
-static int kbd_input_empty (void)
+/*******************************************************************************
+ *
+ * i8042_ready - wait for the i8042 to finish processing commands/data
+ * or a timeout
+ */
+static int i8042_ready(void)
{
- int kbdTimeout = KBD_TIMEOUT * 1000;
+ int kbdTimeout = KBD_TIMEOUT * 1000;
- while ((in8 (I8042_STATUS_REG) & 0x02) && kbdTimeout--)
- udelay(1);
+ while ((in8(I8042_STATUS_REG) & I8042_STR_IBF) && kbdTimeout--)
+ udelay(1);
- return kbdTimeout != -1;
+ return kbdTimeout != -1;
}
/******************************************************************************/
-static int kbd_reset (void)
+static int kbd_reset(void)
{
- if (kbd_input_empty() == 0)
- return -1;
-
- out8 (I8042_DATA_REG, 0xff);
-
- if (kbd_input_empty() == 0)
- return -1;
-
-#ifdef CONFIG_USE_CPCIDVI
- out8 (I8042_COMMAND_REG, 0x60);
-#else
- out8 (I8042_DATA_REG, 0x60);
-#endif
+ if (i8042_ready() == 0)
+ return -1;
+
+ out8(I8042_DATA_REG, I8042_DATA_KBD_RESET);
+
+ if (i8042_ready() == 0)
+ return -1;
+
+ out8(I8042_COMMAND_REG, I8042_CMD_SET_CMD_BYTE);
+
+ if (i8042_ready() == 0)
+ return -1;
+
+ /*
+ * Command byte - bitmask:
+ *
+ * 7 0 = unused; set to 0
+ * 6 0 = no scan code conversion
+ * 1 = standard scan code conversion
+ * 5 0 = check parity, with scan code conversion
+ * 1 = ignore parity, no scan code coversion
+ * 4 0 = Enable keyboard
+ * 1 = Disable keyboard by forcing CLK low
+ * 3 0 = Normal keyboard inhibit function
+ * 1 = Override keyboard inhibit function (used for POST)
+ * 2 0 = System flag status bit indicates reset by power on
+ * 1 = System flag after successful controller self test
+ * 1 0 = unused; set to 0
+ * 0 0 = Do not interrupt on output buffer full
+ * 1 = Output buffer full causes interrupt on IRQ 1
+ */
+ out8(I8042_DATA_REG, 0x45);
+
+ if (i8042_ready() == 0)
+ return -1;
+
+ out8(I8042_COMMAND_REG, I8042_CMD_ENABLE_KBD);
+
+ if (i8042_ready() == 0)
+ return -1;
- if (kbd_input_empty() == 0)
- return -1;
-
- out8 (I8042_DATA_REG, 0x45);
-
-
- if (kbd_input_empty() == 0)
- return -1;
-
- out8 (I8042_COMMAND_REG, 0xae);
-
- if (kbd_input_empty() == 0)
- return -1;
-
- return 0;
+ return 0;
}
diff --git a/include/i8042.h b/include/i8042.h
index 13952899bae..6f8e05af2c1 100644
--- a/include/i8042.h
+++ b/include/i8042.h
@@ -39,6 +39,35 @@
#define I8042_STATUS_REG (CONFIG_SYS_ISA_IO + 0x0064) /* keyboard status read */
#define I8042_COMMAND_REG (CONFIG_SYS_ISA_IO + 0x0064) /* keyboard ctrl write */
+/* Status register bits */
+#define I8042_STR_PARITY 0x80
+#define I8042_STR_TIMEOUT 0x40
+#define I8042_STR_AUXDATA 0x20
+#define I8042_STR_KEYLOCK 0x10
+#define I8042_STR_CMDDAT 0x08
+#define I8042_STR_MUXERR 0x04
+#define I8042_STR_IBF 0x02
+#define I8042_STR_OBF 0x01
+
+/* Command port commands (to i8042 controller) */
+#define I8042_CMD_SET_CMD_BYTE 0x60
+#define I8042_CMD_ENABLE_KBD 0xae
+
+/* Data port commands (to PS/2 device) */
+#define I8042_DATA_LED_WRITE 0xed
+#define I8042_DATA_KBD_RESET 0xff
+
+/* LED bits */
+#define I8042_LED_SCROLL_LOCK 0x01
+#define I8042_LED_NUM_LOCK 0x02
+#define I8042_LED_CAPS_LOCK 0x04
+#define I8042_LED_MASK (I8042_LED_SCROLL_LOCK | \
+ I8042_LED_NUM_LOCK | \
+ I8042_LED_CAPS_LOCK)
+
+
+
+
#define KBD_US 0 /* default US layout */
#define KBD_GER 1 /* german layout */