iPXE
Functions | Variables
efi_usb.c File Reference

EFI USB I/O PROTOCOL. More...

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_utils.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_usb.h>
#include <ipxe/usb.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static const char * efi_usb_direction_name (EFI_USB_DATA_DIRECTION direction)
 Transcribe data direction (for debugging)
static VOID EFIAPI efi_usb_timer (EFI_EVENT event __unused, VOID *context)
 Poll USB bus (from endpoint event timer)
static int efi_usb_mtu (struct efi_usb_interface *usbintf, unsigned int endpoint)
 Get endpoint MTU.
static int efi_usb_open (struct efi_usb_interface *usbintf, unsigned int endpoint, unsigned int attributes, unsigned int interval, struct usb_endpoint_driver_operations *driver)
 Open endpoint.
static void efi_usb_close (struct efi_usb_endpoint *usbep)
 Close endpoint.
static void efi_usb_close_all (struct efi_usb_interface *usbintf)
 Close all endpoints.
static void efi_usb_sync_complete (struct usb_endpoint *ep, struct io_buffer *iobuf __unused, int rc)
 Complete synchronous transfer.
static int efi_usb_sync_transfer (struct efi_usb_interface *usbintf, unsigned int endpoint, unsigned int attributes, unsigned int timeout, void *data, size_t *len)
 Perform synchronous transfer.
static void efi_usb_async_complete (struct usb_endpoint *ep, struct io_buffer *iobuf, int rc)
 Complete asynchronous transfer.
static int efi_usb_async_start (struct efi_usb_interface *usbintf, unsigned int endpoint, unsigned int interval, size_t len, EFI_ASYNC_USB_TRANSFER_CALLBACK callback, void *context)
 Start asynchronous transfer.
static void efi_usb_async_stop (struct efi_usb_interface *usbintf, unsigned int endpoint)
 Stop asynchronous transfer.
static EFI_STATUS EFIAPI efi_usb_control_transfer (EFI_USB_IO_PROTOCOL *usbio, EFI_USB_DEVICE_REQUEST *packet, EFI_USB_DATA_DIRECTION direction, UINT32 timeout, VOID *data, UINTN len, UINT32 *status)
 Perform control transfer.
static EFI_STATUS EFIAPI efi_usb_bulk_transfer (EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, UINTN *len, UINTN timeout, UINT32 *status)
 Perform bulk transfer.
static EFI_STATUS EFIAPI efi_usb_sync_interrupt_transfer (EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, UINTN *len, UINTN timeout, UINT32 *status)
 Perform synchronous interrupt transfer.
static EFI_STATUS EFIAPI efi_usb_async_interrupt_transfer (EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, BOOLEAN start, UINTN interval, UINTN len, EFI_ASYNC_USB_TRANSFER_CALLBACK callback, VOID *context)
 Perform asynchronous interrupt transfer.
static EFI_STATUS EFIAPI efi_usb_isochronous_transfer (EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, UINTN len, UINT32 *status)
 Perform synchronous isochronous transfer.
static EFI_STATUS EFIAPI efi_usb_async_isochronous_transfer (EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, UINTN len, EFI_ASYNC_USB_TRANSFER_CALLBACK callback, VOID *context)
 Perform asynchronous isochronous transfers.
static EFI_STATUS EFIAPI efi_usb_get_device_descriptor (EFI_USB_IO_PROTOCOL *usbio, EFI_USB_DEVICE_DESCRIPTOR *efidesc)
 Get device descriptor.
static EFI_STATUS EFIAPI efi_usb_get_config_descriptor (EFI_USB_IO_PROTOCOL *usbio, EFI_USB_CONFIG_DESCRIPTOR *efidesc)
 Get configuration descriptor.
static EFI_STATUS EFIAPI efi_usb_get_interface_descriptor (EFI_USB_IO_PROTOCOL *usbio, EFI_USB_INTERFACE_DESCRIPTOR *efidesc)
 Get interface descriptor.
static EFI_STATUS EFIAPI efi_usb_get_endpoint_descriptor (EFI_USB_IO_PROTOCOL *usbio, UINT8 index, EFI_USB_ENDPOINT_DESCRIPTOR *efidesc)
 Get endpoint descriptor.
static EFI_STATUS EFIAPI efi_usb_get_string_descriptor (EFI_USB_IO_PROTOCOL *usbio, UINT16 language, UINT8 index, CHAR16 **string)
 Get string descriptor.
static EFI_STATUS EFIAPI efi_usb_get_supported_languages (EFI_USB_IO_PROTOCOL *usbio, UINT16 **languages, UINT16 *len)
 Get supported languages.
static EFI_STATUS EFIAPI efi_usb_port_reset (EFI_USB_IO_PROTOCOL *usbio)
 Reset port.
static int efi_usb_install (struct efi_usb_device *usbdev, unsigned int interface)
 Install interface.
static void efi_usb_uninstall (struct efi_usb_interface *usbintf)
 Uninstall interface.
static void efi_usb_uninstall_all (struct efi_usb_device *efiusb)
 Uninstall all interfaces.
static int efi_usb_probe (struct usb_function *func, struct usb_configuration_descriptor *config)
 Probe device.
static void efi_usb_remove (struct usb_function *func)
 Remove device.

Variables

static struct
usb_endpoint_driver_operations 
efi_usb_sync_driver
 Synchronous endpoint operations.
static struct
usb_endpoint_driver_operations 
efi_usb_async_driver
 Asynchronous endpoint operations.
static EFI_USB_IO_PROTOCOL efi_usb_io_protocol
 USB I/O protocol.
static struct usb_device_id efi_usb_ids []
 USB I/O protocol device IDs.
struct usb_driver usbio_driver __usb_driver
 USB I/O protocol driver.

Detailed Description

EFI USB I/O PROTOCOL.

Definition in file efi_usb.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static const char* efi_usb_direction_name ( EFI_USB_DATA_DIRECTION  direction) [static]

Transcribe data direction (for debugging)

Parameters:
directionData direction
Return values:
textTranscribed data direction

Definition at line 50 of file efi_usb.c.

References EfiUsbDataIn, EfiUsbDataOut, and EfiUsbNoData.

Referenced by efi_usb_control_transfer().

                                                                               {

        switch ( direction ) {
        case EfiUsbDataIn:      return "in";
        case EfiUsbDataOut:     return "out";
        case EfiUsbNoData:      return "none";
        default:                return "<UNKNOWN>";
        }
}
static VOID EFIAPI efi_usb_timer ( EFI_EVENT event  __unused,
VOID context 
) [static]

Poll USB bus (from endpoint event timer)

Parameters:
eventEFI event
contextEFI USB endpoint

Definition at line 73 of file efi_usb.c.

References bus, usb_hub::bus, context, efi_usb_endpoint::ep, usb_port::hub, usb_device::port, efi_usb_device::usb, usb_poll(), usb_refill(), efi_usb_interface::usbdev, and efi_usb_endpoint::usbintf.

