]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c
EmbeddedPkg/AndroidFastbootTransportUsbDxe: Implemented Android FastBoot over USB
[mirror_edk2.git] / EmbeddedPkg / Drivers / AndroidFastbootTransportUsbDxe / FastbootTransportUsb.c
diff --git a/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c b/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c
new file mode 100644 (file)
index 0000000..e7da1fa
--- /dev/null
@@ -0,0 +1,278 @@
+/** @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