]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
merge mainline into keylayouts
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 20 Aug 2010 20:13:19 +0000 (22:13 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 20 Aug 2010 20:13:19 +0000 (22:13 +0200)
1  2 
commands/keylayouts.c
commands/keystatus.c
conf/common.rmk
conf/mips-yeeloong.rmk
include/grub/keyboard_layouts.h
include/grub/term.h
kern/mips/yeeloong/init.c
kern/term.c
term/terminfo.c
term/usb_keyboard.c

index df8b95e021b6edbbf8227ad2ccad9c734d67394f,0000000000000000000000000000000000000000..d2cb0e1e7530d56a79202aa9c9099430519be009
mode 100644,000000..100644
--- /dev/null
@@@ -1,243 -1,0 +1,243 @@@
- #include <grub/gzio.h>
 +/*
 + *  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 <http://www.gnu.org/licenses/>.
 + */
 +
 +#include <grub/term.h>
 +#include <grub/err.h>
 +#include <grub/mm.h>
 +#include <grub/misc.h>
 +#include <grub/env.h>
 +#include <grub/time.h>
 +#include <grub/dl.h>
 +#include <grub/keyboard_layouts.h>
 +#include <grub/command.h>
-   file = grub_gzfile_open (filename, 1);
 +#include <grub/i18n.h>
++#include <grub/file.h>
 +
 +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_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->keyboard_map_shift_l3[code])
 +          {
 +            *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])
 +      {
 +        *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;
 +    }
 +  else
 +    return grub_current_layout->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[])
 +{
 +  char *filename;
 +  grub_file_t file;
 +  grub_uint32_t version;
 +  grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE];
 +  struct grub_keyboard_layout *newmap = NULL;
 +  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_file_open (filename);
 +  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;
 +    }
 +
 +  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;
 +    }
 +
 +  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->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->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->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;
 +
 +  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 grub_command_t cmd;
 +
 +GRUB_MOD_INIT(keylayouts)
 +{
 +  cmd = grub_register_command ("keymap", grub_cmd_keymap,
 +                             0, N_("Load a keyboard layout."));
 +}
 +
 +GRUB_MOD_FINI(keylayouts)
 +{
 +  grub_unregister_command (cmd);
 +}
index 9c7ab84b05dbadad39d3427505431853827544a4,838792889ff3a58322f53965c6e9dd35ae5c6e57..7525b346e8967f40cac84b520a3373b452627ff7
@@@ -31,20 -31,7 +31,23 @@@ static const struct grub_arg_option opt
      {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;
 +
++  if (grub_term_poll_usb)
++    grub_term_poll_usb ();
++
 +  FOR_ACTIVE_TERM_INPUTS(term)
 +  {
 +    if (term->getkeystatus)
 +      status |= term->getkeystatus (term);
 +  }
 +
 +  return status;
 +}
  
  static grub_err_t
  grub_cmd_keystatus (grub_extcmd_t cmd,
diff --cc conf/common.rmk
index e21c693b0a7d692c064c6a0f0a7793c6680cc760,908bd74e867149f9e19fa87a5452543efad9b412..b56e8343c075a7bb12cde73622fda9c0f7cd4b19
@@@ -480,11 -469,6 +480,13 @@@ extcmd_mod_SOURCES = commands/extcmd.c 
  extcmd_mod_CFLAGS = $(COMMON_CFLAGS)
  extcmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
  
++ifneq ($(platform), yeeloong)
 +pkglib_MODULES += keylayouts.mod
 +keylayouts_mod_SOURCES = commands/keylayouts.c
 +keylayouts_mod_CFLAGS = $(COMMON_CFLAGS)
 +keylayouts_mod_LDFLAGS = $(COMMON_LDFLAGS)
++endif
 +
  # For hello.mod.
  hello_mod_SOURCES = hello/hello.c
  hello_mod_CFLAGS = $(COMMON_CFLAGS)
index deb6dd33ffbd0828dc0db86ff8bc9680aa566953,9cbbdf4726fa5264abd06b048bae038da594d747..36d4ee26629e68200109bc8afa42cfa4d94ed204
@@@ -5,7 -5,7 +5,8 @@@ COMMON_CFLAGS += -march=mips
  COMMON_ASFLAGS += -march=mips3
  
  kernel_img_HEADERS += pci.h bitmap.h video.h gfxterm.h font.h \
-                     bitmap_scale.h bufio.h cs5536.h machine/pci.h
 -                    bitmap_scale.h bufio.h cs5536.h machine/pci.h serial.h
++                    bitmap_scale.h bufio.h cs5536.h machine/pci.h serial.h \
++                    keyboard_layouts.h
  
  include $(srcdir)/conf/mips.mk
  
@@@ -21,7 -21,7 +22,7 @@@ kernel_img_SOURCES = kern/$(target_cpu)
        kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c kern/time.c    \
        kern/$(target_cpu)/cache.S \
        \
--      term/at_keyboard.c \
++      term/at_keyboard.c commands/keylayouts.c \
        font/font_cmd.c font/font.c io/bufio.c \
        video/video.c video/fb/video_fb.c video/fb/fbblit.c \
        video/fb/fbfill.c video/fb/fbutil.c video/bitmap.c \
index 1920b8887834cd281ab94d1feac41522bace8b70,0000000000000000000000000000000000000000..f1d2fb2826cbd7dcc38af860a81248a478d06a43
mode 100644,000000..100644
--- /dev/null
@@@ -1,38 -1,0 +1,38 @@@
- unsigned grub_term_map_key (int code, int status);
 +/*
 + *  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 <http://www.gnu.org/licenses/>.
 + */
 +
 +#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 6
 +
 +#define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 128
 +
 +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];
 +  grub_uint32_t keyboard_map_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE];
 +  grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE];
 +};
 +