Referenced by efi_usb_open().

                                                   {
        struct efi_usb_endpoint *usbep = context;
        struct usb_bus *bus = usbep->usbintf->usbdev->usb->port->hub->bus;

        /* Poll bus */
        usb_poll ( bus );

        /* Refill endpoint */
        usb_refill ( &usbep->ep );
}
static int efi_usb_mtu ( struct efi_usb_interface usbintf,
unsigned int  endpoint 
) [static]

Get endpoint MTU.

Parameters:
usbintfEFI USB interface
endpointEndpoint address
Return values:
mtuEndpoint MTU, or negative error

Definition at line 92 of file efi_usb.c.

References usb_interface_descriptor::alternate, DBGC, usb_endpoint_descriptor::endpoint, ENOENT, for_each_interface_descriptor, usb_endpoint_descriptor::header, usb_interface_descriptor::interface, le16_to_cpu, usb_interface_descriptor::name, usb_endpoint_descriptor::sizes, usb_descriptor_header::type, USB_ENDPOINT_MTU, and efi_usb_interface::usbdev.

Referenced by efi_usb_open().

                                                 {
        struct efi_usb_device *usbdev = usbintf->usbdev;
        struct usb_interface_descriptor *interface;
        struct usb_endpoint_descriptor *desc;

        /* Locate cached interface descriptor */
        interface = usb_interface_descriptor ( usbdev->config,
                                               usbintf->interface,
                                               usbintf->alternate );
        if ( ! interface ) {
                DBGC ( usbdev, "USBDEV %s alt %d has no interface descriptor\n",
                       usbintf->name, usbintf->alternate );
                return -ENOENT;
        }

        /* Locate and copy cached endpoint descriptor */
        for_each_interface_descriptor ( desc, usbdev->config, interface ) {
                if ( ( desc->header.type == USB_ENDPOINT_DESCRIPTOR ) &&
                     ( desc->endpoint == endpoint ) )
                        return USB_ENDPOINT_MTU ( le16_to_cpu ( desc->sizes ) );
        }

        DBGC ( usbdev, "USBDEV %s alt %d ep %02x has no descriptor\n",
               usbintf->name, usbintf->alternate, endpoint );
        return -ENOENT;
}
static int efi_usb_open ( struct efi_usb_interface usbintf,
unsigned int  endpoint,
unsigned int  attributes,
unsigned int  interval,
struct usb_endpoint_driver_operations driver 
) [static]

Open endpoint.

Parameters:
usbintfEFI USB interface
endpointEndpoint address
attributesEndpoint attributes
intervalInterval (in milliseconds)
driverDriver operations
Return values:
rcReturn status code

Definition at line 130 of file efi_usb.c.

References EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseEvent, EFI_BOOT_SERVICES::CreateEvent, DBGC, EEFI, efi_systab, efi_usb_mtu(), efi_usb_timer(), efi_usb_interface::endpoint, ENOMEM, efi_usb_endpoint::ep, efi_usb_endpoint::event, EVT_NOTIFY_SIGNAL, EVT_TIMER, free, index, mtu, efi_usb_interface::name, rc, strerror(), TPL_CALLBACK, efi_usb_device::usb, usb_endpoint_close(), usb_endpoint_describe(), USB_ENDPOINT_IDX, usb_endpoint_init(), usb_endpoint_name(), usb_endpoint_open(), efi_usb_interface::usbdev, efi_usb_endpoint::usbintf, and zalloc().

