Browse Source

[usb] Add support for numeric keypad on USB keyboards

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
2f861d736f
3 changed files with 134 additions and 7 deletions
  1. 82
    6
      src/drivers/usb/usbkbd.c
  2. 18
    1
      src/drivers/usb/usbkbd.h
  3. 34
    0
      src/include/ipxe/usbhid.h

+ 82
- 6
src/drivers/usb/usbkbd.c View File

53
  *
53
  *
54
  * @v keycode		Keycode
54
  * @v keycode		Keycode
55
  * @v modifiers		Modifiers
55
  * @v modifiers		Modifiers
56
+ * @v leds		LED state
56
  * @ret key		iPXE key
57
  * @ret key		iPXE key
57
  *
58
  *
58
  * Key codes are defined in the USB HID Usage Tables Keyboard/Keypad
59
  * Key codes are defined in the USB HID Usage Tables Keyboard/Keypad
59
  * page.
60
  * page.
60
  */
61
  */
61
-static unsigned int usbkbd_map ( unsigned int keycode,
62
-				 unsigned int modifiers ) {
62
+static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers,
63
+				 unsigned int leds ) {
63
 	unsigned int key;
64
 	unsigned int key;
64
 
65
 
65
 	if ( keycode < USBKBD_KEY_A ) {
66
 	if ( keycode < USBKBD_KEY_A ) {
70
 		key = ( keycode - USBKBD_KEY_A + 'a' );
71
 		key = ( keycode - USBKBD_KEY_A + 'a' );
71
 		if ( modifiers & USBKBD_CTRL ) {
72
 		if ( modifiers & USBKBD_CTRL ) {
72
 			key -= ( 'a' - CTRL_A );
73
 			key -= ( 'a' - CTRL_A );
73
-		} else if ( modifiers & USBKBD_SHIFT ) {
74
+		} else if ( ( modifiers & USBKBD_SHIFT ) ||
75
+			    ( leds & USBKBD_LED_CAPS_LOCK ) ) {
74
 			key -= ( 'a' - 'A' );
76
 			key -= ( 'a' - 'A' );
75
 		}
77
 		}
76
 	} else if ( keycode <= USBKBD_KEY_0 ) {
78
 	} else if ( keycode <= USBKBD_KEY_0 ) {
100
 			KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
102
 			KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
101
 			KEY_LEFT, KEY_DOWN, KEY_UP
103
 			KEY_LEFT, KEY_DOWN, KEY_UP
102
 		};
104
 		};
103
-		key = special[ keycode - USBKBD_KEY_CAPSLOCK ];
105
+		key = special[ keycode - USBKBD_KEY_CAPS_LOCK ];
106
+	} else if ( keycode <= USBKBD_KEY_PAD_ENTER ) {
107
+		/* Keypad (unaffected by Num Lock) */
108
+		key = "\0/*-+\n" [ keycode - USBKBD_KEY_NUM_LOCK ];
109
+	} else if ( keycode <= USBKBD_KEY_PAD_DOT ) {
110
+		/* Keypad (affected by Num Lock) */
111
+		if ( leds & USBKBD_LED_NUM_LOCK ) {
112
+			key = "1234567890." [ keycode - USBKBD_KEY_PAD_1 ];
113
+		} else {
114
+			static const uint16_t keypad[] = {
115
+				KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, 0,
116
+				KEY_RIGHT, KEY_HOME, KEY_UP, KEY_PPAGE,
117
+				KEY_IC, KEY_DC
118
+			};
119
+			key = keypad[ keycode - USBKBD_KEY_PAD_1 ];
120
+		};
104
 	} else {
121
 	} else {
105
 		key = 0;
122
 		key = 0;
106
 	}
123
 	}
124
  */
141
  */