++unsigned EXPORT_FUNC(grub_term_map_key) (int code, int status);
 +
 +#endif /* GRUB_KEYBOARD_LAYOUTS  */
index de430d66f0b4ddc0b9c0289ea85d8fffdba7424e,734e4ab17ff23d035fe1fe8f497eb05fcbf883e0..009258f6ec00eda7d02a5673cf74ea9af37e1625
@@@ -488,6 -459,11 +488,8 @@@ grub_print_spaces (struct grub_term_out
      grub_putcode (' ', term);
  }
  
 -/* For convenience.  */
 -#define GRUB_TERM_ASCII_CHAR(c)       ((c) & 0xff)
 -
+ extern void (*EXPORT_VAR (grub_term_poll_usb)) (void);
  #endif /* ! ASM_FILE */
  
  #endif /* ! GRUB_TERM_HEADER */
index 523f9028296c3cc8adb63395865699500dc94f9f,523f9028296c3cc8adb63395865699500dc94f9f..2eceff78d70d9fb6cca984171ccb81b9898b93b3
@@@ -39,6 -39,6 +39,7 @@@ extern void grub_gfxterm_init (void)
  extern void grub_at_keyboard_init (void);
  extern void grub_serial_init (void);
  extern void grub_terminfo_init (void);
++extern void grub_keylayouts_init (void);
  
  /* FIXME: use interrupt to count high.  */
  grub_uint64_t
@@@ -205,6 -205,6 +206,7 @@@ grub_machine_init (void
    grub_font_init ();
    grub_gfxterm_init ();
  
++  grub_keylayouts_init ();
    grub_at_keyboard_init ();
  
    grub_terminfo_init ();
diff --cc kern/term.c
Simple merge
diff --cc term/terminfo.c
Simple merge
index ede71bb5fc66c45f6951d86549a612bb33106057,d875ac00a5ebd0a05029ba5b7a959722868a0e2e..f5bd1d60105e28a829235d1d5841aefc470e8df3
  #include <grub/usb.h>
  #include <grub/dl.h>
  #include <grub/time.h>
 +#include <grub/keyboard_layouts.h>
  
  \f
 -static char 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', '\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
 -  };
  
 -static char 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', ' ', '_', '+', '{',
 -    '}', '|', '#', ':', '"', '`', '<', '>',
 -    '?'
 -  };
 +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 /* [ */, 
 +  /* 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;
- /* Valid values for bmRequestType.  See HID definition version 1.11 section
-    7.2.  */
- #define USB_HID_HOST_TO_DEVICE        0x21
- #define USB_HID_DEVICE_TO_HOST        0xA1
  
  /* Valid values for bRequest.  See HID definition version 1.11 section 7.2. */
  #define USB_HID_GET_REPORT    0x01
  #define USB_HID_SET_IDLE      0x0A
  #define USB_HID_SET_PROTOCOL  0x0B
  
 -struct grub_usb_keyboard_data
+ #define USB_HID_BOOT_SUBCLASS 0x01
+ #define USB_HID_KBD_PROTOCOL  0x01
 +#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
 +