Referenced by efi_usb_async_start(), and efi_usb_sync_transfer().

                                                                          {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_device *usbdev = usbintf->usbdev;
        struct efi_usb_endpoint *usbep;
        unsigned int index = USB_ENDPOINT_IDX ( endpoint );
        int mtu;
        EFI_STATUS efirc;
        int rc;

        /* Get endpoint MTU */
        mtu = efi_usb_mtu ( usbintf, endpoint );
        if ( mtu < 0 ) {
                rc = mtu;
                goto err_mtu;
        }

        /* Allocate and initialise structure */
        usbep = zalloc ( sizeof ( *usbep ) );
        if ( ! usbep ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        usbep->usbintf = usbintf;
        usb_endpoint_init ( &usbep->ep, usbdev->usb, driver );
        usb_endpoint_describe ( &usbep->ep, endpoint, attributes, mtu, 0,
                                ( interval << 3 /* microframes */ ) );

        /* Open endpoint */
        if ( ( rc = usb_endpoint_open ( &usbep->ep ) ) != 0 ) {
                DBGC ( usbdev, "USBDEV %s %s could not open: %s\n",
                       usbintf->name, usb_endpoint_name ( &usbep->ep ),
                       strerror ( rc ) );
                goto err_open;
        }

        /* Record opened endpoint */
        usbintf->endpoint[index] = usbep;
        DBGC ( usbdev, "USBDEV %s %s opened\n",
               usbintf->name, usb_endpoint_name ( &usbep->ep ) );

        /* Create event */
        if ( ( efirc = bs->CreateEvent ( ( EVT_TIMER | EVT_NOTIFY_SIGNAL ),
                                         TPL_CALLBACK, efi_usb_timer, usbep,
                                         &usbep->event ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( usbdev, "USBDEV %s %s could not create event: %s\n",
                       usbintf->name, usb_endpoint_name ( &usbep->ep ),
                       strerror ( rc ) );
                goto err_event;
        }

        return 0;

        bs->CloseEvent ( usbep->event );
 err_event:
        usbintf->endpoint[index] = usbep;
        usb_endpoint_close ( &usbep->ep );
 err_open:
        free ( usbep );
 err_alloc:
 err_mtu:
        return rc;
}
static void efi_usb_close ( struct efi_usb_endpoint usbep) [static]

Close endpoint.

Parameters:
usbepEFI USB endpoint

Definition at line 202 of file efi_usb.c.

References usb_endpoint::address, assert, EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseEvent, DBGC, efi_systab, efi_usb_interface::endpoint, efi_usb_endpoint::ep, efi_usb_endpoint::event, free, index, efi_usb_interface::name, NULL, EFI_BOOT_SERVICES::SetTimer, TimerCancel, usb_endpoint_close(), USB_ENDPOINT_IDX, usb_endpoint_name(), efi_usb_interface::usbdev, and efi_usb_endpoint::usbintf.

Referenced by efi_usb_async_start(), efi_usb_async_stop(), efi_usb_close_all(), and efi_usb_sync_transfer().

                                                             {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_interface *usbintf = usbep->usbintf;
        struct efi_usb_device *usbdev = usbintf->usbdev;
        unsigned int index = USB_ENDPOINT_IDX ( usbep->ep.address );

        /* Sanity check */
        assert ( usbintf->endpoint[index] == usbep );

        /* Cancel timer (if applicable) and close event */
        bs->SetTimer ( usbep->event, TimerCancel, 0 );
        bs->CloseEvent ( usbep->event );

        /* Close endpoint */
        usb_endpoint_close ( &usbep->ep );
        DBGC ( usbdev, "USBDEV %s %s closed\n",
               usbintf->name, usb_endpoint_name ( &usbep->ep ) );

        /* Free endpoint */
        free ( usbep );

        /* Record closed endpoint */
        usbintf->endpoint[index] = NULL;
}
static void efi_usb_close_all ( struct efi_usb_interface usbintf) [static]

Close all endpoints.

Parameters:
usbintfEFI USB interface

Definition at line 232 of file efi_usb.c.

References efi_usb_close(), and efi_usb_interface::endpoint.

Referenced by efi_usb_control_transfer(), efi_usb_install(), and efi_usb_uninstall().

                                                                    {
        struct efi_usb_endpoint *usbep;
        unsigned int i;

        for ( i = 0 ; i < ( sizeof ( usbintf->endpoint ) /
                            sizeof ( usbintf->endpoint[0] ) ) ; i++ ) {
                usbep = usbintf->endpoint[i];
                if ( usbep )
                        efi_usb_close ( usbep );
        }
}
static void efi_usb_sync_complete ( struct usb_endpoint ep,
struct io_buffer *iobuf  __unused,
int  rc 
) [static]

Complete synchronous transfer.

Parameters:
epUSB endpoint
iobufI/O buffer
rcCompletion status code

Definition at line 251 of file efi_usb.c.

References container_of, efi_usb_endpoint::rc, and rc.

                                                                               {
        struct efi_usb_endpoint *usbep =
                container_of ( ep, struct efi_usb_endpoint, ep );

        /* Record completion status */
        usbep->rc = rc;
}
static int efi_usb_sync_transfer ( struct efi_usb_interface usbintf,
unsigned int  endpoint,
unsigned int  attributes,
unsigned int  timeout,
void *  data,
size_t len 
) [static]

Perform synchronous transfer.

Parameters:
usbintfUSB endpoint
endpointEndpoint address
attributesEndpoint attributes
timeoutTimeout (in milliseconds)
dataData buffer
lenLength of data buffer
Return values:
rcReturn status code

Definition at line 276 of file efi_usb.c.

References alloc_iob(), assert, usb_hub::bus, io_buffer::data, DBGC, efi_usb_close(), efi_usb_open(), EFIRC, EINPROGRESS, efi_usb_interface::endpoint, ENOMEM, efi_usb_endpoint::ep, ETIMEDOUT, free_iob(), usb_port::hub, index, iob_len(), iob_put, mdelay(), memcpy(), efi_usb_interface::name, usb_device::port, efi_usb_endpoint::rc, rc, strerror(), efi_usb_device::usb, USB_ENDPOINT_IDX, USB_ENDPOINT_IN, usb_endpoint_name(), usb_poll(), usb_stream(), and efi_usb_interface::usbdev.

Referenced by efi_usb_bulk_transfer(), and efi_usb_sync_interrupt_transfer().

                                                             {
        struct efi_usb_device *usbdev = usbintf->usbdev;
        struct efi_usb_endpoint *usbep;
        struct io_buffer *iobuf;
        unsigned int index = USB_ENDPOINT_IDX ( endpoint );
        unsigned int i;
        int rc;

        /* Open endpoint, if applicable */
        if ( ( ! usbintf->endpoint[index] ) &&
             ( ( rc = efi_usb_open ( usbintf, endpoint, attributes, 0,
                                     &efi_usb_sync_driver ) ) != 0 ) ) {
                goto err_open;
        }
        usbep = usbintf->endpoint[index];

        /* Allocate and construct I/O buffer */
        iobuf = alloc_iob ( *len );
        if ( ! iobuf ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        iob_put ( iobuf, *len );
        if ( ! ( endpoint & USB_ENDPOINT_IN ) )
                memcpy ( iobuf->data, data, *len );

        /* Initialise completion status */
        usbep->rc = -EINPROGRESS;

        /* Enqueue transfer */
        if ( ( rc = usb_stream ( &usbep->ep, iobuf, 0 ) ) != 0 ) {
                DBGC ( usbdev, "USBDEV %s %s could not enqueue: %s\n",
                       usbintf->name, usb_endpoint_name ( &usbep->ep ),
                       strerror ( rc ) );
                goto err_stream;
        }

        /* Wait for completion */
        rc = -ETIMEDOUT;
        for ( i = 0 ; ( ( timeout == 0 ) || ( i < timeout ) ) ; i++ ) {

                /* Poll bus */
                usb_poll ( usbdev->usb->port->hub->bus );

                /* Check for completion */
                if ( usbep->rc != -EINPROGRESS ) {
                        rc = usbep->rc;
                        break;
                }

                /* Delay */
                mdelay ( 1 );
        }

        /* Check for errors */
        if ( rc != 0 ) {
                DBGC ( usbdev, "USBDEV %s %s failed: %s\n", usbintf->name,
                       usb_endpoint_name ( &usbep->ep ), strerror ( rc ) );
                goto err_completion;
        }

        /* Copy completion to data buffer, if applicable */
        assert ( iob_len ( iobuf ) <= *len );
        if ( endpoint & USB_ENDPOINT_IN )
                memcpy ( data, iobuf->data, iob_len ( iobuf ) );
        *len = iob_len ( iobuf );

        /* Free I/O buffer */
        free_iob ( iobuf );

        /* Leave endpoint open */
        return 0;

 err_completion:
 err_stream:
        free_iob ( iobuf );
 err_alloc:
        efi_usb_close ( usbep );
 err_open:
        return EFIRC ( rc );
}
static void efi_usb_async_complete ( struct usb_endpoint ep,
struct io_buffer iobuf,
int  rc 
) [static]

Complete asynchronous transfer.

Parameters:
epUSB endpoint
iobufI/O buffer
rcCompletion status code

Definition at line 369 of file efi_usb.c.

References efi_usb_endpoint::callback, container_of, efi_usb_endpoint::context, io_buffer::data, EFI_USB_ERR_STALL, efi_usb_endpoint::ep, iob_len(), usb_endpoint::open, status, and usb_recycle().

                                                                       {
        struct efi_usb_endpoint *usbep =
                container_of ( ep, struct efi_usb_endpoint, ep );
        UINT32 status;

        /* Ignore packets cancelled when the endpoint closes */
        if ( ! ep->open )
                goto drop;

        /* Construct status */
        status = ( ( rc == 0 ) ? 0 : EFI_USB_ERR_STALL );

        /* Report completion */
        usbep->callback ( iobuf->data, iob_len ( iobuf ), usbep->context,
                          status );

 drop:
        /* Recycle I/O buffer */
        usb_recycle ( &usbep->ep, iobuf );
}
static int efi_usb_async_start ( struct efi_usb_interface usbintf,
unsigned int  endpoint,
unsigned int  interval,
size_t  len,
EFI_ASYNC_USB_TRANSFER_CALLBACK  callback,
void *  context 
) [static]

Start asynchronous transfer.

Parameters:
usbintfEFI USB interface
endpointEndpoint address
intervalInterval (in milliseconds)
lenTransfer length
callbackCallback function
contextContext for callback function
Return values:
rcReturn status code

Definition at line 407 of file efi_usb.c.

References EFI_SYSTEM_TABLE::BootServices, efi_usb_endpoint::callback, efi_usb_endpoint::context, context, DBGC, EEFI, efi_systab, EFI_USB_ASYNC_FILL, efi_usb_close(), efi_usb_open(), efi_usb_interface::endpoint, efi_usb_endpoint::ep, efi_usb_endpoint::event, index, efi_usb_interface::name, rc, EFI_BOOT_SERVICES::SetTimer, strerror(), TimerCancel, TimerPeriodic, USB_ENDPOINT_ATTR_INTERRUPT, USB_ENDPOINT_IDX, usb_endpoint_name(), usb_prefill(), usb_refill_init(), and efi_usb_interface::usbdev.

Referenced by efi_usb_async_interrupt_transfer().

                                                 {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_device *usbdev = usbintf->usbdev;
        struct efi_usb_endpoint *usbep;
        unsigned int index = USB_ENDPOINT_IDX ( endpoint );
        EFI_STATUS efirc;
        int rc;

        /* Open endpoint */
        if ( ( rc = efi_usb_open ( usbintf, endpoint,
                                   USB_ENDPOINT_ATTR_INTERRUPT, interval,
                                   &efi_usb_async_driver ) ) != 0 )
                goto err_open;
        usbep = usbintf->endpoint[index];

        /* Record callback parameters */
        usbep->callback = callback;
        usbep->context = context;

        /* Prefill endpoint */
        usb_refill_init ( &usbep->ep, 0, len, EFI_USB_ASYNC_FILL );
        if ( ( rc = usb_prefill ( &usbep->ep ) ) != 0 ) {
                DBGC ( usbdev, "USBDEV %s %s could not prefill: %s\n",
                       usbintf->name, usb_endpoint_name ( &usbep->ep ),
                       strerror ( rc ) );
                goto err_prefill;
        }

        /* Start timer */
        if ( ( efirc = bs->SetTimer ( usbep->event, TimerPeriodic,
                                      ( interval * 10000 ) ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( usbdev, "USBDEV %s %s could not set timer: %s\n",
                       usbintf->name, usb_endpoint_name ( &usbep->ep ),
                       strerror ( rc ) );
                goto err_timer;
        }

        return 0;

        bs->SetTimer ( usbep->event, TimerCancel, 0 );
 err_timer:
 err_prefill:
        efi_usb_close ( usbep );
 err_open:
        return rc;
}
static void efi_usb_async_stop ( struct efi_usb_interface usbintf,
unsigned int  endpoint 
) [static]

Stop asynchronous transfer.

Parameters:
usbintfEFI USB interface
endpointEndpoint address

Definition at line 465 of file efi_usb.c.

References EFI_SYSTEM_TABLE::BootServices, efi_systab, efi_usb_close(), efi_usb_interface::endpoint, efi_usb_endpoint::event, index, EFI_BOOT_SERVICES::SetTimer, TimerCancel, and USB_ENDPOINT_IDX.

Referenced by efi_usb_async_interrupt_transfer().

                                                         {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_endpoint *usbep;
        unsigned int index = USB_ENDPOINT_IDX ( endpoint );

        /* Do nothing if endpoint is already closed */
        usbep = usbintf->endpoint[index];
        if ( ! usbep )
                return;

        /* Stop timer */
        bs->SetTimer ( usbep->event, TimerCancel, 0 );

        /* Close endpoint */
        efi_usb_close ( usbep );
}
static EFI_STATUS EFIAPI efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL usbio,
EFI_USB_DEVICE_REQUEST packet,
EFI_USB_DATA_DIRECTION  direction,
UINT32  timeout,
VOID data,
UINTN  len,
UINT32 status 
) [static]

Perform control transfer.

Parameters:
usbioUSB I/O protocol
packetSetup packet
directionData direction
timeoutTimeout (in milliseconds)
dataData buffer
lenLength of data
Return values:
statusTransfer status
efircEFI status code

Definition at line 503 of file efi_usb.c.

References efi_usb_interface::alternate, EFI_SYSTEM_TABLE::BootServices, efi_usb_device::config, usb_configuration_descriptor::config, container_of, DBGC, DBGC2, efi_systab, efi_usb_close_all(), efi_usb_direction_name(), EFI_USB_ERR_STALL, EFIRC, ENOTSUP, USB_DEVICE_REQUEST::Index, index, le16_to_cpu, USB_DEVICE_REQUEST::Length, efi_usb_interface::name, EFI_BOOT_SERVICES::RaiseTPL, rc, USB_DEVICE_REQUEST::Request, request, USB_DEVICE_REQUEST::RequestType, EFI_BOOT_SERVICES::RestoreTPL, strerror(), TPL_CALLBACK, efi_usb_device::usb, usb_control(), USB_REQUEST_TYPE, USB_SET_CONFIGURATION, USB_SET_INTERFACE, efi_usb_interface::usbdev, USB_DEVICE_REQUEST::Value, and value.

                                            {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;
        unsigned int request = ( packet->RequestType |
                                 USB_REQUEST_TYPE ( packet->Request ) );
        unsigned int value = le16_to_cpu ( packet->Value );
        unsigned int index = le16_to_cpu ( packet->Index );
        EFI_TPL saved_tpl;
        int rc;

        DBGC2 ( usbdev, "USBDEV %s control %04x:%04x:%04x:%04x %s %dms "
                "%p+%zx\n", usbintf->name, request, value, index,
                le16_to_cpu ( packet->Length ),
                efi_usb_direction_name ( direction ), timeout, data,
                ( ( size_t ) len ) );

        /* Raise TPL */
        saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );

        /* Clear status */
        *status = 0;

        /* Block attempts to change the device configuration, since
         * this is logically impossible to do given the constraints of
         * the EFI_USB_IO_PROTOCOL design.
         */
        if ( ( request == USB_SET_CONFIGURATION ) &&
             ( value != usbdev->config->config ) ) {
                DBGC ( usbdev, "USBDEV %s cannot set configuration %d: not "
                       "logically possible\n", usbintf->name, index );
                rc = -ENOTSUP;
                goto err_change_config;
        }

        /* If we are selecting a new alternate setting then close all
         * open endpoints.
         */
        if ( ( request == USB_SET_INTERFACE ) &&
             ( value != usbintf->alternate ) )
                efi_usb_close_all ( usbintf );

        /* Issue control transfer */
        if ( ( rc = usb_control ( usbdev->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,
                       le16_to_cpu ( packet->Length ), data, ( ( size_t ) len ),
                       strerror ( rc ) );
                /* Assume that any error represents a stall */
                *status = EFI_USB_ERR_STALL;
                goto err_control;
        }

        /* Update alternate setting, if applicable */
        if ( request == USB_SET_INTERFACE ) {
                usbintf->alternate = value;
                DBGC ( usbdev, "USBDEV %s alt %d selected\n",
                       usbintf->name, usbintf->alternate );
        }

 err_control:
 err_change_config:
        bs->RestoreTPL ( saved_tpl );
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL usbio,
UINT8  endpoint,
VOID data,
UINTN len,
UINTN  timeout,
UINT32 status 
) [static]

Perform bulk transfer.

Parameters:
usbioUSB I/O protocol
endpointEndpoint address
dataData buffer
lenLength of data
timeoutTimeout (in milliseconds)
Return values:
statusTransfer status
efircEFI status code

Definition at line 587 of file efi_usb.c.

References EFI_SYSTEM_TABLE::BootServices, container_of, DBGC2, efi_systab, EFI_USB_ERR_TIMEOUT, efi_usb_sync_transfer(), EFIRC, len, efi_usb_interface::name, EFI_BOOT_SERVICES::RaiseTPL, rc, EFI_BOOT_SERVICES::RestoreTPL, TPL_CALLBACK, USB_ENDPOINT_ATTR_BULK, USB_ENDPOINT_IN, and efi_usb_interface::usbdev.

                                                                    {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;
        size_t actual = *len;
        EFI_TPL saved_tpl;
        int rc;

        DBGC2 ( usbdev, "USBDEV %s bulk %s %p+%zx %dms\n", usbintf->name,
                ( ( endpoint & USB_ENDPOINT_IN ) ? "IN" : "OUT" ), data,
                ( ( size_t ) *len ), ( ( unsigned int ) timeout ) );

        /* Raise TPL */
        saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );

        /* Clear status */
        *status = 0;

        /* Perform synchronous transfer */
        if ( ( rc = efi_usb_sync_transfer ( usbintf, endpoint,
                                            USB_ENDPOINT_ATTR_BULK, timeout,
                                            data, &actual ) ) != 0 ) {
                /* Assume that any error represents a timeout */
                *status = EFI_USB_ERR_TIMEOUT;
                goto err_transfer;
        }

 err_transfer:
        bs->RestoreTPL ( saved_tpl );
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL usbio,
UINT8  endpoint,
VOID data,
UINTN len,
UINTN  timeout,
UINT32 status 
) [static]

Perform synchronous interrupt transfer.

Parameters:
usbioUSB I/O protocol
endpointEndpoint address
dataData buffer
lenLength of data
timeoutTimeout (in milliseconds)
Return values:
statusTransfer status
efircEFI status code

Definition at line 633 of file efi_usb.c.

References EFI_SYSTEM_TABLE::BootServices, container_of, DBGC2, efi_systab, EFI_USB_ERR_TIMEOUT, efi_usb_sync_transfer(), EFIRC, len, efi_usb_interface::name, EFI_BOOT_SERVICES::RaiseTPL, rc, EFI_BOOT_SERVICES::RestoreTPL, TPL_CALLBACK, USB_ENDPOINT_ATTR_INTERRUPT, USB_ENDPOINT_IN, and efi_usb_interface::usbdev.

                                                   {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;
        size_t actual = *len;
        EFI_TPL saved_tpl;
        int rc;

        DBGC2 ( usbdev, "USBDEV %s sync intr %s %p+%zx %dms\n", usbintf->name,
                ( ( endpoint & USB_ENDPOINT_IN ) ? "IN" : "OUT" ), data,
                ( ( size_t ) *len ), ( ( unsigned int ) timeout ) );

        /* Raise TPL */
        saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );

        /* Clear status */
        *status = 0;

        /* Perform synchronous transfer */
        if ( ( rc = efi_usb_sync_transfer ( usbintf, endpoint,
                                            USB_ENDPOINT_ATTR_INTERRUPT,
                                            timeout, data, &actual ) ) != 0 ) {
                /* Assume that any error represents a timeout */
                *status = EFI_USB_ERR_TIMEOUT;
                goto err_transfer;
        }

 err_transfer:
        bs->RestoreTPL ( saved_tpl );
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL usbio,
UINT8  endpoint,
BOOLEAN  start,
UINTN  interval,
UINTN  len,
EFI_ASYNC_USB_TRANSFER_CALLBACK  callback,
VOID context 
) [static]

Perform asynchronous interrupt transfer.

Parameters:
usbioUSB I/O protocol
endpointEndpoint address
startStart (rather than stop) transfer
intervalPolling interval (in milliseconds)
lenData length
callbackCallback function
contextContext for callback function
Return values:
efircEFI status code

Definition at line 681 of file efi_usb.c.

References EFI_SYSTEM_TABLE::BootServices, container_of, DBGC2, efi_systab, efi_usb_async_start(), efi_usb_async_stop(), EFIRC, efi_usb_interface::name, EFI_BOOT_SERVICES::RaiseTPL, rc, EFI_BOOT_SERVICES::RestoreTPL, TPL_CALLBACK, USB_ENDPOINT_IN, and efi_usb_interface::usbdev.

                                                   {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;
        EFI_TPL saved_tpl;
        int rc;

        DBGC2 ( usbdev, "USBDEV %s async intr %s len %#zx int %d %p/%p\n",
                usbintf->name,
                ( ( endpoint & USB_ENDPOINT_IN ) ? "IN" : "OUT" ),
                ( ( size_t ) len ), ( ( unsigned int ) interval ),
                callback, context );

        /* Raise TPL */
        saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );

        /* Start/stop transfer as applicable */
        if ( start ) {

                /* Start new transfer */
                if ( ( rc = efi_usb_async_start ( usbintf, endpoint, interval,
                                                  len, callback,
                                                  context ) ) != 0 )
                        goto err_start;

        } else {

                /* Stop transfer */
                efi_usb_async_stop ( usbintf, endpoint );

                /* Success */
                rc = 0;

        }

 err_start:
        bs->RestoreTPL ( saved_tpl );
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_usb_isochronous_transfer ( EFI_USB_IO_PROTOCOL usbio,
UINT8  endpoint,
VOID data,
UINTN  len,
UINT32 status 
) [static]

Perform synchronous isochronous transfer.

Parameters:
usbioUSB I/O protocol
endpointEndpoint address
dataData buffer
lenLength of data
Return values:
statusTransfer status
efircEFI status code

Definition at line 736 of file efi_usb.c.

References container_of, DBGC2, EFI_UNSUPPORTED, efi_usb_interface::name, USB_ENDPOINT_IN, and efi_usb_interface::usbdev.

                                                                       {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;

        DBGC2 ( usbdev, "USBDEV %s sync iso %s %p+%zx\n", usbintf->name,
                ( ( endpoint & USB_ENDPOINT_IN ) ? "IN" : "OUT" ), data,
                ( ( size_t ) len ) );

        /* Clear status */
        *status = 0;

        /* Not supported */
        return EFI_UNSUPPORTED;
}
static EFI_STATUS EFIAPI efi_usb_async_isochronous_transfer ( EFI_USB_IO_PROTOCOL usbio,
UINT8  endpoint,
VOID data,
UINTN  len,
EFI_ASYNC_USB_TRANSFER_CALLBACK  callback,
VOID context 
) [static]

Perform asynchronous isochronous transfers.

Parameters:
usbioUSB I/O protocol
endpointEndpoint address
dataData buffer
lenLength of data
callbackCallback function
contextContext for callback function
Return values:
statusTransfer status
efircEFI status code

Definition at line 766 of file efi_usb.c.

References container_of, DBGC2, EFI_UNSUPPORTED, efi_usb_interface::name, USB_ENDPOINT_IN, and efi_usb_interface::usbdev.

                                                     {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;

        DBGC2 ( usbdev, "USBDEV %s async iso %s %p+%zx %p/%p\n", usbintf->name,
                ( ( endpoint & USB_ENDPOINT_IN ) ? "IN" : "OUT" ), data,
                ( ( size_t ) len ), callback, context );

        /* Not supported */
        return EFI_UNSUPPORTED;
}

Get device descriptor.

Parameters:
usbioUSB I/O protocol
Return values:
efidescEFI device descriptor
efircEFI status code

Definition at line 790 of file efi_usb.c.

References container_of, DBGC2, usb_device::device, memcpy(), efi_usb_interface::name, efi_usb_device::usb, and efi_usb_interface::usbdev.

                                                                     {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;

        DBGC2 ( usbdev, "USBDEV %s get device descriptor\n", usbintf->name );

        /* Copy cached device descriptor */
        memcpy ( efidesc, &usbdev->usb->device, sizeof ( *efidesc ) );

        return 0;
}

Get configuration descriptor.

Parameters:
usbioUSB I/O protocol
Return values:
efidescEFI interface descriptor
efircEFI status code

Definition at line 812 of file efi_usb.c.

References efi_usb_device::config, container_of, DBGC2, memcpy(), efi_usb_interface::name, and efi_usb_interface::usbdev.

                                                                     {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;

        DBGC2 ( usbdev, "USBDEV %s get configuration descriptor\n",
                usbintf->name );

        /* Copy cached configuration descriptor */
        memcpy ( efidesc, usbdev->config, sizeof ( *efidesc ) );

        return 0;
}

Get interface descriptor.

Parameters:
usbioUSB I/O protocol
Return values:
efidescEFI interface descriptor
efircEFI status code

Definition at line 835 of file efi_usb.c.

References efi_usb_interface::alternate, efi_usb_device::config, container_of, DBGC, DBGC2, ENOENT, efi_usb_interface::interface, memcpy(), efi_usb_interface::name, usb_interface_descriptor(), and efi_usb_interface::usbdev.

                                                                           {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;
        struct usb_interface_descriptor *desc;

        DBGC2 ( usbdev, "USBDEV %s get interface descriptor\n", usbintf->name );

        /* Locate cached interface descriptor */
        desc = usb_interface_descriptor ( usbdev->config, usbintf->interface,
                                          usbintf->alternate );
        if ( ! desc ) {
                DBGC ( usbdev, "USBDEV %s alt %d has no interface descriptor\n",
                       usbintf->name, usbintf->alternate );
                return -ENOENT;
        }

        /* Copy cached interface descriptor */
        memcpy ( efidesc, desc, sizeof ( *efidesc ) );

        return 0;
}

Get endpoint descriptor.

Parameters:
usbioUSB I/O protocol
addressEndpoint index
Return values:
efidescEFI interface descriptor
efircEFI status code

Definition at line 868 of file efi_usb.c.

References usb_interface_descriptor::alternate, container_of, DBGC, DBGC2, ENOENT, for_each_interface_descriptor, usb_endpoint_descriptor::header, usb_interface_descriptor::interface, memcpy(), efi_usb_interface::name, usb_interface_descriptor::name, usb_descriptor_header::type, and efi_usb_interface::usbdev.

                                                                         {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;
        struct usb_interface_descriptor *interface;
        struct usb_endpoint_descriptor *desc;

        DBGC2 ( usbdev, "USBDEV %s get endpoint %d descriptor\n",
                usbintf->name, index );

        /* Locate cached interface descriptor */
        interface = usb_interface_descriptor ( usbdev->config,
                                               usbintf->interface,
                                               usbintf->alternate );
        if ( ! interface ) {
                DBGC ( usbdev, "USBDEV %s alt %d has no interface descriptor\n",
                       usbintf->name, usbintf->alternate );
                return -ENOENT;
        }

        /* Locate and copy cached endpoint descriptor */
        for_each_interface_descriptor ( desc, usbdev->config, interface ) {
                if ( ( desc->header.type == USB_ENDPOINT_DESCRIPTOR ) &&
                     ( index-- == 0 ) ) {
                        memcpy ( efidesc, desc, sizeof ( *efidesc ) );
                        return 0;
                }
        }
        return -ENOENT;
}
static EFI_STATUS EFIAPI efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL usbio,
UINT16  language,
UINT8  index,
CHAR16 **  string 
) [static]

Get string descriptor.

Parameters:
usbioUSB I/O protocol
languageLanguage ID
indexString index
Return values:
stringString
efircEFI status code

Definition at line 910 of file efi_usb.c.

References EFI_BOOT_SERVICES::AllocatePool, EFI_SYSTEM_TABLE::BootServices, buffer, container_of, DBGC, DBGC2, EEFI, efi_systab, EfiBootServicesData, EFIRC, EFI_BOOT_SERVICES::FreePool, usb_descriptor_header::len, len, memmove(), memset(), efi_usb_interface::name, EFI_BOOT_SERVICES::RaiseTPL, rc, EFI_BOOT_SERVICES::RestoreTPL, strerror(), TPL_CALLBACK, efi_usb_device::usb, usb_get_descriptor(), USB_STRING_DESCRIPTOR, efi_usb_interface::usbdev, and VOID.

                                                               {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;
        struct usb_descriptor_header header;
        VOID *buffer;
        size_t len;
        EFI_TPL saved_tpl;
        EFI_STATUS efirc;
        int rc;

        DBGC2 ( usbdev, "USBDEV %s get string %d:%d descriptor\n",
                usbintf->name, language, index );

        /* Raise TPL */
        saved_tpl = bs->RaiseTPL ( TPL_CALLBACK );

        /* Read descriptor header */
        if ( ( rc = usb_get_descriptor ( usbdev->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,
                       index, strerror ( rc ) );
                goto err_get_header;
        }
        len = header.len;

        /* Allocate buffer */
        if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, len,
                                          &buffer ) ) != 0 ) {
                rc = -EEFI ( efirc );
                goto err_alloc;
        }

        /* Read whole descriptor */
        if ( ( rc = usb_get_descriptor ( usbdev->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 ) );
                goto err_get_descriptor;
        }

        /* Shuffle down and terminate string */
        memmove ( buffer, ( buffer + sizeof ( header ) ),
                  ( len - sizeof ( header ) ) );
        memset ( ( buffer + len - sizeof ( header ) ), 0, sizeof ( **string ) );

        /* Restore TPL */
        bs->RestoreTPL ( saved_tpl );

        /* Return allocated string */
        *string = buffer;
        return 0;

 err_get_descriptor:
        bs->FreePool ( buffer );
 err_alloc:
 err_get_header:
        bs->RestoreTPL ( saved_tpl );
        return EFIRC ( rc );
}
static EFI_STATUS EFIAPI efi_usb_get_supported_languages ( EFI_USB_IO_PROTOCOL usbio,
UINT16 **  languages,
UINT16 len 
) [static]

