diff options
author | Michael Brown <mcb30@ipxe.org> | 2015-05-11 14:57:28 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2015-05-12 15:40:20 +0100 |
commit | a8e4187c455aa89f2de7376f959a24f6c7327e11 (patch) | |
tree | a468077a2d077a8c7bd0603538499d495b11936c | |
parent | 0eaa3a34bffde2afb0b8f5f5e3b6ad6820564007 (diff) | |
download | ipxe-a8e4187c455aa89f2de7376f959a24f6c7327e11.tar.gz |
[usb] Add generic USB human interface device (HID) framework
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/drivers/usb/usbhid.c | 151 | ||||
-rw-r--r-- | src/include/ipxe/errfile.h | 1 | ||||
-rw-r--r-- | src/include/ipxe/usbhid.h | 106 |
3 files changed, 258 insertions, 0 deletions
diff --git a/src/drivers/usb/usbhid.c b/src/drivers/usb/usbhid.c new file mode 100644 index 00000000..c74535a0 --- /dev/null +++ b/src/drivers/usb/usbhid.c @@ -0,0 +1,151 @@ +/* + * 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 <string.h> +#include <errno.h> +#include <ipxe/usb.h> +#include <ipxe/usbhid.h> + +/** @file + * + * USB human interface devices (HID) + * + */ + +/** + * Open USB human interface device + * + * @v hid USB human interface device + * @ret rc Return status code + */ +int usbhid_open ( struct usb_hid *hid ) { + int rc; + + /* Open interrupt IN endpoint */ + if ( ( rc = usb_endpoint_open ( &hid->in ) ) != 0 ) { + DBGC ( hid, "HID %s could not open interrupt IN: %s\n", + hid->func->name, strerror ( rc ) ); + goto err_open_in; + } + + /* Refill interrupt IN endpoint */ + if ( ( rc = usb_refill ( &hid->in ) ) != 0 ) { + DBGC ( hid, "HID %s could not refill interrupt IN: %s\n", + hid->func->name, strerror ( rc ) ); + goto err_refill_in; + } + + /* Open interrupt OUT endpoint, if applicable */ + if ( hid->out.usb && + ( ( rc = usb_endpoint_open ( &hid->out ) ) != 0 ) ) { + DBGC ( hid, "HID %s could not open interrupt OUT: %s\n", + hid->func->name, strerror ( rc ) ); + goto err_open_out; + } + + return 0; + + usb_endpoint_close ( &hid->out ); + err_open_out: + err_refill_in: + usb_endpoint_close ( &hid->in ); + err_open_in: + return rc; +} + +/** + * Close USB human interface device + * + * @v hid USB human interface device + */ +void usbhid_close ( struct usb_hid *hid ) { + + /* Close interrupt OUT endpoint, if applicable */ + if ( hid->out.usb ) + usb_endpoint_close ( &hid->out ); + + /* Close interrupt IN endpoint */ + usb_endpoint_close ( &hid->in ); +} + +/** + * Refill USB human interface device endpoints + * + * @v hid USB human interface device + * @ret rc Return status code + */ +int usbhid_refill ( struct usb_hid *hid ) { + int rc; + + /* Refill interrupt IN endpoint */ + if ( ( rc = usb_refill ( &hid->in ) ) != 0 ) + return rc; + + /* Refill interrupt OUT endpoint, if applicable */ + if ( hid->out.usb && ( ( rc = usb_refill ( &hid->out ) ) != 0 ) ) + return rc; + + return 0; +} + +/** + * Describe USB human interface device + * + * @v hid USB human interface device + * @v config Configuration descriptor + * @ret rc Return status code + */ +int usbhid_describe ( struct usb_hid *hid, + struct usb_configuration_descriptor *config ) { + struct usb_interface_descriptor *desc; + int rc; + + /* Locate interface descriptor */ + desc = usb_interface_descriptor ( config, hid->func->interface[0], 0 ); + if ( ! desc ) { + DBGC ( hid, "HID %s has no interface descriptor\n", + hid->func->name ); + return -EINVAL; + } + + /* Describe interrupt IN endpoint */ + if ( ( rc = usb_endpoint_described ( &hid->in, config, desc, + USB_INTERRUPT_IN, 0 ) ) != 0 ) { + DBGC ( hid, "HID %s could not describe interrupt IN: %s\n", + hid->func->name, strerror ( rc ) ); + return rc; + } + + /* Describe interrupt OUT endpoint, if applicable */ + if ( hid->out.usb && + ( ( rc = usb_endpoint_described ( &hid->out, config, desc, + USB_INTERRUPT_OUT, 0 ) ) != 0 )){ + DBGC ( hid, "HID %s could not describe interrupt OUT: %s\n", + hid->func->name, strerror ( rc ) ); + return rc; + } + + return 0; +} diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 3ebd5b2a..c736c624 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -81,6 +81,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_xhci ( ERRFILE_DRIVER | 0x00090000 ) #define ERRFILE_ehci ( ERRFILE_DRIVER | 0x000a0000 ) #define ERRFILE_uhci ( ERRFILE_DRIVER | 0x000b0000 ) +#define ERRFILE_usbhid ( ERRFILE_DRIVER | 0x000c0000 ) #define ERRFILE_nvs ( ERRFILE_DRIVER | 0x00100000 ) #define ERRFILE_spi ( ERRFILE_DRIVER | 0x00110000 ) diff --git a/src/include/ipxe/usbhid.h b/src/include/ipxe/usbhid.h new file mode 100644 index 00000000..fe9d8445 --- /dev/null +++ b/src/include/ipxe/usbhid.h @@ -0,0 +1,106 @@ +#ifndef _IPXE_USBHID_H +#define _IPXE_USBHID_H + +/** @file + * + * USB human interface devices (HID) + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/usb.h> + +/** Class code for human interface devices */ +#define USB_CLASS_HID 3 + +/** Subclass code for boot devices */ +#define USB_SUBCLASS_HID_BOOT 1 + +/** Set protocol */ +#define USBHID_SET_PROTOCOL \ + ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \ + USB_REQUEST_TYPE ( 0x0b ) ) + +/** Boot protocol */ +#define USBHID_PROTOCOL_BOOT 0 + +/** Report protocol */ +#define USBHID_PROTOCOL_REPORT 1 + +/** Set idle time */ +#define USBHID_SET_IDLE \ + ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \ + USB_REQUEST_TYPE ( 0x0a ) ) + +/** A USB human interface device */ +struct usb_hid { + /** USB function */ + struct usb_function *func; + /** Interrupt IN endpoint */ + struct usb_endpoint in; + /** Interrupt OUT endpoint (optional) */ + struct usb_endpoint out; +}; + +/** + * Initialise USB human interface device + * + * @v hid USB human interface device + * @v func USB function + * @v in Interrupt IN endpoint operations + * @v out Interrupt OUT endpoint operations (or NULL) + */ +static inline __attribute__ (( always_inline )) void +usbhid_init ( struct usb_hid *hid, struct usb_function *func, + struct usb_endpoint_driver_operations *in, + struct usb_endpoint_driver_operations *out ) { + struct usb_device *usb = func->usb; + + hid->func = func; + usb_endpoint_init ( &hid->in, usb, in ); + if ( out ) + usb_endpoint_init ( &hid->out, usb, out ); +} + +/** + * Set protocol + * + * @v usb USB device + * @v interface Interface number + * @v protocol HID protocol + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +usbhid_set_protocol ( struct usb_device *usb, unsigned int interface, + unsigned int protocol ) { + + return usb_control ( usb, USBHID_SET_PROTOCOL, protocol, interface, + NULL, 0 ); +} + +/** + * Set idle time + * + * @v usb USB device + * @v interface Interface number + * @v report Report ID + * @v duration Duration (in 4ms units) + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +usbhid_set_idle ( struct usb_device *usb, unsigned int interface, + unsigned int report, unsigned int duration ) { + + return usb_control ( usb, USBHID_SET_IDLE, + ( ( duration << 8 ) | report ), + interface, NULL, 0 ); +} + +extern int usbhid_open ( struct usb_hid *hid ); +extern void usbhid_close ( struct usb_hid *hid ); +extern int usbhid_refill ( struct usb_hid *hid ); +extern int usbhid_describe ( struct usb_hid *hid, + struct usb_configuration_descriptor *config ); + +#endif /* _IPXE_USBHID_H */ |