iPXE
usbkbd.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <errno.h>
00029 #include <assert.h>
00030 #include <ipxe/console.h>
00031 #include <ipxe/keys.h>
00032 #include <ipxe/usb.h>
00033 #include "usbkbd.h"
00034 
00035 /** @file
00036  *
00037  * USB keyboard driver
00038  *
00039  */
00040 
00041 /** List of USB keyboards */
00042 static LIST_HEAD ( usb_keyboards );
00043 
00044 /******************************************************************************
00045  *
00046  * Keyboard map
00047  *
00048  ******************************************************************************
00049  */
00050 
00051 /**
00052  * Map USB keycode to iPXE key
00053  *
00054  * @v keycode           Keycode
00055  * @v modifiers         Modifiers
00056  * @v leds              LED state
00057  * @ret key             iPXE key
00058  *
00059  * Key codes are defined in the USB HID Usage Tables Keyboard/Keypad
00060  * page.
00061  */
00062 static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers,
00063                                  unsigned int leds ) {
00064         unsigned int key;
00065 
00066         if ( keycode < USBKBD_KEY_A ) {
00067                 /* Not keys */
00068                 key = 0;
00069         } else if ( keycode <= USBKBD_KEY_Z ) {
00070                 /* Alphabetic keys */
00071                 key = ( keycode - USBKBD_KEY_A + 'a' );
00072                 if ( modifiers & USBKBD_CTRL ) {
00073                         key -= ( 'a' - CTRL_A );
00074                 } else if ( ( modifiers & USBKBD_SHIFT ) ||
00075                             ( leds & USBKBD_LED_CAPS_LOCK ) ) {
00076                         key -= ( 'a' - 'A' );
00077                 }
00078         } else if ( keycode <= USBKBD_KEY_0 ) {
00079                 /* Numeric key row */
00080                 if ( modifiers & USBKBD_SHIFT ) {
00081                         key = "!@#$%^&*()" [ keycode - USBKBD_KEY_1 ];
00082                 } else {
00083                         key = ( ( ( keycode - USBKBD_KEY_1 + 1 ) % 10 ) + '0' );
00084                 }
00085         } else if ( keycode <= USBKBD_KEY_SPACE ) {
00086                 /* Unmodifiable keys */
00087                 static const uint8_t unmodifable[] =
00088                         { LF, ESC, BACKSPACE, TAB, ' ' };
00089                 key = unmodifable[ keycode - USBKBD_KEY_ENTER ];
00090         } else if ( keycode <= USBKBD_KEY_SLASH ) {
00091                 /* Punctuation keys */
00092                 if ( modifiers & USBKBD_SHIFT ) {
00093                         key = "_+{}|~:\"~<>?" [ keycode - USBKBD_KEY_MINUS ];
00094                 } else {
00095                         key = "-=[]\\#;'`,./" [ keycode - USBKBD_KEY_MINUS ];
00096                 }
00097         } else if ( keycode <= USBKBD_KEY_UP ) {
00098                 /* Special keys */
00099                 static const uint16_t special[] = {
00100                         0, 0, 0, 0, 0, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
00101                         KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, KEY_IC, KEY_HOME,
00102                         KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
00103                         KEY_LEFT, KEY_DOWN, KEY_UP
00104                 };
00105                 key = special[ keycode - USBKBD_KEY_CAPS_LOCK ];
00106         } else if ( keycode <= USBKBD_KEY_PAD_ENTER ) {
00107                 /* Keypad (unaffected by Num Lock) */
00108                 key = "\0/*-+\n" [ keycode - USBKBD_KEY_NUM_LOCK ];
00109         } else if ( keycode <= USBKBD_KEY_PAD_DOT ) {
00110                 /* Keypad (affected by Num Lock) */
00111                 if ( leds & USBKBD_LED_NUM_LOCK ) {
00112                         key = "1234567890." [ keycode - USBKBD_KEY_PAD_1 ];
00113                 } else {
00114                         static const uint16_t keypad[] = {
00115                                 KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, 0,
00116                                 KEY_RIGHT, KEY_HOME, KEY_UP, KEY_PPAGE,
00117                                 KEY_IC, KEY_DC
00118                         };
00119                         key = keypad[ keycode - USBKBD_KEY_PAD_1 ];
00120                 };
00121         } else {
00122                 key = 0;
00123         }
00124 
00125         return key;
00126 }
00127 
00128 /******************************************************************************
00129  *
00130  * Keyboard buffer
00131  *
00132  ******************************************************************************
00133  */
00134 
00135 /**
00136  * Insert keypress into keyboard buffer
00137  *
00138  * @v kbd               USB keyboard
00139  * @v keycode           Keycode
00140  * @v modifiers         Modifiers
00141  */
00142 static void usbkbd_produce ( struct usb_keyboard *kbd, unsigned int keycode,
00143                              unsigned int modifiers ) {
00144         unsigned int leds = 0;
00145         unsigned int key;
00146 
00147         /* Check for LED-modifying keys */
00148         if ( keycode == USBKBD_KEY_CAPS_LOCK ) {
00149                 leds = USBKBD_LED_CAPS_LOCK;
00150         } else if ( keycode == USBKBD_KEY_NUM_LOCK ) {
00151                 leds = USBKBD_LED_NUM_LOCK;
00152         }
00153 
00154         /* Handle LED-modifying keys */
00155         if ( leds ) {
00156                 kbd->leds ^= leds;
00157                 kbd->leds_changed = 1;
00158                 return;
00159         }
00160 
00161         /* Map to iPXE key */
00162         key = usbkbd_map ( keycode, modifiers, kbd->leds );
00163 
00164         /* Do nothing if this keycode has no corresponding iPXE key */
00165         if ( ! key ) {
00166                 DBGC ( kbd, "KBD %s has no key for keycode %#02x:%#02x\n",
00167                        kbd->name, modifiers, keycode );
00168                 return;
00169         }
00170 
00171         /* Check for buffer overrun */
00172         if ( usbkbd_fill ( kbd ) >= USBKBD_BUFSIZE ) {
00173                 DBGC ( kbd, "KBD %s buffer overrun (key %#02x)\n",
00174                        kbd->name, key );
00175                 return;
00176         }
00177 
00178         /* Insert into buffer */
00179         kbd->key[ ( kbd->prod++ ) % USBKBD_BUFSIZE ] = key;
00180         DBGC2 ( kbd, "KBD %s key %#02x produced\n", kbd->name, key );
00181 }
00182 
00183 /**
00184  * Consume character from keyboard buffer
00185  *
00186  * @v kbd               USB keyboard
00187  * @ret character       Character
00188  */
00189 static unsigned int usbkbd_consume ( struct usb_keyboard *kbd ) {
00190         static char buf[] = "\x1b[xx~";
00191         char *tmp = &buf[2];
00192         unsigned int key;
00193         unsigned int character;
00194         unsigned int ansi_n;
00195         unsigned int len;
00196 
00197         /* Sanity check */
00198         assert ( usbkbd_fill ( kbd ) > 0 );
00199 
00200         /* Get current keypress */
00201         key = kbd->key[ kbd->cons % USBKBD_BUFSIZE ];
00202 
00203         /* If this is a straightforward key, just consume and return it */
00204         if ( key < KEY_MIN ) {
00205                 kbd->cons++;
00206                 DBGC2 ( kbd, "KBD %s key %#02x consumed\n", kbd->name, key );
00207                 return key;
00208         }
00209 
00210         /* Construct ANSI sequence */
00211         ansi_n = KEY_ANSI_N ( key );
00212         if ( ansi_n )
00213                 tmp += sprintf ( tmp, "%d", ansi_n );
00214         *(tmp++) = KEY_ANSI_TERMINATOR ( key );
00215         *tmp = '\0';
00216         len = ( tmp - buf );
00217         assert ( len < sizeof ( buf ) );
00218         if ( kbd->subcons == 0 ) {
00219                 DBGC2 ( kbd, "KBD %s key %#02x consumed as ^[%s\n",
00220                         kbd->name, key, &buf[1] );
00221         }
00222 
00223         /* Extract character from ANSI sequence */
00224         assert ( kbd->subcons < len );
00225         character = buf[ kbd->subcons++ ];
00226 
00227         /* Consume key if applicable */
00228         if ( kbd->subcons == len ) {
00229                 kbd->cons++;
00230                 kbd->subcons = 0;
00231         }
00232 
00233         return character;
00234 }
00235 
00236 /******************************************************************************
00237  *
00238  * Keyboard report
00239  *
00240  ******************************************************************************
00241  */
00242 
00243 /**
00244  * Check for presence of keycode in report
00245  *
00246  * @v report            Keyboard report
00247  * @v keycode           Keycode (must be non-zero)
00248  * @ret has_keycode     Keycode is present in report
00249  */
00250 static int usbkbd_has_keycode ( struct usb_keyboard_report *report,
00251                                 unsigned int keycode ) {
00252         unsigned int i;
00253 
00254         /* Check for keycode */
00255         for ( i = 0 ; i < ( sizeof ( report->keycode ) /
00256                             sizeof ( report->keycode[0] ) ) ; i++ ) {
00257                 if ( report->keycode[i] == keycode )
00258                         return keycode;
00259         }
00260 
00261         return 0;
00262 }
00263 
00264 /**
00265  * Handle keyboard report
00266  *
00267  * @v kbd               USB keyboard
00268  * @v new               New keyboard report
00269  */
00270 static void usbkbd_report ( struct usb_keyboard *kbd,
00271                             struct usb_keyboard_report *new ) {
00272         struct usb_keyboard_report *old = &kbd->report;
00273         unsigned int keycode;
00274         unsigned int i;
00275 
00276         /* Check if current key has been released */
00277         if ( kbd->keycode && ! usbkbd_has_keycode ( new, kbd->keycode ) ) {
00278                 DBGC2 ( kbd, "KBD %s keycode %#02x released\n",
00279                         kbd->name, kbd->keycode );
00280                 kbd->keycode = 0;
00281         }
00282 
00283         /* Decrement auto-repeat hold-off timer, if applicable */
00284         if ( kbd->holdoff )
00285                 kbd->holdoff--;
00286 
00287         /* Check if a new key has been pressed */
00288         for ( i = 0 ; i < ( sizeof ( new->keycode ) /
00289                             sizeof ( new->keycode[0] ) ) ; i++ ) {
00290 
00291                 /* Ignore keys present in the previous report */
00292                 keycode = new->keycode[i];
00293                 if ( ( keycode == 0 ) || usbkbd_has_keycode ( old, keycode ) )
00294                         continue;
00295                 DBGC2 ( kbd, "KBD %s keycode %#02x pressed\n",
00296                         kbd->name, keycode );
00297 
00298                 /* Insert keypress into keyboard buffer */
00299                 usbkbd_produce ( kbd, keycode, new->modifiers );
00300 
00301                 /* Record as most recent keycode */
00302                 kbd->keycode = keycode;
00303 
00304                 /* Start auto-repeat hold-off timer */
00305                 kbd->holdoff = USBKBD_HOLDOFF;
00306         }
00307 
00308         /* Insert auto-repeated keypress into keyboard buffer, if applicable */
00309         if ( kbd->keycode && ! kbd->holdoff )
00310                 usbkbd_produce ( kbd, kbd->keycode, new->modifiers );
00311 
00312         /* Record report */
00313         memcpy ( old, new, sizeof ( *old ) );
00314 }
00315 
00316 /******************************************************************************
00317  *
00318  * Interrupt endpoint
00319  *
00320  ******************************************************************************
00321  */
00322 
00323 /**
00324  * Complete interrupt transfer
00325  *
00326  * @v ep                USB endpoint
00327  * @v iobuf             I/O buffer
00328  * @v rc                Completion status code
00329  */
00330 static void usbkbd_complete ( struct usb_endpoint *ep,
00331                               struct io_buffer *iobuf, int rc ) {
00332         struct usb_keyboard *kbd = container_of ( ep, struct usb_keyboard,
00333                                                   hid.in );
00334         struct usb_keyboard_report *report;
00335 
00336         /* Ignore packets cancelled when the endpoint closes */
00337         if ( ! ep->open )
00338                 goto drop;
00339 
00340         /* Ignore packets with errors */
00341         if ( rc != 0 ) {
00342                 DBGC ( kbd, "KBD %s interrupt IN failed: %s\n",
00343                        kbd->name, strerror ( rc ) );
00344                 goto drop;
00345         }
00346 
00347         /* Ignore underlength packets */
00348         if ( iob_len ( iobuf ) < sizeof ( *report ) ) {
00349                 DBGC ( kbd, "KBD %s underlength report:\n", kbd->name );
00350                 DBGC_HDA ( kbd, 0, iobuf->data, iob_len ( iobuf ) );
00351                 goto drop;
00352         }
00353         report = iobuf->data;
00354 
00355         /* Handle keyboard report */
00356         usbkbd_report ( kbd, report );
00357 
00358  drop:
00359         /* Recycle I/O buffer */
00360         usb_recycle ( &kbd->hid.in, iobuf );
00361 }
00362 
00363 /** Interrupt endpoint operations */
00364 static struct usb_endpoint_driver_operations usbkbd_operations = {
00365         .complete = usbkbd_complete,
00366 };
00367 
00368 /******************************************************************************
00369  *
00370  * Keyboard LEDs
00371  *
00372  ******************************************************************************
00373  */
00374 
00375 /**
00376  * Set keyboard LEDs
00377  *
00378  * @v kbd               USB keyboard
00379  * @ret rc              Return status code
00380  */
00381 static int usbkbd_set_leds ( struct usb_keyboard *kbd ) {
00382         struct usb_function *func = kbd->hid.func;
00383         int rc;
00384 
00385         DBGC2 ( kbd, "KBD %s setting LEDs to %#02x\n", kbd->name, kbd->leds );
00386 
00387         /* Set keyboard LEDs */
00388         if ( ( rc = usbhid_set_report ( func->usb, func->interface[0],
00389                                         USBHID_REPORT_OUTPUT, 0, &kbd->leds,
00390                                         sizeof ( kbd->leds ) ) ) != 0 ) {
00391                 DBGC ( kbd, "KBD %s could not set LEDs to %#02x: %s\n",
00392                        kbd->name, kbd->leds, strerror ( rc ) );
00393                 return rc;
00394         }
00395 
00396         return 0;
00397 }
00398 
00399 /******************************************************************************
00400  *
00401  * USB interface
00402  *
00403  ******************************************************************************
00404  */
00405 
00406 /**
00407  * Probe device
00408  *
00409  * @v func              USB function
00410  * @v config            Configuration descriptor
00411  * @ret rc              Return status code
00412  */
00413 static int usbkbd_probe ( struct usb_function *func,
00414                           struct usb_configuration_descriptor *config ) {
00415         struct usb_device *usb = func->usb;
00416         struct usb_keyboard *kbd;
00417         int rc;
00418 
00419         /* Allocate and initialise structure */
00420         kbd = zalloc ( sizeof ( *kbd ) );
00421         if ( ! kbd ) {
00422                 rc = -ENOMEM;
00423                 goto err_alloc;
00424         }
00425         kbd->name = func->name;
00426         kbd->bus = usb->port->hub->bus;
00427         usbhid_init ( &kbd->hid, func, &usbkbd_operations, NULL );
00428         usb_refill_init ( &kbd->hid.in, 0, sizeof ( kbd->report ),
00429                           USBKBD_INTR_MAX_FILL );
00430 
00431         /* Describe USB human interface device */
00432         if ( ( rc = usbhid_describe ( &kbd->hid, config ) ) != 0 ) {
00433                 DBGC ( kbd, "KBD %s could not describe: %s\n",
00434                        kbd->name, strerror ( rc ) );
00435                 goto err_describe;
00436         }
00437         DBGC ( kbd, "KBD %s using %s (len %zd)\n",
00438                kbd->name, usb_endpoint_name ( &kbd->hid.in ), kbd->hid.in.mtu );
00439 
00440         /* Set boot protocol */
00441         if ( ( rc = usbhid_set_protocol ( usb, func->interface[0],
00442                                           USBHID_PROTOCOL_BOOT ) ) != 0 ) {
00443                 DBGC ( kbd, "KBD %s could not set boot protocol: %s\n",
00444                        kbd->name, strerror ( rc ) );
00445                 goto err_set_protocol;
00446         }
00447 
00448         /* Set idle time */
00449         if ( ( rc = usbhid_set_idle ( usb, func->interface[0], 0,
00450                                       USBKBD_IDLE_DURATION ) ) != 0 ) {
00451                 DBGC ( kbd, "KBD %s could not set idle time: %s\n",
00452                        kbd->name, strerror ( rc ) );
00453                 goto err_set_idle;
00454         }
00455 
00456         /* Open USB human interface device */
00457         if ( ( rc = usbhid_open ( &kbd->hid ) ) != 0 ) {
00458                 DBGC ( kbd, "KBD %s could not open: %s\n",
00459                        kbd->name, strerror ( rc ) );
00460                 goto err_open;
00461         }
00462 
00463         /* Add to list of USB keyboards */
00464         list_add_tail ( &kbd->list, &usb_keyboards );
00465 
00466         /* Set initial LED state */
00467         usbkbd_set_leds ( kbd );
00468 
00469         usb_func_set_drvdata ( func, kbd );
00470         return 0;
00471 
00472         usbhid_close ( &kbd->hid );
00473  err_open:
00474  err_set_idle:
00475  err_set_protocol:
00476  err_describe:
00477         free ( kbd );
00478  err_alloc:
00479         return rc;
00480 }
00481 
00482 /**
00483  * Remove device
00484  *
00485  * @v func              USB function
00486  */
00487 static void usbkbd_remove ( struct usb_function *func ) {
00488         struct usb_keyboard *kbd = usb_func_get_drvdata ( func );
00489 
00490         /* Remove from list of USB keyboards */
00491         list_del ( &kbd->list );
00492 
00493         /* Close USB human interface device */
00494         usbhid_close ( &kbd->hid );
00495 
00496         /* Free device */
00497         free ( kbd );
00498 }
00499 
00500 /** USB keyboard device IDs */
00501 static struct usb_device_id usbkbd_ids[] = {
00502         {
00503                 .name = "kbd",
00504                 .vendor = USB_ANY_ID,
00505                 .product = USB_ANY_ID,
00506         },
00507 };
00508 
00509 /** USB keyboard driver */
00510 struct usb_driver usbkbd_driver __usb_driver = {
00511         .ids = usbkbd_ids,
00512         .id_count = ( sizeof ( usbkbd_ids ) / sizeof ( usbkbd_ids[0] ) ),
00513         .class = USB_CLASS_ID ( USB_CLASS_HID, USB_SUBCLASS_HID_BOOT,
00514                                 USBKBD_PROTOCOL ),
00515         .score = USB_SCORE_NORMAL,
00516         .probe = usbkbd_probe,
00517         .remove = usbkbd_remove,
00518 };
00519 
00520 /******************************************************************************
00521  *
00522  * Console interface
00523  *
00524  ******************************************************************************
00525  */
00526 
00527 /**
00528  * Read a character from the console
00529  *
00530  * @ret character       Character read
00531  */
00532 static int usbkbd_getchar ( void ) {
00533         struct usb_keyboard *kbd;
00534 
00535         /* Consume first available key */
00536         list_for_each_entry ( kbd, &usb_keyboards, list ) {
00537                 if ( usbkbd_fill ( kbd ) )
00538                         return usbkbd_consume ( kbd );
00539         }
00540 
00541         return 0;
00542 }
00543 
00544 /**
00545  * Check for available input
00546  *
00547  * @ret is_available    Input is available
00548  */
00549 static int usbkbd_iskey ( void ) {
00550         struct usb_keyboard *kbd;
00551         unsigned int fill;
00552 
00553         /* Poll USB keyboards, refill endpoints, and set LEDs if applicable */
00554         list_for_each_entry ( kbd, &usb_keyboards, list ) {
00555 
00556                 /* Poll keyboard */
00557                 usb_poll ( kbd->bus );
00558 
00559                 /* Refill endpoints */
00560                 usb_refill ( &kbd->hid.in );
00561 
00562                 /* Update keyboard LEDs, if applicable */
00563                 if ( kbd->leds_changed ) {
00564                         usbkbd_set_leds ( kbd );
00565                         kbd->leds_changed = 0;
00566                 }
00567         }
00568 
00569         /* Check for a non-empty keyboard buffer */
00570         list_for_each_entry ( kbd, &usb_keyboards, list ) {
00571                 fill = usbkbd_fill ( kbd );
00572                 if ( fill )
00573                         return fill;
00574         }
00575 
00576         return 0;
00577 }
00578 
00579 /** USB keyboard console */
00580 struct console_driver usbkbd_console __console_driver = {
00581         .getchar = usbkbd_getchar,
00582         .iskey = usbkbd_iskey,
00583 };