On Mon, Aug 24, 2009 at 02:23:52PM +0200, Robert Millan wrote: > I don't have time to test it, but what we want is roughly something like > this. If you would please test and confirm it's working the way you expected, > it can be committed.
OK, here's a cleanup that (a) fixes some compilation errors in your patch and (b) adds USB keyboard support back in. How does this look? 2009-08-24 Colin Watson <cjwat...@ubuntu.com> 2009-08-24 Robert Millan <rmh.g...@aybabtu.com> Add `getkeystatus' terminal method. Use it in `sleep' to detect Shift being held down. * 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_keyboard_getkeystatus): New function. (grub_usb_keyboard_term): Set `getkeystatus' member. * commands/sleep.c (grub_check_keyboard): New function. (grub_interruptible_millisleep, grub_cmd_sleep): Use grub_check_keyboard, checking whether Shift is pressed in addition to checking for Escape. Index: kern/term.c =================================================================== --- kern/term.c (revision 2525) +++ kern/term.c (working copy) @@ -140,6 +140,15 @@ return (grub_cur_term_input->checkkey) (); } +int +grub_getkeystatus (void) +{ + if (grub_cur_term_input->getkeystatus) + return (grub_cur_term_input->getkeystatus) (); + else + return 0; +} + grub_uint16_t grub_getxy (void) { Index: include/grub/term.h =================================================================== --- include/grub/term.h (revision 2525) +++ include/grub/term.h (working copy) @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2007,2008 Free Software Foundation, Inc. + * 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 @@ -72,6 +72,12 @@ #define GRUB_TERM_NEED_INIT (1 << 16) +/* 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) + + /* Unicode characters for fancy graphics. */ #define GRUB_TERM_DISP_LEFT 0x2190 #define GRUB_TERM_DISP_UP 0x2191 @@ -157,6 +163,9 @@ /* Get a character. */ int (*getkey) (void); + + /* Get keyboard modifier status. */ + int (*getkeystatus) (void); }; typedef struct grub_term_input *grub_term_input_t; @@ -275,6 +284,7 @@ grub_ssize_t EXPORT_FUNC(grub_getcharwidth) (grub_uint32_t code); int EXPORT_FUNC(grub_getkey) (void); int EXPORT_FUNC(grub_checkkey) (void); +int EXPORT_FUNC(grub_getkeystatus) (void); grub_uint16_t EXPORT_FUNC(grub_getwh) (void); grub_uint16_t EXPORT_FUNC(grub_getxy) (void); void EXPORT_FUNC(grub_gotoxy) (grub_uint8_t x, grub_uint8_t y); Index: include/grub/i386/pc/memory.h =================================================================== --- include/grub/i386/pc/memory.h (revision 2525) +++ include/grub/i386/pc/memory.h (working copy) @@ -78,8 +78,20 @@ /* The data segment of the pseudo real mode. */ #define GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG 0x20 +#define GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR 0x400 + #ifndef ASM_FILE +/* See http://heim.ifi.uio.no/~stanisls/helppc/bios_data_area.html for a + description of the BIOS Data Area layout. */ +struct grub_machine_bios_data_area +{ + grub_uint8_t unused1[0x17]; + grub_uint8_t keyboard_flag_lower; /* 0x17 */ + grub_uint8_t keyboard_flag_upper; /* 0x17 */ + grub_uint8_t unused2[0xf0 - 0x19]; +}; + struct grub_machine_mmap_entry { grub_uint32_t size; Index: commands/sleep.c =================================================================== --- commands/sleep.c (revision 2525) +++ commands/sleep.c (working copy) @@ -1,7 +1,7 @@ /* sleep.c - Command to wait a specified number of seconds. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,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 @@ -43,6 +43,20 @@ grub_printf ("%d ", n); } +static int +grub_check_keyboard (void) +{ + int mods = grub_getkeystatus (); + if (mods >= 0 && (mods & GRUB_TERM_STATUS_SHIFT) != 0) + return 1; + + if (grub_checkkey () >= 0 && + GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC) + return 1; + + return 0; +} + /* Based on grub_millisleep() from kern/generic/millisleep.c. */ static int grub_interruptible_millisleep (grub_uint32_t ms) @@ -52,8 +66,7 @@ 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_check_keyboard ()) return 1; return 0; @@ -74,7 +87,7 @@ if (n == 0) { /* Either `0' or broken input. */ - return 0; + return grub_check_keyboard (); } xy = grub_getxy (); Index: term/i386/pc/console.c =================================================================== --- term/i386/pc/console.c (revision 2525) +++ term/i386/pc/console.c (working copy) @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2007,2008 Free Software Foundation, Inc. + * 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 @@ -16,15 +16,35 @@ * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ +#include <grub/machine/memory.h> #include <grub/machine/console.h> #include <grub/term.h> #include <grub/types.h> +static const struct grub_machine_bios_data_area *bios_data_area = GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR; + +static int +grub_console_getkeystatus (void) +{ + grub_uint8_t status = bios_data_area->keyboard_flag_lower; + int mods = 0; + + if (status & 0x03) + mods |= GRUB_TERM_STATUS_SHIFT; + if (status & 0x04) + mods |= GRUB_TERM_STATUS_CTRL; + if (status & 0x08) + mods |= GRUB_TERM_STATUS_ALT; + + return mods; +} + static struct grub_term_input grub_console_term_input = { .name = "console", .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, + .getkeystatus = grub_console_getkeystatus, }; static struct grub_term_output grub_console_term_output = Index: term/usb_keyboard.c =================================================================== --- term/usb_keyboard.c (revision 2526) +++ term/usb_keyboard.c (working copy) @@ -238,11 +238,55 @@ 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; + + 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); + + 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 }; -- Colin Watson [cjwat...@ubuntu.com] _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel