From d3f99770c0aa0a4468062963ba5f1b7dd1ebcbbd Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Wed, 5 Mar 2014 04:51:31 +0000 Subject: 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 +++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c (limited to 'EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c') 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; +} -- cgit v1.2.3