125
 static void usbkbd_produce ( struct usb_keyboard *kbd, unsigned int keycode,
142
 static void usbkbd_produce ( struct usb_keyboard *kbd, unsigned int keycode,
126
 			     unsigned int modifiers ) {
143
 			     unsigned int modifiers ) {
144
+	unsigned int leds = 0;
127
 	unsigned int key;
145
 	unsigned int key;
128
 
146
 
147
+	/* Check for LED-modifying keys */
148
+	if ( keycode == USBKBD_KEY_CAPS_LOCK ) {
149
+		leds = USBKBD_LED_CAPS_LOCK;
150
+	} else if ( keycode == USBKBD_KEY_NUM_LOCK ) {
151
+		leds = USBKBD_LED_NUM_LOCK;
152
+	}
153
+
154
+	/* Handle LED-modifying keys */
155
+	if ( leds ) {
156
+		kbd->leds ^= leds;
157
+		kbd->leds_changed = 1;
158
+		return;
159
+	}
160
+
129
 	/* Map to iPXE key */
161
 	/* Map to iPXE key */
130
-	key = usbkbd_map ( keycode, modifiers );
162
+	key = usbkbd_map ( keycode, modifiers, kbd->leds );
131
 
163
 
132
 	/* Do nothing if this keycode has no corresponding iPXE key */
164
 	/* Do nothing if this keycode has no corresponding iPXE key */
133
 	if ( ! key ) {
165
 	if ( ! key ) {
333
 	.complete = usbkbd_complete,
365
 	.complete = usbkbd_complete,
334
 };
366
 };
335
 
367
 
368
+/******************************************************************************
369
+ *
370
+ * Keyboard LEDs
371
+ *
372
+ ******************************************************************************
373
+ */
374
+
375
+/**
376
+ * Set keyboard LEDs
377
+ *
378
+ * @v kbd		USB keyboard
379
+ * @ret rc		Return status code
380
+ */
381
+static int usbkbd_set_leds ( struct usb_keyboard *kbd ) {
382
+	struct usb_function *func = kbd->hid.func;
383
+	int rc;
384
+
385
+	DBGC2 ( kbd, "KBD %s setting LEDs to %#02x\n", kbd->name, kbd->leds );
386
+
387
+	/* Set keyboard LEDs */
388
+	if ( ( rc = usbhid_set_report ( func->usb, func->interface[0],
389
+					USBHID_REPORT_OUTPUT, 0, &kbd->leds,
390
+					sizeof ( kbd->leds ) ) ) != 0 ) {
391
+		DBGC ( kbd, "KBD %s could not set LEDs to %#02x: %s\n",
392
+		       kbd->name, kbd->leds, strerror ( rc ) );
393
+		return rc;
394
+	}
395
+
396
+	return 0;
397
+}
398
+
336
 /******************************************************************************
399
 /******************************************************************************
337
  *
400
  *
338
  * USB interface
401
  * USB interface
400
 	/* Add to list of USB keyboards */
463
 	/* Add to list of USB keyboards */
401
 	list_add_tail ( &kbd->list, &usb_keyboards );
464
 	list_add_tail ( &kbd->list, &usb_keyboards );
402
 
465
 
466
+	/* Set initial LED state */
467
+	usbkbd_set_leds ( kbd );
468
+
403
 	usb_func_set_drvdata ( func, kbd );
469
 	usb_func_set_drvdata ( func, kbd );
404
 	return 0;
470
 	return 0;
405
 
471
 
484
 	struct usb_keyboard *kbd;
550
 	struct usb_keyboard *kbd;
485
 	unsigned int fill;
551
 	unsigned int fill;
486
 
552
 
487
-	/* Poll all USB keyboards and refill endpoints */
553
+	/* Poll USB keyboards, refill endpoints, and set LEDs if applicable */
488
 	list_for_each_entry ( kbd, &usb_keyboards, list ) {
554
 	list_for_each_entry ( kbd, &usb_keyboards, list ) {
555
+
556
+		/* Poll keyboard */
489
 		usb_poll ( kbd->bus );
557
 		usb_poll ( kbd->bus );
558
+
559
+		/* Refill endpoints */
490
 		usb_refill ( &kbd->hid.in );
560
 		usb_refill ( &kbd->hid.in );
561
+
562
+		/* Update keyboard LEDs, if applicable */
563
+		if ( kbd->leds_changed ) {
564
+			usbkbd_set_leds ( kbd );
565
+			kbd->leds_changed = 0;
566
+		}
491
 	}
567
 	}
492
 
568
 
493
 	/* Check for a non-empty keyboard buffer */
569
 	/* Check for a non-empty keyboard buffer */

+ 18
- 1
src/drivers/usb/usbkbd.h View File

68
 	USBKBD_KEY_SPACE = 0x2c,
68
 	USBKBD_KEY_SPACE = 0x2c,
69
 	USBKBD_KEY_MINUS = 0x2d,
69
 	USBKBD_KEY_MINUS = 0x2d,
70
 	USBKBD_KEY_SLASH = 0x38,
70
 	USBKBD_KEY_SLASH = 0x38,
71
-	USBKBD_KEY_CAPSLOCK = 0x39,
71
+	USBKBD_KEY_CAPS_LOCK = 0x39,
72
+	USBKBD_KEY_F1 = 0x3a,
72
 	USBKBD_KEY_UP = 0x52,
73
 	USBKBD_KEY_UP = 0x52,
74
+	USBKBD_KEY_NUM_LOCK = 0x53,
75
+	USBKBD_KEY_PAD_ENTER = 0x58,
76
+	USBKBD_KEY_PAD_1 = 0x59,
77
+	USBKBD_KEY_PAD_DOT = 0x63,
78
+};
79
+
80
+/** USB keyboard LEDs */
81
+enum usb_keyboard_led {
82
+	USBKBD_LED_NUM_LOCK = 0x01,
83
+	USBKBD_LED_CAPS_LOCK = 0x02,
84
+	USBKBD_LED_SCROLL_LOCK = 0x04,
73
 };
85
 };
