summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb
diff options
context:
space:
mode:
authorMichael Brown2016-01-06 17:30:01 +0100
committerMichael Brown2016-01-06 19:55:08 +0100
commit2f861d736f8b156aa87de3f0e250380ca292f767 (patch)
tree4c98803b2380a5b0585d26107e5a69c5f2c71b9b /src/drivers/usb
parent[romprefix] Report an optimistic runtime size estimate (diff)
downloadipxe-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.c88
-rw-r--r--src/drivers/usb/usbkbd.h19
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.