2009-08-28 Colin Watson <cjwatson@ubuntu.com>

2009-08-28  Robert Millan  <rmh.grub@aybabtu.com>

	Add `getkeystatus' terminal method.  Add a new `keystatus' command
	to query it.

	* include/grub/term.h (GRUB_TERM_STATUS_SHIFT,
	GRUB_TERM_STATUS_CTRL, GRUB_TERM_STATUS_ALT): Definitions for
	modifier key bitmasks.
	(struct grub_term_input): Add `getkeystatus' member.
	(grub_getkeystatus): Add prototype.
	* kern/term.c (grub_getkeystatus): New function.

	* include/grub/i386/pc/memory.h
	(GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR): New macro.
	(struct grub_machine_bios_data_area): Define necessary parts of BIOS
	Data Area layout.
	* term/i386/pc/console.c (grub_console_getkeystatus): New function.
	(grub_console_term_input): Set `getkeystatus' member.
	* term/usb_keyboard.c (grub_usb_hid): Macroify HID protocol
	constants.
	(grub_usb_keyboard_getreport): Likewise.
	(grub_usb_keyboard_checkkey): Likewise.
	(grub_usb_keyboard_getkeystatus): New function.
	(grub_usb_keyboard_term): Set `getkeystatus' member.

	* commands/keystatus.c: New file.
	* conf/common.rmk (pkglib_MODULES): Add keystatus.mod.
	(keystatus_mod_SOURCES): New variable.
	(keystatus_mod_CFLAGS): Likewise.
	(keystatus_mod_LDFLAGS): Likewise.
	* conf/i386-coreboot.rmk (grub_emu_SOURCES): Add
	commands/keystatus.c.
	* conf/i386-efi.rmk (grub_emu_SOURCES): Likewise.
	* conf/i386-ieee1275.rmk (grub_emu_SOURCES): Likewise.
	* conf/i386-pc.rmk (grub_emu_SOURCES): Likewise.
	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise.
	* conf/x86_64-efi.rmk (grub_emu_SOURCES): Likewise.
	* DISTLIST: Add commands/keystatus.c.
This commit is contained in:
cjwatson 2009-08-28 13:20:34 +00:00
parent 6e2a90859a
commit 4cbe67e509
15 changed files with 270 additions and 15 deletions

View file

@ -58,6 +58,19 @@ static char keyboard_map_shift[128] =
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 0x61
/* Valid values for bRequest. See HID definition version 1.11 section 7.2. */
#define USB_HID_GET_REPORT 0x01
#define USB_HID_GET_IDLE 0x02
#define USB_HID_GET_PROTOCOL 0x03
#define USB_HID_SET_REPORT 0x09
#define USB_HID_SET_IDLE 0x0A
#define USB_HID_SET_PROTOCOL 0x0B
static void
grub_usb_hid (void)
{
@ -90,17 +103,19 @@ grub_usb_hid (void)
grub_usb_iterate (usb_iterate);
/* Place the device in boot mode. */
grub_usb_control_msg (usbdev, 0x21, 0x0B, 0, 0, 0, 0);
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, 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, 0x21, 0x0A, 0<<8, 0, 0, 0);
grub_usb_control_msg (usbdev, USB_HID_HOST_TO_DEVICE, USB_HID_SET_IDLE,
0<<8, 0, 0, 0);
}
static grub_err_t
grub_usb_keyboard_getreport (grub_usb_device_t dev, grub_uint8_t *report)
{
return grub_usb_control_msg (dev, (1 << 7) | (1 << 5) | 1, 0x01, 0, 0,
8, (char *) report);
return grub_usb_control_msg (dev, USB_HID_DEVICE_TO_HOST, USB_HID_GET_REPORT,
0, 0, 8, (char *) report);
}
@ -151,7 +166,8 @@ grub_usb_keyboard_checkkey (void)
/* Wait until the key is released. */
while (!err && data[2])
{
err = grub_usb_control_msg (usbdev, (1 << 7) | (1 << 5) | 1, 0x01, 0, 0,
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"
@ -238,11 +254,67 @@ grub_usb_keyboard_getkey (void)
return key;
}
static int
grub_usb_keyboard_getkeystatus (void)
{
grub_uint8_t data[8];
int mods = 0;
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]);
/* 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;
grub_errno = GRUB_ERR_NONE;
return mods;
}
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
};