Get supported languages.

Parameters:
usbioUSB I/O protocol
Return values:
languagesLanguage ID table
lenLength of language ID table
efircEFI status code

Definition at line 986 of file efi_usb.c.

References container_of, DBGC2, efi_usb_device::languages, usb_descriptor_header::len, efi_usb_interface::name, and efi_usb_interface::usbdev.

                                                                    {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;

        DBGC2 ( usbdev, "USBDEV %s get supported languages\n", usbintf->name );

        /* Return cached supported languages */
        *languages = ( ( ( void * ) usbdev->languages ) +
                       sizeof ( *(usbdev->languages) ) );
        *len = usbdev->languages->len;

        return 0;
}

Reset port.

Parameters:
usbioUSB I/O protocol
Return values:
efircEFI status code

Definition at line 1009 of file efi_usb.c.

References container_of, DBGC2, EFI_INVALID_PARAMETER, efi_usb_interface::name, and efi_usb_interface::usbdev.

                                                  {
        struct efi_usb_interface *usbintf =
                container_of ( usbio, struct efi_usb_interface, usbio );
        struct efi_usb_device *usbdev = usbintf->usbdev;

        DBGC2 ( usbdev, "USBDEV %s reset port\n", usbintf->name );

        /* This is logically impossible to do, since resetting the
         * port may destroy state belonging to other
         * EFI_USB_IO_PROTOCOL instances belonging to the same USB
         * device.  (This is yet another artifact of the incredibly
         * poor design of the EFI_USB_IO_PROTOCOL.)
         */
        return EFI_INVALID_PARAMETER;
}
static int efi_usb_install ( struct efi_usb_device usbdev,
unsigned int  interface 
) [static]

