From d3f99770c0aa0a4468062963ba5f1b7dd1ebcbbd Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Wed, 5 Mar 2014 04:51:31 +0000 Subject: [PATCH] EmbeddedPkg/AndroidFastbootTransportUsbDxe: Implemented Android FastBoot over USB Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15316 6f19259b-4bc3-4df7-8a09-765794883524 --- .../FastbootTransportUsb.c | 278 ++++++++++++++++++ .../FastbootTransportUsbDxe.inf | 46 +++ EmbeddedPkg/EmbeddedPkg.dec | 10 + EmbeddedPkg/EmbeddedPkg.dsc | 1 + 4 files changed, 335 insertions(+) create mode 100644 EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c create mode 100644 EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf diff --git a/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c b/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c new file mode 100644 index 0000000000..e7da1fa5fc --- /dev/null +++ b/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c @@ -0,0 +1,278 @@ +/** @file + + Copyright (c) 2014, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/* + * Implementation of the FASTBOOT_TRANSPORT_PROTOCOL using the USB_DEVICE_PROTOCOL + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +STATIC USB_DEVICE_PROTOCOL *mUsbDevice; + +// Configuration attributes: +// bit 7 reserved and must be 1, bit 6 means self-powered. +#define CONFIG_DESC_ATTRIBUTES (BIT7 | BIT6) + +#define MAX_PACKET_SIZE_BULK 512 + +STATIC USB_DEVICE_PROTOCOL *mUsbDevice; +STATIC EFI_EVENT mReceiveEvent = NULL; +STATIC LIST_ENTRY mPacketList; + +// List type for queued received packets +typedef struct _FASTBOOT_USB_PACKET_LIST { + LIST_ENTRY Link; + VOID *Buffer; + UINTN BufferSize; +} FASTBOOT_USB_PACKET_LIST; + + +/* + No string descriptors - all string descriptor members are set to 0 +*/ + +STATIC USB_DEVICE_DESCRIPTOR mDeviceDescriptor = { + sizeof (USB_DEVICE_DESCRIPTOR), //Length + USB_DESC_TYPE_DEVICE, //DescriptorType + 0x0200, //BcdUSB + 0xFF, //DeviceClass + 0, //DeviceSubClass + 0, //DeviceProtocol + 64, //MaxPacketSize0 + FixedPcdGet32 (PcdAndroidFastbootUsbVendorId), //IdVendor + FixedPcdGet32 (PcdAndroidFastbootUsbProductId), //IdProduct + 0, //BcdDevice + 0, //StrManufacturer + 0, //StrProduct + 0, //StrSerialNumber + 1 //NumConfigurations +}; + +/* + We have one configuration, one interface, and two endpoints (one IN, one OUT) +*/ + +// Lazy (compile-time) way to concatenate descriptors to pass to the USB device +// protocol + +#pragma pack(1) +typedef struct { + USB_CONFIG_DESCRIPTOR ConfigDescriptor; + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor1; + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor2; +} GET_CONFIG_DESCRIPTOR_RESPONSE; +#pragma pack() + +STATIC GET_CONFIG_DESCRIPTOR_RESPONSE mGetConfigDescriptorResponse = { + { // USB_CONFIG_DESCRIPTOR + sizeof (USB_CONFIG_DESCRIPTOR), //Length; + USB_DESC_TYPE_CONFIG, //DescriptorType; + sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE), //TotalLength; + 1, //NumInterfaces; + 1, //ConfigurationValue; + 0, //Configuration; + CONFIG_DESC_ATTRIBUTES, //Attributes; + 0 //MaxPower; + }, + { // USB_INTERFACE_DESCRIPTOR + sizeof (USB_INTERFACE_DESCRIPTOR), //Length; + USB_DESC_TYPE_INTERFACE, //DescriptorType; + 0, //InterfaceNumber; + 0, //AlternateSetting; + 2, //NumEndpoints; + 0xFF, //InterfaceClass; + // Vendor specific interface subclass and protocol codes. + // I found these values in the Fastboot code + // (in match_fastboot_with_serial in fastboot.c). + 0x42, //InterfaceSubClass; + 0x03, //InterfaceProtocol; + 0 //Interface; + }, + { // USB_ENDPOINT_DESCRIPTOR (In Endpoint) + sizeof (USB_ENDPOINT_DESCRIPTOR), //Length; + USB_DESC_TYPE_ENDPOINT, //DescriptorType; + 1 | BIT7, //EndpointAddress; + 0x2, //Attributes; + MAX_PACKET_SIZE_BULK, //MaxPacketSize; + 16 //Interval; + }, + { // STATIC USB_ENDPOINT_DESCRIPTOR (Out Endpoint) + sizeof (USB_ENDPOINT_DESCRIPTOR), //Length; + USB_DESC_TYPE_ENDPOINT, //DescriptorType; + 1, //EndpointAddress; + 0x2, //Attributes; + MAX_PACKET_SIZE_BULK, //MaxPacketSize; + 16 //Interval; + } +}; + +STATIC +VOID +DataReceived ( + IN UINTN Size, + IN VOID *Buffer + ) +{ + FASTBOOT_USB_PACKET_LIST *NewEntry; + + NewEntry = AllocatePool (sizeof (*NewEntry)); + ASSERT (NewEntry != NULL); + + NewEntry->Buffer = Buffer; + NewEntry->BufferSize = Size; + + InsertTailList (&mPacketList, &NewEntry->Link); + + if (mReceiveEvent) { + gBS->SignalEvent (mReceiveEvent); + } +} + +STATIC +VOID +DataSent ( + IN UINT8 EndpointIndex + ) +{ + // Don't care. +} + +/* + Set up the transport system for use by Fastboot. + e.g. For USB this probably means making the device enumerable. +*/ +EFI_STATUS +FastbootTransportUsbStart ( + EFI_EVENT ReceiveEvent + ) +{ + GET_CONFIG_DESCRIPTOR_RESPONSE *Responses; + + mReceiveEvent = ReceiveEvent; + + mGetConfigDescriptorResponse.ConfigDescriptor.TotalLength = sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE); + Responses = &mGetConfigDescriptorResponse; + + InitializeListHead (&mPacketList); + + return mUsbDevice->Start (&mDeviceDescriptor, (VOID **) &Responses, DataReceived, DataSent); +} + +/* + Function to be called when all Fastboot transactions are finished, to + de-initialise the transport system. + e.g. A USB OTG system might want to get out of peripheral mode so it can be + a USB host. +*/ +EFI_STATUS +FastbootTransportUsbStop ( + VOID + ) +{ + // not yet implemented in USB + return EFI_SUCCESS; +} + +/* + Send data. This function can be used both for command responses like "OKAY" + and for the data phase (the protocol doesn't describe any situation when the + latter might be necessary, but does allow it) + */ +EFI_STATUS +FastbootTransportUsbSend ( + IN UINTN BufferSize, + IN CONST VOID *Buffer, + IN EFI_EVENT *FatalErrorEvent + ) +{ + // Current USB protocol is blocking, so ignore FatalErrorEvent + return mUsbDevice->Send(1, BufferSize, Buffer); +} + +/* + When the event has been Signalled to say data is available from the host, + this function is used to get data. In order to handle the case where several + packets are received before ReceiveEvent's notify function is called, packets + received are queued, and each call to this function returns the next packet in + the queue. It should therefore be called in a loop, the exit condition being a + return of EFI_NOT_READY. + + Parameters: + Buffer - The buffer in which to place data + BufferSize - The size of Buffer in bytes + + Return EFI_NOT_READY if there is no data available +*/ +EFI_STATUS +FastbootTransportUsbReceive ( + OUT UINTN *BufferSize, + OUT VOID **Buffer + ) +{ + FASTBOOT_USB_PACKET_LIST *Entry; + + if (IsListEmpty (&mPacketList)) { + return EFI_NOT_READY; + } + + Entry = (FASTBOOT_USB_PACKET_LIST *) GetFirstNode (&mPacketList); + + *BufferSize = Entry->BufferSize; + *Buffer = Entry->Buffer; + + RemoveEntryList (&Entry->Link); + FreePool (Entry); + + return EFI_SUCCESS; +} + +STATIC FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = { + FastbootTransportUsbStart, + FastbootTransportUsbStop, + FastbootTransportUsbSend, + FastbootTransportUsbReceive +}; + +EFI_STATUS +FastbootTransportUsbEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // Assume there's only one USB peripheral controller. + Status = gBS->LocateProtocol (&gUsbDeviceProtocolGuid, NULL, (VOID **) &mUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gAndroidFastbootTransportProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTransportProtocol + ); + return Status; +} diff --git a/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf b/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf new file mode 100644 index 0000000000..c5ada1a0be --- /dev/null +++ b/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf @@ -0,0 +1,46 @@ +#/** @file +# +# Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FastbootTransportUsbDxe + FILE_GUID = f6bec3fe-88fb-11e3-ae84-e73b77561c35 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FastbootTransportUsbEntryPoint + +[Sources.common] + FastbootTransportUsb.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEfiDriverBindingProtocolGuid + gUsbDeviceProtocolGuid + gAndroidFastbootTransportProtocolGuid + gEfiSimpleTextOutProtocolGuid + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[FixedPcd] + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec index 95fb60e880..c219befc30 100644 --- a/EmbeddedPkg/EmbeddedPkg.dec +++ b/EmbeddedPkg/EmbeddedPkg.dec @@ -129,6 +129,16 @@ gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount|10000000|UINT32|0x0000004c gEmbeddedTokenSpaceGuid.PcdGdbTimerPeriodMilliseconds|250|UINT32|0x0000004d + # + # Android FastBoot + # + + # The Android FastBoot utility has hard-coded USB Vendor IDs that it recognises + # (and 0xf00d isn't one of them!). + # You'll need to pass it "-i 0xf00d" to get it to recognise this device. + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId|0xf00d|UINT32|0x00000022 + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023 + [PcdsFixedAtBuild.ARM] gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010 gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00000011 diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc index a9db4ed6af..7c3021aa52 100644 --- a/EmbeddedPkg/EmbeddedPkg.dsc +++ b/EmbeddedPkg/EmbeddedPkg.dsc @@ -255,6 +255,7 @@ EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf + EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf [Components.IA32, Components.X64, Components.IPF, Components.ARM] EmbeddedPkg/GdbStub/GdbStub.inf