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