++struct grub_usb_keyboard_data
++{
++  grub_usb_device_t usbdev;
++  grub_uint8_t status;
++  int key;
++  struct grub_usb_desc_endp *endp;
++};
++
++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
+   };
 +static int
 +interpret_status (grub_uint8_t data0)
  {
 -  grub_usb_device_t usbdev;
 -  grub_uint8_t status;
 -  int key;
 -  struct grub_usb_desc_endp *endp;
 -};
 +  int mods = 0;
  
 -static struct grub_term_input grub_usb_keyboards[16];
 +  /* 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)
+ grub_usb_keyboard_detach (grub_usb_device_t usbdev,
+                         int config __attribute__ ((unused)),
+                         int interface __attribute__ ((unused)))
  {
-   struct grub_usb_desc_device *descdev;
-   auto int usb_iterate (grub_usb_device_t dev);
-   int usb_iterate (grub_usb_device_t dev)
+   unsigned i;
+   for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++)
      {
-       descdev = &dev->descdev;
+       struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data;
+       if (!data)
+       continue;
+       if (data->usbdev != usbdev)
+       continue;
+       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;
+     }
+ }
+ static int
+ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno)
+ {
+   unsigned curnum;
+   struct grub_usb_keyboard_data *data;
+   struct grub_usb_desc_endp *endp = NULL;
+   int j;
+   grub_dprintf ("usb_keyboard", "%x %x %x %d %d\n",
+               usbdev->descdev.class, usbdev->descdev.subclass,
+               usbdev->descdev.protocol, configno, interfno);
+   for (curnum = 0; curnum < ARRAY_SIZE (grub_usb_keyboards); curnum++)
+     if (!grub_usb_keyboards[curnum].data)
+       break;
+   if (curnum == ARRAY_SIZE (grub_usb_keyboards))
+     return 0;
  
-       grub_dprintf ("usb_keyboard", "%x %x %x\n",
-                  descdev->class, descdev->subclass, descdev->protocol);
+   if (usbdev->descdev.class != 0 
+       || usbdev->descdev.subclass != 0 || usbdev->descdev.protocol != 0)
+     return 0;
  
- #if 0
-       if (descdev->class != 0x09
-         || descdev->subclass == 0x01
-         || descdev->protocol != 0x02)
-       return 0;
- #endif
+   if (usbdev->config[configno].interf[interfno].descif->subclass
+       != USB_HID_BOOT_SUBCLASS
+       || usbdev->config[configno].interf[interfno].descif->protocol
+       != USB_HID_KBD_PROTOCOL)
+     return 0;
  
-       if (descdev->class != 0 || descdev->subclass != 0 || descdev->protocol != 0)
-       return 0;
+   for (j = 0; j < usbdev->config[configno].interf[interfno].descif->endpointcnt;
+        j++)
+     {
+       endp = &usbdev->config[configno].interf[interfno].descendp[j];
  
-       grub_printf ("HID found!\n");
+       if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
+         == GRUB_USB_EP_INTERRUPT)
+       break;
+     }
+   if (j == usbdev->config[configno].interf[interfno].descif->endpointcnt)
+     return 0;
  
-       usbdev = dev;
+   grub_dprintf ("usb_keyboard", "HID found!\n");
  
-       return 1;
+   data = grub_malloc (sizeof (*data));
+   if (!data)
+     {
+       grub_print_error ();
+       return 0;
      }
-   grub_usb_iterate (usb_iterate);
+   data->usbdev = usbdev;
+   data->endp = endp;
  
    /* Place the device in boot mode.  */
-   grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_PROTOCOL,
-                       0, 0, 0, 0);
+   grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
+                       USB_HID_SET_PROTOCOL, 0, 0, 0, 0);
  
    /* Reports every time an event occurs and not more often than that.  */
-   grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
-                       0<<8, 0, 0, 0);
- }
+   grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT,
+                       USB_HID_SET_IDLE, 0<<8, 0, 0, 0);
+   grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term,
+              sizeof (grub_usb_keyboards[curnum]));
+   grub_usb_keyboards[curnum].data = data;
+   usbdev->config[configno].interf[interfno].detach_hook
+     = grub_usb_keyboard_detach;
+   grub_usb_keyboards[curnum].name = grub_xasprintf ("usb_keyboard%d", curnum);
+   if (!grub_usb_keyboards[curnum].name)
+     {
+       grub_print_error ();
+       return 0;
+     }
  
