[efi] Split efi_usb_path() out to a separate function

Provide efi_usb_path() as a standalone function, to allow for reuse by
the USB mass storage driver.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/171/head
Michael Brown 2020-10-16 15:07:14 +01:00
parent 2091288eaa
commit 87e39a9c93
4 changed files with 89 additions and 54 deletions

View File

@ -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 ) \

View File

@ -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 */

View File

@ -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
@ -56,6 +60,62 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) {
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
*

View File

@ -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;
}