Install interface.

Parameters:
usbdevEFI USB device
interfaceInterface number
Return values:
rcReturn status code

Definition at line 1056 of file efi_usb.c.

References usb_port::address, EFI_SYSTEM_TABLE::BootServices, DBGC, EEFI, efi_device_path_protocol_guid, efi_devpath_len(), efi_handle_name(), efi_systab, efi_usb_close_all(), efi_usb_io_protocol_guid, efi_usb_device::efidev, END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, ENOMEM, free, efi_usb_interface::handle, USB_DEVICE_PATH::Header, usb_port::hub, EFI_BOOT_SERVICES::InstallMultipleProtocolInterfaces, efi_usb_interface::interface, USB_DEVICE_PATH::InterfaceNumber, efi_usb_device::interfaces, EFI_DEVICE_PATH_PROTOCOL::Length, efi_usb_interface::list, list_add_tail, list_del, memcpy(), MESSAGING_DEVICE_PATH, MSG_USB_DP, efi_usb_device::name, efi_usb_interface::name, NULL, USB_DEVICE_PATH::ParentPortNumber, efi_device::path, efi_usb_interface::path, usb_device::port, rc, snprintf(), strerror(), EFI_DEVICE_PATH_PROTOCOL::SubType, EFI_DEVICE_PATH_PROTOCOL::Type, EFI_BOOT_SERVICES::UninstallMultipleProtocolInterfaces, efi_usb_device::usb, usb_hub::usb, usb_depth(), efi_usb_interface::usbdev, efi_usb_interface::usbio, and zalloc().

