aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/ipxe/efi/efi_path.h3
-rw-r--r--src/include/ipxe/efi/efi_usb.h6
-rw-r--r--src/interface/efi/efi_path.c60
-rw-r--r--src/interface/efi/efi_usb.c74
4 files changed, 89 insertions, 54 deletions
diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h
index 0d5b902..c1d53e7 100644
--- a/src/include/ipxe/efi/efi_path.h
+++ b/src/include/ipxe/efi/efi_path.h
@@ -13,9 +13,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/DevicePath.h>
+struct usb_function;
+
extern EFI_DEVICE_PATH_PROTOCOL *
efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path );
extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path );
+extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func );
extern EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *interface );
#define efi_describe_TYPE( object_type ) \
diff --git a/src/include/ipxe/efi/efi_usb.h b/src/include/ipxe/efi/efi_usb.h
index 41d9cc6..06baff5 100644
--- a/src/include/ipxe/efi/efi_usb.h
+++ b/src/include/ipxe/efi/efi_usb.h
@@ -17,10 +17,8 @@
struct efi_usb_device {
/** Name */
const char *name;
- /** The underlying USB device */
- struct usb_device *usb;
- /** The underlying EFI device */
- struct efi_device *efidev;
+ /** The underlying USB function */
+ struct usb_function *func;
/** Configuration descriptor */
struct usb_configuration_descriptor *config;
/** Supported languages */
diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c
index fa43060..162400a 100644
--- a/src/interface/efi/efi_path.c
+++ b/src/interface/efi/efi_path.c
@@ -17,7 +17,11 @@
* 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
@@ -57,6 +61,62 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *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
*
* @v intf Interface
diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c
index 7ffeb7f..55b5bc8 100644
--- a/src/interface/efi/efi_usb.c
+++ b/src/interface/efi/efi_usb.c
@@ -73,10 +73,10 @@ static const char * efi_usb_direction_name ( EFI_USB_DATA_DIRECTION direction ){
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 )
@@ -179,7 +179,7 @@ static int efi_usb_open ( struct efi_usb_interface *usbintf,
}
/* 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 */ ) );
@@ -354,7 +354,7 @@ static int efi_usb_sync_transfer ( struct efi_usb_interface *usbintf,
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 ) {
@@ -594,7 +594,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio,
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,
@@ -841,7 +841,7 @@ efi_usb_get_device_descriptor ( EFI_USB_IO_PROTOCOL *usbio,
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;
}
@@ -972,8 +972,9 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language,
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,
@@ -996,9 +997,9 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 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 ) );
@@ -1107,25 +1108,13 @@ static EFI_USB_IO_PROTOCOL efi_usb_io_protocol = {
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;
@@ -1136,22 +1125,12 @@ static int efi_usb_install ( struct efi_usb_device *usbdev,
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 */
@@ -1182,6 +1161,8 @@ static int efi_usb_install ( struct efi_usb_device *usbdev,
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;
@@ -1219,6 +1200,9 @@ static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) {
/* Remove from list of interfaces */
list_del ( &usbintf->list );
+ /* Free device path */
+ free ( usbintf->path );
+
/* Free interface */
free ( usbintf );
}
@@ -1252,7 +1236,6 @@ static int efi_usb_probe ( struct usb_function *func,
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;
@@ -1260,13 +1243,6 @@ static int efi_usb_probe ( struct usb_function *func,
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 );
@@ -1288,8 +1264,7 @@ static int efi_usb_probe ( struct usb_function *func,
}
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 );
@@ -1325,7 +1300,6 @@ static int efi_usb_probe ( struct usb_function *func,
err_get_languages:
free ( usbdev );
err_alloc:
- err_no_efidev:
return rc;
}