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
DataReceived(IN UINTN Size,IN VOID * Buffer)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
DataSent(IN UINT8 EndpointIndex)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
FastbootTransportUsbStart(EFI_EVENT ReceiveEvent)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
FastbootTransportUsbStop(VOID)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
FastbootTransportUsbSend(IN UINTN BufferSize,IN CONST VOID * Buffer,IN EFI_EVENT * FatalErrorEvent)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
FastbootTransportUsbReceive(OUT UINTN * BufferSize,OUT VOID ** Buffer)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 EFI_STATUS
FastbootTransportUsbRequestReceive(IN UINTN BufferSize)251 FastbootTransportUsbRequestReceive (
252   IN UINTN   BufferSize
253   )
254 {
255 DEBUG ((DEBUG_ERROR, "#%a, %d, BufferSize:%d\n", __func__, __LINE__, BufferSize));
256   if (mUsbDevice->Request) {
257     return mUsbDevice->Request (BufferSize);
258   }
259   return EFI_SUCCESS;
260 }
261 
262 STATIC FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = {
263   FastbootTransportUsbStart,
264   FastbootTransportUsbStop,
265   FastbootTransportUsbSend,
266   FastbootTransportUsbReceive,
267   FastbootTransportUsbRequestReceive
268 };
269 
270 EFI_STATUS
FastbootTransportUsbEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)271 FastbootTransportUsbEntryPoint (
272   IN EFI_HANDLE        ImageHandle,
273   IN EFI_SYSTEM_TABLE *SystemTable
274   )
275 {
276   EFI_STATUS Status;
277 
278   // Assume there's only one USB peripheral controller.
279   Status = gBS->LocateProtocol (&gUsbDeviceProtocolGuid, NULL, (VOID **) &mUsbDevice);
280   if (EFI_ERROR (Status)) {
281     return Status;
282   }
283 
284   Status = gBS->InstallProtocolInterface (
285                   &ImageHandle,
286                   &gAndroidFastbootTransportProtocolGuid,
287                   EFI_NATIVE_INTERFACE,
288                   &mTransportProtocol
289                   );
290   return Status;
291 }
292