summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/usb/usbkbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/usb/usbkbd.c')
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/usbkbd.c509
1 files changed, 0 insertions, 509 deletions
diff --git a/qemu/roms/ipxe/src/drivers/usb/usbkbd.c b/qemu/roms/ipxe/src/drivers/usb/usbkbd.c
deleted file mode 100644
index ea94f2e63..000000000
--- a/qemu/roms/ipxe/src/drivers/usb/usbkbd.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * You can also choose to distribute this program under the terms of
- * the Unmodified Binary Distribution Licence (as given in the file
- * COPYING.UBDL), provided that you have satisfied its requirements.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <ipxe/console.h>
-#include <ipxe/keys.h>
-#include <ipxe/usb.h>
-#include "usbkbd.h"
-
-/** @file
- *
- * USB keyboard driver
- *
- */
-
-/** List of USB keyboards */
-static LIST_HEAD ( usb_keyboards );
-
-/******************************************************************************
- *
- * Keyboard map
- *
- ******************************************************************************
- */
-
-/**
- * Map USB keycode to iPXE key
- *
- * @v keycode Keycode
- * @v modifiers Modifiers
- * @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 ) {
- unsigned int key;
-
- if ( keycode < USBKBD_KEY_A ) {
- /* Not keys */
- key = 0;
- } else if ( keycode <= USBKBD_KEY_Z ) {
- /* Alphabetic keys */
- key = ( keycode - USBKBD_KEY_A + 'a' );
- if ( modifiers & USBKBD_CTRL ) {
- key -= ( 'a' - CTRL_A );
- } else if ( modifiers & USBKBD_SHIFT ) {
- key -= ( 'a' - 'A' );
- }
- } else if ( keycode <= USBKBD_KEY_0 ) {
- /* Numeric key row */
- if ( modifiers & USBKBD_SHIFT ) {
- key = "!@#$%^&*()" [ keycode - USBKBD_KEY_1 ];
- } else {
- key = ( ( ( keycode - USBKBD_KEY_1 + 1 ) % 10 ) + '0' );
- }
- } else if ( keycode <= USBKBD_KEY_SPACE ) {
- /* Unmodifiable keys */
- static const uint8_t unmodifable[] =
- { LF, ESC, BACKSPACE, TAB, ' ' };
- key = unmodifable[ keycode - USBKBD_KEY_ENTER ];
- } else if ( keycode <= USBKBD_KEY_SLASH ) {
- /* Punctuation keys */
- if ( modifiers & USBKBD_SHIFT ) {
- key = "_+{}|~:\"~<>?" [ keycode - USBKBD_KEY_MINUS ];
- } else {
- key = "-=[]\\#;'`,./" [ keycode - USBKBD_KEY_MINUS ];
- }
- } else if ( keycode <= USBKBD_KEY_UP ) {
- /* Special keys */
- static const uint16_t special[] = {
- 0, 0, 0, 0, 0, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
- KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, KEY_IC, KEY_HOME,
- KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
- KEY_LEFT, KEY_DOWN, KEY_UP
- };
- key = special[ keycode - USBKBD_KEY_CAPSLOCK ];
- } else {
- key = 0;
- }
-
- return key;
-}
-
-/******************************************************************************
- *
- * Keyboard buffer
- *
- ******************************************************************************
- */
-
-/**
- * Insert keypress into keyboard buffer
- *
- * @v kbd USB keyboard
- * @v keycode Keycode
- * @v modifiers Modifiers
- */
-static void usbkbd_produce ( struct usb_keyboard *kbd, unsigned int keycode,
- unsigned int modifiers ) {
- unsigned int key;
-
- /* Map to iPXE key */
- key = usbkbd_map ( keycode, modifiers );
-
- /* Do nothing if this keycode has no corresponding iPXE key */
- if ( ! key ) {
- DBGC ( kbd, "KBD %s has no key for keycode %#02x:%#02x\n",
- kbd->name, modifiers, keycode );
- return;
- }
-
- /* Check for buffer overrun */
- if ( usbkbd_fill ( kbd ) >= USBKBD_BUFSIZE ) {
- DBGC ( kbd, "KBD %s buffer overrun (key %#02x)\n",
- kbd->name, key );
- return;
- }
-
- /* Insert into buffer */
- kbd->key[ ( kbd->prod++ ) % USBKBD_BUFSIZE ] = key;
- DBGC2 ( kbd, "KBD %s key %#02x produced\n", kbd->name, key );
-}
-
-/**
- * Consume character from keyboard buffer
- *
- * @v kbd USB keyboard
- * @ret character Character
- */
-static unsigned int usbkbd_consume ( struct usb_keyboard *kbd ) {
- static char buf[] = "\x1b[xx~";
- char *tmp = &buf[2];
- unsigned int key;
- unsigned int character;
- unsigned int ansi_n;
- unsigned int len;
-
- /* Sanity check */
- assert ( usbkbd_fill ( kbd ) > 0 );
-
- /* Get current keypress */
- key = kbd->key[ kbd->cons % USBKBD_BUFSIZE ];
-
- /* If this is a straightforward key, just consume and return it */
- if ( key < KEY_MIN ) {
- kbd->cons++;
- DBGC2 ( kbd, "KBD %s key %#02x consumed\n", kbd->name, key );
- return key;
- }
-
- /* Construct ANSI sequence */
- ansi_n = KEY_ANSI_N ( key );
- if ( ansi_n )
- tmp += sprintf ( tmp, "%d", ansi_n );
- *(tmp++) = KEY_ANSI_TERMINATOR ( key );
- *tmp = '\0';
- len = ( tmp - buf );
- assert ( len < sizeof ( buf ) );
- if ( kbd->subcons == 0 ) {
- DBGC2 ( kbd, "KBD %s key %#02x consumed as ^[%s\n",
- kbd->name, key, &buf[1] );
- }
-
- /* Extract character from ANSI sequence */
- assert ( kbd->subcons < len );
- character = buf[ kbd->subcons++ ];
-
- /* Consume key if applicable */
- if ( kbd->subcons == len ) {
- kbd->cons++;
- kbd->subcons = 0;
- }
-
- return character;
-}
-
-/******************************************************************************
- *
- * Keyboard report
- *
- ******************************************************************************
- */
-
-/**
- * Check for presence of keycode in report
- *
- * @v report Keyboard report
- * @v keycode Keycode (must be non-zero)
- * @ret has_keycode Keycode is present in report
- */
-static int usbkbd_has_keycode ( struct usb_keyboard_report *report,
- unsigned int keycode ) {
- unsigned int i;
-
- /* Check for keycode */
- for ( i = 0 ; i < ( sizeof ( report->keycode ) /
- sizeof ( report->keycode[0] ) ) ; i++ ) {
- if ( report->keycode[i] == keycode )
- return keycode;
- }
-
- return 0;
-}
-
-/**
- * Handle keyboard report
- *
- * @v kbd USB keyboard
- * @v new New keyboard report
- */
-static void usbkbd_report ( struct usb_keyboard *kbd,
- struct usb_keyboard_report *new ) {
- struct usb_keyboard_report *old = &kbd->report;
- unsigned int keycode;
- unsigned int i;
-
- /* Check if current key has been released */
- if ( kbd->keycode && ! usbkbd_has_keycode ( new, kbd->keycode ) ) {
- DBGC2 ( kbd, "KBD %s keycode %#02x released\n",
- kbd->name, kbd->keycode );
- kbd->keycode = 0;
- }
-
- /* Decrement auto-repeat hold-off timer, if applicable */
- if ( kbd->holdoff )
- kbd->holdoff--;
-
- /* Check if a new key has been pressed */
- for ( i = 0 ; i < ( sizeof ( new->keycode ) /
- sizeof ( new->keycode[0] ) ) ; i++ ) {
-
- /* Ignore keys present in the previous report */
- keycode = new->keycode[i];
- if ( ( keycode == 0 ) || usbkbd_has_keycode ( old, keycode ) )
- continue;
- DBGC2 ( kbd, "KBD %s keycode %#02x pressed\n",
- kbd->name, keycode );
-
- /* Insert keypress into keyboard buffer */
- usbkbd_produce ( kbd, keycode, new->modifiers );
-
- /* Record as most recent keycode */
- kbd->keycode = keycode;
-
- /* Start auto-repeat hold-off timer */
- kbd->holdoff = USBKBD_HOLDOFF;
- }
-
- /* Insert auto-repeated keypress into keyboard buffer, if applicable */
- if ( kbd->keycode && ! kbd->holdoff )
- usbkbd_produce ( kbd, kbd->keycode, new->modifiers );
-
- /* Record report */
- memcpy ( old, new, sizeof ( *old ) );
-}
-
-/******************************************************************************
- *
- * Interrupt endpoint
- *
- ******************************************************************************
- */
-
-/**
- * Complete interrupt transfer
- *
- * @v ep USB endpoint
- * @v iobuf I/O buffer
- * @v rc Completion status code
- */
-static void usbkbd_complete ( struct usb_endpoint *ep,
- struct io_buffer *iobuf, int rc ) {
- struct usb_keyboard *kbd = container_of ( ep, struct usb_keyboard,
- hid.in );
- struct usb_keyboard_report *report;
-
- /* Ignore packets cancelled when the endpoint closes */
- if ( ! ep->open )
- goto drop;
-
- /* Ignore packets with errors */
- if ( rc != 0 ) {
- DBGC ( kbd, "KBD %s interrupt IN failed: %s\n",
- kbd->name, strerror ( rc ) );
- goto drop;
- }
-
- /* Ignore underlength packets */
- if ( iob_len ( iobuf ) < sizeof ( *report ) ) {
- DBGC ( kbd, "KBD %s underlength report:\n", kbd->name );
- DBGC_HDA ( kbd, 0, iobuf->data, iob_len ( iobuf ) );
- goto drop;
- }
- report = iobuf->data;
-
- /* Handle keyboard report */
- usbkbd_report ( kbd, report );
-
- drop:
- /* Recycle I/O buffer */
- usb_recycle ( &kbd->hid.in, iobuf );
-}
-
-/** Interrupt endpoint operations */
-static struct usb_endpoint_driver_operations usbkbd_operations = {
- .complete = usbkbd_complete,
-};
-
-/******************************************************************************
- *
- * USB interface
- *
- ******************************************************************************
- */
-
-/**
- * Probe device
- *
- * @v func USB function
- * @v config Configuration descriptor
- * @ret rc Return status code
- */
-static int usbkbd_probe ( struct usb_function *func,
- struct usb_configuration_descriptor *config ) {
- struct usb_device *usb = func->usb;
- struct usb_keyboard *kbd;
- int rc;
-
- /* Allocate and initialise structure */
- kbd = zalloc ( sizeof ( *kbd ) );
- if ( ! kbd ) {
- rc = -ENOMEM;
- goto err_alloc;
- }
- kbd->name = func->name;
- kbd->bus = usb->port->hub->bus;
- usbhid_init ( &kbd->hid, func, &usbkbd_operations, NULL );
- usb_refill_init ( &kbd->hid.in, sizeof ( kbd->report ),
- USBKBD_INTR_MAX_FILL );
-
- /* Describe USB human interface device */
- if ( ( rc = usbhid_describe ( &kbd->hid, config ) ) != 0 ) {
- DBGC ( kbd, "KBD %s could not describe: %s\n",
- kbd->name, strerror ( rc ) );
- goto err_describe;
- }
- DBGC ( kbd, "KBD %s using %s (len %zd)\n",
- kbd->name, usb_endpoint_name ( &kbd->hid.in ), kbd->hid.in.mtu );
-
- /* Set boot protocol */
- if ( ( rc = usbhid_set_protocol ( usb, func->interface[0],
- USBHID_PROTOCOL_BOOT ) ) != 0 ) {
- DBGC ( kbd, "KBD %s could not set boot protocol: %s\n",
- kbd->name, strerror ( rc ) );
- goto err_set_protocol;
- }
-
- /* Set idle time */
- if ( ( rc = usbhid_set_idle ( usb, func->interface[0], 0,
- USBKBD_IDLE_DURATION ) ) != 0 ) {
- DBGC ( kbd, "KBD %s could not set idle time: %s\n",
- kbd->name, strerror ( rc ) );
- goto err_set_idle;
- }
-
- /* Open USB human interface device */
- if ( ( rc = usbhid_open ( &kbd->hid ) ) != 0 ) {
- DBGC ( kbd, "KBD %s could not open: %s\n",
- kbd->name, strerror ( rc ) );
- goto err_open;
- }
-
- /* Add to list of USB keyboards */
- list_add_tail ( &kbd->list, &usb_keyboards );
-
- usb_func_set_drvdata ( func, kbd );
- return 0;
-
- usbhid_close ( &kbd->hid );
- err_open:
- err_set_idle:
- err_set_protocol:
- err_describe:
- free ( kbd );
- err_alloc:
- return rc;
-}
-
-/**
- * Remove device
- *
- * @v func USB function
- */
-static void usbkbd_remove ( struct usb_function *func ) {
- struct usb_keyboard *kbd = usb_func_get_drvdata ( func );
-
- /* Remove from list of USB keyboards */
- list_del ( &kbd->list );
-
- /* Close USB human interface device */
- usbhid_close ( &kbd->hid );
-
- /* Free device */
- free ( kbd );
-}
-
-/** USB keyboard device IDs */
-static struct usb_device_id usbkbd_ids[] = {
- {
- .name = "kbd",
- .vendor = USB_ANY_ID,
- .product = USB_ANY_ID,
- .class = {
- .class = USB_CLASS_HID,
- .subclass = USB_SUBCLASS_HID_BOOT,
- .protocol = USBKBD_PROTOCOL,
- },
- },
-};
-
-/** USB keyboard driver */
-struct usb_driver usbkbd_driver __usb_driver = {
- .ids = usbkbd_ids,
- .id_count = ( sizeof ( usbkbd_ids ) / sizeof ( usbkbd_ids[0] ) ),
- .probe = usbkbd_probe,
- .remove = usbkbd_remove,
-};
-
-/******************************************************************************
- *
- * Console interface
- *
- ******************************************************************************
- */
-
-/**
- * Read a character from the console
- *
- * @ret character Character read
- */
-static int usbkbd_getchar ( void ) {
- struct usb_keyboard *kbd;
-
- /* Consume first available key */
- list_for_each_entry ( kbd, &usb_keyboards, list ) {
- if ( usbkbd_fill ( kbd ) )
- return usbkbd_consume ( kbd );
- }
-
- return 0;
-}
-
-/**
- * Check for available input
- *
- * @ret is_available Input is available
- */
-static int usbkbd_iskey ( void ) {
- struct usb_keyboard *kbd;
- unsigned int fill;
-
- /* Poll all USB keyboards and refill endpoints */
- list_for_each_entry ( kbd, &usb_keyboards, list ) {
- usb_poll ( kbd->bus );
- usb_refill ( &kbd->hid.in );
- }
-
- /* Check for a non-empty keyboard buffer */
- list_for_each_entry ( kbd, &usb_keyboards, list ) {
- fill = usbkbd_fill ( kbd );
- if ( fill )
- return fill;
- }
-
- return 0;
-}
-
-/** USB keyboard console */
-struct console_driver usbkbd_console __console_driver = {
- .getchar = usbkbd_getchar,
- .iskey = usbkbd_iskey,
-};