2009-02-21 Robert Millan <rmh@aybabtu.com>
Implement USB keyboard support (based on patch by Marco Gerards) * conf/i386-pc.rmk (pkglib_MODULES): Add `usb_keyboard.mod'. (usb_keyboard_mod_SOURCES, usb_keyboard_mod_CFLAGS) (usb_keyboard_mod_LDFLAGS): New variables. * term/usb_keyboard.c: New file.
This commit is contained in:
parent
8fa4ea7017
commit
6374daf387
5 changed files with 332 additions and 2 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2009-02-21 Robert Millan <rmh@aybabtu.com>
|
||||
|
||||
Implement USB keyboard support (based on patch by Marco Gerards)
|
||||
|
||||
* conf/i386-pc.rmk (pkglib_MODULES): Add `usb_keyboard.mod'.
|
||||
(usb_keyboard_mod_SOURCES, usb_keyboard_mod_CFLAGS)
|
||||
(usb_keyboard_mod_LDFLAGS): New variables.
|
||||
|
||||
* term/usb_keyboard.c: New file.
|
||||
|
||||
2009-02-14 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Corrected wrong declaration
|
||||
|
|
1
DISTLIST
1
DISTLIST
|
@ -425,6 +425,7 @@ partmap/sun.c
|
|||
term/gfxterm.c
|
||||
term/terminfo.c
|
||||
term/tparm.c
|
||||
term/usb_keyboard.c
|
||||
term/efi/console.c
|
||||
term/i386/vga_common.c
|
||||
term/i386/pc/at_keyboard.c
|
||||
|
|
|
@ -980,7 +980,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \
|
|||
ata.mod vga.mod memdisk.mod pci.mod lspci.mod \
|
||||
aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
|
||||
datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \
|
||||
usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod
|
||||
usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod
|
||||
|
||||
# For biosdisk.mod.
|
||||
biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
|
||||
|
@ -3054,6 +3054,63 @@ partmap-usbms_mod-disk_usbms.lst: disk/usbms.c $(disk/usbms.c_DEPENDENCIES) genp
|
|||
usbms_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
usbms_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
# For usb_keyboard.mod
|
||||
usb_keyboard_mod_SOURCES = term/usb_keyboard.c
|
||||
CLEANFILES += usb_keyboard.mod mod-usb_keyboard.o mod-usb_keyboard.c pre-usb_keyboard.o usb_keyboard_mod-term_usb_keyboard.o und-usb_keyboard.lst
|
||||
ifneq ($(usb_keyboard_mod_EXPORTS),no)
|
||||
CLEANFILES += def-usb_keyboard.lst
|
||||
DEFSYMFILES += def-usb_keyboard.lst
|
||||
endif
|
||||
MOSTLYCLEANFILES += usb_keyboard_mod-term_usb_keyboard.d
|
||||
UNDSYMFILES += und-usb_keyboard.lst
|
||||
|
||||
usb_keyboard.mod: pre-usb_keyboard.o mod-usb_keyboard.o $(TARGET_OBJ2ELF)
|
||||
-rm -f $@
|
||||
$(TARGET_CC) $(usb_keyboard_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ pre-usb_keyboard.o mod-usb_keyboard.o
|
||||
if test ! -z $(TARGET_OBJ2ELF); then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi
|
||||
$(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@
|
||||
|
||||
pre-usb_keyboard.o: $(usb_keyboard_mod_DEPENDENCIES) usb_keyboard_mod-term_usb_keyboard.o
|
||||
-rm -f $@
|
||||
$(TARGET_CC) $(usb_keyboard_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ usb_keyboard_mod-term_usb_keyboard.o
|
||||
|
||||
mod-usb_keyboard.o: mod-usb_keyboard.c
|
||||
$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_keyboard_mod_CFLAGS) -c -o $@ $<
|
||||
|
||||
mod-usb_keyboard.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
|
||||
sh $(srcdir)/genmodsrc.sh 'usb_keyboard' $< > $@ || (rm -f $@; exit 1)
|
||||
|
||||
ifneq ($(usb_keyboard_mod_EXPORTS),no)
|
||||
def-usb_keyboard.lst: pre-usb_keyboard.o
|
||||
$(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 usb_keyboard/' > $@
|
||||
endif
|
||||
|
||||
und-usb_keyboard.lst: pre-usb_keyboard.o
|
||||
echo 'usb_keyboard' > $@
|
||||
$(NM) -u -P -p $< | cut -f1 -d' ' >> $@
|
||||
|
||||
usb_keyboard_mod-term_usb_keyboard.o: term/usb_keyboard.c $(term/usb_keyboard.c_DEPENDENCIES)
|
||||
$(TARGET_CC) -Iterm -I$(srcdir)/term $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_keyboard_mod_CFLAGS) -MD -c -o $@ $<
|
||||
-include usb_keyboard_mod-term_usb_keyboard.d
|
||||
|
||||
CLEANFILES += cmd-usb_keyboard_mod-term_usb_keyboard.lst fs-usb_keyboard_mod-term_usb_keyboard.lst partmap-usb_keyboard_mod-term_usb_keyboard.lst
|
||||
COMMANDFILES += cmd-usb_keyboard_mod-term_usb_keyboard.lst
|
||||
FSFILES += fs-usb_keyboard_mod-term_usb_keyboard.lst
|
||||
PARTMAPFILES += partmap-usb_keyboard_mod-term_usb_keyboard.lst
|
||||
|
||||
cmd-usb_keyboard_mod-term_usb_keyboard.lst: term/usb_keyboard.c $(term/usb_keyboard.c_DEPENDENCIES) gencmdlist.sh
|
||||
set -e; $(TARGET_CC) -Iterm -I$(srcdir)/term $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_keyboard_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh usb_keyboard > $@ || (rm -f $@; exit 1)
|
||||
|
||||
fs-usb_keyboard_mod-term_usb_keyboard.lst: term/usb_keyboard.c $(term/usb_keyboard.c_DEPENDENCIES) genfslist.sh
|
||||
set -e; $(TARGET_CC) -Iterm -I$(srcdir)/term $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_keyboard_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh usb_keyboard > $@ || (rm -f $@; exit 1)
|
||||
|
||||
partmap-usb_keyboard_mod-term_usb_keyboard.lst: term/usb_keyboard.c $(term/usb_keyboard.c_DEPENDENCIES) genpartmaplist.sh
|
||||
set -e; $(TARGET_CC) -Iterm -I$(srcdir)/term $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(usb_keyboard_mod_CFLAGS) -E $< | sh $(srcdir)/genpartmaplist.sh usb_keyboard > $@ || (rm -f $@; exit 1)
|
||||
|
||||
|
||||
usb_keyboard_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
usb_keyboard_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
# For pxe.mod
|
||||
pxe_mod_SOURCES = fs/i386/pc/pxe.c
|
||||
CLEANFILES += pxe.mod mod-pxe.o mod-pxe.c pre-pxe.o pxe_mod-fs_i386_pc_pxe.o und-pxe.lst
|
||||
|
|
|
@ -173,7 +173,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \
|
|||
ata.mod vga.mod memdisk.mod pci.mod lspci.mod \
|
||||
aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
|
||||
datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \
|
||||
usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod
|
||||
usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod
|
||||
|
||||
# For biosdisk.mod.
|
||||
biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
|
||||
|
@ -335,6 +335,11 @@ usbms_mod_SOURCES = disk/usbms.c
|
|||
usbms_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
usbms_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
# For usb_keyboard.mod
|
||||
usb_keyboard_mod_SOURCES = term/usb_keyboard.c
|
||||
usb_keyboard_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
usb_keyboard_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
||||
# For pxe.mod
|
||||
pxe_mod_SOURCES = fs/i386/pc/pxe.c
|
||||
pxe_mod_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
|
257
term/usb_keyboard.c
Normal file
257
term/usb_keyboard.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
/* Support for the HID Boot Protocol. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 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/machine/machine.h>
|
||||
#include <grub/machine/console.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/cpu/io.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/usb.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
|
||||
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_usb_device_t usbdev;
|
||||
|
||||
static void
|
||||
grub_usb_hid (void)
|
||||
{
|
||||
struct grub_usb_desc_device *descdev;
|
||||
|
||||
auto int usb_iterate (grub_usb_device_t dev);
|
||||
int usb_iterate (grub_usb_device_t dev)
|
||||
{
|
||||
descdev = &dev->descdev;
|
||||
|
||||
grub_dprintf ("usb_keyboard", "%x %x %x\n",
|
||||
descdev->class, descdev->subclass, descdev->protocol);
|
||||
|
||||
#if 0
|
||||
if (descdev->class != 0x09
|
||||
|| descdev->subclass == 0x01
|
||||
|| descdev->protocol != 0x02)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (descdev->class != 0 || descdev->subclass != 0 || descdev->protocol != 0)
|
||||
return 0;
|
||||
|
||||
grub_printf ("HID found!\n");
|
||||
|
||||
usbdev = dev;
|
||||
|
||||
return 1;
|
||||
}
|
||||
grub_usb_iterate (usb_iterate);
|
||||
|
||||
/* Place the device in boot mode. */
|
||||
grub_usb_control_msg (usbdev, 0x21, 0x0B, 0, 0, 0, 0);
|
||||
|
||||
/* Reports everytime an event occurs and not more often than that. */
|
||||
grub_usb_control_msg (usbdev, 0x21, 0x0A, 0<<8, 0, 0, 0);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_usb_keyboard_getreport (grub_usb_device_t dev, unsigned char *report)
|
||||
{
|
||||
return grub_usb_control_msg (dev, (1 << 7) | (1 << 5) | 1, 0x01, 0, 0,
|
||||
8, (char *) report);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
grub_usb_keyboard_checkkey (void)
|
||||
{
|
||||
unsigned char data[8];
|
||||
int key;
|
||||
int i;
|
||||
grub_err_t err;
|
||||
|
||||
data[2] = 0;
|
||||
for (i = 0; i < 50; i++)
|
||||
{
|
||||
/* Get_Report. */
|
||||
err = grub_usb_keyboard_getreport (usbdev, data);
|
||||
|
||||
if (! err && data[2])
|
||||
break;
|
||||
}
|
||||
|
||||
if (err || !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)
|
||||
key = keyboard_map[data[2]] - 'a' + 1;
|
||||
else if (data[0] & 0x02 || data[0] & 0x20)
|
||||
key = keyboard_map_shift[data[2]];
|
||||
else
|
||||
key = keyboard_map[data[2]];
|
||||
|
||||
if (key == 0)
|
||||
grub_printf ("Unknown key 0x%x detected\n", data[2]);
|
||||
|
||||
#if 0
|
||||
/* Wait until the key is released. */
|
||||
while (!err && data[2])
|
||||
{
|
||||
err = grub_usb_control_msg (usbdev, (1 << 7) | (1 << 5) | 1, 0x01, 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
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
return 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 (void)
|
||||
{
|
||||
int key;
|
||||
int key_release;
|
||||
grub_err_t err;
|
||||
unsigned char data[8];
|
||||
grub_uint64_t currtime;
|
||||
int timeout;
|
||||
static grub_usb_keyboard_repeat_t repeat = GRUB_HIDBOOT_REPEAT_NONE;
|
||||
|
||||
again:
|
||||
|
||||
do
|
||||
{
|
||||
key = grub_usb_keyboard_checkkey ();
|
||||
} while (key == -1);
|
||||
|
||||
data[2] = !0; /* Or whatever. */
|
||||
err = 0;
|
||||
|
||||
switch (repeat)
|
||||
{
|
||||
case GRUB_HIDBOOT_REPEAT_NONE:
|
||||
timeout = 100;
|
||||
break;
|
||||
case GRUB_HIDBOOT_REPEAT_FIRST:
|
||||
timeout = 500;
|
||||
break;
|
||||
case GRUB_HIDBOOT_REPEAT:
|
||||
timeout = 50;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait until the key is released. */
|
||||
currtime = grub_get_time_ms ();
|
||||
while (!err && data[2])
|
||||
{
|
||||
/* Implement a timeout. */
|
||||
if (grub_get_time_ms () > currtime + timeout)
|
||||
{
|
||||
if (repeat == 0)
|
||||
repeat = 1;
|
||||
else
|
||||
repeat = 2;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return key;
|
||||
}
|
||||
|
||||
err = grub_usb_keyboard_getreport (usbdev, data);
|
||||
}
|
||||
|
||||
if (repeat)
|
||||
{
|
||||
repeat = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
repeat = 0;
|
||||
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static struct grub_term_input grub_usb_keyboard_term =
|
||||
{
|
||||
.name = "usb_keyboard",
|
||||
.checkkey = grub_usb_keyboard_checkkey,
|
||||
.getkey = grub_usb_keyboard_getkey,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT(usb_keyboard)
|
||||
{
|
||||
(void) mod; /* To stop warning. */
|
||||
|
||||
grub_usb_hid ();
|
||||
grub_term_register_input (&grub_usb_keyboard_term);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI(usb_keyboard)
|
||||
{
|
||||
grub_term_unregister_input (&grub_usb_keyboard_term);
|
||||
}
|
Loading…
Reference in a new issue