Referenced by efi_usb_probe().

                                                      {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_device *efidev = usbdev->efidev;
        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_devpath_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 );
        if ( ! usbintf ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        snprintf ( usbintf->name, sizeof ( usbintf->name ), "%s[%d]",
                   usbdev->name, interface );
        usbintf->usbdev = 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;
        }

        /* Add to list of interfaces */
        list_add_tail ( &usbintf->list, &usbdev->interfaces );

        /* Install protocols */
        if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
                        &usbintf->handle,
                        &efi_usb_io_protocol_guid, &usbintf->usbio,
                        &efi_device_path_protocol_guid, usbintf->path,
                        NULL ) ) != 0 ) {
                rc = -EEFI ( efirc );
                DBGC ( usbdev, "USBDEV %s could not install protocols: %s\n",
                       usbintf->name, strerror ( rc ) );
                goto err_install_protocol;
        }

        DBGC ( usbdev, "USBDEV %s installed as %s\n",
               usbintf->name, efi_handle_name ( usbintf->handle ) );
        return 0;

        efi_usb_close_all ( usbintf );
        bs->UninstallMultipleProtocolInterfaces (
                        usbintf->handle,
                        &efi_usb_io_protocol_guid, &usbintf->usbio,
                        &efi_device_path_protocol_guid, usbintf->path,
                        NULL );
 err_install_protocol:
        list_del ( &usbintf->list );
        free ( usbintf );
 err_alloc:
        return rc;
}
static void efi_usb_uninstall ( struct efi_usb_interface usbintf) [static]

