These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / include / ipxe / usb.h
diff --git a/qemu/roms/ipxe/src/include/ipxe/usb.h b/qemu/roms/ipxe/src/include/ipxe/usb.h
new file mode 100644 (file)
index 0000000..ab060b8
--- /dev/null
@@ -0,0 +1,1319 @@
+#ifndef _IPXE_USB_H
+#define _IPXE_USB_H
+
+/** @file
+ *
+ * Universal Serial Bus (USB)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <byteswap.h>
+#include <ipxe/list.h>
+#include <ipxe/device.h>
+#include <ipxe/process.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/tables.h>
+
+/** USB protocols */
+enum usb_protocol {
+       /** USB 2.0 */
+       USB_PROTO_2_0 = 0x0200,
+       /** USB 3.0 */
+       USB_PROTO_3_0 = 0x0300,
+       /** USB 3.1 */
+       USB_PROTO_3_1 = 0x0301,
+};
+
+/** Define a USB speed
+ *
+ * @v mantissa         Mantissa
+ * @v exponent         Exponent (in engineering terms: 1=k, 2=M, 3=G)
+ * @ret speed          USB speed
+ */
+#define USB_SPEED( mantissa, exponent ) ( (exponent << 16) | (mantissa) )
+
+/** Extract USB speed mantissa */
+#define USB_SPEED_MANTISSA(speed) ( (speed) & 0xffff )
+
+/** Extract USB speed exponent */
+#define USB_SPEED_EXPONENT(speed) ( ( (speed) >> 16 ) & 0x3 )
+
+/** USB device speeds */
+enum usb_speed {
+       /** Not connected */
+       USB_SPEED_NONE = 0,
+       /** Low speed (1.5Mbps) */
+       USB_SPEED_LOW = USB_SPEED ( 1500, 1 ),
+       /** Full speed (12Mbps) */
+       USB_SPEED_FULL = USB_SPEED ( 12, 2 ),
+       /** High speed (480Mbps) */
+       USB_SPEED_HIGH = USB_SPEED ( 480, 2 ),
+       /** Super speed (5Gbps) */
+       USB_SPEED_SUPER = USB_SPEED ( 5, 3 ),
+};
+
+/** USB packet IDs */
+enum usb_pid {
+       /** IN PID */
+       USB_PID_IN = 0x69,
+       /** OUT PID */
+       USB_PID_OUT = 0xe1,
+       /** SETUP PID */
+       USB_PID_SETUP = 0x2d,
+};
+
+/** A USB setup data packet */
+struct usb_setup_packet {
+       /** Request */
+       uint16_t request;
+       /** Value paramer */
+       uint16_t value;
+       /** Index parameter */
+       uint16_t index;
+       /** Length of data stage */
+       uint16_t len;
+} __attribute__ (( packed ));
+
+/** Data transfer is from host to device */
+#define USB_DIR_OUT ( 0 << 7 )
+
+/** Data transfer is from device to host */
+#define USB_DIR_IN ( 1 << 7 )
+
+/** Standard request type */
+#define USB_TYPE_STANDARD ( 0 << 5 )
+
+/** Class-specific request type */
+#define USB_TYPE_CLASS ( 1 << 5 )
+
+/** Vendor-specific request type */
+#define USB_TYPE_VENDOR ( 2 << 5 )
+
+/** Request recipient is the device */
+#define USB_RECIP_DEVICE ( 0 << 0 )
+
+/** Request recipient is an interface */
+#define USB_RECIP_INTERFACE ( 1 << 0 )
+
+/** Request recipient is an endpoint */
+#define USB_RECIP_ENDPOINT ( 2 << 0 )
+
+/** Construct USB request type */
+#define USB_REQUEST_TYPE(type) ( (type) << 8 )
+
+/** Get status */
+#define USB_GET_STATUS ( USB_DIR_IN | USB_REQUEST_TYPE ( 0 ) )
+
+/** Clear feature */
+#define USB_CLEAR_FEATURE ( USB_DIR_OUT | USB_REQUEST_TYPE ( 1 ) )
+
+/** Set feature */
+#define USB_SET_FEATURE ( USB_DIR_OUT | USB_REQUEST_TYPE ( 3 ) )
+
+/** Set address */
+#define USB_SET_ADDRESS ( USB_DIR_OUT | USB_REQUEST_TYPE ( 5 ) )
+
+/** Get descriptor */
+#define USB_GET_DESCRIPTOR ( USB_DIR_IN | USB_REQUEST_TYPE ( 6 ) )
+
+/** Set descriptor */
+#define USB_SET_DESCRIPTOR ( USB_DIR_OUT | USB_REQUEST_TYPE ( 7 ) )
+
+/** Get configuration */
+#define USB_GET_CONFIGURATION ( USB_DIR_IN | USB_REQUEST_TYPE ( 8 ) )
+
+/** Set configuration */
+#define USB_SET_CONFIGURATION ( USB_DIR_OUT | USB_REQUEST_TYPE ( 9 ) )
+
+/** Get interface */
+#define USB_GET_INTERFACE \
+       ( USB_DIR_IN | USB_RECIP_INTERFACE | USB_REQUEST_TYPE ( 10 ) )
+
+/** Set interface */
+#define USB_SET_INTERFACE \
+       ( USB_DIR_OUT | USB_RECIP_INTERFACE | USB_REQUEST_TYPE ( 11 ) )
+
+/** Endpoint halt feature */
+#define USB_ENDPOINT_HALT 0
+
+/** A USB class code tuple */
+struct usb_class {
+       /** Class code */
+       uint8_t class;
+       /** Subclass code */
+       uint8_t subclass;
+       /** Protocol code */
+       uint8_t protocol;
+} __attribute__ (( packed ));
+
+/** Class code for USB hubs */
+#define USB_CLASS_HUB 9
+
+/** A USB descriptor header */
+struct usb_descriptor_header {
+       /** Length of descriptor */
+       uint8_t len;
+       /** Descriptor type */
+       uint8_t type;
+} __attribute__ (( packed ));
+
+/** A USB device descriptor */
+struct usb_device_descriptor {
+       /** Descriptor header */
+       struct usb_descriptor_header header;
+       /** USB specification release number in BCD */
+       uint16_t protocol;
+       /** Device class */
+       struct usb_class class;
+       /** Maximum packet size for endpoint zero */
+       uint8_t mtu;
+       /** Vendor ID */
+       uint16_t vendor;
+       /** Product ID */
+       uint16_t product;
+       /** Device release number in BCD */
+       uint16_t release;
+       /** Manufacturer string */
+       uint8_t manufacturer;
+       /** Product string */
+       uint8_t name;
+       /** Serial number string */
+       uint8_t serial;
+       /** Number of possible configurations */
+       uint8_t configurations;
+} __attribute__ (( packed ));
+
+/** A USB device descriptor */
+#define USB_DEVICE_DESCRIPTOR 1
+
+/** A USB configuration descriptor */
+struct usb_configuration_descriptor {
+       /** Descriptor header */
+       struct usb_descriptor_header header;
+       /** Total length */
+       uint16_t len;
+       /** Number of interfaces */
+       uint8_t interfaces;
+       /** Configuration value */
+       uint8_t config;
+       /** Configuration string */
+       uint8_t name;
+       /** Attributes */
+       uint8_t attributes;
+       /** Maximum power consumption */
+       uint8_t power;
+} __attribute__ (( packed ));
+
+/** A USB configuration descriptor */
+#define USB_CONFIGURATION_DESCRIPTOR 2
+
+/** A USB string descriptor */
+struct usb_string_descriptor {
+       /** Descriptor header */
+       struct usb_descriptor_header header;
+       /** String */
+       char string[0];
+} __attribute__ (( packed ));
+
+/** A USB string descriptor */
+#define USB_STRING_DESCRIPTOR 3
+
+/** A USB interface descriptor */
+struct usb_interface_descriptor {
+       /** Descriptor header */
+       struct usb_descriptor_header header;
+       /** Interface number */
+       uint8_t interface;
+       /** Alternate setting */
+       uint8_t alternate;
+       /** Number of endpoints */
+       uint8_t endpoints;
+       /** Interface class */
+       struct usb_class class;
+       /** Interface name */
+       uint8_t name;
+} __attribute__ (( packed ));
+
+/** A USB interface descriptor */
+#define USB_INTERFACE_DESCRIPTOR 4
+
+/** A USB endpoint descriptor */
+struct usb_endpoint_descriptor {
+       /** Descriptor header */
+       struct usb_descriptor_header header;
+       /** Endpoint address */
+       uint8_t endpoint;
+       /** Attributes */
+       uint8_t attributes;
+       /** Maximum packet size and burst size */
+       uint16_t sizes;
+       /** Polling interval */
+       uint8_t interval;
+} __attribute__ (( packed ));
+
+/** A USB endpoint descriptor */
+#define USB_ENDPOINT_DESCRIPTOR 5
+
+/** Endpoint attribute transfer type mask */
+#define USB_ENDPOINT_ATTR_TYPE_MASK 0x03
+
+/** Endpoint periodic type */
+#define USB_ENDPOINT_ATTR_PERIODIC 0x01
+
+/** Control endpoint transfer type */
+#define USB_ENDPOINT_ATTR_CONTROL 0x00
+
+/** Bulk endpoint transfer type */
+#define USB_ENDPOINT_ATTR_BULK 0x02
+
+/** Interrupt endpoint transfer type */
+#define USB_ENDPOINT_ATTR_INTERRUPT 0x03
+
+/** Bulk OUT endpoint (internal) type */
+#define USB_BULK_OUT ( USB_ENDPOINT_ATTR_BULK | USB_DIR_OUT )
+
+/** Bulk IN endpoint (internal) type */
+#define USB_BULK_IN ( USB_ENDPOINT_ATTR_BULK | USB_DIR_IN )
+
+/** Interrupt IN endpoint (internal) type */
+#define USB_INTERRUPT_IN ( USB_ENDPOINT_ATTR_INTERRUPT | USB_DIR_IN )
+
+/** Interrupt OUT endpoint (internal) type */
+#define USB_INTERRUPT_OUT ( USB_ENDPOINT_ATTR_INTERRUPT | USB_DIR_OUT )
+
+/** USB endpoint MTU */
+#define USB_ENDPOINT_MTU(sizes) ( ( (sizes) >> 0 ) & 0x07ff )
+
+/** USB endpoint maximum burst size */
+#define USB_ENDPOINT_BURST(sizes) ( ( (sizes) >> 11 ) & 0x0003 )
+
+/** A USB endpoint companion descriptor */
+struct usb_endpoint_companion_descriptor {
+       /** Descriptor header */
+       struct usb_descriptor_header header;
+       /** Maximum burst size */
+       uint8_t burst;
+       /** Extended attributes */
+       uint8_t extended;
+       /** Number of bytes per service interval */
+       uint16_t periodic;
+} __attribute__ (( packed ));
+
+/** A USB endpoint companion descriptor */
+#define USB_ENDPOINT_COMPANION_DESCRIPTOR 48
+
+/** A USB interface association descriptor */
+struct usb_interface_association_descriptor {
+       /** Descriptor header */
+       struct usb_descriptor_header header;
+       /** First interface number */
+       uint8_t first;
+       /** Interface count */
+       uint8_t count;
+       /** Association class */
+       struct usb_class class;
+       /** Association name */
+       uint8_t name;
+} __attribute__ (( packed ));
+
+/** A USB interface association descriptor */
+#define USB_INTERFACE_ASSOCIATION_DESCRIPTOR 11
+
+/** A class-specific interface descriptor */
+#define USB_CS_INTERFACE_DESCRIPTOR 36
+
+/** A class-specific endpoint descriptor */
+#define USB_CS_ENDPOINT_DESCRIPTOR 37
+
+/**
+ * Get next USB descriptor
+ *
+ * @v desc             USB descriptor header
+ * @ret next           Next USB descriptor header
+ */
+static inline __attribute__ (( always_inline )) struct usb_descriptor_header *
+usb_next_descriptor ( struct usb_descriptor_header *desc ) {
+
+       return ( ( ( void * ) desc ) + desc->len );
+}
+
+/**
+ * Check that descriptor lies within a configuration descriptor
+ *
+ * @v config           Configuration descriptor
+ * @v desc             Descriptor header
+ * @v is_within                Descriptor is within the configuration descriptor
+ */
+static inline __attribute__ (( always_inline )) int
+usb_is_within_config ( struct usb_configuration_descriptor *config,
+                      struct usb_descriptor_header *desc ) {
+       struct usb_descriptor_header *end =
+               ( ( ( void * ) config ) + le16_to_cpu ( config->len ) );
+
+       /* Check that descriptor starts within the configuration
+        * descriptor, and that the length does not exceed the
+        * configuration descriptor.  This relies on the fact that
+        * usb_next_descriptor() needs to access only the first byte
+        * of the descriptor in order to determine the length.
+        */
+       return ( ( desc < end ) && ( usb_next_descriptor ( desc ) <= end ) );
+}
+
+/** Iterate over all configuration descriptors */
+#define for_each_config_descriptor( desc, config )                        \
+       for ( desc = container_of ( &(config)->header,                     \
+                                   typeof ( *desc ), header ) ;           \
+             usb_is_within_config ( (config), &desc->header ) ;           \
+             desc = container_of ( usb_next_descriptor ( &desc->header ), \
+                                   typeof ( *desc ), header ) )
+
+/** Iterate over all configuration descriptors within an interface descriptor */
+#define for_each_interface_descriptor( desc, config, interface )          \
+       for ( desc = container_of ( usb_next_descriptor ( &(interface)->   \
+                                                         header ),        \
+                                   typeof ( *desc ), header ) ;           \
+             ( usb_is_within_config ( (config), &desc->header ) &&        \
+               ( desc->header.type != USB_INTERFACE_DESCRIPTOR ) ) ;      \
+             desc = container_of ( usb_next_descriptor ( &desc->header ), \
+                                   typeof ( *desc ), header ) )
+
+/** A USB endpoint */
+struct usb_endpoint {
+       /** USB device */
+       struct usb_device *usb;
+       /** Endpoint address */
+       unsigned int address;
+       /** Attributes */
+       unsigned int attributes;
+       /** Maximum transfer size */
+       size_t mtu;
+       /** Maximum burst size */
+       unsigned int burst;
+       /** Interval (in microframes) */
+       unsigned int interval;
+
+       /** Endpoint is open */
+       int open;
+       /** Buffer fill level */
+       unsigned int fill;
+
+       /** List of halted endpoints */
+       struct list_head halted;
+
+       /** Host controller operations */
+       struct usb_endpoint_host_operations *host;
+       /** Host controller private data */
+       void *priv;
+       /** Driver operations */
+       struct usb_endpoint_driver_operations *driver;
+
+       /** Recycled I/O buffer list */
+       struct list_head recycled;
+       /** Refill buffer length */
+       size_t len;
+       /** Maximum fill level */
+       unsigned int max;
+};
+
+/** USB endpoint host controller operations */
+struct usb_endpoint_host_operations {
+       /** Open endpoint
+        *
+        * @v ep                USB endpoint
+        * @ret rc              Return status code
+        */
+       int ( * open ) ( struct usb_endpoint *ep );
+       /** Close endpoint
+        *
+        * @v ep                USB endpoint
+        */
+       void ( * close ) ( struct usb_endpoint *ep );
+       /**
+        * Reset endpoint
+        *
+        * @v ep                USB endpoint
+        * @ret rc              Return status code
+        */
+       int ( * reset ) ( struct usb_endpoint *ep );
+       /** Update MTU
+        *
+        * @v ep                USB endpoint
+        * @ret rc              Return status code
+        */
+       int ( * mtu ) ( struct usb_endpoint *ep );
+       /** Enqueue message transfer
+        *
+        * @v ep                USB endpoint
+        * @v iobuf             I/O buffer
+        * @ret rc              Return status code
+        */
+       int ( * message ) ( struct usb_endpoint *ep,
+                           struct io_buffer *iobuf );
+       /** Enqueue stream transfer
+        *
+        * @v ep                USB endpoint
+        * @v iobuf             I/O buffer
+        * @v terminate         Terminate using a short packet
+        * @ret rc              Return status code
+        */
+       int ( * stream ) ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+                          int terminate );
+};
+
+/** USB endpoint driver operations */
+struct usb_endpoint_driver_operations {
+       /** Complete transfer
+        *
+        * @v ep                USB endpoint
+        * @v iobuf             I/O buffer
+        * @v rc                Completion status code
+        */
+       void ( * complete ) ( struct usb_endpoint *ep,
+                             struct io_buffer *iobuf, int rc );
+};
+
+/** Control endpoint address */
+#define USB_EP0_ADDRESS 0x00
+
+/** Control endpoint attributes */
+#define USB_EP0_ATTRIBUTES 0x00
+
+/** Calculate default MTU based on device speed
+ *
+ * @v speed            Device speed
+ * @ret mtu            Default MTU
+ */
+#define USB_EP0_DEFAULT_MTU(speed)                     \
+       ( ( (speed) >= USB_SPEED_SUPER ) ? 512 :        \
+         ( ( (speed) >= USB_SPEED_FULL ) ? 64 : 8 ) )
+
+/** Control endpoint maximum burst size */
+#define USB_EP0_BURST 0
+
+/** Control endpoint interval */
+#define USB_EP0_INTERVAL 0
+
+/** Maximum endpoint number */
+#define USB_ENDPOINT_MAX 0x0f
+
+/** Endpoint direction is in */
+#define USB_ENDPOINT_IN 0x80
+
+/** Construct endpoint index from endpoint address */
+#define USB_ENDPOINT_IDX(address)                                      \
+       ( ( (address) & USB_ENDPOINT_MAX ) |                            \
+         ( ( (address) & USB_ENDPOINT_IN ) >> 3 ) )
+
+/**
+ * Initialise USB endpoint
+ *
+ * @v ep               USB endpoint
+ * @v usb              USB device
+ * @v driver           Driver operations
+ */
+static inline __attribute__ (( always_inline )) void
+usb_endpoint_init ( struct usb_endpoint *ep, struct usb_device *usb,
+                   struct usb_endpoint_driver_operations *driver ) {
+
+       ep->usb = usb;
+       ep->driver = driver;
+}
+
+/**
+ * Describe USB endpoint
+ *
+ * @v ep               USB endpoint
+ * @v address          Endpoint address
+ * @v attributes       Attributes
+ * @v mtu              Maximum packet size
+ * @v burst            Maximum burst size
+ * @v interval         Interval (in microframes)
+ */
+static inline __attribute__ (( always_inline )) void
+usb_endpoint_describe ( struct usb_endpoint *ep, unsigned int address,
+                       unsigned int attributes, size_t mtu,
+                       unsigned int burst, unsigned int interval ) {
+
+       ep->address = address;
+       ep->attributes = attributes;
+       ep->mtu = mtu;
+       ep->burst = burst;
+       ep->interval = interval;
+}
+
+/**
+ * Set USB endpoint host controller private data
+ *
+ * @v ep               USB endpoint
+ * @v priv             Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_endpoint_set_hostdata ( struct usb_endpoint *ep, void *priv ) {
+       ep->priv = priv;
+}
+
+/**
+ * Get USB endpoint host controller private data
+ *
+ * @v ep               USB endpoint
+ * @ret priv           Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_endpoint_get_hostdata ( struct usb_endpoint *ep ) {
+       return ep->priv;
+}
+
+extern const char * usb_endpoint_name ( struct usb_endpoint *ep );
+extern int
+usb_endpoint_described ( struct usb_endpoint *ep,
+                        struct usb_configuration_descriptor *config,
+                        struct usb_interface_descriptor *interface,
+                        unsigned int type, unsigned int index );
+extern int usb_endpoint_open ( struct usb_endpoint *ep );
+extern void usb_endpoint_close ( struct usb_endpoint *ep );
+extern int usb_message ( struct usb_endpoint *ep, unsigned int request,
+                        unsigned int value, unsigned int index,
+                        struct io_buffer *iobuf );
+extern int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf,
+                       int terminate );
+extern void usb_complete_err ( struct usb_endpoint *ep,
+                              struct io_buffer *iobuf, int rc );
+
+/**
+ * Initialise USB endpoint refill
+ *
+ * @v ep               USB endpoint
+ * @v len              Refill buffer length (or zero to use endpoint's MTU)
+ * @v max              Maximum fill level
+ */
+static inline __attribute__ (( always_inline )) void
+usb_refill_init ( struct usb_endpoint *ep, size_t len, unsigned int max ) {
+
+       INIT_LIST_HEAD ( &ep->recycled );
+       ep->len = len;
+       ep->max = max;
+}
+
+/**
+ * Recycle I/O buffer
+ *
+ * @v ep               USB endpoint
+ * @v iobuf            I/O buffer
+ */
+static inline __attribute__ (( always_inline )) void
+usb_recycle ( struct usb_endpoint *ep, struct io_buffer *iobuf ) {
+
+       list_add_tail ( &iobuf->list, &ep->recycled );
+}
+
+extern int usb_prefill ( struct usb_endpoint *ep );
+extern int usb_refill ( struct usb_endpoint *ep );
+extern void usb_flush ( struct usb_endpoint *ep );
+
+/**
+ * A USB function
+ *
+ * A USB function represents an association of interfaces within a USB
+ * device.
+ */
+struct usb_function {
+       /** Name */
+       const char *name;
+       /** USB device */
+       struct usb_device *usb;
+       /** Class */
+       struct usb_class class;
+       /** Number of interfaces */
+       unsigned int count;
+       /** Generic device */
+       struct device dev;
+       /** List of functions within this USB device */
+       struct list_head list;
+
+       /** Driver */
+       struct usb_driver *driver;
+       /** Driver private data */
+       void *priv;
+
+       /** List of interface numbers
+        *
+        * This must be the last field within the structure.
+        */
+       uint8_t interface[0];
+};
+
+/**
+ * Set USB function driver private data
+ *
+ * @v func             USB function
+ * @v priv             Driver private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_func_set_drvdata ( struct usb_function *func, void *priv ) {
+       func->priv = priv;
+}
+
+/**
+ * Get USB function driver private data
+ *
+ * @v function         USB function
+ * @ret priv           Driver private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_func_get_drvdata ( struct usb_function *func ) {
+       return func->priv;
+}
+
+/** A USB device */
+struct usb_device {
+       /** Name */
+       char name[32];
+       /** USB port */
+       struct usb_port *port;
+       /** List of devices on this bus */
+       struct list_head list;
+       /** Device address, if assigned */
+       unsigned int address;
+       /** Device descriptor */
+       struct usb_device_descriptor device;
+       /** List of functions */
+       struct list_head functions;
+
+       /** Host controller operations */
+       struct usb_device_host_operations *host;
+       /** Host controller private data */
+       void *priv;
+
+       /** Endpoint list */
+       struct usb_endpoint *ep[32];
+
+       /** Control endpoint */
+       struct usb_endpoint control;
+       /** Completed control transfers */
+       struct list_head complete;
+};
+
+/** USB device host controller operations */
+struct usb_device_host_operations {
+       /** Open device
+        *
+        * @v usb               USB device
+        * @ret rc              Return status code
+        */
+       int ( * open ) ( struct usb_device *usb );
+       /** Close device
+        *
+        * @v usb               USB device
+        */
+       void ( * close ) ( struct usb_device *usb );
+       /** Assign device address
+        *
+        * @v usb               USB device
+        * @ret rc              Return status code
+        */
+       int ( * address ) ( struct usb_device *usb );
+};
+
+/**
+ * Set USB device host controller private data
+ *
+ * @v usb              USB device
+ * @v priv             Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_set_hostdata ( struct usb_device *usb, void *priv ) {
+       usb->priv = priv;
+}
+
+/**
+ * Get USB device host controller private data
+ *
+ * @v usb              USB device
+ * @ret priv           Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_get_hostdata ( struct usb_device *usb ) {
+       return usb->priv;
+}
+
+/**
+ * Get USB endpoint
+ *
+ * @v usb              USB device
+ * @v address          Endpoint address
+ * @ret ep             USB endpoint, or NULL if not opened
+ */
+static inline struct usb_endpoint * usb_endpoint ( struct usb_device *usb,
+                                                  unsigned int address ) {
+
+       return usb->ep[ USB_ENDPOINT_IDX ( address ) ];
+}
+
+/** A USB port */
+struct usb_port {
+       /** USB hub */
+       struct usb_hub *hub;
+       /** Port address */
+       unsigned int address;
+       /** Port protocol */
+       unsigned int protocol;
+       /** Port speed */
+       unsigned int speed;
+       /** Port disconnection has been detected
+        *
+        * This should be set whenever the underlying hardware reports
+        * a connection status change.
+        */
+       int disconnected;
+       /** Port has an attached device */
+       int attached;
+       /** Currently attached device (if in use)
+        *
+        * Note that this field will be NULL if the attached device
+        * has been freed (e.g. because there were no drivers found).
+        */
+       struct usb_device *usb;
+       /** List of changed ports */
+       struct list_head changed;
+};
+
+/** A USB hub */
+struct usb_hub {
+       /** Name */
+       const char *name;
+       /** USB bus */
+       struct usb_bus *bus;
+       /** Underlying USB device, if any */
+       struct usb_device *usb;
+       /** Hub protocol */
+       unsigned int protocol;
+       /** Number of ports */
+       unsigned int ports;
+
+       /** List of hubs */
+       struct list_head list;
+
+       /** Host controller operations */
+       struct usb_hub_host_operations *host;
+       /** Driver operations */
+       struct usb_hub_driver_operations *driver;
+       /** Driver private data */
+       void *priv;
+
+       /** Port list
+        *
+        * This must be the last field within the structure.
+        */
+       struct usb_port port[0];
+};
+
+/** USB hub host controller operations */
+struct usb_hub_host_operations {
+       /** Open hub
+        *
+        * @v hub               USB hub
+        * @ret rc              Return status code
+        */
+       int ( * open ) ( struct usb_hub *hub );
+       /** Close hub
+        *
+        * @v hub               USB hub
+        */
+       void ( * close ) ( struct usb_hub *hub );
+};
+
+/** USB hub driver operations */
+struct usb_hub_driver_operations {
+       /** Open hub
+        *
+        * @v hub               USB hub
+        * @ret rc              Return status code
+        */
+       int ( * open ) ( struct usb_hub *hub );
+       /** Close hub
+        *
+        * @v hub               USB hub
+        */
+       void ( * close ) ( struct usb_hub *hub );
+       /** Enable port
+        *
+        * @v hub               USB hub
+        * @v port              USB port
+        * @ret rc              Return status code
+        */
+       int ( * enable ) ( struct usb_hub *hub, struct usb_port *port );
+       /** Disable port
+        *
+        * @v hub               USB hub
+        * @v port              USB port
+        * @ret rc              Return status code
+        */
+       int ( * disable ) ( struct usb_hub *hub, struct usb_port *port );
+       /** Update port speed
+        *
+        * @v hub               USB hub
+        * @v port              USB port
+        * @ret rc              Return status code
+        */
+       int ( * speed ) ( struct usb_hub *hub, struct usb_port *port );
+       /** Clear transaction translator buffer
+        *
+        * @v hub               USB hub
+        * @v port              USB port
+        * @v ep                USB endpoint
+        * @ret rc              Return status code
+        */
+       int ( * clear_tt ) ( struct usb_hub *hub, struct usb_port *port,
+                            struct usb_endpoint *ep );
+};
+
+/**
+ * Set USB hub driver private data
+ *
+ * @v hub              USB hub
+ * @v priv             Driver private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_hub_set_drvdata ( struct usb_hub *hub, void *priv ) {
+       hub->priv = priv;
+}
+
+/**
+ * Get USB hub driver private data
+ *
+ * @v hub              USB hub
+ * @ret priv           Driver private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_hub_get_drvdata ( struct usb_hub *hub ) {
+       return hub->priv;
+}
+
+/**
+ * Get USB port
+ *
+ * @v hub              USB hub
+ * @v address          Port address
+ * @ret port           USB port
+ */
+static inline __attribute__ (( always_inline )) struct usb_port *
+usb_port ( struct usb_hub *hub, unsigned int address ) {
+
+       return &hub->port[ address - 1 ];
+}
+
+/** A USB bus */
+struct usb_bus {
+       /** Name */
+       const char *name;
+       /** Underlying hardware device */
+       struct device *dev;
+       /** Host controller operations set */
+       struct usb_host_operations *op;
+
+       /** Largest transfer allowed on the bus */
+       size_t mtu;
+       /** Address in-use mask
+        *
+        * This is used only by buses which perform manual address
+        * assignment.  USB allows for addresses in the range [1,127].
+        * We use a simple bitmask which restricts us to the range
+        * [1,64]; this is unlikely to be a problem in practice.  For
+        * comparison: controllers which perform autonomous address
+        * assignment (such as xHCI) typically allow for only 32
+        * devices per bus anyway.
+        */
+       unsigned long long addresses;
+
+       /** Root hub */
+       struct usb_hub *hub;
+
+       /** List of USB buses */
+       struct list_head list;
+       /** List of devices */
+       struct list_head devices;
+       /** List of hubs */
+       struct list_head hubs;
+
+       /** Host controller operations */
+       struct usb_bus_host_operations *host;
+       /** Host controller private data */
+       void *priv;
+};
+
+/** USB bus host controller operations */
+struct usb_bus_host_operations {
+       /** Open bus
+        *
+        * @v bus               USB bus
+        * @ret rc              Return status code
+        */
+       int ( * open ) ( struct usb_bus *bus );
+       /** Close bus
+        *
+        * @v bus               USB bus
+        */
+       void ( * close ) ( struct usb_bus *bus );
+       /** Poll bus
+        *
+        * @v bus               USB bus
+        */
+       void ( * poll ) ( struct usb_bus *bus );
+};
+
+/** USB host controller operations */
+struct usb_host_operations {
+       /** Endpoint operations */
+       struct usb_endpoint_host_operations endpoint;
+       /** Device operations */
+       struct usb_device_host_operations device;
+       /** Bus operations */
+       struct usb_bus_host_operations bus;
+       /** Hub operations */
+       struct usb_hub_host_operations hub;
+       /** Root hub operations */
+       struct usb_hub_driver_operations root;
+};
+
+/**
+ * Set USB bus host controller private data
+ *
+ * @v bus              USB bus
+ * @v priv             Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void
+usb_bus_set_hostdata ( struct usb_bus *bus, void *priv ) {
+       bus->priv = priv;
+}
+
+/**
+ * Get USB bus host controller private data
+ *
+ * @v bus              USB bus
+ * @ret priv           Host controller private data
+ */
+static inline __attribute__ (( always_inline )) void *
+usb_bus_get_hostdata ( struct usb_bus *bus ) {
+       return bus->priv;
+}
+
+/**
+ * Poll USB bus
+ *
+ * @v bus              USB bus
+ */
+static inline __attribute__ (( always_inline )) void
+usb_poll ( struct usb_bus *bus ) {
+       bus->host->poll ( bus );
+}
+
+/** Iterate over all USB buses */
+#define for_each_usb_bus( bus ) \
+       list_for_each_entry ( (bus), &usb_buses, list )
+
+/**
+ * Complete transfer (without error)
+ *
+ * @v ep               USB endpoint
+ * @v iobuf            I/O buffer
+ */
+static inline __attribute__ (( always_inline )) void
+usb_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf ) {
+       usb_complete_err ( ep, iobuf, 0 );
+}
+
+extern int usb_control ( struct usb_device *usb, unsigned int request,
+                        unsigned int value, unsigned int index, void *data,
+                        size_t len );
+extern int usb_get_string_descriptor ( struct usb_device *usb,
+                                      unsigned int index,
+                                      unsigned int language,
+                                      char *buf, size_t len );
+
+/**
+ * Get status
+ *
+ * @v usb              USB device
+ * @v type             Request type
+ * @v index            Target index
+ * @v data             Status to fill in
+ * @v len              Length of status descriptor
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_status ( struct usb_device *usb, unsigned int type, unsigned int index,
+                void *data, size_t len ) {
+
+       return usb_control ( usb, ( USB_GET_STATUS | type ), 0, index,
+                            data, len );
+}
+
+/**
+ * Clear feature
+ *
+ * @v usb              USB device
+ * @v type             Request type
+ * @v feature          Feature selector
+ * @v index            Target index
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_clear_feature ( struct usb_device *usb, unsigned int type,
+                   unsigned int feature, unsigned int index ) {
+
+       return usb_control ( usb, ( USB_CLEAR_FEATURE | type ),
+                            feature, index, NULL, 0 );
+}
+
+/**
+ * Set feature
+ *
+ * @v usb              USB device
+ * @v type             Request type
+ * @v feature          Feature selector
+ * @v index            Target index
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_feature ( struct usb_device *usb, unsigned int type,
+                 unsigned int feature, unsigned int index ) {
+
+       return usb_control ( usb, ( USB_SET_FEATURE | type ),
+                            feature, index, NULL, 0 );
+}
+
+/**
+ * Set address
+ *
+ * @v usb              USB device
+ * @v address          Device address
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_address ( struct usb_device *usb, unsigned int address ) {
+
+       return usb_control ( usb, USB_SET_ADDRESS, address, 0, NULL, 0 );
+}
+
+/**
+ * Get USB descriptor
+ *
+ * @v usb              USB device
+ * @v type             Request type
+ * @v desc             Descriptor type
+ * @v index            Descriptor index
+ * @v language         Language ID (for string descriptors)
+ * @v data             Descriptor to fill in
+ * @v len              Maximum length of descriptor
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_descriptor ( struct usb_device *usb, unsigned int type,
+                    unsigned int desc, unsigned int index,
+                    unsigned int language, struct usb_descriptor_header *data,
+                    size_t len ) {
+
+       return usb_control ( usb, ( USB_GET_DESCRIPTOR | type ),
+                            ( ( desc << 8 ) | index ), language, data, len );
+}
+
+/**
+ * Get first part of USB device descriptor (up to and including MTU)
+ *
+ * @v usb              USB device
+ * @v data             Device descriptor to (partially) fill in
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_mtu ( struct usb_device *usb, struct usb_device_descriptor *data ) {
+
+       return usb_get_descriptor ( usb, 0, USB_DEVICE_DESCRIPTOR, 0, 0,
+                                   &data->header,
+                                   ( offsetof ( typeof ( *data ), mtu ) +
+                                     sizeof ( data->mtu ) ) );
+}
+
+/**
+ * Get USB device descriptor
+ *
+ * @v usb              USB device
+ * @v data             Device descriptor to fill in
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_get_device_descriptor ( struct usb_device *usb,
+                           struct usb_device_descriptor *data ) {
+
+       return usb_get_descriptor ( usb, 0, USB_DEVICE_DESCRIPTOR, 0, 0,
+                                   &data->header, sizeof ( *data ) );
+}
+
+/**
+ * Get USB configuration descriptor
+ *
+ * @v usb              USB device
+ * @v index            Configuration index
+ * @v data             Configuration descriptor to fill in
+ * @ret rc             Return status code
+ */
+static inline __attribute (( always_inline )) int
+usb_get_config_descriptor ( struct usb_device *usb, unsigned int index,
+                           struct usb_configuration_descriptor *data,
+                           size_t len ) {
+
+       return usb_get_descriptor ( usb, 0, USB_CONFIGURATION_DESCRIPTOR, index,
+                                   0, &data->header, len );
+}
+
+/**
+ * Set USB configuration
+ *
+ * @v usb              USB device
+ * @v index            Configuration index
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_configuration ( struct usb_device *usb, unsigned int index ) {
+
+       return usb_control ( usb, USB_SET_CONFIGURATION, index, 0, NULL, 0 );
+}
+
+/**
+ * Set USB interface alternate setting
+ *
+ * @v usb              USB device
+ * @v interface                Interface number
+ * @v alternate                Alternate setting
+ * @ret rc             Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_set_interface ( struct usb_device *usb, unsigned int interface,
+                   unsigned int alternate ) {
+
+       return usb_control ( usb, USB_SET_INTERFACE, alternate, interface,
+                            NULL, 0 );
+}
+
+extern struct list_head usb_buses;
+
+extern struct usb_interface_descriptor *
+usb_interface_descriptor ( struct usb_configuration_descriptor *config,
+                          unsigned int interface, unsigned int alternate );
+extern struct usb_endpoint_descriptor *
+usb_endpoint_descriptor ( struct usb_configuration_descriptor *config,
+                         struct usb_interface_descriptor *interface,
+                         unsigned int type, unsigned int index );
+extern struct usb_endpoint_companion_descriptor *
+usb_endpoint_companion_descriptor ( struct usb_configuration_descriptor *config,
+                                   struct usb_endpoint_descriptor *desc );
+
+extern struct usb_hub * alloc_usb_hub ( struct usb_bus *bus,
+                                       struct usb_device *usb,
+                                       unsigned int ports,
+                                       struct usb_hub_driver_operations *op );
+extern int register_usb_hub ( struct usb_hub *hub );
+extern void unregister_usb_hub ( struct usb_hub *hub );
+extern void free_usb_hub ( struct usb_hub *hub );
+
+extern void usb_port_changed ( struct usb_port *port );
+
+extern struct usb_bus * alloc_usb_bus ( struct device *dev,
+                                       unsigned int ports, size_t mtu,
+                                       struct usb_host_operations *op );
+extern int register_usb_bus ( struct usb_bus *bus );
+extern void unregister_usb_bus ( struct usb_bus *bus );
+extern void free_usb_bus ( struct usb_bus *bus );
+extern struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type,
+                                                  unsigned int location );
+
+extern int usb_alloc_address ( struct usb_bus *bus );
+extern void usb_free_address ( struct usb_bus *bus, unsigned int address );
+extern unsigned int usb_route_string ( struct usb_device *usb );
+extern unsigned int usb_depth ( struct usb_device *usb );
+extern struct usb_port * usb_root_hub_port ( struct usb_device *usb );
+extern struct usb_port * usb_transaction_translator ( struct usb_device *usb );
+
+/** Minimum reset time
+ *
+ * Section 7.1.7.5 of the USB2 specification states that root hub
+ * ports should assert reset signalling for at least 50ms.
+ */
+#define USB_RESET_DELAY_MS 50
+
+/** Reset recovery time
+ *
+ * Section 9.2.6.2 of the USB2 specification states that the
+ * "recovery" interval after a port reset is 10ms.
+ */
+#define USB_RESET_RECOVER_DELAY_MS 10
+
+/** Maximum time to wait for a control transaction to complete
+ *
+ * Section 9.2.6.1 of the USB2 specification states that the upper
+ * limit for commands to be processed is 5 seconds.
+ */
+#define USB_CONTROL_MAX_WAIT_MS 5000
+
+/** Set address recovery time
+ *
+ * Section 9.2.6.3 of the USB2 specification states that devices are
+ * allowed a 2ms recovery interval after receiving a new address.
+ */
+#define USB_SET_ADDRESS_RECOVER_DELAY_MS 2
+
+/** Time to wait for ports to stabilise
+ *
+ * Section 7.1.7.3 of the USB specification states that we must allow
+ * 100ms for devices to signal attachment, and an additional 100ms for
+ * connection debouncing.  (This delay is parallelised across all
+ * ports on a hub; we do not delay separately for each port.)
+ */
+#define USB_PORT_DELAY_MS 200
+
+/** A USB device ID */
+struct usb_device_id {
+       /** Name */
+       const char *name;
+       /** Vendor ID */
+       uint16_t vendor;
+       /** Product ID */
+       uint16_t product;
+       /** Class */
+       struct usb_class class;
+};
+
+/** Match-anything ID */
+#define USB_ANY_ID 0xffff
+
+/** A USB driver */
+struct usb_driver {
+       /** USB ID table */
+       struct usb_device_id *ids;
+       /** Number of entries in ID table */
+       unsigned int id_count;
+       /**
+        * Probe device
+        *
+        * @v func              USB function
+        * @v config            Configuration descriptor
+        * @ret rc              Return status code
+        */
+       int ( * probe ) ( struct usb_function *func,
+                         struct usb_configuration_descriptor *config );
+       /**
+        * Remove device
+        *
+        * @v func              USB function
+        */
+       void ( * remove ) ( struct usb_function *func );
+};
+
+/** USB driver table */
+#define USB_DRIVERS __table ( struct usb_driver, "usb_drivers" )
+
+/** Declare a USB driver */
+#define __usb_driver __table_entry ( USB_DRIVERS, 01 )
+
+#endif /* _IPXE_USB_H */