]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / UsbBus.c
... / ...
CommitLineData
1/** @file\r
2\r
3 Usb Bus Driver Binding and Bus IO Protocol.\r
4\r
5Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "UsbBus.h"\r
11\r
12EFI_USB_IO_PROTOCOL mUsbIoProtocol = {\r
13 UsbIoControlTransfer,\r
14 UsbIoBulkTransfer,\r
15 UsbIoAsyncInterruptTransfer,\r
16 UsbIoSyncInterruptTransfer,\r
17 UsbIoIsochronousTransfer,\r
18 UsbIoAsyncIsochronousTransfer,\r
19 UsbIoGetDeviceDescriptor,\r
20 UsbIoGetActiveConfigDescriptor,\r
21 UsbIoGetInterfaceDescriptor,\r
22 UsbIoGetEndpointDescriptor,\r
23 UsbIoGetStringDescriptor,\r
24 UsbIoGetSupportedLanguages,\r
25 UsbIoPortReset\r
26};\r
27\r
28EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {\r
29 UsbBusControllerDriverSupported,\r
30 UsbBusControllerDriverStart,\r
31 UsbBusControllerDriverStop,\r
32 0xa,\r
33 NULL,\r
34 NULL\r
35};\r
36\r
37/**\r
38 USB_IO function to execute a control transfer. This\r
39 function will execute the USB transfer. If transfer\r
40 successes, it will sync the internal state of USB bus\r
41 with device state.\r
42\r
43 @param This The USB_IO instance\r
44 @param Request The control transfer request\r
45 @param Direction Direction for data stage\r
46 @param Timeout The time to wait before timeout\r
47 @param Data The buffer holding the data\r
48 @param DataLength Then length of the data\r
49 @param UsbStatus USB result\r
50\r
51 @retval EFI_INVALID_PARAMETER The parameters are invalid\r
52 @retval EFI_SUCCESS The control transfer succeeded.\r
53 @retval Others Failed to execute the transfer\r
54\r
55**/\r
56EFI_STATUS\r
57EFIAPI\r
58UsbIoControlTransfer (\r
59 IN EFI_USB_IO_PROTOCOL *This,\r
60 IN EFI_USB_DEVICE_REQUEST *Request,\r
61 IN EFI_USB_DATA_DIRECTION Direction,\r
62 IN UINT32 Timeout,\r
63 IN OUT VOID *Data OPTIONAL,\r
64 IN UINTN DataLength OPTIONAL,\r
65 OUT UINT32 *UsbStatus\r
66 )\r
67{\r
68 USB_DEVICE *Dev;\r
69 USB_INTERFACE *UsbIf;\r
70 USB_ENDPOINT_DESC *EpDesc;\r
71 EFI_TPL OldTpl;\r
72 EFI_STATUS Status;\r
73 UINTN RequestedDataLength;\r
74\r
75 if (UsbStatus == NULL) {\r
76 return EFI_INVALID_PARAMETER;\r
77 }\r
78\r
79 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
80\r
81 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
82 Dev = UsbIf->Device;\r
83\r
84 RequestedDataLength = DataLength;\r
85 Status = UsbHcControlTransfer (\r
86 Dev->Bus,\r
87 Dev->Address,\r
88 Dev->Speed,\r
89 Dev->MaxPacket0,\r
90 Request,\r
91 Direction,\r
92 Data,\r
93 &DataLength,\r
94 (UINTN)Timeout,\r
95 &Dev->Translator,\r
96 UsbStatus\r
97 );\r
98 //\r
99 // If the request completed successfully and the Direction of the request is\r
100 // EfiUsbDataIn or EfiUsbDataOut, then make sure the actual number of bytes\r
101 // transferred is the same as the number of bytes requested. If a different\r
102 // number of bytes were transferred, then return EFI_DEVICE_ERROR.\r
103 //\r
104 if (!EFI_ERROR (Status)) {\r
105 if ((Direction != EfiUsbNoData) && (DataLength != RequestedDataLength)) {\r
106 Status = EFI_DEVICE_ERROR;\r
107 goto ON_EXIT;\r
108 }\r
109 }\r
110\r
111 if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
112 //\r
113 // Clear TT buffer when CTRL/BULK split transaction failes\r
114 // Clear the TRANSLATOR TT buffer, not parent's buffer\r
115 //\r
116 ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);\r
117 if (Dev->Translator.TranslatorHubAddress != 0) {\r
118 UsbHubCtrlClearTTBuffer (\r
119 Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
120 Dev->Translator.TranslatorPortNumber,\r
121 Dev->Address,\r
122 0,\r
123 USB_ENDPOINT_CONTROL\r
124 );\r
125 }\r
126\r
127 goto ON_EXIT;\r
128 }\r
129\r
130 //\r
131 // Some control transfer will change the device's internal\r
132 // status, such as Set_Configuration and Set_Interface.\r
133 // We must synchronize the bus driver's status with that in\r
134 // device. We ignore the Set_Descriptor request because it's\r
135 // hardly used by any device, especially in pre-boot environment\r
136 //\r
137\r
138 //\r
139 // Reset the endpoint toggle when endpoint stall is cleared\r
140 //\r
141 if ((Request->Request == USB_REQ_CLEAR_FEATURE) &&\r
142 (Request->RequestType == USB_REQUEST_TYPE (\r
143 EfiUsbNoData,\r
144 USB_REQ_TYPE_STANDARD,\r
145 USB_TARGET_ENDPOINT\r
146 )) &&\r
147 (Request->Value == USB_FEATURE_ENDPOINT_HALT))\r
148 {\r
149 EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8)Request->Index);\r
150\r
151 if (EpDesc != NULL) {\r
152 EpDesc->Toggle = 0;\r
153 }\r
154 }\r
155\r
156 //\r
157 // Select a new configuration. This is a dangerous action. Upper driver\r
158 // should stop use its current UsbIo after calling this driver. The old\r
159 // UsbIo will be uninstalled and new UsbIo be installed. We can't use\r
160 // ReinstallProtocol since interfaces in different configuration may be\r
161 // completely irrelevant.\r
162 //\r
163 if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
164 (Request->RequestType == USB_REQUEST_TYPE (\r
165 EfiUsbNoData,\r
166 USB_REQ_TYPE_STANDARD,\r
167 USB_TARGET_DEVICE\r
168 )))\r
169 {\r
170 //\r
171 // Don't re-create the USB interfaces if configuration isn't changed.\r
172 //\r
173 if ((Dev->ActiveConfig != NULL) &&\r
174 (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue))\r
175 {\r
176 goto ON_EXIT;\r
177 }\r
178\r
179 DEBUG ((DEBUG_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r
180\r
181 if (Dev->ActiveConfig != NULL) {\r
182 UsbRemoveConfig (Dev);\r
183 }\r
184\r
185 if (Request->Value != 0) {\r
186 Status = UsbSelectConfig (Dev, (UINT8)Request->Value);\r
187 }\r
188\r
189 //\r
190 // Exit now, Old USB_IO is invalid now\r
191 //\r
192 goto ON_EXIT;\r
193 }\r
194\r
195 //\r
196 // A new alternative setting is selected for the interface.\r
197 // No need to reinstall UsbIo in this case because only\r
198 // underlying communication endpoints are changed. Functionality\r
199 // should remains the same.\r
200 //\r
201 if ((Request->Request == USB_REQ_SET_INTERFACE) &&\r
202 (Request->RequestType == USB_REQUEST_TYPE (\r
203 EfiUsbNoData,\r
204 USB_REQ_TYPE_STANDARD,\r
205 USB_TARGET_INTERFACE\r
206 )) &&\r
207 (Request->Index == UsbIf->IfSetting->Desc.InterfaceNumber))\r
208 {\r
209 Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8)Request->Value);\r
210\r
211 if (!EFI_ERROR (Status)) {\r
212 ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);\r
213 UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];\r
214 }\r
215 }\r
216\r
217ON_EXIT:\r
218 gBS->RestoreTPL (OldTpl);\r
219 return Status;\r
220}\r
221\r
222/**\r
223 Execute a bulk transfer to the device endpoint.\r
224\r
225 @param This The USB IO instance.\r
226 @param Endpoint The device endpoint.\r
227 @param Data The data to transfer.\r
228 @param DataLength The length of the data to transfer.\r
229 @param Timeout Time to wait before timeout.\r
230 @param UsbStatus The result of USB transfer.\r
231\r
232 @retval EFI_SUCCESS The bulk transfer is OK.\r
233 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
234 @retval Others Failed to execute transfer, reason returned in\r
235 UsbStatus.\r
236\r
237**/\r
238EFI_STATUS\r
239EFIAPI\r
240UsbIoBulkTransfer (\r
241 IN EFI_USB_IO_PROTOCOL *This,\r
242 IN UINT8 Endpoint,\r
243 IN OUT VOID *Data,\r
244 IN OUT UINTN *DataLength,\r
245 IN UINTN Timeout,\r
246 OUT UINT32 *UsbStatus\r
247 )\r
248{\r
249 USB_DEVICE *Dev;\r
250 USB_INTERFACE *UsbIf;\r
251 USB_ENDPOINT_DESC *EpDesc;\r
252 UINT8 BufNum;\r
253 UINT8 Toggle;\r
254 EFI_TPL OldTpl;\r
255 EFI_STATUS Status;\r
256\r
257 if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15) ||\r
258 (UsbStatus == NULL))\r
259 {\r
260 return EFI_INVALID_PARAMETER;\r
261 }\r
262\r
263 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
264\r
265 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
266 Dev = UsbIf->Device;\r
267\r
268 EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r
269\r
270 if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {\r
271 Status = EFI_INVALID_PARAMETER;\r
272 goto ON_EXIT;\r
273 }\r
274\r
275 BufNum = 1;\r
276 Toggle = EpDesc->Toggle;\r
277 Status = UsbHcBulkTransfer (\r
278 Dev->Bus,\r
279 Dev->Address,\r
280 Endpoint,\r
281 Dev->Speed,\r
282 EpDesc->Desc.MaxPacketSize,\r
283 BufNum,\r
284 &Data,\r
285 DataLength,\r
286 &Toggle,\r
287 Timeout,\r
288 &Dev->Translator,\r
289 UsbStatus\r
290 );\r
291\r
292 EpDesc->Toggle = Toggle;\r
293\r
294 if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
295 //\r
296 // Clear TT buffer when CTRL/BULK split transaction failes.\r
297 // Clear the TRANSLATOR TT buffer, not parent's buffer\r
298 //\r
299 ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);\r
300 if (Dev->Translator.TranslatorHubAddress != 0) {\r
301 UsbHubCtrlClearTTBuffer (\r
302 Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
303 Dev->Translator.TranslatorPortNumber,\r
304 Dev->Address,\r
305 0,\r
306 USB_ENDPOINT_BULK\r
307 );\r
308 }\r
309 }\r
310\r
311ON_EXIT:\r
312 gBS->RestoreTPL (OldTpl);\r
313 return Status;\r
314}\r
315\r
316/**\r
317 Execute a synchronous interrupt transfer.\r
318\r
319 @param This The USB IO instance.\r
320 @param Endpoint The device endpoint.\r
321 @param Data The data to transfer.\r
322 @param DataLength The length of the data to transfer.\r
323 @param Timeout Time to wait before timeout.\r
324 @param UsbStatus The result of USB transfer.\r
325\r
326 @retval EFI_SUCCESS The synchronous interrupt transfer is OK.\r
327 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
328 @retval Others Failed to execute transfer, reason returned in\r
329 UsbStatus.\r
330\r
331**/\r
332EFI_STATUS\r
333EFIAPI\r
334UsbIoSyncInterruptTransfer (\r
335 IN EFI_USB_IO_PROTOCOL *This,\r
336 IN UINT8 Endpoint,\r
337 IN OUT VOID *Data,\r
338 IN OUT UINTN *DataLength,\r
339 IN UINTN Timeout,\r
340 OUT UINT32 *UsbStatus\r
341 )\r
342{\r
343 USB_DEVICE *Dev;\r
344 USB_INTERFACE *UsbIf;\r
345 USB_ENDPOINT_DESC *EpDesc;\r
346 EFI_TPL OldTpl;\r
347 UINT8 Toggle;\r
348 EFI_STATUS Status;\r
349\r
350 if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15) ||\r
351 (UsbStatus == NULL))\r
352 {\r
353 return EFI_INVALID_PARAMETER;\r
354 }\r
355\r
356 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
357\r
358 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
359 Dev = UsbIf->Device;\r
360\r
361 EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r
362\r
363 if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
364 Status = EFI_INVALID_PARAMETER;\r
365 goto ON_EXIT;\r
366 }\r
367\r
368 Toggle = EpDesc->Toggle;\r
369 Status = UsbHcSyncInterruptTransfer (\r
370 Dev->Bus,\r
371 Dev->Address,\r
372 Endpoint,\r
373 Dev->Speed,\r
374 EpDesc->Desc.MaxPacketSize,\r
375 Data,\r
376 DataLength,\r
377 &Toggle,\r
378 Timeout,\r
379 &Dev->Translator,\r
380 UsbStatus\r
381 );\r
382\r
383 EpDesc->Toggle = Toggle;\r
384\r
385ON_EXIT:\r
386 gBS->RestoreTPL (OldTpl);\r
387 return Status;\r
388}\r
389\r
390/**\r
391 Queue a new asynchronous interrupt transfer, or remove the old\r
392 request if (IsNewTransfer == FALSE).\r
393\r
394 @param This The USB_IO instance.\r
395 @param Endpoint The device endpoint.\r
396 @param IsNewTransfer Whether this is a new request, if it's old, remove\r
397 the request.\r
398 @param PollInterval The interval to poll the transfer result, (in ms).\r
399 @param DataLength The length of perodic data transfer.\r
400 @param Callback The function to call periodically when transfer is\r
401 ready.\r
402 @param Context The context to the callback.\r
403\r
404 @retval EFI_SUCCESS New transfer is queued or old request is removed.\r
405 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
406 @retval Others Failed to queue the new request or remove the old\r
407 request.\r
408\r
409**/\r
410EFI_STATUS\r
411EFIAPI\r
412UsbIoAsyncInterruptTransfer (\r
413 IN EFI_USB_IO_PROTOCOL *This,\r
414 IN UINT8 Endpoint,\r
415 IN BOOLEAN IsNewTransfer,\r
416 IN UINTN PollInterval OPTIONAL,\r
417 IN UINTN DataLength OPTIONAL,\r
418 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback OPTIONAL,\r
419 IN VOID *Context OPTIONAL\r
420 )\r
421{\r
422 USB_DEVICE *Dev;\r
423 USB_INTERFACE *UsbIf;\r
424 USB_ENDPOINT_DESC *EpDesc;\r
425 EFI_TPL OldTpl;\r
426 UINT8 Toggle;\r
427 EFI_STATUS Status;\r
428\r
429 if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {\r
430 return EFI_INVALID_PARAMETER;\r
431 }\r
432\r
433 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
434 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
435 Dev = UsbIf->Device;\r
436\r
437 EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);\r
438\r
439 if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
440 Status = EFI_INVALID_PARAMETER;\r
441 goto ON_EXIT;\r
442 }\r
443\r
444 Toggle = EpDesc->Toggle;\r
445 Status = UsbHcAsyncInterruptTransfer (\r
446 Dev->Bus,\r
447 Dev->Address,\r
448 Endpoint,\r
449 Dev->Speed,\r
450 EpDesc->Desc.MaxPacketSize,\r
451 IsNewTransfer,\r
452 &Toggle,\r
453 PollInterval,\r
454 DataLength,\r
455 &Dev->Translator,\r
456 Callback,\r
457 Context\r
458 );\r
459\r
460 EpDesc->Toggle = Toggle;\r
461\r
462ON_EXIT:\r
463 gBS->RestoreTPL (OldTpl);\r
464 return Status;\r
465}\r
466\r
467/**\r
468 Execute a synchronous isochronous transfer.\r
469\r
470 @param This The USB IO instance.\r
471 @param DeviceEndpoint The device endpoint.\r
472 @param Data The data to transfer.\r
473 @param DataLength The length of the data to transfer.\r
474 @param UsbStatus The result of USB transfer.\r
475\r
476 @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r
477\r
478**/\r
479EFI_STATUS\r
480EFIAPI\r
481UsbIoIsochronousTransfer (\r
482 IN EFI_USB_IO_PROTOCOL *This,\r
483 IN UINT8 DeviceEndpoint,\r
484 IN OUT VOID *Data,\r
485 IN UINTN DataLength,\r
486 OUT UINT32 *Status\r
487 )\r
488{\r
489 return EFI_UNSUPPORTED;\r
490}\r
491\r
492/**\r
493 Queue an asynchronous isochronous transfer.\r
494\r
495 @param This The USB_IO instance.\r
496 @param DeviceEndpoint The device endpoint.\r
497 @param Data The data to transfer.\r
498 @param DataLength The length of perodic data transfer.\r
499 @param IsochronousCallBack The function to call periodically when transfer is\r
500 ready.\r
501 @param Context The context to the callback.\r
502\r
503 @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported.\r
504\r
505**/\r
506EFI_STATUS\r
507EFIAPI\r
508UsbIoAsyncIsochronousTransfer (\r
509 IN EFI_USB_IO_PROTOCOL *This,\r
510 IN UINT8 DeviceEndpoint,\r
511 IN OUT VOID *Data,\r
512 IN UINTN DataLength,\r
513 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
514 IN VOID *Context OPTIONAL\r
515 )\r
516{\r
517 return EFI_UNSUPPORTED;\r
518}\r
519\r
520/**\r
521 Retrieve the device descriptor of the device.\r
522\r
523 @param This The USB IO instance.\r
524 @param Descriptor The variable to receive the device descriptor.\r
525\r
526 @retval EFI_SUCCESS The device descriptor is returned.\r
527 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
528\r
529**/\r
530EFI_STATUS\r
531EFIAPI\r
532UsbIoGetDeviceDescriptor (\r
533 IN EFI_USB_IO_PROTOCOL *This,\r
534 OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor\r
535 )\r
536{\r
537 USB_DEVICE *Dev;\r
538 USB_INTERFACE *UsbIf;\r
539 EFI_TPL OldTpl;\r
540\r
541 if (Descriptor == NULL) {\r
542 return EFI_INVALID_PARAMETER;\r
543 }\r
544\r
545 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
546\r
547 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
548 Dev = UsbIf->Device;\r
549\r
550 CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r
551\r
552 gBS->RestoreTPL (OldTpl);\r
553 return EFI_SUCCESS;\r
554}\r
555\r
556/**\r
557 Return the configuration descriptor of the current active configuration.\r
558\r
559 @param This The USB IO instance.\r
560 @param Descriptor The USB configuration descriptor.\r
561\r
562 @retval EFI_SUCCESS The active configuration descriptor is returned.\r
563 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
564 @retval EFI_NOT_FOUND Currently no active configuration is selected.\r
565\r
566**/\r
567EFI_STATUS\r
568EFIAPI\r
569UsbIoGetActiveConfigDescriptor (\r
570 IN EFI_USB_IO_PROTOCOL *This,\r
571 OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor\r
572 )\r
573{\r
574 USB_DEVICE *Dev;\r
575 USB_INTERFACE *UsbIf;\r
576 EFI_STATUS Status;\r
577 EFI_TPL OldTpl;\r
578\r
579 if (Descriptor == NULL) {\r
580 return EFI_INVALID_PARAMETER;\r
581 }\r
582\r
583 Status = EFI_SUCCESS;\r
584 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
585\r
586 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
587 Dev = UsbIf->Device;\r
588\r
589 if (Dev->ActiveConfig == NULL) {\r
590 Status = EFI_NOT_FOUND;\r
591 goto ON_EXIT;\r
592 }\r
593\r
594 CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));\r
595\r
596ON_EXIT:\r
597 gBS->RestoreTPL (OldTpl);\r
598 return Status;\r
599}\r
600\r
601/**\r
602 Retrieve the active interface setting descriptor for this USB IO instance.\r
603\r
604 @param This The USB IO instance.\r
605 @param Descriptor The variable to receive active interface setting.\r
606\r
607 @retval EFI_SUCCESS The active interface setting is returned.\r
608 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
609\r
610**/\r
611EFI_STATUS\r
612EFIAPI\r
613UsbIoGetInterfaceDescriptor (\r
614 IN EFI_USB_IO_PROTOCOL *This,\r
615 OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor\r
616 )\r
617{\r
618 USB_INTERFACE *UsbIf;\r
619 EFI_TPL OldTpl;\r
620\r
621 if (Descriptor == NULL) {\r
622 return EFI_INVALID_PARAMETER;\r
623 }\r
624\r
625 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
626\r
627 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
628 CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));\r
629\r
630 gBS->RestoreTPL (OldTpl);\r
631 return EFI_SUCCESS;\r
632}\r
633\r
634/**\r
635 Retrieve the endpoint descriptor from this interface setting.\r
636\r
637 @param This The USB IO instance.\r
638 @param Index The index (start from zero) of the endpoint to\r
639 retrieve.\r
640 @param Descriptor The variable to receive the descriptor.\r
641\r
642 @retval EFI_SUCCESS The endpoint descriptor is returned.\r
643 @retval EFI_INVALID_PARAMETER Some parameter is invalid.\r
644\r
645**/\r
646EFI_STATUS\r
647EFIAPI\r
648UsbIoGetEndpointDescriptor (\r
649 IN EFI_USB_IO_PROTOCOL *This,\r
650 IN UINT8 Index,\r
651 OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor\r
652 )\r
653{\r
654 USB_INTERFACE *UsbIf;\r
655 EFI_TPL OldTpl;\r
656\r
657 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
658\r
659 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
660\r
661 if ((Descriptor == NULL) || (Index > 15)) {\r
662 gBS->RestoreTPL (OldTpl);\r
663 return EFI_INVALID_PARAMETER;\r
664 }\r
665\r
666 if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {\r
667 gBS->RestoreTPL (OldTpl);\r
668 return EFI_NOT_FOUND;\r
669 }\r
670\r
671 CopyMem (\r
672 Descriptor,\r
673 &(UsbIf->IfSetting->Endpoints[Index]->Desc),\r
674 sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r
675 );\r
676\r
677 gBS->RestoreTPL (OldTpl);\r
678 return EFI_SUCCESS;\r
679}\r
680\r
681/**\r
682 Retrieve the supported language ID table from the device.\r
683\r
684 @param This The USB IO instance.\r
685 @param LangIDTable The table to return the language IDs.\r
686 @param TableSize The size, in bytes, of the table LangIDTable.\r
687\r
688 @retval EFI_SUCCESS The language ID is return.\r
689\r
690**/\r
691EFI_STATUS\r
692EFIAPI\r
693UsbIoGetSupportedLanguages (\r
694 IN EFI_USB_IO_PROTOCOL *This,\r
695 OUT UINT16 **LangIDTable,\r
696 OUT UINT16 *TableSize\r
697 )\r
698{\r
699 USB_DEVICE *Dev;\r
700 USB_INTERFACE *UsbIf;\r
701 EFI_TPL OldTpl;\r
702\r
703 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
704\r
705 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
706 Dev = UsbIf->Device;\r
707\r
708 *LangIDTable = Dev->LangId;\r
709 *TableSize = (UINT16)(Dev->TotalLangId * sizeof (UINT16));\r
710\r
711 gBS->RestoreTPL (OldTpl);\r
712 return EFI_SUCCESS;\r
713}\r
714\r
715/**\r
716 Retrieve an indexed string in the language of LangID.\r
717\r
718 @param This The USB IO instance.\r
719 @param LangID The language ID of the string to retrieve.\r
720 @param StringIndex The index of the string.\r
721 @param String The variable to receive the string.\r
722\r
723 @retval EFI_SUCCESS The string is returned.\r
724 @retval EFI_NOT_FOUND No such string existed.\r
725\r
726**/\r
727EFI_STATUS\r
728EFIAPI\r
729UsbIoGetStringDescriptor (\r
730 IN EFI_USB_IO_PROTOCOL *This,\r
731 IN UINT16 LangID,\r
732 IN UINT8 StringIndex,\r
733 OUT CHAR16 **String\r
734 )\r
735{\r
736 USB_DEVICE *Dev;\r
737 USB_INTERFACE *UsbIf;\r
738 EFI_USB_STRING_DESCRIPTOR *StrDesc;\r
739 EFI_TPL OldTpl;\r
740 UINT8 *Buf;\r
741 UINT8 Index;\r
742 EFI_STATUS Status;\r
743\r
744 if ((StringIndex == 0) || (LangID == 0)) {\r
745 return EFI_NOT_FOUND;\r
746 }\r
747\r
748 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
749\r
750 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
751 Dev = UsbIf->Device;\r
752\r
753 //\r
754 // Check whether language ID is supported\r
755 //\r
756 Status = EFI_NOT_FOUND;\r
757\r
758 for (Index = 0; Index < Dev->TotalLangId; Index++) {\r
759 ASSERT (Index < USB_MAX_LANG_ID);\r
760 if (Dev->LangId[Index] == LangID) {\r
761 break;\r
762 }\r
763 }\r
764\r
765 if (Index == Dev->TotalLangId) {\r
766 goto ON_EXIT;\r
767 }\r
768\r
769 //\r
770 // Retrieve the string descriptor then allocate a buffer\r
771 // to hold the string itself.\r
772 //\r
773 StrDesc = UsbGetOneString (Dev, StringIndex, LangID);\r
774\r
775 if (StrDesc == NULL) {\r
776 goto ON_EXIT;\r
777 }\r
778\r
779 if (StrDesc->Length <= 2) {\r
780 goto FREE_STR;\r
781 }\r
782\r
783 Buf = AllocateZeroPool (StrDesc->Length);\r
784\r
785 if (Buf == NULL) {\r
786 Status = EFI_OUT_OF_RESOURCES;\r
787 goto FREE_STR;\r
788 }\r
789\r
790 CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);\r
791 *String = (CHAR16 *)Buf;\r
792 Status = EFI_SUCCESS;\r
793\r
794FREE_STR:\r
795 gBS->FreePool (StrDesc);\r
796\r
797ON_EXIT:\r
798 gBS->RestoreTPL (OldTpl);\r
799 return Status;\r
800}\r
801\r
802/**\r
803 Reset the device, then if that succeeds, reconfigure the\r
804 device with its address and current active configuration.\r
805\r
806 @param This The USB IO instance.\r
807\r
808 @retval EFI_SUCCESS The device is reset and configured.\r
809 @retval Others Failed to reset the device.\r
810\r
811**/\r
812EFI_STATUS\r
813EFIAPI\r
814UsbIoPortReset (\r
815 IN EFI_USB_IO_PROTOCOL *This\r
816 )\r
817{\r
818 USB_INTERFACE *UsbIf;\r
819 USB_INTERFACE *HubIf;\r
820 USB_DEVICE *Dev;\r
821 EFI_TPL OldTpl;\r
822 EFI_STATUS Status;\r
823 UINT8 DevAddress;\r
824\r
825 OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
826\r
827 UsbIf = USB_INTERFACE_FROM_USBIO (This);\r
828 Dev = UsbIf->Device;\r
829\r
830 if (UsbIf->IsHub) {\r
831 Status = EFI_INVALID_PARAMETER;\r
832 goto ON_EXIT;\r
833 }\r
834\r
835 HubIf = Dev->ParentIf;\r
836 Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
837\r
838 if (EFI_ERROR (Status)) {\r
839 DEBUG ((\r
840 DEBUG_ERROR,\r
841 "UsbIoPortReset: failed to reset hub port %d@hub %d - %r\n",\r
842 Dev->ParentPort,\r
843 Dev->ParentAddr,\r
844 Status\r
845 ));\r
846\r
847 goto ON_EXIT;\r
848 }\r
849\r
850 HubIf->HubApi->ClearPortChange (HubIf, Dev->ParentPort);\r
851\r
852 //\r
853 // Reset the device to its current address. The device now has an address\r
854 // of ZERO after port reset, so need to set Dev->Address to the device again for\r
855 // host to communicate with it.\r
856 //\r
857 DevAddress = Dev->Address;\r
858 Dev->Address = 0;\r
859 Status = UsbSetAddress (Dev, DevAddress);\r
860 Dev->Address = DevAddress;\r
861\r
862 gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);\r
863\r
864 if (EFI_ERROR (Status)) {\r
865 //\r
866 // It may fail due to device disconnection or other reasons.\r
867 //\r
868 DEBUG ((\r
869 DEBUG_ERROR,\r
870 "UsbIoPortReset: failed to set address for device %d - %r\n",\r
871 Dev->Address,\r
872 Status\r
873 ));\r
874\r
875 goto ON_EXIT;\r
876 }\r
877\r
878 DEBUG ((DEBUG_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Dev->Address));\r
879\r
880 //\r
881 // Reset the current active configure, after this device\r
882 // is in CONFIGURED state.\r
883 //\r
884 if (Dev->ActiveConfig != NULL) {\r
885 Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);\r
886\r
887 if (EFI_ERROR (Status)) {\r
888 DEBUG ((\r
889 DEBUG_ERROR,\r
890 "UsbIoPortReset: failed to set configure for device %d - %r\n",\r
891 Dev->Address,\r
892 Status\r
893 ));\r
894 }\r
895 }\r
896\r
897ON_EXIT:\r
898 gBS->RestoreTPL (OldTpl);\r
899 return Status;\r
900}\r
901\r
902/**\r
903 Install Usb Bus Protocol on host controller, and start the Usb bus.\r
904\r
905 @param This The USB bus driver binding instance.\r
906 @param Controller The controller to check.\r
907 @param RemainingDevicePath The remaining device patch.\r
908\r
909 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
910 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus.\r
911 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
912\r
913**/\r
914EFI_STATUS\r
915EFIAPI\r
916UsbBusBuildProtocol (\r
917 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
918 IN EFI_HANDLE Controller,\r
919 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
920 )\r
921{\r
922 USB_BUS *UsbBus;\r
923 USB_DEVICE *RootHub;\r
924 USB_INTERFACE *RootIf;\r
925 EFI_STATUS Status;\r
926 EFI_STATUS Status2;\r
927\r
928 UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r
929\r
930 if (UsbBus == NULL) {\r
931 return EFI_OUT_OF_RESOURCES;\r
932 }\r
933\r
934 UsbBus->Signature = USB_BUS_SIGNATURE;\r
935 UsbBus->HostHandle = Controller;\r
936 UsbBus->MaxDevices = USB_MAX_DEVICES;\r
937\r
938 Status = gBS->OpenProtocol (\r
939 Controller,\r
940 &gEfiDevicePathProtocolGuid,\r
941 (VOID **)&UsbBus->DevicePath,\r
942 This->DriverBindingHandle,\r
943 Controller,\r
944 EFI_OPEN_PROTOCOL_BY_DRIVER\r
945 );\r
946\r
947 if (EFI_ERROR (Status)) {\r
948 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to open device path - %r\n", Status));\r
949\r
950 FreePool (UsbBus);\r
951 return Status;\r
952 }\r
953\r
954 //\r
955 // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
956 // This is for backward compatibility with EFI 1.x. In UEFI\r
957 // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r
958 // and USB_HC because EHCI driver will install both protocols\r
959 // (for the same reason). If we don't consume both of them,\r
960 // the unconsumed one may be opened by others.\r
961 //\r
962 Status = gBS->OpenProtocol (\r
963 Controller,\r
964 &gEfiUsb2HcProtocolGuid,\r
965 (VOID **)&(UsbBus->Usb2Hc),\r
966 This->DriverBindingHandle,\r
967 Controller,\r
968 EFI_OPEN_PROTOCOL_BY_DRIVER\r
969 );\r
970\r
971 Status2 = gBS->OpenProtocol (\r
972 Controller,\r
973 &gEfiUsbHcProtocolGuid,\r
974 (VOID **)&(UsbBus->UsbHc),\r
975 This->DriverBindingHandle,\r
976 Controller,\r
977 EFI_OPEN_PROTOCOL_BY_DRIVER\r
978 );\r
979\r
980 if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r
981 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC - %r\n", Status));\r
982\r
983 Status = EFI_DEVICE_ERROR;\r
984 goto CLOSE_HC;\r
985 }\r
986\r
987 if (!EFI_ERROR (Status)) {\r
988 //\r
989 // The EFI_USB2_HC_PROTOCOL is produced for XHCI support.\r
990 // Then its max supported devices are 256. Otherwise it's 128.\r
991 //\r
992 ASSERT (UsbBus->Usb2Hc != NULL);\r
993 if (UsbBus->Usb2Hc->MajorRevision == 0x3) {\r
994 UsbBus->MaxDevices = 256;\r
995 }\r
996 }\r
997\r
998 //\r
999 // Install an EFI_USB_BUS_PROTOCOL to host controller to identify it.\r
1000 //\r
1001 Status = gBS->InstallProtocolInterface (\r
1002 &Controller,\r
1003 &gEfiCallerIdGuid,\r
1004 EFI_NATIVE_INTERFACE,\r
1005 &UsbBus->BusId\r
1006 );\r
1007\r
1008 if (EFI_ERROR (Status)) {\r
1009 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to install bus protocol - %r\n", Status));\r
1010 goto CLOSE_HC;\r
1011 }\r
1012\r
1013 //\r
1014 // Initial the wanted child device path list, and add first RemainingDevicePath\r
1015 //\r
1016 InitializeListHead (&UsbBus->WantedUsbIoDPList);\r
1017 Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath);\r
1018 ASSERT (!EFI_ERROR (Status));\r
1019 //\r
1020 // Create a fake usb device for root hub\r
1021 //\r
1022 RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r
1023\r
1024 if (RootHub == NULL) {\r
1025 Status = EFI_OUT_OF_RESOURCES;\r
1026 goto UNINSTALL_USBBUS;\r
1027 }\r
1028\r
1029 RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
1030\r
1031 if (RootIf == NULL) {\r
1032 FreePool (RootHub);\r
1033 Status = EFI_OUT_OF_RESOURCES;\r
1034 goto FREE_ROOTHUB;\r
1035 }\r
1036\r
1037 RootHub->Bus = UsbBus;\r
1038 RootHub->NumOfInterface = 1;\r
1039 RootHub->Interfaces[0] = RootIf;\r
1040 RootHub->Tier = 0;\r
1041 RootIf->Signature = USB_INTERFACE_SIGNATURE;\r
1042 RootIf->Device = RootHub;\r
1043 RootIf->DevicePath = UsbBus->DevicePath;\r
1044\r
1045 //\r
1046 // Report Status Code here since we will enumerate the USB devices\r
1047 //\r
1048 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1049 EFI_PROGRESS_CODE,\r
1050 (EFI_IO_BUS_USB | EFI_IOB_PC_DETECT),\r
1051 UsbBus->DevicePath\r
1052 );\r
1053\r
1054 Status = mUsbRootHubApi.Init (RootIf);\r
1055\r
1056 if (EFI_ERROR (Status)) {\r
1057 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to init root hub - %r\n", Status));\r
1058 goto FREE_ROOTHUB;\r
1059 }\r
1060\r
1061 UsbBus->Devices[0] = RootHub;\r
1062\r
1063 DEBUG ((DEBUG_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf));\r
1064 return EFI_SUCCESS;\r
1065\r
1066FREE_ROOTHUB:\r
1067 if (RootIf != NULL) {\r
1068 FreePool (RootIf);\r
1069 }\r
1070\r
1071 if (RootHub != NULL) {\r
1072 FreePool (RootHub);\r
1073 }\r
1074\r
1075UNINSTALL_USBBUS:\r
1076 gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &UsbBus->BusId);\r
1077\r
1078CLOSE_HC:\r
1079 if (UsbBus->Usb2Hc != NULL) {\r
1080 gBS->CloseProtocol (\r
1081 Controller,\r
1082 &gEfiUsb2HcProtocolGuid,\r
1083 This->DriverBindingHandle,\r
1084 Controller\r
1085 );\r
1086 }\r
1087\r
1088 if (UsbBus->UsbHc != NULL) {\r
1089 gBS->CloseProtocol (\r
1090 Controller,\r
1091 &gEfiUsbHcProtocolGuid,\r
1092 This->DriverBindingHandle,\r
1093 Controller\r
1094 );\r
1095 }\r
1096\r
1097 gBS->CloseProtocol (\r
1098 Controller,\r
1099 &gEfiDevicePathProtocolGuid,\r
1100 This->DriverBindingHandle,\r
1101 Controller\r
1102 );\r
1103 FreePool (UsbBus);\r
1104\r
1105 DEBUG ((DEBUG_ERROR, "UsbBusStart: Failed to start bus driver - %r\n", Status));\r
1106 return Status;\r
1107}\r
1108\r
1109/**\r
1110 The USB bus driver entry pointer.\r
1111\r
1112 @param ImageHandle The driver image handle.\r
1113 @param SystemTable The system table.\r
1114\r
1115 @return EFI_SUCCESS The component name protocol is installed.\r
1116 @return Others Failed to init the usb driver.\r
1117\r
1118**/\r
1119EFI_STATUS\r
1120EFIAPI\r
1121UsbBusDriverEntryPoint (\r
1122 IN EFI_HANDLE ImageHandle,\r
1123 IN EFI_SYSTEM_TABLE *SystemTable\r
1124 )\r
1125{\r
1126 return EfiLibInstallDriverBindingComponentName2 (\r
1127 ImageHandle,\r
1128 SystemTable,\r
1129 &mUsbBusDriverBinding,\r
1130 ImageHandle,\r
1131 &mUsbBusComponentName,\r
1132 &mUsbBusComponentName2\r
1133 );\r
1134}\r
1135\r
1136/**\r
1137 Check whether USB bus driver support this device.\r
1138\r
1139 @param This The USB bus driver binding protocol.\r
1140 @param Controller The controller handle to check.\r
1141 @param RemainingDevicePath The remaining device path.\r
1142\r
1143 @retval EFI_SUCCESS The bus supports this controller.\r
1144 @retval EFI_UNSUPPORTED This device isn't supported.\r
1145\r
1146**/\r
1147EFI_STATUS\r
1148EFIAPI\r
1149UsbBusControllerDriverSupported (\r
1150 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1151 IN EFI_HANDLE Controller,\r
1152 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1153 )\r
1154{\r
1155 EFI_DEV_PATH_PTR DevicePathNode;\r
1156 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
1157 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
1158 EFI_USB_HC_PROTOCOL *UsbHc;\r
1159 EFI_STATUS Status;\r
1160\r
1161 //\r
1162 // Check whether device path is valid\r
1163 //\r
1164 if (RemainingDevicePath != NULL) {\r
1165 //\r
1166 // Check if RemainingDevicePath is the End of Device Path Node,\r
1167 // if yes, go on checking other conditions\r
1168 //\r
1169 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
1170 //\r
1171 // If RemainingDevicePath isn't the End of Device Path Node,\r
1172 // check its validation\r
1173 //\r
1174 DevicePathNode.DevPath = RemainingDevicePath;\r
1175\r
1176 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
1177 ( (DevicePathNode.DevPath->SubType != MSG_USB_DP) &&\r
1178 (DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP)\r
1179 && (DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP)\r
1180 ))\r
1181 {\r
1182 return EFI_UNSUPPORTED;\r
1183 }\r
1184 }\r
1185 }\r
1186\r
1187 //\r
1188 // Check whether USB_HC2 protocol is installed\r
1189 //\r
1190 Status = gBS->OpenProtocol (\r
1191 Controller,\r
1192 &gEfiUsb2HcProtocolGuid,\r
1193 (VOID **)&Usb2Hc,\r
1194 This->DriverBindingHandle,\r
1195 Controller,\r
1196 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1197 );\r
1198 if (Status == EFI_ALREADY_STARTED) {\r
1199 return EFI_SUCCESS;\r
1200 }\r
1201\r
1202 if (EFI_ERROR (Status)) {\r
1203 //\r
1204 // If failed to open USB_HC2, fall back to USB_HC\r
1205 //\r
1206 Status = gBS->OpenProtocol (\r
1207 Controller,\r
1208 &gEfiUsbHcProtocolGuid,\r
1209 (VOID **)&UsbHc,\r
1210 This->DriverBindingHandle,\r
1211 Controller,\r
1212 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1213 );\r
1214 if (Status == EFI_ALREADY_STARTED) {\r
1215 return EFI_SUCCESS;\r
1216 }\r
1217\r
1218 if (EFI_ERROR (Status)) {\r
1219 return Status;\r
1220 }\r
1221\r
1222 //\r
1223 // Close the USB_HC used to perform the supported test\r
1224 //\r
1225 gBS->CloseProtocol (\r
1226 Controller,\r
1227 &gEfiUsbHcProtocolGuid,\r
1228 This->DriverBindingHandle,\r
1229 Controller\r
1230 );\r
1231 } else {\r
1232 //\r
1233 // Close the USB_HC2 used to perform the supported test\r
1234 //\r
1235 gBS->CloseProtocol (\r
1236 Controller,\r
1237 &gEfiUsb2HcProtocolGuid,\r
1238 This->DriverBindingHandle,\r
1239 Controller\r
1240 );\r
1241 }\r
1242\r
1243 //\r
1244 // Open the EFI Device Path protocol needed to perform the supported test\r
1245 //\r
1246 Status = gBS->OpenProtocol (\r
1247 Controller,\r
1248 &gEfiDevicePathProtocolGuid,\r
1249 (VOID **)&ParentDevicePath,\r
1250 This->DriverBindingHandle,\r
1251 Controller,\r
1252 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1253 );\r
1254 if (Status == EFI_ALREADY_STARTED) {\r
1255 return EFI_SUCCESS;\r
1256 }\r
1257\r
1258 if (!EFI_ERROR (Status)) {\r
1259 //\r
1260 // Close protocol, don't use device path protocol in the Support() function\r
1261 //\r
1262 gBS->CloseProtocol (\r
1263 Controller,\r
1264 &gEfiDevicePathProtocolGuid,\r
1265 This->DriverBindingHandle,\r
1266 Controller\r
1267 );\r
1268\r
1269 return EFI_SUCCESS;\r
1270 }\r
1271\r
1272 return Status;\r
1273}\r
1274\r
1275/**\r
1276 Start to process the controller.\r
1277\r
1278 @param This The USB bus driver binding instance.\r
1279 @param Controller The controller to check.\r
1280 @param RemainingDevicePath The remaining device patch.\r
1281\r
1282 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
1283 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb\r
1284 bus.\r
1285 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
1286\r
1287**/\r
1288EFI_STATUS\r
1289EFIAPI\r
1290UsbBusControllerDriverStart (\r
1291 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1292 IN EFI_HANDLE Controller,\r
1293 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1294 )\r
1295{\r
1296 EFI_USB_BUS_PROTOCOL *UsbBusId;\r
1297 EFI_STATUS Status;\r
1298 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
1299\r
1300 Status = gBS->OpenProtocol (\r
1301 Controller,\r
1302 &gEfiDevicePathProtocolGuid,\r
1303 (VOID **)&ParentDevicePath,\r
1304 This->DriverBindingHandle,\r
1305 Controller,\r
1306 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1307 );\r
1308 ASSERT_EFI_ERROR (Status);\r
1309\r
1310 //\r
1311 // Report Status Code here since we will initialize the host controller\r
1312 //\r
1313 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1314 EFI_PROGRESS_CODE,\r
1315 (EFI_IO_BUS_USB | EFI_IOB_PC_INIT),\r
1316 ParentDevicePath\r
1317 );\r
1318\r
1319 //\r
1320 // Locate the USB bus protocol, if it is found, USB bus\r
1321 // is already started on this controller.\r
1322 //\r
1323 Status = gBS->OpenProtocol (\r
1324 Controller,\r
1325 &gEfiCallerIdGuid,\r
1326 (VOID **)&UsbBusId,\r
1327 This->DriverBindingHandle,\r
1328 Controller,\r
1329 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1330 );\r
1331\r
1332 if (EFI_ERROR (Status)) {\r
1333 //\r
1334 // If first start, build the bus execute environment and install bus protocol\r
1335 //\r
1336 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_IO_BUS_USB | EFI_P_PC_ENABLE));\r
1337 Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath);\r
1338 if (EFI_ERROR (Status)) {\r
1339 return Status;\r
1340 }\r
1341\r
1342 //\r
1343 // Try get the Usb Bus protocol interface again\r
1344 //\r
1345 Status = gBS->OpenProtocol (\r
1346 Controller,\r
1347 &gEfiCallerIdGuid,\r
1348 (VOID **)&UsbBusId,\r
1349 This->DriverBindingHandle,\r
1350 Controller,\r
1351 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1352 );\r
1353 ASSERT (!EFI_ERROR (Status));\r
1354 } else {\r
1355 //\r
1356 // USB Bus driver need to control the recursive connect policy of the bus, only those wanted\r
1357 // usb child device will be recursively connected.\r
1358 // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time.\r
1359 // All wanted usb child devices will be remembered by the usb bus driver itself.\r
1360 // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices.\r
1361 //\r
1362 // Save the passed in RemainingDevicePath this time\r
1363 //\r
1364 if (RemainingDevicePath != NULL) {\r
1365 if (IsDevicePathEnd (RemainingDevicePath)) {\r
1366 //\r
1367 // If RemainingDevicePath is the End of Device Path Node,\r
1368 // skip enumerate any device and return EFI_SUCCESS\r
1369 //\r
1370 return EFI_SUCCESS;\r
1371 }\r
1372 }\r
1373\r
1374 Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath);\r
1375 ASSERT (!EFI_ERROR (Status));\r
1376 //\r
1377 // Ensure all wanted child usb devices are fully recursively connected\r
1378 //\r
1379 Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId);\r
1380 ASSERT (!EFI_ERROR (Status));\r
1381 }\r
1382\r
1383 return EFI_SUCCESS;\r
1384}\r
1385\r
1386/**\r
1387 Stop handle the controller by this USB bus driver.\r
1388\r
1389 @param This The USB bus driver binding protocol.\r
1390 @param Controller The controller to release.\r
1391 @param NumberOfChildren The child of USB bus that opened controller\r
1392 BY_CHILD.\r
1393 @param ChildHandleBuffer The array of child handle.\r
1394\r
1395 @retval EFI_SUCCESS The controller or children are stopped.\r
1396 @retval EFI_DEVICE_ERROR Failed to stop the driver.\r
1397\r
1398**/\r
1399EFI_STATUS\r
1400EFIAPI\r
1401UsbBusControllerDriverStop (\r
1402 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1403 IN EFI_HANDLE Controller,\r
1404 IN UINTN NumberOfChildren,\r
1405 IN EFI_HANDLE *ChildHandleBuffer\r
1406 )\r
1407{\r
1408 USB_BUS *Bus;\r
1409 USB_DEVICE *RootHub;\r
1410 USB_DEVICE *UsbDev;\r
1411 USB_INTERFACE *RootIf;\r
1412 USB_INTERFACE *UsbIf;\r
1413 EFI_USB_BUS_PROTOCOL *BusId;\r
1414 EFI_USB_IO_PROTOCOL *UsbIo;\r
1415 EFI_TPL OldTpl;\r
1416 UINTN Index;\r
1417 EFI_STATUS Status;\r
1418 EFI_STATUS ReturnStatus;\r
1419\r
1420 Status = EFI_SUCCESS;\r
1421\r
1422 if (NumberOfChildren > 0) {\r
1423 //\r
1424 // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
1425 //\r
1426 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1427\r
1428 ReturnStatus = EFI_SUCCESS;\r
1429 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1430 Status = gBS->OpenProtocol (\r
1431 ChildHandleBuffer[Index],\r
1432 &gEfiUsbIoProtocolGuid,\r
1433 (VOID **)&UsbIo,\r
1434 This->DriverBindingHandle,\r
1435 Controller,\r
1436 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1437 );\r
1438\r
1439 if (EFI_ERROR (Status)) {\r
1440 //\r
1441 // It is possible that the child has already been released:\r
1442 // 1. For combo device, free one device will release others.\r
1443 // 2. If a hub is released, all devices on its down facing\r
1444 // ports are released also.\r
1445 //\r
1446 continue;\r
1447 }\r
1448\r
1449 UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);\r
1450 UsbDev = UsbIf->Device;\r
1451\r
1452 ReturnStatus = UsbRemoveDevice (UsbDev);\r
1453 }\r
1454\r
1455 gBS->RestoreTPL (OldTpl);\r
1456 return ReturnStatus;\r
1457 }\r
1458\r
1459 DEBUG ((DEBUG_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller));\r
1460\r
1461 //\r
1462 // Locate USB_BUS for the current host controller\r
1463 //\r
1464 Status = gBS->OpenProtocol (\r
1465 Controller,\r
1466 &gEfiCallerIdGuid,\r
1467 (VOID **)&BusId,\r
1468 This->DriverBindingHandle,\r
1469 Controller,\r
1470 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1471 );\r
1472\r
1473 if (EFI_ERROR (Status)) {\r
1474 return Status;\r
1475 }\r
1476\r
1477 Bus = USB_BUS_FROM_THIS (BusId);\r
1478\r
1479 //\r
1480 // Stop the root hub, then free all the devices\r
1481 //\r
1482 // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
1483 //\r
1484 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1485\r
1486 RootHub = Bus->Devices[0];\r
1487 RootIf = RootHub->Interfaces[0];\r
1488\r
1489 ASSERT (Bus->MaxDevices <= 256);\r
1490 ReturnStatus = EFI_SUCCESS;\r
1491 for (Index = 1; Index < Bus->MaxDevices; Index++) {\r
1492 if (Bus->Devices[Index] != NULL) {\r
1493 Status = UsbRemoveDevice (Bus->Devices[Index]);\r
1494 if (EFI_ERROR (Status)) {\r
1495 ReturnStatus = Status;\r
1496 }\r
1497 }\r
1498 }\r
1499\r
1500 gBS->RestoreTPL (OldTpl);\r
1501\r
1502 if (!EFI_ERROR (ReturnStatus)) {\r
1503 mUsbRootHubApi.Release (RootIf);\r
1504 gBS->FreePool (RootIf);\r
1505 gBS->FreePool (RootHub);\r
1506\r
1507 Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);\r
1508 ASSERT (!EFI_ERROR (Status));\r
1509\r
1510 //\r
1511 // Uninstall the bus identifier and close USB_HC/USB2_HC protocols\r
1512 //\r
1513 gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &Bus->BusId);\r
1514\r
1515 if (Bus->Usb2Hc != NULL) {\r
1516 Status = gBS->CloseProtocol (\r
1517 Controller,\r
1518 &gEfiUsb2HcProtocolGuid,\r
1519 This->DriverBindingHandle,\r
1520 Controller\r
1521 );\r
1522 }\r
1523\r
1524 if (Bus->UsbHc != NULL) {\r
1525 Status = gBS->CloseProtocol (\r
1526 Controller,\r
1527 &gEfiUsbHcProtocolGuid,\r
1528 This->DriverBindingHandle,\r
1529 Controller\r
1530 );\r
1531 }\r
1532\r
1533 if (!EFI_ERROR (Status)) {\r
1534 gBS->CloseProtocol (\r
1535 Controller,\r
1536 &gEfiDevicePathProtocolGuid,\r
1537 This->DriverBindingHandle,\r
1538 Controller\r
1539 );\r
1540\r
1541 gBS->FreePool (Bus);\r
1542 }\r
1543 }\r
1544\r
1545 return Status;\r
1546}\r