Uninstall interface.

Parameters:
usbintfEFI USB interface

Definition at line 1143 of file efi_usb.c.

References EFI_SYSTEM_TABLE::BootServices, efi_device_path_protocol_guid, efi_systab, efi_usb_close_all(), efi_usb_io_protocol_guid, free, efi_usb_interface::handle, efi_usb_interface::list, list_del, NULL, efi_usb_interface::path, EFI_BOOT_SERVICES::UninstallMultipleProtocolInterfaces, and efi_usb_interface::usbio.

Referenced by efi_usb_uninstall_all().

                                                                    {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;

        /* Close all endpoints */
        efi_usb_close_all ( usbintf );

        /* Uninstall protocols */
        bs->UninstallMultipleProtocolInterfaces (
                        usbintf->handle,
                        &efi_usb_io_protocol_guid, &usbintf->usbio,
                        &efi_device_path_protocol_guid, usbintf->path,
                        NULL );

        /* Remove from list of interfaces */
        list_del ( &usbintf->list );

        /* Free interface */
        free ( usbintf );
}
static void efi_usb_uninstall_all ( struct efi_usb_device efiusb) [static]

Uninstall all interfaces.

Parameters:
usbdevEFI USB device

Definition at line 1168 of file efi_usb.c.

References efi_usb_uninstall(), efi_usb_device::interfaces, efi_usb_interface::list, and list_first_entry.

