Home | History | Annotate | Download | only in AndroidFastbootTransportUsbDxe
      1 /** @file
      2 
      3   Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
      4 
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 /*
     16  * Implementation of the FASTBOOT_TRANSPORT_PROTOCOL using the USB_DEVICE_PROTOCOL
     17  */
     18 
     19 #include <Protocol/UsbDevice.h>
     20 #include <Protocol/AndroidFastbootTransport.h>
     21 #include <Protocol/SimpleTextOut.h>
     22 
     23 #include <Library/BaseLib.h>
     24 #include <Library/BaseMemoryLib.h>
     25 #include <Library/DebugLib.h>
     26 #include <Library/MemoryAllocationLib.h>
     27 #include <Library/UefiBootServicesTableLib.h>
     28 #include <Library/UefiDriverEntryPoint.h>
     29 
     30 STATIC USB_DEVICE_PROTOCOL *mUsbDevice;
     31 
     32 // Configuration attributes:
     33 // bit 7 reserved and must be 1, bit 6 means self-powered.
     34 #define CONFIG_DESC_ATTRIBUTES      (BIT7 | BIT6)
     35 
     36 #define MAX_PACKET_SIZE_BULK        512
     37 
     38 STATIC USB_DEVICE_PROTOCOL  *mUsbDevice;
     39 STATIC EFI_EVENT             mReceiveEvent = NULL;
     40 STATIC LIST_ENTRY            mPacketList;
     41 
     42 // List type for queued received packets
     43 typedef struct _FASTBOOT_USB_PACKET_LIST {
     44   LIST_ENTRY  Link;
     45   VOID       *Buffer;
     46   UINTN       BufferSize;
     47 } FASTBOOT_USB_PACKET_LIST;
     48 
     49 
     50 /*
     51   No string descriptors - all string descriptor members are set to 0
     52 */
     53 
     54 STATIC USB_DEVICE_DESCRIPTOR mDeviceDescriptor = {
     55   sizeof (USB_DEVICE_DESCRIPTOR),                  //Length
     56   USB_DESC_TYPE_DEVICE,                            //DescriptorType
     57   0x0200,                                          //BcdUSB
     58   0xFF,                                            //DeviceClass
     59   0,                                               //DeviceSubClass
     60   0,                                               //DeviceProtocol
     61   64,                                              //MaxPacketSize0
     62   FixedPcdGet32 (PcdAndroidFastbootUsbVendorId),   //IdVendor
     63   FixedPcdGet32 (PcdAndroidFastbootUsbProductId),  //IdProduct
     64   0,                                               //BcdDevice
     65   0,                                               //StrManufacturer
     66   0,                                               //StrProduct
     67   0,                                               //StrSerialNumber
     68   1                                                //NumConfigurations
     69 };
     70 
     71 /*
     72   We have one configuration, one interface, and two endpoints (one IN, one OUT)
     73 */
     74 
     75 // Lazy (compile-time) way to concatenate descriptors to pass to the USB device
     76 // protocol
     77 
     78 #pragma pack(1)
     79 typedef struct {
     80   USB_CONFIG_DESCRIPTOR     ConfigDescriptor;
     81   USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
     82   USB_ENDPOINT_DESCRIPTOR   EndpointDescriptor1;
     83   USB_ENDPOINT_DESCRIPTOR   EndpointDescriptor2;
     84 } GET_CONFIG_DESCRIPTOR_RESPONSE;
     85 #pragma pack()
     86 
     87 STATIC GET_CONFIG_DESCRIPTOR_RESPONSE mGetConfigDescriptorResponse = {
     88   { // USB_CONFIG_DESCRIPTOR
     89     sizeof (USB_CONFIG_DESCRIPTOR),                   //Length;
     90     USB_DESC_TYPE_CONFIG,                             //DescriptorType;
     91     sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE),          //TotalLength;
     92     1,                                                //NumInterfaces;
     93     1,                                                //ConfigurationValue;
     94     0,                                                //Configuration;
     95     CONFIG_DESC_ATTRIBUTES,                           //Attributes;
     96     0                                                 //MaxPower;
     97   },
     98   { // USB_INTERFACE_DESCRIPTOR
     99     sizeof (USB_INTERFACE_DESCRIPTOR), //Length;
    100     USB_DESC_TYPE_INTERFACE, //DescriptorType;
    101     0,                                                //InterfaceNumber;
    102     0,                                                //AlternateSetting;
    103     2,                                                //NumEndpoints;
    104     0xFF,                                             //InterfaceClass;
    105     // Vendor specific interface subclass and protocol codes.
    106     // I found these values in the Fastboot code
    107     // (in match_fastboot_with_serial in fastboot.c).
    108     0x42,                                             //InterfaceSubClass;
    109     0x03,                                             //InterfaceProtocol;
    110     0                                                 //Interface;
    111   },
    112   { // USB_ENDPOINT_DESCRIPTOR (In Endpoint)
    113     sizeof (USB_ENDPOINT_DESCRIPTOR),                 //Length;
    114     USB_DESC_TYPE_ENDPOINT,                           //DescriptorType;
    115     1 | BIT7,                                         //EndpointAddress;
    116     0x2,                                              //Attributes;
    117     MAX_PACKET_SIZE_BULK,                             //MaxPacketSize;
    118     16                                                //Interval;
    119   },
    120   { // STATIC USB_ENDPOINT_DESCRIPTOR (Out Endpoint)
    121     sizeof (USB_ENDPOINT_DESCRIPTOR),                 //Length;
    122     USB_DESC_TYPE_ENDPOINT,                           //DescriptorType;
    123     1,                                                //EndpointAddress;
    124     0x2,                                              //Attributes;
    125     MAX_PACKET_SIZE_BULK,                             //MaxPacketSize;
    126     16                                                //Interval;
    127   }
    128 };
    129 
    130 STATIC
    131 VOID
    132 DataReceived (
    133   IN UINTN    Size,
    134   IN VOID    *Buffer
    135   )
    136 {
    137   FASTBOOT_USB_PACKET_LIST *NewEntry;
    138 
    139   NewEntry = AllocatePool (sizeof (*NewEntry));
    140   ASSERT (NewEntry != NULL);
    141 
    142   NewEntry->Buffer = Buffer;
    143   NewEntry->BufferSize = Size;
    144 
    145   InsertTailList (&mPacketList, &NewEntry->Link);
    146 
    147   if (mReceiveEvent) {
    148     gBS->SignalEvent (mReceiveEvent);
    149   }
    150 }
    151 
    152 STATIC
    153 VOID
    154 DataSent (
    155   IN UINT8 EndpointIndex
    156   )
    157 {
    158   // Don't care.
    159 }
    160 
    161 /*
    162   Set up the transport system for use by Fastboot.
    163   e.g. For USB this probably means making the device enumerable.
    164 */
    165 EFI_STATUS
    166 FastbootTransportUsbStart (
    167   EFI_EVENT ReceiveEvent
    168   )
    169 {
    170   GET_CONFIG_DESCRIPTOR_RESPONSE  *Responses;
    171 
    172   mReceiveEvent = ReceiveEvent;
    173 
    174   mGetConfigDescriptorResponse.ConfigDescriptor.TotalLength = sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE);
    175   Responses = &mGetConfigDescriptorResponse;
    176 
    177   InitializeListHead (&mPacketList);
    178 
    179   return mUsbDevice->Start (&mDeviceDescriptor, (VOID **) &Responses, DataReceived, DataSent);
    180 }
    181 
    182 /*
    183   Function to be called when all Fastboot transactions are finished, to
    184   de-initialise the transport system.
    185   e.g. A USB OTG system might want to get out of peripheral mode so it can be
    186        a USB host.
    187 */
    188 EFI_STATUS
    189 FastbootTransportUsbStop (
    190   VOID
    191   )
    192 {
    193   // not yet implemented in USB
    194   return EFI_SUCCESS;
    195 }
    196 
    197 /*
    198   Send data. This function can be used both for command responses like "OKAY"
    199   and for the data phase (the protocol doesn't describe any situation when the
    200    latter might be necessary, but does allow it)
    201  */
    202 EFI_STATUS
    203 FastbootTransportUsbSend (
    204   IN        UINTN      BufferSize,
    205   IN  CONST VOID      *Buffer,
    206   IN        EFI_EVENT *FatalErrorEvent
    207   )
    208 {
    209   // Current USB protocol is blocking, so ignore FatalErrorEvent
    210   return mUsbDevice->Send(1, BufferSize, Buffer);
    211 }
    212 
    213 /*
    214   When the event has been Signalled to say data is available from the host,
    215   this function is used to get data. In order to handle the case where several
    216   packets are received before ReceiveEvent's notify function is called, packets
    217   received are queued, and each call to this function returns the next packet in
    218   the queue. It should therefore be called in a loop, the exit condition being a
    219   return of EFI_NOT_READY.
    220 
    221   Parameters:
    222     Buffer      - The buffer in which to place data
    223     BufferSize  - The size of Buffer in bytes
    224 
    225   Return EFI_NOT_READY if there is no data available
    226 */
    227 EFI_STATUS
    228 FastbootTransportUsbReceive (
    229   OUT UINTN  *BufferSize,
    230   OUT VOID  **Buffer
    231   )
    232 {
    233   FASTBOOT_USB_PACKET_LIST *Entry;
    234 
    235   if (IsListEmpty (&mPacketList)) {
    236     return EFI_NOT_READY;
    237   }
    238 
    239   Entry = (FASTBOOT_USB_PACKET_LIST *) GetFirstNode (&mPacketList);
    240 
    241   *BufferSize = Entry->BufferSize;
    242   *Buffer = Entry->Buffer;
    243 
    244   RemoveEntryList (&Entry->Link);
    245   FreePool (Entry);
    246 
    247   return EFI_SUCCESS;
    248 }
    249 
    250 STATIC FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = {
    251   FastbootTransportUsbStart,
    252   FastbootTransportUsbStop,
    253   FastbootTransportUsbSend,
    254   FastbootTransportUsbReceive
    255 };
    256 
    257 EFI_STATUS
    258 FastbootTransportUsbEntryPoint (
    259   IN EFI_HANDLE        ImageHandle,
    260   IN EFI_SYSTEM_TABLE *SystemTable
    261   )
    262 {
    263   EFI_STATUS Status;
    264 
    265   // Assume there's only one USB peripheral controller.
    266   Status = gBS->LocateProtocol (&gUsbDeviceProtocolGuid, NULL, (VOID **) &mUsbDevice);
    267   if (EFI_ERROR (Status)) {
    268     return Status;
    269   }
    270 
    271   Status = gBS->InstallProtocolInterface (
    272                   &ImageHandle,
    273                   &gAndroidFastbootTransportProtocolGuid,
    274                   EFI_NATIVE_INTERFACE,
    275                   &mTransportProtocol
    276                   );
    277   return Status;
    278 }
    279