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