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