blob: 2f65662be2c83967a5f93f27b4de906e3cb98419 [file] [log] [blame]
Channagoud Kadabif8aa7632015-11-12 14:27:01 -08001/** @file
2
3 Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
4
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met:
20 * * Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * * Redistributions in binary form must reproduce the above
23 * copyright notice, this list of conditions and the following
24 * disclaimer in the documentation and/or other materials provided
25 * with the distribution.
26 * * Neither the name of The Linux Foundation nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
31 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
37 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
38 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
39 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
40 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41*/
42
43#include <Uefi.h>
44#include <Library/PcdLib.h>
45#include <Library/UefiLib.h>
46#include <Library/UefiApplicationEntryPoint.h>
47#include <Library/UefiBootServicesTableLib.h>
48#include <Library/UefiRuntimeServicesTableLib.h>
49#include <Protocol/EFIUsbDevice.h>
50#include <Library/DebugLib.h>
51#include <Library/LinuxLoaderLib.h>
52
53#include "UsbDescriptors.h"
54#include "FastbootCmds.h"
55#include "FastbootMain.h"
56
57#define USB_BUFF_SIZE 1024*1024*1
58
59/* Global fastboot data */
60static FastbootDeviceData Fbd;
61
62FastbootDeviceData GetFastbootDeviceData()
63{
64 return Fbd;
65}
66
67/* Dummy function needed for event notification callback */
68VOID DummyNotify (IN EFI_EVENT Event,IN VOID *Context)
69{
70}
71
72EFI_STATUS
73FastbootUsbDeviceStart(VOID)
74{
75 EFI_STATUS Status;
76 USB_DEVICE_DESCRIPTOR *DevDesc;
77 VOID *Descriptors;
78 EFI_EVENT UsbConfigEvt;
79 EFI_GUID UsbDeviceProtolGuid =
80 { 0xd9d9ce48, 0x44b8, 0x4f49,
81 { 0x8e, 0x3e, 0x2a, 0x3b, 0x92, 0x7d, 0xc6, 0xc1 } };
82 EFI_GUID InitUsbControllerGuid =
83 { 0x1c0cffce, 0xfc8d, 0x4e44,
84 { 0x8c, 0x78, 0x9c, 0x9e, 0x5b, 0x53, 0xd, 0x36 } };
85
86 Status = gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, DummyNotify, NULL, &InitUsbControllerGuid, &UsbConfigEvt);
87 if (EFI_ERROR(Status))
88 {
89 DEBUG((EFI_D_ERROR, "Usb controller init event not signaled: %r\n", Status));
90 return Status;
91 }
92 else
93 {
94 gBS->SignalEvent(UsbConfigEvt);
95 gBS->CloseEvent(UsbConfigEvt);
96 }
97
98 /* Locate the USBFastboot Protocol from DXE */
99 Status = gBS->LocateProtocol( &UsbDeviceProtolGuid,
100 NULL,
101 (VOID **) &Fbd.UsbDeviceProtocol);
102 if (Status != EFI_SUCCESS)
103 {
104 DEBUG((EFI_D_ERROR, "couldnt find USB device protocol, exiting now"));
105 return Status;
106 }
107
108 /* Build the descriptor for fastboot */
109 BuildDefaultDescriptors(&DevDesc, &Descriptors);
110
111 /* Start the usb device */
112 Status = Fbd.UsbDeviceProtocol->Start(DevDesc, &Descriptors, &DeviceQualifier, NULL, 5, StrDescriptors);
113
114 /* Allocate buffers required to receive the data from Host*/
115 Status = Fbd.UsbDeviceProtocol->AllocateTransferBuffer(USB_BUFF_SIZE, &Fbd.gRxBuffer);
116 if (EFI_ERROR(Status))
117 {
118 DEBUG((EFI_D_ERROR, "Error Allocate RX buffer, cannot enter fastboot mode\n"));
119 return EFI_OUT_OF_RESOURCES;
120 }
121
122 /* Allocate buffers required to send data from device to Host*/
123 Status = Fbd.UsbDeviceProtocol->AllocateTransferBuffer(USB_BUFF_SIZE, &Fbd.gTxBuffer);
124 if (EFI_ERROR(Status))
125 {
126 DEBUG((EFI_D_ERROR, "Error Allocate TX buffer, cannot enter fastboot mode\n"));
127 return EFI_OUT_OF_RESOURCES;
128 }
129
130 DEBUG((EFI_D_ERROR, "fastboot: processing commands\n"));
131
132 return Status;
133}
134
135/* API to stop USB device when booting to kernel, used for "fastboot boot" */
136EFI_STATUS
137FastbootUsbDeviceStop( VOID )
138{
139 EFI_STATUS Status;
140
141 /* Free the Rx & Tx Buffers */
142 Status = Fbd.UsbDeviceProtocol->FreeTransferBuffer(Fbd.gTxBuffer);
143 ASSERT(!EFI_ERROR(Status));
144 Status = Fbd.UsbDeviceProtocol->FreeTransferBuffer(Fbd.gRxBuffer);
145 ASSERT(!EFI_ERROR(Status));
146 return Status;
147}
148
149/* Process bulk transfer out come for Rx */
150EFI_STATUS
151ProcessBulkXfrCompleteRx(
152 IN USB_DEVICE_TRANSFER_OUTCOME *Uto
153)
154{
155 EFI_STATUS Status = EFI_SUCCESS;
156
157 // switch on the transfer status
158 switch (Uto->Status)
159 {
160 case UsbDeviceTransferStatusCompleteOK:
161 DataReady(Uto->BytesCompleted, Fbd.gRxBuffer);
162 break;
163
164 case UsbDeviceTransferStatusCancelled:
165 //if usb connected, retry, otherwise wait to get connected, then retry
166 DEBUG((EFI_D_ERROR, "Bulk in XFR aborted\n"));
167 Status = EFI_ABORTED;
168 break;
169
170 default: // Other statuses should not occur
171 Status = EFI_DEVICE_ERROR;
172 break;
173 }
174 return Status;
175}
176
177/* Process bulk transfer out come for Tx */
178EFI_STATUS
179ProcessBulkXfrCompleteTx(
180 IN USB_DEVICE_TRANSFER_OUTCOME *Uto
181)
182{
183 EFI_STATUS Status = EFI_SUCCESS;
184
185 // Switch on the transfer status
186 switch (Uto->Status) {
187 case UsbDeviceTransferStatusCompleteOK:
188 DEBUG((EFI_D_ERROR, "UsbDeviceTransferStatusCompleteOK\n"));
189 /* Just Queue the next recieve, must be a Command */
190 Status = Fbd.UsbDeviceProtocol->Send(ENDPOINT_IN, GetXfrSize() , Fbd.gRxBuffer);
191 break;
192
193 case UsbDeviceTransferStatusCancelled:
194 DEBUG((EFI_D_ERROR, "Bulk in xfr aborted"));
195 Status = EFI_DEVICE_ERROR;
196 break;
197
198 default: // Other statuses should not occur
199 DEBUG((EFI_D_ERROR, "unhandled trasnfer status"));
200 Status = EFI_DEVICE_ERROR;
201 break;
202 }
203 return Status;
204}
205
206/* Handle USB events, this will keep looking for events from USB protocol */
207EFI_STATUS HandleUsbEvents()
208{
209 EFI_STATUS Status = EFI_SUCCESS;
210 USB_DEVICE_EVENT Msg;
211 USB_DEVICE_EVENT_DATA Payload;
212 UINTN PayloadSize;
213
214 /* Look for Event from Usb device protocol */
215 Fbd.UsbDeviceProtocol->HandleEvent(&Msg, &PayloadSize, &Payload);
216 if (UsbDeviceEventDeviceStateChange == Msg)
217 {
218 if (UsbDeviceStateConnected == Payload.DeviceState) {
219 DEBUG ((EFI_D_INFO, "Fastboot Device connected\n"));
220 /* Queue receive buffer */
221 Status = Fbd.UsbDeviceProtocol->Send(0x1, 511, Fbd.gRxBuffer);
222 }
223 if (UsbDeviceStateDisconnected == Payload.DeviceState) {
224 DEBUG ((EFI_D_INFO, "Fastboot Device disconnected\n"));
225 }
226 }
227 else if (UsbDeviceEventTransferNotification == Msg) {
228 /* Check if the transfer notification is on the Bulk EP and process it*/
229 if (1 == USB_INDEX_TO_EP(Payload.TransferOutcome.EndpointIndex)) {
230 /* If the direction is from host to device then process RX */
231 if (USB_ENDPOINT_DIRECTION_OUT == USB_INDEX_TO_EPDIR(Payload.TransferOutcome.EndpointIndex)) {
232
233 Status = ProcessBulkXfrCompleteRx(&Payload.TransferOutcome);
234 if (EFI_ERROR(Status))
235 {
236 /* Should not happen, even if it happens we keep waiting for USB to be connected */
237 DEBUG((EFI_D_ERROR, "Error, should not happen! Check your USB connection"));
238 }
239 }
240 else {
241 /* Else the direction is from device to host, process TX */
242 Status = ProcessBulkXfrCompleteTx(&Payload.TransferOutcome);
243 if (EFI_ERROR(Status))
244 {
245 /* Should not happen, even if it happens we keep waiting for USB to be connected */
246 DEBUG((EFI_D_ERROR, "Error, should not happen! Check your USB connection"));
247 }
248 }
249 }
250 }
251 return Status;
252}
253
254/* Entry point for Fastboot App */
255EFI_STATUS
256EFIAPI
257FastbootAppEntryPoint(
258 IN EFI_HANDLE ImageHandle,
259 IN EFI_SYSTEM_TABLE *SystemTable
260 )
261{
262 EFI_STATUS Status = EFI_SUCCESS;
263
264 /* Any fastboot initiazation if needed */
265 Status = FastbootAppInit();
266 if (Status != EFI_SUCCESS)
267 {
268 DEBUG((EFI_D_ERROR, "couldnt init fastboot , exiting"));
269 return Status;
270 }
271 /* Start the USB device enumeration */
272 Status = FastbootUsbDeviceStart();
273 if (Status != EFI_SUCCESS)
274 {
275 DEBUG((EFI_D_ERROR, "couldnt Start fastboot usb device, exiting"));
276 return Status;
277 }
278
279 /* Wait for USB events in tight loop */
280 while (1)
281 {
282 Status = HandleUsbEvents();
283
284 if (FastbootFatal())
285 {
286 DEBUG((EFI_D_ERROR, "Continue detected, Exiting App...\n"));
287 break;
288 }
289 }
290
291 /* Close the fastboot app and stop USB device */
292 Status = FastbootAppUnInit();
293 if (Status != EFI_SUCCESS)
294 {
295 DEBUG((EFI_D_ERROR, "couldnt uninit fastboot\n"));
296 return Status;
297 }
298
299 Status = FastbootUsbDeviceStop();
300 return Status;
301}