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