74
 
86
 
75
 /** Keyboard idle duration (in 4ms units)
87
 /** Keyboard idle duration (in 4ms units)
120
 	/** Autorepeat hold-off time (in number of completions reported) */
132
 	/** Autorepeat hold-off time (in number of completions reported) */
121
 	unsigned int holdoff;
133
 	unsigned int holdoff;
122
 
134
 
135
+	/** Keyboard LED state */
136
+	uint8_t leds;
137
+	/** Keyboard LEDs changed */
138
+	uint8_t leds_changed;
139
+
123
 	/** Keyboard buffer
140
 	/** Keyboard buffer
124
 	 *
141
 	 *
125
 	 * This stores iPXE key values.
142
 	 * This stores iPXE key values.

+ 34
- 0
src/include/ipxe/usbhid.h View File

33
 	( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE |		\
33
 	( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE |		\
34
 	  USB_REQUEST_TYPE ( 0x0a ) )
34
 	  USB_REQUEST_TYPE ( 0x0a ) )
35
 
35
 
36
+/** Set report */
37
+#define USBHID_SET_REPORT						\
38
+	( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE |		\
39
+	  USB_REQUEST_TYPE ( 0x09 ) )
40
+
41
+/** Input report type */
42
+#define USBHID_REPORT_INPUT 0x01
43
+
44
+/** Output report type */
45
+#define USBHID_REPORT_OUTPUT 0x02
46
+
47
+/** Feature report type */
48
+#define USBHID_REPORT_FEATURE 0x03
49
+
36
 /** A USB human interface device */
50
 /** A USB human interface device */
37
 struct usb_hid {
51
 struct usb_hid {
38
 	/** USB function */
52
 	/** USB function */
97
 			     interface, NULL, 0 );
111
 			     interface, NULL, 0 );
98
 }
112
 }
99
 
113
 
114
+/**
115
+ * Set report
116
+ *
117
+ * @v usb		USB device
118
+ * @v interface		Interface number
119
+ * @v type		Report type
120
+ * @v report		Report ID
121
+ * @v data		Report data
122
+ * @v len		Length of report data
123
+ * @ret rc		Return status code
124
+ */
125
+static inline __attribute__ (( always_inline )) int
126
+usbhid_set_report ( struct usb_device *usb, unsigned int interface,
127
+		    unsigned int type, unsigned int report, void *data,
128
+		    size_t len ) {
129
+
130
+	return usb_control ( usb, USBHID_SET_REPORT, ( ( type << 8 ) | report ),
131
+			     interface, data, len );
132
+}
133
+
100
 extern int usbhid_open ( struct usb_hid *hid );
134
 extern int usbhid_open ( struct usb_hid *hid );
101
 extern void usbhid_close ( struct usb_hid *hid );
135
 extern void usbhid_close ( struct usb_hid *hid );
102
 extern int usbhid_refill ( struct usb_hid *hid );
136
 extern int usbhid_refill ( struct usb_hid *hid );

Loading…
Cancel
Save