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