mirror of https://github.com/acidanthera/audk.git
279 lines
9.0 KiB
C
279 lines
9.0 KiB
C
|
/** @file
|
||
|
|
||
|
Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
|
||
|
|
||
|
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 <Protocol/UsbDevice.h>
|
||
|
#include <Protocol/AndroidFastbootTransport.h>
|
||
|
#include <Protocol/SimpleTextOut.h>
|
||
|
|
||
|
#include <Library/BaseLib.h>
|
||
|
#include <Library/BaseMemoryLib.h>
|
||
|
#include <Library/DebugLib.h>
|
||
|
#include <Library/MemoryAllocationLib.h>
|
||
|
#include <Library/UefiBootServicesTableLib.h>
|
||
|
#include <Library/UefiDriverEntryPoint.h>
|
||
|
|
||
|
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;
|
||
|
}
|