diff options
author | Michael Brown | 2016-01-06 17:30:01 +0100 |
---|---|---|
committer | Michael Brown | 2016-01-06 19:55:08 +0100 |
commit | 2f861d736f8b156aa87de3f0e250380ca292f767 (patch) | |
tree | 4c98803b2380a5b0585d26107e5a69c5f2c71b9b /src/drivers/usb | |
parent | [romprefix] Report an optimistic runtime size estimate (diff) | |
download | ipxe-2f861d736f8b156aa87de3f0e250380ca292f767.tar.gz ipxe-2f861d736f8b156aa87de3f0e250380ca292f767.tar.xz ipxe-2f861d736f8b156aa87de3f0e250380ca292f767.zip |
[usb] Add support for numeric keypad on USB keyboards
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb')
-rw-r--r-- | src/drivers/usb/usbkbd.c | 88 | ||||
-rw-r--r-- | src/drivers/usb/usbkbd.h | 19 |
2 files changed, 100 insertions, 7 deletions
diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index 512adfe2..76db5771 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -53,13 +53,14 @@ static LIST_HEAD ( usb_keyboards ); * * @v keycode Keycode * @v modifiers Modifiers + * @v leds LED state * @ret key iPXE key * * Key codes are defined in the USB HID Usage Tables Keyboard/Keypad * page. */ -static unsigned int usbkbd_map ( unsigned int keycode, - unsigned int modifiers ) { +static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, + unsigned int leds ) { unsigned int key; if ( keycode < USBKBD_KEY_A ) { @@ -70,7 +71,8 @@ static unsigned int usbkbd_map ( unsigned int keycode, key = ( keycode - USBKBD_KEY_A + 'a' ); if ( modifiers & USBKBD_CTRL ) { key -= ( 'a' - CTRL_A ); - } else if ( modifiers & USBKBD_SHIFT ) { + } else if ( ( modifiers & USBKBD_SHIFT ) || + ( leds & USBKBD_LED_CAPS_LOCK ) ) { key -= ( 'a' - 'A' ); } } else if ( keycode <= USBKBD_KEY_0 ) { @@ -100,7 +102,22 @@ static unsigned int usbkbd_map ( unsigned int keycode, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP }; - key = special[ keycode - USBKBD_KEY_CAPSLOCK ]; + key = special[ keycode - USBKBD_KEY_CAPS_LOCK ]; + } else if ( keycode <= USBKBD_KEY_PAD_ENTER ) { + /* Keypad (unaffected by Num Lock) */ + key = "\0/*-+\n" [ keycode - USBKBD_KEY_NUM_LOCK ]; + } else if ( keycode <= USBKBD_KEY_PAD_DOT ) { + /* Keypad (affected by Num Lock) */ + if ( leds & USBKBD_LED_NUM_LOCK ) { + key = "1234567890." [ keycode - USBKBD_KEY_PAD_1 ]; + } else { + static const uint16_t keypad[] = { + KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, 0, + KEY_RIGHT, KEY_HOME, KEY_UP, KEY_PPAGE, + KEY_IC, KEY_DC + }; + key = keypad[ keycode - USBKBD_KEY_PAD_1 ]; + }; } else { key = 0; } @@ -124,10 +141,25 @@ static unsigned int usbkbd_map ( unsigned int keycode, */ static void usbkbd_produce ( struct usb_keyboard *kbd, unsigned int keycode, unsigned int modifiers ) { + unsigned int leds = 0; unsigned int key; + /* Check for LED-modifying keys */ + if ( keycode == USBKBD_KEY_CAPS_LOCK ) { + leds = USBKBD_LED_CAPS_LOCK; + } else if ( keycode == USBKBD_KEY_NUM_LOCK ) { + leds = USBKBD_LED_NUM_LOCK; + } + + /* Handle LED-modifying keys */ + if ( leds ) { + kbd->leds ^= leds; + kbd->leds_changed = 1; + return; + } + /* Map to iPXE key */ - key = usbkbd_map ( keycode, modifiers ); + key = usbkbd_map ( keycode, modifiers, kbd->leds ); /* Do nothing if this keycode has no corresponding iPXE key */ if ( ! key ) { @@ -335,6 +367,37 @@ static struct usb_endpoint_driver_operations usbkbd_operations = { /****************************************************************************** * + * Keyboard LEDs + * + ****************************************************************************** + */ + +/** + * Set keyboard LEDs + * + * @v kbd USB keyboard + * @ret rc Return status code + */ +static int usbkbd_set_leds ( struct usb_keyboard *kbd ) { + struct usb_function *func = kbd->hid.func; + int rc; + + DBGC2 ( kbd, "KBD %s setting LEDs to %#02x\n", kbd->name, kbd->leds ); + + /* Set keyboard LEDs */ + if ( ( rc = usbhid_set_report ( func->usb, func->interface[0], + USBHID_REPORT_OUTPUT, 0, &kbd->leds, + sizeof ( kbd->leds ) ) ) != 0 ) { + DBGC ( kbd, "KBD %s could not set LEDs to %#02x: %s\n", + kbd->name, kbd->leds, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/****************************************************************************** + * * USB interface * ****************************************************************************** @@ -400,6 +463,9 @@ static int usbkbd_probe ( struct usb_function *func, /* Add to list of USB keyboards */ list_add_tail ( &kbd->list, &usb_keyboards ); + /* Set initial LED state */ + usbkbd_set_leds ( kbd ); + usb_func_set_drvdata ( func, kbd ); return 0; @@ -484,10 +550,20 @@ static int usbkbd_iskey ( void ) { struct usb_keyboard *kbd; unsigned int fill; - /* Poll all USB keyboards and refill endpoints */ + /* Poll USB keyboards, refill endpoints, and set LEDs if applicable */ list_for_each_entry ( kbd, &usb_keyboards, list ) { + + /* Poll keyboard */ usb_poll ( kbd->bus ); + + /* Refill endpoints */ usb_refill ( &kbd->hid.in ); + + /* Update keyboard LEDs, if applicable */ + if ( kbd->leds_changed ) { + usbkbd_set_leds ( kbd ); + kbd->leds_changed = 0; + } } /* Check for a non-empty keyboard buffer */ diff --git a/src/drivers/usb/usbkbd.h b/src/drivers/usb/usbkbd.h index 7eab24e4..cedebfe7 100644 --- a/src/drivers/usb/usbkbd.h +++ b/src/drivers/usb/usbkbd.h @@ -68,8 +68,20 @@ enum usb_keycode { USBKBD_KEY_SPACE = 0x2c, USBKBD_KEY_MINUS = 0x2d, USBKBD_KEY_SLASH = 0x38, - USBKBD_KEY_CAPSLOCK = 0x39, + USBKBD_KEY_CAPS_LOCK = 0x39, + USBKBD_KEY_F1 = 0x3a, USBKBD_KEY_UP = 0x52, + USBKBD_KEY_NUM_LOCK = 0x53, + USBKBD_KEY_PAD_ENTER = 0x58, + USBKBD_KEY_PAD_1 = 0x59, + USBKBD_KEY_PAD_DOT = 0x63, +}; + +/** USB keyboard LEDs */ +enum usb_keyboard_led { + USBKBD_LED_NUM_LOCK = 0x01, + USBKBD_LED_CAPS_LOCK = 0x02, + USBKBD_LED_SCROLL_LOCK = 0x04, }; /** Keyboard idle duration (in 4ms units) @@ -120,6 +132,11 @@ struct usb_keyboard { /** Autorepeat hold-off time (in number of completions reported) */ unsigned int holdoff; + /** Keyboard LED state */ + uint8_t leds; + /** Keyboard LEDs changed */ + uint8_t leds_changed; + /** Keyboard buffer * * This stores iPXE key values. |