- static grub_err_t
- grub_usb_keyboard_getreport (grub_usb_device_t dev, grub_uint8_t *report)
- {
-   return grub_usb_control_msg (dev, USB_HID_DEVICE_TO_HOST, USB_HID_GET_REPORT,
-                              0, 0, 8, (char *) report);
+   {
+     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,
+                               sizeof (report), (char *) report);
+     if (err)
+       {
+       data->status = 0;
+       data->key = -1;
+       }
+     else
+       {
+       data->status = report[0];
+       data->key = report[2] ? : -1;
+       }
+   }
+   grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]);
+   return 1;
  }
  
  \f
@@@ -221,40 -241,22 +313,18 @@@ grub_usb_keyboard_checkkey (struct grub
                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;
 -  else if (data[0] & 0x02 || data[0] & 0x20)
 -    termdata->key = keyboard_map_shift[data[2]];
 -  else
 -    termdata->key = keyboard_map[data[2]];
 -
 -  if (termdata->key == 0)
 +  if (usb_to_at_map[data[2]] == 0)
      grub_printf ("Unknown key 0x%x detected\n", data[2]);
-     key = grub_term_map_key (usb_to_at_map[data[2]], interpret_status (data[0]));
 +  else
++    termdata->key = grub_term_map_key (usb_to_at_map[data[2]],
++                                     interpret_status (data[0]));
 +
    grub_errno = GRUB_ERR_NONE;
  
-   return key;
- #if 0
-   /* Wait until the key is released.  */
-   while (!err && data[2])
-     {
-       err = grub_usb_control_msg (usbdev, USB_HID_DEVICE_TO_HOST,
-                                 USB_HID_GET_REPORT, 0, 0,
-                                 sizeof (data), (char *) data);
-       grub_dprintf ("usb_keyboard",
-                   "report2: 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]);
-     }
- #endif
-   return key;
+   return termdata->key;
  }
  
- typedef enum
- {
-   GRUB_HIDBOOT_REPEAT_NONE,
-   GRUB_HIDBOOT_REPEAT_FIRST,
-   GRUB_HIDBOOT_REPEAT
- } grub_usb_keyboard_repeat_t;
  static int
  grub_usb_keyboard_getkey (struct grub_term_input *term)
  {
  }
  
  static int
- grub_usb_keyboard_getkeystatus (struct grub_term_input *term __attribute__ ((unused)))
+ grub_usb_keyboard_getkeystatus (struct grub_term_input *term)
  {
-   grub_uint8_t data[8];
-   grub_err_t err;
-   grub_uint64_t currtime;
-   int timeout = 50;
-   /* Set idle time to the minimum offered by the spec (4 milliseconds) so
-      that we can find out the current state.  */
-   grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
-                       0<<8, 0, 0, 0);
-   currtime = grub_get_time_ms ();
-   do
-     {
-       /* Get_Report.  */
-       err = grub_usb_keyboard_getreport (usbdev, data);
-       /* Implement a timeout.  */
-       if (grub_get_time_ms () > currtime + timeout)
-       break;
-     }
-   while (err || !data[0]);
-   /* Go back to reporting every time an event occurs and not more often than
-      that.  */
-   grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
-                       0<<8, 0, 0, 0);
-   /* We allowed a while for modifiers to show up in the report, but it is
-      not an error if they never did.  */
-   if (err)
-     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]);
-   grub_errno = GRUB_ERR_NONE;
+   struct grub_usb_keyboard_data *termdata = term->data;
 -  int mods = 0;
 -
 -  /* Check Shift, Control, and Alt status.  */
 -  if (termdata->status & 0x02 || termdata->status & 0x20)
 -    mods |= GRUB_TERM_STATUS_SHIFT;
 -  if (termdata->status & 0x01 || termdata->status & 0x10)
 -    mods |= GRUB_TERM_STATUS_CTRL;
 -  if (termdata->status & 0x04 || termdata->status & 0x40)
 -    mods |= GRUB_TERM_STATUS_ALT;
  
-   return interpret_status (data[0]);
 -  return mods;
++  return interpret_status (termdata->status);
  }
  
- static struct grub_term_input grub_usb_keyboard_term =
-   {
-     .name = "usb_keyboard",
-     .checkkey = grub_usb_keyboard_checkkey,
-     .getkey = grub_usb_keyboard_getkey,
-     .getkeystatus = grub_usb_keyboard_getkeystatus,
-     .next = 0
-   };
+ struct grub_usb_attach_desc attach_hook =
+ {
+   .class = GRUB_USB_CLASS_HID,
+   .hook = grub_usb_keyboard_attach
+ };
  
  GRUB_MOD_INIT(usb_keyboard)
  {