david/ipxe
david
/
ipxe
Archived
1
0
Fork 0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/include/ipxe/usb.h

1414 lines
35 KiB
C

#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 parameter */
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 mask */
#define USB_RECIP_MASK ( 0x1f << 0 )
/** 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
/** Language ID for English */
#define USB_LANG_ENGLISH 0x0409
/** 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 reserved header length */
size_t reserve;
/** Refill buffer payload 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 zlp Append a zero-length packet
* @ret rc Return status code
*/
int ( * stream ) ( struct usb_endpoint *ep, struct io_buffer *iobuf,
int zlp );
};
/** 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 reserve Refill buffer reserved header length
* @v len Refill buffer payload length (zero for endpoint's MTU)
* @v max Maximum fill level
*/
static inline __attribute__ (( always_inline )) void
usb_refill_init ( struct usb_endpoint *ep, size_t reserve, size_t len,
unsigned int max ) {
INIT_LIST_HEAD ( &ep->recycled );
ep->reserve = reserve;
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 class descriptor */
union usb_class_descriptor {
/** Class */
struct usb_class class;
/** Scalar value */
uint32_t scalar;
};
/**
* A USB function descriptor
*
* This is an internal descriptor used to represent an association of
* interfaces within a USB device.
*/
struct usb_function_descriptor {
/** Vendor ID */
uint16_t vendor;
/** Product ID */
uint16_t product;
/** Class */
union usb_class_descriptor class;
/** Number of interfaces */
unsigned int count;
};
/**
* 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;
/** Function descriptor */
struct usb_function_descriptor desc;
/** 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;
/** Driver device ID */
struct usb_device_id *id;
/** 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;
/** Device speed */
unsigned int speed;
/** 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;
/** Default language ID (if known) */
unsigned int language;
};
/** 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;
/** Arbitrary driver data */
unsigned long driver_data;
};
/** Match-anything ID */
#define USB_ANY_ID 0xffff
/** A USB class ID */
struct usb_class_id {
/** Class */
union usb_class_descriptor class;
/** Class mask */
union usb_class_descriptor mask;
};
/** Construct USB class ID
*
* @v base Base class code (or USB_ANY_ID)
* @v subclass Subclass code (or USB_ANY_ID)
* @v protocol Protocol code (or USB_ANY_ID)
*/
#define USB_CLASS_ID( base, subclass, protocol ) { \
.class = { \
.class = { \
( (base) & 0xff ), \
( (subclass) & 0xff ), \
( (protocol) & 0xff ), \
}, \
}, \
.mask = { \
.class = { \
( ( (base) == USB_ANY_ID ) ? 0x00 : 0xff ), \
( ( (subclass) == USB_ANY_ID ) ? 0x00 : 0xff ), \
( ( (protocol) == USB_ANY_ID ) ? 0x00 : 0xff ), \
}, \
}, \
}
/** A USB driver */
struct usb_driver {
/** USB ID table */
struct usb_device_id *ids;
/** Number of entries in ID table */
unsigned int id_count;
/** Class ID */
struct usb_class_id class;
/** Driver score
*
* This is used to determine the preferred configuration for a
* USB device.
*/
unsigned int score;
/**
* 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 )
/** USB driver scores */
enum usb_driver_score {
/** Fallback driver (has no effect on overall score) */
USB_SCORE_FALLBACK = 0,
/** Deprecated driver */
USB_SCORE_DEPRECATED = 1,
/** Normal driver */
USB_SCORE_NORMAL = 2,
};
extern struct usb_driver *
usb_find_driver ( struct usb_function_descriptor *desc,
struct usb_device_id **id );
#endif /* _IPXE_USB_H */