1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
|
/** @file
Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
/*
* 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;
}
|