--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+/*\r
+ * Implementation of the FASTBOOT_TRANSPORT_PROTOCOL using the USB_DEVICE_PROTOCOL\r
+ */\r
+\r
+#include <Protocol/UsbDevice.h>\r
+#include <Protocol/AndroidFastbootTransport.h>\r
+#include <Protocol/SimpleTextOut.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+\r
+STATIC USB_DEVICE_PROTOCOL *mUsbDevice;\r
+\r
+// Configuration attributes:\r
+// bit 7 reserved and must be 1, bit 6 means self-powered.\r
+#define CONFIG_DESC_ATTRIBUTES (BIT7 | BIT6)\r
+\r
+#define MAX_PACKET_SIZE_BULK 512\r
+\r
+STATIC USB_DEVICE_PROTOCOL *mUsbDevice;\r
+STATIC EFI_EVENT mReceiveEvent = NULL;\r
+STATIC LIST_ENTRY mPacketList;\r
+\r
+// List type for queued received packets\r
+typedef struct _FASTBOOT_USB_PACKET_LIST {\r
+ LIST_ENTRY Link;\r
+ VOID *Buffer;\r
+ UINTN BufferSize;\r
+} FASTBOOT_USB_PACKET_LIST;\r
+\r
+\r
+/*\r
+ No string descriptors - all string descriptor members are set to 0\r
+*/\r
+\r
+STATIC USB_DEVICE_DESCRIPTOR mDeviceDescriptor = {\r
+ sizeof (USB_DEVICE_DESCRIPTOR), //Length\r
+ USB_DESC_TYPE_DEVICE, //DescriptorType\r
+ 0x0200, //BcdUSB\r
+ 0xFF, //DeviceClass\r
+ 0, //DeviceSubClass\r
+ 0, //DeviceProtocol\r
+ 64, //MaxPacketSize0\r
+ FixedPcdGet32 (PcdAndroidFastbootUsbVendorId), //IdVendor\r
+ FixedPcdGet32 (PcdAndroidFastbootUsbProductId), //IdProduct\r
+ 0, //BcdDevice\r
+ 0, //StrManufacturer\r
+ 0, //StrProduct\r
+ 0, //StrSerialNumber\r
+ 1 //NumConfigurations\r
+};\r
+\r
+/*\r
+ We have one configuration, one interface, and two endpoints (one IN, one OUT)\r
+*/\r
+\r
+// Lazy (compile-time) way to concatenate descriptors to pass to the USB device\r
+// protocol\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+ USB_CONFIG_DESCRIPTOR ConfigDescriptor;\r
+ USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;\r
+ USB_ENDPOINT_DESCRIPTOR EndpointDescriptor1;\r
+ USB_ENDPOINT_DESCRIPTOR EndpointDescriptor2;\r
+} GET_CONFIG_DESCRIPTOR_RESPONSE;\r
+#pragma pack()\r
+\r
+STATIC GET_CONFIG_DESCRIPTOR_RESPONSE mGetConfigDescriptorResponse = {\r
+ { // USB_CONFIG_DESCRIPTOR\r
+ sizeof (USB_CONFIG_DESCRIPTOR), //Length;\r
+ USB_DESC_TYPE_CONFIG, //DescriptorType;\r
+ sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE), //TotalLength;\r
+ 1, //NumInterfaces;\r
+ 1, //ConfigurationValue;\r
+ 0, //Configuration;\r
+ CONFIG_DESC_ATTRIBUTES, //Attributes;\r
+ 0 //MaxPower;\r
+ },\r
+ { // USB_INTERFACE_DESCRIPTOR\r
+ sizeof (USB_INTERFACE_DESCRIPTOR), //Length;\r
+ USB_DESC_TYPE_INTERFACE, //DescriptorType;\r
+ 0, //InterfaceNumber;\r
+ 0, //AlternateSetting;\r
+ 2, //NumEndpoints;\r
+ 0xFF, //InterfaceClass;\r
+ // Vendor specific interface subclass and protocol codes.\r
+ // I found these values in the Fastboot code\r
+ // (in match_fastboot_with_serial in fastboot.c).\r
+ 0x42, //InterfaceSubClass;\r
+ 0x03, //InterfaceProtocol;\r
+ 0 //Interface;\r
+ },\r
+ { // USB_ENDPOINT_DESCRIPTOR (In Endpoint)\r
+ sizeof (USB_ENDPOINT_DESCRIPTOR), //Length;\r
+ USB_DESC_TYPE_ENDPOINT, //DescriptorType;\r
+ 1 | BIT7, //EndpointAddress;\r
+ 0x2, //Attributes;\r
+ MAX_PACKET_SIZE_BULK, //MaxPacketSize;\r
+ 16 //Interval;\r
+ },\r
+ { // STATIC USB_ENDPOINT_DESCRIPTOR (Out Endpoint)\r
+ sizeof (USB_ENDPOINT_DESCRIPTOR), //Length;\r
+ USB_DESC_TYPE_ENDPOINT, //DescriptorType;\r
+ 1, //EndpointAddress;\r
+ 0x2, //Attributes;\r
+ MAX_PACKET_SIZE_BULK, //MaxPacketSize;\r
+ 16 //Interval;\r
+ }\r
+};\r
+\r
+STATIC\r
+VOID\r
+DataReceived (\r
+ IN UINTN Size,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ FASTBOOT_USB_PACKET_LIST *NewEntry;\r
+\r
+ NewEntry = AllocatePool (sizeof (*NewEntry));\r
+ ASSERT (NewEntry != NULL);\r
+\r
+ NewEntry->Buffer = Buffer;\r
+ NewEntry->BufferSize = Size;\r
+\r
+ InsertTailList (&mPacketList, &NewEntry->Link);\r
+\r
+ if (mReceiveEvent) {\r
+ gBS->SignalEvent (mReceiveEvent);\r
+ }\r
+}\r
+\r
+STATIC\r
+VOID\r
+DataSent (\r
+ IN UINT8 EndpointIndex\r
+ )\r
+{\r
+ // Don't care.\r
+}\r
+\r
+/*\r
+ Set up the transport system for use by Fastboot.\r
+ e.g. For USB this probably means making the device enumerable.\r
+*/\r
+EFI_STATUS\r
+FastbootTransportUsbStart (\r
+ EFI_EVENT ReceiveEvent\r
+ )\r
+{\r
+ GET_CONFIG_DESCRIPTOR_RESPONSE *Responses;\r
+\r
+ mReceiveEvent = ReceiveEvent;\r
+\r
+ mGetConfigDescriptorResponse.ConfigDescriptor.TotalLength = sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE);\r
+ Responses = &mGetConfigDescriptorResponse;\r
+\r
+ InitializeListHead (&mPacketList);\r
+\r
+ return mUsbDevice->Start (&mDeviceDescriptor, (VOID **) &Responses, DataReceived, DataSent);\r
+}\r
+\r
+/*\r
+ Function to be called when all Fastboot transactions are finished, to\r
+ de-initialise the transport system.\r
+ e.g. A USB OTG system might want to get out of peripheral mode so it can be\r
+ a USB host.\r
+*/\r
+EFI_STATUS\r
+FastbootTransportUsbStop (\r
+ VOID\r
+ )\r
+{\r
+ // not yet implemented in USB\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/*\r
+ Send data. This function can be used both for command responses like "OKAY"\r
+ and for the data phase (the protocol doesn't describe any situation when the\r
+ latter might be necessary, but does allow it)\r
+ */\r
+EFI_STATUS\r
+FastbootTransportUsbSend (\r
+ IN UINTN BufferSize,\r
+ IN CONST VOID *Buffer,\r
+ IN EFI_EVENT *FatalErrorEvent\r
+ )\r
+{\r
+ // Current USB protocol is blocking, so ignore FatalErrorEvent\r
+ return mUsbDevice->Send(1, BufferSize, Buffer);\r
+}\r
+\r
+/*\r
+ When the event has been Signalled to say data is available from the host,\r
+ this function is used to get data. In order to handle the case where several\r
+ packets are received before ReceiveEvent's notify function is called, packets\r
+ received are queued, and each call to this function returns the next packet in\r
+ the queue. It should therefore be called in a loop, the exit condition being a\r
+ return of EFI_NOT_READY.\r
+\r
+ Parameters:\r
+ Buffer - The buffer in which to place data\r
+ BufferSize - The size of Buffer in bytes\r
+\r
+ Return EFI_NOT_READY if there is no data available\r
+*/\r
+EFI_STATUS\r
+FastbootTransportUsbReceive (\r
+ OUT UINTN *BufferSize,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ FASTBOOT_USB_PACKET_LIST *Entry;\r
+\r
+ if (IsListEmpty (&mPacketList)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ Entry = (FASTBOOT_USB_PACKET_LIST *) GetFirstNode (&mPacketList);\r
+\r
+ *BufferSize = Entry->BufferSize;\r
+ *Buffer = Entry->Buffer;\r
+\r
+ RemoveEntryList (&Entry->Link);\r
+ FreePool (Entry);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = {\r
+ FastbootTransportUsbStart,\r
+ FastbootTransportUsbStop,\r
+ FastbootTransportUsbSend,\r
+ FastbootTransportUsbReceive\r
+};\r
+\r
+EFI_STATUS\r
+FastbootTransportUsbEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ // Assume there's only one USB peripheral controller.\r
+ Status = gBS->LocateProtocol (&gUsbDeviceProtocolGuid, NULL, (VOID **) &mUsbDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ImageHandle,\r
+ &gAndroidFastbootTransportProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &mTransportProtocol\r
+ );\r
+ return Status;\r
+}\r