Referenced by efi_usb_probe(), and efi_usb_remove().

                                                                    {
        struct efi_usb_interface *usbintf;

        /* Uninstall all interfaces */
        while ( ( usbintf = list_first_entry ( &efiusb->interfaces,
                                               struct efi_usb_interface,
                                               list ) ) ) {
                efi_usb_uninstall ( usbintf );
        }
}
static int efi_usb_probe ( struct usb_function func,
struct usb_configuration_descriptor config 
) [static]

Probe device.

Parameters:
funcUSB function
configConfiguration descriptor
Return values:
rcReturn status code

Definition at line 1186 of file efi_usb.c.

References assert, EFI_SYSTEM_TABLE::BootServices, efi_usb_device::config, EFI_BOOT_SERVICES::ConnectController, usb_function_descriptor::count, DBGC, usb_function::desc, usb_function::dev, efi_systab, efi_usb_install(), efi_usb_uninstall_all(), efi_usb_device::efidev, efidev_parent(), ENOMEM, ENOTTY, free, efi_usb_interface::handle, INIT_LIST_HEAD, usb_function::interface, efi_usb_device::interfaces, efi_usb_device::languages, le16_to_cpu, usb_descriptor_header::len, usb_configuration_descriptor::len, list_empty, list_for_each_entry, memcpy(), efi_usb_device::name, usb_function::name, NULL, rc, strerror(), TRUE, efi_usb_device::usb, usb_function::usb, usb_func_set_drvdata(), usb_get_descriptor(), USB_STRING_DESCRIPTOR, and zalloc().

                                                                         {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        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;
        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 );

        /* Get supported languages descriptor header */
        if ( ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, 0, 0,
                                         &header, sizeof ( header ) ) ) != 0 ) {
                /* Assume no strings are present */
                header.len = 0;
        }

        /* Allocate and initialise structure */
        usbdev = zalloc ( sizeof ( *usbdev ) + config_len + header.len );
        if ( ! usbdev ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        usb_func_set_drvdata ( func, usbdev );
        usbdev->name = func->name;
        usbdev->usb = usb;
        usbdev->efidev = efidev;
        usbdev->config = ( ( ( void * ) usbdev ) + sizeof ( *usbdev ) );
        memcpy ( usbdev->config, config, config_len );
        usbdev->languages = ( ( ( void * ) usbdev->config ) + config_len );
        INIT_LIST_HEAD ( &usbdev->interfaces );

        /* Get supported languages descriptor */
        if ( header.len &&
             ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, 0, 0,
                                         usbdev->languages,
                                         header.len ) ) != 0 ) {
                DBGC ( usbdev, "USBDEV %s could not get supported languages: "
                       "%s\n", usbdev->name, strerror ( rc ) );
                goto err_get_languages;
        }

        /* Install interfaces */
        for ( i = 0 ; i < func->desc.count ; i++ ) {
                if ( ( rc = efi_usb_install ( usbdev,
                                              func->interface[i] ) ) != 0 )
                        goto err_install;
        }

        /* Connect any external drivers */
        list_for_each_entry ( usbintf, &usbdev->interfaces, list )
                bs->ConnectController ( usbintf->handle, NULL, NULL, TRUE );

        return 0;

 err_install:
        efi_usb_uninstall_all ( usbdev );
        assert ( list_empty ( &usbdev->interfaces ) );
 err_get_languages:
        free ( usbdev );
 err_alloc:
 err_no_efidev:
        return rc;
}
static void efi_usb_remove ( struct usb_function func) [static]

Remove device.

Parameters:
funcUSB function

Definition at line 1268 of file efi_usb.c.

References assert, efi_usb_uninstall_all(), free, efi_usb_device::interfaces, list_empty, and usb_func_get_drvdata().

                                                         {
        struct efi_usb_device *usbdev = usb_func_get_drvdata ( func );

        /* Uninstall all interfaces */
        efi_usb_uninstall_all ( usbdev );
        assert ( list_empty ( &usbdev->interfaces ) );

        /* Free device */
        free ( usbdev );
}

Variable Documentation

Initial value:
 {
        .complete = efi_usb_sync_complete,
}

Synchronous endpoint operations.

Definition at line 261 of file efi_usb.c.

Initial value:
 {
        .complete = efi_usb_async_complete,
}

Asynchronous endpoint operations.

Definition at line 392 of file efi_usb.c.

Initial value:
 {
        .UsbControlTransfer             = efi_usb_control_transfer,
        .UsbBulkTransfer                = efi_usb_bulk_transfer,
        .UsbAsyncInterruptTransfer      = efi_usb_async_interrupt_transfer,
        .UsbSyncInterruptTransfer       = efi_usb_sync_interrupt_transfer,
        .UsbIsochronousTransfer         = efi_usb_isochronous_transfer,
        .UsbAsyncIsochronousTransfer    = efi_usb_async_isochronous_transfer,
        .UsbGetDeviceDescriptor         = efi_usb_get_device_descriptor,
        .UsbGetConfigDescriptor         = efi_usb_get_config_descriptor,
        .UsbGetInterfaceDescriptor      = efi_usb_get_interface_descriptor,
        .UsbGetEndpointDescriptor       = efi_usb_get_endpoint_descriptor,
        .UsbGetStringDescriptor         = efi_usb_get_string_descriptor,
        .UsbGetSupportedLanguages       = efi_usb_get_supported_languages,
        .UsbPortReset                   = efi_usb_port_reset,
}

USB I/O protocol.

Definition at line 1026 of file efi_usb.c.

struct usb_device_id efi_usb_ids[] [static]
Initial value:
 {
        {
                .name = "usbio",
                .vendor = USB_ANY_ID,
                .product = USB_ANY_ID,
        },
}

USB I/O protocol device IDs.

Definition at line 1280 of file efi_usb.c.

struct usb_driver usbio_driver __usb_driver
Initial value:
 {
        .ids = efi_usb_ids,
        .id_count = ( sizeof ( efi_usb_ids ) / sizeof ( efi_usb_ids[0] ) ),
        .class = USB_CLASS_ID ( USB_ANY_ID, USB_ANY_ID, USB_ANY_ID ),
        .score = USB_SCORE_FALLBACK,
        .probe = efi_usb_probe,
        .remove = efi_usb_remove,
}

USB I/O protocol driver.

Definition at line 1289 of file efi_usb.c.