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