2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
30 #include <ipxe/console.h>
31 #include <ipxe/keys.h>
41 /** List of USB keyboards */
42 static LIST_HEAD ( usb_keyboards
);
44 /******************************************************************************
48 ******************************************************************************
52 * Map USB keycode to iPXE key
55 * @v modifiers Modifiers
58 * Key codes are defined in the USB HID Usage Tables Keyboard/Keypad
61 static unsigned int usbkbd_map ( unsigned int keycode
,
62 unsigned int modifiers
) {
65 if ( keycode
< USBKBD_KEY_A
) {
68 } else if ( keycode
<= USBKBD_KEY_Z
) {
70 key
= ( keycode
- USBKBD_KEY_A
+ 'a' );
71 if ( modifiers
& USBKBD_CTRL
) {
72 key
-= ( 'a' - CTRL_A
);
73 } else if ( modifiers
& USBKBD_SHIFT
) {
76 } else if ( keycode
<= USBKBD_KEY_0
) {
78 if ( modifiers
& USBKBD_SHIFT
) {
79 key
= "!@#$%^&*()" [ keycode
- USBKBD_KEY_1
];
81 key
= ( ( ( keycode
- USBKBD_KEY_1
+ 1 ) % 10 ) + '0' );
83 } else if ( keycode
<= USBKBD_KEY_SPACE
) {
84 /* Unmodifiable keys */
85 static const uint8_t unmodifable
[] =
86 { LF
, ESC
, BACKSPACE
, TAB
, ' ' };
87 key
= unmodifable
[ keycode
- USBKBD_KEY_ENTER
];
88 } else if ( keycode
<= USBKBD_KEY_SLASH
) {
89 /* Punctuation keys */
90 if ( modifiers
& USBKBD_SHIFT
) {
91 key
= "_+{}|~:\"~<>?" [ keycode
- USBKBD_KEY_MINUS
];
93 key
= "-=[]\\#;'`,./" [ keycode
- USBKBD_KEY_MINUS
];
95 } else if ( keycode
<= USBKBD_KEY_UP
) {
97 static const uint16_t special
[] = {
98 0, 0, 0, 0, 0, KEY_F5
, KEY_F6
, KEY_F7
, KEY_F8
, KEY_F9
,
99 KEY_F10
, KEY_F11
, KEY_F12
, 0, 0, 0, KEY_IC
, KEY_HOME
,
100 KEY_PPAGE
, KEY_DC
, KEY_END
, KEY_NPAGE
, KEY_RIGHT
,
101 KEY_LEFT
, KEY_DOWN
, KEY_UP
103 key
= special
[ keycode
- USBKBD_KEY_CAPSLOCK
];
111 /******************************************************************************
115 ******************************************************************************
119 * Insert keypress into keyboard buffer
121 * @v kbd USB keyboard
123 * @v modifiers Modifiers
125 static void usbkbd_produce ( struct usb_keyboard
*kbd
, unsigned int keycode
,
126 unsigned int modifiers
) {
129 /* Map to iPXE key */
130 key
= usbkbd_map ( keycode
, modifiers
);
132 /* Do nothing if this keycode has no corresponding iPXE key */
134 DBGC ( kbd
, "KBD %s has no key for keycode %#02x:%#02x\n",
135 kbd
->name
, modifiers
, keycode
);
139 /* Check for buffer overrun */
140 if ( usbkbd_fill ( kbd
) >= USBKBD_BUFSIZE
) {
141 DBGC ( kbd
, "KBD %s buffer overrun (key %#02x)\n",
146 /* Insert into buffer */
147 kbd
->key
[ ( kbd
->prod
++ ) % USBKBD_BUFSIZE
] = key
;
148 DBGC2 ( kbd
, "KBD %s key %#02x produced\n", kbd
->name
, key
);
152 * Consume character from keyboard buffer
154 * @v kbd USB keyboard
155 * @ret character Character
157 static unsigned int usbkbd_consume ( struct usb_keyboard
*kbd
) {
158 static char buf
[] = "\x1b[xx~";
161 unsigned int character
;
166 assert ( usbkbd_fill ( kbd
) > 0 );
168 /* Get current keypress */
169 key
= kbd
->key
[ kbd
->cons
% USBKBD_BUFSIZE
];
171 /* If this is a straightforward key, just consume and return it */
172 if ( key
< KEY_MIN
) {
174 DBGC2 ( kbd
, "KBD %s key %#02x consumed\n", kbd
->name
, key
);
178 /* Construct ANSI sequence */
179 ansi_n
= KEY_ANSI_N ( key
);
181 tmp
+= sprintf ( tmp
, "%d", ansi_n
);
182 *(tmp
++) = KEY_ANSI_TERMINATOR ( key
);
185 assert ( len
< sizeof ( buf
) );
186 if ( kbd
->subcons
== 0 ) {
187 DBGC2 ( kbd
, "KBD %s key %#02x consumed as ^[%s\n",
188 kbd
->name
, key
, &buf
[1] );
191 /* Extract character from ANSI sequence */
192 assert ( kbd
->subcons
< len
);
193 character
= buf
[ kbd
->subcons
++ ];
195 /* Consume key if applicable */
196 if ( kbd
->subcons
== len
) {
204 /******************************************************************************
208 ******************************************************************************
212 * Check for presence of keycode in report
214 * @v report Keyboard report
215 * @v keycode Keycode (must be non-zero)
216 * @ret has_keycode Keycode is present in report
218 static int usbkbd_has_keycode ( struct usb_keyboard_report
*report
,
219 unsigned int keycode
) {
222 /* Check for keycode */
223 for ( i
= 0 ; i
< ( sizeof ( report
->keycode
) /
224 sizeof ( report
->keycode
[0] ) ) ; i
++ ) {
225 if ( report
->keycode
[i
] == keycode
)
233 * Handle keyboard report
235 * @v kbd USB keyboard
236 * @v new New keyboard report
238 static void usbkbd_report ( struct usb_keyboard
*kbd
,
239 struct usb_keyboard_report
*new ) {
240 struct usb_keyboard_report
*old
= &kbd
->report
;
241 unsigned int keycode
;
244 /* Check if current key has been released */
245 if ( kbd
->keycode
&& ! usbkbd_has_keycode ( new, kbd
->keycode
) ) {
246 DBGC2 ( kbd
, "KBD %s keycode %#02x released\n",
247 kbd
->name
, kbd
->keycode
);
251 /* Decrement auto-repeat hold-off timer, if applicable */
255 /* Check if a new key has been pressed */
256 for ( i
= 0 ; i
< ( sizeof ( new->keycode
) /
257 sizeof ( new->keycode
[0] ) ) ; i
++ ) {
259 /* Ignore keys present in the previous report */
260 keycode
= new->keycode
[i
];
261 if ( ( keycode
== 0 ) || usbkbd_has_keycode ( old
, keycode
) )
263 DBGC2 ( kbd
, "KBD %s keycode %#02x pressed\n",
264 kbd
->name
, keycode
);
266 /* Insert keypress into keyboard buffer */
267 usbkbd_produce ( kbd
, keycode
, new->modifiers
);
269 /* Record as most recent keycode */
270 kbd
->keycode
= keycode
;
272 /* Start auto-repeat hold-off timer */
273 kbd
->holdoff
= USBKBD_HOLDOFF
;
276 /* Insert auto-repeated keypress into keyboard buffer, if applicable */
277 if ( kbd
->keycode
&& ! kbd
->holdoff
)
278 usbkbd_produce ( kbd
, kbd
->keycode
, new->modifiers
);
281 memcpy ( old
, new, sizeof ( *old
) );
284 /******************************************************************************
288 ******************************************************************************
292 * Complete interrupt transfer
295 * @v iobuf I/O buffer
296 * @v rc Completion status code
298 static void usbkbd_complete ( struct usb_endpoint
*ep
,
299 struct io_buffer
*iobuf
, int rc
) {
300 struct usb_keyboard
*kbd
= container_of ( ep
, struct usb_keyboard
,
302 struct usb_keyboard_report
*report
;
304 /* Ignore packets cancelled when the endpoint closes */
308 /* Ignore packets with errors */
310 DBGC ( kbd
, "KBD %s interrupt IN failed: %s\n",
311 kbd
->name
, strerror ( rc
) );
315 /* Ignore underlength packets */
316 if ( iob_len ( iobuf
) < sizeof ( *report
) ) {
317 DBGC ( kbd
, "KBD %s underlength report:\n", kbd
->name
);
318 DBGC_HDA ( kbd
, 0, iobuf
->data
, iob_len ( iobuf
) );
321 report
= iobuf
->data
;
323 /* Handle keyboard report */
324 usbkbd_report ( kbd
, report
);
327 /* Recycle I/O buffer */
328 usb_recycle ( &kbd
->hid
.in
, iobuf
);
331 /** Interrupt endpoint operations */
332 static struct usb_endpoint_driver_operations usbkbd_operations
= {
333 .complete
= usbkbd_complete
,
336 /******************************************************************************
340 ******************************************************************************
346 * @v func USB function
347 * @v config Configuration descriptor
348 * @ret rc Return status code
350 static int usbkbd_probe ( struct usb_function
*func
,
351 struct usb_configuration_descriptor
*config
) {
352 struct usb_device
*usb
= func
->usb
;
353 struct usb_keyboard
*kbd
;
356 /* Allocate and initialise structure */
357 kbd
= zalloc ( sizeof ( *kbd
) );
362 kbd
->name
= func
->name
;
363 kbd
->bus
= usb
->port
->hub
->bus
;
364 usbhid_init ( &kbd
->hid
, func
, &usbkbd_operations
, NULL
);
365 usb_refill_init ( &kbd
->hid
.in
, sizeof ( kbd
->report
),
366 USBKBD_INTR_MAX_FILL
);
368 /* Describe USB human interface device */
369 if ( ( rc
= usbhid_describe ( &kbd
->hid
, config
) ) != 0 ) {
370 DBGC ( kbd
, "KBD %s could not describe: %s\n",
371 kbd
->name
, strerror ( rc
) );
374 DBGC ( kbd
, "KBD %s using %s (len %zd)\n",
375 kbd
->name
, usb_endpoint_name ( &kbd
->hid
.in
), kbd
->hid
.in
.mtu
);
377 /* Set boot protocol */
378 if ( ( rc
= usbhid_set_protocol ( usb
, func
->interface
[0],
379 USBHID_PROTOCOL_BOOT
) ) != 0 ) {
380 DBGC ( kbd
, "KBD %s could not set boot protocol: %s\n",
381 kbd
->name
, strerror ( rc
) );
382 goto err_set_protocol
;
386 if ( ( rc
= usbhid_set_idle ( usb
, func
->interface
[0], 0,
387 USBKBD_IDLE_DURATION
) ) != 0 ) {
388 DBGC ( kbd
, "KBD %s could not set idle time: %s\n",
389 kbd
->name
, strerror ( rc
) );
393 /* Open USB human interface device */
394 if ( ( rc
= usbhid_open ( &kbd
->hid
) ) != 0 ) {
395 DBGC ( kbd
, "KBD %s could not open: %s\n",
396 kbd
->name
, strerror ( rc
) );
400 /* Add to list of USB keyboards */
401 list_add_tail ( &kbd
->list
, &usb_keyboards
);
403 usb_func_set_drvdata ( func
, kbd
);
406 usbhid_close ( &kbd
->hid
);
419 * @v func USB function
421 static void usbkbd_remove ( struct usb_function
*func
) {
422 struct usb_keyboard
*kbd
= usb_func_get_drvdata ( func
);
424 /* Remove from list of USB keyboards */
425 list_del ( &kbd
->list
);
427 /* Close USB human interface device */
428 usbhid_close ( &kbd
->hid
);
434 /** USB keyboard device IDs */
435 static struct usb_device_id usbkbd_ids
[] = {
438 .vendor
= USB_ANY_ID
,
439 .product
= USB_ANY_ID
,
441 .class = USB_CLASS_HID
,
442 .subclass
= USB_SUBCLASS_HID_BOOT
,
443 .protocol
= USBKBD_PROTOCOL
,
448 /** USB keyboard driver */
449 struct usb_driver usbkbd_driver __usb_driver
= {
451 .id_count
= ( sizeof ( usbkbd_ids
) / sizeof ( usbkbd_ids
[0] ) ),
452 .probe
= usbkbd_probe
,
453 .remove
= usbkbd_remove
,
456 /******************************************************************************
460 ******************************************************************************
464 * Read a character from the console
466 * @ret character Character read
468 static int usbkbd_getchar ( void ) {
469 struct usb_keyboard
*kbd
;
471 /* Consume first available key */
472 list_for_each_entry ( kbd
, &usb_keyboards
, list
) {
473 if ( usbkbd_fill ( kbd
) )
474 return usbkbd_consume ( kbd
);
481 * Check for available input
483 * @ret is_available Input is available
485 static int usbkbd_iskey ( void ) {
486 struct usb_keyboard
*kbd
;
489 /* Poll all USB keyboards and refill endpoints */
490 list_for_each_entry ( kbd
, &usb_keyboards
, list
) {
491 usb_poll ( kbd
->bus
);
492 usb_refill ( &kbd
->hid
.in
);
495 /* Check for a non-empty keyboard buffer */
496 list_for_each_entry ( kbd
, &usb_keyboards
, list
) {
497 fill
= usbkbd_fill ( kbd
);
505 /** USB keyboard console */
506 struct console_driver usbkbd_console __console_driver
= {
507 .getchar
= usbkbd_getchar
,
508 .iskey
= usbkbd_iskey
,