* 02110-1301, USA.
*/
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/usb.h>
#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_path.h>
/** @file
return ( ( ( void * ) end ) - ( ( void * ) path ) );
}
+/**
+ * Construct EFI device path for USB function
+ *
+ * @v func USB function
+ * @ret path EFI device path, or NULL on error
+ *
+ * The caller is responsible for eventually calling free() on the
+ * allocated device path.
+ */
+EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) {
+ struct usb_device *usb = func->usb;
+ struct efi_device *efidev;
+ EFI_DEVICE_PATH_PROTOCOL *path;
+ EFI_DEVICE_PATH_PROTOCOL *end;
+ USB_DEVICE_PATH *usbpath;
+ unsigned int count;
+ size_t prefix_len;
+ size_t len;
+
+ /* Sanity check */
+ assert ( func->desc.count >= 1 );
+
+ /* Find parent EFI device */
+ efidev = efidev_parent ( &func->dev );
+ if ( ! efidev )
+ return NULL;
+
+ /* Calculate device path length */
+ count = ( usb_depth ( usb ) + 1 );
+ prefix_len = efi_path_len ( efidev->path );
+ len = ( prefix_len + ( count * sizeof ( *usbpath ) ) +
+ sizeof ( *end ) );
+
+ /* Allocate device path */
+ path = zalloc ( len );
+ if ( ! path )
+ return NULL;
+
+ /* Construct device path */
+ memcpy ( path, efidev->path, prefix_len );
+ end = ( ( ( void * ) path ) + len - sizeof ( *end ) );
+ end->Type = END_DEVICE_PATH_TYPE;
+ end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ end->Length[0] = sizeof ( *end );
+ usbpath = ( ( ( void * ) end ) - sizeof ( *usbpath ) );
+ usbpath->InterfaceNumber = func->interface[0];
+ for ( ; usb ; usbpath--, usb = usb->port->hub->usb ) {
+ usbpath->Header.Type = MESSAGING_DEVICE_PATH;
+ usbpath->Header.SubType = MSG_USB_DP;
+ usbpath->Header.Length[0] = sizeof ( *usbpath );
+ usbpath->ParentPortNumber = ( usb->port->address - 1 );
+ }
+
+ return path;
+}
+
/**
* Describe object as an EFI device path
*
static VOID EFIAPI efi_usb_timer ( EFI_EVENT event __unused,
VOID *context ) {
struct efi_usb_endpoint *usbep = context;
- struct usb_bus *bus = usbep->usbintf->usbdev->usb->port->hub->bus;
+ struct usb_function *func = usbep->usbintf->usbdev->func;
/* Poll bus */
- usb_poll ( bus );
+ usb_poll ( func->usb->port->hub->bus );
/* Refill endpoint */
if ( usbep->ep.open )
}
/* Allocate and initialise structure */
- usb_endpoint_init ( &usbep->ep, usbdev->usb, driver );
+ usb_endpoint_init ( &usbep->ep, usbdev->func->usb, driver );
usb_endpoint_describe ( &usbep->ep, endpoint, attributes, mtu, 0,
( interval << 3 /* microframes */ ) );
for ( i = 0 ; ( ( timeout == 0 ) || ( i < timeout ) ) ; i++ ) {
/* Poll bus */
- usb_poll ( usbdev->usb->port->hub->bus );
+ usb_poll ( usbdev->func->usb->port->hub->bus );
/* Check for completion */
if ( usbep->rc != -EINPROGRESS ) {
efi_usb_close_all ( usbintf );
/* Issue control transfer */
- if ( ( rc = usb_control ( usbdev->usb, request, value, index,
+ if ( ( rc = usb_control ( usbdev->func->usb, request, value, index,
data, len ) ) != 0 ) {
DBGC ( usbdev, "USBDEV %s control %04x:%04x:%04x:%04x %p+%zx "
"failed: %s\n", usbintf->name, request, value, index,
DBGC2 ( usbdev, "USBDEV %s get device descriptor\n", usbintf->name );
/* Copy cached device descriptor */
- memcpy ( efidesc, &usbdev->usb->device, sizeof ( *efidesc ) );
+ memcpy ( efidesc, &usbdev->func->usb->device, sizeof ( *efidesc ) );
return 0;
}
saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );
/* Read descriptor header */
- if ( ( rc = usb_get_descriptor ( usbdev->usb, 0, USB_STRING_DESCRIPTOR,
- index, language, &header,
+ if ( ( rc = usb_get_descriptor ( usbdev->func->usb, 0,
+ USB_STRING_DESCRIPTOR, index,
+ language, &header,
sizeof ( header ) ) ) != 0 ) {
DBGC ( usbdev, "USBDEV %s could not get string %d:%d "
"descriptor header: %s\n", usbintf->name, language,
}
/* Read whole descriptor */
- if ( ( rc = usb_get_descriptor ( usbdev->usb, 0, USB_STRING_DESCRIPTOR,
- index, language, buffer,
- len ) ) != 0 ) {
+ if ( ( rc = usb_get_descriptor ( usbdev->func->usb, 0,
+ USB_STRING_DESCRIPTOR, index,
+ language, buffer, len ) ) != 0 ) {
DBGC ( usbdev, "USBDEV %s could not get string %d:%d "
"descriptor: %s\n", usbintf->name, language,
index, strerror ( rc ) );
static int efi_usb_install ( struct efi_usb_device *usbdev,
unsigned int interface ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- struct efi_device *efidev = usbdev->efidev;
+ struct usb_function *func = usbdev->func;
struct efi_usb_interface *usbintf;
- struct usb_device *usb;
- EFI_DEVICE_PATH_PROTOCOL *path_end;
- USB_DEVICE_PATH *usbpath;
- unsigned int path_count;
- size_t path_prefix_len;
- size_t path_len;
EFI_STATUS efirc;
int rc;
- /* Calculate device path length */
- path_count = ( usb_depth ( usbdev->usb ) + 1 );
- path_prefix_len = efi_path_len ( efidev->path );
- path_len = ( path_prefix_len + ( path_count * sizeof ( *usbpath ) ) +
- sizeof ( *path_end ) );
-
/* Allocate and initialise structure */
- usbintf = zalloc ( sizeof ( *usbintf ) + path_len );
+ usbintf = zalloc ( sizeof ( *usbintf ) );
if ( ! usbintf ) {
rc = -ENOMEM;
goto err_alloc;
usbintf->interface = interface;
memcpy ( &usbintf->usbio, &efi_usb_io_protocol,
sizeof ( usbintf->usbio ) );
- usbintf->path = ( ( ( void * ) usbintf ) + sizeof ( *usbintf ) );
/* Construct device path */
- memcpy ( usbintf->path, efidev->path, path_prefix_len );
- path_end = ( ( ( void * ) usbintf->path ) + path_len -
- sizeof ( *path_end ) );
- path_end->Type = END_DEVICE_PATH_TYPE;
- path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
- path_end->Length[0] = sizeof ( *path_end );
- usbpath = ( ( ( void * ) path_end ) - sizeof ( *usbpath ) );
- usbpath->InterfaceNumber = interface;
- for ( usb = usbdev->usb ; usb ; usbpath--, usb = usb->port->hub->usb ) {
- usbpath->Header.Type = MESSAGING_DEVICE_PATH;
- usbpath->Header.SubType = MSG_USB_DP;
- usbpath->Header.Length[0] = sizeof ( *usbpath );
- usbpath->ParentPortNumber = ( usb->port->address - 1 );
+ usbintf->path = efi_usb_path ( func );
+ if ( ! usbintf->path ) {
+ rc = -ENODEV;
+ goto err_path;
}
/* Add to list of interfaces */
efi_usb_close_all ( usbintf );
efi_usb_free_all ( usbintf );
list_del ( &usbintf->list );
+ free ( usbintf->path );
+ err_path:
free ( usbintf );
err_alloc:
return rc;
/* Remove from list of interfaces */
list_del ( &usbintf->list );
+ /* Free device path */
+ free ( usbintf->path );
+
/* Free interface */
free ( usbintf );
}
struct usb_device *usb = func->usb;
struct efi_usb_device *usbdev;
struct efi_usb_interface *usbintf;
- struct efi_device *efidev;
struct usb_descriptor_header header;
struct usb_descriptor_header *lang;
size_t config_len;
unsigned int i;
int rc;
- /* Find parent EFI device */
- efidev = efidev_parent ( &func->dev );
- if ( ! efidev ) {
- rc = -ENOTTY;
- goto err_no_efidev;
- }
-
/* Get configuration length */
config_len = le16_to_cpu ( config->len );
}
usb_func_set_drvdata ( func, usbdev );
usbdev->name = func->name;
- usbdev->usb = usb;
- usbdev->efidev = efidev;
+ usbdev->func = func;
usbdev->config = ( ( ( void * ) usbdev ) + sizeof ( *usbdev ) );
memcpy ( usbdev->config, config, config_len );
lang = ( ( ( void * ) usbdev->config ) + config_len );
err_get_languages:
free ( usbdev );
err_alloc:
- err_no_efidev:
return rc;
}