EFI_USB_IO_PROTOCOL pseudo Host Controller Interface driver.
The EFI_USB_IO_PROTOCOL is an almost unbelievably poorly designed abstraction of a USB device. It would be just about forgivable for an API to support only synchronous operation for bulk OUT endpoints. It is imbecilic to support only synchronous operation for bulk IN endpoints. This apparently intern-designed API throttles a typical NIC down to 1.5% of its maximum throughput. That isn't a typo. It really is that slow.
We can't even work around this stupidity by talking to the host controller abstraction directly, because an identical limitation exists in the EFI_USB2_HC_PROTOCOL.
Unless you derive therapeutic value from watching download progress indicators lethargically creep through every single integer from 0 to 100, you should use iPXE's native USB host controller drivers instead. (Or just upgrade from UEFI to "legacy" BIOS, which will produce a similar speed increase.)
For added excitement, the EFI_USB_IO_PROTOCOL makes the (demonstrably incorrect) assumption that a USB driver needs to attach to exactly one interface within a USB device, and provides a helper method to retrieve "the" interface descriptor. Since pretty much every USB network device requires binding to a pair of control+data interfaces, this aspect of EFI_USB_IO_PROTOCOL is of no use to us.
We have our own existing code for reading USB descriptors, so we don't actually care that the UsbGetInterfaceDescriptor() method provided by EFI_USB_IO_PROTOCOL is useless for network devices. We can read the descriptors ourselves (via UsbControlTransfer()) and get all of the information we need this way. We can even work around the fact that EFI_USB_IO_PROTOCOL provides separate handles for each of the two interfaces comprising our network device.
However, if we discover that we need to select an alternative device configuration (e.g. for devices exposing both RNDIS and ECM), then all hell breaks loose. EFI_USB_IO_PROTOCOL starts to panic because its cached interface and endpoint descriptors will no longer be valid. As mentioned above, the cached descriptors are useless for network devices anyway so we really don't care about this, but EFI_USB_IO_PROTOCOL certainly cares. It prints out a manic warning message containing no fewer than six exclamation marks and then literally commits seppuku in the middle of the UsbControlTransfer() method by attempting to uninstall itself. Quite how the caller is supposed to react when asked to stop using the EFI_USB_IO_PROTOCOL instance while in the middle of an uninterruptible call to said instance is left as an exercise for the interested reader.
There is no sensible way to work around this, so we just preemptively fail if asked to change the device configuration, on the basis that reporting a sarcastic error message is often preferable to jumping through a NULL pointer and crashing the system.
Definition in file usbio.c.
Poll control endpoint.
- Parameters
-
Definition at line 315 of file usbio.c.
328 unsigned int recipient;
338 if ( endpoint->
cons == endpoint->
prod )
348 DBGC ( usbio,
"USBIO %s %s non-message transfer\n",
351 goto err_not_message;
390 DBGC ( usbio,
"USBIO %s cannot change configuration: %s\n",
392 goto err_moronic_specification;
399 DBGC ( usbio,
"USBIO %s %s could not submit control transfer ",
401 DBGC ( usbio,
"via %s: %s (status %04x)\n",
416 err_moronic_specification:
#define iob_pull(iobuf, len)
struct arbelprm_rc_send_wqe rc
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
#define USB_RECIP_MASK
Request recipient mask.
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
struct usbio_device * usbio
USB I/O device.
#define USB_RECIP_INTERFACE
Request recipient is an interface.
#define iob_push(iobuf, len)
The EFI_USB_IO_PROTOCOL provides four basic transfers types described in the USB 1....
uint8_t direction
Direction.
EFI_USB_DATA_DIRECTION
USB data transfer direction.
static void usbio_close(struct usbio_device *usbio, unsigned int interface)
Close USB I/O interface.
#define USBIO_RING_COUNT
USB I/O ring buffer size.
EFI_USB_IO_PROTOCOL * io
USB I/O protocol.
#define ENOTSUP
Operation not supported.
uint8_t flags[USBIO_RING_COUNT]
Flags.
Format of Setup Data for USB Device Requests USB 2.0 spec, Section 9.3.
#define USB_DIR_IN
Data transfer is from device to host.
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
char * strerror(int errno)
Retrieve string representation of error number.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
#define le16_to_cpu(value)
struct usb_configuration_descriptor * config
Configuration descriptor.
const char * usb_endpoint_name(struct usb_endpoint *ep)
Get USB endpoint name (for debugging)
EFI_USB_IO_CONTROL_TRANSFER UsbControlTransfer
unsigned int prod
Producer counter.
struct usbio_interface * interface
USB I/O protocol interfaces.
uint8_t config
Configuration value.
unsigned int cons
Consumer counter.
static void usb_complete(struct usb_endpoint *ep, struct io_buffer *iobuf)
Complete transfer (without error)
void * data
Start of data.
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
u8 request[0]
List of IEs requested.
uint8_t data[48]
Additional event data.
struct usb_endpoint * ep
USB endpoint.
EFI_HANDLE handle
EFI device handle.
A USB I/O protocol device.
EFI_HANDLE handle
EFI device handle.
#define USB_SET_CONFIGURATION
Set configuration.
#define NULL
NULL pointer (VOID *)
static int usbio_open(struct usbio_device *usbio, unsigned int interface)
Open USB I/O interface.
This is a message transfer.
struct io_buffer * iobuf[USBIO_RING_COUNT]
I/O buffers.
void usb_complete_err(struct usb_endpoint *ep, struct io_buffer *iobuf, int rc)
Complete transfer (possibly with error)
#define ENOTSUP_MORONIC_SPECIFICATION
References usbio_device::config, usb_configuration_descriptor::config, usbio_endpoint::cons, data, io_buffer::data, DBGC, direction, EEFI, efi_handle_name(), EfiUsbDataIn, EfiUsbDataOut, EfiUsbNoData, ENOTSUP, ENOTSUP_MORONIC_SPECIFICATION, usbio_endpoint::ep, flags, usbio_endpoint::flags, handle, usbio_interface::handle, usbio_device::handle, index, usbio_device::interface, usbio_interface::io, iob_len(), iob_pull, iob_push, usbio_endpoint::iobuf, le16_to_cpu, len, msg(), NULL, usbio_endpoint::prod, rc, request, status, strerror(), usb_complete(), usb_complete_err(), USB_DIR_IN, usb_endpoint_name(), USB_RECIP_INTERFACE, USB_RECIP_MASK, USB_SET_CONFIGURATION, _EFI_USB_IO_PROTOCOL::UsbControlTransfer, usbio_endpoint::usbio, usbio_close(), USBIO_MESSAGE, usbio_open(), and USBIO_RING_COUNT.
Open endpoint.
- Parameters
-
- Return values
-
Definition at line 835 of file usbio.c.
845 endpoint =
zalloc (
sizeof ( *endpoint ) );
878 goto err_open_interface;
881 DBGC ( usbio,
"USBIO %s %s using ",
886 if ( (
rc = endpoint->
op->
open ( endpoint ) ) != 0 )
887 goto err_open_endpoint;
895 endpoint->
op->
close ( endpoint );
static void usb_endpoint_set_hostdata(struct usb_endpoint *ep, void *priv)
Set USB endpoint host controller private data.
A USB I/O protocol interface.
struct arbelprm_rc_send_wqe rc
struct usbio_device * usbio
USB I/O device.
#define USB_ENDPOINT_ATTR_TYPE_MASK
Endpoint attribute transfer type mask.
uint8_t attr
Type and attributes.
static struct usbio_operations usbio_control_operations
Control endpoint operations.
#define USB_ENDPOINT_ATTR_BULK
Bulk endpoint transfer type.
static void usbio_close(struct usbio_device *usbio, unsigned int interface)
Close USB I/O interface.
EFI_USB_IO_PROTOCOL * io
USB I/O protocol.
#define ENOTSUP
Operation not supported.
#define list_del(list)
Delete an entry from a list.
#define ENOMEM
Not enough space.
unsigned int interface
Containing interface number.
struct usb_port * port
USB port.
EFI_HANDLE handle
EFI handle.
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
struct list_head endpoints
List of endpoints.
static struct usbio_operations usbio_bulk_in_operations
Bulk endpoint operations.
#define USB_DIR_IN
Data transfer is from device to host.
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
EFI_USB_IO_PROTOCOL * io
USB I/O protocol.
#define USB_ENDPOINT_ATTR_INTERRUPT
Interrupt endpoint transfer type.
static void(* free)(struct refcnt *refcnt))
void * zalloc(size_t size)
Allocate cleared memory.
void(* close)(struct usbio_endpoint *endpoint)
Close endpoint.
struct usbio_operations * op
USB I/O endpoint operations.
const char * usb_endpoint_name(struct usb_endpoint *ep)
Get USB endpoint name (for debugging)
struct usbio_interface * interface
USB I/O protocol interfaces.
static void * usb_bus_get_hostdata(struct usb_bus *bus)
Get USB bus host controller private data.
struct usb_hub * hub
USB hub.
int(* open)(struct usbio_endpoint *endpoint)
Open endpoint.
static struct usbio_operations usbio_interrupt_operations
Interrupt endpoint operations.
#define USB_ENDPOINT_ATTR_CONTROL
Control endpoint transfer type.
struct list_head list
List of endpoints.
struct usb_endpoint * ep
USB endpoint.
struct usb_device * usb
USB device.
EFI_HANDLE handle
EFI device handle.
static struct usbio_operations usbio_bulk_out_operations
Bulk endpoint operations.
struct usb_bus * bus
USB bus.
A USB I/O protocol device.
EFI_HANDLE handle
EFI device handle.
unsigned int attributes
Attributes.
static int usbio_open(struct usbio_device *usbio, unsigned int interface)
Open USB I/O interface.
unsigned int address
Endpoint address.
References usb_endpoint::address, attr, usb_endpoint::attributes, bus, usb_hub::bus, usbio_operations::close, DBGC, efi_handle_name(), ENOMEM, ENOTSUP, usbio_endpoint::ep, free, handle, usbio_endpoint::handle, usbio_interface::handle, usbio_device::handle, usb_port::hub, usbio_endpoint::interface, usbio_endpoint::io, usbio_interface::io, usbio_endpoint::list, list_add_tail, list_del, usbio_endpoint::op, usbio_operations::open, usb_device::port, rc, usb_endpoint::usb, usb_bus_get_hostdata(), USB_DIR_IN, USB_ENDPOINT_ATTR_BULK, USB_ENDPOINT_ATTR_CONTROL, USB_ENDPOINT_ATTR_INTERRUPT, USB_ENDPOINT_ATTR_TYPE_MASK, usb_endpoint_name(), usb_endpoint_set_hostdata(), usbio_endpoint::usbio, usbio_bulk_in_operations, usbio_bulk_out_operations, usbio_close(), usbio_control_operations, usbio_interrupt_operations, usbio_open(), and zalloc().
Fetch configuration descriptor.
- Parameters
-
- Return values
-
Definition at line 1373 of file usbio.c.
1393 DBGC ( usbio,
"USB %s could not get device descriptor: " 1395 goto err_get_device_descriptor;
1402 DBGC ( usbio,
"USB %s could not get partial configuration " 1405 goto err_get_configuration_descriptor;
1423 for ( i = 0 ; i <
count ; i++ ) {
1429 msg.setup.index = 0;
1438 DBGC ( usbio,
"USB %s could not get configuration %d " 1441 goto err_control_transfer;
1450 DBGC ( usbio,
"USB %s configuration descriptor length " 1460 DBGC ( usbio,
"USB %s could not find current configuration " 1465 err_control_transfer:
1468 err_get_configuration_descriptor:
1469 err_get_device_descriptor:
#define EINVAL
Invalid argument.
struct arbelprm_rc_send_wqe rc
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
#define USB_GET_DESCRIPTOR
Get descriptor.
#define ENOENT
No such file or directory.
The EFI_USB_IO_PROTOCOL provides four basic transfers types described in the USB 1....
uint16_t device
Device ID.
#define ENOMEM
Not enough space.
Format of Setup Data for USB Device Requests USB 2.0 spec, Section 9.3.
pseudo_bit_t value[0x00020]
uint16_t count
Number of entries.
#define USB_CONFIGURATION_DESCRIPTOR
A USB configuration descriptor.
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
char * strerror(int errno)
Retrieve string representation of error number.
static void(* free)(struct refcnt *refcnt))
#define le16_to_cpu(value)
void * malloc(size_t size)
Allocate memory.
struct usb_configuration_descriptor * config
Configuration descriptor.
EFI_USB_IO_CONTROL_TRANSFER UsbControlTransfer
uint8_t config
Configuration value.
EFI_USB_IO_GET_DEVICE_DESCRIPTOR UsbGetDeviceDescriptor
EFI_USB_IO_PROTOCOL * io
USB I/O protocol.
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
#define cpu_to_le16(value)
Standard Configuration Descriptor USB 2.0 spec, Section 9.6.3.
uint16_t len
Total length.
EFI_HANDLE handle
EFI device handle.
Standard Device Descriptor USB 2.0 spec, Section 9.6.1.
EFI_USB_IO_GET_CONFIG_DESCRIPTOR UsbGetConfigDescriptor
References usbio_device::config, usb_configuration_descriptor::config, USB_CONFIG_DESCRIPTOR::ConfigurationValue, count, cpu_to_le16, DBGC, device, EEFI, efi_handle_name(), EfiUsbDataIn, EINVAL, ENOENT, ENOMEM, free, handle, usbio_device::handle, usbio_device::io, le16_to_cpu, len, usb_configuration_descriptor::len, malloc(), msg(), rc, status, strerror(), USB_CONFIG_DESCRIPTOR::TotalLength, USB_CONFIGURATION_DESCRIPTOR, USB_GET_DESCRIPTOR, _EFI_USB_IO_PROTOCOL::UsbControlTransfer, _EFI_USB_IO_PROTOCOL::UsbGetConfigDescriptor, _EFI_USB_IO_PROTOCOL::UsbGetDeviceDescriptor, and value.
Referenced by usbio_start().
Construct device path for opening other interfaces.
- Parameters
-
- Return values
-
Definition at line 1479 of file usbio.c.
1500 DBGC ( usbio,
"USBIO %s cannot open device path protocol: " 1502 goto err_open_protocol;
1508 if (
len <
sizeof ( *usbpath ) ) {
1509 DBGC ( usbio,
"USBIO %s underlength device path\n",
1512 goto err_underlength;
1514 usbpath = ( ( (
void * ) path ) +
len -
sizeof ( *usbpath ) );
1517 DBGC ( usbio,
"USBIO %s not a USB device path: ",
1526 if ( ! usbio->
path ) {
1532 sizeof ( *usbpath ) );
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
#define EINVAL
Invalid argument.
struct arbelprm_rc_send_wqe rc
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
This protocol can be used on any device handle to obtain generic path/location information concerning...
EFI_CLOSE_PROTOCOL CloseProtocol
#define MESSAGING_DEVICE_PATH
Messaging Device Paths.
#define ENOMEM
Not enough space.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
const char * efi_devpath_text(EFI_DEVICE_PATH_PROTOCOL *path)
Get textual representation of device path.
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL
EFI_DEVICE_PATH_PROTOCOL Header
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
char * strerror(int errno)
Retrieve string representation of error number.
static void(* free)(struct refcnt *refcnt))
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
EFI_DEVICE_PATH_PROTOCOL * path
Device path.
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
void * malloc(size_t size)
Allocate memory.
USB_DEVICE_PATH * usbpath
Final component of USB device path.
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
UINT8 SubType
Varies by Type 0xFF End Entire Device Path, or 0x01 End This Instance of a Device Path and start a ne...
uint32_t end
Ending offset.
UINT8 Type
0x01 Hardware Device Path.
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
EFI_HANDLE handle
EFI device handle.
#define MSG_USB_DP
USB Device Path SubType.
References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, DBGC, EEFI, efi_device_path_protocol_guid, efi_devpath_text(), efi_handle_name(), efi_image_handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL, efi_path_len(), efi_systab, EINVAL, end, ENOMEM, free, handle, usbio_device::handle, USB_DEVICE_PATH::Header, len, malloc(), memcpy(), MESSAGING_DEVICE_PATH, MSG_USB_DP, EFI_BOOT_SERVICES::OpenProtocol, usbio_device::path, rc, strerror(), EFI_DEVICE_PATH_PROTOCOL::SubType, EFI_DEVICE_PATH_PROTOCOL::Type, u, and usbio_device::usbpath.
Referenced by usbio_start().
static int usbio_start |
( |
struct efi_device * |
efidev | ) |
|
|
static |
Attach driver to device.
- Parameters
-
- Return values
-
Definition at line 1610 of file usbio.c.
1623 usbio =
zalloc (
sizeof ( *usbio ) );
1639 DBGC ( usbio,
"USBIO %s cannot open USB I/O protocol: %s\n",
1642 goto err_open_usbio;
1662 goto err_interfaces;
1667 if ( ! usbio->
bus ) {
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
struct arbelprm_rc_send_wqe rc
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
struct device dev
Generic device.
static int usbio_path(struct usbio_device *usbio)
Construct device path for opening other interfaces.
#define list_add(new, head)
Add a new entry to the head of a list.
struct usb_bus * alloc_usb_bus(struct device *dev, unsigned int ports, size_t mtu, struct usb_host_operations *op)
Allocate USB bus.
#define EFI_OPEN_PROTOCOL_BY_DRIVER
The EFI_USB_IO_PROTOCOL provides four basic transfers types described in the USB 1....
#define EFI_OPEN_PROTOCOL_EXCLUSIVE
#define DBGC_EFI_OPENERS(...)
EFI_HANDLE device
EFI device handle.
EFI_CLOSE_PROTOCOL CloseProtocol
struct device * parent
Bus device.
static void usb_bus_set_hostdata(struct usb_bus *bus, void *priv)
Set USB bus host controller private data.
#define USBIO_MTU
USB I/O maximum transfer size.
#define list_del(list)
Delete an entry from a list.
#define ENOMEM
Not enough space.
void unregister_usb_bus(struct usb_bus *bus)
Unregister USB bus.
struct list_head endpoints
List of endpoints.
static int usbio_config(struct usbio_device *usbio)
Fetch configuration descriptor.
struct usb_bus * bus
USB bus.
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
char * strerror(int errno)
Retrieve string representation of error number.
EFI_GUID efi_usb_io_protocol_guid
USB I/O protocol GUID.
static void(* free)(struct refcnt *refcnt))
void * zalloc(size_t size)
Allocate cleared memory.
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
struct list_head siblings
Devices on the same bus.
EFI_DEVICE_PATH_PROTOCOL * path
Device path.
struct usb_configuration_descriptor * config
Configuration descriptor.
#define INIT_LIST_HEAD(list)
Initialise a list head.
struct usbio_interface * interface
USB I/O protocol interfaces.
int register_usb_bus(struct usb_bus *bus)
Register USB bus.
EFI_USB_IO_PROTOCOL * io
USB I/O protocol.
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
struct list_head children
Devices attached to this device.
struct usb_hub * hub
Root hub.
static void usb_hub_set_drvdata(struct usb_hub *hub, void *priv)
Set USB hub driver private data.
static struct usb_port * usb_port(struct usb_hub *hub, unsigned int address)
Get USB port.
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
EFI_HANDLE handle
EFI device handle.
static void efidev_set_drvdata(struct efi_device *efidev, void *priv)
Set EFI driver-private data.
A USB I/O protocol device.
USB I/O endpoint operations.
struct device dev
Generic device.
static int usbio_interfaces(struct usbio_device *usbio)
Construct interface list.
void free_usb_bus(struct usb_bus *bus)
Free USB bus.
void efi_device_info(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying device information.
References alloc_usb_bus(), EFI_SYSTEM_TABLE::BootServices, usbio_device::bus, device::children, EFI_BOOT_SERVICES::CloseProtocol, usbio_device::config, DBGC, DBGC_EFI_OPENERS, efi_device::dev, usbio_device::dev, efi_device::device, EEFI, efi_device_info(), efi_handle_name(), efi_image_handle, EFI_OPEN_PROTOCOL_BY_DRIVER, EFI_OPEN_PROTOCOL_EXCLUSIVE, efi_systab, efi_usb_io_protocol_guid, efidev_set_drvdata(), usbio_device::endpoints, ENOMEM, free, free_usb_bus(), handle, usbio_device::handle, usb_bus::hub, INIT_LIST_HEAD, usbio_device::interface, usbio_device::io, list_add, list_del, EFI_BOOT_SERVICES::OpenProtocol, device::parent, usbio_device::path, port, rc, register_usb_bus(), device::siblings, strerror(), u, unregister_usb_bus(), usb_bus_set_hostdata(), usb_hub_set_drvdata(), usb_port(), USB_PROTO_2_0, usbio_config(), usbio_interfaces(), USBIO_MTU, usbio_path(), and zalloc().