From 87fae34a1ff2b165ad532b251e328494797cfc8e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 10 May 2010 14:54:51 +0200 Subject: [PATCH 01/64] Skeleton for keyboard layouts --- commands/cat.c | 2 +- commands/keylayouts.c | 186 ++++++++++++++++++++++++++++++++++++++ commands/keystatus.c | 15 ++- commands/sleep.c | 3 +- conf/common.rmk | 5 + include/grub/term.h | 44 +++++---- kern/i386/pc/startup.S | 49 ---------- kern/rescue_reader.c | 2 +- kern/term.c | 36 +------- lib/crypto.c | 2 +- normal/auth.c | 2 +- normal/cmdline.c | 33 ++++--- normal/main.c | 2 +- normal/menu.c | 23 +++-- normal/menu_entry.c | 48 ++++++---- term/at_keyboard.c | 25 +++-- term/i386/pc/console.c | 1 + term/usb_keyboard.c | 6 +- util/grub-fstest.c | 7 +- util/grub-probe.c | 7 +- util/i386/pc/grub-setup.c | 7 +- 21 files changed, 337 insertions(+), 168 deletions(-) create mode 100644 commands/keylayouts.c diff --git a/commands/cat.c b/commands/cat.c index 3bdafc4c6..556196b4a 100644 --- a/commands/cat.c +++ b/commands/cat.c @@ -63,7 +63,7 @@ grub_cmd_cat (grub_command_t cmd __attribute__ ((unused)), } while (grub_checkkey () >= 0 && - (key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != GRUB_TERM_ESC) + (key = grub_getkey ()) != GRUB_TERM_ESC) ; } diff --git a/commands/keylayouts.c b/commands/keylayouts.c new file mode 100644 index 000000000..35bbb8376 --- /dev/null +++ b/commands/keylayouts.c @@ -0,0 +1,186 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +static int keyboard_map[128] = +{ + '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', '\n', '\0', 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', '\0', '*', + '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_KEY_HOME, + GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, '\0', GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, + GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, '\0', GRUB_TERM_KEY_DC +}; + +/* Define scan codes. */ +#define GRUB_TERM_AT_KEY_LEFT 0x4B00 +#define GRUB_TERM_AT_KEY_RIGHT 0x4D00 +#define GRUB_TERM_AT_KEY_UP 0x4800 +#define GRUB_TERM_AT_KEY_DOWN 0x5000 +#define GRUB_TERM_AT_KEY_IC 0x5200 +#define GRUB_TERM_AT_KEY_DC 0x5300 +#define GRUB_TERM_AT_KEY_BACKSPACE 0x0008 +#define GRUB_TERM_AT_KEY_HOME 0x4700 +#define GRUB_TERM_AT_KEY_END 0x4F00 +#define GRUB_TERM_AT_KEY_NPAGE 0x5100 +#define GRUB_TERM_AT_KEY_PPAGE 0x4900 + +static int +get_abstract_code (grub_term_input_t term, int in) +{ + unsigned flags = 0; + switch (term->flags & GRUB_TERM_INPUT_FLAGS_TYPE_MASK) + { + default: + return in; + case GRUB_TERM_INPUT_FLAGS_TYPE_BIOS: + { + unsigned status = 0; + if (term->getkeystatus) + status = term->getkeystatus (); + if (status & GRUB_TERM_CAPS) + flags |= GRUB_TERM_CAPS; + } + /* Fall through. */ + case GRUB_TERM_INPUT_FLAGS_TYPE_AT: + { + struct { + int from, to; + } translations[] = + { + {GRUB_TERM_AT_KEY_LEFT, GRUB_TERM_KEY_LEFT}, + {GRUB_TERM_AT_KEY_RIGHT, GRUB_TERM_KEY_RIGHT}, + {GRUB_TERM_AT_KEY_UP, GRUB_TERM_KEY_UP}, + {GRUB_TERM_AT_KEY_DOWN, GRUB_TERM_KEY_DOWN}, + {GRUB_TERM_AT_KEY_HOME, GRUB_TERM_KEY_HOME}, + {GRUB_TERM_AT_KEY_END, GRUB_TERM_KEY_END}, + {GRUB_TERM_AT_KEY_DC, GRUB_TERM_KEY_DC}, + {GRUB_TERM_AT_KEY_PPAGE, GRUB_TERM_KEY_PPAGE}, + {GRUB_TERM_AT_KEY_NPAGE, GRUB_TERM_KEY_NPAGE} + }; + unsigned i; + for (i = 0; i < ARRAY_SIZE (translations); i++) + if (translations[i].from == (in & 0xffff)) + return translations[i].to | flags; + if ((term->flags & GRUB_TERM_INPUT_FLAGS_TYPE_MASK) + == GRUB_TERM_INPUT_FLAGS_TYPE_AT) + return in & ~0xff00; + /* Detect CTRL'ed keys. */ + if ((in & 0xff) > 0 && (in & 0xff) < 0x20 + && ((in & 0xffff) != (0x0100 | '\e')) + && ((in & 0xffff) != (0x0f00 | '\t')) + && ((in & 0xffff) != (0x0e00 | '\b')) + && ((in & 0xffff) != (0x1c00 | '\r')) + && ((in & 0xffff) != (0x1c00 | '\n'))) + return ((in & 0xff) - 1 + 'a') | flags | GRUB_TERM_CTRL; + /* Detect ALT'ed keys. */ + /* XXX no way to distinguish left and right ALT. */ + if (((in & 0xff) == 0) && keyboard_map[(in & 0xff00) >> 8] >= 'a' + && keyboard_map[(in & 0xff00) >> 8] <= 'z') + return keyboard_map[(in & 0xff00) >> 8] | flags | GRUB_TERM_ALT_GR; + + return (in & 0xff) | flags; + } + } +} + +static int +map (grub_term_input_t term __attribute__ ((unused)), int in) +{ + return in; +} + +static int +translate (grub_term_input_t term, int in) +{ + int code, code2; + code = get_abstract_code (term, in); + if ((code & GRUB_TERM_CAPS) && (code & 0xff) >= 'a' && (code & 0xff) <= 'z') + code = (code & 0xff) + 'A' - 'a'; + else if ((code & GRUB_TERM_CAPS) && (code & 0xff) >= 'A' + && (code & 0xff) <= 'Z') + code = (code & 0xff) + 'a' - 'A'; + + code2 = map (term, code & 0xff); + if ((code & GRUB_TERM_CAPS) && (code2 & 0xff) >= 'a' && (code2 & 0xff) <= 'z') + code2 = code2 + 'A' - 'a'; + else if ((code & GRUB_TERM_CAPS) && (code2 & 0xff) >= 'A' + && (code2 & 0xff) <= 'Z') + code2 = code2 + 'a' - 'A'; + return code2 | (code & ~0xffffff); +} + +static int +grub_getkey_smart (void) +{ + grub_term_input_t term; + + grub_refresh (); + + while (1) + { + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->checkkey (); + if (key != -1) + return translate (term, term->getkey ()); + } + + grub_cpu_idle (); + } +} + +int +grub_checkkey (void) +{ + grub_term_input_t term; + + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->checkkey (); + if (key != -1) + return translate (term, key); + } + + return -1; +} + +static int (*grub_getkey_saved) (void); + +GRUB_MOD_INIT(keylayouts) +{ + grub_getkey_saved = grub_getkey; + grub_getkey = grub_getkey_smart; +} + +GRUB_MOD_FINI(keylayouts) +{ + grub_getkey = grub_getkey_saved; +} diff --git a/commands/keystatus.c b/commands/keystatus.c index 838792889..fc4d11d73 100644 --- a/commands/keystatus.c +++ b/commands/keystatus.c @@ -31,7 +31,20 @@ static const struct grub_arg_option options[] = {0, 0, 0, 0, 0, 0} }; -#define grub_cur_term_input grub_term_get_current_input () +static int +grub_getkeystatus (void) +{ + int status = 0; + grub_term_input_t term; + + FOR_ACTIVE_TERM_INPUTS(term) + { + if (term->getkeystatus) + status |= term->getkeystatus (); + } + + return status; +} static grub_err_t grub_cmd_keystatus (grub_extcmd_t cmd, diff --git a/commands/sleep.c b/commands/sleep.c index ead279506..bce1aee1d 100644 --- a/commands/sleep.c +++ b/commands/sleep.c @@ -52,8 +52,7 @@ grub_interruptible_millisleep (grub_uint32_t ms) start = grub_get_time_ms (); while (grub_get_time_ms () - start < ms) - if (grub_checkkey () >= 0 && - GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC) + if (grub_checkkey () >= 0 && grub_getkey () == GRUB_TERM_ESC) return 1; return 0; diff --git a/conf/common.rmk b/conf/common.rmk index 4b39e9b71..13e1c7a6c 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -491,6 +491,11 @@ extcmd_mod_SOURCES = commands/extcmd.c lib/arg.c extcmd_mod_CFLAGS = $(COMMON_CFLAGS) extcmd_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += keylayouts.mod +keylayouts_mod_SOURCES = commands/keylayouts.c +keylayouts_mod_CFLAGS = $(COMMON_CFLAGS) +keylayouts_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For hello.mod. hello_mod_SOURCES = hello/hello.c hello_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/include/grub/term.h b/include/grub/term.h index 143aabe1e..a2fa80c1f 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -20,18 +20,27 @@ #define GRUB_TERM_HEADER 1 /* Internal codes used by GRUB to represent terminal input. */ -#define GRUB_TERM_LEFT 2 -#define GRUB_TERM_RIGHT 6 -#define GRUB_TERM_UP 16 -#define GRUB_TERM_DOWN 14 -#define GRUB_TERM_HOME 1 -#define GRUB_TERM_END 5 -#define GRUB_TERM_DC 4 -#define GRUB_TERM_PPAGE 7 -#define GRUB_TERM_NPAGE 3 +#define GRUB_TERM_CTRL 0x02000000 +#define GRUB_TERM_ALT 0x04000000 +/* Used by keylayouts code. Never returned in grub_getkey. */ +#define GRUB_TERM_ALT_GR 0x08000000 +#define GRUB_TERM_CAPS 0x10000000 + +/* Keys without associated character. */ +#define GRUB_TERM_EXTENDED 0x1000000 +#define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 1) +#define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 2) +#define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 3) +#define GRUB_TERM_KEY_DOWN (GRUB_TERM_EXTENDED | 4) +#define GRUB_TERM_KEY_HOME (GRUB_TERM_EXTENDED | 5) +#define GRUB_TERM_KEY_END (GRUB_TERM_EXTENDED | 6) +#define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 7) +#define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 8) +#define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 9) + #define GRUB_TERM_ESC '\e' #define GRUB_TERM_TAB '\t' -#define GRUB_TERM_BACKSPACE 8 +#define GRUB_TERM_BACKSPACE '\b' #ifndef ASM_FILE @@ -135,9 +144,15 @@ struct grub_term_input /* Get keyboard modifier status. */ int (*getkeystatus) (void); + + grub_uint32_t flags; }; typedef struct grub_term_input *grub_term_input_t; +#define GRUB_TERM_INPUT_FLAGS_TYPE_MASK 0xf +#define GRUB_TERM_INPUT_FLAGS_TYPE_AT 0x1 +#define GRUB_TERM_INPUT_FLAGS_TYPE_BIOS 0x2 + struct grub_term_output { /* The next terminal. */ @@ -253,9 +268,8 @@ grub_term_unregister_output (grub_term_output_t term) void EXPORT_FUNC(grub_putchar) (int c); void EXPORT_FUNC(grub_putcode) (grub_uint32_t code, struct grub_term_output *term); -int EXPORT_FUNC(grub_getkey) (void); -int EXPORT_FUNC(grub_checkkey) (void); -int EXPORT_FUNC(grub_getkeystatus) (void); +extern int (*EXPORT_VAR(grub_getkey)) (void); +int grub_checkkey (void); void EXPORT_FUNC(grub_cls) (void); void EXPORT_FUNC(grub_setcolorstate) (grub_term_color_state state); void EXPORT_FUNC(grub_refresh) (void); @@ -409,10 +423,6 @@ grub_print_spaces (struct grub_term_output *term, int number_spaces) grub_putcode (' ', term); } - -/* For convenience. */ -#define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff) - #endif /* ! ASM_FILE */ #endif /* ! GRUB_TERM_HEADER */ diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 374277767..6aa3297ab 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1154,54 +1154,6 @@ FUNCTION(grub_console_real_putchar) * %al = ASCII character */ -/* this table is used in translate_keycode below */ -LOCAL (translation_table): - .word GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT - .word GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT - .word GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP - .word GRUB_CONSOLE_KEY_DOWN, GRUB_TERM_DOWN - .word GRUB_CONSOLE_KEY_HOME, GRUB_TERM_HOME - .word GRUB_CONSOLE_KEY_END, GRUB_TERM_END - .word GRUB_CONSOLE_KEY_DC, GRUB_TERM_DC - .word GRUB_CONSOLE_KEY_BACKSPACE, GRUB_TERM_BACKSPACE - .word GRUB_CONSOLE_KEY_PPAGE, GRUB_TERM_PPAGE - .word GRUB_CONSOLE_KEY_NPAGE, GRUB_TERM_NPAGE - .word 0 - -/* - * translate_keycode translates the key code %dx to an ascii code. - */ - .code16 - -translate_keycode: - pushw %bx - pushw %si - -#ifdef __APPLE__ - movw $(ABS(LOCAL (translation_table)) - 0x10000), %si -#else - movw $ABS(LOCAL (translation_table)), %si -#endif - -1: lodsw - /* check if this is the end */ - testw %ax, %ax - jz 2f - /* load the ascii code into %ax */ - movw %ax, %bx - lodsw - /* check if this matches the key code */ - cmpw %bx, %dx - jne 1b - /* translate %dx, if successful */ - movw %ax, %dx - -2: popw %si - popw %bx - ret - - .code32 - FUNCTION(grub_console_getkey) pushl %ebp @@ -1228,7 +1180,6 @@ FUNCTION(grub_console_getkey) int $0x16 movw %ax, %dx /* real_to_prot uses %eax */ - call translate_keycode DATA32 call real_to_prot .code32 diff --git a/kern/rescue_reader.c b/kern/rescue_reader.c index f573cf41f..7cecac6ec 100644 --- a/kern/rescue_reader.c +++ b/kern/rescue_reader.c @@ -38,7 +38,7 @@ grub_rescue_read_line (char **line, int cont) grub_printf ((cont) ? "> " : "grub rescue> "); grub_memset (linebuf, 0, GRUB_RESCUE_BUF_SIZE); - while ((c = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && c != '\r') + while ((c = grub_getkey ()) != '\n' && c != '\r') { if (grub_isprint (c)) { diff --git a/kern/term.c b/kern/term.c index 6e3a2b454..ab3d952fa 100644 --- a/kern/term.c +++ b/kern/term.c @@ -75,8 +75,8 @@ grub_putchar (int c) } } -int -grub_getkey (void) +static int +grub_getkey_dumb (void) { grub_term_input_t term; @@ -88,42 +88,14 @@ grub_getkey (void) { int key = term->checkkey (); if (key != -1) - return term->getkey (); + return term->getkey () & 0xff; } grub_cpu_idle (); } } -int -grub_checkkey (void) -{ - grub_term_input_t term; - - FOR_ACTIVE_TERM_INPUTS(term) - { - int key = term->checkkey (); - if (key != -1) - return key; - } - - return -1; -} - -int -grub_getkeystatus (void) -{ - int status = 0; - grub_term_input_t term; - - FOR_ACTIVE_TERM_INPUTS(term) - { - if (term->getkeystatus) - status |= term->getkeystatus (); - } - - return status; -} +int (*grub_getkey) (void) = grub_getkey_dumb; void grub_cls (void) diff --git a/lib/crypto.c b/lib/crypto.c index d11f0994f..405d18911 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -420,7 +420,7 @@ grub_password_get (char buf[], unsigned buf_size) while (1) { - key = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + key = grub_getkey (); if (key == '\n' || key == '\r') break; diff --git a/normal/auth.c b/normal/auth.c index 156b84c37..76dfddb53 100644 --- a/normal/auth.c +++ b/normal/auth.c @@ -162,7 +162,7 @@ grub_username_get (char buf[], unsigned buf_size) while (1) { - key = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + key = grub_getkey (); if (key == '\n' || key == '\r') break; diff --git a/normal/cmdline.c b/normal/cmdline.c index 05d665411..618e25e08 100644 --- a/normal/cmdline.c +++ b/normal/cmdline.c @@ -387,16 +387,18 @@ grub_cmdline_get (const char *prompt) grub_refresh (); - while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r') + while ((key = grub_getkey ()) != '\n' && key != '\r') { switch (key) { - case 1: /* Ctrl-a */ + case GRUB_TERM_CTRL | 'a': + case GRUB_TERM_KEY_HOME: lpos = 0; cl_set_pos_all (); break; - case 2: /* Ctrl-b */ + case GRUB_TERM_CTRL | 'b': + case GRUB_TERM_KEY_LEFT: if (lpos > 0) { lpos--; @@ -404,12 +406,14 @@ grub_cmdline_get (const char *prompt) } break; - case 5: /* Ctrl-e */ + case GRUB_TERM_CTRL | 'e': + case GRUB_TERM_KEY_END: lpos = llen; cl_set_pos_all (); break; - case 6: /* Ctrl-f */ + case GRUB_TERM_CTRL | 'f': + case GRUB_TERM_KEY_RIGHT: if (lpos < llen) { lpos++; @@ -417,7 +421,8 @@ grub_cmdline_get (const char *prompt) } break; - case 9: /* Ctrl-i or TAB */ + case GRUB_TERM_CTRL | 'i': + case '\t': { int restore; char *insertu8; @@ -489,7 +494,7 @@ grub_cmdline_get (const char *prompt) } break; - case 11: /* Ctrl-k */ + case GRUB_TERM_CTRL | 'k': if (lpos < llen) { if (kill_buf) @@ -513,7 +518,8 @@ grub_cmdline_get (const char *prompt) } break; - case 14: /* Ctrl-n */ + case GRUB_TERM_CTRL | 'n': + case GRUB_TERM_KEY_DOWN: { grub_uint32_t *hist; @@ -531,7 +537,9 @@ grub_cmdline_get (const char *prompt) break; } - case 16: /* Ctrl-p */ + + case GRUB_TERM_KEY_UP: + case GRUB_TERM_CTRL | 'p': { grub_uint32_t *hist; @@ -550,7 +558,7 @@ grub_cmdline_get (const char *prompt) } break; - case 21: /* Ctrl-u */ + case GRUB_TERM_CTRL | 'u': if (lpos > 0) { grub_size_t n = lpos; @@ -576,7 +584,7 @@ grub_cmdline_get (const char *prompt) } break; - case 25: /* Ctrl-y */ + case GRUB_TERM_CTRL | 'y': if (kill_buf) cl_insert (kill_buf); break; @@ -594,7 +602,8 @@ grub_cmdline_get (const char *prompt) break; /* fall through */ - case 4: /* Ctrl-d */ + case GRUB_TERM_CTRL | 'd': + case GRUB_TERM_KEY_DC: if (lpos < llen) cl_delete (1); break; diff --git a/normal/main.c b/normal/main.c index 4ed17e82c..ff4be3a79 100644 --- a/normal/main.c +++ b/normal/main.c @@ -163,7 +163,7 @@ static struct { {"backspace", '\b'}, {"tab", '\t'}, - {"delete", GRUB_TERM_DC} + {"delete", GRUB_TERM_KEY_DC} }; /* Add a menu entry to the current menu context (as given by the environment diff --git a/normal/menu.c b/normal/menu.c index 09c5fd1eb..b740ea3ca 100644 --- a/normal/menu.c +++ b/normal/menu.c @@ -397,7 +397,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) if (grub_checkkey () >= 0 || timeout < 0) { - c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + c = grub_getkey (); if (timeout >= 0) { @@ -408,31 +408,36 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) switch (c) { - case GRUB_TERM_HOME: + case GRUB_TERM_KEY_HOME: + case GRUB_TERM_CTRL | 'a': current_entry = 0; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_END: + case GRUB_TERM_KEY_END: + case GRUB_TERM_CTRL | 'e': current_entry = menu->size - 1; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_UP: + case GRUB_TERM_KEY_UP: + case GRUB_TERM_CTRL | 'p': case '^': if (current_entry > 0) current_entry--; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_DOWN: + case GRUB_TERM_CTRL | 'n': + case GRUB_TERM_KEY_DOWN: case 'v': if (current_entry < menu->size - 1) current_entry++; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_PPAGE: + case GRUB_TERM_CTRL | 'g': + case GRUB_TERM_KEY_PPAGE: if (current_entry < GRUB_MENU_PAGE_SIZE) current_entry = 0; else @@ -440,7 +445,8 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_NPAGE: + case GRUB_TERM_CTRL | 'c': + case GRUB_TERM_KEY_NPAGE: if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size) current_entry += GRUB_MENU_PAGE_SIZE; else @@ -450,7 +456,8 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) case '\n': case '\r': - case 6: + case GRUB_TERM_KEY_RIGHT: + case GRUB_TERM_CTRL | 'f': menu_fini (); *auto_boot = 0; return current_entry; diff --git a/normal/menu_entry.c b/normal/menu_entry.c index 644fe90fd..0b03147dd 100644 --- a/normal/menu_entry.c +++ b/normal/menu_entry.c @@ -1262,7 +1262,7 @@ grub_menu_entry_run (grub_menu_entry_t entry) while (1) { - int c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + int c = grub_getkey (); if (screen->completion_shown) { @@ -1278,70 +1278,78 @@ grub_menu_entry_run (grub_menu_entry_t entry) switch (c) { - case 16: /* C-p */ + case GRUB_TERM_KEY_UP: + case GRUB_TERM_CTRL | 'p': if (! previous_line (screen, 1)) goto fail; break; - case 14: /* C-n */ + case GRUB_TERM_CTRL | 'n': + case GRUB_TERM_KEY_DOWN: if (! next_line (screen, 1)) goto fail; break; - case 6: /* C-f */ + case GRUB_TERM_CTRL | 'f': + case GRUB_TERM_KEY_RIGHT: if (! forward_char (screen, 1)) goto fail; break; - case 2: /* C-b */ + case GRUB_TERM_CTRL | 'b': + case GRUB_TERM_KEY_LEFT: if (! backward_char (screen, 1)) goto fail; break; - case 1: /* C-a */ + case GRUB_TERM_CTRL | 'a': + case GRUB_TERM_KEY_HOME: if (! beginning_of_line (screen, 1)) goto fail; break; - case 5: /* C-e */ + case GRUB_TERM_CTRL | 'e': + case GRUB_TERM_KEY_END: if (! end_of_line (screen, 1)) goto fail; break; - case '\t': /* C-i */ + case GRUB_TERM_CTRL | 'i': + case '\t': if (! complete (screen, prev_c == c, 1)) goto fail; break; - case 4: /* C-d */ + case GRUB_TERM_CTRL | 'd': + case GRUB_TERM_KEY_DC: if (! delete_char (screen, 1)) goto fail; break; - case 8: /* C-h */ + case GRUB_TERM_CTRL | 'h': if (! backward_delete_char (screen, 1)) goto fail; break; - case 11: /* C-k */ + case GRUB_TERM_CTRL | 'k': if (! kill_line (screen, prev_c == c, 1)) goto fail; break; - case 21: /* C-u */ + case GRUB_TERM_CTRL | 'u': /* FIXME: What behavior is good for this key? */ break; - case 25: /* C-y */ + case GRUB_TERM_CTRL | 'y': if (! yank (screen, 1)) goto fail; break; - case 12: /* C-l */ + case GRUB_TERM_CTRL | 'l': /* FIXME: centering. */ goto refresh; - case 15: /* C-o */ + case GRUB_TERM_CTRL | 'o': if (! open_line (screen, 1)) goto fail; break; @@ -1356,18 +1364,18 @@ grub_menu_entry_run (grub_menu_entry_t entry) destroy_screen (screen); return; - case 3: /* C-c */ + case GRUB_TERM_CTRL | 'c': grub_cmdline_run (1); goto refresh; - case 24: /* C-x */ + case GRUB_TERM_CTRL | 'x': if (! run (screen)) goto fail; goto refresh; - case 18: /* C-r */ - case 19: /* C-s */ - case 20: /* C-t */ + case GRUB_TERM_CTRL | 'r': + case GRUB_TERM_CTRL | 's': + case GRUB_TERM_CTRL | 't': /* FIXME */ break; diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 1f84ae71a..f1932f64e 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -41,7 +41,7 @@ static grub_uint8_t led_status; #define KEYBOARD_LED_NUM (1 << 1) #define KEYBOARD_LED_CAPS (1 << 2) -static char keyboard_map[128] = +static int keyboard_map[128] = { '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, @@ -51,9 +51,9 @@ static char keyboard_map[128] = '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '*', '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_HOME, - GRUB_TERM_UP, GRUB_TERM_NPAGE, '-', GRUB_TERM_LEFT, '\0', GRUB_TERM_RIGHT, '+', GRUB_TERM_END, - GRUB_TERM_DOWN, GRUB_TERM_PPAGE, '\0', GRUB_TERM_DC, '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_KEY_HOME, + GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, '\0', GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, + GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, '\0', GRUB_TERM_KEY_DC, '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, OLPC_RIGHT @@ -213,9 +213,8 @@ grub_at_keyboard_getkey_noblock (void) key = -1; break; default: - if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R)) - key = keyboard_map[code] - 'a' + 1; - else if ((at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L | KEYBOARD_STATUS_SHIFT_R)) + if ((at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L + | KEYBOARD_STATUS_SHIFT_R)) && keyboard_map_shift[code]) key = keyboard_map_shift[code]; else @@ -231,6 +230,17 @@ grub_at_keyboard_getkey_noblock (void) else if ((key >= 'A') && (key <= 'Z')) key += 'a' - 'A'; } + + if (at_keyboard_status & KEYBOARD_STATUS_ALT_L) + key |= GRUB_TERM_ALT; + if (at_keyboard_status & KEYBOARD_STATUS_ALT_R) + key |= GRUB_TERM_ALT_GR; + if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L + | KEYBOARD_STATUS_CTRL_R)) + key |= GRUB_TERM_CTRL; + + if (at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK) + key |= GRUB_TERM_CAPS; } return key; } @@ -290,6 +300,7 @@ static struct grub_term_input grub_at_keyboard_term = .fini = grub_keyboard_controller_fini, .checkkey = grub_at_keyboard_checkkey, .getkey = grub_at_keyboard_getkey, + .flags = GRUB_TERM_INPUT_FLAGS_TYPE_AT }; GRUB_MOD_INIT(at_keyboard) diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index 43cfe2f2a..09baabd8f 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -51,6 +51,7 @@ static struct grub_term_input grub_console_term_input = .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, .getkeystatus = grub_console_getkeystatus, + .flags = GRUB_TERM_INPUT_FLAGS_TYPE_BIOS }; static struct grub_term_output grub_console_term_output = diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 5d76c5e02..8f9a79ec4 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -28,7 +28,7 @@ #include -static char keyboard_map[128] = +static int keyboard_map[128] = { '\0', '\0', '\0', '\0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', @@ -39,8 +39,8 @@ static char keyboard_map[128] = ']', '\\', '#', ';', '\'', '`', ',', '.', '/', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', GRUB_TERM_HOME, GRUB_TERM_PPAGE, GRUB_TERM_DC, GRUB_TERM_END, GRUB_TERM_NPAGE, GRUB_TERM_RIGHT, - GRUB_TERM_LEFT, GRUB_TERM_DOWN, GRUB_TERM_UP + '\0', '\0', GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, + GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_UP }; static char keyboard_map_shift[128] = diff --git a/util/grub-fstest.c b/util/grub-fstest.c index c03c43451..14ddf2ad8 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -49,14 +49,13 @@ grub_putchar (int c) putchar (c); } -int -grub_getkey (void) +static int +grub_getkey_real (void) { return -1; } -struct grub_handler_class grub_term_input_class; -struct grub_handler_class grub_term_output_class; +int (*grub_getkey) (void) = grub_getkey_real; void grub_refresh (void) diff --git a/util/grub-probe.c b/util/grub-probe.c index bb41480e2..cb082da6d 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -64,14 +64,13 @@ grub_putchar (int c) putchar (c); } -int -grub_getkey (void) +static int +grub_getkey_real (void) { return -1; } -struct grub_handler_class grub_term_input_class; -struct grub_handler_class grub_term_output_class; +int (*grub_getkey) (void) = grub_getkey_real; void grub_refresh (void) diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 63fa8c328..ffdb356a6 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -63,14 +63,13 @@ grub_putchar (int c) putchar (c); } -int -grub_getkey (void) +static int +grub_getkey_real (void) { return -1; } -struct grub_handler_class grub_term_input_class; -struct grub_handler_class grub_term_output_class; +int (*grub_getkey) (void) = grub_getkey_real; void grub_refresh (void) From 08bfb543c40ade8ed8d19dc9eb2d797172482282 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 10 May 2010 15:04:46 +0200 Subject: [PATCH 02/64] Add key_102 --- commands/keylayouts.c | 13 ++++++++++--- include/grub/term.h | 3 +++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 35bbb8376..24da21364 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -83,7 +83,9 @@ get_abstract_code (grub_term_input_t term, int in) {GRUB_TERM_AT_KEY_END, GRUB_TERM_KEY_END}, {GRUB_TERM_AT_KEY_DC, GRUB_TERM_KEY_DC}, {GRUB_TERM_AT_KEY_PPAGE, GRUB_TERM_KEY_PPAGE}, - {GRUB_TERM_AT_KEY_NPAGE, GRUB_TERM_KEY_NPAGE} + {GRUB_TERM_AT_KEY_NPAGE, GRUB_TERM_KEY_NPAGE}, + {0x5600 | '\\', GRUB_TERM_KEY_102}, + {0x5600 | '|', GRUB_TERM_KEY_SHIFT_102}, }; unsigned i; for (i = 0; i < ARRAY_SIZE (translations); i++) @@ -114,6 +116,11 @@ get_abstract_code (grub_term_input_t term, int in) static int map (grub_term_input_t term __attribute__ ((unused)), int in) { + if (in == GRUB_TERM_KEY_102) + return '\\'; + if (in == GRUB_TERM_KEY_SHIFT_102) + return '|'; + return in; } @@ -128,13 +135,13 @@ translate (grub_term_input_t term, int in) && (code & 0xff) <= 'Z') code = (code & 0xff) + 'a' - 'A'; - code2 = map (term, code & 0xff); + code2 = map (term, code & 0x1ffffff); if ((code & GRUB_TERM_CAPS) && (code2 & 0xff) >= 'a' && (code2 & 0xff) <= 'z') code2 = code2 + 'A' - 'a'; else if ((code & GRUB_TERM_CAPS) && (code2 & 0xff) >= 'A' && (code2 & 0xff) <= 'Z') code2 = code2 + 'a' - 'A'; - return code2 | (code & ~0xffffff); + return code2 | (code & ~0x1ffffff); } static int diff --git a/include/grub/term.h b/include/grub/term.h index a2fa80c1f..b3db120df 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -37,6 +37,9 @@ #define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 7) #define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 8) #define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 9) +/* Used by keylayouts code. Never returned in grub_getkey. */ +#define GRUB_TERM_KEY_102 (GRUB_TERM_EXTENDED | 10) +#define GRUB_TERM_KEY_SHIFT_102 (GRUB_TERM_EXTENDED | 11) #define GRUB_TERM_ESC '\e' #define GRUB_TERM_TAB '\t' From 1ff38af9b95e76e9e63f85fa1981b0c89c132ed9 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 10 May 2010 20:57:01 +0200 Subject: [PATCH 03/64] Simplify AT keyboards and support 102nd key --- commands/keylayouts.c | 19 ++++++++----------- include/grub/term.h | 6 +++--- term/at_keyboard.c | 10 ++++++---- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 24da21364..9b1d92c73 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -58,19 +58,12 @@ get_abstract_code (grub_term_input_t term, int in) unsigned flags = 0; switch (term->flags & GRUB_TERM_INPUT_FLAGS_TYPE_MASK) { + case GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES: default: return in; case GRUB_TERM_INPUT_FLAGS_TYPE_BIOS: { unsigned status = 0; - if (term->getkeystatus) - status = term->getkeystatus (); - if (status & GRUB_TERM_CAPS) - flags |= GRUB_TERM_CAPS; - } - /* Fall through. */ - case GRUB_TERM_INPUT_FLAGS_TYPE_AT: - { struct { int from, to; } translations[] = @@ -88,12 +81,16 @@ get_abstract_code (grub_term_input_t term, int in) {0x5600 | '|', GRUB_TERM_KEY_SHIFT_102}, }; unsigned i; + + if (term->getkeystatus) + status = term->getkeystatus (); + if (status & GRUB_TERM_CAPS) + flags |= GRUB_TERM_CAPS; + for (i = 0; i < ARRAY_SIZE (translations); i++) if (translations[i].from == (in & 0xffff)) return translations[i].to | flags; - if ((term->flags & GRUB_TERM_INPUT_FLAGS_TYPE_MASK) - == GRUB_TERM_INPUT_FLAGS_TYPE_AT) - return in & ~0xff00; + /* Detect CTRL'ed keys. */ if ((in & 0xff) > 0 && (in & 0xff) < 0x20 && ((in & 0xffff) != (0x0100 | '\e')) diff --git a/include/grub/term.h b/include/grub/term.h index b3db120df..064093bc5 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -152,9 +152,9 @@ struct grub_term_input }; typedef struct grub_term_input *grub_term_input_t; -#define GRUB_TERM_INPUT_FLAGS_TYPE_MASK 0xf -#define GRUB_TERM_INPUT_FLAGS_TYPE_AT 0x1 -#define GRUB_TERM_INPUT_FLAGS_TYPE_BIOS 0x2 +#define GRUB_TERM_INPUT_FLAGS_TYPE_MASK 0xf +#define GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES 0x0 +#define GRUB_TERM_INPUT_FLAGS_TYPE_BIOS 0x1 struct grub_term_output { diff --git a/term/at_keyboard.c b/term/at_keyboard.c index f1932f64e..bf94200cc 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -53,13 +53,14 @@ static int keyboard_map[128] = '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, '\0', GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, - GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, '\0', GRUB_TERM_KEY_DC, '\0', '\0', '\0', '\0', + GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, '\0', GRUB_TERM_KEY_DC, '\0', '\0', + GRUB_TERM_KEY_102, '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, OLPC_RIGHT }; -static char keyboard_map_shift[128] = +static int keyboard_map_shift[128] = { '\0', '\0', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\0', '\0', @@ -67,7 +68,8 @@ static char keyboard_map_shift[128] = 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?' + 'B', 'N', 'M', '<', '>', '?', + [0x56] = GRUB_TERM_KEY_SHIFT_102 }; static grub_uint8_t grub_keyboard_controller_orig; @@ -300,7 +302,7 @@ static struct grub_term_input grub_at_keyboard_term = .fini = grub_keyboard_controller_fini, .checkkey = grub_at_keyboard_checkkey, .getkey = grub_at_keyboard_getkey, - .flags = GRUB_TERM_INPUT_FLAGS_TYPE_AT + .flags = GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES }; GRUB_MOD_INIT(at_keyboard) From 176194068fd30237e1262271cb8d9cbfcd380fb0 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 10 May 2010 21:23:40 +0200 Subject: [PATCH 04/64] cleaner AltGr handling --- commands/keylayouts.c | 31 ++++++++++++++++++++++--------- include/grub/term.h | 1 + 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 9b1d92c73..370d55c4f 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -111,8 +111,13 @@ get_abstract_code (grub_term_input_t term, int in) } static int -map (grub_term_input_t term __attribute__ ((unused)), int in) +map (grub_term_input_t term, int in) { + /* No match with AltGr. Interpret it as Alt rather than as L3 modifier then. + */ + if (in & GRUB_TERM_ALT_GR) + return map (term, in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT_GR; + if (in == GRUB_TERM_KEY_102) return '\\'; if (in == GRUB_TERM_KEY_SHIFT_102) @@ -124,7 +129,7 @@ map (grub_term_input_t term __attribute__ ((unused)), int in) static int translate (grub_term_input_t term, int in) { - int code, code2; + int code, flags; code = get_abstract_code (term, in); if ((code & GRUB_TERM_CAPS) && (code & 0xff) >= 'a' && (code & 0xff) <= 'z') code = (code & 0xff) + 'A' - 'a'; @@ -132,13 +137,21 @@ translate (grub_term_input_t term, int in) && (code & 0xff) <= 'Z') code = (code & 0xff) + 'a' - 'A'; - code2 = map (term, code & 0x1ffffff); - if ((code & GRUB_TERM_CAPS) && (code2 & 0xff) >= 'a' && (code2 & 0xff) <= 'z') - code2 = code2 + 'A' - 'a'; - else if ((code & GRUB_TERM_CAPS) && (code2 & 0xff) >= 'A' - && (code2 & 0xff) <= 'Z') - code2 = code2 + 'a' - 'A'; - return code2 | (code & ~0x1ffffff); + flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR); + code &= (GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR); + code = map (term, code); + /* Transform unconsumed AltGr into Alt. */ + if (code & GRUB_TERM_ALT_GR) + { + flags |= GRUB_TERM_ALT; + code &= ~GRUB_TERM_ALT_GR; + } + if ((flags & GRUB_TERM_CAPS) && code >= 'a' && code <= 'z') + code += 'A' - 'a'; + else if ((flags & GRUB_TERM_CAPS) && code >= 'A' + && code <= 'Z') + code += 'a' - 'A'; + return code | flags; } static int diff --git a/include/grub/term.h b/include/grub/term.h index 064093bc5..626349ac5 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -28,6 +28,7 @@ /* Keys without associated character. */ #define GRUB_TERM_EXTENDED 0x1000000 +#define GRUB_TERM_KEY_MASK 0x1ffffff #define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 1) #define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 2) #define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 3) From 9fbfb64abec41ceebbf4844efdd408ee2a681e9d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 10 May 2010 21:25:46 +0200 Subject: [PATCH 05/64] adjust usb_keyboard for keylayouts --- term/usb_keyboard.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 8f9a79ec4..5a388eb73 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -150,10 +150,16 @@ grub_usb_keyboard_checkkey (void) data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); - /* Check if the Control or Shift key was pressed. */ - if (data[0] & 0x01 || data[0] & 0x10) - key = keyboard_map[data[2]] - 'a' + 1; - else if (data[0] & 0x02 || data[0] & 0x20) +#define GRUB_USB_KEYBOARD_LEFT_CTRL 0x01 +#define GRUB_USB_KEYBOARD_LEFT_SHIFT 0x02 +#define GRUB_USB_KEYBOARD_LEFT_ALT 0x04 +#define GRUB_USB_KEYBOARD_RIGHT_CTRL 0x10 +#define GRUB_USB_KEYBOARD_RIGHT_SHIFT 0x20 +#define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40 + + /* Check if the Shift key was pressed. */ + if (data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT + || data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) key = keyboard_map_shift[data[2]]; else key = keyboard_map[data[2]]; @@ -161,6 +167,18 @@ grub_usb_keyboard_checkkey (void) if (key == 0) grub_printf ("Unknown key 0x%x detected\n", data[2]); + /* Check if the Ctrl key was pressed. */ + if (data[0] & GRUB_USB_KEYBOARD_LEFT_CTRL + || data[0] & GRUB_USB_KEYBOARD_RIGHT_CTRL) + key |= GRUB_TERM_CTRL; + + /* Check if the Alt key was pressed. */ + if (data[0] & GRUB_USB_KEYBOARD_LEFT_ALT) + key |= GRUB_TERM_ALT; + + if (data[0] & GRUB_USB_KEYBOARD_RIGHT_ALT) + key |= GRUB_TERM_ALT_GR; + #if 0 /* Wait until the key is released. */ while (!err && data[2]) @@ -314,6 +332,7 @@ static struct grub_term_input grub_usb_keyboard_term = .checkkey = grub_usb_keyboard_checkkey, .getkey = grub_usb_keyboard_getkey, .getkeystatus = grub_usb_keyboard_getkeystatus, + .flags = GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES, .next = 0 }; From 7a6459e12d3dbc01020f0e6c6dcf12a2afdd3bc1 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 01:07:50 +0200 Subject: [PATCH 06/64] support for Fn keys --- commands/keylayouts.c | 67 ++++++--------------------- commands/keystatus.c | 2 +- include/grub/at_keyboard.h | 24 ++++++++++ include/grub/term.h | 17 ++++++- normal/main.c | 15 +++++- normal/menu_entry.c | 3 ++ normal/menu_text.c | 9 +--- term/at_keyboard.c | 19 +------- term/efi/console.c | 94 +++++++------------------------------- term/terminfo.c | 34 +++++++------- term/usb_keyboard.c | 24 ++++++---- 11 files changed, 123 insertions(+), 185 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 370d55c4f..58baabe67 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -23,39 +23,13 @@ #include #include #include +#include -static int keyboard_map[128] = -{ - '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', '\n', '\0', 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', '\0', '*', - '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_KEY_HOME, - GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, '\0', GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, - GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, '\0', GRUB_TERM_KEY_DC -}; - -/* Define scan codes. */ -#define GRUB_TERM_AT_KEY_LEFT 0x4B00 -#define GRUB_TERM_AT_KEY_RIGHT 0x4D00 -#define GRUB_TERM_AT_KEY_UP 0x4800 -#define GRUB_TERM_AT_KEY_DOWN 0x5000 -#define GRUB_TERM_AT_KEY_IC 0x5200 -#define GRUB_TERM_AT_KEY_DC 0x5300 -#define GRUB_TERM_AT_KEY_BACKSPACE 0x0008 -#define GRUB_TERM_AT_KEY_HOME 0x4700 -#define GRUB_TERM_AT_KEY_END 0x4F00 -#define GRUB_TERM_AT_KEY_NPAGE 0x5100 -#define GRUB_TERM_AT_KEY_PPAGE 0x4900 +GRUB_AT_KEY_KEYBOARD_MAP (keyboard_map); static int get_abstract_code (grub_term_input_t term, int in) { - unsigned flags = 0; switch (term->flags & GRUB_TERM_INPUT_FLAGS_TYPE_MASK) { case GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES: @@ -64,32 +38,18 @@ get_abstract_code (grub_term_input_t term, int in) case GRUB_TERM_INPUT_FLAGS_TYPE_BIOS: { unsigned status = 0; - struct { - int from, to; - } translations[] = - { - {GRUB_TERM_AT_KEY_LEFT, GRUB_TERM_KEY_LEFT}, - {GRUB_TERM_AT_KEY_RIGHT, GRUB_TERM_KEY_RIGHT}, - {GRUB_TERM_AT_KEY_UP, GRUB_TERM_KEY_UP}, - {GRUB_TERM_AT_KEY_DOWN, GRUB_TERM_KEY_DOWN}, - {GRUB_TERM_AT_KEY_HOME, GRUB_TERM_KEY_HOME}, - {GRUB_TERM_AT_KEY_END, GRUB_TERM_KEY_END}, - {GRUB_TERM_AT_KEY_DC, GRUB_TERM_KEY_DC}, - {GRUB_TERM_AT_KEY_PPAGE, GRUB_TERM_KEY_PPAGE}, - {GRUB_TERM_AT_KEY_NPAGE, GRUB_TERM_KEY_NPAGE}, - {0x5600 | '\\', GRUB_TERM_KEY_102}, - {0x5600 | '|', GRUB_TERM_KEY_SHIFT_102}, - }; - unsigned i; + unsigned flags = 0; if (term->getkeystatus) - status = term->getkeystatus (); + status = term->getkeystatus (term); if (status & GRUB_TERM_CAPS) flags |= GRUB_TERM_CAPS; - for (i = 0; i < ARRAY_SIZE (translations); i++) - if (translations[i].from == (in & 0xffff)) - return translations[i].to | flags; + if ((0x5600 | '\\') == (in & 0xffff)) + return GRUB_TERM_KEY_102 | flags; + + if ((0x5600 | '|') == (in & 0xffff)) + return GRUB_TERM_KEY_SHIFT_102 | flags; /* Detect CTRL'ed keys. */ if ((in & 0xff) > 0 && (in & 0xff) < 0x20 @@ -105,6 +65,9 @@ get_abstract_code (grub_term_input_t term, int in) && keyboard_map[(in & 0xff00) >> 8] <= 'z') return keyboard_map[(in & 0xff00) >> 8] | flags | GRUB_TERM_ALT_GR; + if ((in & 0xff) == 0) + return keyboard_map[(in & 0xff00) >> 8] | flags; + return (in & 0xff) | flags; } } @@ -165,9 +128,9 @@ grub_getkey_smart (void) { FOR_ACTIVE_TERM_INPUTS(term) { - int key = term->checkkey (); + int key = term->checkkey (term); if (key != -1) - return translate (term, term->getkey ()); + return translate (term, term->getkey (term)); } grub_cpu_idle (); @@ -181,7 +144,7 @@ grub_checkkey (void) FOR_ACTIVE_TERM_INPUTS(term) { - int key = term->checkkey (); + int key = term->checkkey (term); if (key != -1) return translate (term, key); } diff --git a/commands/keystatus.c b/commands/keystatus.c index fc4d11d73..9db92b942 100644 --- a/commands/keystatus.c +++ b/commands/keystatus.c @@ -40,7 +40,7 @@ grub_getkeystatus (void) FOR_ACTIVE_TERM_INPUTS(term) { if (term->getkeystatus) - status |= term->getkeystatus (); + status |= term->getkeystatus (term); } return status; diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 10421540a..3f72fa879 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -51,4 +51,28 @@ #define OLPC_RIGHT '\0' #endif +#define GRUB_AT_KEY_KEYBOARD_MAP(name) \ +static const int name[128] = \ +{ \ + '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', \ + '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, \ + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', \ + 'o', 'p', '[', ']', '\n', '\0', 'a', 's', \ + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', \ + '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', \ + 'b', 'n', 'm', ',', '.', '/', '\0', '*', \ + '\0', ' ', '\0', GRUB_TERM_KEY_F1, \ + GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, \ + GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, \ + GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, \ + GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, \ + '\0', GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, \ + GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, \ + GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, \ + '\0', '\0', GRUB_TERM_KEY_102, GRUB_TERM_KEY_F11, \ + GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', \ + '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, \ + OLPC_RIGHT \ +} + #endif diff --git a/include/grub/term.h b/include/grub/term.h index 7871c656f..dbafef0e1 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -38,10 +38,23 @@ #define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 7) #define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 8) #define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 9) +#define GRUB_TERM_KEY_F1 (GRUB_TERM_EXTENDED | 10) +#define GRUB_TERM_KEY_F2 (GRUB_TERM_EXTENDED | 11) +#define GRUB_TERM_KEY_F3 (GRUB_TERM_EXTENDED | 12) +#define GRUB_TERM_KEY_F4 (GRUB_TERM_EXTENDED | 13) +#define GRUB_TERM_KEY_F5 (GRUB_TERM_EXTENDED | 14) +#define GRUB_TERM_KEY_F6 (GRUB_TERM_EXTENDED | 15) +#define GRUB_TERM_KEY_F7 (GRUB_TERM_EXTENDED | 16) +#define GRUB_TERM_KEY_F8 (GRUB_TERM_EXTENDED | 17) +#define GRUB_TERM_KEY_F9 (GRUB_TERM_EXTENDED | 18) +#define GRUB_TERM_KEY_F10 (GRUB_TERM_EXTENDED | 19) +#define GRUB_TERM_KEY_F11 (GRUB_TERM_EXTENDED | 20) +#define GRUB_TERM_KEY_F12 (GRUB_TERM_EXTENDED | 21) +#define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 22) /* Used by keylayouts code. Never returned in grub_getkey. */ -#define GRUB_TERM_KEY_102 (GRUB_TERM_EXTENDED | 10) -#define GRUB_TERM_KEY_SHIFT_102 (GRUB_TERM_EXTENDED | 11) +#define GRUB_TERM_KEY_102 (GRUB_TERM_EXTENDED | 23) +#define GRUB_TERM_KEY_SHIFT_102 (GRUB_TERM_EXTENDED | 24) #define GRUB_TERM_ESC '\e' #define GRUB_TERM_TAB '\t' diff --git a/normal/main.c b/normal/main.c index 7582c7f13..6eee57799 100644 --- a/normal/main.c +++ b/normal/main.c @@ -164,7 +164,20 @@ static struct { {"backspace", '\b'}, {"tab", '\t'}, - {"delete", GRUB_TERM_KEY_DC} + {"delete", GRUB_TERM_KEY_DC}, + {"insert", GRUB_TERM_KEY_INSERT}, + {"f1", GRUB_TERM_KEY_F1}, + {"f2", GRUB_TERM_KEY_F2}, + {"f3", GRUB_TERM_KEY_F3}, + {"f4", GRUB_TERM_KEY_F4}, + {"f5", GRUB_TERM_KEY_F5}, + {"f6", GRUB_TERM_KEY_F6}, + {"f7", GRUB_TERM_KEY_F7}, + {"f8", GRUB_TERM_KEY_F8}, + {"f9", GRUB_TERM_KEY_F9}, + {"f10", GRUB_TERM_KEY_F10}, + {"f11", GRUB_TERM_KEY_F11}, + {"f12", GRUB_TERM_KEY_F12}, }; /* Add a menu entry to the current menu context (as given by the environment diff --git a/normal/menu_entry.c b/normal/menu_entry.c index 8e943612a..87292d445 100644 --- a/normal/menu_entry.c +++ b/normal/menu_entry.c @@ -1337,6 +1337,7 @@ grub_menu_entry_run (grub_menu_entry_t entry) break; case GRUB_TERM_CTRL | 'h': + case '\b': if (! backward_delete_char (screen, 1)) goto fail; break; @@ -1375,10 +1376,12 @@ grub_menu_entry_run (grub_menu_entry_t entry) return; case GRUB_TERM_CTRL | 'c': + case GRUB_TERM_KEY_F2: grub_cmdline_run (1); goto refresh; case GRUB_TERM_CTRL | 'x': + case GRUB_TERM_KEY_F10: { int chars_before = grub_normal_get_char_counter (); run (screen); diff --git a/normal/menu_text.c b/normal/menu_text.c index 3e3e7e2fa..fc4a89196 100644 --- a/normal/menu_text.c +++ b/normal/menu_text.c @@ -120,17 +120,10 @@ print_message (int nested, int edit, struct grub_term_output *term) if (edit) { grub_putcode ('\n', term); -#ifdef GRUB_MACHINE_EFI grub_print_message_indented (_("Minimum Emacs-like screen editing is \ -supported. TAB lists completions. Press F1 to boot, F2=Ctrl-a, F3=Ctrl-e, \ -F4 for a command-line or ESC to discard edits and return to the GRUB menu."), - STANDARD_MARGIN, STANDARD_MARGIN, term); -#else - grub_print_message_indented (_("Minimum Emacs-like screen editing is \ -supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \ +supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \ command-line or ESC to discard edits and return to the GRUB menu."), STANDARD_MARGIN, STANDARD_MARGIN, term); -#endif } else { diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 683981be3..e89f3bf5b 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -41,24 +41,7 @@ static grub_uint8_t led_status; #define KEYBOARD_LED_NUM (1 << 1) #define KEYBOARD_LED_CAPS (1 << 2) -static int keyboard_map[128] = -{ - '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', '\n', '\0', 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', '\0', '*', - '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_KEY_HOME, - GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, '\0', GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, - GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, '\0', GRUB_TERM_KEY_DC, '\0', '\0', - GRUB_TERM_KEY_102, '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, - OLPC_RIGHT -}; +GRUB_AT_KEY_KEYBOARD_MAP (keyboard_map); static int keyboard_map_shift[128] = { diff --git a/term/efi/console.c b/term/efi/console.c index dca002910..f47263ee4 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -100,6 +100,17 @@ grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), efi_call_2 (o->output_string, o, str); } +const unsigned efi_codes[] = + { + 0, GRUB_TERM_UP, GRUB_TERM_DOWN, GRUB_TERM_RIGHT, + GRUB_TERM_LEFT, GRUB_TERM_HOME, GRUB_TERM_END, GRUB_TERM_KEY_INSERT, + GRUB_TERM_DC, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_F1, + GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, + GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, + GRUB_TERM_KEY_F10, 0, 0, '\e' + }; + + static int grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) { @@ -112,85 +123,14 @@ grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) i = grub_efi_system_table->con_in; status = efi_call_2 (i->read_key_stroke, i, &key); -#if 0 - switch (status) - { - case GRUB_EFI_SUCCESS: - { - grub_uint16_t xy; - xy = grub_getxy (); - grub_gotoxy (0, 0); - grub_printf ("scan_code=%x,unicode_char=%x ", - (unsigned) key.scan_code, - (unsigned) key.unicode_char); - grub_gotoxy (xy >> 8, xy & 0xff); - } - break; + if (status != GRUB_EFI_SUCCESS) + return -1; - case GRUB_EFI_NOT_READY: - //grub_printf ("not ready "); - break; - - default: - //grub_printf ("device error "); - break; - } -#endif - - if (status == GRUB_EFI_SUCCESS) - { - switch (key.scan_code) - { - case 0x00: - read_key = key.unicode_char; - break; - case 0x01: - read_key = GRUB_TERM_UP; - break; - case 0x02: - read_key = GRUB_TERM_DOWN; - break; - case 0x03: - read_key = GRUB_TERM_RIGHT; - break; - case 0x04: - read_key = GRUB_TERM_LEFT; - break; - case 0x05: - read_key = GRUB_TERM_HOME; - break; - case 0x06: - read_key = GRUB_TERM_END; - break; - case 0x07: - break; - case 0x08: - read_key = GRUB_TERM_DC; - break; - case 0x09: - break; - case 0x0a: - break; - case 0x0b: - read_key = 24; - break; - case 0x0c: - read_key = 1; - break; - case 0x0d: - read_key = 5; - break; - case 0x0e: - read_key = 3; - break; - case 0x17: - read_key = '\e'; - break; - default: - break; - } - } + if (key.scan_code == 0) + read_key = key.unicode_char; + else if (key.scan_code < ARRAY_SIZE (efi_codes)) + read_key = efi_codes[key.scan_code]; return read_key; } diff --git a/term/terminfo.c b/term/terminfo.c index ff54e5dba..9030c2580 100644 --- a/term/terminfo.c +++ b/term/terminfo.c @@ -402,34 +402,34 @@ grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void)) static struct { char key; - char ascii; + unsigned ascii; } three_code_table[] = { - {'4', GRUB_TERM_DC}, - {'A', GRUB_TERM_UP}, - {'B', GRUB_TERM_DOWN}, - {'C', GRUB_TERM_RIGHT}, - {'D', GRUB_TERM_LEFT}, - {'F', GRUB_TERM_END}, - {'H', GRUB_TERM_HOME}, - {'K', GRUB_TERM_END}, - {'P', GRUB_TERM_DC}, - {'?', GRUB_TERM_PPAGE}, - {'/', GRUB_TERM_NPAGE} + {'4', GRUB_TERM_KEY_DC}, + {'A', GRUB_TERM_KEY_UP}, + {'B', GRUB_TERM_KEY_DOWN}, + {'C', GRUB_TERM_KEY_RIGHT}, + {'D', GRUB_TERM_KEY_LEFT}, + {'F', GRUB_TERM_KEY_END}, + {'H', GRUB_TERM_KEY_HOME}, + {'K', GRUB_TERM_KEY_END}, + {'P', GRUB_TERM_KEY_DC}, + {'?', GRUB_TERM_KEY_PPAGE}, + {'/', GRUB_TERM_KEY_NPAGE} }; static struct { char key; - char ascii; + unsigned ascii; } four_code_table[] = { - {'1', GRUB_TERM_HOME}, - {'3', GRUB_TERM_DC}, - {'5', GRUB_TERM_PPAGE}, - {'6', GRUB_TERM_NPAGE} + {'1', GRUB_TERM_KEY_HOME}, + {'3', GRUB_TERM_KEY_DC}, + {'5', GRUB_TERM_KEY_PPAGE}, + {'6', GRUB_TERM_KEY_NPAGE} }; unsigned i; diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index ba67e2b85..e18f205e8 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -27,7 +27,7 @@ #include -static int keyboard_map[128] = +static unsigned keyboard_map[128] = { '\0', '\0', '\0', '\0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', @@ -36,13 +36,17 @@ static int keyboard_map[128] = '3', '4', '5', '6', '7', '8', '9', '0', '\n', GRUB_TERM_ESC, GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, ' ', '-', '=', '[', ']', '\\', '#', ';', '\'', '`', ',', '.', - '/', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, - GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_UP + '/', '\0', GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, + GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6, + GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, GRUB_TERM_KEY_F10, + GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, '\0', '\0', + '\0', GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, + GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, + GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_UP, + [0x64] = GRUB_TERM_KEY_102 }; -static char keyboard_map_shift[128] = +static unsigned keyboard_map_shift[128] = { '\0', '\0', '\0', '\0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', @@ -51,7 +55,8 @@ static char keyboard_map_shift[128] = '#', '$', '%', '^', '&', '*', '(', ')', '\n', '\0', '\0', '\0', ' ', '_', '+', '{', '}', '|', '#', ':', '"', '`', '<', '>', - '?' + '?', + [0x64] = GRUB_TERM_KEY_SHIFT_102 }; static grub_usb_device_t usbdev; @@ -157,8 +162,9 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused) #define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40 /* Check if the Shift key was pressed. */ - if (data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT - || data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) + if ((data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT + || data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) + && keyboard_map_shift[data[2]]) key = keyboard_map_shift[data[2]]; else key = keyboard_map[data[2]]; From b6f7b4ba03559d7340a811bfe03a1a47b49f8dc6 Mon Sep 17 00:00:00 2001 From: Carles Pina i Estany Date: Thu, 19 Aug 2010 02:15:29 +0200 Subject: [PATCH 07/64] Reimported heavily modified version of cpina's grub-mklayout --- ChangeLog.keyboard_layouts | 7 + conf/common.rmk | 4 + include/grub/at_keyboard.h | 15 +- include/grub/keyboard_layouts.h | 28 ++++ include/grub/term.h | 4 +- term/at_keyboard.c | 13 +- util/grub-mklayouts.c | 279 ++++++++++++++++++++++++++++++++ 7 files changed, 335 insertions(+), 15 deletions(-) create mode 100644 ChangeLog.keyboard_layouts create mode 100644 include/grub/keyboard_layouts.h create mode 100644 util/grub-mklayouts.c diff --git a/ChangeLog.keyboard_layouts b/ChangeLog.keyboard_layouts new file mode 100644 index 000000000..65af097ff --- /dev/null +++ b/ChangeLog.keyboard_layouts @@ -0,0 +1,7 @@ +2010-01-18 Carles Pina i Estany + + Adds keyboard layouts support. + + * conf/common.rmk (bin_UTILITIES): Add grub-mklayouts rules. + * include/grub/keyboard_layouts.h: New file. + * util/grub-mklayouts.c: New file. diff --git a/conf/common.rmk b/conf/common.rmk index ee6b94032..745b1837e 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -80,6 +80,10 @@ endif bin_UTILITIES += grub-mkrelpath grub_mkrelpath_SOURCES = gnulib/progname.c util/grub-mkrelpath.c util/misc.c kern/emu/misc.c +# For grub-mklayouts. +bin_UTILITIES += grub-mklayouts +grub_mklayouts_SOURCES = gnulib/progname.c util/grub-mklayouts.c util/misc.c kern/emu/misc.c + bin_UTILITIES += grub-bin2h grub_bin2h_SOURCES = gnulib/progname.c util/bin2h.c diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 3f72fa879..8bb090d2a 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -52,7 +52,7 @@ #endif #define GRUB_AT_KEY_KEYBOARD_MAP(name) \ -static const int name[128] = \ +static const unsigned name[128] = \ { \ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', \ '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, \ @@ -75,4 +75,17 @@ static const int name[128] = \ OLPC_RIGHT \ } +#define GRUB_AT_KEY_KEYBOARD_MAP_SHIFT(name) \ +static unsigned name[128] = \ +{ \ + '\0', '\0', '!', '@', '#', '$', '%', '^', \ + '&', '*', '(', ')', '_', '+', '\0', '\0', \ + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', \ + 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', \ + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', \ + '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', \ + 'B', 'N', 'M', '<', '>', '?', \ + [0x56] = GRUB_TERM_KEY_SHIFT_102 \ +} + #endif diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h new file mode 100644 index 000000000..1d263e268 --- /dev/null +++ b/include/grub/keyboard_layouts.h @@ -0,0 +1,28 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_KEYBOARD_LAYOUTS_H +#define GRUB_KEYBOARD_LAYOUTS_H 1 + +#define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" +#define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) +#define GRUB_KEYBOARD_LAYOUTS_VERSION 2 + +#define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 256 + +#endif /* GRUB_KEYBOARD_LAYOUTS */ diff --git a/include/grub/term.h b/include/grub/term.h index dbafef0e1..fa813d1b5 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -53,8 +53,8 @@ #define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 22) /* Used by keylayouts code. Never returned in grub_getkey. */ -#define GRUB_TERM_KEY_102 (GRUB_TERM_EXTENDED | 23) -#define GRUB_TERM_KEY_SHIFT_102 (GRUB_TERM_EXTENDED | 24) +#define GRUB_TERM_KEY_102 0x80 +#define GRUB_TERM_KEY_SHIFT_102 0x81 #define GRUB_TERM_ESC '\e' #define GRUB_TERM_TAB '\t' diff --git a/term/at_keyboard.c b/term/at_keyboard.c index e89f3bf5b..4c9c2a23a 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -42,18 +42,7 @@ static grub_uint8_t led_status; #define KEYBOARD_LED_CAPS (1 << 2) GRUB_AT_KEY_KEYBOARD_MAP (keyboard_map); - -static int keyboard_map_shift[128] = -{ - '\0', '\0', '!', '@', '#', '$', '%', '^', - '&', '*', '(', ')', '_', '+', '\0', '\0', - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', - 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', - '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?', - [0x56] = GRUB_TERM_KEY_SHIFT_102 -}; +GRUB_AT_KEY_KEYBOARD_MAP_SHIFT (keyboard_map_shift); static grub_uint8_t grub_keyboard_controller_orig; diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c new file mode 100644 index 000000000..48b17e798 --- /dev/null +++ b/util/grub-mklayouts.c @@ -0,0 +1,279 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "progname.h" + +#define CKBCOMP "ckbcomp" + +static struct option options[] = { + {"output", required_argument, 0, 'o'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +struct console_grub_equivalence +{ + char *layout; + grub_uint32_t grub; +}; + +static struct console_grub_equivalence console_grub_equivalences[] = { + {"KP_1", '1'}, + {"KP_2", '2'}, + {"KP_3", '3'}, + {"KP_4", '4'}, + {"KP_5", '5'}, + {"KP_6", '6'}, + {"KP_7", '7'}, + {"KP_8", '8'}, + {"KP_9", '9'}, + + {"KP_Multiply", '*'}, + {"KP_Substract", '-'}, + {"KP_Add", '+'}, + {"KP_Divide", '/'}, + + {"KP_Enter", '\n'}, + {"Return", '\n'}, + {"", '\0'} +}; + +GRUB_AT_KEY_KEYBOARD_MAP (us_keyboard_map); +GRUB_AT_KEY_KEYBOARD_MAP_SHIFT (us_keyboard_map_shifted); + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] LAYOUT\n\ + -o, --output set output base name file. Default is LAYOUT.gkb\n\ + -h, --help display this message and exit.\n\ + -V, --version print version information and exit.\n\ + -v, --verbose print verbose messages.\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +char +lookup (char *code) +{ + int i; + + for (i = 0; console_grub_equivalences[i].grub != '\0'; i++) + if (strcmp (code, console_grub_equivalences[i].layout) == 0) + return console_grub_equivalences[i].grub; + + return '\0'; +} + +unsigned int +get_grub_code (char *layout_code) +{ + unsigned int code; + + if (strncmp (layout_code, "U+", sizeof ("U+") - 1) == 0) + sscanf (layout_code, "U+%x", &code); + else if (strncmp (layout_code, "+U+", sizeof ("+U+") - 1) == 0) + sscanf (layout_code, "+U+%x", &code); + else + code = lookup (layout_code); + return code; +} + +void +write_file (char* filename, grub_uint32_t *keyboard_map) +{ + FILE *fp_output; + grub_uint32_t version; + unsigned i; + + version = grub_cpu_to_le32 (GRUB_KEYBOARD_LAYOUTS_VERSION); + + for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) + keyboard_map[i] = grub_cpu_to_le32 (keyboard_map[i]); + + fp_output = fopen (filename, "w"); + + if (!fp_output) + { + grub_util_error ("cannot open `%s'", filename); + exit (1); + } + + fwrite (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, 1, + GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, fp_output); + fwrite (&version, sizeof (version), 1, fp_output); + fwrite (keyboard_map, sizeof (keyboard_map[0]), + GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE, fp_output); + fclose (fp_output); +} + +void +write_keymaps (char *keymap, char *file_basename) +{ + grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + + char line[2048]; + pid_t pid; + int pipe_communication[2]; + int ok; + + FILE *fp_pipe; + + if (pipe (pipe_communication) == -1) + { + grub_util_error ("cannot prepare the pipe"); + exit (2); + } + + pid = fork (); + if (pid < 0) + { + grub_util_error ("cannot fork"); + exit (2); + } + else if (pid == 0) + { + close (1); + dup (pipe_communication[1]); + close (pipe_communication[0]); + execlp (CKBCOMP, CKBCOMP, keymap, NULL); + grub_util_error ("%s %s cannot be executed", CKBCOMP, keymap); + exit (3); + } + close (pipe_communication[1]); + fp_pipe = fdopen (pipe_communication[0], "r"); + + memset (keyboard_map, 0, sizeof (keyboard_map)); + + /* Process the ckbcomp output and prepare the layouts. */ + ok = 0; + while (fgets (line, sizeof (line), fp_pipe)) + { + if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0) + { + unsigned keycode; + char normal[64]; + char shift[64]; + sscanf (line, "keycode %u = %60s %60s", &keycode, normal, shift); + if (keycode < ARRAY_SIZE (us_keyboard_map) + && us_keyboard_map[keycode] < ARRAY_SIZE (keyboard_map)) + { + keyboard_map[us_keyboard_map[keycode]] = get_grub_code (normal); + ok = 1; + } + if (keycode < ARRAY_SIZE (us_keyboard_map_shifted) + && us_keyboard_map_shifted[keycode] < ARRAY_SIZE (keyboard_map)) + { + keyboard_map[us_keyboard_map_shifted[keycode]] + = get_grub_code (shift); + ok = 1; + } + } + } + + if (ok == 0) + { + fprintf (stderr, "ERROR: no keycodes found. Check output of %s %s.\n", + CKBCOMP, keymap); + exit (1); + } + + write_file (file_basename, keyboard_map); +} + +int +main (int argc, char *argv[]) +{ + int verbosity; + char *file_basename = NULL; + + set_program_name (argv[0]); + + verbosity = 0; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "o:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'o': + file_basename = optarg; + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, + PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain LAYOUT. */ + if (optind >= argc) + { + fprintf (stderr, "No layout is specified.\n"); + usage (1); + } + + if (file_basename == NULL) + { + file_basename = xasprintf ("%s.gkb", argv[optind]); + write_keymaps (argv[optind], file_basename); + free (file_basename); + } + else + write_keymaps (argv[optind], file_basename); + + return 0; +} From 211144767584a29193a70172b134ee2f4ea0e6c9 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 02:21:36 +0200 Subject: [PATCH 08/64] Add new flag SHIFT --- include/grub/term.h | 6 ++++-- term/at_keyboard.c | 12 ++++++++---- term/usb_keyboard.c | 10 +++++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/grub/term.h b/include/grub/term.h index fa813d1b5..1f64bebc7 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -20,6 +20,8 @@ #define GRUB_TERM_HEADER 1 /* Internal codes used by GRUB to represent terminal input. */ +/* Only for keys otherwise not having shifted modification. */ +#define GRUB_TERM_SHIFT 0x01000000 #define GRUB_TERM_CTRL 0x02000000 #define GRUB_TERM_ALT 0x04000000 /* Used by keylayouts code. Never returned in grub_getkey. */ @@ -27,8 +29,8 @@ #define GRUB_TERM_CAPS 0x10000000 /* Keys without associated character. */ -#define GRUB_TERM_EXTENDED 0x1000000 -#define GRUB_TERM_KEY_MASK 0x1ffffff +#define GRUB_TERM_EXTENDED 0x00800000 +#define GRUB_TERM_KEY_MASK 0x00ffffff #define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 1) #define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 2) #define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 3) diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 4c9c2a23a..cc0c69e22 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -187,10 +187,14 @@ grub_at_keyboard_getkey_noblock (void) key = -1; break; default: - if ((at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L - | KEYBOARD_STATUS_SHIFT_R)) - && keyboard_map_shift[code]) - key = keyboard_map_shift[code]; + if (at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L + | KEYBOARD_STATUS_SHIFT_R)) + { + if (keyboard_map_shift[code]) + key = keyboard_map_shift[code]; + else + key = keyboard_map[code] | GRUB_TERM_SHIFT; + } else key = keyboard_map[code]; diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index e18f205e8..9e1ce5e60 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -162,10 +162,14 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused) #define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40 /* Check if the Shift key was pressed. */ - if ((data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT + if (data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT || data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) - && keyboard_map_shift[data[2]]) - key = keyboard_map_shift[data[2]]; + { + if (keyboard_map_shift[data[2]]) + key = keyboard_map_shift[data[2]]; + else + key = keyboard_map[data[2]] | GRUB_TERM_SHIFT; + } else key = keyboard_map[data[2]]; From d90aa78482dfa4eebcf226484a386c0c6c3581a6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 02:57:05 +0200 Subject: [PATCH 09/64] KEyboard layout support --- commands/keylayouts.c | 112 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 58baabe67..05595f8d1 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -24,6 +24,10 @@ #include #include #include +#include +#include +#include +#include GRUB_AT_KEY_KEYBOARD_MAP (keyboard_map); @@ -73,20 +77,21 @@ get_abstract_code (grub_term_input_t term, int in) } } +static grub_uint32_t mapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + static int -map (grub_term_input_t term, int in) +map (grub_term_input_t term __attribute__ ((unused)), int in) { - /* No match with AltGr. Interpret it as Alt rather than as L3 modifier then. - */ + /* AltGr isn't supported yet. */ if (in & GRUB_TERM_ALT_GR) - return map (term, in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT_GR; + in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT_GR; - if (in == GRUB_TERM_KEY_102) - return '\\'; - if (in == GRUB_TERM_KEY_SHIFT_102) - return '|'; + if ((in & GRUB_TERM_EXTENDED) || (in & GRUB_TERM_KEY_MASK) == '\b' + || (in & GRUB_TERM_KEY_MASK) == '\t' || (in & GRUB_TERM_KEY_MASK) == '\e' + || (in & GRUB_TERM_KEY_MASK) >= ARRAY_SIZE (mapping)) + return in; - return in; + return mapping[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK); } static int @@ -152,15 +157,104 @@ grub_checkkey (void) return -1; } +static grub_err_t +grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + char *filename; + grub_file_t file; + grub_uint32_t version; + grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE]; + grub_uint32_t newmapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + unsigned i; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file or layout name required"); + if (argv[0][0] != '(' && argv[0][0] != '/' && argv[0][0] != '+') + { + const char *prefix = grub_env_get ("prefix"); + if (!prefix) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "No prefix set"); + filename = grub_xasprintf ("%s/layouts/%s.gkb", prefix, argv[0]); + if (!filename) + return grub_errno; + } + else + filename = argv[0]; + + file = grub_gzfile_open (filename, 1); + if (! file) + goto fail; + + if (grub_file_read (file, magic, sizeof (magic)) != sizeof (magic)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + + if (grub_memcmp (magic, GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, + GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE) != 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid magic"); + goto fail; + } + + if (grub_file_read (file, &version, sizeof (version)) != sizeof (version)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + + if (grub_le_to_cpu32 (version) != GRUB_KEYBOARD_LAYOUTS_VERSION) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid version"); + goto fail; + } + + if (grub_file_read (file, newmapping, sizeof (newmapping)) + != sizeof (newmapping)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + + for (i = 0; i < ARRAY_SIZE (mapping); i++) + mapping[i] = grub_le_to_cpu32(newmapping[i]); + + return GRUB_ERR_NONE; + + fail: + if (filename != argv[0]) + grub_free (filename); + if (file) + grub_file_close (file); + return grub_errno; +} + static int (*grub_getkey_saved) (void); +static grub_command_t cmd; + GRUB_MOD_INIT(keylayouts) { + unsigned i; + for (i = 0; i < ARRAY_SIZE (mapping); i++) + mapping[i] = i; + mapping[GRUB_TERM_KEY_102] = '\\'; + mapping[GRUB_TERM_KEY_SHIFT_102] = '|'; + grub_getkey_saved = grub_getkey; grub_getkey = grub_getkey_smart; + + cmd = grub_register_command ("keymap", grub_cmd_keymap, + 0, N_("Load a keyboard layout.")); } GRUB_MOD_FINI(keylayouts) { grub_getkey = grub_getkey_saved; + grub_unregister_command (cmd); } From 7ea82054f562055adb3d5c44ca402ec894cd89d4 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 04:13:32 +0200 Subject: [PATCH 10/64] Solve keypad-related issues --- commands/keylayouts.c | 44 ++++++++++++++++++++++-------- include/grub/at_keyboard.h | 56 +++++++++++++++++++++++--------------- include/grub/term.h | 6 ++-- 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 05595f8d1..419cdf45a 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -55,6 +55,11 @@ get_abstract_code (grub_term_input_t term, int in) if ((0x5600 | '|') == (in & 0xffff)) return GRUB_TERM_KEY_SHIFT_102 | flags; + if ((in & 0xff00) == 0x3500 || (in & 0xff00) == 0x3700 + || (in & 0xff00) == 0x4500 + || ((in & 0xff00) >= 0x4700 && (in & 0xff00) <= 0x5300)) + flags |= GRUB_TERM_KEYPAD; + /* Detect CTRL'ed keys. */ if ((in & 0xff) > 0 && (in & 0xff) < 0x20 && ((in & 0xffff) != (0x0100 | '\e')) @@ -79,19 +84,33 @@ get_abstract_code (grub_term_input_t term, int in) static grub_uint32_t mapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; -static int -map (grub_term_input_t term __attribute__ ((unused)), int in) +static unsigned +clear_internal_flags (unsigned in) { + if (in & GRUB_TERM_ALT_GR) + in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT; + return in & ~GRUB_TERM_CAPS & ~GRUB_TERM_KEYPAD; +} + +static unsigned +map (grub_term_input_t term __attribute__ ((unused)), unsigned in) +{ + if (in & GRUB_TERM_KEYPAD) + return clear_internal_flags (in); + /* AltGr isn't supported yet. */ if (in & GRUB_TERM_ALT_GR) - in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT_GR; + in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT; if ((in & GRUB_TERM_EXTENDED) || (in & GRUB_TERM_KEY_MASK) == '\b' + || (in & GRUB_TERM_KEY_MASK) == '\n' || (in & GRUB_TERM_KEY_MASK) == ' ' || (in & GRUB_TERM_KEY_MASK) == '\t' || (in & GRUB_TERM_KEY_MASK) == '\e' + || (in & GRUB_TERM_KEY_MASK) == '\r' || (in & GRUB_TERM_KEY_MASK) >= ARRAY_SIZE (mapping)) - return in; + return clear_internal_flags (in); - return mapping[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK); + return mapping[in & GRUB_TERM_KEY_MASK] + | clear_internal_flags (in & ~GRUB_TERM_KEY_MASK); } static int @@ -99,14 +118,15 @@ translate (grub_term_input_t term, int in) { int code, flags; code = get_abstract_code (term, in); - if ((code & GRUB_TERM_CAPS) && (code & 0xff) >= 'a' && (code & 0xff) <= 'z') - code = (code & 0xff) + 'A' - 'a'; - else if ((code & GRUB_TERM_CAPS) && (code & 0xff) >= 'A' - && (code & 0xff) <= 'Z') - code = (code & 0xff) + 'a' - 'A'; + if ((code & GRUB_TERM_CAPS) && (code & GRUB_TERM_KEY_MASK) >= 'a' + && (code & GRUB_TERM_KEY_MASK) <= 'z') + code = (code & GRUB_TERM_KEY_MASK) + 'A' - 'a'; + else if ((code & GRUB_TERM_CAPS) && (code & GRUB_TERM_KEY_MASK) >= 'A' + && (code & GRUB_TERM_KEY_MASK) <= 'Z') + code = (code & GRUB_TERM_KEY_MASK) + 'a' - 'A'; - flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR); - code &= (GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR); + flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD); + code &= (GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD); code = map (term, code); /* Transform unconsumed AltGr into Alt. */ if (code & GRUB_TERM_ALT_GR) diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 8bb090d2a..e8289d672 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -51,28 +51,40 @@ #define OLPC_RIGHT '\0' #endif -#define GRUB_AT_KEY_KEYBOARD_MAP(name) \ -static const unsigned name[128] = \ -{ \ - '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', \ - '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, \ - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', \ - 'o', 'p', '[', ']', '\n', '\0', 'a', 's', \ - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', \ - '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', \ - 'b', 'n', 'm', ',', '.', '/', '\0', '*', \ - '\0', ' ', '\0', GRUB_TERM_KEY_F1, \ - GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, \ - GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, \ - GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, \ - GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, \ - '\0', GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, \ - GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, \ - GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, \ - '\0', '\0', GRUB_TERM_KEY_102, GRUB_TERM_KEY_F11, \ - GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', \ - '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, \ - OLPC_RIGHT \ +#define GRUB_AT_KEY_KEYBOARD_MAP(name) \ +static const unsigned name[128] = \ +{ \ + /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', \ + /* 0x08 */ '7', '8', '9', '0', \ + /* 0x0c */ '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, \ + /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', \ + /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', \ + /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', \ + /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', \ + /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*' | GRUB_TERM_KEYPAD, \ + /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, \ + /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, \ + /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, \ + /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, \ + /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, \ + /* 0x44 */ GRUB_TERM_KEY_F10, '\0', \ + /* 0x46 */ '\0', GRUB_TERM_KEY_HOME, \ + /* 0x48 */ GRUB_TERM_KEY_UP, \ + /* 0x49 */ GRUB_TERM_KEY_NPAGE, \ + /* 0x4a */ '-' | GRUB_TERM_KEYPAD, \ + /* 0x4b */ GRUB_TERM_KEY_LEFT, \ + /* 0x4c */ GRUB_TERM_KEY_CENTER | GRUB_TERM_KEYPAD, \ + /* 0x4d */ GRUB_TERM_KEY_RIGHT, \ + /* 0x4e */ '+' | GRUB_TERM_KEYPAD, \ + /* 0x4f */ GRUB_TERM_KEY_END, \ + /* 0x50 */ GRUB_TERM_KEY_DOWN, \ + /* 0x51 */ GRUB_TERM_KEY_PPAGE, \ + /* 0x52 */ GRUB_TERM_KEY_INSERT, \ + /* 0x53 */ GRUB_TERM_KEY_DC, \ + /* 0x54 */ '\0', '\0', GRUB_TERM_KEY_102, GRUB_TERM_KEY_F11, \ + /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', \ + /* 0x60 */ '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, \ + /* 0x68 */ OLPC_RIGHT \ } #define GRUB_AT_KEY_KEYBOARD_MAP_SHIFT(name) \ diff --git a/include/grub/term.h b/include/grub/term.h index 1f64bebc7..f2f80152f 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -25,8 +25,9 @@ #define GRUB_TERM_CTRL 0x02000000 #define GRUB_TERM_ALT 0x04000000 /* Used by keylayouts code. Never returned in grub_getkey. */ -#define GRUB_TERM_ALT_GR 0x08000000 -#define GRUB_TERM_CAPS 0x10000000 +#define GRUB_TERM_ALT_GR 0x08000000 +#define GRUB_TERM_CAPS 0x10000000 +#define GRUB_TERM_KEYPAD 0x20000000 /* Keys without associated character. */ #define GRUB_TERM_EXTENDED 0x00800000 @@ -53,6 +54,7 @@ #define GRUB_TERM_KEY_F11 (GRUB_TERM_EXTENDED | 20) #define GRUB_TERM_KEY_F12 (GRUB_TERM_EXTENDED | 21) #define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 22) +#define GRUB_TERM_KEY_CENTER (GRUB_TERM_EXTENDED | 23) /* Used by keylayouts code. Never returned in grub_getkey. */ #define GRUB_TERM_KEY_102 0x80 From eb628338dbd4198d517c91090207b0a651d8088a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 11:44:49 +0200 Subject: [PATCH 11/64] AltGr support --- commands/keylayouts.c | 54 ++++++++++++++++++++++----------- include/grub/keyboard_layouts.h | 2 +- term/at_keyboard.c | 45 +++++++++++++++------------ util/grub-mklayouts.c | 21 +++++++++++-- 4 files changed, 82 insertions(+), 40 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 419cdf45a..25a117560 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -73,6 +73,18 @@ get_abstract_code (grub_term_input_t term, int in) if (((in & 0xff) == 0) && keyboard_map[(in & 0xff00) >> 8] >= 'a' && keyboard_map[(in & 0xff00) >> 8] <= 'z') return keyboard_map[(in & 0xff00) >> 8] | flags | GRUB_TERM_ALT_GR; + if ((in & 0xff) == 0 && (in & 0xff00) >= 0x7800 + && (in & 0xff00) <= 0x8000) + return (((in & 0xff00) >> 8) - 0x78 + '1') | flags | GRUB_TERM_ALT_GR; + + if ((in & 0xff00) == 0x8100) + return '0' | flags | GRUB_TERM_ALT_GR; + + if ((in & 0xffff) == 0x8200) + return '-' | flags | GRUB_TERM_ALT_GR; + + if ((in & 0xffff) == 0x8300) + return '+' | flags | GRUB_TERM_ALT_GR; if ((in & 0xff) == 0) return keyboard_map[(in & 0xff00) >> 8] | flags; @@ -83,34 +95,25 @@ get_abstract_code (grub_term_input_t term, int in) } static grub_uint32_t mapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - -static unsigned -clear_internal_flags (unsigned in) -{ - if (in & GRUB_TERM_ALT_GR) - in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT; - return in & ~GRUB_TERM_CAPS & ~GRUB_TERM_KEYPAD; -} +static grub_uint32_t mapping_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; static unsigned map (grub_term_input_t term __attribute__ ((unused)), unsigned in) { if (in & GRUB_TERM_KEYPAD) - return clear_internal_flags (in); - - /* AltGr isn't supported yet. */ - if (in & GRUB_TERM_ALT_GR) - in = (in & ~GRUB_TERM_ALT_GR) | GRUB_TERM_ALT; + return in; if ((in & GRUB_TERM_EXTENDED) || (in & GRUB_TERM_KEY_MASK) == '\b' || (in & GRUB_TERM_KEY_MASK) == '\n' || (in & GRUB_TERM_KEY_MASK) == ' ' || (in & GRUB_TERM_KEY_MASK) == '\t' || (in & GRUB_TERM_KEY_MASK) == '\e' || (in & GRUB_TERM_KEY_MASK) == '\r' || (in & GRUB_TERM_KEY_MASK) >= ARRAY_SIZE (mapping)) - return clear_internal_flags (in); + return in; - return mapping[in & GRUB_TERM_KEY_MASK] - | clear_internal_flags (in & ~GRUB_TERM_KEY_MASK); + if ((in & GRUB_TERM_ALT_GR) && mapping_alt[in & GRUB_TERM_KEY_MASK]) + return mapping_alt[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK & ~GRUB_TERM_ALT_GR); + + return mapping[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK); } static int @@ -118,6 +121,9 @@ translate (grub_term_input_t term, int in) { int code, flags; code = get_abstract_code (term, in); + + flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD | GRUB_TERM_CAPS); + if ((code & GRUB_TERM_CAPS) && (code & GRUB_TERM_KEY_MASK) >= 'a' && (code & GRUB_TERM_KEY_MASK) <= 'z') code = (code & GRUB_TERM_KEY_MASK) + 'A' - 'a'; @@ -125,7 +131,6 @@ translate (grub_term_input_t term, int in) && (code & GRUB_TERM_KEY_MASK) <= 'Z') code = (code & GRUB_TERM_KEY_MASK) + 'a' - 'A'; - flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD); code &= (GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD); code = map (term, code); /* Transform unconsumed AltGr into Alt. */ @@ -134,6 +139,8 @@ translate (grub_term_input_t term, int in) flags |= GRUB_TERM_ALT; code &= ~GRUB_TERM_ALT_GR; } + code &= ~GRUB_TERM_KEYPAD; + if ((flags & GRUB_TERM_CAPS) && code >= 'a' && code <= 'z') code += 'A' - 'a'; else if ((flags & GRUB_TERM_CAPS) && code >= 'A' @@ -186,6 +193,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), grub_uint32_t version; grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE]; grub_uint32_t newmapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t newmapping_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; unsigned i; if (argc < 1) @@ -241,9 +249,20 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), goto fail; } + if (grub_file_read (file, newmapping_alt, sizeof (newmapping_alt)) + != sizeof (newmapping_alt)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + for (i = 0; i < ARRAY_SIZE (mapping); i++) mapping[i] = grub_le_to_cpu32(newmapping[i]); + for (i = 0; i < ARRAY_SIZE (mapping_alt); i++) + mapping_alt[i] = grub_le_to_cpu32(newmapping_alt[i]); + return GRUB_ERR_NONE; fail: @@ -263,6 +282,7 @@ GRUB_MOD_INIT(keylayouts) unsigned i; for (i = 0; i < ARRAY_SIZE (mapping); i++) mapping[i] = i; + grub_memset (mapping_alt, 0, sizeof (mapping_alt)); mapping[GRUB_TERM_KEY_102] = '\\'; mapping[GRUB_TERM_KEY_SHIFT_102] = '|'; diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index 1d263e268..081e9ca98 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -21,7 +21,7 @@ #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) -#define GRUB_KEYBOARD_LAYOUTS_VERSION 2 +#define GRUB_KEYBOARD_LAYOUTS_VERSION 3 #define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 256 diff --git a/term/at_keyboard.c b/term/at_keyboard.c index cc0c69e22..5adc8b4da 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -34,6 +34,7 @@ static int pending_key = -1; #define KEYBOARD_STATUS_CTRL_R (1 << 5) #define KEYBOARD_STATUS_CAPS_LOCK (1 << 6) #define KEYBOARD_STATUS_NUM_LOCK (1 << 7) +#define KEYBOARD_STATUS_EXTENDED (1 << 8) static grub_uint8_t led_status; @@ -80,12 +81,10 @@ keyboard_controller_led (grub_uint8_t leds) /* FIXME: This should become an interrupt service routine. For now it's just used to catch events from control keys. */ static void -grub_keyboard_isr (char key) +grub_keyboard_isr (grub_uint8_t key) { - char is_make = KEYBOARD_ISMAKE (key); - key = KEYBOARD_SCANCODE (key); - if (is_make) - switch (key) + if (KEYBOARD_ISMAKE (key)) + switch (KEYBOARD_SCANCODE (key)) { case SHIFT_L: at_keyboard_status |= KEYBOARD_STATUS_SHIFT_L; @@ -97,14 +96,14 @@ grub_keyboard_isr (char key) at_keyboard_status |= KEYBOARD_STATUS_CTRL_L; break; case ALT: - at_keyboard_status |= KEYBOARD_STATUS_ALT_L; + if (at_keyboard_status & KEYBOARD_STATUS_EXTENDED) + at_keyboard_status |= KEYBOARD_STATUS_ALT_R; + else + at_keyboard_status |= KEYBOARD_STATUS_ALT_L; break; - default: - /* Skip grub_dprintf. */ - return; } else - switch (key) + switch (KEYBOARD_SCANCODE (key)) { case SHIFT_L: at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_L; @@ -116,15 +115,17 @@ grub_keyboard_isr (char key) at_keyboard_status &= ~KEYBOARD_STATUS_CTRL_L; break; case ALT: - at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L; + if (at_keyboard_status & KEYBOARD_STATUS_EXTENDED) + at_keyboard_status &= ~KEYBOARD_STATUS_ALT_R; + else + at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L; break; - default: - /* Skip grub_dprintf. */ - return; } -#ifdef DEBUG_AT_KEYBOARD - grub_dprintf ("atkeyb", "Control key 0x%0x was %s\n", key, is_make ? "pressed" : "unpressed"); -#endif + if (key == 0xe0) + at_keyboard_status |= KEYBOARD_STATUS_EXTENDED; + else + at_keyboard_status &= ~KEYBOARD_STATUS_EXTENDED; + } /* If there is a raw key pending, return it; otherwise return -1. */ @@ -210,9 +211,15 @@ grub_at_keyboard_getkey_noblock (void) } if (at_keyboard_status & KEYBOARD_STATUS_ALT_L) - key |= GRUB_TERM_ALT; + { + key |= GRUB_TERM_ALT; + grub_printf ("AltL"); + } if (at_keyboard_status & KEYBOARD_STATUS_ALT_R) - key |= GRUB_TERM_ALT_GR; + { + key |= GRUB_TERM_ALT_GR; + grub_printf ("AltGr"); + } if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R)) key |= GRUB_TERM_CTRL; diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index 48b17e798..434f9f4f8 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -115,7 +115,8 @@ get_grub_code (char *layout_code) } void -write_file (char* filename, grub_uint32_t *keyboard_map) +write_file (char* filename, grub_uint32_t *keyboard_map, + grub_uint32_t *keyboard_map_alt) { FILE *fp_output; grub_uint32_t version; @@ -126,6 +127,9 @@ write_file (char* filename, grub_uint32_t *keyboard_map) for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) keyboard_map[i] = grub_cpu_to_le32 (keyboard_map[i]); + for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) + keyboard_map_alt[i] = grub_cpu_to_le32 (keyboard_map_alt[i]); + fp_output = fopen (filename, "w"); if (!fp_output) @@ -139,6 +143,8 @@ write_file (char* filename, grub_uint32_t *keyboard_map) fwrite (&version, sizeof (version), 1, fp_output); fwrite (keyboard_map, sizeof (keyboard_map[0]), GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE, fp_output); + fwrite (keyboard_map_alt, sizeof (keyboard_map_alt[0]), + GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE, fp_output); fclose (fp_output); } @@ -146,6 +152,7 @@ void write_keymaps (char *keymap, char *file_basename) { grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; char line[2048]; pid_t pid; @@ -189,11 +196,17 @@ write_keymaps (char *keymap, char *file_basename) unsigned keycode; char normal[64]; char shift[64]; - sscanf (line, "keycode %u = %60s %60s", &keycode, normal, shift); + char normalalt[64]; + char shiftalt[64]; + + sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode, + normal, shift, normalalt, shiftalt); if (keycode < ARRAY_SIZE (us_keyboard_map) && us_keyboard_map[keycode] < ARRAY_SIZE (keyboard_map)) { keyboard_map[us_keyboard_map[keycode]] = get_grub_code (normal); + keyboard_map_alt[us_keyboard_map[keycode]] + = get_grub_code (normalalt); ok = 1; } if (keycode < ARRAY_SIZE (us_keyboard_map_shifted) @@ -201,6 +214,8 @@ write_keymaps (char *keymap, char *file_basename) { keyboard_map[us_keyboard_map_shifted[keycode]] = get_grub_code (shift); + keyboard_map_alt[us_keyboard_map_shifted[keycode]] + = get_grub_code (shiftalt); ok = 1; } } @@ -213,7 +228,7 @@ write_keymaps (char *keymap, char *file_basename) exit (1); } - write_file (file_basename, keyboard_map); + write_file (file_basename, keyboard_map, keyboard_map_alt); } int From ed19677fe3e6a1217260186d9e1a2494b9ff6cd2 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 13:32:36 +0200 Subject: [PATCH 12/64] Revert all parts done for BIOS keymap translation --- commands/keylayouts.c | 204 ++++---------------------------- include/grub/at_keyboard.h | 49 -------- include/grub/i386/pc/console.h | 13 -- include/grub/keyboard_layouts.h | 24 +++- include/grub/term.h | 63 ++++------ kern/i386/pc/startup.S | 34 +++++- kern/term.c | 23 +++- term/at_keyboard.c | 55 ++++++--- term/i386/pc/console.c | 3 +- term/usb_keyboard.c | 7 +- util/grub-fstest.c | 6 +- util/grub-mklayouts.c | 20 ---- util/grub-probe.c | 6 +- util/i386/pc/grub-setup.c | 6 +- 14 files changed, 166 insertions(+), 347 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 25a117560..bfe30d2ab 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -23,167 +23,11 @@ #include #include #include -#include #include #include #include #include -GRUB_AT_KEY_KEYBOARD_MAP (keyboard_map); - -static int -get_abstract_code (grub_term_input_t term, int in) -{ - switch (term->flags & GRUB_TERM_INPUT_FLAGS_TYPE_MASK) - { - case GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES: - default: - return in; - case GRUB_TERM_INPUT_FLAGS_TYPE_BIOS: - { - unsigned status = 0; - unsigned flags = 0; - - if (term->getkeystatus) - status = term->getkeystatus (term); - if (status & GRUB_TERM_CAPS) - flags |= GRUB_TERM_CAPS; - - if ((0x5600 | '\\') == (in & 0xffff)) - return GRUB_TERM_KEY_102 | flags; - - if ((0x5600 | '|') == (in & 0xffff)) - return GRUB_TERM_KEY_SHIFT_102 | flags; - - if ((in & 0xff00) == 0x3500 || (in & 0xff00) == 0x3700 - || (in & 0xff00) == 0x4500 - || ((in & 0xff00) >= 0x4700 && (in & 0xff00) <= 0x5300)) - flags |= GRUB_TERM_KEYPAD; - - /* Detect CTRL'ed keys. */ - if ((in & 0xff) > 0 && (in & 0xff) < 0x20 - && ((in & 0xffff) != (0x0100 | '\e')) - && ((in & 0xffff) != (0x0f00 | '\t')) - && ((in & 0xffff) != (0x0e00 | '\b')) - && ((in & 0xffff) != (0x1c00 | '\r')) - && ((in & 0xffff) != (0x1c00 | '\n'))) - return ((in & 0xff) - 1 + 'a') | flags | GRUB_TERM_CTRL; - /* Detect ALT'ed keys. */ - /* XXX no way to distinguish left and right ALT. */ - if (((in & 0xff) == 0) && keyboard_map[(in & 0xff00) >> 8] >= 'a' - && keyboard_map[(in & 0xff00) >> 8] <= 'z') - return keyboard_map[(in & 0xff00) >> 8] | flags | GRUB_TERM_ALT_GR; - if ((in & 0xff) == 0 && (in & 0xff00) >= 0x7800 - && (in & 0xff00) <= 0x8000) - return (((in & 0xff00) >> 8) - 0x78 + '1') | flags | GRUB_TERM_ALT_GR; - - if ((in & 0xff00) == 0x8100) - return '0' | flags | GRUB_TERM_ALT_GR; - - if ((in & 0xffff) == 0x8200) - return '-' | flags | GRUB_TERM_ALT_GR; - - if ((in & 0xffff) == 0x8300) - return '+' | flags | GRUB_TERM_ALT_GR; - - if ((in & 0xff) == 0) - return keyboard_map[(in & 0xff00) >> 8] | flags; - - return (in & 0xff) | flags; - } - } -} - -static grub_uint32_t mapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; -static grub_uint32_t mapping_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - -static unsigned -map (grub_term_input_t term __attribute__ ((unused)), unsigned in) -{ - if (in & GRUB_TERM_KEYPAD) - return in; - - if ((in & GRUB_TERM_EXTENDED) || (in & GRUB_TERM_KEY_MASK) == '\b' - || (in & GRUB_TERM_KEY_MASK) == '\n' || (in & GRUB_TERM_KEY_MASK) == ' ' - || (in & GRUB_TERM_KEY_MASK) == '\t' || (in & GRUB_TERM_KEY_MASK) == '\e' - || (in & GRUB_TERM_KEY_MASK) == '\r' - || (in & GRUB_TERM_KEY_MASK) >= ARRAY_SIZE (mapping)) - return in; - - if ((in & GRUB_TERM_ALT_GR) && mapping_alt[in & GRUB_TERM_KEY_MASK]) - return mapping_alt[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK & ~GRUB_TERM_ALT_GR); - - return mapping[in & GRUB_TERM_KEY_MASK] | (in & ~GRUB_TERM_KEY_MASK); -} - -static int -translate (grub_term_input_t term, int in) -{ - int code, flags; - code = get_abstract_code (term, in); - - flags = code & ~(GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD | GRUB_TERM_CAPS); - - if ((code & GRUB_TERM_CAPS) && (code & GRUB_TERM_KEY_MASK) >= 'a' - && (code & GRUB_TERM_KEY_MASK) <= 'z') - code = (code & GRUB_TERM_KEY_MASK) + 'A' - 'a'; - else if ((code & GRUB_TERM_CAPS) && (code & GRUB_TERM_KEY_MASK) >= 'A' - && (code & GRUB_TERM_KEY_MASK) <= 'Z') - code = (code & GRUB_TERM_KEY_MASK) + 'a' - 'A'; - - code &= (GRUB_TERM_KEY_MASK | GRUB_TERM_ALT_GR | GRUB_TERM_KEYPAD); - code = map (term, code); - /* Transform unconsumed AltGr into Alt. */ - if (code & GRUB_TERM_ALT_GR) - { - flags |= GRUB_TERM_ALT; - code &= ~GRUB_TERM_ALT_GR; - } - code &= ~GRUB_TERM_KEYPAD; - - if ((flags & GRUB_TERM_CAPS) && code >= 'a' && code <= 'z') - code += 'A' - 'a'; - else if ((flags & GRUB_TERM_CAPS) && code >= 'A' - && code <= 'Z') - code += 'a' - 'A'; - return code | flags; -} - -static int -grub_getkey_smart (void) -{ - grub_term_input_t term; - - grub_refresh (); - - while (1) - { - FOR_ACTIVE_TERM_INPUTS(term) - { - int key = term->checkkey (term); - if (key != -1) - return translate (term, term->getkey (term)); - } - - grub_cpu_idle (); - } -} - -int -grub_checkkey (void) -{ - grub_term_input_t term; - - FOR_ACTIVE_TERM_INPUTS(term) - { - int key = term->checkkey (term); - if (key != -1) - return translate (term, key); - } - - return -1; -} - static grub_err_t grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), int argc, char *argv[]) @@ -192,8 +36,7 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), grub_file_t file; grub_uint32_t version; grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE]; - grub_uint32_t newmapping[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t newmapping_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + struct grub_keyboard_layout *newmap = NULL; unsigned i; if (argc < 1) @@ -241,60 +84,53 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), goto fail; } - if (grub_file_read (file, newmapping, sizeof (newmapping)) - != sizeof (newmapping)) + newmap = grub_malloc (sizeof (*newmap)); + if (!newmap) + goto fail; + + if (grub_file_read (file, newmap, sizeof (*newmap)) != sizeof (*newmap)) { if (!grub_errno) grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); goto fail; } - if (grub_file_read (file, newmapping_alt, sizeof (newmapping_alt)) - != sizeof (newmapping_alt)) - { - if (!grub_errno) - grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); - goto fail; - } + for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map); i++) + newmap->at.keyboard_map[i] = grub_le_to_cpu32(newmap->at.keyboard_map[i]); - for (i = 0; i < ARRAY_SIZE (mapping); i++) - mapping[i] = grub_le_to_cpu32(newmapping[i]); + for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map_shift); i++) + newmap->at.keyboard_map_shift[i] + = grub_le_to_cpu32(newmap->at.keyboard_map_shift[i]); - for (i = 0; i < ARRAY_SIZE (mapping_alt); i++) - mapping_alt[i] = grub_le_to_cpu32(newmapping_alt[i]); + for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map_l3); i++) + newmap->at.keyboard_map_l3[i] + = grub_le_to_cpu32(newmap->at.keyboard_map_l3[i]); + + for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map_shift_l3); i++) + newmap->at.keyboard_map_shift_l3[i] + = grub_le_to_cpu32(newmap->at.keyboard_map_shift_l3[i]); return GRUB_ERR_NONE; fail: if (filename != argv[0]) grub_free (filename); + grub_free (newmap); if (file) grub_file_close (file); return grub_errno; } -static int (*grub_getkey_saved) (void); - static grub_command_t cmd; GRUB_MOD_INIT(keylayouts) { - unsigned i; - for (i = 0; i < ARRAY_SIZE (mapping); i++) - mapping[i] = i; - grub_memset (mapping_alt, 0, sizeof (mapping_alt)); - mapping[GRUB_TERM_KEY_102] = '\\'; - mapping[GRUB_TERM_KEY_SHIFT_102] = '|'; - - grub_getkey_saved = grub_getkey; - grub_getkey = grub_getkey_smart; - cmd = grub_register_command ("keymap", grub_cmd_keymap, 0, N_("Load a keyboard layout.")); } GRUB_MOD_FINI(keylayouts) { - grub_getkey = grub_getkey_saved; + grub_current_layout = NULL; grub_unregister_command (cmd); } diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index e8289d672..10421540a 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -51,53 +51,4 @@ #define OLPC_RIGHT '\0' #endif -#define GRUB_AT_KEY_KEYBOARD_MAP(name) \ -static const unsigned name[128] = \ -{ \ - /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', \ - /* 0x08 */ '7', '8', '9', '0', \ - /* 0x0c */ '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, \ - /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', \ - /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', \ - /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', \ - /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', \ - /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*' | GRUB_TERM_KEYPAD, \ - /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, \ - /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, \ - /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, \ - /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, \ - /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, \ - /* 0x44 */ GRUB_TERM_KEY_F10, '\0', \ - /* 0x46 */ '\0', GRUB_TERM_KEY_HOME, \ - /* 0x48 */ GRUB_TERM_KEY_UP, \ - /* 0x49 */ GRUB_TERM_KEY_NPAGE, \ - /* 0x4a */ '-' | GRUB_TERM_KEYPAD, \ - /* 0x4b */ GRUB_TERM_KEY_LEFT, \ - /* 0x4c */ GRUB_TERM_KEY_CENTER | GRUB_TERM_KEYPAD, \ - /* 0x4d */ GRUB_TERM_KEY_RIGHT, \ - /* 0x4e */ '+' | GRUB_TERM_KEYPAD, \ - /* 0x4f */ GRUB_TERM_KEY_END, \ - /* 0x50 */ GRUB_TERM_KEY_DOWN, \ - /* 0x51 */ GRUB_TERM_KEY_PPAGE, \ - /* 0x52 */ GRUB_TERM_KEY_INSERT, \ - /* 0x53 */ GRUB_TERM_KEY_DC, \ - /* 0x54 */ '\0', '\0', GRUB_TERM_KEY_102, GRUB_TERM_KEY_F11, \ - /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', \ - /* 0x60 */ '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, \ - /* 0x68 */ OLPC_RIGHT \ -} - -#define GRUB_AT_KEY_KEYBOARD_MAP_SHIFT(name) \ -static unsigned name[128] = \ -{ \ - '\0', '\0', '!', '@', '#', '$', '%', '^', \ - '&', '*', '(', ')', '_', '+', '\0', '\0', \ - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', \ - 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', \ - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', \ - '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', \ - 'B', 'N', 'M', '<', '>', '?', \ - [0x56] = GRUB_TERM_KEY_SHIFT_102 \ -} - #endif diff --git a/include/grub/i386/pc/console.h b/include/grub/i386/pc/console.h index 7f58344ec..fabb13d5c 100644 --- a/include/grub/i386/pc/console.h +++ b/include/grub/i386/pc/console.h @@ -19,19 +19,6 @@ #ifndef GRUB_CONSOLE_MACHINE_HEADER #define GRUB_CONSOLE_MACHINE_HEADER 1 -/* Define scan codes. */ -#define GRUB_CONSOLE_KEY_LEFT 0x4B00 -#define GRUB_CONSOLE_KEY_RIGHT 0x4D00 -#define GRUB_CONSOLE_KEY_UP 0x4800 -#define GRUB_CONSOLE_KEY_DOWN 0x5000 -#define GRUB_CONSOLE_KEY_IC 0x5200 -#define GRUB_CONSOLE_KEY_DC 0x5300 -#define GRUB_CONSOLE_KEY_BACKSPACE 0x0008 -#define GRUB_CONSOLE_KEY_HOME 0x4700 -#define GRUB_CONSOLE_KEY_END 0x4F00 -#define GRUB_CONSOLE_KEY_NPAGE 0x5100 -#define GRUB_CONSOLE_KEY_PPAGE 0x4900 - #ifndef ASM_FILE #include diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index 081e9ca98..2d6e3d54c 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -21,8 +21,28 @@ #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) -#define GRUB_KEYBOARD_LAYOUTS_VERSION 3 +#define GRUB_KEYBOARD_LAYOUTS_VERSION 4 -#define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 256 +#define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 128 + +struct grub_keyboard_layout +{ + struct + { + grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + } at; + struct + { + grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + } usb; +}; + +struct grub_keyboard_layout *EXPORT_VAR (grub_current_layout); #endif /* GRUB_KEYBOARD_LAYOUTS */ diff --git a/include/grub/term.h b/include/grub/term.h index f2f80152f..036e8caaa 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -24,41 +24,34 @@ #define GRUB_TERM_SHIFT 0x01000000 #define GRUB_TERM_CTRL 0x02000000 #define GRUB_TERM_ALT 0x04000000 -/* Used by keylayouts code. Never returned in grub_getkey. */ -#define GRUB_TERM_ALT_GR 0x08000000 -#define GRUB_TERM_CAPS 0x10000000 -#define GRUB_TERM_KEYPAD 0x20000000 /* Keys without associated character. */ #define GRUB_TERM_EXTENDED 0x00800000 #define GRUB_TERM_KEY_MASK 0x00ffffff -#define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 1) -#define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 2) -#define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 3) -#define GRUB_TERM_KEY_DOWN (GRUB_TERM_EXTENDED | 4) -#define GRUB_TERM_KEY_HOME (GRUB_TERM_EXTENDED | 5) -#define GRUB_TERM_KEY_END (GRUB_TERM_EXTENDED | 6) -#define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 7) -#define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 8) -#define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 9) -#define GRUB_TERM_KEY_F1 (GRUB_TERM_EXTENDED | 10) -#define GRUB_TERM_KEY_F2 (GRUB_TERM_EXTENDED | 11) -#define GRUB_TERM_KEY_F3 (GRUB_TERM_EXTENDED | 12) -#define GRUB_TERM_KEY_F4 (GRUB_TERM_EXTENDED | 13) -#define GRUB_TERM_KEY_F5 (GRUB_TERM_EXTENDED | 14) -#define GRUB_TERM_KEY_F6 (GRUB_TERM_EXTENDED | 15) -#define GRUB_TERM_KEY_F7 (GRUB_TERM_EXTENDED | 16) -#define GRUB_TERM_KEY_F8 (GRUB_TERM_EXTENDED | 17) -#define GRUB_TERM_KEY_F9 (GRUB_TERM_EXTENDED | 18) -#define GRUB_TERM_KEY_F10 (GRUB_TERM_EXTENDED | 19) -#define GRUB_TERM_KEY_F11 (GRUB_TERM_EXTENDED | 20) -#define GRUB_TERM_KEY_F12 (GRUB_TERM_EXTENDED | 21) -#define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 22) -#define GRUB_TERM_KEY_CENTER (GRUB_TERM_EXTENDED | 23) -/* Used by keylayouts code. Never returned in grub_getkey. */ -#define GRUB_TERM_KEY_102 0x80 -#define GRUB_TERM_KEY_SHIFT_102 0x81 +#define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 0x4b) +#define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 0x4d) +#define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 0x48) +#define GRUB_TERM_KEY_DOWN (GRUB_TERM_EXTENDED | 0x50) +#define GRUB_TERM_KEY_HOME (GRUB_TERM_EXTENDED | 0x47) +#define GRUB_TERM_KEY_END (GRUB_TERM_EXTENDED | 0x4f) +#define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 0x53) +#define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 0x49) +#define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 0x51) +#define GRUB_TERM_KEY_F1 (GRUB_TERM_EXTENDED | 0x3b) +#define GRUB_TERM_KEY_F2 (GRUB_TERM_EXTENDED | 0x3c) +#define GRUB_TERM_KEY_F3 (GRUB_TERM_EXTENDED | 0x3d) +#define GRUB_TERM_KEY_F4 (GRUB_TERM_EXTENDED | 0x3e) +#define GRUB_TERM_KEY_F5 (GRUB_TERM_EXTENDED | 0x3f) +#define GRUB_TERM_KEY_F6 (GRUB_TERM_EXTENDED | 0x40) +#define GRUB_TERM_KEY_F7 (GRUB_TERM_EXTENDED | 0x41) +#define GRUB_TERM_KEY_F8 (GRUB_TERM_EXTENDED | 0x42) +#define GRUB_TERM_KEY_F9 (GRUB_TERM_EXTENDED | 0x43) +#define GRUB_TERM_KEY_F10 (GRUB_TERM_EXTENDED | 0x44) +#define GRUB_TERM_KEY_F11 (GRUB_TERM_EXTENDED | 0x57) +#define GRUB_TERM_KEY_F12 (GRUB_TERM_EXTENDED | 0x58) +#define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 0x52) +#define GRUB_TERM_KEY_CENTER (GRUB_TERM_EXTENDED | 0x4c) #define GRUB_TERM_ESC '\e' #define GRUB_TERM_TAB '\t' @@ -168,16 +161,10 @@ struct grub_term_input /* Get keyboard modifier status. */ int (*getkeystatus) (struct grub_term_input *term); - grub_uint32_t flags; - void *data; }; typedef struct grub_term_input *grub_term_input_t; -#define GRUB_TERM_INPUT_FLAGS_TYPE_MASK 0xf -#define GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES 0x0 -#define GRUB_TERM_INPUT_FLAGS_TYPE_BIOS 0x1 - struct grub_term_output { /* The next terminal. */ @@ -314,8 +301,8 @@ grub_term_unregister_output (grub_term_output_t term) #define FOR_DISABLED_TERM_OUTPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_outputs_disabled)) void grub_putcode (grub_uint32_t code, struct grub_term_output *term); -extern int (*EXPORT_VAR(grub_getkey)) (void); -int grub_checkkey (void); +int EXPORT_FUNC(grub_getkey) (void); +int EXPORT_FUNC(grub_checkkey) (void); void grub_cls (void); void EXPORT_FUNC(grub_refresh) (void); void grub_puts_terminal (const char *str, struct grub_term_output *term); diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index cbc4c5cfb..ef5904bb2 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1147,6 +1147,11 @@ FUNCTION(grub_console_putchar) ret +LOCAL(bypass_table): + .word 0x0100 | '\e',0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r' + .word 0x1c00 | '\n' +LOCAL(bypass_table_end): + /* * int grub_console_getkey (void) * BIOS call "INT 16H Function 00H" to read character from keyboard @@ -1180,17 +1185,39 @@ FUNCTION(grub_console_getkey) movb $0, %ah int $0x16 + xorl %edx, %edx movw %ax, %dx /* real_to_prot uses %eax */ DATA32 call real_to_prot .code32 - movw %dx, %ax + movl $0xff, %eax + testl %eax, %edx + jz 1f + + andl %edx, %eax + cmp %eax, 0x20 + ja 2f + movl %edx, %eax + leal LOCAL(bypass_table), %esi + movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx + repne cmpsw + jz 3f + + addl $('a' - 1 | GRUB_TERM_CTRL), %eax + jmp 2f +3: + andl $0xff, %eax + jmp 2f + +1: movl %edx, %eax + shrl $8, %eax + orl $GRUB_TERM_EXTENDED, %eax +2: popl %ebp ret - /* * int grub_console_checkkey (void) * if there is a character pending, return it; otherwise return -1 @@ -1216,6 +1243,7 @@ FUNCTION(grub_console_checkkey) jz notpending + xorl %edx, %edx movw %ax, %dx DATA32 jmp pending @@ -1226,8 +1254,6 @@ pending: DATA32 call real_to_prot .code32 - movl %edx, %eax - popl %ebp ret diff --git a/kern/term.c b/kern/term.c index d582dbb68..04d20364a 100644 --- a/kern/term.c +++ b/kern/term.c @@ -22,11 +22,13 @@ #include #include #include +#include struct grub_term_output *grub_term_outputs_disabled; struct grub_term_input *grub_term_inputs_disabled; struct grub_term_output *grub_term_outputs; struct grub_term_input *grub_term_inputs; +struct grub_keyboard_layout *grub_current_layout; /* Put a Unicode character. */ static void @@ -76,8 +78,8 @@ grub_xputs_dumb (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_dumb; -static int -grub_getkey_dumb (void) +int +grub_getkey (void) { grub_term_input_t term; @@ -89,14 +91,27 @@ grub_getkey_dumb (void) { int key = term->checkkey (term); if (key != -1) - return term->getkey (term) & 0xff; + return term->getkey (term); } grub_cpu_idle (); } } -int (*grub_getkey) (void) = grub_getkey_dumb; +int +grub_checkkey (void) +{ + grub_term_input_t term; + + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->checkkey (term); + if (key != -1) + return key; + } + + return -1; +} void grub_refresh (void) diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 5adc8b4da..492075115 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -42,8 +42,43 @@ static grub_uint8_t led_status; #define KEYBOARD_LED_NUM (1 << 1) #define KEYBOARD_LED_CAPS (1 << 2) -GRUB_AT_KEY_KEYBOARD_MAP (keyboard_map); -GRUB_AT_KEY_KEYBOARD_MAP_SHIFT (keyboard_map_shift); +static const unsigned keyboard_map[128] = +{ + /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', + /* 0x08 */ '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, + /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', + /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', + /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*', + /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, + /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, + /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, + /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, + /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, + /* 0x44 */ GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, + /* 0x48 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, + /* 0x4c */ GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, + /* 0x50 */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, + /* 0x52 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, + /* 0x54 */ '\0', '\0', '\\', GRUB_TERM_KEY_F11, + /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', + /* 0x60 */ '\0', '\0', '\0', '\0', + /* 0x64 */ '\0', GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_LEFT, + /* 0x68 */ GRUB_TERM_KEY_RIGHT +}; + +static unsigned keyboard_map_shift[128] = +{ + '\0', '\0', '!', '@', '#', '$', '%', '^', + '&', '*', '(', ')', '_', '+', '\0', '\0', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', + [0x56] = '|' +}; static grub_uint8_t grub_keyboard_controller_orig; @@ -211,21 +246,12 @@ grub_at_keyboard_getkey_noblock (void) } if (at_keyboard_status & KEYBOARD_STATUS_ALT_L) - { - key |= GRUB_TERM_ALT; - grub_printf ("AltL"); - } + key |= GRUB_TERM_ALT; if (at_keyboard_status & KEYBOARD_STATUS_ALT_R) - { - key |= GRUB_TERM_ALT_GR; - grub_printf ("AltGr"); - } + key |= GRUB_TERM_ALT; if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R)) key |= GRUB_TERM_CTRL; - - if (at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK) - key |= GRUB_TERM_CAPS; } return key; } @@ -284,8 +310,7 @@ static struct grub_term_input grub_at_keyboard_term = .init = grub_keyboard_controller_init, .fini = grub_keyboard_controller_fini, .checkkey = grub_at_keyboard_checkkey, - .getkey = grub_at_keyboard_getkey, - .flags = GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES + .getkey = grub_at_keyboard_getkey }; GRUB_MOD_INIT(at_keyboard) diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index 1bf954874..74df4c27f 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -50,8 +50,7 @@ static struct grub_term_input grub_console_term_input = .name = "console", .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, - .getkeystatus = grub_console_getkeystatus, - .flags = GRUB_TERM_INPUT_FLAGS_TYPE_BIOS + .getkeystatus = grub_console_getkeystatus }; static struct grub_term_output grub_console_term_output = diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 9e1ce5e60..3432f700c 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -43,7 +43,7 @@ static unsigned keyboard_map[128] = '\0', GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_UP, - [0x64] = GRUB_TERM_KEY_102 + [0x64] = '\\' }; static unsigned keyboard_map_shift[128] = @@ -56,7 +56,7 @@ static unsigned keyboard_map_shift[128] = '\n', '\0', '\0', '\0', ' ', '_', '+', '{', '}', '|', '#', ':', '"', '`', '<', '>', '?', - [0x64] = GRUB_TERM_KEY_SHIFT_102 + [0x64] = '|' }; static grub_usb_device_t usbdev; @@ -186,7 +186,7 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused) key |= GRUB_TERM_ALT; if (data[0] & GRUB_USB_KEYBOARD_RIGHT_ALT) - key |= GRUB_TERM_ALT_GR; + key |= GRUB_TERM_ALT; #if 0 /* Wait until the key is released. */ @@ -341,7 +341,6 @@ static struct grub_term_input grub_usb_keyboard_term = .checkkey = grub_usb_keyboard_checkkey, .getkey = grub_usb_keyboard_getkey, .getkeystatus = grub_usb_keyboard_getkeystatus, - .flags = GRUB_TERM_INPUT_FLAGS_TYPE_TERMCODES, .next = 0 }; diff --git a/util/grub-fstest.c b/util/grub-fstest.c index 715dfe2dd..2c80b964c 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -51,14 +51,12 @@ grub_xputs_real (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_real; -static int -grub_getkey_real (void) +int +grub_getkey (void) { return -1; } -int (*grub_getkey) (void) = grub_getkey_real; - void grub_refresh (void) { diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index 434f9f4f8..9aca88cb1 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -67,9 +67,6 @@ static struct console_grub_equivalence console_grub_equivalences[] = { {"", '\0'} }; -GRUB_AT_KEY_KEYBOARD_MAP (us_keyboard_map); -GRUB_AT_KEY_KEYBOARD_MAP_SHIFT (us_keyboard_map_shifted); - static void usage (int status) { @@ -201,23 +198,6 @@ write_keymaps (char *keymap, char *file_basename) sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode, normal, shift, normalalt, shiftalt); - if (keycode < ARRAY_SIZE (us_keyboard_map) - && us_keyboard_map[keycode] < ARRAY_SIZE (keyboard_map)) - { - keyboard_map[us_keyboard_map[keycode]] = get_grub_code (normal); - keyboard_map_alt[us_keyboard_map[keycode]] - = get_grub_code (normalalt); - ok = 1; - } - if (keycode < ARRAY_SIZE (us_keyboard_map_shifted) - && us_keyboard_map_shifted[keycode] < ARRAY_SIZE (keyboard_map)) - { - keyboard_map[us_keyboard_map_shifted[keycode]] - = get_grub_code (shift); - keyboard_map_alt[us_keyboard_map_shifted[keycode]] - = get_grub_code (shiftalt); - ok = 1; - } } } diff --git a/util/grub-probe.c b/util/grub-probe.c index e4d3f2906..56cbc5592 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -68,14 +68,12 @@ grub_xputs_real (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_real; -static int -grub_getkey_real (void) +int +grub_getkey (void) { return -1; } -int (*grub_getkey) (void) = grub_getkey_real; - void grub_refresh (void) { diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 4e3980965..524572fad 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -72,14 +72,12 @@ grub_xputs_real (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_real; -static int -grub_getkey_real (void) +int +grub_getkey (void) { return -1; } -int (*grub_getkey) (void) = grub_getkey_real; - void grub_refresh (void) { From e55e09628d0f67ecf87b0d3b0bdad140bd48bdce Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 15:00:31 +0200 Subject: [PATCH 13/64] Hook AT keyboard mapping --- commands/keylayouts.c | 127 ++++++++++++++++++++++++++++++- commands/keystatus.c | 6 +- include/grub/keyboard_layouts.h | 30 ++++---- include/grub/term.h | 12 ++- kern/term.c | 2 - term/at_keyboard.c | 129 ++++++-------------------------- term/i386/pc/console.c | 18 +---- term/usb_keyboard.c | 20 +++-- util/grub-mklayouts.c | 119 ++++++++++++++++++++++++----- 9 files changed, 290 insertions(+), 173 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index bfe30d2ab..b7aee7fab 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -28,6 +28,115 @@ #include #include +static struct grub_keyboard_layout layout_us = { + .at = { + .keyboard_map = { + /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', + /* 0x08 */ '7', '8', '9', '0', + /* 0x0c */ '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, + /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', + /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', + /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*', + /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, + /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, + /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, + /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, + /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, + /* 0x44 */ GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, + /* 0x48 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, + /* 0x4c */ GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, + /* 0x4e */ '+', GRUB_TERM_KEY_END, + /* 0x50 */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, + /* 0x52 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, + /* 0x54 */ '\0', '\0', '\\', GRUB_TERM_KEY_F11, + /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', + /* 0x60 */ '\0', '\0', '\0', '\0', + /* 0x64 */ '\0', GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_LEFT, + /* 0x68 */ GRUB_TERM_KEY_RIGHT + }, + .keyboard_map_shift = { + '\0', '\0', '!', '@', '#', '$', '%', '^', + '&', '*', '(', ')', '_', '+', '\0', '\0', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', + [0x56] = '|' + } + } +}; + +static struct grub_keyboard_layout *grub_current_layout = &layout_us; + +static int +map_key_core (int code, int status, int *alt_gr_consumed) +{ + *alt_gr_consumed = 0; + + if (status & GRUB_TERM_STATUS_RALT) + { + if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) + { + if (grub_current_layout->at.keyboard_map_shift_l3[code]) + { + *alt_gr_consumed = 1; + return grub_current_layout->at.keyboard_map_shift_l3[code]; + } + else if (grub_current_layout->at.keyboard_map_shift[code]) + { + *alt_gr_consumed = 1; + return grub_current_layout->at.keyboard_map_l3[code] + | GRUB_TERM_SHIFT; + } + } + else if (grub_current_layout->at.keyboard_map_shift[code]) + { + *alt_gr_consumed = 1; + return grub_current_layout->at.keyboard_map_l3[code]; + } + } + if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) + { + if (grub_current_layout->at.keyboard_map_shift[code]) + return grub_current_layout->at.keyboard_map_shift[code]; + else + return grub_current_layout->at.keyboard_map[code] | GRUB_TERM_SHIFT; + } + else + return grub_current_layout->at.keyboard_map[code]; +} + +unsigned +grub_term_map_key (int code, int status) +{ + int alt_gr_consumed; + int key; + + key = map_key_core (code, status, &alt_gr_consumed); + + if (key == 0 || key == GRUB_TERM_SHIFT) + grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code); + + if (status & GRUB_TERM_STATUS_CAPS) + { + if ((key >= 'a') && (key <= 'z')) + key += 'A' - 'a'; + else if ((key >= 'A') && (key <= 'Z')) + key += 'a' - 'A'; + } + + if ((status & GRUB_TERM_STATUS_LALT) || + ((status & GRUB_TERM_STATUS_RALT) && !alt_gr_consumed)) + key |= GRUB_TERM_ALT; + if (status & (GRUB_TERM_STATUS_LCTRL | GRUB_TERM_STATUS_RCTRL)) + key |= GRUB_TERM_CTRL; + + return key; +} + static grub_err_t grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), int argc, char *argv[]) @@ -110,6 +219,23 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), newmap->at.keyboard_map_shift_l3[i] = grub_le_to_cpu32(newmap->at.keyboard_map_shift_l3[i]); + for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map); i++) + newmap->usb.keyboard_map[i] = grub_le_to_cpu32(newmap->usb.keyboard_map[i]); + + for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map_shift); i++) + newmap->usb.keyboard_map_shift[i] + = grub_le_to_cpu32(newmap->usb.keyboard_map_shift[i]); + + for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map_l3); i++) + newmap->usb.keyboard_map_l3[i] + = grub_le_to_cpu32(newmap->usb.keyboard_map_l3[i]); + + for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map_shift_l3); i++) + newmap->usb.keyboard_map_shift_l3[i] + = grub_le_to_cpu32(newmap->usb.keyboard_map_shift_l3[i]); + + grub_current_layout = newmap; + return GRUB_ERR_NONE; fail: @@ -131,6 +257,5 @@ GRUB_MOD_INIT(keylayouts) GRUB_MOD_FINI(keylayouts) { - grub_current_layout = NULL; grub_unregister_command (cmd); } diff --git a/commands/keystatus.c b/commands/keystatus.c index 9db92b942..9c7ab84b0 100644 --- a/commands/keystatus.c +++ b/commands/keystatus.c @@ -56,11 +56,11 @@ grub_cmd_keystatus (grub_extcmd_t cmd, int mods; if (state[0].set) - expect_mods |= GRUB_TERM_STATUS_SHIFT; + expect_mods |= (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT); if (state[1].set) - expect_mods |= GRUB_TERM_STATUS_CTRL; + expect_mods |= (GRUB_TERM_STATUS_LCTRL | GRUB_TERM_STATUS_RCTRL); if (state[2].set) - expect_mods |= GRUB_TERM_STATUS_ALT; + expect_mods |= (GRUB_TERM_STATUS_LALT | GRUB_TERM_STATUS_RALT); grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods); diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index 2d6e3d54c..6d4b620c2 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -21,28 +21,24 @@ #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) -#define GRUB_KEYBOARD_LAYOUTS_VERSION 4 +#define GRUB_KEYBOARD_LAYOUTS_VERSION 5 #define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 128 -struct grub_keyboard_layout +struct grub_keyboard_layout_kbd { - struct - { - grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t keyboard_map_shift[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t keyboard_map_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - } at; - struct - { - grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t keyboard_map_shift[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t keyboard_map_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - } usb; + grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; }; -struct grub_keyboard_layout *EXPORT_VAR (grub_current_layout); +struct grub_keyboard_layout +{ + struct grub_keyboard_layout_kbd at; + struct grub_keyboard_layout_kbd usb; +}; + +unsigned grub_term_map_key (int code, int status); #endif /* GRUB_KEYBOARD_LAYOUTS */ diff --git a/include/grub/term.h b/include/grub/term.h index 036e8caaa..de430d66f 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -110,9 +110,15 @@ grub_term_color_state; /* Bitmasks for modifier keys returned by grub_getkeystatus. */ -#define GRUB_TERM_STATUS_SHIFT (1 << 0) -#define GRUB_TERM_STATUS_CTRL (1 << 1) -#define GRUB_TERM_STATUS_ALT (1 << 2) +#define GRUB_TERM_STATUS_RSHIFT (1 << 0) +#define GRUB_TERM_STATUS_LSHIFT (1 << 1) +#define GRUB_TERM_STATUS_RCTRL (1 << 2) +#define GRUB_TERM_STATUS_RALT (1 << 3) +#define GRUB_TERM_STATUS_SCROLL (1 << 4) +#define GRUB_TERM_STATUS_NUM (1 << 5) +#define GRUB_TERM_STATUS_CAPS (1 << 6) +#define GRUB_TERM_STATUS_LCTRL (1 << 8) +#define GRUB_TERM_STATUS_LALT (1 << 9) /* Menu-related geometrical constants. */ diff --git a/kern/term.c b/kern/term.c index 04d20364a..6ddf63208 100644 --- a/kern/term.c +++ b/kern/term.c @@ -22,13 +22,11 @@ #include #include #include -#include struct grub_term_output *grub_term_outputs_disabled; struct grub_term_input *grub_term_inputs_disabled; struct grub_term_output *grub_term_outputs; struct grub_term_input *grub_term_inputs; -struct grub_keyboard_layout *grub_current_layout; /* Put a Unicode character. */ static void diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 492075115..054dc9805 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -22,64 +22,18 @@ #include #include #include +#include static short at_keyboard_status = 0; +static int extended_pending = 0; static int pending_key = -1; -#define KEYBOARD_STATUS_SHIFT_L (1 << 0) -#define KEYBOARD_STATUS_SHIFT_R (1 << 1) -#define KEYBOARD_STATUS_ALT_L (1 << 2) -#define KEYBOARD_STATUS_ALT_R (1 << 3) -#define KEYBOARD_STATUS_CTRL_L (1 << 4) -#define KEYBOARD_STATUS_CTRL_R (1 << 5) -#define KEYBOARD_STATUS_CAPS_LOCK (1 << 6) -#define KEYBOARD_STATUS_NUM_LOCK (1 << 7) -#define KEYBOARD_STATUS_EXTENDED (1 << 8) - static grub_uint8_t led_status; #define KEYBOARD_LED_SCROLL (1 << 0) #define KEYBOARD_LED_NUM (1 << 1) #define KEYBOARD_LED_CAPS (1 << 2) -static const unsigned keyboard_map[128] = -{ - /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', - /* 0x08 */ '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, - /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', - /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', - /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*', - /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, - /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, - /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, - /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, - /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, - /* 0x44 */ GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, - /* 0x48 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, - /* 0x4c */ GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, '+', GRUB_TERM_KEY_END, - /* 0x50 */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, - /* 0x52 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, - /* 0x54 */ '\0', '\0', '\\', GRUB_TERM_KEY_F11, - /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', - /* 0x60 */ '\0', '\0', '\0', '\0', - /* 0x64 */ '\0', GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_LEFT, - /* 0x68 */ GRUB_TERM_KEY_RIGHT -}; - -static unsigned keyboard_map_shift[128] = -{ - '\0', '\0', '!', '@', '#', '$', '%', '^', - '&', '*', '(', ')', '_', '+', '\0', '\0', - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', - 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', - '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?', - [0x56] = '|' -}; - static grub_uint8_t grub_keyboard_controller_orig; static void @@ -122,45 +76,41 @@ grub_keyboard_isr (grub_uint8_t key) switch (KEYBOARD_SCANCODE (key)) { case SHIFT_L: - at_keyboard_status |= KEYBOARD_STATUS_SHIFT_L; + at_keyboard_status |= GRUB_TERM_STATUS_LSHIFT; break; case SHIFT_R: - at_keyboard_status |= KEYBOARD_STATUS_SHIFT_R; + at_keyboard_status |= GRUB_TERM_STATUS_RSHIFT; break; case CTRL: - at_keyboard_status |= KEYBOARD_STATUS_CTRL_L; + at_keyboard_status |= GRUB_TERM_STATUS_LCTRL; break; case ALT: - if (at_keyboard_status & KEYBOARD_STATUS_EXTENDED) - at_keyboard_status |= KEYBOARD_STATUS_ALT_R; + if (extended_pending) + at_keyboard_status |= GRUB_TERM_STATUS_RALT; else - at_keyboard_status |= KEYBOARD_STATUS_ALT_L; + at_keyboard_status |= GRUB_TERM_STATUS_LALT; break; } else switch (KEYBOARD_SCANCODE (key)) { case SHIFT_L: - at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_L; + at_keyboard_status &= ~GRUB_TERM_STATUS_LSHIFT; break; case SHIFT_R: - at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_R; + at_keyboard_status &= ~GRUB_TERM_STATUS_RSHIFT; break; case CTRL: - at_keyboard_status &= ~KEYBOARD_STATUS_CTRL_L; + at_keyboard_status &= ~GRUB_TERM_STATUS_LCTRL; break; case ALT: - if (at_keyboard_status & KEYBOARD_STATUS_EXTENDED) - at_keyboard_status &= ~KEYBOARD_STATUS_ALT_R; + if (extended_pending) + at_keyboard_status &= ~GRUB_TERM_STATUS_RALT; else - at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L; + at_keyboard_status &= ~GRUB_TERM_STATUS_LALT; break; } - if (key == 0xe0) - at_keyboard_status |= KEYBOARD_STATUS_EXTENDED; - else - at_keyboard_status &= ~KEYBOARD_STATUS_EXTENDED; - + extended_pending = (key == 0xe0); } /* If there is a raw key pending, return it; otherwise return -1. */ @@ -177,11 +127,12 @@ grub_keyboard_getkey (void) return (KEYBOARD_SCANCODE (key)); } + /* If there is a character pending, return it; otherwise return -1. */ static int grub_at_keyboard_getkey_noblock (void) { - int code, key; + int code; code = grub_keyboard_getkey (); if (code == -1) return -1; @@ -194,66 +145,34 @@ grub_at_keyboard_getkey_noblock (void) /* Caps lock sends scan code twice. Get the second one and discard it. */ while (grub_keyboard_getkey () == -1); - at_keyboard_status ^= KEYBOARD_STATUS_CAPS_LOCK; + at_keyboard_status ^= GRUB_TERM_STATUS_CAPS; led_status ^= KEYBOARD_LED_CAPS; keyboard_controller_led (led_status); #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK)); #endif - key = -1; - break; + return -1; case NUM_LOCK: /* Num lock sends scan code twice. Get the second one and discard it. */ while (grub_keyboard_getkey () == -1); - at_keyboard_status ^= KEYBOARD_STATUS_NUM_LOCK; + at_keyboard_status ^= GRUB_TERM_STATUS_NUM; led_status ^= KEYBOARD_LED_NUM; keyboard_controller_led (led_status); #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_NUM_LOCK)); #endif - key = -1; - break; + return -1; case SCROLL_LOCK: - /* For scroll lock we don't keep track of status. Only update its led. */ + at_keyboard_status ^= GRUB_TERM_STATUS_SCROLL; led_status ^= KEYBOARD_LED_SCROLL; keyboard_controller_led (led_status); - key = -1; - break; + return -1; default: - if (at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L - | KEYBOARD_STATUS_SHIFT_R)) - { - if (keyboard_map_shift[code]) - key = keyboard_map_shift[code]; - else - key = keyboard_map[code] | GRUB_TERM_SHIFT; - } - else - key = keyboard_map[code]; - - if (key == 0) - grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code); - - if (at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK) - { - if ((key >= 'a') && (key <= 'z')) - key += 'A' - 'a'; - else if ((key >= 'A') && (key <= 'Z')) - key += 'a' - 'A'; - } - - if (at_keyboard_status & KEYBOARD_STATUS_ALT_L) - key |= GRUB_TERM_ALT; - if (at_keyboard_status & KEYBOARD_STATUS_ALT_R) - key |= GRUB_TERM_ALT; - if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L - | KEYBOARD_STATUS_CTRL_R)) - key |= GRUB_TERM_CTRL; + return grub_term_map_key (code, at_keyboard_status); } - return key; } static int diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index 74df4c27f..009647c4c 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -24,25 +24,11 @@ static const struct grub_machine_bios_data_area *bios_data_area = (struct grub_machine_bios_data_area *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR; -#define KEYBOARD_LEFT_SHIFT (1 << 0) -#define KEYBOARD_RIGHT_SHIFT (1 << 1) -#define KEYBOARD_CTRL (1 << 2) -#define KEYBOARD_ALT (1 << 3) - static int grub_console_getkeystatus (struct grub_term_input *term __attribute__ ((unused))) { - grub_uint8_t status = bios_data_area->keyboard_flag_lower; - int mods = 0; - - if (status & (KEYBOARD_LEFT_SHIFT | KEYBOARD_RIGHT_SHIFT)) - mods |= GRUB_TERM_STATUS_SHIFT; - if (status & KEYBOARD_CTRL) - mods |= GRUB_TERM_STATUS_CTRL; - if (status & KEYBOARD_ALT) - mods |= GRUB_TERM_STATUS_ALT; - - return mods; + /* conveniently GRUB keystatus is modelled after BIOS one. */ + return bios_data_area->keyboard_flag_lower & ~0x80; } static struct grub_term_input grub_console_term_input = diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 3432f700c..f35cc4b65 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -163,7 +163,7 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused) /* Check if the Shift key was pressed. */ if (data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT - || data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) + || data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) { if (keyboard_map_shift[data[2]]) key = keyboard_map_shift[data[2]]; @@ -323,12 +323,18 @@ grub_usb_keyboard_getkeystatus (struct grub_term_input *term __attribute__ ((unu data[4], data[5], data[6], data[7]); /* Check Shift, Control, and Alt status. */ - if (data[0] & 0x02 || data[0] & 0x20) - mods |= GRUB_TERM_STATUS_SHIFT; - if (data[0] & 0x01 || data[0] & 0x10) - mods |= GRUB_TERM_STATUS_CTRL; - if (data[0] & 0x04 || data[0] & 0x40) - mods |= GRUB_TERM_STATUS_ALT; + if (data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT) + mods |= GRUB_TERM_STATUS_LSHIFT; + if (data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) + mods |= GRUB_TERM_STATUS_RSHIFT; + if (data[0] & GRUB_USB_KEYBOARD_LEFT_CTRL) + mods |= GRUB_TERM_STATUS_LCTRL; + if (data[0] & GRUB_USB_KEYBOARD_RIGHT_CTRL) + mods |= GRUB_TERM_STATUS_RCTRL; + if (data[0] & GRUB_USB_KEYBOARD_LEFT_ALT) + mods |= GRUB_TERM_STATUS_LALT; + if (data[0] & GRUB_USB_KEYBOARD_RIGHT_ALT) + mods |= GRUB_TERM_STATUS_RALT; grub_errno = GRUB_ERR_NONE; diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index 9aca88cb1..43aa745a5 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -46,6 +46,26 @@ struct console_grub_equivalence grub_uint32_t grub; }; +static int at_to_usb_map[128] = +{ + 0, 41, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 45, 46, 42, 43, + 20, 26, 8, 21, 23, 28, 24, 12, + 18, 19, 47, 48, 40, 0, 4, 22, + 7, 9, 10, 11, 13, 14, 15, 51, + 52, 53, 0, 49, 29, 27, 6, 25, + 5, 17, 16, 54, 55, 56, 0, 0, + 0, 44, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 74, + 82, 78, 45, 80, 0, 79, 0, 77, + 81, 75, 0, 76, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + static struct console_grub_equivalence console_grub_equivalences[] = { {"KP_1", '1'}, {"KP_2", '2'}, @@ -85,7 +105,26 @@ Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); exit (status); } -char +void +add_special_keys (struct grub_keyboard_layout *layout) +{ + layout->at.keyboard_map[71] = GRUB_TERM_KEY_HOME; + layout->at.keyboard_map[72] = GRUB_TERM_KEY_UP; + layout->at.keyboard_map[73] = GRUB_TERM_KEY_NPAGE; + layout->at.keyboard_map[75] = GRUB_TERM_KEY_LEFT; + layout->at.keyboard_map[77] = GRUB_TERM_KEY_RIGHT; + layout->at.keyboard_map[79] = GRUB_TERM_KEY_END; + layout->at.keyboard_map[80] = GRUB_TERM_KEY_DOWN; + layout->at.keyboard_map[81] = GRUB_TERM_KEY_PPAGE; + layout->at.keyboard_map[83] = GRUB_TERM_KEY_DC; + + layout->at.keyboard_map[101] = GRUB_TERM_KEY_UP; + layout->at.keyboard_map[102] = GRUB_TERM_KEY_DOWN; + layout->at.keyboard_map[103] = GRUB_TERM_KEY_LEFT; + layout->at.keyboard_map[104] = GRUB_TERM_KEY_RIGHT; +} + +static char lookup (char *code) { int i; @@ -97,7 +136,7 @@ lookup (char *code) return '\0'; } -unsigned int +static unsigned int get_grub_code (char *layout_code) { unsigned int code; @@ -111,9 +150,8 @@ get_grub_code (char *layout_code) return code; } -void -write_file (char* filename, grub_uint32_t *keyboard_map, - grub_uint32_t *keyboard_map_alt) +static void +write_file (char* filename, struct grub_keyboard_layout *layout) { FILE *fp_output; grub_uint32_t version; @@ -121,11 +159,35 @@ write_file (char* filename, grub_uint32_t *keyboard_map, version = grub_cpu_to_le32 (GRUB_KEYBOARD_LAYOUTS_VERSION); - for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) - keyboard_map[i] = grub_cpu_to_le32 (keyboard_map[i]); + for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map); i++) + layout->at.keyboard_map[i] = grub_cpu_to_le32(layout->at.keyboard_map[i]); - for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) - keyboard_map_alt[i] = grub_cpu_to_le32 (keyboard_map_alt[i]); + for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map_shift); i++) + layout->at.keyboard_map_shift[i] + = grub_cpu_to_le32(layout->at.keyboard_map_shift[i]); + + for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map_l3); i++) + layout->at.keyboard_map_l3[i] + = grub_cpu_to_le32(layout->at.keyboard_map_l3[i]); + + for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map_shift_l3); i++) + layout->at.keyboard_map_shift_l3[i] + = grub_cpu_to_le32(layout->at.keyboard_map_shift_l3[i]); + + for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map); i++) + layout->usb.keyboard_map[i] = grub_cpu_to_le32(layout->usb.keyboard_map[i]); + + for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map_shift); i++) + layout->usb.keyboard_map_shift[i] + = grub_cpu_to_le32(layout->usb.keyboard_map_shift[i]); + + for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map_l3); i++) + layout->usb.keyboard_map_l3[i] + = grub_cpu_to_le32(layout->usb.keyboard_map_l3[i]); + + for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map_shift_l3); i++) + layout->usb.keyboard_map_shift_l3[i] + = grub_cpu_to_le32(layout->usb.keyboard_map_shift_l3[i]); fp_output = fopen (filename, "w"); @@ -138,23 +200,19 @@ write_file (char* filename, grub_uint32_t *keyboard_map, fwrite (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, 1, GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, fp_output); fwrite (&version, sizeof (version), 1, fp_output); - fwrite (keyboard_map, sizeof (keyboard_map[0]), - GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE, fp_output); - fwrite (keyboard_map_alt, sizeof (keyboard_map_alt[0]), - GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE, fp_output); + fwrite (layout, 1, sizeof (*layout), fp_output); fclose (fp_output); } -void +static void write_keymaps (char *keymap, char *file_basename) { - grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - grub_uint32_t keyboard_map_alt[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; - + struct grub_keyboard_layout layout; char line[2048]; pid_t pid; int pipe_communication[2]; int ok; + unsigned i; FILE *fp_pipe; @@ -182,7 +240,7 @@ write_keymaps (char *keymap, char *file_basename) close (pipe_communication[1]); fp_pipe = fdopen (pipe_communication[0], "r"); - memset (keyboard_map, 0, sizeof (keyboard_map)); + memset (&layout, 0, sizeof (layout)); /* Process the ckbcomp output and prepare the layouts. */ ok = 0; @@ -198,9 +256,30 @@ write_keymaps (char *keymap, char *file_basename) sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode, normal, shift, normalalt, shiftalt); + if (keycode < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) + { + layout.at.keyboard_map[keycode] = get_grub_code (normal); + layout.at.keyboard_map_shift[keycode] = get_grub_code (shift); + layout.at.keyboard_map_l3[keycode] = get_grub_code (normalalt); + layout.at.keyboard_map_shift_l3[keycode] + = get_grub_code (shiftalt); + ok = 1; + } } } + for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) + { + layout.usb.keyboard_map[at_to_usb_map[i]] = layout.at.keyboard_map[i]; + layout.usb.keyboard_map_shift[at_to_usb_map[i]] + = layout.at.keyboard_map_shift[i]; + layout.usb.keyboard_map_l3[at_to_usb_map[i]] + = layout.at.keyboard_map_l3[i]; + layout.usb.keyboard_map_shift_l3[at_to_usb_map[i]] + = layout.at.keyboard_map_shift_l3[i]; + } + + if (ok == 0) { fprintf (stderr, "ERROR: no keycodes found. Check output of %s %s.\n", @@ -208,7 +287,9 @@ write_keymaps (char *keymap, char *file_basename) exit (1); } - write_file (file_basename, keyboard_map, keyboard_map_alt); + add_special_keys (&layout); + + write_file (file_basename, &layout); } int From 5ef4e08416445b1b4245b09bc80725d4aca45f82 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 15:32:43 +0200 Subject: [PATCH 14/64] add usb keymap support --- commands/keylayouts.c | 128 ++++++++++++--------------- include/grub/keyboard_layouts.h | 10 +-- term/usb_keyboard.c | 151 +++++++++++++++----------------- util/grub-mklayouts.c | 103 ++++++---------------- 4 files changed, 157 insertions(+), 235 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index b7aee7fab..df8b95e02 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -29,43 +29,40 @@ #include static struct grub_keyboard_layout layout_us = { - .at = { - .keyboard_map = { - /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', - /* 0x08 */ '7', '8', '9', '0', - /* 0x0c */ '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, - /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', - /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', - /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*', - /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, - /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, - /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, - /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, - /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, - /* 0x44 */ GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, - /* 0x48 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, - /* 0x4c */ GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, - /* 0x4e */ '+', GRUB_TERM_KEY_END, - /* 0x50 */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, - /* 0x52 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, - /* 0x54 */ '\0', '\0', '\\', GRUB_TERM_KEY_F11, - /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', - /* 0x60 */ '\0', '\0', '\0', '\0', - /* 0x64 */ '\0', GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_LEFT, - /* 0x68 */ GRUB_TERM_KEY_RIGHT - }, - .keyboard_map_shift = { - '\0', '\0', '!', '@', '#', '$', '%', '^', - '&', '*', '(', ')', '_', '+', '\0', '\0', - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', - 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', - '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?', - [0x56] = '|' - } + .keyboard_map = { + /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', + /* 0x08 */ '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, + /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', + /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', + /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*', + /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, + /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, + /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, + /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, + /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, + /* 0x44 */ GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, + /* 0x48 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, + /* 0x4c */ GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, + /* 0x4e */ '+', GRUB_TERM_KEY_END, + /* 0x50 */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, + /* 0x52 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, + /* 0x54 */ '\0', '\0', '\\', GRUB_TERM_KEY_F11, + /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', + /* 0x60 */ '\0', '\0', '\0', '\0', + /* 0x64 */ '\0', GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_LEFT, + /* 0x68 */ GRUB_TERM_KEY_RIGHT + }, + .keyboard_map_shift = { + '\0', '\0', '!', '@', '#', '$', '%', '^', + '&', '*', '(', ')', '_', '+', '\0', '\0', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', + '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', + [0x56] = '|' } }; @@ -80,33 +77,33 @@ map_key_core (int code, int status, int *alt_gr_consumed) { if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) { - if (grub_current_layout->at.keyboard_map_shift_l3[code]) + if (grub_current_layout->keyboard_map_shift_l3[code]) { *alt_gr_consumed = 1; - return grub_current_layout->at.keyboard_map_shift_l3[code]; + return grub_current_layout->keyboard_map_shift_l3[code]; } - else if (grub_current_layout->at.keyboard_map_shift[code]) + else if (grub_current_layout->keyboard_map_shift[code]) { *alt_gr_consumed = 1; - return grub_current_layout->at.keyboard_map_l3[code] + return grub_current_layout->keyboard_map_l3[code] | GRUB_TERM_SHIFT; } } - else if (grub_current_layout->at.keyboard_map_shift[code]) + else if (grub_current_layout->keyboard_map_shift[code]) { *alt_gr_consumed = 1; - return grub_current_layout->at.keyboard_map_l3[code]; + return grub_current_layout->keyboard_map_l3[code]; } } if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) { - if (grub_current_layout->at.keyboard_map_shift[code]) - return grub_current_layout->at.keyboard_map_shift[code]; + if (grub_current_layout->keyboard_map_shift[code]) + return grub_current_layout->keyboard_map_shift[code]; else - return grub_current_layout->at.keyboard_map[code] | GRUB_TERM_SHIFT; + return grub_current_layout->keyboard_map[code] | GRUB_TERM_SHIFT; } else - return grub_current_layout->at.keyboard_map[code]; + return grub_current_layout->keyboard_map[code]; } unsigned @@ -204,35 +201,20 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), goto fail; } - for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map); i++) - newmap->at.keyboard_map[i] = grub_le_to_cpu32(newmap->at.keyboard_map[i]); + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map); i++) + newmap->keyboard_map[i] = grub_le_to_cpu32(newmap->keyboard_map[i]); - for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map_shift); i++) - newmap->at.keyboard_map_shift[i] - = grub_le_to_cpu32(newmap->at.keyboard_map_shift[i]); + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift); i++) + newmap->keyboard_map_shift[i] + = grub_le_to_cpu32(newmap->keyboard_map_shift[i]); - for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map_l3); i++) - newmap->at.keyboard_map_l3[i] - = grub_le_to_cpu32(newmap->at.keyboard_map_l3[i]); + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_l3); i++) + newmap->keyboard_map_l3[i] + = grub_le_to_cpu32(newmap->keyboard_map_l3[i]); - for (i = 0; i < ARRAY_SIZE (newmap->at.keyboard_map_shift_l3); i++) - newmap->at.keyboard_map_shift_l3[i] - = grub_le_to_cpu32(newmap->at.keyboard_map_shift_l3[i]); - - for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map); i++) - newmap->usb.keyboard_map[i] = grub_le_to_cpu32(newmap->usb.keyboard_map[i]); - - for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map_shift); i++) - newmap->usb.keyboard_map_shift[i] - = grub_le_to_cpu32(newmap->usb.keyboard_map_shift[i]); - - for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map_l3); i++) - newmap->usb.keyboard_map_l3[i] - = grub_le_to_cpu32(newmap->usb.keyboard_map_l3[i]); - - for (i = 0; i < ARRAY_SIZE (newmap->usb.keyboard_map_shift_l3); i++) - newmap->usb.keyboard_map_shift_l3[i] - = grub_le_to_cpu32(newmap->usb.keyboard_map_shift_l3[i]); + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift_l3); i++) + newmap->keyboard_map_shift_l3[i] + = grub_le_to_cpu32(newmap->keyboard_map_shift_l3[i]); grub_current_layout = newmap; diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index 6d4b620c2..1920b8887 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -21,11 +21,11 @@ #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) -#define GRUB_KEYBOARD_LAYOUTS_VERSION 5 +#define GRUB_KEYBOARD_LAYOUTS_VERSION 6 #define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 128 -struct grub_keyboard_layout_kbd +struct grub_keyboard_layout { grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; grub_uint32_t keyboard_map_shift[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; @@ -33,12 +33,6 @@ struct grub_keyboard_layout_kbd grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; }; -struct grub_keyboard_layout -{ - struct grub_keyboard_layout_kbd at; - struct grub_keyboard_layout_kbd usb; -}; - unsigned grub_term_map_key (int code, int status); #endif /* GRUB_KEYBOARD_LAYOUTS */ diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index f35cc4b65..6f1e1a9e8 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -25,39 +25,45 @@ #include #include #include +#include -static unsigned keyboard_map[128] = - { - '\0', '\0', '\0', '\0', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', - '3', '4', '5', '6', '7', '8', '9', '0', - '\n', GRUB_TERM_ESC, GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, ' ', '-', '=', '[', - ']', '\\', '#', ';', '\'', '`', ',', '.', - '/', '\0', GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, - GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6, - GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, GRUB_TERM_KEY_F10, - GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, '\0', '\0', - '\0', GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, - GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, - GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_UP, - [0x64] = '\\' - }; -static unsigned keyboard_map_shift[128] = - { - '\0', '\0', '\0', '\0', 'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', - '#', '$', '%', '^', '&', '*', '(', ')', - '\n', '\0', '\0', '\0', ' ', '_', '+', '{', - '}', '|', '#', ':', '"', '`', '<', '>', - '?', - [0x64] = '|' - }; +static grub_uint8_t usb_to_at_map[128] = +{ + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, + /* 0x04 */ 0x1e /* a */, 0x30 /* b */, 0x2e /* c */, 0x20 /* d */, + /* 0x08 */ 0x12 /* e */, 0x21 /* f */, 0x22 /* g */, 0x23 /* h */, + /* 0x0c */ 0x17 /* i */, 0x24 /* j */, 0x25 /* k */, 0x26 /* l */, + /* 0x10 */ 0x32 /* m */, 0x31 /* n */, 0x18 /* o */, 0x19 /* p */, + /* 0x14 */ 0x10 /* q */, 0x13 /* r */, 0x1f /* s */, 0x14 /* t */, + /* 0x18 */ 0x16 /* u */, 0x2f /* v */, 0x11 /* w */, 0x2d /* x */, + /* 0x1c */ 0x15 /* y */, 0x2c /* z */, 0x02 /* 1 */, 0x03 /* 2 */, + /* 0x20 */ 0x04 /* 3 */, 0x05 /* 4 */, 0x06 /* 5 */, 0x07 /* 6 */, + /* 0x24 */ 0x08 /* 7 */, 0x09 /* 8 */, 0x0a /* 9 */, 0x0b /* 0 */, + /* 0x28 */ 0x1c /* Enter */, 0x01 /* Escape */, 0x0e /* \b */, 0x0f /* \t */, + /* 0x2c */ 0x39 /* Space */, 0x4a /* - */, 0x0d /* = */, 0x1a /* [ */, + /* 0x30 */ 0x1b /* ] */, 0x2b /* \ */, 0x00, 0x27 /* ; */, + /* 0x34 */ 0x28 /* " */, 0x29 /* ` */, 0x33 /* , */, 0x34 /* . */, + /* 0x38 */ 0x35 /* / */, 0x00, 0x00, 0x00, + /* 0x3c */ 0x00, 0x00, 0x00, 0x00, + /* 0x40 */ 0x00, 0x00, 0x00, 0x00, + /* 0x44 */ 0x00, 0x00, 0x00, 0x00, + /* 0x48 */ 0x00, 0x00, 0x47 /* HOME */, 0x51 /* PPAGE */, + /* 0x4c */ 0x53 /* DC */, 0x4f /* END */, 0x49 /* NPAGE */, 0x4d /* RIGHT */, + /* 0x50 */ 0x4b /* LEFT */, 0x50 /* DOWN */, 0x48 /* UP */, 0x00, + /* 0x54 */ 0x00, 0x00, 0x00, 0x00, + /* 0x58 */ 0x00, 0x00, 0x00, 0x00, + /* 0x5c */ 0x00, 0x00, 0x00, 0x00, + /* 0x60 */ 0x00, 0x00, 0x00, 0x00, + /* 0x64 */ 0x56 /* 102nd key. */, 0x00, 0x00, 0x00, + /* 0x68 */ 0x00, 0x00, 0x00, 0x00, + /* 0x6c */ 0x00, 0x00, 0x00, 0x00, + /* 0x70 */ 0x00, 0x00, 0x00, 0x00, + /* 0x74 */ 0x00, 0x00, 0x00, 0x00, + /* 0x78 */ 0x00, 0x00, 0x00, 0x00, + /* 0x7c */ 0x00, 0x00, 0x00, 0x00, +}; static grub_usb_device_t usbdev; @@ -74,6 +80,35 @@ static grub_usb_device_t usbdev; #define USB_HID_SET_IDLE 0x0A #define USB_HID_SET_PROTOCOL 0x0B +#define GRUB_USB_KEYBOARD_LEFT_CTRL 0x01 +#define GRUB_USB_KEYBOARD_LEFT_SHIFT 0x02 +#define GRUB_USB_KEYBOARD_LEFT_ALT 0x04 +#define GRUB_USB_KEYBOARD_RIGHT_CTRL 0x10 +#define GRUB_USB_KEYBOARD_RIGHT_SHIFT 0x20 +#define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40 + +static int +interpret_status (grub_uint8_t data0) +{ + int mods = 0; + + /* Check Shift, Control, and Alt status. */ + if (data0 & GRUB_USB_KEYBOARD_LEFT_SHIFT) + mods |= GRUB_TERM_STATUS_LSHIFT; + if (data0 & GRUB_USB_KEYBOARD_RIGHT_SHIFT) + mods |= GRUB_TERM_STATUS_RSHIFT; + if (data0 & GRUB_USB_KEYBOARD_LEFT_CTRL) + mods |= GRUB_TERM_STATUS_LCTRL; + if (data0 & GRUB_USB_KEYBOARD_RIGHT_CTRL) + mods |= GRUB_TERM_STATUS_RCTRL; + if (data0 & GRUB_USB_KEYBOARD_LEFT_ALT) + mods |= GRUB_TERM_STATUS_LALT; + if (data0 & GRUB_USB_KEYBOARD_RIGHT_ALT) + mods |= GRUB_TERM_STATUS_RALT; + + return mods; +} + static void grub_usb_hid (void) { @@ -127,7 +162,7 @@ static int grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused))) { grub_uint8_t data[8]; - int key; + int key = 0; grub_err_t err; grub_uint64_t currtime; int timeout = 50; @@ -154,39 +189,14 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused) data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); -#define GRUB_USB_KEYBOARD_LEFT_CTRL 0x01 -#define GRUB_USB_KEYBOARD_LEFT_SHIFT 0x02 -#define GRUB_USB_KEYBOARD_LEFT_ALT 0x04 -#define GRUB_USB_KEYBOARD_RIGHT_CTRL 0x10 -#define GRUB_USB_KEYBOARD_RIGHT_SHIFT 0x20 -#define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40 - - /* Check if the Shift key was pressed. */ - if (data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT - || data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) - { - if (keyboard_map_shift[data[2]]) - key = keyboard_map_shift[data[2]]; - else - key = keyboard_map[data[2]] | GRUB_TERM_SHIFT; - } - else - key = keyboard_map[data[2]]; - - if (key == 0) + if (usb_to_at_map[data[2]] == 0) grub_printf ("Unknown key 0x%x detected\n", data[2]); + else + key = grub_term_map_key (usb_to_at_map[data[2]], interpret_status (data[0])); - /* Check if the Ctrl key was pressed. */ - if (data[0] & GRUB_USB_KEYBOARD_LEFT_CTRL - || data[0] & GRUB_USB_KEYBOARD_RIGHT_CTRL) - key |= GRUB_TERM_CTRL; + grub_errno = GRUB_ERR_NONE; - /* Check if the Alt key was pressed. */ - if (data[0] & GRUB_USB_KEYBOARD_LEFT_ALT) - key |= GRUB_TERM_ALT; - - if (data[0] & GRUB_USB_KEYBOARD_RIGHT_ALT) - key |= GRUB_TERM_ALT; + return key; #if 0 /* Wait until the key is released. */ @@ -203,8 +213,6 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused) } #endif - grub_errno = GRUB_ERR_NONE; - return key; } @@ -284,7 +292,6 @@ static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term __attribute__ ((unused))) { grub_uint8_t data[8]; - int mods = 0; grub_err_t err; grub_uint64_t currtime; int timeout = 50; @@ -322,23 +329,9 @@ grub_usb_keyboard_getkeystatus (struct grub_term_input *term __attribute__ ((unu data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); - /* Check Shift, Control, and Alt status. */ - if (data[0] & GRUB_USB_KEYBOARD_LEFT_SHIFT) - mods |= GRUB_TERM_STATUS_LSHIFT; - if (data[0] & GRUB_USB_KEYBOARD_RIGHT_SHIFT) - mods |= GRUB_TERM_STATUS_RSHIFT; - if (data[0] & GRUB_USB_KEYBOARD_LEFT_CTRL) - mods |= GRUB_TERM_STATUS_LCTRL; - if (data[0] & GRUB_USB_KEYBOARD_RIGHT_CTRL) - mods |= GRUB_TERM_STATUS_RCTRL; - if (data[0] & GRUB_USB_KEYBOARD_LEFT_ALT) - mods |= GRUB_TERM_STATUS_LALT; - if (data[0] & GRUB_USB_KEYBOARD_RIGHT_ALT) - mods |= GRUB_TERM_STATUS_RALT; - grub_errno = GRUB_ERR_NONE; - return mods; + return interpret_status (data[0]); } static struct grub_term_input grub_usb_keyboard_term = diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index 43aa745a5..6a51a9a76 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -46,26 +46,6 @@ struct console_grub_equivalence grub_uint32_t grub; }; -static int at_to_usb_map[128] = -{ - 0, 41, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 45, 46, 42, 43, - 20, 26, 8, 21, 23, 28, 24, 12, - 18, 19, 47, 48, 40, 0, 4, 22, - 7, 9, 10, 11, 13, 14, 15, 51, - 52, 53, 0, 49, 29, 27, 6, 25, - 5, 17, 16, 54, 55, 56, 0, 0, - 0, 44, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 74, - 82, 78, 45, 80, 0, 79, 0, 77, - 81, 75, 0, 76, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - static struct console_grub_equivalence console_grub_equivalences[] = { {"KP_1", '1'}, {"KP_2", '2'}, @@ -108,20 +88,20 @@ Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); void add_special_keys (struct grub_keyboard_layout *layout) { - layout->at.keyboard_map[71] = GRUB_TERM_KEY_HOME; - layout->at.keyboard_map[72] = GRUB_TERM_KEY_UP; - layout->at.keyboard_map[73] = GRUB_TERM_KEY_NPAGE; - layout->at.keyboard_map[75] = GRUB_TERM_KEY_LEFT; - layout->at.keyboard_map[77] = GRUB_TERM_KEY_RIGHT; - layout->at.keyboard_map[79] = GRUB_TERM_KEY_END; - layout->at.keyboard_map[80] = GRUB_TERM_KEY_DOWN; - layout->at.keyboard_map[81] = GRUB_TERM_KEY_PPAGE; - layout->at.keyboard_map[83] = GRUB_TERM_KEY_DC; + layout->keyboard_map[71] = GRUB_TERM_KEY_HOME; + layout->keyboard_map[72] = GRUB_TERM_KEY_UP; + layout->keyboard_map[73] = GRUB_TERM_KEY_NPAGE; + layout->keyboard_map[75] = GRUB_TERM_KEY_LEFT; + layout->keyboard_map[77] = GRUB_TERM_KEY_RIGHT; + layout->keyboard_map[79] = GRUB_TERM_KEY_END; + layout->keyboard_map[80] = GRUB_TERM_KEY_DOWN; + layout->keyboard_map[81] = GRUB_TERM_KEY_PPAGE; + layout->keyboard_map[83] = GRUB_TERM_KEY_DC; - layout->at.keyboard_map[101] = GRUB_TERM_KEY_UP; - layout->at.keyboard_map[102] = GRUB_TERM_KEY_DOWN; - layout->at.keyboard_map[103] = GRUB_TERM_KEY_LEFT; - layout->at.keyboard_map[104] = GRUB_TERM_KEY_RIGHT; + layout->keyboard_map[101] = GRUB_TERM_KEY_UP; + layout->keyboard_map[102] = GRUB_TERM_KEY_DOWN; + layout->keyboard_map[103] = GRUB_TERM_KEY_LEFT; + layout->keyboard_map[104] = GRUB_TERM_KEY_RIGHT; } static char @@ -159,35 +139,20 @@ write_file (char* filename, struct grub_keyboard_layout *layout) version = grub_cpu_to_le32 (GRUB_KEYBOARD_LAYOUTS_VERSION); - for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map); i++) - layout->at.keyboard_map[i] = grub_cpu_to_le32(layout->at.keyboard_map[i]); + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map); i++) + layout->keyboard_map[i] = grub_cpu_to_le32(layout->keyboard_map[i]); - for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map_shift); i++) - layout->at.keyboard_map_shift[i] - = grub_cpu_to_le32(layout->at.keyboard_map_shift[i]); + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift); i++) + layout->keyboard_map_shift[i] + = grub_cpu_to_le32(layout->keyboard_map_shift[i]); - for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map_l3); i++) - layout->at.keyboard_map_l3[i] - = grub_cpu_to_le32(layout->at.keyboard_map_l3[i]); + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_l3); i++) + layout->keyboard_map_l3[i] + = grub_cpu_to_le32(layout->keyboard_map_l3[i]); - for (i = 0; i < ARRAY_SIZE (layout->at.keyboard_map_shift_l3); i++) - layout->at.keyboard_map_shift_l3[i] - = grub_cpu_to_le32(layout->at.keyboard_map_shift_l3[i]); - - for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map); i++) - layout->usb.keyboard_map[i] = grub_cpu_to_le32(layout->usb.keyboard_map[i]); - - for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map_shift); i++) - layout->usb.keyboard_map_shift[i] - = grub_cpu_to_le32(layout->usb.keyboard_map_shift[i]); - - for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map_l3); i++) - layout->usb.keyboard_map_l3[i] - = grub_cpu_to_le32(layout->usb.keyboard_map_l3[i]); - - for (i = 0; i < ARRAY_SIZE (layout->usb.keyboard_map_shift_l3); i++) - layout->usb.keyboard_map_shift_l3[i] - = grub_cpu_to_le32(layout->usb.keyboard_map_shift_l3[i]); + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift_l3); i++) + layout->keyboard_map_shift_l3[i] + = grub_cpu_to_le32(layout->keyboard_map_shift_l3[i]); fp_output = fopen (filename, "w"); @@ -258,28 +223,16 @@ write_keymaps (char *keymap, char *file_basename) normal, shift, normalalt, shiftalt); if (keycode < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) { - layout.at.keyboard_map[keycode] = get_grub_code (normal); - layout.at.keyboard_map_shift[keycode] = get_grub_code (shift); - layout.at.keyboard_map_l3[keycode] = get_grub_code (normalalt); - layout.at.keyboard_map_shift_l3[keycode] + layout.keyboard_map[keycode] = get_grub_code (normal); + layout.keyboard_map_shift[keycode] = get_grub_code (shift); + layout.keyboard_map_l3[keycode] = get_grub_code (normalalt); + layout.keyboard_map_shift_l3[keycode] = get_grub_code (shiftalt); ok = 1; } } } - for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) - { - layout.usb.keyboard_map[at_to_usb_map[i]] = layout.at.keyboard_map[i]; - layout.usb.keyboard_map_shift[at_to_usb_map[i]] - = layout.at.keyboard_map_shift[i]; - layout.usb.keyboard_map_l3[at_to_usb_map[i]] - = layout.at.keyboard_map_l3[i]; - layout.usb.keyboard_map_shift_l3[at_to_usb_map[i]] - = layout.at.keyboard_map_shift_l3[i]; - } - - if (ok == 0) { fprintf (stderr, "ERROR: no keycodes found. Check output of %s %s.\n", From b09634f02706eb412f9becf9d1d4084bcad97112 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 16:12:18 +0200 Subject: [PATCH 15/64] Added missing values and indented USB table --- term/usb_keyboard.c | 96 ++++++++++++++++++++++++++++--------------- util/grub-mklayouts.c | 4 ++ 2 files changed, 68 insertions(+), 32 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 6f1e1a9e8..ede71bb5f 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -31,38 +31,70 @@ static grub_uint8_t usb_to_at_map[128] = { - /* 0x00 */ 0x00, 0x00, 0x00, 0x00, - /* 0x04 */ 0x1e /* a */, 0x30 /* b */, 0x2e /* c */, 0x20 /* d */, - /* 0x08 */ 0x12 /* e */, 0x21 /* f */, 0x22 /* g */, 0x23 /* h */, - /* 0x0c */ 0x17 /* i */, 0x24 /* j */, 0x25 /* k */, 0x26 /* l */, - /* 0x10 */ 0x32 /* m */, 0x31 /* n */, 0x18 /* o */, 0x19 /* p */, - /* 0x14 */ 0x10 /* q */, 0x13 /* r */, 0x1f /* s */, 0x14 /* t */, - /* 0x18 */ 0x16 /* u */, 0x2f /* v */, 0x11 /* w */, 0x2d /* x */, - /* 0x1c */ 0x15 /* y */, 0x2c /* z */, 0x02 /* 1 */, 0x03 /* 2 */, - /* 0x20 */ 0x04 /* 3 */, 0x05 /* 4 */, 0x06 /* 5 */, 0x07 /* 6 */, - /* 0x24 */ 0x08 /* 7 */, 0x09 /* 8 */, 0x0a /* 9 */, 0x0b /* 0 */, - /* 0x28 */ 0x1c /* Enter */, 0x01 /* Escape */, 0x0e /* \b */, 0x0f /* \t */, - /* 0x2c */ 0x39 /* Space */, 0x4a /* - */, 0x0d /* = */, 0x1a /* [ */, - /* 0x30 */ 0x1b /* ] */, 0x2b /* \ */, 0x00, 0x27 /* ; */, - /* 0x34 */ 0x28 /* " */, 0x29 /* ` */, 0x33 /* , */, 0x34 /* . */, - /* 0x38 */ 0x35 /* / */, 0x00, 0x00, 0x00, - /* 0x3c */ 0x00, 0x00, 0x00, 0x00, - /* 0x40 */ 0x00, 0x00, 0x00, 0x00, - /* 0x44 */ 0x00, 0x00, 0x00, 0x00, - /* 0x48 */ 0x00, 0x00, 0x47 /* HOME */, 0x51 /* PPAGE */, - /* 0x4c */ 0x53 /* DC */, 0x4f /* END */, 0x49 /* NPAGE */, 0x4d /* RIGHT */, - /* 0x50 */ 0x4b /* LEFT */, 0x50 /* DOWN */, 0x48 /* UP */, 0x00, - /* 0x54 */ 0x00, 0x00, 0x00, 0x00, - /* 0x58 */ 0x00, 0x00, 0x00, 0x00, - /* 0x5c */ 0x00, 0x00, 0x00, 0x00, - /* 0x60 */ 0x00, 0x00, 0x00, 0x00, - /* 0x64 */ 0x56 /* 102nd key. */, 0x00, 0x00, 0x00, - /* 0x68 */ 0x00, 0x00, 0x00, 0x00, - /* 0x6c */ 0x00, 0x00, 0x00, 0x00, - /* 0x70 */ 0x00, 0x00, 0x00, 0x00, - /* 0x74 */ 0x00, 0x00, 0x00, 0x00, - /* 0x78 */ 0x00, 0x00, 0x00, 0x00, - /* 0x7c */ 0x00, 0x00, 0x00, 0x00, + /* 0x00 */ 0x00, 0x00, + /* 0x02 */ 0x00, 0x00, + /* 0x04 */ 0x1e /* a */, 0x30 /* b */, + /* 0x06 */ 0x2e /* c */, 0x20 /* d */, + /* 0x08 */ 0x12 /* e */, 0x21 /* f */, + /* 0x0a */ 0x22 /* g */, 0x23 /* h */, + /* 0x0c */ 0x17 /* i */, 0x24 /* j */, + /* 0x0e */ 0x25 /* k */, 0x26 /* l */, + /* 0x10 */ 0x32 /* m */, 0x31 /* n */, + /* 0x12 */ 0x18 /* o */, 0x19 /* p */, + /* 0x14 */ 0x10 /* q */, 0x13 /* r */, + /* 0x16 */ 0x1f /* s */, 0x14 /* t */, + /* 0x18 */ 0x16 /* u */, 0x2f /* v */, + /* 0x1a */ 0x11 /* w */, 0x2d /* x */, + /* 0x1c */ 0x15 /* y */, 0x2c /* z */, + /* 0x1e */ 0x02 /* 1 */, 0x03 /* 2 */, + /* 0x20 */ 0x04 /* 3 */, 0x05 /* 4 */, + /* 0x22 */ 0x06 /* 5 */, 0x07 /* 6 */, + /* 0x24 */ 0x08 /* 7 */, 0x09 /* 8 */, + /* 0x26 */ 0x0a /* 9 */, 0x0b /* 0 */, + /* 0x28 */ 0x1c /* Enter */, 0x01 /* Escape */, + /* 0x2a */ 0x0e /* \b */, 0x0f /* \t */, + /* 0x2c */ 0x39 /* Space */, 0x0c /* - */, + /* 0x2e */ 0x0d /* = */, 0x1a /* [ */, + /* 0x30 */ 0x1b /* ] */, 0x2b /* \ */, + /* 0x32 */ 0x00, 0x27 /* ; */, + /* 0x34 */ 0x28 /* " */, 0x29 /* ` */, + /* 0x36 */ 0x33 /* , */, 0x34 /* . */, + /* 0x38 */ 0x35 /* / */, 0x00, + /* 0x3a */ 0x3b /* F1 */, 0x3c /* F2 */, + /* 0x3c */ 0x3d /* F3 */, 0x3e /* F4 */, + /* 0x3e */ 0x3f /* F5 */, 0x40 /* F6 */, + /* 0x40 */ 0x41 /* F7 */, 0x42 /* F8 */, + /* 0x42 */ 0x43 /* F9 */, 0x44 /* F10 */, + /* 0x44 */ 0x57 /* F11 */, 0x58 /* F12 */, + /* 0x46 */ 0x00, 0x00, + /* 0x48 */ 0x00, 0x00, + /* 0x4a */ 0x47 /* HOME */, 0x51 /* PPAGE */, + /* 0x4c */ 0x53 /* DC */, 0x4f /* END */, + /* 0x4e */ 0x49 /* NPAGE */, 0x4d /* RIGHT */, + /* 0x50 */ 0x4b /* LEFT */, 0x50 /* DOWN */, + /* 0x52 */ 0x48 /* UP */, 0x00, + /* 0x54 */ 0x00, 0x00, + /* 0x56 */ 0x00, 0x00, + /* 0x58 */ 0x00, 0x00, + /* 0x5a */ 0x00, 0x00, + /* 0x5c */ 0x00, 0x00, + /* 0x5e */ 0x00, 0x00, + /* 0x60 */ 0x00, 0x00, + /* 0x62 */ 0x00, 0x00, + /* 0x64 */ 0x56 /* 102nd key. */, 0x00, + /* 0x66 */ 0x00, 0x00, + /* 0x68 */ 0x00, 0x00, + /* 0x6a */ 0x00, 0x00, + /* 0x6c */ 0x00, 0x00, + /* 0x6e */ 0x00, 0x00, + /* 0x70 */ 0x00, 0x00, + /* 0x72 */ 0x00, 0x00, + /* 0x74 */ 0x00, 0x00, + /* 0x76 */ 0x00, 0x00, + /* 0x78 */ 0x00, 0x00, + /* 0x7a */ 0x00, 0x00, + /* 0x7c */ 0x00, 0x00, + /* 0x7e */ 0x00, 0x00, }; static grub_usb_device_t usbdev; diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index 6a51a9a76..dde2383e2 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -47,6 +47,10 @@ struct console_grub_equivalence }; static struct console_grub_equivalence console_grub_equivalences[] = { + {"Escape", GRUB_TERM_ESC}, + {"Tab", GRUB_TERM_TAB}, + {"Delete", GRUB_TERM_BACKSPACE}, + {"KP_1", '1'}, {"KP_2", '2'}, {"KP_3", '3'}, From b17520411991170f09751a50093760dc8dbf4d31 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 19:17:36 +0200 Subject: [PATCH 16/64] Add missing keys to grub-mklayouts --- util/grub-mklayouts.c | 174 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 143 insertions(+), 31 deletions(-) diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index dde2383e2..49ad6be97 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -51,24 +51,136 @@ static struct console_grub_equivalence console_grub_equivalences[] = { {"Tab", GRUB_TERM_TAB}, {"Delete", GRUB_TERM_BACKSPACE}, - {"KP_1", '1'}, - {"KP_2", '2'}, - {"KP_3", '3'}, - {"KP_4", '4'}, - {"KP_5", '5'}, - {"KP_6", '6'}, - {"KP_7", '7'}, - {"KP_8", '8'}, - {"KP_9", '9'}, - {"KP_Multiply", '*'}, - {"KP_Substract", '-'}, + {"KP_Subtract", '-'}, {"KP_Add", '+'}, {"KP_Divide", '/'}, {"KP_Enter", '\n'}, {"Return", '\n'}, - {"", '\0'} + + {"F1", GRUB_TERM_KEY_F1}, + {"F2", GRUB_TERM_KEY_F2}, + {"F3", GRUB_TERM_KEY_F3}, + {"F4", GRUB_TERM_KEY_F4}, + {"F5", GRUB_TERM_KEY_F5}, + {"F6", GRUB_TERM_KEY_F6}, + {"F7", GRUB_TERM_KEY_F7}, + {"F8", GRUB_TERM_KEY_F8}, + {"F9", GRUB_TERM_KEY_F9}, + {"F10", GRUB_TERM_KEY_F10}, + {"F11", GRUB_TERM_KEY_F11}, + {"F12", GRUB_TERM_KEY_F12}, + {"F13", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT}, + {"F14", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT}, + {"F15", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT}, + {"F16", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT}, + {"F17", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT}, + {"F18", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT}, + {"F19", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT}, + {"F20", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT}, + {"F21", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT}, + {"F22", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT}, + {"F23", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT}, + {"F24", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT}, + {"Console_13", GRUB_TERM_KEY_F1 | GRUB_TERM_ALT}, + {"Console_14", GRUB_TERM_KEY_F2 | GRUB_TERM_ALT}, + {"Console_15", GRUB_TERM_KEY_F3 | GRUB_TERM_ALT}, + {"Console_16", GRUB_TERM_KEY_F4 | GRUB_TERM_ALT}, + {"Console_17", GRUB_TERM_KEY_F5 | GRUB_TERM_ALT}, + {"Console_18", GRUB_TERM_KEY_F6 | GRUB_TERM_ALT}, + {"Console_19", GRUB_TERM_KEY_F7 | GRUB_TERM_ALT}, + {"Console_20", GRUB_TERM_KEY_F8 | GRUB_TERM_ALT}, + {"Console_21", GRUB_TERM_KEY_F9 | GRUB_TERM_ALT}, + {"Console_22", GRUB_TERM_KEY_F10 | GRUB_TERM_ALT}, + {"Console_23", GRUB_TERM_KEY_F11 | GRUB_TERM_ALT}, + {"Console_24", GRUB_TERM_KEY_F12 | GRUB_TERM_ALT}, + {"Console_25", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_26", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_27", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_28", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_29", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_30", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_31", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_32", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_33", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_34", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_35", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_36", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + + {"Insert", GRUB_TERM_KEY_INSERT}, + {"Down", GRUB_TERM_KEY_DOWN}, + {"Up", GRUB_TERM_KEY_UP}, + {"Home", GRUB_TERM_KEY_HOME}, + {"End", GRUB_TERM_KEY_END}, + {"Right", GRUB_TERM_KEY_RIGHT}, + {"Left", GRUB_TERM_KEY_LEFT}, + {"VoidSymbol", 0}, + + /* "Undead" keys since no dead key support in GRUB. */ + {"dead_acute", '\''}, + {"dead_circumflex", '^'}, + {"dead_grave", '`'}, + {"dead_tilde", '~'}, + {"dead_diaeresis", '"'}, + + /* Following ones don't provide any useful symbols for shell. */ + {"dead_cedilla", 0}, + {"dead_ogonek", 0}, + {"dead_caron", 0}, + {"dead_breve", 0}, + {"dead_doubleacute", 0}, + + /* NumLock not supported yet. */ + {"KP_0", GRUB_TERM_KEY_INSERT}, + {"KP_1", GRUB_TERM_KEY_END}, + {"KP_2", GRUB_TERM_KEY_DOWN}, + {"KP_3", GRUB_TERM_KEY_NPAGE}, + {"KP_4", GRUB_TERM_KEY_LEFT}, + {"KP_5", 0}, + {"KP_6", GRUB_TERM_KEY_RIGHT}, + {"KP_7", GRUB_TERM_KEY_HOME}, + {"KP_8", GRUB_TERM_KEY_UP}, + {"KP_9", GRUB_TERM_KEY_PPAGE}, + {"KP_Period", GRUB_TERM_KEY_DC}, + + /* Unused in GRUB. */ + {"Pause", 0}, + {"Remove", 0}, + {"Next", 0}, + {"Prior", 0}, + {"Scroll_Forward", 0}, + {"Scroll_Backward", 0}, + {"Hex_0", 0}, + {"Hex_1", 0}, + {"Hex_2", 0}, + {"Hex_3", 0}, + {"Hex_4", 0}, + {"Hex_5", 0}, + {"Hex_6", 0}, + {"Hex_7", 0}, + {"Hex_8", 0}, + {"Hex_9", 0}, + {"Hex_A", 0}, + {"Hex_B", 0}, + {"Hex_C", 0}, + {"Hex_D", 0}, + {"Hex_E", 0}, + {"Hex_F", 0}, + {"Scroll_Lock", 0}, + {"Show_Memory", 0}, + {"Show_Registers", 0}, + {"Control_backslash", 0}, + + /* Keys currently not remappable. */ + {"CtrlL_Lock", 0}, + {"Num_Lock", 0}, + {"Alt", 0}, + {"AltGr", 0}, + {"Control", 0}, + {"Shift", 0}, + + {NULL, '\0'} }; static void @@ -92,16 +204,7 @@ Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); void add_special_keys (struct grub_keyboard_layout *layout) { - layout->keyboard_map[71] = GRUB_TERM_KEY_HOME; - layout->keyboard_map[72] = GRUB_TERM_KEY_UP; - layout->keyboard_map[73] = GRUB_TERM_KEY_NPAGE; - layout->keyboard_map[75] = GRUB_TERM_KEY_LEFT; - layout->keyboard_map[77] = GRUB_TERM_KEY_RIGHT; - layout->keyboard_map[79] = GRUB_TERM_KEY_END; - layout->keyboard_map[80] = GRUB_TERM_KEY_DOWN; - layout->keyboard_map[81] = GRUB_TERM_KEY_PPAGE; - layout->keyboard_map[83] = GRUB_TERM_KEY_DC; - + /* OLPC keys. */ layout->keyboard_map[101] = GRUB_TERM_KEY_UP; layout->keyboard_map[102] = GRUB_TERM_KEY_DOWN; layout->keyboard_map[103] = GRUB_TERM_KEY_LEFT; @@ -113,10 +216,12 @@ lookup (char *code) { int i; - for (i = 0; console_grub_equivalences[i].grub != '\0'; i++) + for (i = 0; console_grub_equivalences[i].layout != NULL; i++) if (strcmp (code, console_grub_equivalences[i].layout) == 0) return console_grub_equivalences[i].grub; + printf ("Unknown key %s\n", code); + return '\0'; } @@ -174,14 +279,13 @@ write_file (char* filename, struct grub_keyboard_layout *layout) } static void -write_keymaps (char *keymap, char *file_basename) +write_keymaps (char *argv[], int argc, char *file_basename) { struct grub_keyboard_layout layout; char line[2048]; pid_t pid; int pipe_communication[2]; int ok; - unsigned i; FILE *fp_pipe; @@ -199,11 +303,19 @@ write_keymaps (char *keymap, char *file_basename) } else if (pid == 0) { + char **args; + int j; close (1); dup (pipe_communication[1]); close (pipe_communication[0]); - execlp (CKBCOMP, CKBCOMP, keymap, NULL); - grub_util_error ("%s %s cannot be executed", CKBCOMP, keymap); + args = xmalloc (sizeof (args[0]) * (argc + 2)); + args[0] = CKBCOMP; + for (j = 0; j < argc; j++) + args[j + 1] = argv[j]; + args[argc + 1] = NULL; + execvp (CKBCOMP, args); + grub_util_error ("%s cannot be executed", CKBCOMP); + free (args); exit (3); } close (pipe_communication[1]); @@ -239,8 +351,8 @@ write_keymaps (char *keymap, char *file_basename) if (ok == 0) { - fprintf (stderr, "ERROR: no keycodes found. Check output of %s %s.\n", - CKBCOMP, keymap); + fprintf (stderr, "ERROR: no keycodes found. Check output of %s.\n", + CKBCOMP); exit (1); } @@ -302,11 +414,11 @@ main (int argc, char *argv[]) if (file_basename == NULL) { file_basename = xasprintf ("%s.gkb", argv[optind]); - write_keymaps (argv[optind], file_basename); + write_keymaps (argv + optind, argc - optind, file_basename); free (file_basename); } else - write_keymaps (argv[optind], file_basename); + write_keymaps (argv + optind, argc - optind, file_basename); return 0; } From 5a3e99b388eaecaaa615300b5eb738fcdd780f7e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 20:43:40 +0200 Subject: [PATCH 17/64] MAke grub-mklayouts do only one thing rather than doing all the piping --- util/grub-mklayouts.c | 109 ++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 68 deletions(-) diff --git a/util/grub-mklayouts.c b/util/grub-mklayouts.c index 49ad6be97..8fdee8590 100644 --- a/util/grub-mklayouts.c +++ b/util/grub-mklayouts.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "progname.h" @@ -240,9 +241,8 @@ get_grub_code (char *layout_code) } static void -write_file (char* filename, struct grub_keyboard_layout *layout) +write_file (FILE *out, struct grub_keyboard_layout *layout) { - FILE *fp_output; grub_uint32_t version; unsigned i; @@ -263,69 +263,24 @@ write_file (char* filename, struct grub_keyboard_layout *layout) layout->keyboard_map_shift_l3[i] = grub_cpu_to_le32(layout->keyboard_map_shift_l3[i]); - fp_output = fopen (filename, "w"); - - if (!fp_output) - { - grub_util_error ("cannot open `%s'", filename); - exit (1); - } - fwrite (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, 1, - GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, fp_output); - fwrite (&version, sizeof (version), 1, fp_output); - fwrite (layout, 1, sizeof (*layout), fp_output); - fclose (fp_output); + GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, out); + fwrite (&version, sizeof (version), 1, out); + fwrite (layout, 1, sizeof (*layout), out); } static void -write_keymaps (char *argv[], int argc, char *file_basename) +write_keymaps (FILE *in, FILE *out) { struct grub_keyboard_layout layout; char line[2048]; - pid_t pid; - int pipe_communication[2]; int ok; - FILE *fp_pipe; - - if (pipe (pipe_communication) == -1) - { - grub_util_error ("cannot prepare the pipe"); - exit (2); - } - - pid = fork (); - if (pid < 0) - { - grub_util_error ("cannot fork"); - exit (2); - } - else if (pid == 0) - { - char **args; - int j; - close (1); - dup (pipe_communication[1]); - close (pipe_communication[0]); - args = xmalloc (sizeof (args[0]) * (argc + 2)); - args[0] = CKBCOMP; - for (j = 0; j < argc; j++) - args[j + 1] = argv[j]; - args[argc + 1] = NULL; - execvp (CKBCOMP, args); - grub_util_error ("%s cannot be executed", CKBCOMP); - free (args); - exit (3); - } - close (pipe_communication[1]); - fp_pipe = fdopen (pipe_communication[0], "r"); - memset (&layout, 0, sizeof (layout)); /* Process the ckbcomp output and prepare the layouts. */ ok = 0; - while (fgets (line, sizeof (line), fp_pipe)) + while (fgets (line, sizeof (line), in)) { if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0) { @@ -358,14 +313,16 @@ write_keymaps (char *argv[], int argc, char *file_basename) add_special_keys (&layout); - write_file (file_basename, &layout); + write_file (out, &layout); } int main (int argc, char *argv[]) { int verbosity; - char *file_basename = NULL; + char *infile_name = NULL; + char *outfile_name = NULL; + FILE *in, *out; set_program_name (argv[0]); @@ -374,7 +331,7 @@ main (int argc, char *argv[]) /* Check for options. */ while (1) { - int c = getopt_long (argc, argv, "o:hVv", options, 0); + int c = getopt_long (argc, argv, "o:i:hVv", options, 0); if (c == -1) break; @@ -385,8 +342,12 @@ main (int argc, char *argv[]) usage (0); break; + case 'i': + infile_name = optarg; + break; + case 'o': - file_basename = optarg; + outfile_name = optarg; break; case 'V': @@ -404,21 +365,33 @@ main (int argc, char *argv[]) } } - /* Obtain LAYOUT. */ - if (optind >= argc) + if (infile_name) + in = fopen (infile_name, "r"); + else + in = stdin; + + if (!in) + grub_util_error ("Couldn't open input file: %s\n", strerror (errno)); + + if (outfile_name) + out = fopen (outfile_name, "r"); + else + out = stdout; + + if (!out) { - fprintf (stderr, "No layout is specified.\n"); - usage (1); + if (in != stdin) + fclose (in); + grub_util_error ("Couldn't open input file: %s\n", strerror (errno)); } - if (file_basename == NULL) - { - file_basename = xasprintf ("%s.gkb", argv[optind]); - write_keymaps (argv + optind, argc - optind, file_basename); - free (file_basename); - } - else - write_keymaps (argv + optind, argc - optind, file_basename); + write_keymaps (in, out); + + if (in != stdin) + fclose (in); + + if (out != stdout) + fclose (out); return 0; } From 9c9ec877cb6ab2d39b7f57525cb31b4acb47e5cb Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 20:47:08 +0200 Subject: [PATCH 18/64] Rename grub-mklayouts to grub-mklayout --- conf/common.rmk | 6 +++--- util/{grub-mklayouts.c => grub-mklayout.c} | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename util/{grub-mklayouts.c => grub-mklayout.c} (100%) diff --git a/conf/common.rmk b/conf/common.rmk index 745b1837e..82edc0aa0 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -80,9 +80,9 @@ endif bin_UTILITIES += grub-mkrelpath grub_mkrelpath_SOURCES = gnulib/progname.c util/grub-mkrelpath.c util/misc.c kern/emu/misc.c -# For grub-mklayouts. -bin_UTILITIES += grub-mklayouts -grub_mklayouts_SOURCES = gnulib/progname.c util/grub-mklayouts.c util/misc.c kern/emu/misc.c +# For grub-mklayout. +bin_UTILITIES += grub-mklayout +grub_mklayout_SOURCES = gnulib/progname.c util/grub-mklayout.c util/misc.c kern/emu/misc.c bin_UTILITIES += grub-bin2h grub_bin2h_SOURCES = gnulib/progname.c util/bin2h.c diff --git a/util/grub-mklayouts.c b/util/grub-mklayout.c similarity index 100% rename from util/grub-mklayouts.c rename to util/grub-mklayout.c From 88e543b519d930457462d6931d2c9cb55ea94ba5 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Aug 2010 20:48:31 +0200 Subject: [PATCH 19/64] Add grub-kbdcomp --- conf/common.rmk | 7 +++++++ util/grub-kbdcomp.in | 6 ++++++ 2 files changed, 13 insertions(+) create mode 100644 util/grub-kbdcomp.in diff --git a/conf/common.rmk b/conf/common.rmk index 82edc0aa0..e21c693b0 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -180,6 +180,13 @@ CLEANFILES += grub-pe2elf grub_macho2img_SOURCES = util/grub-macho2img.c CLEANFILES += grub-macho2img +# For grub-kbdcomp +grub-kbdcomp: util/grub-kbdcomp.in config.status + ./config.status --file=$@:$< + chmod +x $@ +sbin_SCRIPTS += grub-kbdcomp +CLEANFILES += grub-kbdcomp + # For grub-mkconfig grub-mkconfig: util/grub-mkconfig.in config.status ./config.status --file=$@:$< diff --git a/util/grub-kbdcomp.in b/util/grub-kbdcomp.in new file mode 100644 index 000000000..87b24bcdf --- /dev/null +++ b/util/grub-kbdcomp.in @@ -0,0 +1,6 @@ +#!/bin/sh + +grub_mklayout=${bindir}/`echo grub-mklayout | sed ${transform}` + +ckbcomp "$@" | $grub_mklayout -o "$1".gkb + From 8bb7e81637ba2f457daf8ce4c137e9851ab10960 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Aug 2010 01:23:33 +0200 Subject: [PATCH 20/64] Fix printf bug --- util/grub-mklayout.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index 8fdee8590..210ad646a 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -172,9 +172,12 @@ static struct console_grub_equivalence console_grub_equivalences[] = { {"Show_Memory", 0}, {"Show_Registers", 0}, {"Control_backslash", 0}, + {"Compose", 0}, /* Keys currently not remappable. */ {"CtrlL_Lock", 0}, + {"Caps_Lock", 0}, + {"ShiftL", 0}, {"Num_Lock", 0}, {"Alt", 0}, {"AltGr", 0}, @@ -221,7 +224,7 @@ lookup (char *code) if (strcmp (code, console_grub_equivalences[i].layout) == 0) return console_grub_equivalences[i].grub; - printf ("Unknown key %s\n", code); + fprintf (stderr, "Unknown key %s\n", code); return '\0'; } @@ -374,7 +377,7 @@ main (int argc, char *argv[]) grub_util_error ("Couldn't open input file: %s\n", strerror (errno)); if (outfile_name) - out = fopen (outfile_name, "r"); + out = fopen (outfile_name, "wb"); else out = stdout; @@ -382,7 +385,7 @@ main (int argc, char *argv[]) { if (in != stdin) fclose (in); - grub_util_error ("Couldn't open input file: %s\n", strerror (errno)); + grub_util_error ("Couldn't open output file: %s\n", strerror (errno)); } write_keymaps (in, out); From 0b335a9797e188032ccca7fba48ed80fa10cc738 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 20 Aug 2010 23:33:41 +0200 Subject: [PATCH 21/64] Fix cutting bits by implicit conversion to char --- util/grub-mklayout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index 210ad646a..91dea87a6 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -215,7 +215,7 @@ add_special_keys (struct grub_keyboard_layout *layout) layout->keyboard_map[104] = GRUB_TERM_KEY_RIGHT; } -static char +static unsigned lookup (char *code) { int i; From d9a8a9736e2c9e66a6f989c2acb8071c257aa4e6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 00:05:39 +0200 Subject: [PATCH 22/64] Add missing insert and \ codes --- term/usb_keyboard.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index f5bd1d601..6b8891716 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -55,8 +55,10 @@ static grub_uint8_t usb_to_at_map[128] = /* 0x2a */ 0x0e /* \b */, 0x0f /* \t */, /* 0x2c */ 0x39 /* Space */, 0x0c /* - */, /* 0x2e */ 0x0d /* = */, 0x1a /* [ */, - /* 0x30 */ 0x1b /* ] */, 0x2b /* \ */, - /* 0x32 */ 0x00, 0x27 /* ; */, + /* According to usage table 0x31 should be remapped to 0x2b + but testing with real keyboard shows that 0x32 is remapped to 0x2b. */ + /* 0x30 */ 0x1b /* ] */, 0x00, + /* 0x32 */ 0x2b /* \ */, 0x27 /* ; */, /* 0x34 */ 0x28 /* " */, 0x29 /* ` */, /* 0x36 */ 0x33 /* , */, 0x34 /* . */, /* 0x38 */ 0x35 /* / */, 0x00, @@ -67,7 +69,7 @@ static grub_uint8_t usb_to_at_map[128] = /* 0x42 */ 0x43 /* F9 */, 0x44 /* F10 */, /* 0x44 */ 0x57 /* F11 */, 0x58 /* F12 */, /* 0x46 */ 0x00, 0x00, - /* 0x48 */ 0x00, 0x00, + /* 0x48 */ 0x00, 0x52 /* Insert */, /* 0x4a */ 0x47 /* HOME */, 0x51 /* PPAGE */, /* 0x4c */ 0x53 /* DC */, 0x4f /* END */, /* 0x4e */ 0x49 /* NPAGE */, 0x4d /* RIGHT */, From 735e864757e9dd158bacbf6a5c902442f65890f5 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 00:29:57 +0200 Subject: [PATCH 23/64] Implement CapsLock --- term/usb_keyboard.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 6b8891716..7b67c6e96 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -99,6 +99,8 @@ static grub_uint8_t usb_to_at_map[128] = /* 0x7e */ 0x00, 0x00, }; +#define CAPS_LOCK 0x39 +#define CAPS_LOCK_LED 0x02 /* Valid values for bRequest. See HID definition version 1.11 section 7.2. */ #define USB_HID_GET_REPORT 0x01 @@ -122,7 +124,9 @@ struct grub_usb_keyboard_data { grub_usb_device_t usbdev; grub_uint8_t status; + grub_uint16_t mods; int key; + int interfno; struct grub_usb_desc_endp *endp; }; @@ -237,6 +241,7 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) } data->usbdev = usbdev; + data->interfno = interfno; data->endp = endp; /* Place the device in boot mode. */ @@ -278,6 +283,8 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) } } + data->mods = 0; + grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]); return 1; @@ -285,6 +292,19 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) +static void +send_leds (struct grub_usb_keyboard_data *termdata) +{ + char report[1]; + report[0] = 0; + if (termdata->mods & GRUB_TERM_STATUS_CAPS) + report[0] |= CAPS_LOCK_LED; + grub_usb_control_msg (termdata->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, + USB_HID_SET_REPORT, 0x0200, termdata->interfno, + sizeof (report), (char *) report); + grub_errno = GRUB_ERR_NONE; +} + static int grub_usb_keyboard_checkkey (struct grub_term_input *term) { @@ -309,6 +329,13 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) if (actual < 3 || !data[2]) return -1; + if (data[2] == CAPS_LOCK) + { + termdata->mods ^= GRUB_TERM_STATUS_CAPS; + send_leds (termdata); + return -1; + } + grub_dprintf ("usb_keyboard", "report: 0x%02x 0x%02x 0x%02x 0x%02x" " 0x%02x 0x%02x 0x%02x 0x%02x\n", @@ -320,7 +347,8 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) else termdata->key = grub_term_map_key (usb_to_at_map[data[2]], - interpret_status (data[0])); + interpret_status (data[0]) + | termdata->mods); grub_errno = GRUB_ERR_NONE; @@ -348,7 +376,7 @@ grub_usb_keyboard_getkeystatus (struct grub_term_input *term) { struct grub_usb_keyboard_data *termdata = term->data; - return interpret_status (termdata->status); + return interpret_status (termdata->status) | termdata->mods; } struct grub_usb_attach_desc attach_hook = From d10d149667bd650414dcc4ce5ba055cbc4ed8d0f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 13:54:10 +0200 Subject: [PATCH 24/64] Return USB_ERR_INTERNAL instead of grub_errno when appropriate --- bus/usb/usbtrans.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bus/usb/usbtrans.c b/bus/usb/usbtrans.c index db2ec097a..4a2e112bf 100644 --- a/bus/usb/usbtrans.c +++ b/bus/usb/usbtrans.c @@ -209,7 +209,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, if (! transfer) { grub_dma_free (data_chunk); - return grub_errno; + return GRUB_USB_ERR_INTERNAL; } datablocks = ((size + max - 1) / max); @@ -229,7 +229,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, { grub_free (transfer); grub_dma_free (data_chunk); - return grub_errno; + return GRUB_USB_ERR_INTERNAL; } /* Set up all transfers. */ From 12cbb3ccd0876ef7731c10f22b0a426464cd064d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 13:55:06 +0200 Subject: [PATCH 25/64] Don't retire active transaction on a NAK --- bus/usb/uhci.c | 51 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c index 0bba24b54..d0416d7e2 100644 --- a/bus/usb/uhci.c +++ b/bus/usb/uhci.c @@ -519,32 +519,35 @@ grub_uhci_transfer (grub_usb_controller_t dev, grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status); - /* Check if the endpoint is stalled. */ - if (errtd->ctrl_status & (1 << 22)) - err = GRUB_USB_ERR_STALL; + if (!(errtd->ctrl_status & (1 << 23))) + { + /* Check if the endpoint is stalled. */ + if (errtd->ctrl_status & (1 << 22)) + err = GRUB_USB_ERR_STALL; - /* Check if an error related to the data buffer occurred. */ - if (errtd->ctrl_status & (1 << 21)) - err = GRUB_USB_ERR_DATA; + /* Check if an error related to the data buffer occurred. */ + if (errtd->ctrl_status & (1 << 21)) + err = GRUB_USB_ERR_DATA; - /* Check if a babble error occurred. */ - if (errtd->ctrl_status & (1 << 20)) - err = GRUB_USB_ERR_BABBLE; + /* Check if a babble error occurred. */ + if (errtd->ctrl_status & (1 << 20)) + err = GRUB_USB_ERR_BABBLE; - /* Check if a NAK occurred. */ - if (errtd->ctrl_status & (1 << 19)) - err = GRUB_USB_ERR_NAK; + /* Check if a NAK occurred. */ + if (errtd->ctrl_status & (1 << 19)) + err = GRUB_USB_ERR_NAK; - /* Check if a timeout occurred. */ - if (errtd->ctrl_status & (1 << 18)) - err = GRUB_USB_ERR_TIMEOUT; + /* Check if a timeout occurred. */ + if (errtd->ctrl_status & (1 << 18)) + err = GRUB_USB_ERR_TIMEOUT; - /* Check if a bitstuff error occurred. */ - if (errtd->ctrl_status & (1 << 17)) - err = GRUB_USB_ERR_BITSTUFF; + /* Check if a bitstuff error occurred. */ + if (errtd->ctrl_status & (1 << 17)) + err = GRUB_USB_ERR_BITSTUFF; - if (err) - goto fail; + if (err) + break; + } /* Fall through, no errors occurred, so the QH might be updated. */ @@ -554,17 +557,15 @@ grub_uhci_transfer (grub_usb_controller_t dev, { err = GRUB_USB_ERR_STALL; grub_dprintf ("uhci", "transaction timed out\n"); - goto fail; + break; } grub_cpu_idle (); } - grub_dprintf ("uhci", "transaction complete\n"); - - fail: - if (err != GRUB_USB_ERR_NONE) grub_dprintf ("uhci", "transaction failed\n"); + else + grub_dprintf ("uhci", "transaction complete\n"); /* Place the QH back in the free list and deallocate the associated TDs. */ From bcfa613bc4a54b5910489057231dc2fae1eacf01 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 13:56:55 +0200 Subject: [PATCH 26/64] correctly pass interfno and don't use GetReport --- term/usb_keyboard.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index d875ac00a..adb84fa94 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -167,11 +167,11 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) /* Place the device in boot mode. */ grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, - USB_HID_SET_PROTOCOL, 0, 0, 0, 0); + USB_HID_SET_PROTOCOL, 0, interfno, 0, 0); /* Reports every time an event occurs and not more often than that. */ grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, - USB_HID_SET_IDLE, 0<<8, 0, 0, 0); + USB_HID_SET_IDLE, 0<<8, interfno, 0, 0); grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term, sizeof (grub_usb_keyboards[curnum])); @@ -185,12 +185,18 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) return 0; } + /* Test showed that getting report may make the keyboard go nuts. + Moreover since we're reattaching keyboard it usually sends + an initial message on interrupt pipe and so we retrieve + the same keystatus. + */ +#if 0 { grub_uint8_t report[8]; grub_usb_err_t err; grub_memset (report, 0, sizeof (report)); err = grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_IN, - USB_HID_GET_REPORT, 0x0000, interfno, + USB_HID_GET_REPORT, 0x0100, interfno, sizeof (report), (char *) report); if (err) { @@ -203,6 +209,10 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) data->key = report[2] ? : -1; } } +#else + data->status = 0; + data->key = -1; +#endif grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]); @@ -279,6 +289,8 @@ grub_usb_keyboard_getkeystatus (struct grub_term_input *term) struct grub_usb_keyboard_data *termdata = term->data; int mods = 0; + grub_usb_keyboard_checkkey (term); + /* Check Shift, Control, and Alt status. */ if (termdata->status & 0x02 || termdata->status & 0x20) mods |= GRUB_TERM_STATUS_SHIFT; From 3ee4474e8dc092c7da7d7cb920d0a86bf1e15bd7 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 16:09:43 +0200 Subject: [PATCH 27/64] Prepare infrastructure for background USB transfers --- bus/usb/ohci.c | 794 ++++++++++++++++++++++------------------ bus/usb/uhci.c | 205 +++++++---- bus/usb/usb.c | 2 +- bus/usb/usbtrans.c | 40 +- include/grub/usb.h | 14 +- include/grub/usbtrans.h | 2 + 6 files changed, 606 insertions(+), 451 deletions(-) diff --git a/bus/usb/ohci.c b/bus/usb/ohci.c index 7f757485c..ba723996a 100644 --- a/bus/usb/ohci.c +++ b/bus/usb/ohci.c @@ -652,36 +652,32 @@ grub_ohci_transaction (grub_ohci_td_t td, td->next_td = 0; } +struct grub_ohci_transfer_controller_data +{ + grub_uint32_t tderr_phys; + grub_uint32_t td_last_phys; + grub_ohci_ed_t ed_virt; + grub_ohci_td_t td_current_virt; + grub_ohci_td_t td_head_virt; + grub_uint64_t bad_OHCI_delay; +}; + static grub_usb_err_t -grub_ohci_transfer (grub_usb_controller_t dev, - grub_usb_transfer_t transfer, int timeout, - grub_size_t *actual) +grub_ohci_setup_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) { struct grub_ohci *o = (struct grub_ohci *) dev->data; - grub_ohci_ed_t ed_virt; int bulk = 0; - grub_ohci_td_t td_head_virt; - grub_ohci_td_t td_current_virt; grub_ohci_td_t td_next_virt; - grub_ohci_td_t tderr_virt = NULL; grub_uint32_t target; grub_uint32_t td_head_phys; grub_uint32_t td_tail_phys; - grub_uint32_t td_last_phys; - grub_uint32_t tderr_phys = 0; - grub_uint32_t status; - grub_uint32_t control; - grub_uint8_t errcode = 0; - grub_usb_err_t err = GRUB_USB_ERR_NONE; int i; - grub_uint64_t maxtime; - grub_uint64_t bad_OHCI_delay = 0; - int err_halt = 0; - int err_timeout = 0; - int err_unrec = 0; - grub_uint32_t intstatus; + struct grub_ohci_transfer_controller_data *cdata; - *actual = 0; + cdata = grub_zalloc (sizeof (*cdata)); + if (!cdata) + return GRUB_USB_ERR_INTERNAL; /* Pre-set target for ED - we need it to find proper ED */ /* Set the device address. */ @@ -703,21 +699,23 @@ grub_ohci_transfer (grub_usb_controller_t dev, case GRUB_USB_TRANSACTION_TYPE_CONTROL: break; - default : + default: + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } /* Find proper ED or add new ED */ - ed_virt = grub_ohci_find_ed (o, bulk, target); - if (!ed_virt) + cdata->ed_virt = grub_ohci_find_ed (o, bulk, target); + if (!cdata->ed_virt) { grub_dprintf ("ohci","Fatal: No free ED !\n"); + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } /* Take pointer to first TD from ED */ - td_head_phys = grub_le_to_cpu32 (ed_virt->td_head) & ~0xf; - td_tail_phys = grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf; + td_head_phys = grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf; + td_tail_phys = grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf; /* Sanity check - td_head should be equal to td_tail */ if (td_head_phys != td_tail_phys) /* Should never happen ! */ @@ -726,6 +724,7 @@ grub_ohci_transfer (grub_usb_controller_t dev, grub_dprintf ("ohci", "HEAD = 0x%02x, TAIL = 0x%02x\n", td_head_phys, td_tail_phys); /* XXX: Fix: What to do ? */ + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } @@ -733,65 +732,64 @@ grub_ohci_transfer (grub_usb_controller_t dev, * we must allocate the first TD. */ if (!td_head_phys) { - td_head_virt = grub_ohci_alloc_td (o); - if (!td_head_virt) + cdata->td_head_virt = grub_ohci_alloc_td (o); + if (!cdata->td_head_virt) return GRUB_USB_ERR_INTERNAL; /* We don't need de-allocate ED */ /* We can set td_head only when ED is not active, i.e. * when it is newly allocated. */ - ed_virt->td_head = grub_cpu_to_le32 ( grub_ohci_td_virt2phys (o, - td_head_virt) ); - ed_virt->td_tail = ed_virt->td_head; + cdata->ed_virt->td_head + = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, cdata->td_head_virt)); + cdata->ed_virt->td_tail = cdata->ed_virt->td_head; } else - td_head_virt = grub_ohci_td_phys2virt ( o, td_head_phys ); + cdata->td_head_virt = grub_ohci_td_phys2virt ( o, td_head_phys ); /* Set TDs */ - td_last_phys = td_head_phys; /* initial value to make compiler happy... */ - for (i = 0, td_current_virt = td_head_virt; + cdata->td_last_phys = td_head_phys; /* initial value to make compiler happy... */ + for (i = 0, cdata->td_current_virt = cdata->td_head_virt; i < transfer->transcnt; i++) { grub_usb_transaction_t tr = &transfer->transactions[i]; - grub_ohci_transaction (td_current_virt, tr->pid, tr->toggle, + grub_ohci_transaction (cdata->td_current_virt, tr->pid, tr->toggle, tr->size, tr->data); /* Set index of TD in transfer */ - td_current_virt->tr_index = (grub_uint32_t) i; + cdata->td_current_virt->tr_index = (grub_uint32_t) i; /* No IRQ request in TD if bad_OHCI set */ if (o->bad_OHCI) - td_current_virt->token |= grub_cpu_to_le32 ( 7 << 21); + cdata->td_current_virt->token |= grub_cpu_to_le32 ( 7 << 21); /* Remember last used (processed) TD phys. addr. */ - td_last_phys = grub_ohci_td_virt2phys (o, td_current_virt); + cdata->td_last_phys = grub_ohci_td_virt2phys (o, cdata->td_current_virt); /* Allocate next TD */ td_next_virt = grub_ohci_alloc_td (o); if (!td_next_virt) /* No free TD, cancel transfer and free TDs except head TD */ { if (i) /* if i==0 we have nothing to free... */ - grub_ohci_free_tds (o, - grub_ohci_td_phys2virt(o, - grub_le_to_cpu32 (td_head_virt->next_td) ) ); + grub_ohci_free_tds (o, grub_ohci_td_phys2virt(o, + grub_le_to_cpu32 (cdata->td_head_virt->next_td))); /* Reset head TD */ - grub_memset ( (void*)td_head_virt, 0, + grub_memset ( (void*)cdata->td_head_virt, 0, sizeof(struct grub_ohci_td) ); grub_dprintf ("ohci", "Fatal: No free TD !"); + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } /* Chain TDs */ - td_current_virt->link_td = (grub_uint32_t) td_next_virt; - td_current_virt->next_td = grub_cpu_to_le32 ( - grub_ohci_td_virt2phys (o, - td_next_virt) ); - td_next_virt->prev_td_phys = grub_ohci_td_virt2phys (o, - td_current_virt); - td_current_virt = td_next_virt; + cdata->td_current_virt->link_td = (grub_uint32_t) td_next_virt; + cdata->td_current_virt->next_td + = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, td_next_virt)); + td_next_virt->prev_td_phys + = grub_ohci_td_virt2phys (o, cdata->td_current_virt); + cdata->td_current_virt = td_next_virt; } grub_dprintf ("ohci", "Tail TD (not processed) = %p\n", - td_current_virt); + cdata->td_current_virt); /* Setup the Endpoint Descriptor for transfer. */ /* First set necessary fields in TARGET but keep (or set) skip bit */ @@ -799,12 +797,12 @@ grub_ohci_transfer (grub_usb_controller_t dev, * size never change after first allocation of ED. * But unfortunately max. packet size may change during initial * setup sequence and we must handle it. */ - ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); + cdata->ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); /* Set td_tail */ - ed_virt->td_tail - = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, td_current_virt)); + cdata->ed_virt->td_tail + = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, cdata->td_current_virt)); /* Now reset skip bit */ - ed_virt->target = grub_cpu_to_le32 (target); + cdata->ed_virt->target = grub_cpu_to_le32 (target); /* ed_virt->td_head = grub_cpu_to_le32 (td_head); Must not be changed, it is maintained by OHCI */ /* ed_virt->next_ed = grub_cpu_to_le32 (0); Handled by grub_ohci_find_ed, do not change ! */ @@ -834,93 +832,19 @@ grub_ohci_transfer (grub_usb_controller_t dev, } } - /* Safety measure to avoid a hang. */ - maxtime = grub_get_time_ms () + timeout; - - /* Wait until the transfer is completed or STALLs. */ - do - { - /* Check transfer status */ - intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - if (!o->bad_OHCI && (intstatus & 0x2) != 0) - { - /* Remember last successful TD */ - tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; - /* Reset DoneHead */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - /* if TD is last, finish */ - if (tderr_phys == td_last_phys) - { - if (grub_le_to_cpu32 (ed_virt->td_head) & 1) - err_halt = 1; - break; - } - continue; - } + return GRUB_USB_ERR_NONE; +} - if ((intstatus & 0x10) != 0) - { /* Unrecoverable error - only reset can help...! */ - err_unrec = 1; - break; - } - - /* Detected a HALT. */ - if (err_halt || (grub_le_to_cpu32 (ed_virt->td_head) & 1)) - { - err_halt = 1; - /* ED is halted, but donehead event can happened in the meantime */ - intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - if (!o->bad_OHCI && (intstatus & 0x2) != 0) - /* Don't break loop now, first do donehead action(s) */ - continue; - break; - } - - /* bad OHCI handling */ - if ( (grub_le_to_cpu32 (ed_virt->td_head) & ~0xf) == - (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf) ) /* Empty ED */ - { - if (o->bad_OHCI) /* Bad OHCI detected previously */ - { - /* Try get last successful TD. */ - tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; - if (tderr_phys)/* Reset DoneHead if we were successful */ - { - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - } - /* Check the HALT bit */ - if (grub_le_to_cpu32 (ed_virt->td_head) & 1) - err_halt = 1; - break; - } - else /* Detection of bad OHCI */ - /* We should wait short time (~2ms) before we say that - * it is bad OHCI to prevent some hazard - - * donehead can react in the meantime. This waiting is done - * only once per OHCI driver "live cycle". */ - if (!bad_OHCI_delay) /* Set delay time */ - bad_OHCI_delay = grub_get_time_ms () + 2; - else if (grub_get_time_ms () >= bad_OHCI_delay) - o->bad_OHCI = 1; - continue; - } - - /* Timeout ? */ - if (grub_get_time_ms () > maxtime) - { - err_timeout = 1; - break; - } - - grub_cpu_idle (); - } - while (1); +static void +pre_finish_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_uint32_t target; + grub_uint32_t status; + grub_uint32_t control; + grub_uint32_t intstatus; /* There are many ways how the loop above can finish: * - normally without any error via INTSTATUS WDH bit @@ -952,8 +876,8 @@ grub_ohci_transfer (grub_usb_controller_t dev, /* Remember target for debug and set skip flag in ED */ /* It should be normaly not necessary but we need it at least * in case of timeout */ - target = grub_le_to_cpu32 ( ed_virt->target ); - ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); + target = grub_le_to_cpu32 ( cdata->ed_virt->target ); + cdata->ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); /* Read registers for debug - they should be read now because * debug prints case unwanted delays, so something can happen * in the meantime... */ @@ -964,224 +888,23 @@ grub_ohci_transfer (grub_usb_controller_t dev, grub_dprintf ("ohci", "loop finished: control=0x%02x status=0x%02x\n", control, status); grub_dprintf ("ohci", "intstatus=0x%02x \n\t\t tderr_phys=0x%02x, td_last_phys=0x%02x\n", - intstatus, tderr_phys, td_last_phys); - grub_dprintf ("ohci", "err_unrec=%d, err_timeout=%d \n\t\t err_halt=%d, bad_OHCI=%d\n", - err_unrec, err_timeout, err_halt, o->bad_OHCI); + intstatus, cdata->tderr_phys, cdata->td_last_phys); grub_dprintf ("ohci", "TARGET=0x%02x, HEAD=0x%02x, TAIL=0x%02x\n", target, - grub_le_to_cpu32 (ed_virt->td_head), - grub_le_to_cpu32 (ed_virt->td_tail) ); + grub_le_to_cpu32 (cdata->ed_virt->td_head), + grub_le_to_cpu32 (cdata->ed_virt->td_tail) ); - if (!err_halt && !err_unrec && !err_timeout) /* normal finish */ - { - /* Simple workaround if donehead is not working */ - if (o->bad_OHCI && - ( !tderr_phys || (tderr_phys != td_last_phys) ) ) - { - grub_dprintf ("ohci", "normal finish, but tderr_phys corrected\n"); - tderr_phys = td_last_phys; - /* I hope we can do it as transfer (most probably) finished OK */ - } - /* Prepare pointer to last processed TD */ - tderr_virt = grub_ohci_td_phys2virt (o, tderr_phys); - /* Set index of last processed TD */ - if (tderr_virt) - transfer->last_trans = tderr_virt->tr_index; - else - transfer->last_trans = -1; - *actual = transfer->size + 1; - } +} - else if (err_halt) /* error, ED is halted by OHCI, i.e. can be modified */ - { - /* First we must get proper tderr_phys value */ - if (o->bad_OHCI) /* In case of bad_OHCI tderr_phys can be wrong */ - { - if ( tderr_phys ) /* check if tderr_phys points to TD with error */ - errcode = grub_le_to_cpu32 ( grub_ohci_td_phys2virt (o, - tderr_phys)->token ) - >> 28; - if ( !tderr_phys || !errcode ) /* tderr_phys not valid or points to wrong TD */ - { /* Retired TD with error should be previous TD to ED->td_head */ - tderr_phys = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 ( ed_virt->td_head) & ~0xf ) - ->prev_td_phys; - } - } - - /* Even if we have "good" OHCI, in some cases - * tderr_phys can be zero, check it */ - else if ( !tderr_phys ) - { /* Retired TD with error should be previous TD to ED->td_head */ - tderr_phys = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 ( ed_virt->td_head) & ~0xf ) - ->prev_td_phys; - } - - /* Prepare pointer to last processed TD and get error code */ - tderr_virt = grub_ohci_td_phys2virt (o, tderr_phys); - /* Set index of last processed TD */ - if (tderr_virt) - { - errcode = grub_le_to_cpu32 ( tderr_virt->token ) >> 28; - transfer->last_trans = tderr_virt->tr_index; - } - else - transfer->last_trans = -1; - - /* Evaluation of error code */ - grub_dprintf ("ohci", "OHCI tderr_phys=0x%02x, errcode=0x%02x\n", - tderr_phys, errcode); - switch (errcode) - { - case 0: - /* XXX: Should not happen! */ - grub_error (GRUB_ERR_IO, "OHCI failed without reporting the reason"); - err = GRUB_USB_ERR_INTERNAL; - break; - - case 1: - /* XXX: CRC error. */ - err = GRUB_USB_ERR_TIMEOUT; - break; - - case 2: - err = GRUB_USB_ERR_BITSTUFF; - break; - - case 3: - /* XXX: Data Toggle error. */ - err = GRUB_USB_ERR_DATA; - break; - - case 4: - err = GRUB_USB_ERR_STALL; - break; - - case 5: - /* XXX: Not responding. */ - err = GRUB_USB_ERR_TIMEOUT; - break; - - case 6: - /* XXX: PID Check bits failed. */ - err = GRUB_USB_ERR_BABBLE; - break; - - case 7: - /* XXX: PID unexpected failed. */ - err = GRUB_USB_ERR_BABBLE; - break; - - case 8: - /* XXX: Data overrun error. */ - err = GRUB_USB_ERR_DATA; - grub_dprintf ("ohci", "Overrun, failed TD address: %p, index: %d\n", - tderr_virt, tderr_virt->tr_index); - break; - - case 9: - /* XXX: Data underrun error. */ - grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n", - tderr_virt, tderr_virt->tr_index); - if (transfer->last_trans == -1) - break; - *actual = transfer->transactions[transfer->last_trans].size - - (grub_le_to_cpu32 (tderr_virt->buffer_end) - - grub_le_to_cpu32 (tderr_virt->buffer)) - + transfer->transactions[transfer->last_trans].preceding; - break; - - case 10: - /* XXX: Reserved. */ - err = GRUB_USB_ERR_NAK; - break; - - case 11: - /* XXX: Reserved. */ - err = GRUB_USB_ERR_NAK; - break; - - case 12: - /* XXX: Buffer overrun. */ - err = GRUB_USB_ERR_DATA; - break; - - case 13: - /* XXX: Buffer underrun. */ - err = GRUB_USB_ERR_DATA; - break; - - default: - err = GRUB_USB_ERR_NAK; - break; - } - - } - - else if (err_unrec) - { - /* Don't try to get error code and last processed TD for proper - * toggle bit value - anything can be invalid */ - err = GRUB_USB_ERR_UNRECOVERABLE; - grub_dprintf("ohci", "Unrecoverable error!"); - - /* Do OHCI reset in case of unrecoverable error - maybe we will need - * do more - re-enumerate bus etc. (?) */ - - /* Suspend the OHCI by issuing a reset. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic. */ - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - grub_millisleep (1); - grub_dprintf ("ohci", "Unrecoverable error - OHCI reset\n"); - - /* Misc. resets. */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, 0x7f); /* Clears everything */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, o->ed_ctrl_addr); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, o->ed_bulk_addr); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - - /* Enable the OHCI. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, - (2 << 6) - | GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE - | GRUB_OHCI_REG_CONTROL_BULK_ENABLE ); - } - - else if (err_timeout) - { - /* In case of timeout do not detect error from TD */ - err = GRUB_ERR_TIMEOUT; - grub_dprintf("ohci", "Timeout !\n"); - - /* We should wait for next SOF to be sure that ED is unaccessed - * by OHCI */ - /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); - /* Wait for new SOF */ - while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) == 0); - - /* Now we must find last processed TD if bad_OHCI == TRUE */ - if (o->bad_OHCI) - { /* Retired TD with error should be previous TD to ED->td_head */ - tderr_phys = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 ( ed_virt->td_head) & ~0xf) - ->prev_td_phys; - } - tderr_virt = grub_ohci_td_phys2virt (o, tderr_phys); - if (tderr_virt) - transfer->last_trans = tderr_virt->tr_index; - else - transfer->last_trans = -1; - } +static void +finish_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; /* Set empty ED - set HEAD = TAIL = last (not processed) TD */ - ed_virt->td_head = grub_cpu_to_le32 (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf); + cdata->ed_virt->td_head = grub_cpu_to_le32 (grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf); /* At this point always should be: * ED has skip bit set and halted or empty or after next SOF, @@ -1195,23 +918,368 @@ grub_ohci_transfer (grub_usb_controller_t dev, grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); /* Un-chainig of last TD */ - if (td_current_virt->prev_td_phys) + if (cdata->td_current_virt->prev_td_phys) { grub_ohci_td_t td_prev_virt - = grub_ohci_td_phys2virt (o, td_current_virt->prev_td_phys); - - td_next_virt = (grub_ohci_td_t) td_prev_virt->link_td; - if (td_current_virt == td_next_virt) + = grub_ohci_td_phys2virt (o, cdata->td_current_virt->prev_td_phys); + + if (cdata->td_current_virt == (grub_ohci_td_t) td_prev_virt->link_td) td_prev_virt->link_td = 0; } - grub_dprintf ("ohci", "OHCI finished, freeing, err=0x%02x, errcode=0x%02x\n", - err, errcode); - grub_ohci_free_tds (o, td_head_virt); + grub_dprintf ("ohci", "OHCI finished, freeing\n"); + grub_ohci_free_tds (o, cdata->td_head_virt); +} + +static grub_usb_err_t +parse_halt (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_uint8_t errcode = 0; + grub_usb_err_t err = GRUB_USB_ERR_NAK; + grub_ohci_td_t tderr_virt = NULL; + + *actual = 0; + + pre_finish_transfer (dev, transfer); + + /* First we must get proper tderr_phys value */ + if (o->bad_OHCI) /* In case of bad_OHCI tderr_phys can be wrong */ + { + if (cdata->tderr_phys) /* check if tderr_phys points to TD with error */ + errcode = grub_le_to_cpu32 (grub_ohci_td_phys2virt (o, + cdata->tderr_phys)->token) + >> 28; + if ( !cdata->tderr_phys || !errcode ) /* tderr_phys not valid or points to wrong TD */ + { /* Retired TD with error should be previous TD to ED->td_head */ + cdata->tderr_phys = grub_ohci_td_phys2virt (o, + grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf ) + ->prev_td_phys; + } + } + /* Even if we have "good" OHCI, in some cases + * tderr_phys can be zero, check it */ + else if (!cdata->tderr_phys) + /* Retired TD with error should be previous TD to ED->td_head */ + cdata->tderr_phys + = grub_ohci_td_phys2virt (o, + grub_le_to_cpu32 (cdata->ed_virt->td_head) + & ~0xf)->prev_td_phys; + + + /* Prepare pointer to last processed TD and get error code */ + tderr_virt = grub_ohci_td_phys2virt (o, cdata->tderr_phys); + /* Set index of last processed TD */ + if (tderr_virt) + { + errcode = grub_le_to_cpu32 (tderr_virt->token) >> 28; + transfer->last_trans = tderr_virt->tr_index; + } + else + transfer->last_trans = -1; + + /* Evaluation of error code */ + grub_dprintf ("ohci", "OHCI tderr_phys=0x%02x, errcode=0x%02x\n", + cdata->tderr_phys, errcode); + switch (errcode) + { + case 0: + /* XXX: Should not happen! */ + grub_error (GRUB_ERR_IO, "OHCI failed without reporting the reason"); + err = GRUB_USB_ERR_INTERNAL; + break; + + case 1: + /* XXX: CRC error. */ + err = GRUB_USB_ERR_TIMEOUT; + break; + + case 2: + err = GRUB_USB_ERR_BITSTUFF; + break; + + case 3: + /* XXX: Data Toggle error. */ + err = GRUB_USB_ERR_DATA; + break; + + case 4: + err = GRUB_USB_ERR_STALL; + break; + + case 5: + /* XXX: Not responding. */ + err = GRUB_USB_ERR_TIMEOUT; + break; + + case 6: + /* XXX: PID Check bits failed. */ + err = GRUB_USB_ERR_BABBLE; + break; + + case 7: + /* XXX: PID unexpected failed. */ + err = GRUB_USB_ERR_BABBLE; + break; + + case 8: + /* XXX: Data overrun error. */ + err = GRUB_USB_ERR_DATA; + grub_dprintf ("ohci", "Overrun, failed TD address: %p, index: %d\n", + tderr_virt, tderr_virt->tr_index); + break; + + case 9: + /* XXX: Data underrun error. */ + grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n", + tderr_virt, tderr_virt->tr_index); + if (transfer->last_trans == -1) + break; + *actual = transfer->transactions[transfer->last_trans].size + - (grub_le_to_cpu32 (tderr_virt->buffer_end) + - grub_le_to_cpu32 (tderr_virt->buffer)) + + transfer->transactions[transfer->last_trans].preceding; + err = GRUB_USB_ERR_NONE; + break; + + case 10: + /* XXX: Reserved. */ + err = GRUB_USB_ERR_NAK; + break; + + case 11: + /* XXX: Reserved. */ + err = GRUB_USB_ERR_NAK; + break; + + case 12: + /* XXX: Buffer overrun. */ + err = GRUB_USB_ERR_DATA; + break; + + case 13: + /* XXX: Buffer underrun. */ + err = GRUB_USB_ERR_DATA; + break; + + default: + err = GRUB_USB_ERR_NAK; + break; + } + + finish_transfer (dev, transfer); return err; } +static grub_usb_err_t +parse_success (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_ohci_td_t tderr_virt = NULL; + + pre_finish_transfer (dev, transfer); + + /* Simple workaround if donehead is not working */ + if (o->bad_OHCI && + (!cdata->tderr_phys || (cdata->tderr_phys != cdata->td_last_phys))) + { + grub_dprintf ("ohci", "normal finish, but tderr_phys corrected\n"); + cdata->tderr_phys = cdata->td_last_phys; + /* I hope we can do it as transfer (most probably) finished OK */ + } + /* Prepare pointer to last processed TD */ + tderr_virt = grub_ohci_td_phys2virt (o, cdata->tderr_phys); + /* Set index of last processed TD */ + if (tderr_virt) + transfer->last_trans = tderr_virt->tr_index; + else + transfer->last_trans = -1; + *actual = transfer->size + 1; + + finish_transfer (dev, transfer); + + return GRUB_USB_ERR_NONE; +} + +static grub_usb_err_t +parse_unrec (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + + *actual = 0; + + pre_finish_transfer (dev, transfer); + + /* Don't try to get error code and last processed TD for proper + * toggle bit value - anything can be invalid */ + grub_dprintf("ohci", "Unrecoverable error!"); + + /* Do OHCI reset in case of unrecoverable error - maybe we will need + * do more - re-enumerate bus etc. (?) */ + + /* Suspend the OHCI by issuing a reset. */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic. */ + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); + grub_millisleep (1); + grub_dprintf ("ohci", "Unrecoverable error - OHCI reset\n"); + + /* Misc. resets. */ + o->hcca->donehead = 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, 0x7f); /* Clears everything */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, o->ed_ctrl_addr); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, o->ed_bulk_addr); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + + /* Enable the OHCI. */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, + (2 << 6) + | GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE + | GRUB_OHCI_REG_CONTROL_BULK_ENABLE ); + finish_transfer (dev, transfer); + + return GRUB_USB_ERR_UNRECOVERABLE; +} + +static grub_usb_err_t +grub_ohci_check_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_uint32_t intstatus; + + /* Check transfer status */ + intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + if (!o->bad_OHCI && (intstatus & 0x2) != 0) + { + /* Remember last successful TD */ + cdata->tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; + /* Reset DoneHead */ + o->hcca->donehead = 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + /* if TD is last, finish */ + if (cdata->tderr_phys == cdata->td_last_phys) + { + if (grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1) + return parse_halt (dev, transfer, actual); + else + return parse_success (dev, transfer, actual); + } + return GRUB_USB_ERR_WAIT; + } + + if ((intstatus & 0x10) != 0) + /* Unrecoverable error - only reset can help...! */ + return parse_unrec (dev, transfer, actual); + + /* Detected a HALT. */ + if ((grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1)) + { + /* ED is halted, but donehead event can happened in the meantime */ + intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + if (!o->bad_OHCI && (intstatus & 0x2) != 0) + { + /* Remember last successful TD */ + cdata->tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; + /* Reset DoneHead */ + o->hcca->donehead = 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + /* if TD is last, finish */ + } + return parse_halt (dev, transfer, actual); + } + + /* bad OHCI handling */ + if ( (grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf) == + (grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf) ) /* Empty ED */ + { + if (o->bad_OHCI) /* Bad OHCI detected previously */ + { + /* Try get last successful TD. */ + cdata->tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; + if (cdata->tderr_phys)/* Reset DoneHead if we were successful */ + { + o->hcca->donehead = 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + } + /* Check the HALT bit */ + if (grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1) + return parse_halt (dev, transfer, actual); + else + return parse_success (dev, transfer, actual); + } + else /* Detection of bad OHCI */ + /* We should wait short time (~2ms) before we say that + * it is bad OHCI to prevent some hazard - + * donehead can react in the meantime. This waiting is done + * only once per OHCI driver "live cycle". */ + if (!cdata->bad_OHCI_delay) /* Set delay time */ + cdata->bad_OHCI_delay = grub_get_time_ms () + 2; + else if (grub_get_time_ms () >= cdata->bad_OHCI_delay) + o->bad_OHCI = 1; + return GRUB_USB_ERR_WAIT; + } + + return GRUB_USB_ERR_WAIT; +} + +static grub_usb_err_t +grub_ohci_cancel_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_ohci_td_t tderr_virt = NULL; + + pre_finish_transfer (dev, transfer); + + grub_dprintf("ohci", "Timeout !\n"); + + /* We should wait for next SOF to be sure that ED is unaccessed + * by OHCI */ + /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); + /* Wait for new SOF */ + while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) == 0); + + /* Now we must find last processed TD if bad_OHCI == TRUE */ + if (o->bad_OHCI) + /* Retired TD with error should be previous TD to ED->td_head */ + cdata->tderr_phys + = grub_ohci_td_phys2virt (o, grub_le_to_cpu32 (cdata->ed_virt->td_head) + & ~0xf)->prev_td_phys; + + tderr_virt = grub_ohci_td_phys2virt (o,cdata-> tderr_phys); + if (tderr_virt) + transfer->last_trans = tderr_virt->tr_index; + else + transfer->last_trans = -1; + + finish_transfer (dev, transfer); + + return GRUB_USB_ERR_NONE; +} + static grub_err_t grub_ohci_portstatus (grub_usb_controller_t dev, unsigned int port, unsigned int enable) @@ -1398,7 +1466,9 @@ static struct grub_usb_controller_dev usb_controller = { .name = "ohci", .iterate = grub_ohci_iterate, - .transfer = grub_ohci_transfer, + .setup_transfer = grub_ohci_setup_transfer, + .check_transfer = grub_ohci_check_transfer, + .cancel_transfer = grub_ohci_cancel_transfer, .hubports = grub_ohci_hubports, .portstatus = grub_ohci_portstatus, .detect_dev = grub_ohci_detect_dev diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c index d0416d7e2..4792f961a 100644 --- a/bus/usb/uhci.c +++ b/bus/usb/uhci.c @@ -438,26 +438,35 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, return td; } +struct grub_uhci_transfer_controller_data +{ + grub_uhci_qh_t qh; + grub_uhci_td_t td_first; +}; + static grub_usb_err_t -grub_uhci_transfer (grub_usb_controller_t dev, - grub_usb_transfer_t transfer, - int timeout, grub_size_t *actual) +grub_uhci_setup_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) { struct grub_uhci *u = (struct grub_uhci *) dev->data; - grub_uhci_qh_t qh; grub_uhci_td_t td; - grub_uhci_td_t td_first = NULL; grub_uhci_td_t td_prev = NULL; - grub_usb_err_t err = GRUB_USB_ERR_NONE; int i; - grub_uint64_t endtime; + struct grub_uhci_transfer_controller_data *cdata; - *actual = 0; + cdata = grub_malloc (sizeof (*cdata)); + if (!cdata) + return GRUB_USB_ERR_INTERNAL; + + cdata->td_first = NULL; /* Allocate a queue head for the transfer queue. */ - qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL); - if (! qh) - return GRUB_USB_ERR_INTERNAL; + cdata->qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL); + if (! cdata->qh) + { + grub_free (cdata); + return GRUB_USB_ERR_INTERNAL; + } grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase); @@ -470,18 +479,20 @@ grub_uhci_transfer (grub_usb_controller_t dev, tr->size, tr->data); if (! td) { + grub_size_t actual = 0; /* Terminate and free. */ td_prev->linkptr2 = 0; td_prev->linkptr = 1; - if (td_first) - grub_free_queue (u, td_first, NULL, actual); + if (cdata->td_first) + grub_free_queue (u, cdata->td_first, NULL, &actual); + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } - if (! td_first) - td_first = td; + if (! cdata->td_first) + cdata->td_first = td; else { td_prev->linkptr2 = (grub_uint32_t) td; @@ -497,82 +508,112 @@ grub_uhci_transfer (grub_usb_controller_t dev, /* Link it into the queue and terminate. Now the transaction can take place. */ - qh->elinkptr = (grub_uint32_t) td_first; + cdata->qh->elinkptr = (grub_uint32_t) cdata->td_first; grub_dprintf ("uhci", "initiate transaction\n"); - /* Wait until either the transaction completed or an error - occurred. */ - endtime = grub_get_time_ms () + timeout; - for (;;) + transfer->controller_data = cdata; + + return GRUB_USB_ERR_NONE; +} + +static grub_usb_err_t +grub_uhci_check_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_uhci *u = (struct grub_uhci *) dev->data; + grub_uhci_td_t errtd; + struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data; + + *actual = 0; + + errtd = (grub_uhci_td_t) (cdata->qh->elinkptr & ~0x0f); + + grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n", + errtd->ctrl_status, errtd->buffer & (~15), errtd); + + /* Check if the transaction completed. */ + if (cdata->qh->elinkptr & 1) { - grub_uhci_td_t errtd; + grub_dprintf ("uhci", "transaction complete\n"); - errtd = (grub_uhci_td_t) (qh->elinkptr & ~0x0f); - - grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n", - errtd->ctrl_status, errtd->buffer & (~15), errtd); - - /* Check if the transaction completed. */ - if (qh->elinkptr & 1) - break; - - grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status); - - if (!(errtd->ctrl_status & (1 << 23))) - { - /* Check if the endpoint is stalled. */ - if (errtd->ctrl_status & (1 << 22)) - err = GRUB_USB_ERR_STALL; - - /* Check if an error related to the data buffer occurred. */ - if (errtd->ctrl_status & (1 << 21)) - err = GRUB_USB_ERR_DATA; - - /* Check if a babble error occurred. */ - if (errtd->ctrl_status & (1 << 20)) - err = GRUB_USB_ERR_BABBLE; - - /* Check if a NAK occurred. */ - if (errtd->ctrl_status & (1 << 19)) - err = GRUB_USB_ERR_NAK; - - /* Check if a timeout occurred. */ - if (errtd->ctrl_status & (1 << 18)) - err = GRUB_USB_ERR_TIMEOUT; - - /* Check if a bitstuff error occurred. */ - if (errtd->ctrl_status & (1 << 17)) - err = GRUB_USB_ERR_BITSTUFF; - - if (err) - break; - } - - /* Fall through, no errors occurred, so the QH might be - updated. */ - grub_dprintf ("uhci", "transaction fallthrough\n"); - - if (grub_get_time_ms () > endtime) - { - err = GRUB_USB_ERR_STALL; - grub_dprintf ("uhci", "transaction timed out\n"); - break; - } - grub_cpu_idle (); + /* Place the QH back in the free list and deallocate the associated + TDs. */ + cdata->qh->elinkptr = 1; + grub_free_queue (u, cdata->td_first, transfer, actual); + grub_free (cdata); + return GRUB_USB_ERR_NONE; } - if (err != GRUB_USB_ERR_NONE) - grub_dprintf ("uhci", "transaction failed\n"); - else - grub_dprintf ("uhci", "transaction complete\n"); + grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status); + + if (!(errtd->ctrl_status & (1 << 23))) + { + grub_usb_err_t err = GRUB_USB_ERR_NONE; + + /* Check if the endpoint is stalled. */ + if (errtd->ctrl_status & (1 << 22)) + err = GRUB_USB_ERR_STALL; + + /* Check if an error related to the data buffer occurred. */ + if (errtd->ctrl_status & (1 << 21)) + err = GRUB_USB_ERR_DATA; + + /* Check if a babble error occurred. */ + if (errtd->ctrl_status & (1 << 20)) + err = GRUB_USB_ERR_BABBLE; + + /* Check if a NAK occurred. */ + if (errtd->ctrl_status & (1 << 19)) + err = GRUB_USB_ERR_NAK; + + /* Check if a timeout occurred. */ + if (errtd->ctrl_status & (1 << 18)) + err = GRUB_USB_ERR_TIMEOUT; + + /* Check if a bitstuff error occurred. */ + if (errtd->ctrl_status & (1 << 17)) + err = GRUB_USB_ERR_BITSTUFF; + + if (err) + { + grub_dprintf ("uhci", "transaction failed\n"); + + /* Place the QH back in the free list and deallocate the associated + TDs. */ + cdata->qh->elinkptr = 1; + grub_free_queue (u, cdata->td_first, transfer, actual); + grub_free (cdata); + + return err; + } + } + + /* Fall through, no errors occurred, so the QH might be + updated. */ + grub_dprintf ("uhci", "transaction fallthrough\n"); + + return GRUB_USB_ERR_WAIT; +} + +static grub_usb_err_t +grub_uhci_cancel_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_uhci *u = (struct grub_uhci *) dev->data; + grub_size_t actual; + struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data; + + grub_dprintf ("uhci", "transaction cancel\n"); /* Place the QH back in the free list and deallocate the associated TDs. */ - qh->elinkptr = 1; - grub_free_queue (u, td_first, transfer, actual); + cdata->qh->elinkptr = 1; + grub_free_queue (u, cdata->td_first, transfer, &actual); + grub_free (cdata); - return err; + return GRUB_USB_ERR_NONE; } static int @@ -706,7 +747,9 @@ static struct grub_usb_controller_dev usb_controller = { .name = "uhci", .iterate = grub_uhci_iterate, - .transfer = grub_uhci_transfer, + .setup_transfer = grub_uhci_setup_transfer, + .check_transfer = grub_uhci_check_transfer, + .cancel_transfer = grub_uhci_cancel_transfer, .hubports = grub_uhci_hubports, .portstatus = grub_uhci_portstatus, .detect_dev = grub_uhci_detect_dev diff --git a/bus/usb/usb.c b/bus/usb/usb.c index 2bd805ef2..80d386c8d 100644 --- a/bus/usb/usb.c +++ b/bus/usb/usb.c @@ -338,7 +338,7 @@ grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc) GRUB_MOD_INIT(usb) { - grub_term_poll_usb = grub_usb_poll_devices; + // grub_term_poll_usb = grub_usb_poll_devices; } GRUB_MOD_FINI(usb) diff --git a/bus/usb/usbtrans.c b/bus/usb/usbtrans.c index 4a2e112bf..27377a3a5 100644 --- a/bus/usb/usbtrans.c +++ b/bus/usb/usbtrans.c @@ -23,6 +23,39 @@ #include #include #include +#include + +static grub_usb_err_t +grub_usb_execute_and_wait_transfer (grub_usb_device_t dev, + grub_usb_transfer_t transfer, + int timeout, grub_size_t *actual) +{ + grub_usb_err_t err; + grub_uint64_t endtime; + + endtime = grub_get_time_ms () + timeout; + err = dev->controller.dev->setup_transfer (&dev->controller, transfer); + if (err) + return err; + while (1) + { + err = dev->controller.dev->check_transfer (&dev->controller, transfer, + actual); + if (!err) + return GRUB_USB_ERR_NONE; + if (err != GRUB_USB_ERR_WAIT) + return err; + if (grub_get_time_ms () > endtime) + { + err = dev->controller.dev->cancel_transfer (&dev->controller, + transfer); + if (err) + return err; + return GRUB_USB_ERR_TIMEOUT; + } + grub_cpu_idle (); + } +} grub_usb_err_t grub_usb_control_msg (grub_usb_device_t dev, @@ -147,8 +180,8 @@ grub_usb_control_msg (grub_usb_device_t dev, transfer->transactions[datablocks + 1].toggle = 1; - err = dev->controller.dev->transfer (&dev->controller, transfer, - 1000, &actual); + err = grub_usb_execute_and_wait_transfer (dev, transfer, 1000, &actual); + grub_dprintf ("usb", "control: err=%d\n", err); grub_free (transfer->transactions); @@ -248,8 +281,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, size -= tr->size; } - err = dev->controller.dev->transfer (&dev->controller, transfer, timeout, - actual); + err = grub_usb_execute_and_wait_transfer (dev, transfer, timeout, actual); /* We must remember proper toggle value even if some transactions * were not processed - correct value should be inversion of last * processed transaction (TD). */ diff --git a/include/grub/usb.h b/include/grub/usb.h index bb3336580..e7d119646 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -30,6 +30,7 @@ typedef struct grub_usb_controller_dev *grub_usb_controller_dev_t; typedef enum { GRUB_USB_ERR_NONE, + GRUB_USB_ERR_WAIT, GRUB_USB_ERR_INTERNAL, GRUB_USB_ERR_STALL, GRUB_USB_ERR_DATA, @@ -97,6 +98,7 @@ grub_usb_err_t grub_usb_root_hub (grub_usb_controller_t controller); + /* XXX: All handled by libusb for now. */ struct grub_usb_controller_dev { @@ -105,9 +107,15 @@ struct grub_usb_controller_dev int (*iterate) (int (*hook) (grub_usb_controller_t dev)); - grub_usb_err_t (*transfer) (grub_usb_controller_t dev, - grub_usb_transfer_t transfer, - int timeout, grub_size_t *actual); + grub_usb_err_t (*setup_transfer) (grub_usb_controller_t dev, + grub_usb_transfer_t transfer); + + grub_usb_err_t (*check_transfer) (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual); + + grub_usb_err_t (*cancel_transfer) (grub_usb_controller_t dev, + grub_usb_transfer_t transfer); int (*hubports) (grub_usb_controller_t dev); diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index a5bb2e8b2..486e83f40 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -62,6 +62,8 @@ struct grub_usb_transfer int last_trans; /* Index of last processed transaction in OHCI/UHCI driver. */ + + void *controller_data; }; typedef struct grub_usb_transfer *grub_usb_transfer_t; From e959937cfd6fca6f85da92c9b5b7f0153b276102 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 17:12:51 +0200 Subject: [PATCH 28/64] Use background transfers for usb_keyboard --- bus/usb/usbtrans.c | 97 +++++++++++++++++++++++++++++++++-------- include/grub/usb.h | 5 +++ include/grub/usbtrans.h | 6 +++ term/usb_keyboard.c | 41 ++++++++++++++--- 4 files changed, 127 insertions(+), 22 deletions(-) diff --git a/bus/usb/usbtrans.c b/bus/usb/usbtrans.c index 27377a3a5..5d6966ecc 100644 --- a/bus/usb/usbtrans.c +++ b/bus/usb/usbtrans.c @@ -195,29 +195,27 @@ grub_usb_control_msg (grub_usb_device_t dev, return err; } -static grub_usb_err_t -grub_usb_bulk_readwrite (grub_usb_device_t dev, - int endpoint, grub_size_t size0, char *data_in, - grub_transfer_type_t type, int timeout, - grub_size_t *actual) +static grub_usb_transfer_t +grub_usb_bulk_setup_readwrite (grub_usb_device_t dev, + int endpoint, grub_size_t size0, char *data_in, + grub_transfer_type_t type) { int i; grub_usb_transfer_t transfer; int datablocks; unsigned int max; - grub_usb_err_t err; - int toggle = dev->toggle[endpoint]; volatile char *data; grub_uint32_t data_addr; struct grub_pci_dma_chunk *data_chunk; grub_size_t size = size0; + int toggle = dev->toggle[endpoint]; grub_dprintf ("usb", "bulk: size=0x%02x type=%d\n", size, type); /* FIXME: avoid allocation any kind of buffer in a first place. */ data_chunk = grub_memalign_dma32 (128, size); if (!data_chunk) - return GRUB_USB_ERR_INTERNAL; + return NULL; data = grub_dma_get_virt (data_chunk); data_addr = grub_dma_get_phys (data_chunk); if (type == GRUB_USB_TRANSFER_TYPE_OUT) @@ -242,7 +240,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, if (! transfer) { grub_dma_free (data_chunk); - return GRUB_USB_ERR_INTERNAL; + return NULL; } datablocks = ((size + max - 1) / max); @@ -251,9 +249,12 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, transfer->endpoint = endpoint & 15; transfer->devaddr = dev->addr; transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK; + transfer->dir = type; transfer->max = max; transfer->dev = dev; transfer->last_trans = -1; /* Reset index of last processed transaction (TD) */ + transfer->data_chunk = data_chunk; + transfer->data = data_in; /* Allocate an array of transfer data structures. */ transfer->transactions = grub_malloc (transfer->transcnt @@ -262,7 +263,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, { grub_free (transfer); grub_dma_free (data_chunk); - return GRUB_USB_ERR_INTERNAL; + return NULL; } /* Set up all transfers. */ @@ -280,24 +281,51 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, tr->preceding = i * max; size -= tr->size; } + return transfer; +} + +static void +grub_usb_bulk_finish_readwrite (grub_usb_transfer_t transfer) +{ + grub_usb_device_t dev = transfer->dev; + int toggle = dev->toggle[transfer->endpoint]; - err = grub_usb_execute_and_wait_transfer (dev, transfer, timeout, actual); /* We must remember proper toggle value even if some transactions * were not processed - correct value should be inversion of last * processed transaction (TD). */ if (transfer->last_trans >= 0) toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1; else - toggle = dev->toggle[endpoint]; /* Nothing done, take original */ - grub_dprintf ("usb", "bulk: err=%d, toggle=%d\n", err, toggle); - dev->toggle[endpoint] = toggle; + toggle = dev->toggle[transfer->endpoint]; /* Nothing done, take original */ + grub_dprintf ("usb", "bulk: toggle=%d\n", toggle); + dev->toggle[transfer->endpoint] = toggle; + + if (transfer->dir == GRUB_USB_TRANSFER_TYPE_IN) + grub_memcpy (transfer->data, (void *) + grub_dma_get_virt (transfer->data_chunk), + transfer->size + 1); grub_free (transfer->transactions); grub_free (transfer); - grub_dma_free (data_chunk); + grub_dma_free (transfer->data_chunk); +} - if (type == GRUB_USB_TRANSFER_TYPE_IN) - grub_memcpy (data_in, (char *) data, size0); +static grub_usb_err_t +grub_usb_bulk_readwrite (grub_usb_device_t dev, + int endpoint, grub_size_t size0, char *data_in, + grub_transfer_type_t type, int timeout, + grub_size_t *actual) +{ + grub_usb_err_t err; + grub_usb_transfer_t transfer; + + transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size0, + data_in, type); + if (!transfer) + return GRUB_USB_ERR_INTERNAL; + err = grub_usb_execute_and_wait_transfer (dev, transfer, timeout, actual); + + grub_usb_bulk_finish_readwrite (transfer); return err; } @@ -329,6 +357,41 @@ grub_usb_bulk_read (grub_usb_device_t dev, return err; } +grub_usb_err_t +grub_usb_check_transfer (grub_usb_transfer_t transfer, grub_size_t *actual) +{ + grub_usb_err_t err; + grub_usb_device_t dev = transfer->dev; + + err = dev->controller.dev->check_transfer (&dev->controller, transfer, + actual); + if (err == GRUB_USB_ERR_WAIT) + return err; + + grub_usb_bulk_finish_readwrite (transfer); + + return err; +} + +grub_usb_transfer_t +grub_usb_bulk_read_background (grub_usb_device_t dev, + int endpoint, grub_size_t size, void *data) +{ + grub_usb_err_t err; + grub_usb_transfer_t transfer; + + transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size, + data, GRUB_USB_TRANSFER_TYPE_IN); + if (!transfer) + return NULL; + + err = dev->controller.dev->setup_transfer (&dev->controller, transfer); + if (err) + return NULL; + + return transfer; +} + grub_usb_err_t grub_usb_bulk_read_extended (grub_usb_device_t dev, int endpoint, grub_size_t size, char *data, diff --git a/include/grub/usb.h b/include/grub/usb.h index e7d119646..768ec2f66 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -274,5 +274,10 @@ grub_usb_err_t grub_usb_bulk_read_extended (grub_usb_device_t dev, int endpoint, grub_size_t size, char *data, int timeout, grub_size_t *actual); +grub_usb_transfer_t +grub_usb_bulk_read_background (grub_usb_device_t dev, + int endpoint, grub_size_t size, void *data); +grub_usb_err_t +grub_usb_check_transfer (grub_usb_transfer_t trans, grub_size_t *actual); #endif /* GRUB_USB_H */ diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index 486e83f40..a8aca3119 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -56,6 +56,8 @@ struct grub_usb_transfer grub_transaction_type_t type; + grub_transfer_type_t dir; + struct grub_usb_device *dev; struct grub_usb_transaction *transactions; @@ -64,6 +66,10 @@ struct grub_usb_transfer /* Index of last processed transaction in OHCI/UHCI driver. */ void *controller_data; + + /* Used when finishing transfer to copy data back. */ + struct grub_pci_dma_chunk *data_chunk; + void *data; }; typedef struct grub_usb_transfer *grub_usb_transfer_t; diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index adb84fa94..1a486b53d 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -84,6 +84,9 @@ struct grub_usb_keyboard_data grub_uint8_t status; int key; struct grub_usb_desc_endp *endp; + grub_usb_transfer_t transfer; + grub_uint8_t report[8]; + int dead; }; static struct grub_term_input grub_usb_keyboards[16]; @@ -214,8 +217,20 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) data->key = -1; #endif + data->transfer = grub_usb_bulk_read_background (usbdev, + data->endp->endp_addr, + sizeof (data->report), + (char *) data->report); + if (!data->transfer) + { + grub_print_error (); + return 0; + } + grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]); + data->dead = 0; + return 1; } @@ -224,19 +239,35 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) static int grub_usb_keyboard_checkkey (struct grub_term_input *term) { - grub_uint8_t data[8]; grub_usb_err_t err; struct grub_usb_keyboard_data *termdata = term->data; + grub_uint8_t data[sizeof (termdata->report)]; grub_size_t actual; if (termdata->key != -1) return termdata->key; - data[2] = 0; + if (termdata->dead) + return -1; + /* Poll interrupt pipe. */ - err = grub_usb_bulk_read_extended (termdata->usbdev, - termdata->endp->endp_addr, sizeof (data), - (char *) data, 10, &actual); + err = grub_usb_check_transfer (termdata->transfer, &actual); + + if (err == GRUB_USB_ERR_WAIT) + return -1; + + grub_memcpy (data, termdata->report, sizeof (data)); + + termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev, + termdata->endp->endp_addr, + sizeof (termdata->report), + (char *) termdata->report); + if (!termdata->transfer) + { + grub_printf ("%s failed. Stopped\n", term->name); + termdata->dead = 1; + } + if (err || actual < 1) return -1; From 2eb310be7981acf9284ae68857711da29b59ceb7 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 18:24:09 +0200 Subject: [PATCH 29/64] Enable usb device polling again --- bus/usb/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bus/usb/usb.c b/bus/usb/usb.c index 80d386c8d..2bd805ef2 100644 --- a/bus/usb/usb.c +++ b/bus/usb/usb.c @@ -338,7 +338,7 @@ grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc) GRUB_MOD_INIT(usb) { - // grub_term_poll_usb = grub_usb_poll_devices; + grub_term_poll_usb = grub_usb_poll_devices; } GRUB_MOD_FINI(usb) From 0aaf4938c785b06e611351bb927d9c1689355629 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 19:41:37 +0200 Subject: [PATCH 30/64] Fix incorrect toggle calculation --- bus/usb/uhci.c | 2 +- bus/usb/usbtrans.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c index 4792f961a..addfb41e8 100644 --- a/bus/usb/uhci.c +++ b/bus/usb/uhci.c @@ -474,7 +474,7 @@ grub_uhci_setup_transfer (grub_usb_controller_t dev, { grub_usb_transaction_t tr = &transfer->transactions[i]; - td = grub_uhci_transaction (u, transfer->endpoint, tr->pid, + td = grub_uhci_transaction (u, transfer->endpoint & 15, tr->pid, transfer->devaddr, tr->toggle, tr->size, tr->data); if (! td) diff --git a/bus/usb/usbtrans.c b/bus/usb/usbtrans.c index 5d6966ecc..7e6840083 100644 --- a/bus/usb/usbtrans.c +++ b/bus/usb/usbtrans.c @@ -246,7 +246,7 @@ grub_usb_bulk_setup_readwrite (grub_usb_device_t dev, datablocks = ((size + max - 1) / max); transfer->transcnt = datablocks; transfer->size = size - 1; - transfer->endpoint = endpoint & 15; + transfer->endpoint = endpoint; transfer->devaddr = dev->addr; transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK; transfer->dir = type; From 5a2823c1913acbb22d06191b1057e7651f5936db Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 19:42:31 +0200 Subject: [PATCH 31/64] Give better debug message in usb_keyboard_checkkey --- term/usb_keyboard.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 1a486b53d..e9be331cf 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -258,6 +258,13 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) grub_memcpy (data, termdata->report, sizeof (data)); + grub_dprintf ("usb_keyboard", + "err = %d, actual = %d report: 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + err, actual, + data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); + termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev, termdata->endp->endp_addr, sizeof (termdata->report), @@ -276,12 +283,6 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) if (actual < 3 || !data[2]) return -1; - grub_dprintf ("usb_keyboard", - "report: 0x%02x 0x%02x 0x%02x 0x%02x" - " 0x%02x 0x%02x 0x%02x 0x%02x\n", - data[0], data[1], data[2], data[3], - data[4], data[5], data[6], data[7]); - /* Check if the Control or Shift key was pressed. */ if (data[0] & 0x01 || data[0] & 0x10) termdata->key = keyboard_map[data[2]] - 'a' + 1; From b481fe847a3cc1642085940f541c8fda8a5f878d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 20:54:20 +0200 Subject: [PATCH 32/64] really set controller_data in ohci --- bus/usb/ohci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bus/usb/ohci.c b/bus/usb/ohci.c index ba723996a..66b7c0855 100644 --- a/bus/usb/ohci.c +++ b/bus/usb/ohci.c @@ -832,6 +832,8 @@ grub_ohci_setup_transfer (grub_usb_controller_t dev, } } + transfer->controller_data = cdata; + return GRUB_USB_ERR_NONE; } From 3593f89bf3cebb02a5881ee71ac09cb61f5195da Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 21:39:15 +0200 Subject: [PATCH 33/64] clear port status change afte polling it --- bus/usb/ohci.c | 12 ++++++++++-- bus/usb/uhci.c | 24 ++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/bus/usb/ohci.c b/bus/usb/ohci.c index 66b7c0855..e3cd490ac 100644 --- a/bus/usb/ohci.c +++ b/bus/usb/ohci.c @@ -1349,8 +1349,16 @@ grub_ohci_detect_dev (grub_usb_controller_t dev, int port, int *changed) grub_dprintf ("ohci", "detect_dev status=0x%02x\n", status); - /* Connect Status Change bit - it detects change of connection */ - *changed = ((status & GRUB_OHCI_RESET_CONNECT_CHANGE) != 0); + /* Connect Status Change bit - it detects change of connection */ + if (status & GRUB_OHCI_RESET_CONNECT_CHANGE) + { + *changed = 1; + /* Reset bit Connect Status Change */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_RESET_CONNECT_CHANGE); + } + else + *changed = 0; if (! (status & 1)) return GRUB_USB_SPEED_NONE; diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c index addfb41e8..472a7054e 100644 --- a/bus/usb/uhci.c +++ b/bus/usb/uhci.c @@ -39,6 +39,18 @@ typedef enum #define GRUB_UHCI_LINK_TERMINATE 1 #define GRUB_UHCI_LINK_QUEUE_HEAD 2 +enum + { + GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED = 0x0002, + GRUB_UHCI_REG_PORTSC_PORT_ENABLED = 0x0004, + GRUB_UHCI_REG_PORTSC_RESUME = 0x0040, + GRUB_UHCI_REG_PORTSC_RESET = 0x0200, + GRUB_UHCI_REG_PORTSC_SUSPEND = 0x1000, + GRUB_UHCI_REG_PORTSC_RW = GRUB_UHCI_REG_PORTSC_PORT_ENABLED + | GRUB_UHCI_REG_PORTSC_RESUME | GRUB_UHCI_REG_PORTSC_RESET + | GRUB_UHCI_REG_PORTSC_SUSPEND + }; + /* UHCI Queue Head. */ struct grub_uhci_qh @@ -693,7 +705,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, return grub_error (GRUB_ERR_IO, "UHCI Timed out"); /* Reset bit Connect Status Change */ - grub_uhci_writereg16 (u, reg, status | (1 << 1)); + grub_uhci_writereg16 (u, reg, status | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED); /* Read final port status */ status = grub_uhci_readreg16 (u, reg); @@ -725,7 +737,15 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port); /* Connect Status Change bit - it detects change of connection */ - *changed = ((status & (1 << 1)) != 0); + if (status & (1 << 1)) + { + *changed = 1; + /* Reset bit Connect Status Change */ + grub_uhci_writereg16 (u, reg, (status & GRUB_UHCI_REG_PORTSC_RW) + | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED); + } + else + *changed = 0; if (! (status & 1)) return GRUB_USB_SPEED_NONE; From f609c84a7fc5ae8b4729a39bcad8c90325c1aa85 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 21:55:24 +0200 Subject: [PATCH 34/64] MAke an enum out of reqtype --- include/grub/usb.h | 8 -------- include/grub/usbtrans.h | 28 +++++++++++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/include/grub/usb.h b/include/grub/usb.h index 768ec2f66..315ae9455 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -49,14 +49,6 @@ typedef enum GRUB_USB_SPEED_HIGH } grub_usb_speed_t; -enum - { - GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT = 0x21, - GRUB_USB_REQTYPE_VENDOR_OUT = 0x40, - GRUB_USB_REQTYPE_CLASS_INTERFACE_IN = 0xa1, - GRUB_USB_REQTYPE_VENDOR_IN = 0xc0 - }; - /* Call HOOK with each device, until HOOK returns non-zero. */ int grub_usb_iterate (int (*hook) (grub_usb_device_t dev)); diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index a8aca3119..ae2fd1bc4 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -74,15 +74,25 @@ struct grub_usb_transfer typedef struct grub_usb_transfer *grub_usb_transfer_t; -#define GRUB_USB_REQTYPE_IN (1 << 7) -#define GRUB_USB_REQTYPE_OUT (0 << 7) -#define GRUB_USB_REQTYPE_STANDARD (0 << 5) -#define GRUB_USB_REQTYPE_CLASS (1 << 5) -#define GRUB_USB_REQTYPE_VENDOR (2 << 5) -#define GRUB_USB_REQTYPE_TARGET_DEV (0 << 0) -#define GRUB_USB_REQTYPE_TARGET_INTERF (1 << 0) -#define GRUB_USB_REQTYPE_TARGET_ENDP (2 << 0) -#define GRUB_USB_REQTYPE_TARGET_OTHER (3 << 0) + +enum + { + GRUB_USB_REQTYPE_TARGET_DEV = (0 << 0), + GRUB_USB_REQTYPE_TARGET_INTERF = (1 << 0), + GRUB_USB_REQTYPE_TARGET_ENDP = (2 << 0), + GRUB_USB_REQTYPE_TARGET_OTHER = (3 << 0), + GRUB_USB_REQTYPE_STANDARD = (0 << 5), + GRUB_USB_REQTYPE_CLASS = (1 << 5), + GRUB_USB_REQTYPE_VENDOR = (2 << 5), + GRUB_USB_REQTYPE_OUT = (0 << 7), + GRUB_USB_REQTYPE_IN = (1 << 7), + GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT = GRUB_USB_REQTYPE_TARGET_INTERF + | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_OUT, + GRUB_USB_REQTYPE_VENDOR_OUT = GRUB_USB_REQTYPE_VENDOR | GRUB_USB_REQTYPE_OUT, + GRUB_USB_REQTYPE_CLASS_INTERFACE_IN = GRUB_USB_REQTYPE_TARGET_INTERF + | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_IN, + GRUB_USB_REQTYPE_VENDOR_IN = GRUB_USB_REQTYPE_VENDOR | GRUB_USB_REQTYPE_IN + }; #define GRUB_USB_REQ_GET_STATUS 0x00 #define GRUB_USB_REQ_CLEAR_FEATURE 0x01 From ff62c48f5a8f2b35ab73eca078e5c5aed4755eb6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 21 Aug 2010 23:09:37 +0200 Subject: [PATCH 35/64] Use status change pipe for hub hotplug detection --- bus/usb/usbhub.c | 112 +++++++++++++++++++++++++++++++++++----- bus/usb/usbtrans.c | 8 +++ include/grub/usb.h | 10 ++++ include/grub/usbtrans.h | 57 +++++++++++++------- term/usb_keyboard.c | 12 +++++ 5 files changed, 167 insertions(+), 32 deletions(-) diff --git a/bus/usb/usbhub.c b/bus/usb/usbhub.c index 7f2c8d24b..111a2495e 100644 --- a/bus/usb/usbhub.c +++ b/bus/usb/usbhub.c @@ -177,16 +177,16 @@ grub_usb_add_hub (grub_usb_device_t dev) grub_dprintf ("usb", "Hub port %d status: 0x%02x\n", i, status); /* If connected, reset and enable the port. */ - if (status & GRUB_USB_HUB_STATUS_CONNECTED) + if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) { grub_usb_speed_t speed; /* Determine the device speed. */ - if (status & GRUB_USB_HUB_STATUS_LOWSPEED) + if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) speed = GRUB_USB_SPEED_LOW; else { - if (status & GRUB_USB_HUB_STATUS_HIGHSPEED) + if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED) speed = GRUB_USB_SPEED_HIGH; else speed = GRUB_USB_SPEED_FULL; @@ -231,7 +231,7 @@ grub_usb_add_hub (grub_usb_device_t dev) | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_TARGET_OTHER), GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_CONNECTED, + GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, i, 0, 0); /* Just ignore the device if the Hub reports some error */ if (err) @@ -252,6 +252,25 @@ grub_usb_add_hub (grub_usb_device_t dev) } } + for (i = 0; i < dev->config[0].interf[0].descif->endpointcnt; + i++) + { + struct grub_usb_desc_endp *endp = NULL; + endp = &dev->config[0].interf[0].descendp[i]; + + if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp) + == GRUB_USB_EP_INTERRUPT) + { + dev->hub_endpoint = endp; + dev->hub_transfer + = grub_usb_bulk_read_background (dev, endp->endp_addr, + grub_min (endp->maxpacket, + sizeof (dev->statuschange)), + (char *) &dev->statuschange); + break; + } + } + return GRUB_ERR_NONE; } @@ -341,6 +360,9 @@ detach_device (grub_usb_device_t dev) return; if (dev->descdev.class == GRUB_USB_CLASS_HUB) { + if (dev->hub_transfer) + grub_usb_cancel_transfer (dev->hub_transfer); + for (i = 0; i < dev->nports; i++) detach_device (dev->children[i]); grub_free (dev->children); @@ -364,41 +386,105 @@ poll_nonroot_hub (grub_usb_device_t dev) grub_uint64_t timeout; grub_usb_device_t next_dev; grub_usb_device_t *attached_devices = dev->children; - + grub_uint8_t changed; + grub_size_t actual; + + if (!dev->hub_transfer) + return; + + err = grub_usb_check_transfer (dev->hub_transfer, &actual); + + if (err == GRUB_USB_ERR_WAIT) + return; + + changed = dev->statuschange; + + dev->hub_transfer + = grub_usb_bulk_read_background (dev, dev->hub_endpoint->endp_addr, + grub_min (dev->hub_endpoint->maxpacket, + sizeof (dev->statuschange)), + (char *) &dev->statuschange); + + if (err || actual == 0 || changed == 0) + return; + + grub_dprintf ("usb", "statuschanged = %02x, err = %d, actual = %d\n", + changed, err, actual); + /* Iterate over the Hub ports. */ for (i = 1; i <= dev->nports; i++) { grub_uint32_t status; + if (!(changed & (1 << i))) + continue; + /* Get the port status. */ err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_TARGET_OTHER), GRUB_USB_REQ_GET_STATUS, 0, i, sizeof (status), (char *) &status); - /* Just ignore the device if the Hub does not report the - status. */ + if (err) continue; - if (status & GRUB_USB_HUB_STATUS_C_CONNECTED) + /* FIXME: properly handle these conditions. */ + if (status & GRUB_USB_HUB_STATUS_C_PORT_RESET) + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_RESET, i, 0, 0); + + if (status & GRUB_USB_HUB_STATUS_C_PORT_ENABLED) + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_ENABLED, i, 0, 0); + + if (status & GRUB_USB_HUB_STATUS_C_PORT_SUSPEND) + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_SUSPEND, i, 0, 0); + + if (status & GRUB_USB_HUB_STATUS_C_PORT_OVERCURRENT) + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_OVERCURRENT, i, 0, 0); + + if (!(status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED)) + continue; + + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, i, 0, 0); + + if (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED) { detach_device (attached_devices[i-1]); attached_devices[i - 1] = NULL; } /* Connected and status of connection changed ? */ - if ((status & GRUB_USB_HUB_STATUS_CONNECTED) - && (status & GRUB_USB_HUB_STATUS_C_CONNECTED)) + if ((status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) + && (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED)) { grub_usb_speed_t speed; /* Determine the device speed. */ - if (status & GRUB_USB_HUB_STATUS_LOWSPEED) + if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) speed = GRUB_USB_SPEED_LOW; else { - if (status & GRUB_USB_HUB_STATUS_HIGHSPEED) + if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED) speed = GRUB_USB_SPEED_HIGH; else speed = GRUB_USB_SPEED_FULL; @@ -442,7 +528,7 @@ poll_nonroot_hub (grub_usb_device_t dev) | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_TARGET_OTHER), GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_CONNECTED, + GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, i, 0, 0); /* Just ignore the device if the Hub reports some error */ if (err) diff --git a/bus/usb/usbtrans.c b/bus/usb/usbtrans.c index 7e6840083..fe55114c7 100644 --- a/bus/usb/usbtrans.c +++ b/bus/usb/usbtrans.c @@ -392,6 +392,14 @@ grub_usb_bulk_read_background (grub_usb_device_t dev, return transfer; } +void +grub_usb_cancel_transfer (grub_usb_transfer_t transfer) +{ + grub_usb_device_t dev = transfer->dev; + dev->controller.dev->cancel_transfer (&dev->controller, transfer); + grub_errno = GRUB_ERR_NONE; +} + grub_usb_err_t grub_usb_bulk_read_extended (grub_usb_device_t dev, int endpoint, grub_size_t size, char *data, diff --git a/include/grub/usb.h b/include/grub/usb.h index 315ae9455..f9cdb2765 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -181,11 +181,19 @@ struct grub_usb_device /* Used by libusb wrapper. Schedulded for removal. */ void *data; + /* Hub information. */ + /* Array of children for a hub. */ grub_usb_device_t *children; /* Number of hub ports. */ unsigned nports; + + grub_usb_transfer_t hub_transfer; + + grub_uint32_t statuschange; + + struct grub_usb_desc_endp *hub_endpoint; }; @@ -271,5 +279,7 @@ grub_usb_bulk_read_background (grub_usb_device_t dev, int endpoint, grub_size_t size, void *data); grub_usb_err_t grub_usb_check_transfer (grub_usb_transfer_t trans, grub_size_t *actual); +void +grub_usb_cancel_transfer (grub_usb_transfer_t trans); #endif /* GRUB_USB_H */ diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index ae2fd1bc4..9e9d75e5d 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -94,31 +94,50 @@ enum GRUB_USB_REQTYPE_VENDOR_IN = GRUB_USB_REQTYPE_VENDOR | GRUB_USB_REQTYPE_IN }; -#define GRUB_USB_REQ_GET_STATUS 0x00 -#define GRUB_USB_REQ_CLEAR_FEATURE 0x01 -#define GRUB_USB_REQ_SET_FEATURE 0x03 -#define GRUB_USB_REQ_SET_ADDRESS 0x05 -#define GRUB_USB_REQ_GET_DESCRIPTOR 0x06 -#define GRUB_USB_REQ_SET_DESCRIPTOR 0x07 -#define GRUB_USB_REQ_GET_CONFIGURATION 0x08 -#define GRUB_USB_REQ_SET_CONFIGURATION 0x09 -#define GRUB_USB_REQ_GET_INTERFACE 0x0A -#define GRUB_USB_REQ_SET_INTERFACE 0x0B -#define GRUB_USB_REQ_SYNC_FRAME 0x0C +enum + { + GRUB_USB_REQ_GET_STATUS = 0x00, + GRUB_USB_REQ_CLEAR_FEATURE = 0x01, + GRUB_USB_REQ_SET_FEATURE = 0x03, + GRUB_USB_REQ_SET_ADDRESS = 0x05, + GRUB_USB_REQ_GET_DESCRIPTOR = 0x06, + GRUB_USB_REQ_SET_DESCRIPTOR = 0x07, + GRUB_USB_REQ_GET_CONFIGURATION = 0x08, + GRUB_USB_REQ_SET_CONFIGURATION = 0x09, + GRUB_USB_REQ_GET_INTERFACE = 0x0A, + GRUB_USB_REQ_SET_INTERFACE = 0x0B, + GRUB_USB_REQ_SYNC_FRAME = 0x0C + }; #define GRUB_USB_FEATURE_ENDP_HALT 0x00 #define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 #define GRUB_USB_FEATURE_TEST_MODE 0x02 -#define GRUB_USB_HUB_FEATURE_PORT_RESET 0x04 -#define GRUB_USB_HUB_FEATURE_PORT_POWER 0x08 -#define GRUB_USB_HUB_FEATURE_C_CONNECTED 0x10 +enum + { + GRUB_USB_HUB_FEATURE_PORT_RESET = 0x04, + GRUB_USB_HUB_FEATURE_PORT_POWER = 0x08, + GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED = 0x10, + GRUB_USB_HUB_FEATURE_C_PORT_ENABLED = 0x11, + GRUB_USB_HUB_FEATURE_C_PORT_SUSPEND = 0x12, + GRUB_USB_HUB_FEATURE_C_PORT_OVERCURRENT = 0x13, + GRUB_USB_HUB_FEATURE_C_PORT_RESET = 0x14 + }; -#define GRUB_USB_HUB_STATUS_CONNECTED (1 << 0) -#define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9) -#define GRUB_USB_HUB_STATUS_HIGHSPEED (1 << 10) -#define GRUB_USB_HUB_STATUS_C_CONNECTED (1 << 16) -#define GRUB_USB_HUB_STATUS_C_PORT_RESET (1 << 20) +enum + { + GRUB_USB_HUB_STATUS_PORT_CONNECTED = (1 << 0), + GRUB_USB_HUB_STATUS_PORT_ENABLED = (1 << 1), + GRUB_USB_HUB_STATUS_PORT_SUSPEND = (1 << 2), + GRUB_USB_HUB_STATUS_PORT_OVERCURRENT = (1 << 3), + GRUB_USB_HUB_STATUS_PORT_LOWSPEED = (1 << 9), + GRUB_USB_HUB_STATUS_PORT_HIGHSPEED = (1 << 10), + GRUB_USB_HUB_STATUS_C_PORT_CONNECTED = (1 << 16), + GRUB_USB_HUB_STATUS_C_PORT_ENABLED = (1 << 17), + GRUB_USB_HUB_STATUS_C_PORT_SUSPEND = (1 << 18), + GRUB_USB_HUB_STATUS_C_PORT_OVERCURRENT = (1 << 19), + GRUB_USB_HUB_STATUS_C_PORT_RESET = (1 << 20) + }; struct grub_usb_packet_setup { diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index e9be331cf..ea13418e0 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -107,6 +107,9 @@ grub_usb_keyboard_detach (grub_usb_device_t usbdev, if (data->usbdev != usbdev) continue; + if (data->transfer) + grub_usb_cancel_transfer (data->transfer); + grub_term_unregister_input (&grub_usb_keyboards[i]); grub_free ((char *) grub_usb_keyboards[i].name); grub_usb_keyboards[i].name = NULL; @@ -351,9 +354,18 @@ GRUB_MOD_FINI(usb_keyboard) for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++) if (grub_usb_keyboards[i].data) { + struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data; + + if (!data) + continue; + + if (data->transfer) + grub_usb_cancel_transfer (data->transfer); + grub_term_unregister_input (&grub_usb_keyboards[i]); grub_free ((char *) grub_usb_keyboards[i].name); grub_usb_keyboards[i].name = NULL; + grub_free (grub_usb_keyboards[i].data); grub_usb_keyboards[i].data = 0; } grub_usb_unregister_attach_hook_class (&attach_hook); From ab247a453f02a2eb0f02d35b6950d26cf6eb327b Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 00:01:21 +0200 Subject: [PATCH 36/64] Ignore keyboard errors and track numlock status --- term/usb_keyboard.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index fc1435c05..759b3eb7d 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -99,8 +99,21 @@ static grub_uint8_t usb_to_at_map[128] = /* 0x7e */ 0x00, 0x00, }; -#define CAPS_LOCK 0x39 -#define CAPS_LOCK_LED 0x02 +enum + { + KEY_NO_KEY = 0x00, + KEY_ERR_BUFFER = 0x01, + KEY_ERR_POST = 0x02, + KEY_ERR_UNDEF = 0x03, + KEY_CAPS_LOCK = 0x39, + KEY_NUM_LOCK = 0x53, + }; + +enum + { + LED_NUM_LOCK = 0x01, + LED_CAPS_LOCK = 0x02 + }; /* Valid values for bRequest. See HID definition version 1.11 section 7.2. */ #define USB_HID_GET_REPORT 0x01 @@ -328,7 +341,9 @@ send_leds (struct grub_usb_keyboard_data *termdata) char report[1]; report[0] = 0; if (termdata->mods & GRUB_TERM_STATUS_CAPS) - report[0] |= CAPS_LOCK_LED; + report[0] |= LED_CAPS_LOCK; + if (termdata->mods & GRUB_TERM_STATUS_NUM) + report[0] |= LED_NUM_LOCK; grub_usb_control_msg (termdata->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, USB_HID_SET_REPORT, 0x0200, termdata->interfno, sizeof (report), (char *) report); @@ -380,18 +395,29 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) termdata->status = data[0]; - if (actual < 3 || !data[2]) + if (actual < 3) return -1; - if (data[2] == CAPS_LOCK) + if (data[2] == KEY_NO_KEY || data[2] == KEY_ERR_BUFFER + || data[2] == KEY_ERR_POST || data[2] == KEY_ERR_UNDEF) + return -1; + + if (data[2] == KEY_CAPS_LOCK) { termdata->mods ^= GRUB_TERM_STATUS_CAPS; send_leds (termdata); return -1; } - if (usb_to_at_map[data[2]] == 0) - grub_printf ("Unknown key 0x%x detected\n", data[2]); + if (data[2] == KEY_NUM_LOCK) + { + termdata->mods ^= GRUB_TERM_STATUS_NUM; + send_leds (termdata); + return -1; + } + + if (data[2] > ARRAY_SIZE (usb_to_at_map) || usb_to_at_map[data[2]] == 0) + grub_printf ("Unknown key 0x%02x detected\n", data[2]); else termdata->key = grub_term_map_key (usb_to_at_map[data[2]], interpret_status (data[0]) From 7e6975d7ea371b0cb6986fb028b21d2da5c93d35 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 00:29:34 +0200 Subject: [PATCH 37/64] Support USB key repeat --- include/grub/term.h | 3 +++ term/usb_keyboard.c | 24 ++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/grub/term.h b/include/grub/term.h index 009258f6e..9956398da 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -490,6 +490,9 @@ grub_print_spaces (struct grub_term_output *term, int number_spaces) extern void (*EXPORT_VAR (grub_term_poll_usb)) (void); +#define GRUB_TERM_REPEAT_PRE_INTERVAL 100 +#define GRUB_TERM_REPEAT_INTERVAL 50 + #endif /* ! ASM_FILE */ #endif /* ! GRUB_TERM_HEADER */ diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 759b3eb7d..c3af1694b 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -144,6 +144,8 @@ struct grub_usb_keyboard_data grub_usb_transfer_t transfer; grub_uint8_t report[8]; int dead; + int last_key; + grub_uint64_t repeat_time; }; static struct grub_term_input grub_usb_keyboards[16]; @@ -368,7 +370,16 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) err = grub_usb_check_transfer (termdata->transfer, &actual); if (err == GRUB_USB_ERR_WAIT) - return -1; + { + if (termdata->last_key != -1 + && grub_get_time_ms () > termdata->repeat_time) + { + termdata->key = termdata->last_key; + termdata->repeat_time = grub_get_time_ms () + + GRUB_TERM_REPEAT_INTERVAL; + } + return termdata->key; + } grub_memcpy (data, termdata->report, sizeof (data)); @@ -382,6 +393,7 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) termdata->dead = 1; } + termdata->last_key = -1; grub_dprintf ("usb_keyboard", "err = %d, actual = %d report: 0x%02x 0x%02x 0x%02x 0x%02x" @@ -419,9 +431,13 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) if (data[2] > ARRAY_SIZE (usb_to_at_map) || usb_to_at_map[data[2]] == 0) grub_printf ("Unknown key 0x%02x detected\n", data[2]); else - termdata->key = grub_term_map_key (usb_to_at_map[data[2]], - interpret_status (data[0]) - | termdata->mods); + { + termdata->last_key = termdata->key + = grub_term_map_key (usb_to_at_map[data[2]], + interpret_status (data[0]) | termdata->mods); + termdata->repeat_time = grub_get_time_ms () + + GRUB_TERM_REPEAT_PRE_INTERVAL; + } grub_errno = GRUB_ERR_NONE; From 7209c54e91d35c69789e774bc29b597cdd37f93e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 00:31:43 +0200 Subject: [PATCH 38/64] Set last_key to -1 at init time --- term/usb_keyboard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index c3af1694b..3dfe5331b 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -326,12 +326,12 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) return 0; } + data->last_key = -1; data->mods = 0; + data->dead = 0; grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]); - data->dead = 0; - return 1; } From c2994de1349f7135118853b2250fccd9a867b9bc Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 00:57:04 +0200 Subject: [PATCH 39/64] Add back accidently removed mov --- kern/i386/pc/startup.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index ef5904bb2..f78fb5baa 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1214,7 +1214,6 @@ FUNCTION(grub_console_getkey) shrl $8, %eax orl $GRUB_TERM_EXTENDED, %eax 2: - popl %ebp ret @@ -1248,12 +1247,15 @@ FUNCTION(grub_console_checkkey) DATA32 jmp pending notpending: + xorl %edx, %edx decl %edx pending: DATA32 call real_to_prot .code32 + movl %edx, %eax + popl %ebp ret From 96157c5378112658d062a1b654fd008d7edce9ce Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 01:01:31 +0200 Subject: [PATCH 40/64] Increase pre-repeat usb keyboad interval --- include/grub/term.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/grub/term.h b/include/grub/term.h index 9956398da..bfe1c8f9b 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -490,7 +490,7 @@ grub_print_spaces (struct grub_term_output *term, int number_spaces) extern void (*EXPORT_VAR (grub_term_poll_usb)) (void); -#define GRUB_TERM_REPEAT_PRE_INTERVAL 100 +#define GRUB_TERM_REPEAT_PRE_INTERVAL 400 #define GRUB_TERM_REPEAT_INTERVAL 50 #endif /* ! ASM_FILE */ From 49c822bc42eb215d168ee87cc1644a8a625b173a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 02:17:14 +0200 Subject: [PATCH 41/64] Support numpad --- commands/keylayouts.c | 52 +++++++++++++++++++++++++++++++++++++++++-- term/at_keyboard.c | 8 +++++-- term/usb_keyboard.c | 30 ++++++++++++------------- 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index d2cb0e1e7..3442d42e7 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -106,13 +106,61 @@ map_key_core (int code, int status, int *alt_gr_consumed) return grub_current_layout->keyboard_map[code]; } +static int +map_high_key (int code, int status) +{ + int ret = 0; + if (status & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT)) + ret |= GRUB_TERM_SHIFT; + + if (code == 0xb5) + return '/'; + + if (code == 0xb7) + return '*'; + + if (code == 0x9c) + return '\n'; + + if (code < 0xc7 || code > 0xd3 || code == 0xca || code == 0xce + || code == 0xcc) + return ret; + /* GRUB keyboard codes are conveniently similar to AT codes. */ + return ret | GRUB_TERM_EXTENDED | (code & ~0x80); +} + +static int +map_num_key (int code, int state) +{ + const int map_arrows[] + = { GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_UP, GRUB_TERM_KEY_PPAGE, + '-', GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, '+', + GRUB_TERM_KEY_END, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_NPAGE, + GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC }; + const int map_nums[] + = { '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.'}; + + if (((state & GRUB_TERM_STATUS_NUM) + && !(state & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT))) + || ((state & GRUB_TERM_STATUS_NUM) + && !(state & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT)))) + return map_nums [code - 0x47]; + else + return map_arrows [code - 0x47]; +} + unsigned grub_term_map_key (int code, int status) { - int alt_gr_consumed; + int alt_gr_consumed = 0; int key; - key = map_key_core (code, status, &alt_gr_consumed); + if (code >= 0x47 && code <= 0x53) + key = map_num_key (code, status); + else if (code & 0x80) + key = map_high_key (code, status); + else + key = map_key_core (code, status, &alt_gr_consumed); if (key == 0 || key == GRUB_TERM_SHIFT) grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code); diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 054dc9805..c98fc8255 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -110,7 +110,6 @@ grub_keyboard_isr (grub_uint8_t key) at_keyboard_status &= ~GRUB_TERM_STATUS_LALT; break; } - extended_pending = (key == 0xe0); } /* If there is a raw key pending, return it; otherwise return -1. */ @@ -118,13 +117,18 @@ static int grub_keyboard_getkey (void) { grub_uint8_t key; + grub_uint8_t ret; if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) return -1; key = grub_inb (KEYBOARD_REG_DATA); /* FIXME */ grub_keyboard_isr (key); + ret = KEYBOARD_SCANCODE (key); + if (extended_pending) + ret |= 0x80; + extended_pending = (key == 0xe0); if (! KEYBOARD_ISMAKE (key)) return -1; - return (KEYBOARD_SCANCODE (key)); + return ret; } diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 3dfe5331b..1082e62d0 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -69,20 +69,20 @@ static grub_uint8_t usb_to_at_map[128] = /* 0x42 */ 0x43 /* F9 */, 0x44 /* F10 */, /* 0x44 */ 0x57 /* F11 */, 0x58 /* F12 */, /* 0x46 */ 0x00, 0x00, - /* 0x48 */ 0x00, 0x52 /* Insert */, - /* 0x4a */ 0x47 /* HOME */, 0x51 /* PPAGE */, - /* 0x4c */ 0x53 /* DC */, 0x4f /* END */, - /* 0x4e */ 0x49 /* NPAGE */, 0x4d /* RIGHT */, - /* 0x50 */ 0x4b /* LEFT */, 0x50 /* DOWN */, - /* 0x52 */ 0x48 /* UP */, 0x00, - /* 0x54 */ 0x00, 0x00, - /* 0x56 */ 0x00, 0x00, - /* 0x58 */ 0x00, 0x00, - /* 0x5a */ 0x00, 0x00, - /* 0x5c */ 0x00, 0x00, - /* 0x5e */ 0x00, 0x00, - /* 0x60 */ 0x00, 0x00, - /* 0x62 */ 0x00, 0x00, + /* 0x48 */ 0x00, 0xd2 /* Insert */, + /* 0x4a */ 0xc7 /* HOME */, 0xd1 /* PPAGE */, + /* 0x4c */ 0xd3 /* DC */, 0xcf /* END */, + /* 0x4e */ 0xc9 /* NPAGE */, 0xcd /* RIGHT */, + /* 0x50 */ 0xcb /* LEFT */, 0xd0 /* DOWN */, + /* 0x52 */ 0xc8 /* UP */, 0x00, + /* 0x54 */ 0xb5 /* Num / */, 0xb7 /* Num * */, + /* 0x56 */ 0x4a /* Num - */, 0x4e /* Num + */, + /* 0x58 */ 0x9c /* Num \n */, 0x4f /* Num 1 */, + /* 0x5a */ 0x50 /* Num 2 */, 0x51 /* Num 3 */, + /* 0x5c */ 0x4b /* Num 4 */, 0x4c /* Num 5 */, + /* 0x5e */ 0x4d /* Num 6 */, 0x47 /* Num 7 */, + /* 0x60 */ 0x48 /* Num 8 */, 0x49 /* Num 9 */, + /* 0x62 */ 0x52 /* Num 0 */, 0x53 /* Num . */, /* 0x64 */ 0x56 /* 102nd key. */, 0x00, /* 0x66 */ 0x00, 0x00, /* 0x68 */ 0x00, 0x00, @@ -428,7 +428,7 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) return -1; } - if (data[2] > ARRAY_SIZE (usb_to_at_map) || usb_to_at_map[data[2]] == 0) + if (data[2] >= ARRAY_SIZE (usb_to_at_map) || usb_to_at_map[data[2]] == 0) grub_printf ("Unknown key 0x%02x detected\n", data[2]); else { From c32f26bce85ec1ba5bc3a2c01ced4b2f10f00705 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 16:06:09 +0200 Subject: [PATCH 42/64] Make USB the main keylayout for simplicity --- commands/keylayouts.c | 194 ++++++++++++++++---------------- include/grub/at_keyboard.h | 12 -- include/grub/atkeymap.h | 111 ++++++++++++++++++ include/grub/keyboard_layouts.h | 2 +- term/at_keyboard.c | 6 +- term/usb_keyboard.c | 83 +------------- util/grub-mklayout.c | 152 ++++++++++++++++--------- 7 files changed, 321 insertions(+), 239 deletions(-) create mode 100644 include/grub/atkeymap.h diff --git a/commands/keylayouts.c b/commands/keylayouts.c index 3442d42e7..c68919aef 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -30,39 +30,96 @@ static struct grub_keyboard_layout layout_us = { .keyboard_map = { - /* 0x00 */ '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', - /* 0x08 */ '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, - /* 0x10 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - /* 0x18 */ 'o', 'p', '[', ']', '\n', '\0', 'a', 's', - /* 0x20 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - /* 0x28 */ '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', - /* 0x30 */ 'b', 'n', 'm', ',', '.', '/', '\0', '*', - /* 0x38 */ '\0', ' ', '\0', GRUB_TERM_KEY_F1, - /* 0x3c */ GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, - /* 0x3e */ GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, - /* 0x40 */ GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, - /* 0x42 */ GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, - /* 0x44 */ GRUB_TERM_KEY_F10, '\0', '\0', GRUB_TERM_KEY_HOME, - /* 0x48 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_NPAGE, '-', GRUB_TERM_KEY_LEFT, - /* 0x4c */ GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, - /* 0x4e */ '+', GRUB_TERM_KEY_END, - /* 0x50 */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_PPAGE, - /* 0x52 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, - /* 0x54 */ '\0', '\0', '\\', GRUB_TERM_KEY_F11, - /* 0x58 */ GRUB_TERM_KEY_F12, '\0', '\0', '\0', '\0', '\0', '\0', '\0', - /* 0x60 */ '\0', '\0', '\0', '\0', - /* 0x64 */ '\0', GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_LEFT, - /* 0x68 */ GRUB_TERM_KEY_RIGHT + /* Keyboard errors. Handled by driver. */ + /* 0x00 */ 0, 0, 0, 0, + + /* 0x04 */ 'a', 'b', 'c', 'd', + /* 0x08 */ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + /* 0x10 */ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + /* 0x18 */ 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', + /* 0x20 */ '3', '4', '5', '6', '7', '8', '9', '0', + /* 0x28 */ '\n', '\e', '\b', '\t', ' ', '-', '=', '[', + /* According to usage table 0x31 should be mapped to '/' + but testing with real keyboard shows that 0x32 is remapped to '/'. + Map 0x31 to 0. + */ + /* 0x30 */ ']', 0, '\\', ';', '\'', '`', ',', '.', + /* 0x39 is CapsLock. Handled by driver. */ + /* 0x38 */ '/', 0, GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, + /* 0x3c */ GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, + /* 0x3e */ GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6, + /* 0x40 */ GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, + /* 0x42 */ GRUB_TERM_KEY_F9, GRUB_TERM_KEY_F10, + /* 0x44 */ GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, + /* PrtScr and ScrollLock. Not handled yet. */ + /* 0x46 */ 0, 0, + /* 0x48 is Pause. Not handled yet. */ + /* 0x48 */ 0, GRUB_TERM_KEY_INSERT, + /* 0x4a */ GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, + /* 0x4c */ GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, + /* 0x4e */ GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, + /* 0x50 */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, + /* 0x53 is NumLock. Handled by driver. */ + /* 0x52 */ GRUB_TERM_KEY_UP, 0, + /* 0x54 */ '/', '*', + /* 0x56 */ '-', '+', + /* 0x58 */ '\n', GRUB_TERM_KEY_END, + /* 0x5a */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_NPAGE, + /* 0x5c */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_CENTER, + /* 0x5e */ GRUB_TERM_KEY_RIGHT, GRUB_TERM_KEY_HOME, + /* 0x60 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_PPAGE, + /* 0x62 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, + /* 0x64 */ '\\' }, .keyboard_map_shift = { - '\0', '\0', '!', '@', '#', '$', '%', '^', - '&', '*', '(', ')', '_', '+', '\0', '\0', - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', - 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', - '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?', - [0x56] = '|' + /* Keyboard errors. Handled by driver. */ + /* 0x00 */ 0, 0, 0, 0, + + /* 0x04 */ 'A', 'B', 'C', 'D', + /* 0x08 */ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + /* 0x10 */ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + /* 0x18 */ 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', + /* 0x20 */ '#', '$', '%', '^', '&', '*', '(', ')', + /* 0x28 */ '\n' | GRUB_TERM_SHIFT, '\e' | GRUB_TERM_SHIFT, + /* 0x2a */ '\b' | GRUB_TERM_SHIFT, '\t' | GRUB_TERM_SHIFT, + /* 0x2c */ ' ' | GRUB_TERM_SHIFT, '_', '+', '{', + /* According to usage table 0x31 should be mapped to '/' + but testing with real keyboard shows that 0x32 is remapped to '/'. + Map 0x31 to 0. + */ + /* 0x30 */ '}', 0, '|', ':', '"', '~', '<', '>', + /* 0x39 is CapsLock. Handled by driver. */ + /* 0x38 */ '?', 0, + /* 0x3a */ GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT, + /* 0x3b */ GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT, + /* 0x3c */ GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT, + /* 0x3d */ GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT, + /* 0x3e */ GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT, + /* 0x3f */ GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT, + /* 0x40 */ GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT, + /* 0x41 */ GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT, + /* 0x42 */ GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT, + /* 0x43 */ GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT, + /* 0x44 */ GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT, + /* 0x45 */ GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT, + /* PrtScr and ScrollLock. Not handled yet. */ + /* 0x46 */ 0, 0, + /* 0x48 is Pause. Not handled yet. */ + /* 0x48 */ 0, GRUB_TERM_KEY_INSERT | GRUB_TERM_SHIFT, + /* 0x4a */ GRUB_TERM_KEY_HOME | GRUB_TERM_SHIFT, + /* 0x4b */ GRUB_TERM_KEY_PPAGE | GRUB_TERM_SHIFT, + /* 0x4c */ GRUB_TERM_KEY_DC | GRUB_TERM_SHIFT, + /* 0x4d */ GRUB_TERM_KEY_END | GRUB_TERM_SHIFT, + /* 0x4e */ GRUB_TERM_KEY_NPAGE | GRUB_TERM_SHIFT, + /* 0x4f */ GRUB_TERM_KEY_RIGHT | GRUB_TERM_SHIFT, + /* 0x50 */ GRUB_TERM_KEY_LEFT | GRUB_TERM_SHIFT, + /* 0x51 */ GRUB_TERM_KEY_DOWN | GRUB_TERM_SHIFT, + /* 0x53 is NumLock. Handled by driver. */ + /* 0x52 */ GRUB_TERM_KEY_UP | GRUB_TERM_SHIFT, 0, + /* 0x54 */ '/', '*', + /* 0x56 */ '-', '+', + /* 0x58 */ '\n' | GRUB_TERM_SHIFT, '1', '2', '3', '4', '5','6', '7', + /* 0x60 */ '8', '9', '0', '.', '|' } }; @@ -82,88 +139,37 @@ map_key_core (int code, int status, int *alt_gr_consumed) *alt_gr_consumed = 1; return grub_current_layout->keyboard_map_shift_l3[code]; } - else if (grub_current_layout->keyboard_map_shift[code]) - { - *alt_gr_consumed = 1; - return grub_current_layout->keyboard_map_l3[code] - | GRUB_TERM_SHIFT; - } } - else if (grub_current_layout->keyboard_map_shift[code]) + else if (grub_current_layout->keyboard_map_l3[code]) { *alt_gr_consumed = 1; return grub_current_layout->keyboard_map_l3[code]; } } if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) - { - if (grub_current_layout->keyboard_map_shift[code]) - return grub_current_layout->keyboard_map_shift[code]; - else - return grub_current_layout->keyboard_map[code] | GRUB_TERM_SHIFT; - } + return grub_current_layout->keyboard_map_shift[code]; else return grub_current_layout->keyboard_map[code]; } -static int -map_high_key (int code, int status) -{ - int ret = 0; - if (status & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT)) - ret |= GRUB_TERM_SHIFT; - - if (code == 0xb5) - return '/'; - - if (code == 0xb7) - return '*'; - - if (code == 0x9c) - return '\n'; - - if (code < 0xc7 || code > 0xd3 || code == 0xca || code == 0xce - || code == 0xcc) - return ret; - /* GRUB keyboard codes are conveniently similar to AT codes. */ - return ret | GRUB_TERM_EXTENDED | (code & ~0x80); -} - -static int -map_num_key (int code, int state) -{ - const int map_arrows[] - = { GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_UP, GRUB_TERM_KEY_PPAGE, - '-', GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_CENTER, GRUB_TERM_KEY_RIGHT, '+', - GRUB_TERM_KEY_END, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_NPAGE, - GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC }; - const int map_nums[] - = { '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.'}; - - if (((state & GRUB_TERM_STATUS_NUM) - && !(state & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT))) - || ((state & GRUB_TERM_STATUS_NUM) - && !(state & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT)))) - return map_nums [code - 0x47]; - else - return map_arrows [code - 0x47]; -} - unsigned grub_term_map_key (int code, int status) { int alt_gr_consumed = 0; int key; - if (code >= 0x47 && code <= 0x53) - key = map_num_key (code, status); - else if (code & 0x80) - key = map_high_key (code, status); - else - key = map_key_core (code, status, &alt_gr_consumed); + if (code >= 0x59 && code <= 0x63 && (status & GRUB_TERM_STATUS_NUM)) + { + if (status & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT)) + status &= ~(GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT); + else + status |= GRUB_TERM_STATUS_RSHIFT; + } + + key = map_key_core (code, status, &alt_gr_consumed); if (key == 0 || key == GRUB_TERM_SHIFT) - grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code); + grub_printf ("Unknown key 0x%x detected\n", code); if (status & GRUB_TERM_STATUS_CAPS) { diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 10421540a..350ce3bf9 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -39,16 +39,4 @@ #define KEYBOARD_ISREADY(x) ((x) & 0x01) #define KEYBOARD_SCANCODE(x) ((x) & 0x7f) -#ifdef GRUB_MACHINE_IEEE1275 -#define OLPC_UP GRUB_TERM_UP -#define OLPC_DOWN GRUB_TERM_DOWN -#define OLPC_LEFT GRUB_TERM_LEFT -#define OLPC_RIGHT GRUB_TERM_RIGHT -#else -#define OLPC_UP '\0' -#define OLPC_DOWN '\0' -#define OLPC_LEFT '\0' -#define OLPC_RIGHT '\0' -#endif - #endif diff --git a/include/grub/atkeymap.h b/include/grub/atkeymap.h new file mode 100644 index 000000000..a8b9140ff --- /dev/null +++ b/include/grub/atkeymap.h @@ -0,0 +1,111 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_AT_KEYMAP_HEADER +#define GRUB_AT_KEYMAP_HEADER 1 + +static inline int +grub_at_map_to_usb (grub_uint8_t keycode) +{ + /* Modifier keys (ctrl, alt, shift, capslock, numlock and scrolllock + are handled by driver and hence here are mapped to 0)*/ + + static const grub_uint8_t at_to_usb_map[] = + { + /* 0x00 */ 0x00 /* Unused */, 0x29 /* Escape */, + /* 0x02 */ 0x1e /* 1 */, 0x1f /* 2 */, + /* 0x04 */ 0x20 /* 3 */, 0x21 /* 4 */, + /* 0x06 */ 0x22 /* 5 */, 0x23 /* 6 */, + /* 0x08 */ 0x24 /* 7 */, 0x25 /* 8 */, + /* 0x0a */ 0x26 /* 9 */, 0x27 /* 0 */, + /* 0x0c */ 0x2d /* - */, 0x2e /* = */, + /* 0x0e */ 0x2a /* \b */, 0x2b /* \t */, + /* 0x10 */ 0x14 /* q */, 0x1a /* w */, + /* 0x12 */ 0x08 /* e */, 0x15 /* r */, + /* 0x14 */ 0x17 /* t */, 0x1c /* y */, + /* 0x16 */ 0x18 /* u */, 0x0c /* i */, + /* 0x18 */ 0x12 /* o */, 0x13 /* p */, + /* 0x1a */ 0x2f /* [ */, 0x30 /* ] */, + /* 0x1c */ 0x28 /* Enter */, 0x00 /* Left CTRL */, + /* 0x1e */ 0x04 /* a */, 0x16 /* s */, + /* 0x20 */ 0x07 /* d */, 0x09 /* f */, + /* 0x22 */ 0x0a /* g */, 0x0b /* h */, + /* 0x24 */ 0x0d /* j */, 0x0e /* k */, + /* 0x26 */ 0x0f /* l */, 0x33 /* ; */, + /* 0x28 */ 0x34 /* " */, 0x35 /* ` */, + /* 0x2a */ 0x00 /* Left Shift */, 0x32 /* \ */, + /* 0x2c */ 0x1d /* z */, 0x1b /* x */, + /* 0x2e */ 0x06 /* c */, 0x19 /* v */, + /* 0x30 */ 0x05 /* b */, 0x11 /* n */, + /* 0x32 */ 0x10 /* m */, 0x36 /* , */, + /* 0x34 */ 0x37 /* . */, 0x38 /* / */, + /* 0x36 */ 0x00 /* Right Shift */, 0x55 /* Num * */, + /* 0x38 */ 0x00 /* Left ALT */, 0x2c /* Space */, + /* 0x3a */ 0x39 /* Caps Lock */, 0x3a /* F1 */, + /* 0x3c */ 0x3b /* F2 */, 0x3c /* F3 */, + /* 0x3e */ 0x3d /* F4 */, 0x3e /* F5 */, + /* 0x40 */ 0x3f /* F6 */, 0x40 /* F7 */, + /* 0x42 */ 0x41 /* F8 */, 0x42 /* F9 */, + /* 0x44 */ 0x43 /* F10 */, 0x53 /* NumLock */, + /* 0x46 */ 0x47 /* Scroll Lock */, 0x5f /* Num 7 */, + /* 0x48 */ 0x60 /* Num 8 */, 0x61 /* Num 9 */, + /* 0x4a */ 0x56 /* Num - */, 0x5c /* Num 4 */, + /* 0x4c */ 0x5d /* Num 5 */, 0x5e /* Num 6 */, + /* 0x4e */ 0x57 /* Num + */, 0x59 /* Num 1 */, + /* 0x50 */ 0x5a /* Num 2 */, 0x5b /* Num 3 */, + /* 0x52 */ 0x62 /* Num 0 */, 0x63 /* Num . */, + /* 0x54 */ 0x00, 0x00, + /* 0x56 */ 0x64 /* 102nd key. */, 0x44 /* F11 */, + /* 0x58 */ 0x45 /* F12 */, 0x00 + }; + + static const struct + { + grub_uint8_t from, to; + } at_to_usb_extended[] = + { + /* OLPC keys. Just mapped to normal keys. */ + {0x65, 0x52 /* Up */ }, + {0x66, 0x51 /* Down */ }, + {0x67, 0x50 /* Left */ }, + {0x68, 0x4f /* Right */ }, + + {0x9c, 0x58 /* Num \n */}, + {0xb5, 0x54 /* Num / */ }, + {0xc7, 0x4a /* Home */ }, + {0xc8, 0x52 /* Up */ }, + {0xc9, 0x4e /* NPage */ }, + {0xcb, 0x50 /* Left */ }, + {0xcd, 0x4f /* Right */ }, + {0xcf, 0x4d /* End */ }, + {0xd0, 0x51 /* Down */ }, + {0xd1, 0x4b /* PPage */ }, + {0xd2, 0x49 /* Insert */}, + {0xd3, 0x4c /* DC */ }, + }; + if (keycode >= ARRAY_SIZE (at_to_usb_map)) + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (at_to_usb_extended); i++) + if (at_to_usb_extended[i].from == keycode) + return at_to_usb_extended[i].to; + return 0; + } + return at_to_usb_map[keycode]; +} +#endif diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index f1d2fb282..b562d671e 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -21,7 +21,7 @@ #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) -#define GRUB_KEYBOARD_LAYOUTS_VERSION 6 +#define GRUB_KEYBOARD_LAYOUTS_VERSION 7 #define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 128 diff --git a/term/at_keyboard.c b/term/at_keyboard.c index c98fc8255..f8595a41a 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -23,6 +23,7 @@ #include #include #include +#include static short at_keyboard_status = 0; static int extended_pending = 0; @@ -123,6 +124,8 @@ grub_keyboard_getkey (void) key = grub_inb (KEYBOARD_REG_DATA); /* FIXME */ grub_keyboard_isr (key); ret = KEYBOARD_SCANCODE (key); + if (ret == SHIFT_L || ret == SHIFT_R || ret == ALT || ret == CTRL) + return -1; if (extended_pending) ret |= 0x80; extended_pending = (key == 0xe0); @@ -175,7 +178,8 @@ grub_at_keyboard_getkey_noblock (void) keyboard_controller_led (led_status); return -1; default: - return grub_term_map_key (code, at_keyboard_status); + return grub_term_map_key (grub_at_map_to_usb (code), + at_keyboard_status); } } diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index 1082e62d0..b57b171f8 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -29,76 +29,6 @@ -static grub_uint8_t usb_to_at_map[128] = -{ - /* 0x00 */ 0x00, 0x00, - /* 0x02 */ 0x00, 0x00, - /* 0x04 */ 0x1e /* a */, 0x30 /* b */, - /* 0x06 */ 0x2e /* c */, 0x20 /* d */, - /* 0x08 */ 0x12 /* e */, 0x21 /* f */, - /* 0x0a */ 0x22 /* g */, 0x23 /* h */, - /* 0x0c */ 0x17 /* i */, 0x24 /* j */, - /* 0x0e */ 0x25 /* k */, 0x26 /* l */, - /* 0x10 */ 0x32 /* m */, 0x31 /* n */, - /* 0x12 */ 0x18 /* o */, 0x19 /* p */, - /* 0x14 */ 0x10 /* q */, 0x13 /* r */, - /* 0x16 */ 0x1f /* s */, 0x14 /* t */, - /* 0x18 */ 0x16 /* u */, 0x2f /* v */, - /* 0x1a */ 0x11 /* w */, 0x2d /* x */, - /* 0x1c */ 0x15 /* y */, 0x2c /* z */, - /* 0x1e */ 0x02 /* 1 */, 0x03 /* 2 */, - /* 0x20 */ 0x04 /* 3 */, 0x05 /* 4 */, - /* 0x22 */ 0x06 /* 5 */, 0x07 /* 6 */, - /* 0x24 */ 0x08 /* 7 */, 0x09 /* 8 */, - /* 0x26 */ 0x0a /* 9 */, 0x0b /* 0 */, - /* 0x28 */ 0x1c /* Enter */, 0x01 /* Escape */, - /* 0x2a */ 0x0e /* \b */, 0x0f /* \t */, - /* 0x2c */ 0x39 /* Space */, 0x0c /* - */, - /* 0x2e */ 0x0d /* = */, 0x1a /* [ */, - /* According to usage table 0x31 should be remapped to 0x2b - but testing with real keyboard shows that 0x32 is remapped to 0x2b. */ - /* 0x30 */ 0x1b /* ] */, 0x00, - /* 0x32 */ 0x2b /* \ */, 0x27 /* ; */, - /* 0x34 */ 0x28 /* " */, 0x29 /* ` */, - /* 0x36 */ 0x33 /* , */, 0x34 /* . */, - /* 0x38 */ 0x35 /* / */, 0x00, - /* 0x3a */ 0x3b /* F1 */, 0x3c /* F2 */, - /* 0x3c */ 0x3d /* F3 */, 0x3e /* F4 */, - /* 0x3e */ 0x3f /* F5 */, 0x40 /* F6 */, - /* 0x40 */ 0x41 /* F7 */, 0x42 /* F8 */, - /* 0x42 */ 0x43 /* F9 */, 0x44 /* F10 */, - /* 0x44 */ 0x57 /* F11 */, 0x58 /* F12 */, - /* 0x46 */ 0x00, 0x00, - /* 0x48 */ 0x00, 0xd2 /* Insert */, - /* 0x4a */ 0xc7 /* HOME */, 0xd1 /* PPAGE */, - /* 0x4c */ 0xd3 /* DC */, 0xcf /* END */, - /* 0x4e */ 0xc9 /* NPAGE */, 0xcd /* RIGHT */, - /* 0x50 */ 0xcb /* LEFT */, 0xd0 /* DOWN */, - /* 0x52 */ 0xc8 /* UP */, 0x00, - /* 0x54 */ 0xb5 /* Num / */, 0xb7 /* Num * */, - /* 0x56 */ 0x4a /* Num - */, 0x4e /* Num + */, - /* 0x58 */ 0x9c /* Num \n */, 0x4f /* Num 1 */, - /* 0x5a */ 0x50 /* Num 2 */, 0x51 /* Num 3 */, - /* 0x5c */ 0x4b /* Num 4 */, 0x4c /* Num 5 */, - /* 0x5e */ 0x4d /* Num 6 */, 0x47 /* Num 7 */, - /* 0x60 */ 0x48 /* Num 8 */, 0x49 /* Num 9 */, - /* 0x62 */ 0x52 /* Num 0 */, 0x53 /* Num . */, - /* 0x64 */ 0x56 /* 102nd key. */, 0x00, - /* 0x66 */ 0x00, 0x00, - /* 0x68 */ 0x00, 0x00, - /* 0x6a */ 0x00, 0x00, - /* 0x6c */ 0x00, 0x00, - /* 0x6e */ 0x00, 0x00, - /* 0x70 */ 0x00, 0x00, - /* 0x72 */ 0x00, 0x00, - /* 0x74 */ 0x00, 0x00, - /* 0x76 */ 0x00, 0x00, - /* 0x78 */ 0x00, 0x00, - /* 0x7a */ 0x00, 0x00, - /* 0x7c */ 0x00, 0x00, - /* 0x7e */ 0x00, 0x00, -}; - enum { KEY_NO_KEY = 0x00, @@ -428,16 +358,9 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) return -1; } - if (data[2] >= ARRAY_SIZE (usb_to_at_map) || usb_to_at_map[data[2]] == 0) - grub_printf ("Unknown key 0x%02x detected\n", data[2]); - else - { - termdata->last_key = termdata->key - = grub_term_map_key (usb_to_at_map[data[2]], - interpret_status (data[0]) | termdata->mods); - termdata->repeat_time = grub_get_time_ms () - + GRUB_TERM_REPEAT_PRE_INTERVAL; - } + termdata->last_key = termdata->key + = grub_term_map_key (data[2], interpret_status (data[0]) | termdata->mods); + termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_PRE_INTERVAL; grub_errno = GRUB_ERR_NONE; diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index 91dea87a6..3aafd8837 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -47,19 +47,47 @@ struct console_grub_equivalence grub_uint32_t grub; }; -static struct console_grub_equivalence console_grub_equivalences[] = { +static struct console_grub_equivalence console_grub_equivalences_shift[] = { + {"KP_0", '0'}, + {"KP_1", '1'}, + {"KP_2", '2'}, + {"KP_3", '3'}, + {"KP_4", '4'}, + {"KP_5", '5'}, + {"KP_6", '6'}, + {"KP_7", '7'}, + {"KP_8", '8'}, + {"KP_9", '9'}, + {"KP_Period", '.'}, +}; + +static struct console_grub_equivalence console_grub_equivalences_unshift[] = { + {"KP_0", GRUB_TERM_KEY_INSERT}, + {"KP_1", GRUB_TERM_KEY_END}, + {"KP_2", GRUB_TERM_KEY_DOWN}, + {"KP_3", GRUB_TERM_KEY_NPAGE}, + {"KP_4", GRUB_TERM_KEY_LEFT}, + {"KP_5", GRUB_TERM_KEY_CENTER}, + {"KP_6", GRUB_TERM_KEY_RIGHT}, + {"KP_7", GRUB_TERM_KEY_HOME}, + {"KP_8", GRUB_TERM_KEY_UP}, + {"KP_9", GRUB_TERM_KEY_PPAGE}, + {"KP_Period", GRUB_TERM_KEY_DC}, +}; + +static struct console_grub_equivalence console_grub_equivalences_common[] = { {"Escape", GRUB_TERM_ESC}, {"Tab", GRUB_TERM_TAB}, {"Delete", GRUB_TERM_BACKSPACE}, + {"KP_Enter", '\n'}, + {"Return", '\n'}, + {"KP_Multiply", '*'}, {"KP_Subtract", '-'}, {"KP_Add", '+'}, {"KP_Divide", '/'}, - {"KP_Enter", '\n'}, - {"Return", '\n'}, - {"F1", GRUB_TERM_KEY_F1}, {"F2", GRUB_TERM_KEY_F2}, {"F3", GRUB_TERM_KEY_F3}, @@ -116,6 +144,9 @@ static struct console_grub_equivalence console_grub_equivalences[] = { {"End", GRUB_TERM_KEY_END}, {"Right", GRUB_TERM_KEY_RIGHT}, {"Left", GRUB_TERM_KEY_LEFT}, + {"Next", GRUB_TERM_KEY_NPAGE}, + {"Prior", GRUB_TERM_KEY_PPAGE}, + {"Remove", GRUB_TERM_KEY_DC}, {"VoidSymbol", 0}, /* "Undead" keys since no dead key support in GRUB. */ @@ -132,24 +163,8 @@ static struct console_grub_equivalence console_grub_equivalences[] = { {"dead_breve", 0}, {"dead_doubleacute", 0}, - /* NumLock not supported yet. */ - {"KP_0", GRUB_TERM_KEY_INSERT}, - {"KP_1", GRUB_TERM_KEY_END}, - {"KP_2", GRUB_TERM_KEY_DOWN}, - {"KP_3", GRUB_TERM_KEY_NPAGE}, - {"KP_4", GRUB_TERM_KEY_LEFT}, - {"KP_5", 0}, - {"KP_6", GRUB_TERM_KEY_RIGHT}, - {"KP_7", GRUB_TERM_KEY_HOME}, - {"KP_8", GRUB_TERM_KEY_UP}, - {"KP_9", GRUB_TERM_KEY_PPAGE}, - {"KP_Period", GRUB_TERM_KEY_DC}, - /* Unused in GRUB. */ {"Pause", 0}, - {"Remove", 0}, - {"Next", 0}, - {"Prior", 0}, {"Scroll_Forward", 0}, {"Scroll_Backward", 0}, {"Hex_0", 0}, @@ -174,16 +189,6 @@ static struct console_grub_equivalence console_grub_equivalences[] = { {"Control_backslash", 0}, {"Compose", 0}, - /* Keys currently not remappable. */ - {"CtrlL_Lock", 0}, - {"Caps_Lock", 0}, - {"ShiftL", 0}, - {"Num_Lock", 0}, - {"Alt", 0}, - {"AltGr", 0}, - {"Control", 0}, - {"Shift", 0}, - {NULL, '\0'} }; @@ -205,24 +210,30 @@ Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); exit (status); } -void +static void add_special_keys (struct grub_keyboard_layout *layout) { - /* OLPC keys. */ - layout->keyboard_map[101] = GRUB_TERM_KEY_UP; - layout->keyboard_map[102] = GRUB_TERM_KEY_DOWN; - layout->keyboard_map[103] = GRUB_TERM_KEY_LEFT; - layout->keyboard_map[104] = GRUB_TERM_KEY_RIGHT; + (void) layout; } static unsigned -lookup (char *code) +lookup (char *code, int shift) { int i; + struct console_grub_equivalence *pr; - for (i = 0; console_grub_equivalences[i].layout != NULL; i++) - if (strcmp (code, console_grub_equivalences[i].layout) == 0) - return console_grub_equivalences[i].grub; + if (shift) + pr = console_grub_equivalences_shift; + else + pr = console_grub_equivalences_unshift; + + for (i = 0; pr[i].layout != NULL; i++) + if (strcmp (code, pr[i].layout) == 0) + return pr[i].grub; + + for (i = 0; console_grub_equivalences_common[i].layout != NULL; i++) + if (strcmp (code, console_grub_equivalences_common[i].layout) == 0) + return console_grub_equivalences_common[i].grub; fprintf (stderr, "Unknown key %s\n", code); @@ -230,7 +241,7 @@ lookup (char *code) } static unsigned int -get_grub_code (char *layout_code) +get_grub_code (char *layout_code, int shift) { unsigned int code; @@ -239,7 +250,7 @@ get_grub_code (char *layout_code) else if (strncmp (layout_code, "+U+", sizeof ("+U+") - 1) == 0) sscanf (layout_code, "+U+%x", &code); else - code = lookup (layout_code); + code = lookup (layout_code, shift); return code; } @@ -287,21 +298,60 @@ write_keymaps (FILE *in, FILE *out) { if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0) { - unsigned keycode; + unsigned keycode_at, orig; + unsigned keycode_usb; char normal[64]; char shift[64]; char normalalt[64]; char shiftalt[64]; + static grub_uint8_t e0_remap[] = { + 0x9c /* Num \n */, 0x9d /* Right CTRL */, 0xb5 /* Num / */, + 0, 0xb8 /* Right ALT */, 0, + 0xc7 /* Home */, 0xc8 /* Up */, 0xc9 /* NPage*/, 0xcb /* Left */, + 0xcd /* Right */, 0xcf /* End */, 0xd0 /* Down */, 0xd1 /* PPage */, + 0xd2 /* Insert */, 0xd3 /* Delete */ + }; - sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode, + sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode_at, normal, shift, normalalt, shiftalt); - if (keycode < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) + orig = keycode_at; + + /* Not used. */ + if (keycode_at == 0x77 /* Pause */ + /* Some obscure keys */ + || keycode_at == 0x63 || keycode_at == 0x7d || keycode_at == 0x7e) + continue; + + if (keycode_at >= 96 && keycode_at < 96 + ARRAY_SIZE (e0_remap)) + keycode_at = e0_remap[keycode_at - 96]; + + /* Not remappable. */ + if (keycode_at == 0x1d /* Left CTRL */ + || keycode_at == 0x9d /* Right CTRL */ + || keycode_at == 0x2a /* Left Shift. */ + || keycode_at == 0x36 /* Right Shift. */ + || keycode_at == 0x38 /* Left ALT. */ + || keycode_at == 0xb8 /* Right ALT. */ + || keycode_at == 0x3a /* CapsLock. */ + || keycode_at == 0x45 /* NumLock. */ + || keycode_at == 0x46 /* ScrollLock. */) + continue; + + keycode_usb = grub_at_map_to_usb (keycode_at); + if (keycode_usb == 0 + || keycode_usb >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) { - layout.keyboard_map[keycode] = get_grub_code (normal); - layout.keyboard_map_shift[keycode] = get_grub_code (shift); - layout.keyboard_map_l3[keycode] = get_grub_code (normalalt); - layout.keyboard_map_shift_l3[keycode] - = get_grub_code (shiftalt); + fprintf (stderr, "Unknown keycode 0x%02x\n", orig); + continue; + } + if (keycode_usb < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) + { + layout.keyboard_map[keycode_usb] = get_grub_code (normal, 0); + layout.keyboard_map_shift[keycode_usb] = get_grub_code (shift, 1); + layout.keyboard_map_l3[keycode_usb] + = get_grub_code (normalalt, 0); + layout.keyboard_map_shift_l3[keycode_usb] + = get_grub_code (shiftalt, 1); ok = 1; } } From 6e05e7f0f869af96ecb95b6d021b46f7e15c28c9 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 17:44:03 +0200 Subject: [PATCH 43/64] Properly handle extended_pending --- term/at_keyboard.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 2b7dd9bee..4213b29db 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -122,13 +122,21 @@ grub_keyboard_getkey (void) if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) return -1; key = grub_inb (KEYBOARD_REG_DATA); + if (key == 0xe0) + { + extended_pending = 1; + return -1; + } /* FIXME */ grub_keyboard_isr (key); ret = KEYBOARD_SCANCODE (key); if (ret == SHIFT_L || ret == SHIFT_R || ret == ALT || ret == CTRL) - return -1; + { + extended_pending = 0; + return -1; + } if (extended_pending) ret |= 0x80; - extended_pending = (key == 0xe0); + extended_pending = 0; if (! KEYBOARD_ISMAKE (key)) return -1; return ret; From f582367ecff67c616b5631331812d87ed5e67fdf Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 18:15:27 +0200 Subject: [PATCH 44/64] Set the leds and drain the input buffer in at_keyboard initialisation --- term/at_keyboard.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 4213b29db..06d545d74 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -223,6 +223,11 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus at_keyboard_status = 0; grub_keyboard_controller_orig = grub_keyboard_controller_read (); grub_keyboard_controller_write (grub_keyboard_controller_orig | KEYBOARD_SCANCODE_SET1); + keyboard_controller_led (led_status); + /* Drain input buffer. */ + while (KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + grub_inb (KEYBOARD_REG_DATA); + return GRUB_ERR_NONE; } From efc3e75f4d7006767be912b82761674f0814b08c Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 18:16:16 +0200 Subject: [PATCH 45/64] Bump keylayouts version --- include/grub/keyboard_layouts.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index b562d671e..2f352a752 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -21,7 +21,7 @@ #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" #define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) -#define GRUB_KEYBOARD_LAYOUTS_VERSION 7 +#define GRUB_KEYBOARD_LAYOUTS_VERSION 8 #define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 128 From 5ea70ca5fabac085dc19caa490efd718882878ee Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 22:53:31 +0200 Subject: [PATCH 46/64] Support scancode set 2 --- include/grub/at_keyboard.h | 10 +- include/grub/atkeymap.h | 111 --------- include/grub/keyboard_layouts.h | 15 +- term/at_keyboard.c | 386 ++++++++++++++++++++++++++------ util/grub-mklayout.c | 102 ++++++--- 5 files changed, 410 insertions(+), 214 deletions(-) delete mode 100644 include/grub/atkeymap.h diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 350ce3bf9..6e0806bdb 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -19,21 +19,13 @@ #ifndef GRUB_AT_KEYBOARD_HEADER #define GRUB_AT_KEYBOARD_HEADER 1 -#define SHIFT_L 0x2a -#define SHIFT_R 0x36 -#define CTRL 0x1d -#define ALT 0x38 -#define CAPS_LOCK 0x3a -#define NUM_LOCK 0x45 -#define SCROLL_LOCK 0x46 - /* Used for sending commands to the controller. */ #define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) #define KEYBOARD_COMMAND_READ 0x20 #define KEYBOARD_COMMAND_WRITE 0x60 #define KEYBOARD_COMMAND_REBOOT 0xfe -#define KEYBOARD_SCANCODE_SET1 0x40 +#define KEYBOARD_AT_TRANSLATE 0x40 #define KEYBOARD_ISMAKE(x) !((x) & 0x80) #define KEYBOARD_ISREADY(x) ((x) & 0x01) diff --git a/include/grub/atkeymap.h b/include/grub/atkeymap.h deleted file mode 100644 index a8b9140ff..000000000 --- a/include/grub/atkeymap.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_AT_KEYMAP_HEADER -#define GRUB_AT_KEYMAP_HEADER 1 - -static inline int -grub_at_map_to_usb (grub_uint8_t keycode) -{ - /* Modifier keys (ctrl, alt, shift, capslock, numlock and scrolllock - are handled by driver and hence here are mapped to 0)*/ - - static const grub_uint8_t at_to_usb_map[] = - { - /* 0x00 */ 0x00 /* Unused */, 0x29 /* Escape */, - /* 0x02 */ 0x1e /* 1 */, 0x1f /* 2 */, - /* 0x04 */ 0x20 /* 3 */, 0x21 /* 4 */, - /* 0x06 */ 0x22 /* 5 */, 0x23 /* 6 */, - /* 0x08 */ 0x24 /* 7 */, 0x25 /* 8 */, - /* 0x0a */ 0x26 /* 9 */, 0x27 /* 0 */, - /* 0x0c */ 0x2d /* - */, 0x2e /* = */, - /* 0x0e */ 0x2a /* \b */, 0x2b /* \t */, - /* 0x10 */ 0x14 /* q */, 0x1a /* w */, - /* 0x12 */ 0x08 /* e */, 0x15 /* r */, - /* 0x14 */ 0x17 /* t */, 0x1c /* y */, - /* 0x16 */ 0x18 /* u */, 0x0c /* i */, - /* 0x18 */ 0x12 /* o */, 0x13 /* p */, - /* 0x1a */ 0x2f /* [ */, 0x30 /* ] */, - /* 0x1c */ 0x28 /* Enter */, 0x00 /* Left CTRL */, - /* 0x1e */ 0x04 /* a */, 0x16 /* s */, - /* 0x20 */ 0x07 /* d */, 0x09 /* f */, - /* 0x22 */ 0x0a /* g */, 0x0b /* h */, - /* 0x24 */ 0x0d /* j */, 0x0e /* k */, - /* 0x26 */ 0x0f /* l */, 0x33 /* ; */, - /* 0x28 */ 0x34 /* " */, 0x35 /* ` */, - /* 0x2a */ 0x00 /* Left Shift */, 0x32 /* \ */, - /* 0x2c */ 0x1d /* z */, 0x1b /* x */, - /* 0x2e */ 0x06 /* c */, 0x19 /* v */, - /* 0x30 */ 0x05 /* b */, 0x11 /* n */, - /* 0x32 */ 0x10 /* m */, 0x36 /* , */, - /* 0x34 */ 0x37 /* . */, 0x38 /* / */, - /* 0x36 */ 0x00 /* Right Shift */, 0x55 /* Num * */, - /* 0x38 */ 0x00 /* Left ALT */, 0x2c /* Space */, - /* 0x3a */ 0x39 /* Caps Lock */, 0x3a /* F1 */, - /* 0x3c */ 0x3b /* F2 */, 0x3c /* F3 */, - /* 0x3e */ 0x3d /* F4 */, 0x3e /* F5 */, - /* 0x40 */ 0x3f /* F6 */, 0x40 /* F7 */, - /* 0x42 */ 0x41 /* F8 */, 0x42 /* F9 */, - /* 0x44 */ 0x43 /* F10 */, 0x53 /* NumLock */, - /* 0x46 */ 0x47 /* Scroll Lock */, 0x5f /* Num 7 */, - /* 0x48 */ 0x60 /* Num 8 */, 0x61 /* Num 9 */, - /* 0x4a */ 0x56 /* Num - */, 0x5c /* Num 4 */, - /* 0x4c */ 0x5d /* Num 5 */, 0x5e /* Num 6 */, - /* 0x4e */ 0x57 /* Num + */, 0x59 /* Num 1 */, - /* 0x50 */ 0x5a /* Num 2 */, 0x5b /* Num 3 */, - /* 0x52 */ 0x62 /* Num 0 */, 0x63 /* Num . */, - /* 0x54 */ 0x00, 0x00, - /* 0x56 */ 0x64 /* 102nd key. */, 0x44 /* F11 */, - /* 0x58 */ 0x45 /* F12 */, 0x00 - }; - - static const struct - { - grub_uint8_t from, to; - } at_to_usb_extended[] = - { - /* OLPC keys. Just mapped to normal keys. */ - {0x65, 0x52 /* Up */ }, - {0x66, 0x51 /* Down */ }, - {0x67, 0x50 /* Left */ }, - {0x68, 0x4f /* Right */ }, - - {0x9c, 0x58 /* Num \n */}, - {0xb5, 0x54 /* Num / */ }, - {0xc7, 0x4a /* Home */ }, - {0xc8, 0x52 /* Up */ }, - {0xc9, 0x4e /* NPage */ }, - {0xcb, 0x50 /* Left */ }, - {0xcd, 0x4f /* Right */ }, - {0xcf, 0x4d /* End */ }, - {0xd0, 0x51 /* Down */ }, - {0xd1, 0x4b /* PPage */ }, - {0xd2, 0x49 /* Insert */}, - {0xd3, 0x4c /* DC */ }, - }; - if (keycode >= ARRAY_SIZE (at_to_usb_map)) - { - unsigned i; - for (i = 0; i < ARRAY_SIZE (at_to_usb_extended); i++) - if (at_to_usb_extended[i].from == keycode) - return at_to_usb_extended[i].to; - return 0; - } - return at_to_usb_map[keycode]; -} -#endif diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index 2f352a752..dd6631a51 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -33,6 +33,19 @@ struct grub_keyboard_layout grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; }; -unsigned EXPORT_FUNC(grub_term_map_key) (int code, int status); +typedef enum grub_keyboard_key + { + GRUB_KEYBOARD_KEY_CAPS_LOCK = 0x39, + GRUB_KEYBOARD_KEY_SCROLL_LOCK = 0x47, + GRUB_KEYBOARD_KEY_NUM_LOCK = 0x53, + GRUB_KEYBOARD_KEY_LEFT_CTRL = 0xe0, + GRUB_KEYBOARD_KEY_LEFT_SHIFT = 0xe1, + GRUB_KEYBOARD_KEY_LEFT_ALT = 0xe2, + GRUB_KEYBOARD_KEY_RIGHT_CTRL = 0xe4, + GRUB_KEYBOARD_KEY_RIGHT_SHIFT = 0xe5, + GRUB_KEYBOARD_KEY_RIGHT_ALT = 0xe6, + } grub_keyboard_key_t; + +unsigned EXPORT_FUNC(grub_term_map_key) (grub_keyboard_key_t code, int status); #endif /* GRUB_KEYBOARD_LAYOUTS */ diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 06d545d74..00c6cef83 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -23,10 +23,10 @@ #include #include #include -#include static short at_keyboard_status = 0; -static int extended_pending = 0; +static int e0_received = 0; +static int f0_received = 0; static int pending_key = -1; static grub_uint8_t led_status; @@ -36,6 +36,145 @@ static grub_uint8_t led_status; #define KEYBOARD_LED_CAPS (1 << 2) static grub_uint8_t grub_keyboard_controller_orig; +static grub_uint8_t grub_keyboard_orig_set; +static grub_uint8_t current_set; + +static const grub_uint8_t set1_mapping[128] = + { + /* 0x00 */ 0x00 /* Unused */, 0x29 /* Escape */, + /* 0x02 */ 0x1e /* 1 */, 0x1f /* 2 */, + /* 0x04 */ 0x20 /* 3 */, 0x21 /* 4 */, + /* 0x06 */ 0x22 /* 5 */, 0x23 /* 6 */, + /* 0x08 */ 0x24 /* 7 */, 0x25 /* 8 */, + /* 0x0a */ 0x26 /* 9 */, 0x27 /* 0 */, + /* 0x0c */ 0x2d /* - */, 0x2e /* = */, + /* 0x0e */ 0x2a /* \b */, 0x2b /* \t */, + /* 0x10 */ 0x14 /* q */, 0x1a /* w */, + /* 0x12 */ 0x08 /* e */, 0x15 /* r */, + /* 0x14 */ 0x17 /* t */, 0x1c /* y */, + /* 0x16 */ 0x18 /* u */, 0x0c /* i */, + /* 0x18 */ 0x12 /* o */, 0x13 /* p */, + /* 0x1a */ 0x2f /* [ */, 0x30 /* ] */, + /* 0x1c */ 0x28 /* Enter */, 0xe0 /* Left CTRL */, + /* 0x1e */ 0x04 /* a */, 0x16 /* s */, + /* 0x20 */ 0x07 /* d */, 0x09 /* f */, + /* 0x22 */ 0x0a /* g */, 0x0b /* h */, + /* 0x24 */ 0x0d /* j */, 0x0e /* k */, + /* 0x26 */ 0x0f /* l */, 0x33 /* ; */, + /* 0x28 */ 0x34 /* " */, 0x35 /* ` */, + /* 0x2a */ 0xe1 /* Left Shift */, 0x32 /* \ */, + /* 0x2c */ 0x1d /* z */, 0x1b /* x */, + /* 0x2e */ 0x06 /* c */, 0x19 /* v */, + /* 0x30 */ 0x05 /* b */, 0x11 /* n */, + /* 0x32 */ 0x10 /* m */, 0x36 /* , */, + /* 0x34 */ 0x37 /* . */, 0x38 /* / */, + /* 0x36 */ 0xe5 /* Right Shift */, 0x55 /* Num * */, + /* 0x38 */ 0xe2 /* Left ALT */, 0x2c /* Space */, + /* 0x3a */ 0x39 /* Caps Lock */, 0x3a /* F1 */, + /* 0x3c */ 0x3b /* F2 */, 0x3c /* F3 */, + /* 0x3e */ 0x3d /* F4 */, 0x3e /* F5 */, + /* 0x40 */ 0x3f /* F6 */, 0x40 /* F7 */, + /* 0x42 */ 0x41 /* F8 */, 0x42 /* F9 */, + /* 0x44 */ 0x43 /* F10 */, 0x53 /* NumLock */, + /* 0x46 */ 0x47 /* Scroll Lock */, 0x5f /* Num 7 */, + /* 0x48 */ 0x60 /* Num 8 */, 0x61 /* Num 9 */, + /* 0x4a */ 0x56 /* Num - */, 0x5c /* Num 4 */, + /* 0x4c */ 0x5d /* Num 5 */, 0x5e /* Num 6 */, + /* 0x4e */ 0x57 /* Num + */, 0x59 /* Num 1 */, + /* 0x50 */ 0x5a /* Num 2 */, 0x5b /* Num 3 */, + /* 0x52 */ 0x62 /* Num 0 */, 0x63 /* Num . */, + /* 0x54 */ 0x00, 0x00, + /* 0x56 */ 0x64 /* 102nd key. */, 0x44 /* F11 */, + /* 0x58 */ 0x45 /* F12 */, 0x00, + /* 0x5a */ 0x00, 0x00, + /* 0x5c */ 0x00, 0x00, + /* 0x5e */ 0x00, 0x00, + /* 0x60 */ 0x00, 0x00, + /* 0x62 */ 0x00, 0x00, + /* OLPC keys. Just mapped to normal keys. */ + /* 0x64 */ 0x00, 0x52 /* Up */, + /* 0x66 */ 0x51 /* Down */, 0x50 /* Left */, + /* 0x68 */ 0x4f /* Right */ + }; + +static const struct +{ + grub_uint8_t from, to; +} set1_e0_mapping[] = + { + {0x1c, 0x58 /* Num \n */}, + {0x1d, 0xe4 /* Right CTRL */}, + {0x35, 0x54 /* Num / */ }, + {0x38, 0xe6 /* Right ALT */}, + {0x47, 0x4a /* Home */ }, + {0x48, 0x52 /* Up */ }, + {0x49, 0x4e /* NPage */ }, + {0x4b, 0x50 /* Left */ }, + {0x4d, 0x4f /* Right */ }, + {0x4f, 0x4d /* End */ }, + {0x50, 0x51 /* Down */ }, + {0x51, 0x4b /* PPage */ }, + {0x52, 0x49 /* Insert */}, + {0x53, 0x4c /* DC */ }, + }; + +static const grub_uint8_t set2_mapping[256] = + { + /* 0x00 */ 0x00, 0x42 /* F9 */, 0x00, 0x3e /* F5 */, + /* 0x04 */ 0x3c /* F3 */, 0x3a /* F1 */, 0x3b /* F2 */, 0x45 /* F12 */, + /* 0x08 */ 0x00, 0x43 /* F10 */, 0x41 /* F8 */, 0x3f /* F6 */, + /* 0x0c */ 0x3d /* F4 */, 0x2b /* \t */, 0x35 /* ` */, 0x00, + /* 0x10 */ 0x00, GRUB_KEYBOARD_KEY_LEFT_ALT, GRUB_KEYBOARD_KEY_LEFT_SHIFT, 0x00, + /* 0x14 */ GRUB_KEYBOARD_KEY_LEFT_CTRL, 0x14 /* q */, 0x1e /* 1 */, 0x00, + /* 0x18 */ 0x00, 0x00, 0x1d /* s */, 0x16 /* s */, + /* 0x1c */ 0x04 /* a */, 0x1a /* w */, 0x1f /* 2 */, 0x00, + /* 0x20 */ 0x00, 0x06 /* c */, 0x1b /* x */, 0x07 /* d */, + /* 0x24 */ 0x08 /* e */, 0x21 /* 4 */, 0x20 /* 3 */, 0x00, + /* 0x28 */ 0x00, 0x2c /* Space */, 0x19 /* v */, 0x09 /* f */, + /* 0x2c */ 0x17 /* t */, 0x15 /* r */, 0x22 /* 5 */, 0x00, + /* 0x30 */ 0x00, 0x11 /* n */, 0x05 /* b */, 0x0b /* h */, + /* 0x34 */ 0x0a /* g */, 0x1c /* y */, 0x23 /* 6 */, 0x00, + /* 0x38 */ 0x00, 0x00, 0x10 /* m */, 0x0d /* j */, + /* 0x3c */ 0x18 /* u */, 0x24 /* 7 */, 0x25 /* 8 */, 0x00, + /* 0x40 */ 0x00, 0x37 /* . */, 0x0e /* k */, 0x0c /* i */, + /* 0x44 */ 0x12 /* o */, 0x27 /* 0 */, 0x26 /* 9 */, 0x00, + /* 0x48 */ 0x00, 0x36 /* , */, 0x38 /* / */, 0x0f /* l */, + /* 0x4c */ 0x33 /* ; */, 0x13 /* p */, 0x2d /* - */, 0x00, + /* 0x50 */ 0x00, 0x00, 0x34 /* ' */, 0x00, + /* 0x54 */ 0x2f /* [ */, 0x2e /* = */, 0x00, 0x00, + /* 0x58 */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_RIGHT_SHIFT, 0x28 /* \n */,0x30 /* ] */, + /* 0x5c */ 0x00, 0x32 /* \ */, 0x00, 0x00, + /* 0x60 */ 0x00, 0x64 /* 102nd key. */, 0x00, 0x00, + /* 0x64 */ 0x00, 0x00, 0x2a /* \b */, 0x00, + /* 0x68 */ 0x00, 0x59 /* Num 1 */, 0x00, 0x5c /* Num 4 */, + /* 0x6c */ 0x5f /* Num 7 */, 0x00, 0x00, 0x00, + /* 0x70 */ 0x62 /* Num 0 */, 0x63 /* Num 0 */, 0x5a /* Num 2 */, 0x5d /* Num 5 */, + /* 0x74 */ 0x5e /* Num 6 */, 0x60 /* Num 8 */, 0x29 /* \e */, 0x53 /* NumLock */, + /* 0x78 */ 0x44 /* F11 */, 0x57 /* Num + */, 0x5b /* Num 3 */, 0x56 /* Num - */, + /* 0x7c */ 0x55 /* Num * */, 0x61 /* Num 9 */, 0x47 /* ScrollLock */, 0x00, + /* 0x80 */ 0x00, 0x00, 0x00, 0x40 /* F7 */, + }; + +static const struct +{ + grub_uint8_t from, to; +} set2_e0_mapping[] = + { + {0x11, GRUB_KEYBOARD_KEY_RIGHT_ALT}, + {0x14, GRUB_KEYBOARD_KEY_RIGHT_CTRL}, + {0x4a, 0x54}, /* Num / */ + {0x5a, 0x58}, /* Num enter */ + {0x69, 0x4d}, /* End */ + {0x6b, 0x50}, /* Left */ + {0x6c, 0x4a}, /* Home */ + {0x70, 0x49}, /* Insert */ + {0x71, 0x4c}, /* Delete */ + {0x72, 0x51}, /* Down */ + {0x74, 0x4f}, /* Right */ + {0x75, 0x52}, /* Up */ + {0x7a, 0x4e}, /* PageDown */ + {0x7d, 0x4b}, /* PageUp */ + }; static void keyboard_controller_wait_until_ready (void) @@ -51,6 +190,55 @@ grub_keyboard_controller_write (grub_uint8_t c) grub_outb (c, KEYBOARD_REG_DATA); } +static grub_uint8_t +query_mode (int mode) +{ + keyboard_controller_wait_until_ready (); + grub_outb (0xf0, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + grub_inb (KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + grub_outb (mode, KEYBOARD_REG_DATA); + + keyboard_controller_wait_until_ready (); + + return grub_inb (KEYBOARD_REG_DATA); +} + +/* QEMU translates the set even in no-translate mode. */ +static inline int +recover_mode (grub_uint8_t report) +{ + if (report == 0x43 || report == 1) + return 1; + if (report == 0x41 || report == 2) + return 2; + if (report == 0x3f || report == 3) + return 3; + return -1; +} + +static void +set_scancodes (void) +{ + grub_keyboard_controller_write (grub_keyboard_controller_orig + & ~KEYBOARD_AT_TRANSLATE); + grub_keyboard_orig_set = recover_mode (query_mode (0)); + + query_mode (2); + current_set = query_mode (0); + current_set = recover_mode (current_set); + if (current_set == 2) + return; + + query_mode (1); + current_set = query_mode (0); + current_set = recover_mode (current_set); + if (current_set == 1) + return; + grub_printf ("No supported scancode set found\n"); +} + static grub_uint8_t grub_keyboard_controller_read (void) { @@ -68,48 +256,126 @@ keyboard_controller_led (grub_uint8_t leds) grub_outb (leds & 0x7, KEYBOARD_REG_DATA); } +static int +fetch_key (int *is_break) +{ + int was_ext = 0; + grub_uint8_t at_key; + int ret = 0; + + if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + return -1; + at_key = grub_inb (KEYBOARD_REG_DATA); + if (at_key == 0xe0) + { + e0_received = 1; + return -1; + } + + was_ext = e0_received; + e0_received = 0; + + switch (current_set) + { + case 1: + *is_break = !!(at_key & 0x80); + if (!was_ext) + ret = set1_mapping[at_key & 0x7f]; + else + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (set1_e0_mapping); i++) + if (set1_e0_mapping[i].from == (at_key & 0x80)) + { + ret = set1_e0_mapping[i].to; + break; + } + } + break; + case 2: + if (at_key == 0xf0) + { + f0_received = 1; + return -1; + } + *is_break = f0_received; + f0_received = 0; + if (!was_ext) + ret = set2_mapping[at_key]; + else + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (set1_e0_mapping); i++) + if (set1_e0_mapping[i].from == (at_key & 0x80)) + { + ret = set1_e0_mapping[i].to; + break; + } + } + break; + default: + return -1; + } + if (!ret) + { + grub_printf ("Unknown key 0x%02x from set %d\n\n", at_key, current_set); + return -1; + } + return ret; +} + /* FIXME: This should become an interrupt service routine. For now it's just used to catch events from control keys. */ -static void -grub_keyboard_isr (grub_uint8_t key) +static int +grub_keyboard_isr (grub_keyboard_key_t key, int is_break) { - if (KEYBOARD_ISMAKE (key)) - switch (KEYBOARD_SCANCODE (key)) + if (!is_break) + switch (key) { - case SHIFT_L: - at_keyboard_status |= GRUB_TERM_STATUS_LSHIFT; - break; - case SHIFT_R: - at_keyboard_status |= GRUB_TERM_STATUS_RSHIFT; - break; - case CTRL: - at_keyboard_status |= GRUB_TERM_STATUS_LCTRL; - break; - case ALT: - if (extended_pending) - at_keyboard_status |= GRUB_TERM_STATUS_RALT; - else - at_keyboard_status |= GRUB_TERM_STATUS_LALT; - break; + case GRUB_KEYBOARD_KEY_LEFT_SHIFT: + at_keyboard_status |= GRUB_TERM_STATUS_LSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_SHIFT: + at_keyboard_status |= GRUB_TERM_STATUS_RSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_CTRL: + at_keyboard_status |= GRUB_TERM_STATUS_LCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_CTRL: + at_keyboard_status |= GRUB_TERM_STATUS_RCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_ALT: + at_keyboard_status |= GRUB_TERM_STATUS_RALT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_ALT: + at_keyboard_status |= GRUB_TERM_STATUS_LALT; + return 1; + default: + return 0; } else switch (KEYBOARD_SCANCODE (key)) { - case SHIFT_L: - at_keyboard_status &= ~GRUB_TERM_STATUS_LSHIFT; - break; - case SHIFT_R: - at_keyboard_status &= ~GRUB_TERM_STATUS_RSHIFT; - break; - case CTRL: - at_keyboard_status &= ~GRUB_TERM_STATUS_LCTRL; - break; - case ALT: - if (extended_pending) - at_keyboard_status &= ~GRUB_TERM_STATUS_RALT; - else - at_keyboard_status &= ~GRUB_TERM_STATUS_LALT; - break; + case GRUB_KEYBOARD_KEY_LEFT_SHIFT: + at_keyboard_status &= ~GRUB_TERM_STATUS_LSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_SHIFT: + at_keyboard_status &= ~GRUB_TERM_STATUS_RSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_CTRL: + at_keyboard_status &= ~GRUB_TERM_STATUS_LCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_CTRL: + at_keyboard_status &= ~GRUB_TERM_STATUS_RCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_ALT: + at_keyboard_status &= ~GRUB_TERM_STATUS_RALT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_ALT: + at_keyboard_status &= ~GRUB_TERM_STATUS_LALT; + return 1; + default: + return 0; } } @@ -117,31 +383,19 @@ grub_keyboard_isr (grub_uint8_t key) static int grub_keyboard_getkey (void) { - grub_uint8_t key; - grub_uint8_t ret; - if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) - return -1; - key = grub_inb (KEYBOARD_REG_DATA); - if (key == 0xe0) - { - extended_pending = 1; - return -1; - } - /* FIXME */ grub_keyboard_isr (key); - ret = KEYBOARD_SCANCODE (key); - if (ret == SHIFT_L || ret == SHIFT_R || ret == ALT || ret == CTRL) - { - extended_pending = 0; - return -1; - } - if (extended_pending) - ret |= 0x80; - extended_pending = 0; - if (! KEYBOARD_ISMAKE (key)) - return -1; - return ret; -} + int key; + int is_break; + key = fetch_key (&is_break); + if (key == -1) + return -1; + + if (grub_keyboard_isr (key, is_break)) + return -1; + if (is_break) + return -1; + return key; +} /* If there is a character pending, return it; otherwise return -1. */ static int @@ -156,7 +410,7 @@ grub_at_keyboard_getkey_noblock (void) #endif switch (code) { - case CAPS_LOCK: + case GRUB_KEYBOARD_KEY_CAPS_LOCK: at_keyboard_status ^= GRUB_TERM_STATUS_CAPS; led_status ^= KEYBOARD_LED_CAPS; keyboard_controller_led (led_status); @@ -165,7 +419,7 @@ grub_at_keyboard_getkey_noblock (void) grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK)); #endif return -1; - case NUM_LOCK: + case GRUB_KEYBOARD_KEY_NUM_LOCK: at_keyboard_status ^= GRUB_TERM_STATUS_NUM; led_status ^= KEYBOARD_LED_NUM; keyboard_controller_led (led_status); @@ -174,14 +428,13 @@ grub_at_keyboard_getkey_noblock (void) grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_NUM_LOCK)); #endif return -1; - case SCROLL_LOCK: + case GRUB_KEYBOARD_KEY_SCROLL_LOCK: at_keyboard_status ^= GRUB_TERM_STATUS_SCROLL; led_status ^= KEYBOARD_LED_SCROLL; keyboard_controller_led (led_status); return -1; default: - return grub_term_map_key (grub_at_map_to_usb (code), - at_keyboard_status); + return grub_term_map_key (code, at_keyboard_status); } } @@ -222,7 +475,7 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus pending_key = -1; at_keyboard_status = 0; grub_keyboard_controller_orig = grub_keyboard_controller_read (); - grub_keyboard_controller_write (grub_keyboard_controller_orig | KEYBOARD_SCANCODE_SET1); + set_scancodes (); keyboard_controller_led (led_status); /* Drain input buffer. */ while (KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) @@ -234,6 +487,7 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus static grub_err_t grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused))) { + query_mode (grub_keyboard_orig_set); grub_keyboard_controller_write (grub_keyboard_controller_orig); return GRUB_ERR_NONE; } diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index 3aafd8837..fc8ffb67a 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -192,6 +191,65 @@ static struct console_grub_equivalence console_grub_equivalences_common[] = { {NULL, '\0'} }; +static grub_uint8_t linux_to_usb_map[128] = { + /* 0x00 */ 0x00 /* Unused */, 0x29 /* Escape */, + /* 0x02 */ 0x1e /* 1 */, 0x1f /* 2 */, + /* 0x04 */ 0x20 /* 3 */, 0x21 /* 4 */, + /* 0x06 */ 0x22 /* 5 */, 0x23 /* 6 */, + /* 0x08 */ 0x24 /* 7 */, 0x25 /* 8 */, + /* 0x0a */ 0x26 /* 9 */, 0x27 /* 0 */, + /* 0x0c */ 0x2d /* - */, 0x2e /* = */, + /* 0x0e */ 0x2a /* \b */, 0x2b /* \t */, + /* 0x10 */ 0x14 /* q */, 0x1a /* w */, + /* 0x12 */ 0x08 /* e */, 0x15 /* r */, + /* 0x14 */ 0x17 /* t */, 0x1c /* y */, + /* 0x16 */ 0x18 /* u */, 0x0c /* i */, + /* 0x18 */ 0x12 /* o */, 0x13 /* p */, + /* 0x1a */ 0x2f /* [ */, 0x30 /* ] */, + /* 0x1c */ 0x28 /* Enter */, 0x00 /* Left CTRL */, + /* 0x1e */ 0x04 /* a */, 0x16 /* s */, + /* 0x20 */ 0x07 /* d */, 0x09 /* f */, + /* 0x22 */ 0x0a /* g */, 0x0b /* h */, + /* 0x24 */ 0x0d /* j */, 0x0e /* k */, + /* 0x26 */ 0x0f /* l */, 0x33 /* ; */, + /* 0x28 */ 0x34 /* " */, 0x35 /* ` */, + /* 0x2a */ 0x00 /* Left Shift */, 0x32 /* \ */, + /* 0x2c */ 0x1d /* z */, 0x1b /* x */, + /* 0x2e */ 0x06 /* c */, 0x19 /* v */, + /* 0x30 */ 0x05 /* b */, 0x11 /* n */, + /* 0x32 */ 0x10 /* m */, 0x36 /* , */, + /* 0x34 */ 0x37 /* . */, 0x38 /* / */, + /* 0x36 */ 0x00 /* Right Shift */, 0x55 /* Num * */, + /* 0x38 */ 0x00 /* Left ALT */, 0x2c /* Space */, + /* 0x3a */ 0x39 /* Caps Lock */, 0x3a /* F1 */, + /* 0x3c */ 0x3b /* F2 */, 0x3c /* F3 */, + /* 0x3e */ 0x3d /* F4 */, 0x3e /* F5 */, + /* 0x40 */ 0x3f /* F6 */, 0x40 /* F7 */, + /* 0x42 */ 0x41 /* F8 */, 0x42 /* F9 */, + /* 0x44 */ 0x43 /* F10 */, 0x53 /* NumLock */, + /* 0x46 */ 0x47 /* Scroll Lock */, 0x5f /* Num 7 */, + /* 0x48 */ 0x60 /* Num 8 */, 0x61 /* Num 9 */, + /* 0x4a */ 0x56 /* Num - */, 0x5c /* Num 4 */, + /* 0x4c */ 0x5d /* Num 5 */, 0x5e /* Num 6 */, + /* 0x4e */ 0x57 /* Num + */, 0x59 /* Num 1 */, + /* 0x50 */ 0x5a /* Num 2 */, 0x5b /* Num 3 */, + /* 0x52 */ 0x62 /* Num 0 */, 0x63 /* Num . */, + /* 0x54 */ 0x00, 0x00, + /* 0x56 */ 0x64 /* 102nd key. */, 0x44 /* F11 */, + /* 0x58 */ 0x45 /* F12 */, 0x00, + /* 0x5a */ 0x00, 0x00, + /* 0x5c */ 0x00, 0x00, + /* 0x5e */ 0x00, 0x00, + /* 0x60 */ 0x58 /* Num \n */, 0x00 /* Right CTRL */, + /* 0x62 */ 0x54 /* Num / */, 0x00, + /* 0x64 */ 0x00 /* Right ALT */, 0x00, + /* 0x66 */ 0x4a /* Home */, 0x52 /* Up */, + /* 0x68 */ 0x4e /* NPage */, 0x50 /* Left */, + /* 0x6a */ 0x4f /* Right */, 0x4d /* End */, + /* 0x6c */ 0x51 /* Down */, 0x4b /* PPage */, + /* 0x6e */ 0x49 /* Insert */, 0x4c /* DC */ +}; + static void usage (int status) { @@ -298,50 +356,40 @@ write_keymaps (FILE *in, FILE *out) { if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0) { - unsigned keycode_at, orig; + unsigned keycode_linux; unsigned keycode_usb; char normal[64]; char shift[64]; char normalalt[64]; char shiftalt[64]; - static grub_uint8_t e0_remap[] = { - 0x9c /* Num \n */, 0x9d /* Right CTRL */, 0xb5 /* Num / */, - 0, 0xb8 /* Right ALT */, 0, - 0xc7 /* Home */, 0xc8 /* Up */, 0xc9 /* NPage*/, 0xcb /* Left */, - 0xcd /* Right */, 0xcf /* End */, 0xd0 /* Down */, 0xd1 /* PPage */, - 0xd2 /* Insert */, 0xd3 /* Delete */ - }; - sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode_at, + sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode_linux, normal, shift, normalalt, shiftalt); - orig = keycode_at; /* Not used. */ - if (keycode_at == 0x77 /* Pause */ + if (keycode_linux == 0x77 /* Pause */ /* Some obscure keys */ - || keycode_at == 0x63 || keycode_at == 0x7d || keycode_at == 0x7e) + || keycode_linux == 0x63 || keycode_linux == 0x7d + || keycode_linux == 0x7e) continue; - if (keycode_at >= 96 && keycode_at < 96 + ARRAY_SIZE (e0_remap)) - keycode_at = e0_remap[keycode_at - 96]; - /* Not remappable. */ - if (keycode_at == 0x1d /* Left CTRL */ - || keycode_at == 0x9d /* Right CTRL */ - || keycode_at == 0x2a /* Left Shift. */ - || keycode_at == 0x36 /* Right Shift. */ - || keycode_at == 0x38 /* Left ALT. */ - || keycode_at == 0xb8 /* Right ALT. */ - || keycode_at == 0x3a /* CapsLock. */ - || keycode_at == 0x45 /* NumLock. */ - || keycode_at == 0x46 /* ScrollLock. */) + if (keycode_linux == 0x1d /* Left CTRL */ + || keycode_linux == 0x9d /* Right CTRL */ + || keycode_linux == 0x2a /* Left Shift. */ + || keycode_linux == 0x36 /* Right Shift. */ + || keycode_linux == 0x38 /* Left ALT. */ + || keycode_linux == 0xb8 /* Right ALT. */ + || keycode_linux == 0x3a /* CapsLock. */ + || keycode_linux == 0x45 /* NumLock. */ + || keycode_linux == 0x46 /* ScrollLock. */) continue; - keycode_usb = grub_at_map_to_usb (keycode_at); + keycode_usb = linux_to_usb_map[keycode_linux]; if (keycode_usb == 0 || keycode_usb >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) { - fprintf (stderr, "Unknown keycode 0x%02x\n", orig); + fprintf (stderr, "Unknown keycode 0x%02x\n", keycode_linux); continue; } if (keycode_usb < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) From 09206dc3d09f29c8dcb2af30b1001ba56e0b9bf4 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 22 Aug 2010 23:56:41 +0200 Subject: [PATCH 47/64] Macroify key constants --- include/grub/keyboard_layouts.h | 99 +++++++++++- term/at_keyboard.c | 257 ++++++++++++++++++-------------- util/grub-mklayout.c | 112 +++++++------- 3 files changed, 296 insertions(+), 172 deletions(-) diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h index dd6631a51..24d4880af 100644 --- a/include/grub/keyboard_layouts.h +++ b/include/grub/keyboard_layouts.h @@ -35,15 +35,106 @@ struct grub_keyboard_layout typedef enum grub_keyboard_key { + GRUB_KEYBOARD_KEY_A = 0x04, + GRUB_KEYBOARD_KEY_B = 0x05, + GRUB_KEYBOARD_KEY_C = 0x06, + GRUB_KEYBOARD_KEY_D = 0x07, + GRUB_KEYBOARD_KEY_E = 0x08, + GRUB_KEYBOARD_KEY_F = 0x09, + GRUB_KEYBOARD_KEY_G = 0x0a, + GRUB_KEYBOARD_KEY_H = 0x0b, + GRUB_KEYBOARD_KEY_I = 0x0c, + GRUB_KEYBOARD_KEY_J = 0x0d, + GRUB_KEYBOARD_KEY_K = 0x0e, + GRUB_KEYBOARD_KEY_L = 0x0f, + GRUB_KEYBOARD_KEY_M = 0x10, + GRUB_KEYBOARD_KEY_N = 0x11, + GRUB_KEYBOARD_KEY_O = 0x12, + GRUB_KEYBOARD_KEY_P = 0x13, + GRUB_KEYBOARD_KEY_Q = 0x14, + GRUB_KEYBOARD_KEY_R = 0x15, + GRUB_KEYBOARD_KEY_S = 0x16, + GRUB_KEYBOARD_KEY_T = 0x17, + GRUB_KEYBOARD_KEY_U = 0x18, + GRUB_KEYBOARD_KEY_V = 0x19, + GRUB_KEYBOARD_KEY_W = 0x1a, + GRUB_KEYBOARD_KEY_X = 0x1b, + GRUB_KEYBOARD_KEY_Y = 0x1c, + GRUB_KEYBOARD_KEY_Z = 0x1d, + GRUB_KEYBOARD_KEY_1 = 0x1e, + GRUB_KEYBOARD_KEY_2 = 0x1f, + GRUB_KEYBOARD_KEY_3 = 0x20, + GRUB_KEYBOARD_KEY_4 = 0x21, + GRUB_KEYBOARD_KEY_5 = 0x22, + GRUB_KEYBOARD_KEY_6 = 0x23, + GRUB_KEYBOARD_KEY_7 = 0x24, + GRUB_KEYBOARD_KEY_8 = 0x25, + GRUB_KEYBOARD_KEY_9 = 0x26, + GRUB_KEYBOARD_KEY_0 = 0x27, + GRUB_KEYBOARD_KEY_ENTER = 0x28, + GRUB_KEYBOARD_KEY_ESCAPE = 0x29, + GRUB_KEYBOARD_KEY_BACKSPACE = 0x2a, + GRUB_KEYBOARD_KEY_TAB = 0x2b, + GRUB_KEYBOARD_KEY_SPACE = 0x2c, + GRUB_KEYBOARD_KEY_DASH = 0x2d, + GRUB_KEYBOARD_KEY_EQUAL = 0x2e, + GRUB_KEYBOARD_KEY_LBRACKET = 0x2f, + GRUB_KEYBOARD_KEY_RBRACKET = 0x30, + GRUB_KEYBOARD_KEY_BACKSLASH = 0x32, + GRUB_KEYBOARD_KEY_SEMICOLON = 0x33, + GRUB_KEYBOARD_KEY_DQUOTE = 0x34, + GRUB_KEYBOARD_KEY_RQUOTE = 0x35, + GRUB_KEYBOARD_KEY_COMMA = 0x36, + GRUB_KEYBOARD_KEY_DOT = 0x37, + GRUB_KEYBOARD_KEY_SLASH = 0x38, GRUB_KEYBOARD_KEY_CAPS_LOCK = 0x39, + GRUB_KEYBOARD_KEY_F1 = 0x3a, + GRUB_KEYBOARD_KEY_F2 = 0x3b, + GRUB_KEYBOARD_KEY_F3 = 0x3c, + GRUB_KEYBOARD_KEY_F4 = 0x3d, + GRUB_KEYBOARD_KEY_F5 = 0x3e, + GRUB_KEYBOARD_KEY_F6 = 0x3f, + GRUB_KEYBOARD_KEY_F7 = 0x40, + GRUB_KEYBOARD_KEY_F8 = 0x41, + GRUB_KEYBOARD_KEY_F9 = 0x42, + GRUB_KEYBOARD_KEY_F10 = 0x43, + GRUB_KEYBOARD_KEY_F11 = 0x44, + GRUB_KEYBOARD_KEY_F12 = 0x45, GRUB_KEYBOARD_KEY_SCROLL_LOCK = 0x47, - GRUB_KEYBOARD_KEY_NUM_LOCK = 0x53, - GRUB_KEYBOARD_KEY_LEFT_CTRL = 0xe0, + GRUB_KEYBOARD_KEY_INSERT = 0x49, + GRUB_KEYBOARD_KEY_HOME = 0x4a, + GRUB_KEYBOARD_KEY_PPAGE = 0x4b, + GRUB_KEYBOARD_KEY_DELETE = 0x4c, + GRUB_KEYBOARD_KEY_END = 0x4d, + GRUB_KEYBOARD_KEY_NPAGE = 0x4e, + GRUB_KEYBOARD_KEY_RIGHT = 0x4f, + GRUB_KEYBOARD_KEY_LEFT = 0x50, + GRUB_KEYBOARD_KEY_DOWN = 0x51, + GRUB_KEYBOARD_KEY_UP = 0x52, + GRUB_KEYBOARD_KEY_NUM_LOCK = 0x53, + GRUB_KEYBOARD_KEY_NUMSLASH = 0x54, + GRUB_KEYBOARD_KEY_NUMMUL = 0x55, + GRUB_KEYBOARD_KEY_NUMMINUS = 0x56, + GRUB_KEYBOARD_KEY_NUMPLUS = 0x57, + GRUB_KEYBOARD_KEY_NUMENTER = 0x58, + GRUB_KEYBOARD_KEY_NUM1 = 0x59, + GRUB_KEYBOARD_KEY_NUM2 = 0x5a, + GRUB_KEYBOARD_KEY_NUM3 = 0x5b, + GRUB_KEYBOARD_KEY_NUM4 = 0x5c, + GRUB_KEYBOARD_KEY_NUM5 = 0x5d, + GRUB_KEYBOARD_KEY_NUM6 = 0x5e, + GRUB_KEYBOARD_KEY_NUM7 = 0x5f, + GRUB_KEYBOARD_KEY_NUM8 = 0x60, + GRUB_KEYBOARD_KEY_NUM9 = 0x61, + GRUB_KEYBOARD_KEY_NUM0 = 0x62, + GRUB_KEYBOARD_KEY_NUMDOT = 0x63, + GRUB_KEYBOARD_KEY_102ND = 0x64, + GRUB_KEYBOARD_KEY_LEFT_CTRL = 0xe0, GRUB_KEYBOARD_KEY_LEFT_SHIFT = 0xe1, - GRUB_KEYBOARD_KEY_LEFT_ALT = 0xe2, + GRUB_KEYBOARD_KEY_LEFT_ALT = 0xe2, GRUB_KEYBOARD_KEY_RIGHT_CTRL = 0xe4, GRUB_KEYBOARD_KEY_RIGHT_SHIFT = 0xe5, - GRUB_KEYBOARD_KEY_RIGHT_ALT = 0xe6, + GRUB_KEYBOARD_KEY_RIGHT_ALT = 0xe6, } grub_keyboard_key_t; unsigned EXPORT_FUNC(grub_term_map_key) (grub_keyboard_key_t code, int status); diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 00c6cef83..c515a3971 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -41,60 +41,60 @@ static grub_uint8_t current_set; static const grub_uint8_t set1_mapping[128] = { - /* 0x00 */ 0x00 /* Unused */, 0x29 /* Escape */, - /* 0x02 */ 0x1e /* 1 */, 0x1f /* 2 */, - /* 0x04 */ 0x20 /* 3 */, 0x21 /* 4 */, - /* 0x06 */ 0x22 /* 5 */, 0x23 /* 6 */, - /* 0x08 */ 0x24 /* 7 */, 0x25 /* 8 */, - /* 0x0a */ 0x26 /* 9 */, 0x27 /* 0 */, - /* 0x0c */ 0x2d /* - */, 0x2e /* = */, - /* 0x0e */ 0x2a /* \b */, 0x2b /* \t */, - /* 0x10 */ 0x14 /* q */, 0x1a /* w */, - /* 0x12 */ 0x08 /* e */, 0x15 /* r */, - /* 0x14 */ 0x17 /* t */, 0x1c /* y */, - /* 0x16 */ 0x18 /* u */, 0x0c /* i */, - /* 0x18 */ 0x12 /* o */, 0x13 /* p */, - /* 0x1a */ 0x2f /* [ */, 0x30 /* ] */, - /* 0x1c */ 0x28 /* Enter */, 0xe0 /* Left CTRL */, - /* 0x1e */ 0x04 /* a */, 0x16 /* s */, - /* 0x20 */ 0x07 /* d */, 0x09 /* f */, - /* 0x22 */ 0x0a /* g */, 0x0b /* h */, - /* 0x24 */ 0x0d /* j */, 0x0e /* k */, - /* 0x26 */ 0x0f /* l */, 0x33 /* ; */, - /* 0x28 */ 0x34 /* " */, 0x35 /* ` */, - /* 0x2a */ 0xe1 /* Left Shift */, 0x32 /* \ */, - /* 0x2c */ 0x1d /* z */, 0x1b /* x */, - /* 0x2e */ 0x06 /* c */, 0x19 /* v */, - /* 0x30 */ 0x05 /* b */, 0x11 /* n */, - /* 0x32 */ 0x10 /* m */, 0x36 /* , */, - /* 0x34 */ 0x37 /* . */, 0x38 /* / */, - /* 0x36 */ 0xe5 /* Right Shift */, 0x55 /* Num * */, - /* 0x38 */ 0xe2 /* Left ALT */, 0x2c /* Space */, - /* 0x3a */ 0x39 /* Caps Lock */, 0x3a /* F1 */, - /* 0x3c */ 0x3b /* F2 */, 0x3c /* F3 */, - /* 0x3e */ 0x3d /* F4 */, 0x3e /* F5 */, - /* 0x40 */ 0x3f /* F6 */, 0x40 /* F7 */, - /* 0x42 */ 0x41 /* F8 */, 0x42 /* F9 */, - /* 0x44 */ 0x43 /* F10 */, 0x53 /* NumLock */, - /* 0x46 */ 0x47 /* Scroll Lock */, 0x5f /* Num 7 */, - /* 0x48 */ 0x60 /* Num 8 */, 0x61 /* Num 9 */, - /* 0x4a */ 0x56 /* Num - */, 0x5c /* Num 4 */, - /* 0x4c */ 0x5d /* Num 5 */, 0x5e /* Num 6 */, - /* 0x4e */ 0x57 /* Num + */, 0x59 /* Num 1 */, - /* 0x50 */ 0x5a /* Num 2 */, 0x5b /* Num 3 */, - /* 0x52 */ 0x62 /* Num 0 */, 0x63 /* Num . */, - /* 0x54 */ 0x00, 0x00, - /* 0x56 */ 0x64 /* 102nd key. */, 0x44 /* F11 */, - /* 0x58 */ 0x45 /* F12 */, 0x00, - /* 0x5a */ 0x00, 0x00, - /* 0x5c */ 0x00, 0x00, - /* 0x5e */ 0x00, 0x00, - /* 0x60 */ 0x00, 0x00, - /* 0x62 */ 0x00, 0x00, + /* 0x00 */ 0 /* Unused */, GRUB_KEYBOARD_KEY_ESCAPE, + /* 0x02 */ GRUB_KEYBOARD_KEY_1, GRUB_KEYBOARD_KEY_2, + /* 0x04 */ GRUB_KEYBOARD_KEY_3, GRUB_KEYBOARD_KEY_4, + /* 0x06 */ GRUB_KEYBOARD_KEY_5, GRUB_KEYBOARD_KEY_6, + /* 0x08 */ GRUB_KEYBOARD_KEY_7, GRUB_KEYBOARD_KEY_8, + /* 0x0a */ GRUB_KEYBOARD_KEY_9, GRUB_KEYBOARD_KEY_0, + /* 0x0c */ GRUB_KEYBOARD_KEY_DASH, GRUB_KEYBOARD_KEY_EQUAL, + /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE, GRUB_KEYBOARD_KEY_TAB, + /* 0x10 */ GRUB_KEYBOARD_KEY_Q, GRUB_KEYBOARD_KEY_W, + /* 0x12 */ GRUB_KEYBOARD_KEY_E, GRUB_KEYBOARD_KEY_R, + /* 0x14 */ GRUB_KEYBOARD_KEY_T, GRUB_KEYBOARD_KEY_Y, + /* 0x16 */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_I, + /* 0x18 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_P, + /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET, GRUB_KEYBOARD_KEY_RBRACKET, + /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER, GRUB_KEYBOARD_KEY_LEFT_CTRL, + /* 0x1e */ GRUB_KEYBOARD_KEY_A, GRUB_KEYBOARD_KEY_S, + /* 0x20 */ GRUB_KEYBOARD_KEY_D, GRUB_KEYBOARD_KEY_F, + /* 0x22 */ GRUB_KEYBOARD_KEY_G, GRUB_KEYBOARD_KEY_H, + /* 0x24 */ GRUB_KEYBOARD_KEY_J, GRUB_KEYBOARD_KEY_K, + /* 0x26 */ GRUB_KEYBOARD_KEY_L, GRUB_KEYBOARD_KEY_SEMICOLON, + /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE, GRUB_KEYBOARD_KEY_RQUOTE, + /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT, GRUB_KEYBOARD_KEY_BACKSLASH, + /* 0x2c */ GRUB_KEYBOARD_KEY_Z, GRUB_KEYBOARD_KEY_X, + /* 0x2e */ GRUB_KEYBOARD_KEY_C, GRUB_KEYBOARD_KEY_V, + /* 0x30 */ GRUB_KEYBOARD_KEY_B, GRUB_KEYBOARD_KEY_N, + /* 0x32 */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_COMMA, + /* 0x34 */ GRUB_KEYBOARD_KEY_DOT, GRUB_KEYBOARD_KEY_SLASH, + /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT, GRUB_KEYBOARD_KEY_NUMMUL, + /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT, GRUB_KEYBOARD_KEY_SPACE, + /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_F1, + /* 0x3c */ GRUB_KEYBOARD_KEY_F2, GRUB_KEYBOARD_KEY_F3, + /* 0x3e */ GRUB_KEYBOARD_KEY_F4, GRUB_KEYBOARD_KEY_F5, + /* 0x40 */ GRUB_KEYBOARD_KEY_F6, GRUB_KEYBOARD_KEY_F7, + /* 0x42 */ GRUB_KEYBOARD_KEY_F8, GRUB_KEYBOARD_KEY_F9, + /* 0x44 */ GRUB_KEYBOARD_KEY_F10, GRUB_KEYBOARD_KEY_NUM_LOCK, + /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, GRUB_KEYBOARD_KEY_NUM7, + /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8, GRUB_KEYBOARD_KEY_NUM9, + /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS, GRUB_KEYBOARD_KEY_NUM4, + /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5, GRUB_KEYBOARD_KEY_NUM6, + /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS, GRUB_KEYBOARD_KEY_NUM1, + /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2, GRUB_KEYBOARD_KEY_NUM3, + /* 0x52 */ GRUB_KEYBOARD_KEY_NUMDOT, GRUB_KEYBOARD_KEY_NUMDOT, + /* 0x54 */ 0, 0, + /* 0x56 */ GRUB_KEYBOARD_KEY_102ND, GRUB_KEYBOARD_KEY_F11, + /* 0x58 */ GRUB_KEYBOARD_KEY_F12, 0, + /* 0x5a */ 0, 0, + /* 0x5c */ 0, 0, + /* 0x5e */ 0, 0, + /* 0x60 */ 0, 0, + /* 0x62 */ 0, 0, /* OLPC keys. Just mapped to normal keys. */ - /* 0x64 */ 0x00, 0x52 /* Up */, - /* 0x66 */ 0x51 /* Down */, 0x50 /* Left */, - /* 0x68 */ 0x4f /* Right */ + /* 0x64 */ 0, GRUB_KEYBOARD_KEY_UP, + /* 0x66 */ GRUB_KEYBOARD_KEY_DOWN, GRUB_KEYBOARD_KEY_LEFT, + /* 0x68 */ GRUB_KEYBOARD_KEY_RIGHT }; static const struct @@ -102,57 +102,90 @@ static const struct grub_uint8_t from, to; } set1_e0_mapping[] = { - {0x1c, 0x58 /* Num \n */}, - {0x1d, 0xe4 /* Right CTRL */}, - {0x35, 0x54 /* Num / */ }, - {0x38, 0xe6 /* Right ALT */}, - {0x47, 0x4a /* Home */ }, - {0x48, 0x52 /* Up */ }, - {0x49, 0x4e /* NPage */ }, - {0x4b, 0x50 /* Left */ }, - {0x4d, 0x4f /* Right */ }, - {0x4f, 0x4d /* End */ }, - {0x50, 0x51 /* Down */ }, - {0x51, 0x4b /* PPage */ }, - {0x52, 0x49 /* Insert */}, - {0x53, 0x4c /* DC */ }, + {0x1c, GRUB_KEYBOARD_KEY_NUMENTER}, + {0x1d, GRUB_KEYBOARD_KEY_RIGHT_CTRL}, + {0x35, GRUB_KEYBOARD_KEY_NUMSLASH }, + {0x38, GRUB_KEYBOARD_KEY_RIGHT_ALT}, + {0x47, GRUB_KEYBOARD_KEY_HOME}, + {0x48, GRUB_KEYBOARD_KEY_UP}, + {0x49, GRUB_KEYBOARD_KEY_NPAGE}, + {0x4b, GRUB_KEYBOARD_KEY_LEFT}, + {0x4d, GRUB_KEYBOARD_KEY_RIGHT}, + {0x4f, GRUB_KEYBOARD_KEY_END}, + {0x50, GRUB_KEYBOARD_KEY_DOWN}, + {0x51, GRUB_KEYBOARD_KEY_PPAGE}, + {0x52, GRUB_KEYBOARD_KEY_INSERT}, + {0x53, GRUB_KEYBOARD_KEY_DELETE}, }; static const grub_uint8_t set2_mapping[256] = { - /* 0x00 */ 0x00, 0x42 /* F9 */, 0x00, 0x3e /* F5 */, - /* 0x04 */ 0x3c /* F3 */, 0x3a /* F1 */, 0x3b /* F2 */, 0x45 /* F12 */, - /* 0x08 */ 0x00, 0x43 /* F10 */, 0x41 /* F8 */, 0x3f /* F6 */, - /* 0x0c */ 0x3d /* F4 */, 0x2b /* \t */, 0x35 /* ` */, 0x00, - /* 0x10 */ 0x00, GRUB_KEYBOARD_KEY_LEFT_ALT, GRUB_KEYBOARD_KEY_LEFT_SHIFT, 0x00, - /* 0x14 */ GRUB_KEYBOARD_KEY_LEFT_CTRL, 0x14 /* q */, 0x1e /* 1 */, 0x00, - /* 0x18 */ 0x00, 0x00, 0x1d /* s */, 0x16 /* s */, - /* 0x1c */ 0x04 /* a */, 0x1a /* w */, 0x1f /* 2 */, 0x00, - /* 0x20 */ 0x00, 0x06 /* c */, 0x1b /* x */, 0x07 /* d */, - /* 0x24 */ 0x08 /* e */, 0x21 /* 4 */, 0x20 /* 3 */, 0x00, - /* 0x28 */ 0x00, 0x2c /* Space */, 0x19 /* v */, 0x09 /* f */, - /* 0x2c */ 0x17 /* t */, 0x15 /* r */, 0x22 /* 5 */, 0x00, - /* 0x30 */ 0x00, 0x11 /* n */, 0x05 /* b */, 0x0b /* h */, - /* 0x34 */ 0x0a /* g */, 0x1c /* y */, 0x23 /* 6 */, 0x00, - /* 0x38 */ 0x00, 0x00, 0x10 /* m */, 0x0d /* j */, - /* 0x3c */ 0x18 /* u */, 0x24 /* 7 */, 0x25 /* 8 */, 0x00, - /* 0x40 */ 0x00, 0x37 /* . */, 0x0e /* k */, 0x0c /* i */, - /* 0x44 */ 0x12 /* o */, 0x27 /* 0 */, 0x26 /* 9 */, 0x00, - /* 0x48 */ 0x00, 0x36 /* , */, 0x38 /* / */, 0x0f /* l */, - /* 0x4c */ 0x33 /* ; */, 0x13 /* p */, 0x2d /* - */, 0x00, - /* 0x50 */ 0x00, 0x00, 0x34 /* ' */, 0x00, - /* 0x54 */ 0x2f /* [ */, 0x2e /* = */, 0x00, 0x00, - /* 0x58 */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_RIGHT_SHIFT, 0x28 /* \n */,0x30 /* ] */, - /* 0x5c */ 0x00, 0x32 /* \ */, 0x00, 0x00, - /* 0x60 */ 0x00, 0x64 /* 102nd key. */, 0x00, 0x00, - /* 0x64 */ 0x00, 0x00, 0x2a /* \b */, 0x00, - /* 0x68 */ 0x00, 0x59 /* Num 1 */, 0x00, 0x5c /* Num 4 */, - /* 0x6c */ 0x5f /* Num 7 */, 0x00, 0x00, 0x00, - /* 0x70 */ 0x62 /* Num 0 */, 0x63 /* Num 0 */, 0x5a /* Num 2 */, 0x5d /* Num 5 */, - /* 0x74 */ 0x5e /* Num 6 */, 0x60 /* Num 8 */, 0x29 /* \e */, 0x53 /* NumLock */, - /* 0x78 */ 0x44 /* F11 */, 0x57 /* Num + */, 0x5b /* Num 3 */, 0x56 /* Num - */, - /* 0x7c */ 0x55 /* Num * */, 0x61 /* Num 9 */, 0x47 /* ScrollLock */, 0x00, - /* 0x80 */ 0x00, 0x00, 0x00, 0x40 /* F7 */, + /* 0x00 */ 0, GRUB_KEYBOARD_KEY_F9, + /* 0x02 */ 0, GRUB_KEYBOARD_KEY_F5, + /* 0x04 */ GRUB_KEYBOARD_KEY_F3, GRUB_KEYBOARD_KEY_F1, + /* 0x06 */ GRUB_KEYBOARD_KEY_F2, GRUB_KEYBOARD_KEY_F12, + /* 0x08 */ 0, GRUB_KEYBOARD_KEY_F10, + /* 0x0a */ GRUB_KEYBOARD_KEY_F8, GRUB_KEYBOARD_KEY_F6, + /* 0x0c */ GRUB_KEYBOARD_KEY_F4, GRUB_KEYBOARD_KEY_TAB, + /* 0x0e */ GRUB_KEYBOARD_KEY_RQUOTE, 0, + /* 0x10 */ 0, GRUB_KEYBOARD_KEY_LEFT_ALT, + /* 0x12 */ GRUB_KEYBOARD_KEY_LEFT_SHIFT, 0, + /* 0x14 */ GRUB_KEYBOARD_KEY_LEFT_CTRL, GRUB_KEYBOARD_KEY_Q, + /* 0x16 */ GRUB_KEYBOARD_KEY_1, 0, + /* 0x18 */ 0, 0, + /* 0x1a */ GRUB_KEYBOARD_KEY_Z, GRUB_KEYBOARD_KEY_S, + /* 0x1c */ GRUB_KEYBOARD_KEY_A, GRUB_KEYBOARD_KEY_W, + /* 0x1e */ GRUB_KEYBOARD_KEY_2, 0, + /* 0x20 */ 0, GRUB_KEYBOARD_KEY_C, + /* 0x22 */ GRUB_KEYBOARD_KEY_X, GRUB_KEYBOARD_KEY_D, + /* 0x24 */ GRUB_KEYBOARD_KEY_E, GRUB_KEYBOARD_KEY_4, + /* 0x26 */ GRUB_KEYBOARD_KEY_3, 0, + /* 0x28 */ 0, GRUB_KEYBOARD_KEY_SPACE, + /* 0x2a */ GRUB_KEYBOARD_KEY_V, GRUB_KEYBOARD_KEY_F, + /* 0x2c */ GRUB_KEYBOARD_KEY_T, GRUB_KEYBOARD_KEY_R, + /* 0x2e */ GRUB_KEYBOARD_KEY_5, 0, + /* 0x30 */ 0, GRUB_KEYBOARD_KEY_N, + /* 0x32 */ GRUB_KEYBOARD_KEY_B, GRUB_KEYBOARD_KEY_H, + /* 0x34 */ GRUB_KEYBOARD_KEY_G, GRUB_KEYBOARD_KEY_Y, + /* 0x36 */ GRUB_KEYBOARD_KEY_6, 0, + /* 0x38 */ 0, 0, + /* 0x3a */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_J, + /* 0x3c */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_7, + /* 0x3e */ GRUB_KEYBOARD_KEY_8, 0, + /* 0x40 */ 0, GRUB_KEYBOARD_KEY_DOT, + /* 0x42 */ GRUB_KEYBOARD_KEY_K, GRUB_KEYBOARD_KEY_I, + /* 0x44 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_0, + /* 0x46 */ GRUB_KEYBOARD_KEY_9, 0, + /* 0x48 */ 0, GRUB_KEYBOARD_KEY_COMMA, + /* 0x4a */ GRUB_KEYBOARD_KEY_SLASH, GRUB_KEYBOARD_KEY_L, + /* 0x4c */ GRUB_KEYBOARD_KEY_SEMICOLON, GRUB_KEYBOARD_KEY_P, + /* 0x4e */ GRUB_KEYBOARD_KEY_DASH, 0, + /* 0x50 */ 0, 0, + /* 0x52 */ GRUB_KEYBOARD_KEY_DQUOTE, 0, + /* 0x54 */ GRUB_KEYBOARD_KEY_LBRACKET, GRUB_KEYBOARD_KEY_EQUAL, + /* 0x56 */ 0, 0, + /* 0x58 */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_RIGHT_SHIFT, + /* 0x5a */ GRUB_KEYBOARD_KEY_ENTER, GRUB_KEYBOARD_KEY_RBRACKET, + /* 0x5c */ 0, GRUB_KEYBOARD_KEY_BACKSLASH, + /* 0x5e */ 0, 0, + /* 0x60 */ 0, GRUB_KEYBOARD_KEY_102ND, + /* 0x62 */ 0, 0, + /* 0x64 */ 0, 0, + /* 0x66 */ GRUB_KEYBOARD_KEY_BACKSPACE, 0, + /* 0x68 */ 0, GRUB_KEYBOARD_KEY_NUM1, + /* 0x6a */ 0, GRUB_KEYBOARD_KEY_NUM4, + /* 0x6c */ GRUB_KEYBOARD_KEY_NUM7, 0, + /* 0x6e */ 0, 0, + /* 0x70 */ GRUB_KEYBOARD_KEY_NUMDOT, GRUB_KEYBOARD_KEY_NUM0, + /* 0x72 */ GRUB_KEYBOARD_KEY_NUM2, GRUB_KEYBOARD_KEY_NUM5, + /* 0x74 */ GRUB_KEYBOARD_KEY_NUM6, GRUB_KEYBOARD_KEY_NUM8, + /* 0x76 */ GRUB_KEYBOARD_KEY_ESCAPE, GRUB_KEYBOARD_KEY_NUM_LOCK, + /* 0x78 */ GRUB_KEYBOARD_KEY_F11, GRUB_KEYBOARD_KEY_NUMPLUS, + /* 0x7a */ GRUB_KEYBOARD_KEY_NUM3, GRUB_KEYBOARD_KEY_NUMMINUS, + /* 0x7c */ GRUB_KEYBOARD_KEY_NUMMUL, GRUB_KEYBOARD_KEY_NUM9, + /* 0x7e */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, 0, + /* 0x80 */ 0, 0, + /* 0x82 */ 0, GRUB_KEYBOARD_KEY_F7, }; static const struct @@ -162,18 +195,18 @@ static const struct { {0x11, GRUB_KEYBOARD_KEY_RIGHT_ALT}, {0x14, GRUB_KEYBOARD_KEY_RIGHT_CTRL}, - {0x4a, 0x54}, /* Num / */ - {0x5a, 0x58}, /* Num enter */ - {0x69, 0x4d}, /* End */ - {0x6b, 0x50}, /* Left */ - {0x6c, 0x4a}, /* Home */ - {0x70, 0x49}, /* Insert */ - {0x71, 0x4c}, /* Delete */ - {0x72, 0x51}, /* Down */ - {0x74, 0x4f}, /* Right */ - {0x75, 0x52}, /* Up */ - {0x7a, 0x4e}, /* PageDown */ - {0x7d, 0x4b}, /* PageUp */ + {0x4a, GRUB_KEYBOARD_KEY_NUMSLASH}, + {0x5a, GRUB_KEYBOARD_KEY_NUMENTER}, + {0x69, GRUB_KEYBOARD_KEY_END}, + {0x6b, GRUB_KEYBOARD_KEY_LEFT}, + {0x6c, GRUB_KEYBOARD_KEY_HOME}, + {0x70, GRUB_KEYBOARD_KEY_INSERT}, + {0x71, GRUB_KEYBOARD_KEY_DELETE}, + {0x72, GRUB_KEYBOARD_KEY_DOWN}, + {0x74, GRUB_KEYBOARD_KEY_RIGHT}, + {0x75, GRUB_KEYBOARD_KEY_UP}, + {0x7a, GRUB_KEYBOARD_KEY_NPAGE}, + {0x7d, GRUB_KEYBOARD_KEY_PPAGE}, }; static void diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index fc8ffb67a..e22888fc5 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -192,62 +192,62 @@ static struct console_grub_equivalence console_grub_equivalences_common[] = { }; static grub_uint8_t linux_to_usb_map[128] = { - /* 0x00 */ 0x00 /* Unused */, 0x29 /* Escape */, - /* 0x02 */ 0x1e /* 1 */, 0x1f /* 2 */, - /* 0x04 */ 0x20 /* 3 */, 0x21 /* 4 */, - /* 0x06 */ 0x22 /* 5 */, 0x23 /* 6 */, - /* 0x08 */ 0x24 /* 7 */, 0x25 /* 8 */, - /* 0x0a */ 0x26 /* 9 */, 0x27 /* 0 */, - /* 0x0c */ 0x2d /* - */, 0x2e /* = */, - /* 0x0e */ 0x2a /* \b */, 0x2b /* \t */, - /* 0x10 */ 0x14 /* q */, 0x1a /* w */, - /* 0x12 */ 0x08 /* e */, 0x15 /* r */, - /* 0x14 */ 0x17 /* t */, 0x1c /* y */, - /* 0x16 */ 0x18 /* u */, 0x0c /* i */, - /* 0x18 */ 0x12 /* o */, 0x13 /* p */, - /* 0x1a */ 0x2f /* [ */, 0x30 /* ] */, - /* 0x1c */ 0x28 /* Enter */, 0x00 /* Left CTRL */, - /* 0x1e */ 0x04 /* a */, 0x16 /* s */, - /* 0x20 */ 0x07 /* d */, 0x09 /* f */, - /* 0x22 */ 0x0a /* g */, 0x0b /* h */, - /* 0x24 */ 0x0d /* j */, 0x0e /* k */, - /* 0x26 */ 0x0f /* l */, 0x33 /* ; */, - /* 0x28 */ 0x34 /* " */, 0x35 /* ` */, - /* 0x2a */ 0x00 /* Left Shift */, 0x32 /* \ */, - /* 0x2c */ 0x1d /* z */, 0x1b /* x */, - /* 0x2e */ 0x06 /* c */, 0x19 /* v */, - /* 0x30 */ 0x05 /* b */, 0x11 /* n */, - /* 0x32 */ 0x10 /* m */, 0x36 /* , */, - /* 0x34 */ 0x37 /* . */, 0x38 /* / */, - /* 0x36 */ 0x00 /* Right Shift */, 0x55 /* Num * */, - /* 0x38 */ 0x00 /* Left ALT */, 0x2c /* Space */, - /* 0x3a */ 0x39 /* Caps Lock */, 0x3a /* F1 */, - /* 0x3c */ 0x3b /* F2 */, 0x3c /* F3 */, - /* 0x3e */ 0x3d /* F4 */, 0x3e /* F5 */, - /* 0x40 */ 0x3f /* F6 */, 0x40 /* F7 */, - /* 0x42 */ 0x41 /* F8 */, 0x42 /* F9 */, - /* 0x44 */ 0x43 /* F10 */, 0x53 /* NumLock */, - /* 0x46 */ 0x47 /* Scroll Lock */, 0x5f /* Num 7 */, - /* 0x48 */ 0x60 /* Num 8 */, 0x61 /* Num 9 */, - /* 0x4a */ 0x56 /* Num - */, 0x5c /* Num 4 */, - /* 0x4c */ 0x5d /* Num 5 */, 0x5e /* Num 6 */, - /* 0x4e */ 0x57 /* Num + */, 0x59 /* Num 1 */, - /* 0x50 */ 0x5a /* Num 2 */, 0x5b /* Num 3 */, - /* 0x52 */ 0x62 /* Num 0 */, 0x63 /* Num . */, - /* 0x54 */ 0x00, 0x00, - /* 0x56 */ 0x64 /* 102nd key. */, 0x44 /* F11 */, - /* 0x58 */ 0x45 /* F12 */, 0x00, - /* 0x5a */ 0x00, 0x00, - /* 0x5c */ 0x00, 0x00, - /* 0x5e */ 0x00, 0x00, - /* 0x60 */ 0x58 /* Num \n */, 0x00 /* Right CTRL */, - /* 0x62 */ 0x54 /* Num / */, 0x00, - /* 0x64 */ 0x00 /* Right ALT */, 0x00, - /* 0x66 */ 0x4a /* Home */, 0x52 /* Up */, - /* 0x68 */ 0x4e /* NPage */, 0x50 /* Left */, - /* 0x6a */ 0x4f /* Right */, 0x4d /* End */, - /* 0x6c */ 0x51 /* Down */, 0x4b /* PPage */, - /* 0x6e */ 0x49 /* Insert */, 0x4c /* DC */ + /* 0x00 */ 0 /* Unused */, GRUB_KEYBOARD_KEY_ESCAPE, + /* 0x02 */ GRUB_KEYBOARD_KEY_1, GRUB_KEYBOARD_KEY_2, + /* 0x04 */ GRUB_KEYBOARD_KEY_3, GRUB_KEYBOARD_KEY_4, + /* 0x06 */ GRUB_KEYBOARD_KEY_5, GRUB_KEYBOARD_KEY_6, + /* 0x08 */ GRUB_KEYBOARD_KEY_7, GRUB_KEYBOARD_KEY_8, + /* 0x0a */ GRUB_KEYBOARD_KEY_9, GRUB_KEYBOARD_KEY_0, + /* 0x0c */ GRUB_KEYBOARD_KEY_DASH, GRUB_KEYBOARD_KEY_EQUAL, + /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE, GRUB_KEYBOARD_KEY_TAB, + /* 0x10 */ GRUB_KEYBOARD_KEY_Q, GRUB_KEYBOARD_KEY_W, + /* 0x12 */ GRUB_KEYBOARD_KEY_E, GRUB_KEYBOARD_KEY_R, + /* 0x14 */ GRUB_KEYBOARD_KEY_T, GRUB_KEYBOARD_KEY_Y, + /* 0x16 */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_I, + /* 0x18 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_P, + /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET, GRUB_KEYBOARD_KEY_RBRACKET, + /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER, GRUB_KEYBOARD_KEY_LEFT_CTRL, + /* 0x1e */ GRUB_KEYBOARD_KEY_A, GRUB_KEYBOARD_KEY_S, + /* 0x20 */ GRUB_KEYBOARD_KEY_D, GRUB_KEYBOARD_KEY_F, + /* 0x22 */ GRUB_KEYBOARD_KEY_G, GRUB_KEYBOARD_KEY_H, + /* 0x24 */ GRUB_KEYBOARD_KEY_J, GRUB_KEYBOARD_KEY_K, + /* 0x26 */ GRUB_KEYBOARD_KEY_L, GRUB_KEYBOARD_KEY_SEMICOLON, + /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE, GRUB_KEYBOARD_KEY_RQUOTE, + /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT, GRUB_KEYBOARD_KEY_BACKSLASH, + /* 0x2c */ GRUB_KEYBOARD_KEY_Z, GRUB_KEYBOARD_KEY_X, + /* 0x2e */ GRUB_KEYBOARD_KEY_C, GRUB_KEYBOARD_KEY_V, + /* 0x30 */ GRUB_KEYBOARD_KEY_B, GRUB_KEYBOARD_KEY_N, + /* 0x32 */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_COMMA, + /* 0x34 */ GRUB_KEYBOARD_KEY_DOT, GRUB_KEYBOARD_KEY_SLASH, + /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT, GRUB_KEYBOARD_KEY_NUMMUL, + /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT, GRUB_KEYBOARD_KEY_SPACE, + /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_F1, + /* 0x3c */ GRUB_KEYBOARD_KEY_F2, GRUB_KEYBOARD_KEY_F3, + /* 0x3e */ GRUB_KEYBOARD_KEY_F4, GRUB_KEYBOARD_KEY_F5, + /* 0x40 */ GRUB_KEYBOARD_KEY_F6, GRUB_KEYBOARD_KEY_F7, + /* 0x42 */ GRUB_KEYBOARD_KEY_F8, GRUB_KEYBOARD_KEY_F9, + /* 0x44 */ GRUB_KEYBOARD_KEY_F10, GRUB_KEYBOARD_KEY_NUM_LOCK, + /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, GRUB_KEYBOARD_KEY_NUM7, + /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8, GRUB_KEYBOARD_KEY_NUM9, + /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS, GRUB_KEYBOARD_KEY_NUM4, + /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5, GRUB_KEYBOARD_KEY_NUM6, + /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS, GRUB_KEYBOARD_KEY_NUM1, + /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2, GRUB_KEYBOARD_KEY_NUM3, + /* 0x52 */ GRUB_KEYBOARD_KEY_NUMDOT, GRUB_KEYBOARD_KEY_NUMDOT, + /* 0x54 */ 0, 0, + /* 0x56 */ GRUB_KEYBOARD_KEY_102ND, GRUB_KEYBOARD_KEY_F11, + /* 0x58 */ GRUB_KEYBOARD_KEY_F12, 0, + /* 0x5a */ 0, 0, + /* 0x5c */ 0, 0, + /* 0x5e */ 0, 0, + /* 0x60 */ GRUB_KEYBOARD_KEY_NUMENTER, GRUB_KEYBOARD_KEY_RIGHT_CTRL, + /* 0x62 */ GRUB_KEYBOARD_KEY_NUMSLASH, 0, + /* 0x64 */ GRUB_KEYBOARD_KEY_RIGHT_ALT, 0, + /* 0x66 */ GRUB_KEYBOARD_KEY_HOME, GRUB_KEYBOARD_KEY_UP, + /* 0x68 */ GRUB_KEYBOARD_KEY_NPAGE, GRUB_KEYBOARD_KEY_LEFT, + /* 0x6a */ GRUB_KEYBOARD_KEY_RIGHT, GRUB_KEYBOARD_KEY_END, + /* 0x6c */ GRUB_KEYBOARD_KEY_DOWN, GRUB_KEYBOARD_KEY_PPAGE, + /* 0x6e */ GRUB_KEYBOARD_KEY_INSERT, GRUB_KEYBOARD_KEY_DELETE }; static void From 9e91bd9d9ae3c89f89b235b2f3976fb2e4cdce2e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 01:13:54 +0200 Subject: [PATCH 48/64] Fix multiple issues with set 2 --- commands/keylayouts.c | 2 +- term/at_keyboard.c | 113 +++++++++++++++++++++++++++--------------- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/commands/keylayouts.c b/commands/keylayouts.c index c68919aef..deb482a85 100644 --- a/commands/keylayouts.c +++ b/commands/keylayouts.c @@ -153,7 +153,7 @@ map_key_core (int code, int status, int *alt_gr_consumed) } unsigned -grub_term_map_key (int code, int status) +grub_term_map_key (grub_keyboard_key_t code, int status) { int alt_gr_consumed = 0; int key; diff --git a/term/at_keyboard.c b/term/at_keyboard.c index c515a3971..b8df4cbf3 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -152,11 +152,11 @@ static const grub_uint8_t set2_mapping[256] = /* 0x3a */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_J, /* 0x3c */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_7, /* 0x3e */ GRUB_KEYBOARD_KEY_8, 0, - /* 0x40 */ 0, GRUB_KEYBOARD_KEY_DOT, + /* 0x40 */ 0, GRUB_KEYBOARD_KEY_COMMA, /* 0x42 */ GRUB_KEYBOARD_KEY_K, GRUB_KEYBOARD_KEY_I, /* 0x44 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_0, /* 0x46 */ GRUB_KEYBOARD_KEY_9, 0, - /* 0x48 */ 0, GRUB_KEYBOARD_KEY_COMMA, + /* 0x48 */ 0, GRUB_KEYBOARD_KEY_DOT, /* 0x4a */ GRUB_KEYBOARD_KEY_SLASH, GRUB_KEYBOARD_KEY_L, /* 0x4c */ GRUB_KEYBOARD_KEY_SEMICOLON, GRUB_KEYBOARD_KEY_P, /* 0x4e */ GRUB_KEYBOARD_KEY_DASH, 0, @@ -220,53 +220,75 @@ grub_keyboard_controller_write (grub_uint8_t c) { keyboard_controller_wait_until_ready (); grub_outb (KEYBOARD_COMMAND_WRITE, KEYBOARD_REG_STATUS); + keyboard_controller_wait_until_ready (); grub_outb (c, KEYBOARD_REG_DATA); } -static grub_uint8_t -query_mode (int mode) +static int +write_mode (int mode) { + grub_uint8_t ack; keyboard_controller_wait_until_ready (); grub_outb (0xf0, KEYBOARD_REG_DATA); keyboard_controller_wait_until_ready (); - grub_inb (KEYBOARD_REG_DATA); - keyboard_controller_wait_until_ready (); grub_outb (mode, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + ack = grub_inb (KEYBOARD_REG_DATA); + if (ack != 0xfa) + return 0; + + return 1; +} + +static int +query_mode (void) +{ + grub_uint8_t ret; + int e; + + e = write_mode (0); + if (!e) + return 0; keyboard_controller_wait_until_ready (); - return grub_inb (KEYBOARD_REG_DATA); + do + ret = grub_inb (KEYBOARD_REG_DATA); + while (ret == 0xfa); + + /* QEMU translates the set even in no-translate mode. */ + if (ret == 0x43 || ret == 1) + return 1; + if (ret == 0x41 || ret == 2) + return 2; + if (ret == 0x3f || ret == 3) + return 3; + return 0; } -/* QEMU translates the set even in no-translate mode. */ -static inline int -recover_mode (grub_uint8_t report) -{ - if (report == 0x43 || report == 1) - return 1; - if (report == 0x41 || report == 2) - return 2; - if (report == 0x3f || report == 3) - return 3; - return -1; -} static void set_scancodes (void) { + grub_keyboard_orig_set = query_mode (); + /* You must have visited computer museum. Keyboard without scancode set + knowledge. Assume XT. */ + if (!grub_keyboard_orig_set) + { + current_set = 1; + return; + } + grub_keyboard_controller_write (grub_keyboard_controller_orig & ~KEYBOARD_AT_TRANSLATE); - grub_keyboard_orig_set = recover_mode (query_mode (0)); - query_mode (2); - current_set = query_mode (0); - current_set = recover_mode (current_set); + write_mode (2); + current_set = query_mode (); if (current_set == 2) return; - query_mode (1); - current_set = query_mode (0); - current_set = recover_mode (current_set); + write_mode (1); + current_set = query_mode (); if (current_set == 1) return; grub_printf ("No supported scancode set found\n"); @@ -305,6 +327,16 @@ fetch_key (int *is_break) return -1; } + if ((current_set == 2 || current_set == 3) && at_key == 0xf0) + { + f0_received = 1; + return -1; + } + + /* Setting LEDs may generate ACKs. */ + if (at_key == 0xfa) + return -1; + was_ext = e0_received; e0_received = 0; @@ -326,11 +358,6 @@ fetch_key (int *is_break) } break; case 2: - if (at_key == 0xf0) - { - f0_received = 1; - return -1; - } *is_break = f0_received; f0_received = 0; if (!was_ext) @@ -338,10 +365,10 @@ fetch_key (int *is_break) else { unsigned i; - for (i = 0; i < ARRAY_SIZE (set1_e0_mapping); i++) - if (set1_e0_mapping[i].from == (at_key & 0x80)) + for (i = 0; i < ARRAY_SIZE (set2_e0_mapping); i++) + if (set2_e0_mapping[i].from == at_key) { - ret = set1_e0_mapping[i].to; + ret = set2_e0_mapping[i].to; break; } } @@ -351,7 +378,12 @@ fetch_key (int *is_break) } if (!ret) { - grub_printf ("Unknown key 0x%02x from set %d\n\n", at_key, current_set); + if (was_ext) + grub_printf ("Unknown key 0xe0+0x%02x from set %d\n", + at_key, current_set); + else + grub_printf ("Unknown key 0x%02x from set %d\n", + at_key, current_set); return -1; } return ret; @@ -387,7 +419,7 @@ grub_keyboard_isr (grub_keyboard_key_t key, int is_break) return 0; } else - switch (KEYBOARD_SCANCODE (key)) + switch (key) { case GRUB_KEYBOARD_KEY_LEFT_SHIFT: at_keyboard_status &= ~GRUB_TERM_STATUS_LSHIFT; @@ -507,12 +539,12 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus { pending_key = -1; at_keyboard_status = 0; - grub_keyboard_controller_orig = grub_keyboard_controller_read (); - set_scancodes (); - keyboard_controller_led (led_status); /* Drain input buffer. */ while (KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) grub_inb (KEYBOARD_REG_DATA); + grub_keyboard_controller_orig = grub_keyboard_controller_read (); + set_scancodes (); + keyboard_controller_led (led_status); return GRUB_ERR_NONE; } @@ -520,7 +552,8 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus static grub_err_t grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused))) { - query_mode (grub_keyboard_orig_set); + if (grub_keyboard_orig_set) + write_mode (grub_keyboard_orig_set); grub_keyboard_controller_write (grub_keyboard_controller_orig); return GRUB_ERR_NONE; } From b88904ca7fab60afec987ed39d95589d33e8bc1f Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 01:44:54 +0200 Subject: [PATCH 49/64] Fix ignoring of set1 extended sequences --- term/at_keyboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/term/at_keyboard.c b/term/at_keyboard.c index b8df4cbf3..ff9f713c6 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -350,7 +350,7 @@ fetch_key (int *is_break) { unsigned i; for (i = 0; i < ARRAY_SIZE (set1_e0_mapping); i++) - if (set1_e0_mapping[i].from == (at_key & 0x80)) + if (set1_e0_mapping[i].from == (at_key & 0x7f)) { ret = set1_e0_mapping[i].to; break; From 7ae3eb623250b80737e227c6efd0ca7740eb01ab Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 11:26:28 +0200 Subject: [PATCH 50/64] Wait for ACKs when setting the mode --- include/grub/at_keyboard.h | 2 ++ term/at_keyboard.c | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 6e0806bdb..3dfa0da80 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -27,6 +27,8 @@ #define KEYBOARD_AT_TRANSLATE 0x40 +#define GRUB_AT_ACK 0xfa + #define KEYBOARD_ISMAKE(x) !((x) & 0x80) #define KEYBOARD_ISREADY(x) ((x) & 0x01) #define KEYBOARD_SCANCODE(x) ((x) & 0x7f) diff --git a/term/at_keyboard.c b/term/at_keyboard.c index ff9f713c6..e9db7834a 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -23,6 +23,7 @@ #include #include #include +#include static short at_keyboard_status = 0; static int e0_received = 0; @@ -225,19 +226,29 @@ grub_keyboard_controller_write (grub_uint8_t c) } static int -write_mode (int mode) +wait_ack (void) { grub_uint8_t ack; + grub_uint64_t endtime = grub_get_time_ms () + 20; + do + { + ack = grub_inb (KEYBOARD_REG_DATA); + } + while (ack != GRUB_AT_ACK && grub_get_time_ms () < endtime); + grub_dprintf ("atkeyb", "Ack 0x%02x\n", ack); + return ack == GRUB_AT_ACK; +} + +static int +write_mode (int mode) +{ keyboard_controller_wait_until_ready (); grub_outb (0xf0, KEYBOARD_REG_DATA); keyboard_controller_wait_until_ready (); grub_outb (mode, KEYBOARD_REG_DATA); keyboard_controller_wait_until_ready (); - ack = grub_inb (KEYBOARD_REG_DATA); - if (ack != 0xfa) - return 0; - return 1; + return wait_ack (); } static int @@ -254,7 +265,7 @@ query_mode (void) do ret = grub_inb (KEYBOARD_REG_DATA); - while (ret == 0xfa); + while (ret == GRUB_AT_ACK); /* QEMU translates the set even in no-translate mode. */ if (ret == 0x43 || ret == 1) @@ -275,6 +286,7 @@ set_scancodes (void) knowledge. Assume XT. */ if (!grub_keyboard_orig_set) { + grub_dprintf ("atkeyb", "No sets support assumed\n"); current_set = 1; return; } @@ -284,11 +296,13 @@ set_scancodes (void) write_mode (2); current_set = query_mode (); + grub_dprintf ("atkeyb", "returned set %d\n", current_set); if (current_set == 2) return; write_mode (1); current_set = query_mode (); + grub_dprintf ("atkeyb", "returned set %d\n", current_set); if (current_set == 1) return; grub_printf ("No supported scancode set found\n"); @@ -334,7 +348,7 @@ fetch_key (int *is_break) } /* Setting LEDs may generate ACKs. */ - if (at_key == 0xfa) + if (at_key == GRUB_AT_ACK) return -1; was_ext = e0_received; @@ -540,8 +554,14 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus pending_key = -1; at_keyboard_status = 0; /* Drain input buffer. */ - while (KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) - grub_inb (KEYBOARD_REG_DATA); + while (1) + { + keyboard_controller_wait_until_ready (); + if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + break; + keyboard_controller_wait_until_ready (); + grub_inb (KEYBOARD_REG_DATA); + } grub_keyboard_controller_orig = grub_keyboard_controller_read (); set_scancodes (); keyboard_controller_led (led_status); From df2174ddedad2a1ae8d404476ae90069c3573adb Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 12:07:49 +0200 Subject: [PATCH 51/64] Remove checkkey on term level --- include/grub/i386/pc/console.h | 1 - include/grub/term.h | 5 +-- include/grub/terminfo.h | 1 - kern/emu/console.c | 40 +++-------------------- kern/i386/pc/startup.S | 58 ++++++++-------------------------- kern/term.c | 21 +++++++++--- term/at_keyboard.c | 36 +-------------------- term/efi/console.c | 48 +++------------------------- term/i386/pc/console.c | 1 - term/ieee1275/ofconsole.c | 1 - term/serial.c | 1 - term/terminfo.c | 43 ++++++++++--------------- term/usb_keyboard.c | 49 +++++----------------------- 13 files changed, 65 insertions(+), 240 deletions(-) diff --git a/include/grub/i386/pc/console.h b/include/grub/i386/pc/console.h index fabb13d5c..1631a40ad 100644 --- a/include/grub/i386/pc/console.h +++ b/include/grub/i386/pc/console.h @@ -27,7 +27,6 @@ #include /* These are global to share code between C and asm. */ -int grub_console_checkkey (struct grub_term_input *term); int grub_console_getkey (struct grub_term_input *term); grub_uint16_t grub_console_getxy (struct grub_term_output *term); void grub_console_gotoxy (struct grub_term_output *term, diff --git a/include/grub/term.h b/include/grub/term.h index bfe1c8f9b..428978142 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -158,10 +158,7 @@ struct grub_term_input /* Clean up the terminal. */ grub_err_t (*fini) (struct grub_term_input *term); - /* Check if any input character is available. */ - int (*checkkey) (struct grub_term_input *term); - - /* Get a character. */ + /* Get a character if any input character is available. Otherwise return -1 */ int (*getkey) (struct grub_term_input *term); /* Get keyboard modifier status. */ diff --git a/include/grub/terminfo.h b/include/grub/terminfo.h index 85ddb5779..1962c71b7 100644 --- a/include/grub/terminfo.h +++ b/include/grub/terminfo.h @@ -64,7 +64,6 @@ void EXPORT_FUNC (grub_terminfo_setcolorstate) (struct grub_term_output *term, const grub_term_color_state state); -int EXPORT_FUNC (grub_terminfo_checkkey) (struct grub_term_input *term); grub_err_t EXPORT_FUNC (grub_terminfo_input_init) (struct grub_term_input *term); int EXPORT_FUNC (grub_terminfo_getkey) (struct grub_term_input *term); void EXPORT_FUNC (grub_terminfo_putchar) (struct grub_term_output *term, diff --git a/kern/emu/console.c b/kern/emu/console.c index f6b13b19b..0bf1e05f9 100644 --- a/kern/emu/console.c +++ b/kern/emu/console.c @@ -102,49 +102,18 @@ grub_ncurses_setcolorstate (struct grub_term_output *term, } } -static int saved_char = ERR; - -static int -grub_ncurses_checkkey (struct grub_term_input *term __attribute__ ((unused))) -{ - int c; - - /* Check for SAVED_CHAR. This should not be true, because this - means checkkey is called twice continuously. */ - if (saved_char != ERR) - return saved_char; - - wtimeout (stdscr, 100); - c = getch (); - /* If C is not ERR, then put it back in the input queue. */ - if (c != ERR) - { - saved_char = c; - return c; - } - - return -1; -} - static int grub_ncurses_getkey (struct grub_term_input *term __attribute__ ((unused))) { int c; - /* If checkkey has already got a character, then return it. */ - if (saved_char != ERR) - { - c = saved_char; - saved_char = ERR; - } - else - { - wtimeout (stdscr, -1); - c = getch (); - } + wtimeout (stdscr, 100); + c = getch (); switch (c) { + case ERR: + return -1; case KEY_LEFT: c = GRUB_TERM_LEFT; break; @@ -288,7 +257,6 @@ grub_ncurses_fini (struct grub_term_output *term __attribute__ ((unused))) static struct grub_term_input grub_ncurses_term_input = { .name = "console", - .checkkey = grub_ncurses_checkkey, .getkey = grub_ncurses_getkey, }; diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index f78fb5baa..2d7264156 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1154,6 +1154,16 @@ LOCAL(bypass_table_end): /* * int grub_console_getkey (void) + * if there is a character pending, return it; otherwise return -1 + * BIOS call "INT 16H Function 01H" to check whether a character is pending + * Call with %ah = 0x1 + * Return: + * If key waiting to be input: + * %ah = keyboard scan code + * %al = ASCII character + * Zero flag = clear + * else + * Zero flag = set * BIOS call "INT 16H Function 00H" to read character from keyboard * Call with %ah = 0x0 * Return: %ah = keyboard scan code @@ -1173,14 +1183,9 @@ FUNCTION(grub_console_getkey) * INT 16/AH = 1 before calling INT 16/AH = 0. */ -1: movb $1, %ah int $0x16 - jnz 2f - hlt - jmp 1b - -2: + jz notpending movb $0, %ah int $0x16 @@ -1217,47 +1222,12 @@ FUNCTION(grub_console_getkey) popl %ebp ret -/* - * int grub_console_checkkey (void) - * if there is a character pending, return it; otherwise return -1 - * BIOS call "INT 16H Function 01H" to check whether a character is pending - * Call with %ah = 0x1 - * Return: - * If key waiting to be input: - * %ah = keyboard scan code - * %al = ASCII character - * Zero flag = clear - * else - * Zero flag = set - */ -FUNCTION(grub_console_checkkey) - pushl %ebp - xorl %edx, %edx - - call prot_to_real /* enter real mode */ +notpending: .code16 - - movb $0x1, %ah - int $0x16 - - jz notpending - - xorl %edx, %edx - movw %ax, %dx - DATA32 jmp pending - -notpending: - xorl %edx, %edx - decl %edx - -pending: DATA32 call real_to_prot .code32 - - movl %edx, %eax - - popl %ebp - ret + decl %eax + jmp 2b /* diff --git a/kern/term.c b/kern/term.c index 185626d36..a05325346 100644 --- a/kern/term.c +++ b/kern/term.c @@ -78,6 +78,8 @@ grub_xputs_dumb (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_dumb; +static int pending_key = -1; + int grub_getkey (void) { @@ -85,6 +87,12 @@ grub_getkey (void) grub_refresh (); + if (pending_key != -1) + { + pending_key = -1; + return pending_key; + } + while (1) { if (grub_term_poll_usb) @@ -92,9 +100,9 @@ grub_getkey (void) FOR_ACTIVE_TERM_INPUTS(term) { - int key = term->checkkey (term); + int key = term->getkey (term); if (key != -1) - return term->getkey (term); + return key; } grub_cpu_idle (); @@ -106,14 +114,17 @@ grub_checkkey (void) { grub_term_input_t term; + if (pending_key != -1) + return pending_key; + if (grub_term_poll_usb) grub_term_poll_usb (); FOR_ACTIVE_TERM_INPUTS(term) { - int key = term->checkkey (term); - if (key != -1) - return key; + pending_key = term->getkey (term); + if (pending_key != -1) + return pending_key; } return -1; diff --git a/term/at_keyboard.c b/term/at_keyboard.c index e9db7834a..6ea908a2b 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -28,7 +28,6 @@ static short at_keyboard_status = 0; static int e0_received = 0; static int f0_received = 0; -static int pending_key = -1; static grub_uint8_t led_status; @@ -478,7 +477,7 @@ grub_keyboard_getkey (void) /* If there is a character pending, return it; otherwise return -1. */ static int -grub_at_keyboard_getkey_noblock (void) +grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) { int code; code = grub_keyboard_getkey (); @@ -517,41 +516,9 @@ grub_at_keyboard_getkey_noblock (void) } } -static int -grub_at_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused))) -{ - if (pending_key != -1) - return 1; - - pending_key = grub_at_keyboard_getkey_noblock (); - - if (pending_key != -1) - return 1; - - return -1; -} - -static int -grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) -{ - int key; - if (pending_key != -1) - { - key = pending_key; - pending_key = -1; - return key; - } - do - { - key = grub_at_keyboard_getkey_noblock (); - } while (key == -1); - return key; -} - static grub_err_t grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unused))) { - pending_key = -1; at_keyboard_status = 0; /* Drain input buffer. */ while (1) @@ -583,7 +550,6 @@ static struct grub_term_input grub_at_keyboard_term = .name = "at_keyboard", .init = grub_keyboard_controller_init, .fini = grub_keyboard_controller_fini, - .checkkey = grub_at_keyboard_checkkey, .getkey = grub_at_keyboard_getkey }; diff --git a/term/efi/console.c b/term/efi/console.c index f47263ee4..97fefd981 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -28,8 +28,6 @@ static const grub_uint8_t grub_console_standard_color = GRUB_EFI_TEXT_ATTR (GRUB_EFI_YELLOW, GRUB_EFI_BACKGROUND_BLACK); -static int read_key = -1; - static grub_uint32_t map_char (grub_uint32_t c) { @@ -112,15 +110,12 @@ const unsigned efi_codes[] = static int -grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) +grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) { grub_efi_simple_input_interface_t *i; grub_efi_input_key_t key; grub_efi_status_t status; - if (read_key >= 0) - return 1; - i = grub_efi_system_table->con_in; status = efi_call_2 (i->read_key_stroke, i, &key); @@ -128,45 +123,11 @@ grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) return -1; if (key.scan_code == 0) - read_key = key.unicode_char; + return key.unicode_char; else if (key.scan_code < ARRAY_SIZE (efi_codes)) - read_key = efi_codes[key.scan_code]; + return efi_codes[key.scan_code]; - return read_key; -} - -static int -grub_console_getkey (struct grub_term_input *term) -{ - grub_efi_simple_input_interface_t *i; - grub_efi_boot_services_t *b; - grub_efi_uintn_t index; - grub_efi_status_t status; - int key; - - if (read_key >= 0) - { - key = read_key; - read_key = -1; - return key; - } - - i = grub_efi_system_table->con_in; - b = grub_efi_system_table->boot_services; - - do - { - status = efi_call_3 (b->wait_for_event, 1, &(i->wait_for_key), &index); - if (status != GRUB_EFI_SUCCESS) - return -1; - - grub_console_checkkey (term); - } - while (read_key < 0); - - key = read_key; - read_key = -1; - return key; + return -1; } static grub_uint16_t @@ -268,7 +229,6 @@ grub_efi_console_fini (struct grub_term_output *term) static struct grub_term_input grub_console_term_input = { .name = "console", - .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, }; diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index 009647c4c..0efeafe4e 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -34,7 +34,6 @@ grub_console_getkeystatus (struct grub_term_input *term __attribute__ ((unused)) static struct grub_term_input grub_console_term_input = { .name = "console", - .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, .getkeystatus = grub_console_getkeystatus }; diff --git a/term/ieee1275/ofconsole.c b/term/ieee1275/ofconsole.c index 604906ceb..e6550254f 100644 --- a/term/ieee1275/ofconsole.c +++ b/term/ieee1275/ofconsole.c @@ -189,7 +189,6 @@ static struct grub_term_input grub_ofconsole_term_input = { .name = "ofconsole", .init = grub_ofconsole_init_input, - .checkkey = grub_terminfo_checkkey, .getkey = grub_terminfo_getkey, .data = &grub_ofconsole_terminfo_input }; diff --git a/term/serial.c b/term/serial.c index 2268788af..f435a7bc5 100644 --- a/term/serial.c +++ b/term/serial.c @@ -99,7 +99,6 @@ static struct grub_term_input grub_serial_term_input = { .name = "serial", .init = grub_terminfo_input_init, - .checkkey = grub_terminfo_checkkey, .getkey = grub_terminfo_getkey, .data = &grub_serial_terminfo_input }; diff --git a/term/terminfo.c b/term/terminfo.c index 5379aac0c..d2d821449 100644 --- a/term/terminfo.c +++ b/term/terminfo.c @@ -467,39 +467,30 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, #undef CONTINUE_READ } -/* The terminfo version of checkkey. */ -int -grub_terminfo_checkkey (struct grub_term_input *termi) -{ - struct grub_terminfo_input_state *data - = (struct grub_terminfo_input_state *) (termi->data); - if (data->npending) - return data->input_buf[0]; - - grub_terminfo_readkey (termi, data->input_buf, - &data->npending, data->readkey); - - if (data->npending) - return data->input_buf[0]; - - return -1; -} - /* The terminfo version of getkey. */ int grub_terminfo_getkey (struct grub_term_input *termi) { struct grub_terminfo_input_state *data = (struct grub_terminfo_input_state *) (termi->data); - int ret; - while (! data->npending) - grub_terminfo_readkey (termi, data->input_buf, &data->npending, - data->readkey); + if (data->npending) + { + data->npending--; + grub_memmove (data->input_buf, data->input_buf + 1, data->npending); + return data->input_buf[0]; + } - ret = data->input_buf[0]; - data->npending--; - grub_memmove (data->input_buf, data->input_buf + 1, data->npending); - return ret; + grub_terminfo_readkey (termi, data->input_buf, + &data->npending, data->readkey); + + if (data->npending) + { + data->npending--; + grub_memmove (data->input_buf, data->input_buf + 1, data->npending); + return data->input_buf[0]; + } + + return -1; } grub_err_t diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index b57b171f8..ca3a81179 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -68,7 +68,6 @@ struct grub_usb_keyboard_data grub_usb_device_t usbdev; grub_uint8_t status; grub_uint16_t mods; - int key; int interfno; struct grub_usb_desc_endp *endp; grub_usb_transfer_t transfer; @@ -78,15 +77,11 @@ struct grub_usb_keyboard_data grub_uint64_t repeat_time; }; -static struct grub_term_input grub_usb_keyboards[16]; - -static int grub_usb_keyboard_checkkey (struct grub_term_input *term); static int grub_usb_keyboard_getkey (struct grub_term_input *term); static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term); static struct grub_term_input grub_usb_keyboard_term = { - .checkkey = grub_usb_keyboard_checkkey, .getkey = grub_usb_keyboard_getkey, .getkeystatus = grub_usb_keyboard_getkeystatus, .next = 0 @@ -231,19 +226,12 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) USB_HID_GET_REPORT, 0x0100, interfno, sizeof (report), (char *) report); if (err) - { - data->status = 0; - data->key = -1; - } + data->status = 0; else - { - data->status = report[0]; - data->key = report[2] ? : -1; - } + data->status = report[0]; } #else data->status = 0; - data->key = -1; #endif data->transfer = grub_usb_bulk_read_background (usbdev, @@ -283,16 +271,13 @@ send_leds (struct grub_usb_keyboard_data *termdata) } static int -grub_usb_keyboard_checkkey (struct grub_term_input *term) +grub_usb_keyboard_getkey (struct grub_term_input *term) { grub_usb_err_t err; struct grub_usb_keyboard_data *termdata = term->data; grub_uint8_t data[sizeof (termdata->report)]; grub_size_t actual; - if (termdata->key != -1) - return termdata->key; - if (termdata->dead) return -1; @@ -304,11 +289,11 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) if (termdata->last_key != -1 && grub_get_time_ms () > termdata->repeat_time) { - termdata->key = termdata->last_key; termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_INTERVAL; + return termdata->last_key; } - return termdata->key; + return -1; } grub_memcpy (data, termdata->report, sizeof (data)); @@ -358,29 +343,13 @@ grub_usb_keyboard_checkkey (struct grub_term_input *term) return -1; } - termdata->last_key = termdata->key - = grub_term_map_key (data[2], interpret_status (data[0]) | termdata->mods); + termdata->last_key = grub_term_map_key (data[2], interpret_status (data[0]) + | termdata->mods); termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_PRE_INTERVAL; grub_errno = GRUB_ERR_NONE; - return termdata->key; -} - -static int -grub_usb_keyboard_getkey (struct grub_term_input *term) -{ - int ret; - struct grub_usb_keyboard_data *termdata = term->data; - - while (termdata->key == -1) - grub_usb_keyboard_checkkey (term); - - ret = termdata->key; - - termdata->key = -1; - - return ret; + return termdata->last_key; } static int @@ -388,8 +357,6 @@ grub_usb_keyboard_getkeystatus (struct grub_term_input *term) { struct grub_usb_keyboard_data *termdata = term->data; - grub_usb_keyboard_checkkey (term); - return interpret_status (termdata->status) | termdata->mods; } From 9518e2a12bab434d0ba96df15773487f6adf0608 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 12:53:42 +0200 Subject: [PATCH 52/64] Macroify GRUB_TERM_NO_KEY and use grub_checkkey in grub_getkey --- include/grub/term.h | 2 ++ kern/i386/pc/startup.S | 3 +++ kern/term.c | 50 +++++++++++++++--------------------------- term/at_keyboard.c | 11 +++++----- term/efi/console.c | 4 ++-- term/terminfo.c | 2 +- term/usb_keyboard.c | 14 ++++++------ 7 files changed, 39 insertions(+), 47 deletions(-) diff --git a/include/grub/term.h b/include/grub/term.h index 428978142..81c18365c 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -19,6 +19,8 @@ #ifndef GRUB_TERM_HEADER #define GRUB_TERM_HEADER 1 +#define GRUB_TERM_NO_KEY -1 + /* Internal codes used by GRUB to represent terminal input. */ /* Only for keys otherwise not having shifted modification. */ #define GRUB_TERM_SHIFT 0x01000000 diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 2d7264156..5a6934dee 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1226,6 +1226,9 @@ notpending: .code16 DATA32 call real_to_prot .code32 +#if GRUB_TERM_NO_KEY != -1 +#error Fix this asm code +#endif decl %eax jmp 2b diff --git a/kern/term.c b/kern/term.c index a05325346..9d23b4f91 100644 --- a/kern/term.c +++ b/kern/term.c @@ -78,43 +78,14 @@ grub_xputs_dumb (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_dumb; -static int pending_key = -1; - -int -grub_getkey (void) -{ - grub_term_input_t term; - - grub_refresh (); - - if (pending_key != -1) - { - pending_key = -1; - return pending_key; - } - - while (1) - { - if (grub_term_poll_usb) - grub_term_poll_usb (); - - FOR_ACTIVE_TERM_INPUTS(term) - { - int key = term->getkey (term); - if (key != -1) - return key; - } - - grub_cpu_idle (); - } -} +static int pending_key = GRUB_TERM_NO_KEY; int grub_checkkey (void) { grub_term_input_t term; - if (pending_key != -1) + if (pending_key != GRUB_TERM_NO_KEY) return pending_key; if (grub_term_poll_usb) @@ -123,13 +94,28 @@ grub_checkkey (void) FOR_ACTIVE_TERM_INPUTS(term) { pending_key = term->getkey (term); - if (pending_key != -1) + if (pending_key != GRUB_TERM_NO_KEY) return pending_key; } return -1; } +int +grub_getkey (void) +{ + grub_refresh (); + + while (pending_key != GRUB_TERM_NO_KEY) + { + grub_cpu_idle (); + grub_checkkey (); + } + pending_key = GRUB_TERM_NO_KEY; + return pending_key; +} + + void grub_refresh (void) { diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 6ea908a2b..681dd3ef9 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -475,14 +475,15 @@ grub_keyboard_getkey (void) return key; } -/* If there is a character pending, return it; otherwise return -1. */ +/* If there is a character pending, return it; + otherwise return GRUB_TERM_NO_KEY. */ static int grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) { int code; code = grub_keyboard_getkey (); if (code == -1) - return -1; + return GRUB_TERM_NO_KEY; #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "Detected key 0x%x\n", key); #endif @@ -496,7 +497,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK)); #endif - return -1; + return GRUB_TERM_NO_KEY; case GRUB_KEYBOARD_KEY_NUM_LOCK: at_keyboard_status ^= GRUB_TERM_STATUS_NUM; led_status ^= KEYBOARD_LED_NUM; @@ -505,12 +506,12 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_NUM_LOCK)); #endif - return -1; + return GRUB_TERM_NO_KEY; case GRUB_KEYBOARD_KEY_SCROLL_LOCK: at_keyboard_status ^= GRUB_TERM_STATUS_SCROLL; led_status ^= KEYBOARD_LED_SCROLL; keyboard_controller_led (led_status); - return -1; + return GRUB_TERM_NO_KEY; default: return grub_term_map_key (code, at_keyboard_status); } diff --git a/term/efi/console.c b/term/efi/console.c index 97fefd981..1667bcd4f 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -120,14 +120,14 @@ grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) status = efi_call_2 (i->read_key_stroke, i, &key); if (status != GRUB_EFI_SUCCESS) - return -1; + return GRUB_TERM_NO_KEY; if (key.scan_code == 0) return key.unicode_char; else if (key.scan_code < ARRAY_SIZE (efi_codes)) return efi_codes[key.scan_code]; - return -1; + return GRUB_TERM_NO_KEY; } static grub_uint16_t diff --git a/term/terminfo.c b/term/terminfo.c index d2d821449..8dea7aea1 100644 --- a/term/terminfo.c +++ b/term/terminfo.c @@ -490,7 +490,7 @@ grub_terminfo_getkey (struct grub_term_input *termi) return data->input_buf[0]; } - return -1; + return GRUB_TERM_NO_KEY; } grub_err_t diff --git a/term/usb_keyboard.c b/term/usb_keyboard.c index ca3a81179..6b1485e96 100644 --- a/term/usb_keyboard.c +++ b/term/usb_keyboard.c @@ -279,7 +279,7 @@ grub_usb_keyboard_getkey (struct grub_term_input *term) grub_size_t actual; if (termdata->dead) - return -1; + return GRUB_TERM_NO_KEY; /* Poll interrupt pipe. */ err = grub_usb_check_transfer (termdata->transfer, &actual); @@ -293,7 +293,7 @@ grub_usb_keyboard_getkey (struct grub_term_input *term) + GRUB_TERM_REPEAT_INTERVAL; return termdata->last_key; } - return -1; + return GRUB_TERM_NO_KEY; } grub_memcpy (data, termdata->report, sizeof (data)); @@ -318,29 +318,29 @@ grub_usb_keyboard_getkey (struct grub_term_input *term) data[4], data[5], data[6], data[7]); if (err || actual < 1) - return -1; + return GRUB_TERM_NO_KEY; termdata->status = data[0]; if (actual < 3) - return -1; + return GRUB_TERM_NO_KEY; if (data[2] == KEY_NO_KEY || data[2] == KEY_ERR_BUFFER || data[2] == KEY_ERR_POST || data[2] == KEY_ERR_UNDEF) - return -1; + return GRUB_TERM_NO_KEY; if (data[2] == KEY_CAPS_LOCK) { termdata->mods ^= GRUB_TERM_STATUS_CAPS; send_leds (termdata); - return -1; + return GRUB_TERM_NO_KEY; } if (data[2] == KEY_NUM_LOCK) { termdata->mods ^= GRUB_TERM_STATUS_NUM; send_leds (termdata); - return -1; + return GRUB_TERM_NO_KEY; } termdata->last_key = grub_term_map_key (data[2], interpret_status (data[0]) From 071b673a7b50b59754841cf1c1f888c51d0a670e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 13:12:29 +0200 Subject: [PATCH 53/64] Fix bugs in grub_getkey introduced in previous commit --- kern/term.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kern/term.c b/kern/term.c index 9d23b4f91..7b3593161 100644 --- a/kern/term.c +++ b/kern/term.c @@ -104,15 +104,19 @@ grub_checkkey (void) int grub_getkey (void) { + int ret; + grub_refresh (); - while (pending_key != GRUB_TERM_NO_KEY) + grub_checkkey (); + while (pending_key == GRUB_TERM_NO_KEY) { grub_cpu_idle (); grub_checkkey (); } + ret = pending_key; pending_key = GRUB_TERM_NO_KEY; - return pending_key; + return ret; } From 9f5a5ad55a2593e89bb2278101fcaea8a35e61c1 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 13:21:26 +0200 Subject: [PATCH 54/64] Fix RCTRL and RALT linux scancodes --- util/grub-mklayout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index e22888fc5..c07869eae 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -375,11 +375,11 @@ write_keymaps (FILE *in, FILE *out) /* Not remappable. */ if (keycode_linux == 0x1d /* Left CTRL */ - || keycode_linux == 0x9d /* Right CTRL */ + || keycode_linux == 0x61 /* Right CTRL */ || keycode_linux == 0x2a /* Left Shift. */ || keycode_linux == 0x36 /* Right Shift. */ || keycode_linux == 0x38 /* Left ALT. */ - || keycode_linux == 0xb8 /* Right ALT. */ + || keycode_linux == 0x64 /* Right ALT. */ || keycode_linux == 0x3a /* CapsLock. */ || keycode_linux == 0x45 /* NumLock. */ || keycode_linux == 0x46 /* ScrollLock. */) From 3ba3c4567e1edcb0a45e543f86e0683ec5b7057c Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 13:21:53 +0200 Subject: [PATCH 55/64] Change GRUB_TERM_NO_KEY to 0 --- include/grub/term.h | 2 +- kern/i386/pc/startup.S | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/grub/term.h b/include/grub/term.h index 81c18365c..dbcb2f52c 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -19,7 +19,7 @@ #ifndef GRUB_TERM_HEADER #define GRUB_TERM_HEADER 1 -#define GRUB_TERM_NO_KEY -1 +#define GRUB_TERM_NO_KEY 0 /* Internal codes used by GRUB to represent terminal input. */ /* Only for keys otherwise not having shifted modification. */ diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 5a6934dee..f7a924fa8 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -1226,10 +1226,9 @@ notpending: .code16 DATA32 call real_to_prot .code32 -#if GRUB_TERM_NO_KEY != -1 +#if GRUB_TERM_NO_KEY != 0 #error Fix this asm code #endif - decl %eax jmp 2b From 400ef90dba295d1f3ed38c10020d34b3365bbcb1 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 20:40:06 +0200 Subject: [PATCH 56/64] Fix reversal of NPAGE and PPAGE when handling Linux keymaps --- util/grub-mklayout.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c index c07869eae..ac59981c7 100644 --- a/util/grub-mklayout.c +++ b/util/grub-mklayout.c @@ -244,9 +244,9 @@ static grub_uint8_t linux_to_usb_map[128] = { /* 0x62 */ GRUB_KEYBOARD_KEY_NUMSLASH, 0, /* 0x64 */ GRUB_KEYBOARD_KEY_RIGHT_ALT, 0, /* 0x66 */ GRUB_KEYBOARD_KEY_HOME, GRUB_KEYBOARD_KEY_UP, - /* 0x68 */ GRUB_KEYBOARD_KEY_NPAGE, GRUB_KEYBOARD_KEY_LEFT, + /* 0x68 */ GRUB_KEYBOARD_KEY_PPAGE, GRUB_KEYBOARD_KEY_LEFT, /* 0x6a */ GRUB_KEYBOARD_KEY_RIGHT, GRUB_KEYBOARD_KEY_END, - /* 0x6c */ GRUB_KEYBOARD_KEY_DOWN, GRUB_KEYBOARD_KEY_PPAGE, + /* 0x6c */ GRUB_KEYBOARD_KEY_DOWN, GRUB_KEYBOARD_KEY_NPAGE, /* 0x6e */ GRUB_KEYBOARD_KEY_INSERT, GRUB_KEYBOARD_KEY_DELETE }; From f0b02c9c86daa78b3580e1de60986d1eea65f9d0 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 20:43:44 +0200 Subject: [PATCH 57/64] Handle ACKs, NACKs and restore state on booting --- include/grub/at_keyboard.h | 2 + term/at_keyboard.c | 115 +++++++++++++++++++++++++++---------- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 3dfa0da80..65cf8a2a2 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -28,6 +28,8 @@ #define KEYBOARD_AT_TRANSLATE 0x40 #define GRUB_AT_ACK 0xfa +#define GRUB_AT_NACK 0xfe +#define GRUB_AT_TRIES 5 #define KEYBOARD_ISMAKE(x) !((x) & 0x80) #define KEYBOARD_ISREADY(x) ((x) & 0x01) diff --git a/term/at_keyboard.c b/term/at_keyboard.c index 681dd3ef9..1b130bd62 100644 --- a/term/at_keyboard.c +++ b/term/at_keyboard.c @@ -24,6 +24,7 @@ #include #include #include +#include static short at_keyboard_status = 0; static int e0_received = 0; @@ -215,39 +216,76 @@ keyboard_controller_wait_until_ready (void) while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS))); } +static grub_uint8_t +wait_ack (void) +{ + grub_uint64_t endtime; + grub_uint8_t ack; + + endtime = grub_get_time_ms () + 20; + do + ack = grub_inb (KEYBOARD_REG_DATA); + while (ack != GRUB_AT_ACK && ack != GRUB_AT_NACK + && grub_get_time_ms () < endtime); + return ack; +} + +static int +at_command (grub_uint8_t data) +{ + unsigned i; + for (i = 0; i < GRUB_AT_TRIES; i++) + { + grub_uint8_t ack; + keyboard_controller_wait_until_ready (); + grub_outb (data, KEYBOARD_REG_STATUS); + ack = wait_ack (); + if (ack == GRUB_AT_NACK) + continue; + if (ack == GRUB_AT_ACK) + break; + return 0; + } + return (i != GRUB_AT_TRIES); +} + static void grub_keyboard_controller_write (grub_uint8_t c) { - keyboard_controller_wait_until_ready (); - grub_outb (KEYBOARD_COMMAND_WRITE, KEYBOARD_REG_STATUS); + at_command (KEYBOARD_COMMAND_WRITE); keyboard_controller_wait_until_ready (); grub_outb (c, KEYBOARD_REG_DATA); } -static int -wait_ack (void) +static grub_uint8_t +grub_keyboard_controller_read (void) { - grub_uint8_t ack; - grub_uint64_t endtime = grub_get_time_ms () + 20; - do - { - ack = grub_inb (KEYBOARD_REG_DATA); - } - while (ack != GRUB_AT_ACK && grub_get_time_ms () < endtime); - grub_dprintf ("atkeyb", "Ack 0x%02x\n", ack); - return ack == GRUB_AT_ACK; + at_command (KEYBOARD_COMMAND_READ); + keyboard_controller_wait_until_ready (); + return grub_inb (KEYBOARD_REG_DATA); } static int write_mode (int mode) { - keyboard_controller_wait_until_ready (); - grub_outb (0xf0, KEYBOARD_REG_DATA); - keyboard_controller_wait_until_ready (); - grub_outb (mode, KEYBOARD_REG_DATA); - keyboard_controller_wait_until_ready (); + unsigned i; + for (i = 0; i < GRUB_AT_TRIES; i++) + { + grub_uint8_t ack; + keyboard_controller_wait_until_ready (); + grub_outb (0xf0, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + grub_outb (mode, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + ack = wait_ack (); + if (ack == GRUB_AT_NACK) + continue; + if (ack == GRUB_AT_ACK) + break; + return 0; + } - return wait_ack (); + return (i != GRUB_AT_TRIES); } static int @@ -276,11 +314,9 @@ query_mode (void) return 0; } - static void set_scancodes (void) { - grub_keyboard_orig_set = query_mode (); /* You must have visited computer museum. Keyboard without scancode set knowledge. Assume XT. */ if (!grub_keyboard_orig_set) @@ -307,14 +343,6 @@ set_scancodes (void) grub_printf ("No supported scancode set found\n"); } -static grub_uint8_t -grub_keyboard_controller_read (void) -{ - keyboard_controller_wait_until_ready (); - grub_outb (KEYBOARD_COMMAND_READ, KEYBOARD_REG_STATUS); - return grub_inb (KEYBOARD_REG_DATA); -} - static void keyboard_controller_led (grub_uint8_t leds) { @@ -531,6 +559,7 @@ grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unus grub_inb (KEYBOARD_REG_DATA); } grub_keyboard_controller_orig = grub_keyboard_controller_read (); + grub_keyboard_orig_set = query_mode (); set_scancodes (); keyboard_controller_led (led_status); @@ -546,6 +575,31 @@ grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unus return GRUB_ERR_NONE; } +static grub_err_t +grub_at_fini_hw (int noreturn __attribute__ ((unused))) +{ + return grub_keyboard_controller_fini (NULL); +} + +static grub_err_t +grub_at_restore_hw (void) +{ + /* Drain input buffer. */ + while (1) + { + keyboard_controller_wait_until_ready (); + if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + break; + keyboard_controller_wait_until_ready (); + grub_inb (KEYBOARD_REG_DATA); + } + set_scancodes (); + keyboard_controller_led (led_status); + + return GRUB_ERR_NONE; +} + + static struct grub_term_input grub_at_keyboard_term = { .name = "at_keyboard", @@ -557,9 +611,12 @@ static struct grub_term_input grub_at_keyboard_term = GRUB_MOD_INIT(at_keyboard) { grub_term_register_input ("at_keyboard", &grub_at_keyboard_term); + grub_loader_register_preboot_hook (grub_at_fini_hw, grub_at_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE); } GRUB_MOD_FINI(at_keyboard) { + grub_keyboard_controller_fini (NULL); grub_term_unregister_input (&grub_at_keyboard_term); } From 7c4425061d365271aee7c90aadbd2356b63cd73a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 23:27:59 +0200 Subject: [PATCH 58/64] Don't reuse finished but not reclaimed QH --- bus/usb/uhci.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/bus/usb/uhci.c b/bus/usb/uhci.c index 472a7054e..b719051d6 100644 --- a/bus/usb/uhci.c +++ b/bus/usb/uhci.c @@ -28,6 +28,8 @@ #define GRUB_UHCI_IOMASK (0x7FF << 5) +#define N_QH 256 + typedef enum { GRUB_UHCI_REG_USBCMD = 0x00, @@ -99,7 +101,7 @@ struct grub_uhci int iobase; grub_uint32_t *framelist; - /* 256 Queue Heads. */ + /* N_QH Queue Heads. */ grub_uhci_qh_t qh; /* 256 Transfer Descriptors. */ @@ -108,6 +110,8 @@ struct grub_uhci /* Free Transfer Descriptors. */ grub_uhci_td_t tdfree; + int qh_busy[N_QH]; + struct grub_uhci *next; }; @@ -260,7 +264,7 @@ grub_uhci_pci_iter (grub_pci_device_t dev, (grub_uint32_t) u->framelist); /* Make the Queue Heads point to each other. */ - for (i = 0; i < 256; i++) + for (i = 0; i < N_QH; i++) { /* Point to the next QH. */ u->qh[i].linkptr = (grub_uint32_t) (&u->qh[i + 1]) & (~15); @@ -273,9 +277,8 @@ grub_uhci_pci_iter (grub_pci_device_t dev, u->qh[i].elinkptr = 1; } - /* The last Queue Head should terminate. 256 are too many QHs so - just use 50. */ - u->qh[50 - 1].linkptr = 1; + /* The last Queue Head should terminate. */ + u->qh[N_QH - 1].linkptr = 1; /* Enable UHCI again. */ grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7)); @@ -344,11 +347,13 @@ grub_free_td (struct grub_uhci *u, grub_uhci_td_t td) } static void -grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td, +grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td, grub_usb_transfer_t transfer, grub_size_t *actual) { int i; /* Index of TD in transfer */ + u->qh_busy[qh - u->qh] = 0; + *actual = 0; /* Free the TDs in this queue and set last_trans. */ @@ -387,19 +392,21 @@ grub_alloc_qh (struct grub_uhci *u, #endif i = 1; - for (; i < 255; i++) + for (; i < N_QH; i++) { - if (u->qh[i].elinkptr & 1) + if (!u->qh_busy[i]) break; } qh = &u->qh[i]; - if (! (qh->elinkptr & 1)) + if (i == N_QH) { grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free queue heads available"); return NULL; } + u->qh_busy[qh - u->qh] = 1; + return qh; } @@ -497,7 +504,7 @@ grub_uhci_setup_transfer (grub_usb_controller_t dev, td_prev->linkptr = 1; if (cdata->td_first) - grub_free_queue (u, cdata->td_first, NULL, &actual); + grub_free_queue (u, cdata->qh, cdata->td_first, NULL, &actual); grub_free (cdata); return GRUB_USB_ERR_INTERNAL; @@ -553,7 +560,7 @@ grub_uhci_check_transfer (grub_usb_controller_t dev, /* Place the QH back in the free list and deallocate the associated TDs. */ cdata->qh->elinkptr = 1; - grub_free_queue (u, cdata->td_first, transfer, actual); + grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual); grub_free (cdata); return GRUB_USB_ERR_NONE; } @@ -595,7 +602,7 @@ grub_uhci_check_transfer (grub_usb_controller_t dev, /* Place the QH back in the free list and deallocate the associated TDs. */ cdata->qh->elinkptr = 1; - grub_free_queue (u, cdata->td_first, transfer, actual); + grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual); grub_free (cdata); return err; @@ -622,7 +629,7 @@ grub_uhci_cancel_transfer (grub_usb_controller_t dev, /* Place the QH back in the free list and deallocate the associated TDs. */ cdata->qh->elinkptr = 1; - grub_free_queue (u, cdata->td_first, transfer, &actual); + grub_free_queue (u, cdata->qh, cdata->td_first, transfer, &actual); grub_free (cdata); return GRUB_USB_ERR_NONE; From a98f88ecfeee316f6cdcb4df1002d66029103886 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 23 Aug 2010 23:28:33 +0200 Subject: [PATCH 59/64] Add pot powered flag declaration --- include/grub/usbtrans.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index 9e9d75e5d..5ee276d26 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -130,6 +130,7 @@ enum GRUB_USB_HUB_STATUS_PORT_ENABLED = (1 << 1), GRUB_USB_HUB_STATUS_PORT_SUSPEND = (1 << 2), GRUB_USB_HUB_STATUS_PORT_OVERCURRENT = (1 << 3), + GRUB_USB_HUB_STATUS_PORT_POWERED = (1 << 8), GRUB_USB_HUB_STATUS_PORT_LOWSPEED = (1 << 9), GRUB_USB_HUB_STATUS_PORT_HIGHSPEED = (1 << 10), GRUB_USB_HUB_STATUS_C_PORT_CONNECTED = (1 << 16), From 69d6fc56036f18f3a9f69a78f24d6df8a40cfbb9 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 30 Aug 2010 01:04:07 +0200 Subject: [PATCH 60/64] Use interrupt endpoint for hubs --- bus/usb/usbhub.c | 290 +++++++++++++---------------------------------- 1 file changed, 81 insertions(+), 209 deletions(-) diff --git a/bus/usb/usbhub.c b/bus/usb/usbhub.c index 111a2495e..0ddba3255 100644 --- a/bus/usb/usbhub.c +++ b/bus/usb/usbhub.c @@ -28,6 +28,8 @@ /* USB Supports 127 devices, with device 0 as special case. */ static struct grub_usb_device *grub_usb_devs[GRUB_USBHUB_MAX_DEVICES]; +static int rescan = 0; + struct grub_usb_hub { struct grub_usb_hub *next; @@ -110,9 +112,6 @@ grub_usb_add_hub (grub_usb_device_t dev) struct grub_usb_usb_hubdesc hubdesc; grub_err_t err; int i; - grub_uint64_t timeout; - grub_usb_device_t next_dev; - grub_usb_device_t *attached_devices; err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | GRUB_USB_REQTYPE_CLASS @@ -131,11 +130,9 @@ grub_usb_add_hub (grub_usb_device_t dev) grub_dprintf ("usb", "Hub set configuration\n"); grub_usb_set_configuration (dev, 1); - attached_devices = grub_zalloc (hubdesc.portcnt - * sizeof (attached_devices[0])); - if (!attached_devices) + dev->children = grub_zalloc (hubdesc.portcnt * sizeof (dev->children[0])); + if (!dev->children) return GRUB_USB_ERR_INTERNAL; - dev->children = attached_devices; dev->nports = hubdesc.portcnt; /* Power on all Hub ports. */ @@ -143,115 +140,15 @@ grub_usb_add_hub (grub_usb_device_t dev) { grub_dprintf ("usb", "Power on - port %d\n", i); /* Power on the port and wait for possible device connect */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_SET_FEATURE, - GRUB_USB_HUB_FEATURE_PORT_POWER, - i, 0, NULL); - /* Just ignore the device if some error happened */ - if (err) - continue; - } - /* Wait for port power-on */ - if (hubdesc.pwdgood >= 50) - grub_millisleep (hubdesc.pwdgood * 2); - else - grub_millisleep (100); - - /* Iterate over the Hub ports. */ - for (i = 1; i <= hubdesc.portcnt; i++) - { - grub_uint32_t status; - - /* Get the port status. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_GET_STATUS, - 0, i, sizeof (status), (char *) &status); - /* Just ignore the device if the Hub does not report the - status. */ - if (err) - continue; - grub_dprintf ("usb", "Hub port %d status: 0x%02x\n", i, status); - - /* If connected, reset and enable the port. */ - if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) - { - grub_usb_speed_t speed; - - /* Determine the device speed. */ - if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) - speed = GRUB_USB_SPEED_LOW; - else - { - if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED) - speed = GRUB_USB_SPEED_HIGH; - else - speed = GRUB_USB_SPEED_FULL; - } - - /* A device is actually connected to this port. - * Now do reset of port. */ - grub_dprintf ("usb", "Reset hub port - port %d\n", i); - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_SET_FEATURE, - GRUB_USB_HUB_FEATURE_PORT_RESET, - i, 0, 0); - /* If the Hub does not cooperate for this port, just skip - the port. */ - if (err) - continue; - - /* Wait for reset procedure done */ - timeout = grub_get_time_ms () + 1000; - do - { - /* Get the port status. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_GET_STATUS, - 0, i, sizeof (status), (char *) &status); - } - while (!err && - !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) && - (grub_get_time_ms() < timeout) ); - if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) ) - continue; - - /* Wait a recovery time after reset, spec. says 10ms */ - grub_millisleep (10); - - /* Do reset of connection change bit */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, - i, 0, 0); - /* Just ignore the device if the Hub reports some error */ - if (err) - continue; - grub_dprintf ("usb", "Hub port - cleared connection change\n"); - - /* Add the device and assign a device address to it. */ - grub_dprintf ("usb", "Call hub_add_dev - port %d\n", i); - next_dev = grub_usb_hub_add_dev (&dev->controller, speed); - if (! next_dev) - continue; - - attached_devices[i - 1] = next_dev; - - /* If the device is a Hub, scan it for more devices. */ - if (next_dev->descdev.class == 0x09) - grub_usb_add_hub (next_dev); - } + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_SET_FEATURE, + GRUB_USB_HUB_FEATURE_PORT_POWER, + i, 0, NULL); } + /* Rest will be done on next usb poll. */ for (i = 0; i < dev->config[0].interf[0].descif->endpointcnt; i++) { @@ -271,6 +168,8 @@ grub_usb_add_hub (grub_usb_device_t dev) } } + rescan = 1; + return GRUB_ERR_NONE; } @@ -383,9 +282,6 @@ poll_nonroot_hub (grub_usb_device_t dev) { grub_err_t err; unsigned i; - grub_uint64_t timeout; - grub_usb_device_t next_dev; - grub_usb_device_t *attached_devices = dev->children; grub_uint8_t changed; grub_size_t actual; @@ -408,9 +304,6 @@ poll_nonroot_hub (grub_usb_device_t dev) if (err || actual == 0 || changed == 0) return; - grub_dprintf ("usb", "statuschanged = %02x, err = %d, actual = %d\n", - changed, err, actual); - /* Iterate over the Hub ports. */ for (i = 1; i <= dev->nports; i++) { @@ -426,17 +319,12 @@ poll_nonroot_hub (grub_usb_device_t dev) GRUB_USB_REQ_GET_STATUS, 0, i, sizeof (status), (char *) &status); + grub_printf ("i = %d, status = %08x\n", i, status); + if (err) continue; /* FIXME: properly handle these conditions. */ - if (status & GRUB_USB_HUB_STATUS_C_PORT_RESET) - grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_PORT_RESET, i, 0, 0); - if (status & GRUB_USB_HUB_STATUS_C_PORT_ENABLED) grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | GRUB_USB_REQTYPE_CLASS @@ -458,96 +346,72 @@ poll_nonroot_hub (grub_usb_device_t dev) GRUB_USB_REQ_CLEAR_FEATURE, GRUB_USB_HUB_FEATURE_C_PORT_OVERCURRENT, i, 0, 0); - if (!(status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED)) - continue; - - grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, i, 0, 0); - if (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED) { - detach_device (attached_devices[i-1]); - attached_devices[i - 1] = NULL; - } + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, i, 0, 0); + + detach_device (dev->children[i - 1]); + dev->children[i - 1] = NULL; - /* Connected and status of connection changed ? */ - if ((status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) - && (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED)) - { - grub_usb_speed_t speed; - - /* Determine the device speed. */ - if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) - speed = GRUB_USB_SPEED_LOW; - else + /* Connected and status of connection changed ? */ + if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) { - if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED) - speed = GRUB_USB_SPEED_HIGH; - else - speed = GRUB_USB_SPEED_FULL; + /* A device is actually connected to this port. + * Now do reset of port. */ + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_SET_FEATURE, + GRUB_USB_HUB_FEATURE_PORT_RESET, + i, 0, 0); + rescan = 1; } + } - /* A device is actually connected to this port. - * Now do reset of port. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_SET_FEATURE, - GRUB_USB_HUB_FEATURE_PORT_RESET, - i, 0, 0); - /* If the Hub does not cooperate for this port, just skip - the port. */ - if (err) - continue; + if (status & GRUB_USB_HUB_STATUS_C_PORT_RESET) + { + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_RESET, i, 0, 0); - /* Wait for reset procedure done */ - timeout = grub_get_time_ms () + 1000; - do - { - /* Get the port status. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_GET_STATUS, - 0, i, sizeof (status), (char *) &status); - } - while (!err && - !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) && - (grub_get_time_ms() < timeout) ); - if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) ) - continue; + if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) + { + grub_usb_speed_t speed; + grub_usb_device_t next_dev; - /* Wait a recovery time after reset, spec. says 10ms */ - grub_millisleep (10); + /* Determine the device speed. */ + if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) + speed = GRUB_USB_SPEED_LOW; + else + { + if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED) + speed = GRUB_USB_SPEED_HIGH; + else + speed = GRUB_USB_SPEED_FULL; + } - /* Do reset of connection change bit */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, - i, 0, 0); - /* Just ignore the device if the Hub reports some error */ - if (err) - continue; + /* Wait a recovery time after reset, spec. says 10ms */ + grub_millisleep (10); - /* Add the device and assign a device address to it. */ - next_dev = grub_usb_hub_add_dev (&dev->controller, speed); - if (! next_dev) - continue; + /* Add the device and assign a device address to it. */ + next_dev = grub_usb_hub_add_dev (&dev->controller, speed); + if (! next_dev) + continue; - attached_devices[i - 1] = next_dev; + dev->children[i - 1] = next_dev; - /* If the device is a Hub, scan it for more devices. */ - if (next_dev->descdev.class == 0x09) - grub_usb_add_hub (next_dev); + /* If the device is a Hub, scan it for more devices. */ + if (next_dev->descdev.class == 0x09) + grub_usb_add_hub (next_dev); + } } } - - return; } void @@ -578,13 +442,21 @@ grub_usb_poll_devices (void) } } - /* We should check changes of non-root hubs too. */ - for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++) + while (1) { - grub_usb_device_t dev = grub_usb_devs[i]; - - if (dev && dev->descdev.class == 0x09) - poll_nonroot_hub (dev); + rescan = 0; + + /* We should check changes of non-root hubs too. */ + for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++) + { + grub_usb_device_t dev = grub_usb_devs[i]; + + if (dev && dev->descdev.class == 0x09) + poll_nonroot_hub (dev); + } + if (!rescan) + break; + grub_millisleep (50); } } From b9c7e9d400b7473006b988a08e19d6bfe76bb795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Nesrsta?= Date: Sat, 18 Sep 2010 10:56:52 +0200 Subject: [PATCH 61/64] Set UHCI low-speed flag --- grub-core/bus/usb/uhci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index 755ec70f7..d51aace8c 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -414,7 +414,7 @@ static grub_uhci_td_t grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, grub_transfer_type_t type, unsigned int addr, unsigned int toggle, grub_size_t size, - grub_uint32_t data) + grub_uint32_t data, grub_usb_speed_t speed) { grub_uhci_td_t td; static const unsigned int tf[] = { 0x69, 0xE1, 0x2D }; @@ -439,7 +439,8 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, td->linkptr = 1; /* Active! Only retry a transfer 3 times. */ - td->ctrl_status = (1 << 23) | (3 << 27); + td->ctrl_status = (1 << 23) | (3 << 27) | + ((speed == GRUB_USB_SPEED_LOW) ? (1 << 26) : 0); /* If zero bytes are transmitted, size is 0x7FF. Otherwise size is size-1. */ @@ -495,7 +496,8 @@ grub_uhci_setup_transfer (grub_usb_controller_t dev, td = grub_uhci_transaction (u, transfer->endpoint & 15, tr->pid, transfer->devaddr, tr->toggle, - tr->size, tr->data); + tr->size, tr->data, + transfer->dev->speed); if (! td) { grub_size_t actual = 0; From e70a1b9535ee1af0c84cab327e006948973d463d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Nesrsta?= Date: Sat, 18 Sep 2010 13:49:15 +0200 Subject: [PATCH 62/64] Fix multiple USB issues --- grub-core/bus/usb/ohci.c | 194 ++++++++++++----------------------- grub-core/bus/usb/uhci.c | 48 +++++---- grub-core/bus/usb/usb.c | 2 +- grub-core/bus/usb/usbhub.c | 104 ++++++++++++++++--- grub-core/bus/usb/usbtrans.c | 4 +- include/grub/usb.h | 3 + 6 files changed, 195 insertions(+), 160 deletions(-) diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c index 7c618a614..b07e30403 100644 --- a/grub-core/bus/usb/ohci.c +++ b/grub-core/bus/usb/ohci.c @@ -98,7 +98,6 @@ struct grub_ohci struct grub_pci_dma_chunk *td_chunk; struct grub_ohci *next; grub_ohci_td_t td_free; /* Pointer to first free TD */ - int bad_OHCI; }; static struct grub_ohci *ohci; @@ -149,8 +148,8 @@ typedef enum #define GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE (1 << 4) #define GRUB_OHCI_RESET_CONNECT_CHANGE (1 << 16) -#define GRUB_OHCI_CTRL_EDS 16 -#define GRUB_OHCI_BULK_EDS 16 +#define GRUB_OHCI_CTRL_EDS 256 +#define GRUB_OHCI_BULK_EDS 510 #define GRUB_OHCI_TDS 256 #define GRUB_OHCI_ED_ADDR_MASK 0x7ff @@ -442,8 +441,10 @@ grub_ohci_pci_iter (grub_pci_device_t dev, (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA) & ~GRUB_OHCI_RHUB_PORT_POWER_MASK) | GRUB_OHCI_RHUB_PORT_ALL_POWERED); +#if 0 /* We don't need it at all, handled via hotplugging */ /* Now we have hot-plugging, we need to wait for stable power only */ grub_millisleep (100); +#endif /* Link to ohci now that initialisation is successful. */ o->next = ohci; @@ -623,7 +624,8 @@ grub_ohci_transaction (grub_ohci_td_t td, break; } - /* Set the token (Always generate interrupt - bits 21-23 = 0). */ + /* Set the token */ + token |= ( 7 << 21); /* Never generate interrupt */ token |= toggle << 24; token |= 1 << 25; @@ -659,7 +661,6 @@ struct grub_ohci_transfer_controller_data grub_ohci_ed_t ed_virt; grub_ohci_td_t td_current_virt; grub_ohci_td_t td_head_virt; - grub_uint64_t bad_OHCI_delay; }; static grub_usb_err_t @@ -756,10 +757,6 @@ grub_ohci_setup_transfer (grub_usb_controller_t dev, /* Set index of TD in transfer */ cdata->td_current_virt->tr_index = (grub_uint32_t) i; - - /* No IRQ request in TD if bad_OHCI set */ - if (o->bad_OHCI) - cdata->td_current_virt->token |= grub_cpu_to_le32 ( 7 << 21); /* Remember last used (processed) TD phys. addr. */ cdata->td_last_phys = grub_ohci_td_virt2phys (o, cdata->td_current_virt); @@ -891,8 +888,8 @@ pre_finish_transfer (grub_usb_controller_t dev, /* Now print debug values - to have full info what happened */ grub_dprintf ("ohci", "loop finished: control=0x%02x status=0x%02x\n", control, status); - grub_dprintf ("ohci", "intstatus=0x%02x \n\t\t tderr_phys=0x%02x, td_last_phys=0x%02x\n", - intstatus, cdata->tderr_phys, cdata->td_last_phys); + grub_dprintf ("ohci", "intstatus=0x%02x, td_last_phys=0x%02x\n", + intstatus, cdata->td_last_phys); grub_dprintf ("ohci", "TARGET=0x%02x, HEAD=0x%02x, TAIL=0x%02x\n", target, grub_le_to_cpu32 (cdata->ed_virt->td_head), @@ -915,12 +912,6 @@ finish_transfer (grub_usb_controller_t dev, * i.e. it is safe to free all TDs except last not processed * ED HEAD == TAIL == phys. addr. of td_current_virt */ - /* Reset DoneHead - sanity cleanup */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - /* Un-chainig of last TD */ if (cdata->td_current_virt->prev_td_phys) { @@ -929,10 +920,13 @@ finish_transfer (grub_usb_controller_t dev, if (cdata->td_current_virt == (grub_ohci_td_t) td_prev_virt->link_td) td_prev_virt->link_td = 0; + + cdata->td_current_virt->prev_td_phys = 0; } grub_dprintf ("ohci", "OHCI finished, freeing\n"); grub_ohci_free_tds (o, cdata->td_head_virt); + grub_free (cdata); } static grub_usb_err_t @@ -951,28 +945,10 @@ parse_halt (grub_usb_controller_t dev, pre_finish_transfer (dev, transfer); /* First we must get proper tderr_phys value */ - if (o->bad_OHCI) /* In case of bad_OHCI tderr_phys can be wrong */ - { - if (cdata->tderr_phys) /* check if tderr_phys points to TD with error */ - errcode = grub_le_to_cpu32 (grub_ohci_td_phys2virt (o, - cdata->tderr_phys)->token) - >> 28; - if ( !cdata->tderr_phys || !errcode ) /* tderr_phys not valid or points to wrong TD */ - { /* Retired TD with error should be previous TD to ED->td_head */ - cdata->tderr_phys = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf ) - ->prev_td_phys; - } - } - /* Even if we have "good" OHCI, in some cases - * tderr_phys can be zero, check it */ - else if (!cdata->tderr_phys) - /* Retired TD with error should be previous TD to ED->td_head */ - cdata->tderr_phys - = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 (cdata->ed_virt->td_head) - & ~0xf)->prev_td_phys; - + /* Retired TD with error should be previous TD to ED->td_head */ + cdata->tderr_phys = grub_ohci_td_phys2virt (o, + grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf ) + ->prev_td_phys; /* Prepare pointer to last processed TD and get error code */ tderr_virt = grub_ohci_td_phys2virt (o, cdata->tderr_phys); @@ -1090,16 +1066,12 @@ parse_success (grub_usb_controller_t dev, pre_finish_transfer (dev, transfer); - /* Simple workaround if donehead is not working */ - if (o->bad_OHCI && - (!cdata->tderr_phys || (cdata->tderr_phys != cdata->td_last_phys))) - { - grub_dprintf ("ohci", "normal finish, but tderr_phys corrected\n"); - cdata->tderr_phys = cdata->td_last_phys; - /* I hope we can do it as transfer (most probably) finished OK */ - } + /* I hope we can do it as transfer (most probably) finished OK */ + cdata->tderr_phys = cdata->td_last_phys; + /* Prepare pointer to last processed TD */ tderr_virt = grub_ohci_td_phys2virt (o, cdata->tderr_phys); + /* Set index of last processed TD */ if (tderr_virt) transfer->last_trans = tderr_virt->tr_index; @@ -1168,25 +1140,6 @@ grub_ohci_check_transfer (grub_usb_controller_t dev, /* Check transfer status */ intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - if (!o->bad_OHCI && (intstatus & 0x2) != 0) - { - /* Remember last successful TD */ - cdata->tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; - /* Reset DoneHead */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - /* if TD is last, finish */ - if (cdata->tderr_phys == cdata->td_last_phys) - { - if (grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1) - return parse_halt (dev, transfer, actual); - else - return parse_success (dev, transfer, actual); - } - return GRUB_USB_ERR_WAIT; - } if ((intstatus & 0x10) != 0) /* Unrecoverable error - only reset can help...! */ @@ -1194,54 +1147,20 @@ grub_ohci_check_transfer (grub_usb_controller_t dev, /* Detected a HALT. */ if ((grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1)) - { - /* ED is halted, but donehead event can happened in the meantime */ - intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - if (!o->bad_OHCI && (intstatus & 0x2) != 0) - { - /* Remember last successful TD */ - cdata->tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; - /* Reset DoneHead */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - /* if TD is last, finish */ - } - return parse_halt (dev, transfer, actual); - } + return parse_halt (dev, transfer, actual); - /* bad OHCI handling */ + /* Finished ED detection */ if ( (grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf) == (grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf) ) /* Empty ED */ { - if (o->bad_OHCI) /* Bad OHCI detected previously */ - { - /* Try get last successful TD. */ - cdata->tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; - if (cdata->tderr_phys)/* Reset DoneHead if we were successful */ - { - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - } - /* Check the HALT bit */ - if (grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1) - return parse_halt (dev, transfer, actual); - else - return parse_success (dev, transfer, actual); - } - else /* Detection of bad OHCI */ - /* We should wait short time (~2ms) before we say that - * it is bad OHCI to prevent some hazard - - * donehead can react in the meantime. This waiting is done - * only once per OHCI driver "live cycle". */ - if (!cdata->bad_OHCI_delay) /* Set delay time */ - cdata->bad_OHCI_delay = grub_get_time_ms () + 2; - else if (grub_get_time_ms () >= cdata->bad_OHCI_delay) - o->bad_OHCI = 1; - return GRUB_USB_ERR_WAIT; + /* Check the HALT bit */ + /* It looks like nonsense - it was tested previously... + * but it can change because OHCI is working + * simultaneously via DMA... */ + if (grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1) + return parse_halt (dev, transfer, actual); + else + return parse_success (dev, transfer, actual); } return GRUB_USB_ERR_WAIT; @@ -1266,14 +1185,16 @@ grub_ohci_cancel_transfer (grub_usb_controller_t dev, /* Wait for new SOF */ while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) == 0); - /* Now we must find last processed TD if bad_OHCI == TRUE */ - if (o->bad_OHCI) - /* Retired TD with error should be previous TD to ED->td_head */ - cdata->tderr_phys - = grub_ohci_td_phys2virt (o, grub_le_to_cpu32 (cdata->ed_virt->td_head) - & ~0xf)->prev_td_phys; + /* Possible retired TD with error should be previous TD to ED->td_head */ + cdata->tderr_phys + = grub_ohci_td_phys2virt (o, grub_le_to_cpu32 (cdata->ed_virt->td_head) + & ~0xf)->prev_td_phys; tderr_virt = grub_ohci_td_phys2virt (o,cdata-> tderr_phys); + + grub_dprintf ("ohci", "Cancel: tderr_phys=0x%08x, tderr_virt=0x%08x\n", + cdata->tderr_phys, (unsigned int)tderr_virt); + if (tderr_virt) transfer->last_trans = tderr_virt->tr_index; else @@ -1290,6 +1211,7 @@ grub_ohci_portstatus (grub_usb_controller_t dev, { struct grub_ohci *o = (struct grub_ohci *) dev->data; grub_uint64_t endtime; + int i; grub_dprintf ("ohci", "begin of portstatus=0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); @@ -1310,31 +1232,47 @@ grub_ohci_portstatus (grub_usb_controller_t dev, return GRUB_ERR_NONE; } - /* Reset the port */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, - GRUB_OHCI_SET_PORT_RESET); - grub_millisleep (50); /* For root hub should be nominaly 50ms */ - - /* End the reset signaling. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, - GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE); - grub_millisleep (10); + /* OHCI does one reset signal 10ms long but USB spec. + * requests 50ms for root hub (no need to be continuous). + * So, we do reset 5 times... */ + for (i = 0; i < 5; i++) + { + /* Reset the port - timing of reset is done by OHCI */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_RESET); - /* Enable the port and wait for it. */ + /* Wait for reset completion */ + endtime = grub_get_time_ms () + 1000; + while (! (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port) + & GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE)) + if (grub_get_time_ms () > endtime) + return grub_error (GRUB_ERR_IO, "OHCI Timed out - reset"); + + /* End the reset signaling - reset the reset status change */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE); + grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); + } + + /* Enable port */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_SET_PORT_ENABLE); + grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); + + /* Wait for signal enabled */ endtime = grub_get_time_ms () + 1000; while (! (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port) & (1 << 1))) if (grub_get_time_ms () > endtime) return grub_error (GRUB_ERR_IO, "OHCI Timed out - enable"); - grub_millisleep (10); - /* Reset bit Connect Status Change */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_RESET_CONNECT_CHANGE); + /* "Reset recovery time" (USB spec.) */ + grub_millisleep (10); + grub_dprintf ("ohci", "end of portstatus=0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index d51aace8c..2265ebed0 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -50,9 +50,12 @@ enum GRUB_UHCI_REG_PORTSC_SUSPEND = 0x1000, GRUB_UHCI_REG_PORTSC_RW = GRUB_UHCI_REG_PORTSC_PORT_ENABLED | GRUB_UHCI_REG_PORTSC_RESUME | GRUB_UHCI_REG_PORTSC_RESET - | GRUB_UHCI_REG_PORTSC_SUSPEND + | GRUB_UHCI_REG_PORTSC_SUSPEND, + /* These bits should not be written as 1 unless we really need it */ + GRUB_UHCI_PORTSC_RWC = ((1 << 1) | (1 << 3) | (1 << 11) | (3 << 13)) }; +#define /* UHCI Queue Head. */ struct grub_uhci_qh @@ -578,23 +581,23 @@ grub_uhci_check_transfer (grub_usb_controller_t dev, err = GRUB_USB_ERR_STALL; /* Check if an error related to the data buffer occurred. */ - if (errtd->ctrl_status & (1 << 21)) + else if (errtd->ctrl_status & (1 << 21)) err = GRUB_USB_ERR_DATA; /* Check if a babble error occurred. */ - if (errtd->ctrl_status & (1 << 20)) + else if (errtd->ctrl_status & (1 << 20)) err = GRUB_USB_ERR_BABBLE; /* Check if a NAK occurred. */ - if (errtd->ctrl_status & (1 << 19)) + else if (errtd->ctrl_status & (1 << 19)) err = GRUB_USB_ERR_NAK; /* Check if a timeout occurred. */ - if (errtd->ctrl_status & (1 << 18)) + else if (errtd->ctrl_status & (1 << 18)) err = GRUB_USB_ERR_TIMEOUT; /* Check if a bitstuff error occurred. */ - if (errtd->ctrl_status & (1 << 17)) + else if (errtd->ctrl_status & (1 << 17)) err = GRUB_USB_ERR_BITSTUFF; if (err) @@ -685,7 +688,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, endtime = grub_get_time_ms () + 1000; while ((grub_uhci_readreg16 (u, reg) & (1 << 2))) if (grub_get_time_ms () > endtime) - return grub_error (GRUB_ERR_IO, "UHCI Timed out"); + return grub_error (GRUB_ERR_IO, "UHCI Timed out - disable"); status = grub_uhci_readreg16 (u, reg); grub_dprintf ("uhci", ">3detect=0x%02x\n", status); @@ -693,28 +696,37 @@ grub_uhci_portstatus (grub_usb_controller_t dev, } /* Reset the port. */ - grub_uhci_writereg16 (u, reg, 1 << 9); + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; + grub_uhci_writereg16 (u, reg, status | (1 << 9)); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ /* Wait for the reset to complete. XXX: How long exactly? */ grub_millisleep (50); /* For root hub should be nominaly 50ms */ - status = grub_uhci_readreg16 (u, reg); + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; grub_uhci_writereg16 (u, reg, status & ~(1 << 9)); - grub_dprintf ("uhci", "reset completed\n"); - grub_millisleep (10); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ + + /* Note: some debug prints were removed because they affected reset/enable timing. */ + + grub_millisleep (1); /* Probably not needed at all or only few microsecs. */ + + /* Reset bits Connect & Enable Status Change */ + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; + grub_uhci_writereg16 (u, reg, status | (1 << 3) | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ /* Enable the port. */ - grub_uhci_writereg16 (u, reg, 1 << 2); - grub_millisleep (10); - - grub_dprintf ("uhci", "waiting for the port to be enabled\n"); + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; + grub_uhci_writereg16 (u, reg, status | (1 << 2)); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ endtime = grub_get_time_ms () + 1000; while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2))) if (grub_get_time_ms () > endtime) - return grub_error (GRUB_ERR_IO, "UHCI Timed out"); + return grub_error (GRUB_ERR_IO, "UHCI Timed out - enable"); - /* Reset bit Connect Status Change */ - grub_uhci_writereg16 (u, reg, status | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED); + /* Reset recovery time */ + grub_millisleep (10); /* Read final port status */ status = grub_uhci_readreg16 (u, reg); diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c index 2bd805ef2..e17bf0c9d 100644 --- a/grub-core/bus/usb/usb.c +++ b/grub-core/bus/usb/usb.c @@ -262,7 +262,7 @@ void grub_usb_device_attach (grub_usb_device_t dev) if (dev->config[0].interf[i].attached) continue; - + for (desc = attach_hooks; desc; desc = desc->next) if (interf->class == desc->class && desc->hook (dev, 0, i)) dev->config[0].interf[i].attached = 1; diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c index 0ddba3255..73d233642 100644 --- a/grub-core/bus/usb/usbhub.c +++ b/grub-core/bus/usb/usbhub.c @@ -179,19 +179,45 @@ attach_root_port (struct grub_usb_hub *hub, int portno, { grub_usb_device_t dev; grub_err_t err; + int total, i; + grub_usb_speed_t current_speed = GRUB_USB_SPEED_NONE; + int changed=0; +#if 0 +/* Specification does not say about disabling of port when device + * connected. If disabling is really necessary for some devices, + * delete this #if 0 and related #endif */ /* Disable the port. XXX: Why? */ err = hub->controller->dev->portstatus (hub->controller, portno, 0); if (err) return; +#endif + /* Wait for completion of insertion and stable power (USB spec.) + * Should be at least 100ms, some devices requires more... + * There is also another thing - some devices have worse contacts + * and connected signal is unstable for some time - we should handle + * it - but prevent deadlock in case when device is too faulty... */ + for (total = i = 0; (i < 250) && (total < 2000); i++, total++) + { + grub_millisleep (1); + current_speed = hub->controller->dev->detect_dev + (hub->controller, portno, &changed); + if (current_speed == GRUB_USB_SPEED_NONE) + i = 0; + } + grub_dprintf ("usb", "total=%d\n", total); + if (total >= 2000) + return; /* Enable the port. */ err = hub->controller->dev->portstatus (hub->controller, portno, 1); if (err) return; + hub->controller->dev->pending_reset = grub_get_time_ms () + 5000; /* Enable the port and create a device. */ dev = grub_usb_hub_add_dev (hub->controller, speed); + hub->controller->dev->pending_reset = 0; if (! dev) return; @@ -238,11 +264,14 @@ grub_usb_root_hub (grub_usb_controller_t controller) for (i = 0; i < hub->nports; i++) { grub_usb_speed_t speed; - speed = controller->dev->detect_dev (hub->controller, i, - &changed); + if (!controller->dev->pending_reset) + { + speed = controller->dev->detect_dev (hub->controller, i, + &changed); - if (speed != GRUB_USB_SPEED_NONE) - attach_root_port (hub, i, speed); + if (speed != GRUB_USB_SPEED_NONE) + attach_root_port (hub, i, speed); + } } return GRUB_USB_ERR_NONE; @@ -284,6 +313,7 @@ poll_nonroot_hub (grub_usb_device_t dev) unsigned i; grub_uint8_t changed; grub_size_t actual; + int j, total; if (!dev->hub_transfer) return; @@ -308,6 +338,7 @@ poll_nonroot_hub (grub_usb_device_t dev) for (i = 1; i <= dev->nports; i++) { grub_uint32_t status; + grub_uint32_t current_status = 0; if (!(changed & (1 << i))) continue; @@ -319,7 +350,8 @@ poll_nonroot_hub (grub_usb_device_t dev) GRUB_USB_REQ_GET_STATUS, 0, i, sizeof (status), (char *) &status); - grub_printf ("i = %d, status = %08x\n", i, status); + grub_printf ("dev = 0x%0x, i = %d, status = %08x\n", + (unsigned int) dev, i, status); if (err) continue; @@ -346,7 +378,8 @@ poll_nonroot_hub (grub_usb_device_t dev) GRUB_USB_REQ_CLEAR_FEATURE, GRUB_USB_HUB_FEATURE_C_PORT_OVERCURRENT, i, 0, 0); - if (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED) + if (!dev->controller.dev->pending_reset && + (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED)) { grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | GRUB_USB_REQTYPE_CLASS @@ -360,8 +393,36 @@ poll_nonroot_hub (grub_usb_device_t dev) /* Connected and status of connection changed ? */ if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) { - /* A device is actually connected to this port. - * Now do reset of port. */ + /* A device is actually connected to this port. */ + /* Wait for completion of insertion and stable power (USB spec.) + * Should be at least 100ms, some devices requires more... + * There is also another thing - some devices have worse contacts + * and connected signal is unstable for some time - we should handle + * it - but prevent deadlock in case when device is too faulty... */ + for (total = j = 0; (j < 250) && (total < 2000); j++, total++) + { + grub_millisleep (1); + /* Get the port status. */ + err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_GET_STATUS, + 0, i, + sizeof (current_status), + (char *) ¤t_status); + if (err) + { + total = 2000; + break; + } + if (!(current_status & GRUB_USB_HUB_STATUS_PORT_CONNECTED)) + j = 0; + } + grub_dprintf ("usb", "(non-root) total=%d\n", total); + if (total >= 2000) + continue; + + /* Now do reset of port. */ grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_TARGET_OTHER), @@ -369,6 +430,15 @@ poll_nonroot_hub (grub_usb_device_t dev) GRUB_USB_HUB_FEATURE_PORT_RESET, i, 0, 0); rescan = 1; + /* We cannot reset more than one device at the same time ! + * Resetting more devices together results in very bad + * situation: more than one device has default address 0 + * at the same time !!! + * Additionaly, we cannot perform another reset + * anywhere on the same OHCI controller until + * we will finish addressing of reseted device ! */ + dev->controller.dev->pending_reset = grub_get_time_ms () + 5000; + return; } } @@ -401,6 +471,7 @@ poll_nonroot_hub (grub_usb_device_t dev) /* Add the device and assign a device address to it. */ next_dev = grub_usb_hub_add_dev (&dev->controller, speed); + dev->controller.dev->pending_reset = 0; if (! next_dev) continue; @@ -426,12 +497,21 @@ grub_usb_poll_devices (void) /* No, it should be never changed, it should be constant. */ for (i = 0; i < hub->nports; i++) { - grub_usb_speed_t speed; + grub_usb_speed_t speed = GRUB_USB_SPEED_NONE; int changed = 0; - speed = hub->controller->dev->detect_dev (hub->controller, i, - &changed); - + if (!hub->controller->dev->pending_reset) + { + /* Check for possible timeout */ + if (grub_get_time_ms () > hub->controller->dev->pending_reset) + { + /* Something went wrong, reset device was not + * addressed properly, timeout happened */ + hub->controller->dev->pending_reset = 0; + speed = hub->controller->dev->detect_dev (hub->controller, + i, &changed); + } + } if (changed) { detach_device (hub->devices[i]); diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c index 6b9b1a5b9..afd2eb0a5 100644 --- a/grub-core/bus/usb/usbtrans.c +++ b/grub-core/bus/usb/usbtrans.c @@ -33,10 +33,12 @@ grub_usb_execute_and_wait_transfer (grub_usb_device_t dev, grub_usb_err_t err; grub_uint64_t endtime; - endtime = grub_get_time_ms () + timeout; err = dev->controller.dev->setup_transfer (&dev->controller, transfer); if (err) return err; + /* endtime moved behind setup transfer to prevent false timeouts + * while debugging... */ + endtime = grub_get_time_ms () + timeout; while (1) { err = dev->controller.dev->check_transfer (&dev->controller, transfer, diff --git a/include/grub/usb.h b/include/grub/usb.h index f9cdb2765..6f838e4f9 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -116,6 +116,9 @@ struct grub_usb_controller_dev grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed); + /* Per controller flag - port reset pending, don't do another reset */ + grub_uint64_t pending_reset; + /* The next host controller. */ struct grub_usb_controller_dev *next; }; From 685475e59622cce56cc8a3d2b180241fc90e1d05 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 18 Sep 2010 13:49:39 +0200 Subject: [PATCH 63/64] Fix yeeloong compilation --- grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 3 +++ include/grub/loader.h | 12 ++++++------ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 8b8d993b3..504bd4463 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -137,6 +137,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cs5536.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pci.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/serial.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h endif if COND_powerpc_ieee1275 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index c0a796ee0..f4a555ebe 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -173,6 +173,8 @@ kernel = { videoinkernel = video/fb/video_fb.c; videoinkernel = video/video.c; + videoinkernel = commands/boot.c; + extra_dist = kern/i386/realmode.S; extra_dist = kern/i386/pc/lzma_decode.S; extra_dist = kern/mips/cache_flush.S; @@ -424,6 +426,7 @@ module = { name = boot; common = commands/boot.c; i386_pc = lib/i386/pc/biosnum.c; + enable = videomodules; }; module = { diff --git a/include/grub/loader.h b/include/grub/loader.h index 319f3c551..c71e8dd10 100644 --- a/include/grub/loader.h +++ b/include/grub/loader.h @@ -26,16 +26,16 @@ #include /* Check if a loader is loaded. */ -int grub_loader_is_loaded (void); +int EXPORT_FUNC (grub_loader_is_loaded) (void); /* Set loader functions. NORETURN must be set to true, if BOOT won't return to the original state. */ -void grub_loader_set (grub_err_t (*boot) (void), - grub_err_t (*unload) (void), - int noreturn); +void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), + grub_err_t (*unload) (void), + int noreturn); /* Unset current loader, if any. */ -void grub_loader_unset (void); +void EXPORT_FUNC (grub_loader_unset) (void); /* Call the boot hook in current loader. This may or may not return, depending on the setting by grub_loader_set. */ @@ -56,7 +56,7 @@ typedef enum { } grub_loader_preboot_hook_prio_t; /* Register a preboot hook. */ -void *grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noret), +void *EXPORT_FUNC(grub_loader_register_preboot_hook) (grub_err_t (*preboot_func) (int noret), grub_err_t (*preboot_rest_func) (void), grub_loader_preboot_hook_prio_t prio); From ab629d0c5de4ea6ba8e50300b271b33c2b945c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Nesrsta?= Date: Sun, 19 Sep 2010 00:34:25 +0200 Subject: [PATCH 64/64] Fix incorrect usb report interpretation --- grub-core/term/usb_keyboard.c | 134 ++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 30 deletions(-) diff --git a/grub-core/term/usb_keyboard.c b/grub-core/term/usb_keyboard.c index 6b1485e96..8a34ec552 100644 --- a/grub-core/term/usb_keyboard.c +++ b/grub-core/term/usb_keyboard.c @@ -75,6 +75,10 @@ struct grub_usb_keyboard_data int dead; int last_key; grub_uint64_t repeat_time; + grub_uint8_t current_report[8]; + grub_uint8_t last_report[8]; + int index; + int max_index; }; static int grub_usb_keyboard_getkey (struct grub_term_input *term); @@ -192,6 +196,9 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) data->interfno = interfno; data->endp = endp; + /* Configure device */ + grub_usb_set_configuration (usbdev, configno + 1); + /* Place the device in boot mode. */ grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, USB_HID_SET_PROTOCOL, 0, interfno, 0, 0); @@ -270,17 +277,96 @@ send_leds (struct grub_usb_keyboard_data *termdata) grub_errno = GRUB_ERR_NONE; } +static int +parse_keycode (struct grub_usb_keyboard_data *termdata) +{ + int index = termdata->index; + int i, keycode; + + /* Sanity check */ + if (index < 2) + index = 2; + + for ( ; index < termdata->max_index; index++) + { + keycode = termdata->current_report[index]; + + if (keycode == KEY_NO_KEY + || keycode == KEY_ERR_BUFFER + || keycode == KEY_ERR_POST + || keycode == KEY_ERR_UNDEF) + { + /* Don't parse (rest of) this report */ + termdata->index = 0; + if (keycode != KEY_NO_KEY) + /* Don't replace last report with current faulty report + * in future ! */ + grub_memcpy (termdata->current_report, + termdata->last_report, + sizeof (termdata->report)); + return GRUB_TERM_NO_KEY; + } + + /* Try to find current keycode in last report. */ + for (i = 2; i < 8; i++) + if (keycode == termdata->last_report[i]) + break; + if (i < 8) + /* Keycode is in last report, it means it was not released, + * ignore it. */ + continue; + + if (keycode == KEY_CAPS_LOCK) + { + termdata->mods ^= GRUB_TERM_STATUS_CAPS; + send_leds (termdata); + continue; + } + + if (keycode == KEY_NUM_LOCK) + { + termdata->mods ^= GRUB_TERM_STATUS_NUM; + send_leds (termdata); + continue; + } + + termdata->last_key = grub_term_map_key (keycode, + interpret_status (termdata->current_report[0]) + | termdata->mods); + termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_PRE_INTERVAL; + + grub_errno = GRUB_ERR_NONE; + + index++; + if (index >= termdata->max_index) + termdata->index = 0; + else + termdata->index = index; + + return termdata->last_key; + } + + /* All keycodes parsed */ + termdata->index = 0; + return GRUB_TERM_NO_KEY; +} + static int grub_usb_keyboard_getkey (struct grub_term_input *term) { grub_usb_err_t err; struct grub_usb_keyboard_data *termdata = term->data; - grub_uint8_t data[sizeof (termdata->report)]; grub_size_t actual; + int keycode = GRUB_TERM_NO_KEY; if (termdata->dead) return GRUB_TERM_NO_KEY; + if (termdata->index) + keycode = parse_keycode (termdata); + if (keycode != GRUB_TERM_NO_KEY) + return keycode; + /* Poll interrupt pipe. */ err = grub_usb_check_transfer (termdata->transfer, &actual); @@ -296,7 +382,14 @@ grub_usb_keyboard_getkey (struct grub_term_input *term) return GRUB_TERM_NO_KEY; } - grub_memcpy (data, termdata->report, sizeof (data)); + if (!err && (actual >= 3)) + grub_memcpy (termdata->last_report, + termdata->current_report, + sizeof (termdata->report)); + + grub_memcpy (termdata->current_report, + termdata->report, + sizeof (termdata->report)); termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev, termdata->endp->endp_addr, @@ -314,42 +407,23 @@ grub_usb_keyboard_getkey (struct grub_term_input *term) "err = %d, actual = %d report: 0x%02x 0x%02x 0x%02x 0x%02x" " 0x%02x 0x%02x 0x%02x 0x%02x\n", err, actual, - data[0], data[1], data[2], data[3], - data[4], data[5], data[6], data[7]); + termdata->current_report[0], termdata->current_report[1], + termdata->current_report[2], termdata->current_report[3], + termdata->current_report[4], termdata->current_report[5], + termdata->current_report[6], termdata->current_report[7]); if (err || actual < 1) return GRUB_TERM_NO_KEY; - termdata->status = data[0]; + termdata->status = termdata->current_report[0]; if (actual < 3) return GRUB_TERM_NO_KEY; - if (data[2] == KEY_NO_KEY || data[2] == KEY_ERR_BUFFER - || data[2] == KEY_ERR_POST || data[2] == KEY_ERR_UNDEF) - return GRUB_TERM_NO_KEY; - - if (data[2] == KEY_CAPS_LOCK) - { - termdata->mods ^= GRUB_TERM_STATUS_CAPS; - send_leds (termdata); - return GRUB_TERM_NO_KEY; - } - - if (data[2] == KEY_NUM_LOCK) - { - termdata->mods ^= GRUB_TERM_STATUS_NUM; - send_leds (termdata); - return GRUB_TERM_NO_KEY; - } - - termdata->last_key = grub_term_map_key (data[2], interpret_status (data[0]) - | termdata->mods); - termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_PRE_INTERVAL; - - grub_errno = GRUB_ERR_NONE; - - return termdata->last_key; + termdata->index = 2; /* New data received. */ + termdata->max_index = actual; + + return parse_keycode (termdata); } static int