1/** @file
2
3    Wrapper function for usb host controller interface.
4
5Copyright (c) 2007 - 2010, 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
17#include "UsbBus.h"
18
19//
20// if RemainingDevicePath== NULL, then all Usb child devices in this bus are wanted.
21// Use a shor form Usb class Device Path, which could match any usb device, in WantedUsbIoDPList to indicate all Usb devices
22// are wanted Usb devices
23//
24USB_CLASS_FORMAT_DEVICE_PATH mAllUsbClassDevicePath = {
25  {
26    {
27      MESSAGING_DEVICE_PATH,
28      MSG_USB_CLASS_DP,
29      {
30        (UINT8) (sizeof (USB_CLASS_DEVICE_PATH)),
31        (UINT8) ((sizeof (USB_CLASS_DEVICE_PATH)) >> 8)
32      }
33    },
34    0xffff, // VendorId
35    0xffff, // ProductId
36    0xff,   // DeviceClass
37    0xff,   // DeviceSubClass
38    0xff    // DeviceProtocol
39  },
40
41  {
42    END_DEVICE_PATH_TYPE,
43    END_ENTIRE_DEVICE_PATH_SUBTYPE,
44    {
45      END_DEVICE_PATH_LENGTH,
46      0
47    }
48  }
49};
50
51
52/**
53  Get the capability of the host controller.
54
55  @param  UsbBus           The usb driver.
56  @param  MaxSpeed         The maximum speed this host controller supports.
57  @param  NumOfPort        The number of the root hub port.
58  @param  Is64BitCapable   Whether this controller support 64 bit addressing.
59
60  @retval EFI_SUCCESS      The host controller capability is returned.
61  @retval Others           Failed to retrieve the host controller capability.
62
63**/
64EFI_STATUS
65UsbHcGetCapability (
66  IN  USB_BUS             *UsbBus,
67  OUT UINT8               *MaxSpeed,
68  OUT UINT8               *NumOfPort,
69  OUT UINT8               *Is64BitCapable
70  )
71{
72  EFI_STATUS              Status;
73
74  if (UsbBus->Usb2Hc != NULL) {
75    Status = UsbBus->Usb2Hc->GetCapability (
76                              UsbBus->Usb2Hc,
77                              MaxSpeed,
78                              NumOfPort,
79                              Is64BitCapable
80                              );
81
82  } else {
83    Status = UsbBus->UsbHc->GetRootHubPortNumber (UsbBus->UsbHc, NumOfPort);
84
85    *MaxSpeed       = EFI_USB_SPEED_FULL;
86    *Is64BitCapable = (UINT8) FALSE;
87  }
88
89  return Status;
90}
91
92
93/**
94  Reset the host controller.
95
96  @param  UsbBus                The usb bus driver.
97  @param  Attributes            The reset type, only global reset is used by this driver.
98
99  @retval EFI_SUCCESS           The reset operation succeeded.
100  @retval EFI_INVALID_PARAMETER Attributes is not valid.
101  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is
102                                not currently supported by the host controller.
103  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.
104**/
105EFI_STATUS
106UsbHcReset (
107  IN USB_BUS              *UsbBus,
108  IN UINT16               Attributes
109  )
110{
111  EFI_STATUS              Status;
112
113  if (UsbBus->Usb2Hc != NULL) {
114    Status = UsbBus->Usb2Hc->Reset (UsbBus->Usb2Hc, Attributes);
115  } else {
116    Status = UsbBus->UsbHc->Reset (UsbBus->UsbHc, Attributes);
117  }
118
119  return Status;
120}
121
122
123/**
124  Get the current operation state of the host controller.
125
126  @param  UsbBus           The USB bus driver.
127  @param  State            The host controller operation state.
128
129  @retval EFI_SUCCESS      The operation state is returned in State.
130  @retval Others           Failed to get the host controller state.
131
132**/
133EFI_STATUS
134UsbHcGetState (
135  IN  USB_BUS             *UsbBus,
136  OUT EFI_USB_HC_STATE    *State
137  )
138{
139  EFI_STATUS              Status;
140
141  if (UsbBus->Usb2Hc != NULL) {
142    Status = UsbBus->Usb2Hc->GetState (UsbBus->Usb2Hc, State);
143  } else {
144    Status = UsbBus->UsbHc->GetState (UsbBus->UsbHc, State);
145  }
146
147  return Status;
148}
149
150
151/**
152  Set the host controller operation state.
153
154  @param  UsbBus           The USB bus driver.
155  @param  State            The state to set.
156
157  @retval EFI_SUCCESS      The host controller is now working at State.
158  @retval Others           Failed to set operation state.
159
160**/
161EFI_STATUS
162UsbHcSetState (
163  IN USB_BUS              *UsbBus,
164  IN EFI_USB_HC_STATE     State
165  )
166{
167  EFI_STATUS              Status;
168
169  if (UsbBus->Usb2Hc != NULL) {
170    Status = UsbBus->Usb2Hc->SetState (UsbBus->Usb2Hc, State);
171  } else {
172    Status = UsbBus->UsbHc->SetState (UsbBus->UsbHc, State);
173  }
174
175  return Status;
176}
177
178
179/**
180  Get the root hub port state.
181
182  @param  UsbBus           The USB bus driver.
183  @param  PortIndex        The index of port.
184  @param  PortStatus       The variable to save port state.
185
186  @retval EFI_SUCCESS      The root port state is returned in.
187  @retval Others           Failed to get the root hub port state.
188
189**/
190EFI_STATUS
191UsbHcGetRootHubPortStatus (
192  IN  USB_BUS             *UsbBus,
193  IN  UINT8               PortIndex,
194  OUT EFI_USB_PORT_STATUS *PortStatus
195  )
196{
197  EFI_STATUS              Status;
198
199  if (UsbBus->Usb2Hc != NULL) {
200    Status = UsbBus->Usb2Hc->GetRootHubPortStatus (UsbBus->Usb2Hc, PortIndex, PortStatus);
201  } else {
202    Status = UsbBus->UsbHc->GetRootHubPortStatus (UsbBus->UsbHc, PortIndex, PortStatus);
203  }
204
205  return Status;
206}
207
208
209/**
210  Set the root hub port feature.
211
212  @param  UsbBus           The USB bus driver.
213  @param  PortIndex        The port index.
214  @param  Feature          The port feature to set.
215
216  @retval EFI_SUCCESS      The port feature is set.
217  @retval Others           Failed to set port feature.
218
219**/
220EFI_STATUS
221UsbHcSetRootHubPortFeature (
222  IN USB_BUS              *UsbBus,
223  IN UINT8                PortIndex,
224  IN EFI_USB_PORT_FEATURE Feature
225  )
226{
227  EFI_STATUS              Status;
228
229
230  if (UsbBus->Usb2Hc != NULL) {
231    Status = UsbBus->Usb2Hc->SetRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
232  } else {
233    Status = UsbBus->UsbHc->SetRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
234  }
235
236  return Status;
237}
238
239
240/**
241  Clear the root hub port feature.
242
243  @param  UsbBus           The USB bus driver.
244  @param  PortIndex        The port index.
245  @param  Feature          The port feature to clear.
246
247  @retval EFI_SUCCESS      The port feature is clear.
248  @retval Others           Failed to clear port feature.
249
250**/
251EFI_STATUS
252UsbHcClearRootHubPortFeature (
253  IN USB_BUS              *UsbBus,
254  IN UINT8                PortIndex,
255  IN EFI_USB_PORT_FEATURE Feature
256  )
257{
258  EFI_STATUS              Status;
259
260  if (UsbBus->Usb2Hc != NULL) {
261    Status = UsbBus->Usb2Hc->ClearRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
262  } else {
263    Status = UsbBus->UsbHc->ClearRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
264  }
265
266  return Status;
267}
268
269
270/**
271  Execute a control transfer to the device.
272
273  @param  UsbBus           The USB bus driver.
274  @param  DevAddr          The device address.
275  @param  DevSpeed         The device speed.
276  @param  MaxPacket        Maximum packet size of endpoint 0.
277  @param  Request          The control transfer request.
278  @param  Direction        The direction of data stage.
279  @param  Data             The buffer holding data.
280  @param  DataLength       The length of the data.
281  @param  TimeOut          Timeout (in ms) to wait until timeout.
282  @param  Translator       The transaction translator for low/full speed device.
283  @param  UsbResult        The result of transfer.
284
285  @retval EFI_SUCCESS      The control transfer finished without error.
286  @retval Others           The control transfer failed, reason returned in UsbReslt.
287
288**/
289EFI_STATUS
290UsbHcControlTransfer (
291  IN  USB_BUS                             *UsbBus,
292  IN  UINT8                               DevAddr,
293  IN  UINT8                               DevSpeed,
294  IN  UINTN                               MaxPacket,
295  IN  EFI_USB_DEVICE_REQUEST              *Request,
296  IN  EFI_USB_DATA_DIRECTION              Direction,
297  IN  OUT VOID                            *Data,
298  IN  OUT UINTN                           *DataLength,
299  IN  UINTN                               TimeOut,
300  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
301  OUT UINT32                              *UsbResult
302  )
303{
304  EFI_STATUS              Status;
305  BOOLEAN                 IsSlowDevice;
306
307  if (UsbBus->Usb2Hc != NULL) {
308    Status = UsbBus->Usb2Hc->ControlTransfer (
309                               UsbBus->Usb2Hc,
310                               DevAddr,
311                               DevSpeed,
312                               MaxPacket,
313                               Request,
314                               Direction,
315                               Data,
316                               DataLength,
317                               TimeOut,
318                               Translator,
319                               UsbResult
320                               );
321
322  } else {
323    IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
324    Status = UsbBus->UsbHc->ControlTransfer (
325                              UsbBus->UsbHc,
326                              DevAddr,
327                              IsSlowDevice,
328                              (UINT8) MaxPacket,
329                              Request,
330                              Direction,
331                              Data,
332                              DataLength,
333                              TimeOut,
334                              UsbResult
335                              );
336  }
337
338  return Status;
339}
340
341
342/**
343  Execute a bulk transfer to the device's endpoint.
344
345  @param  UsbBus           The USB bus driver.
346  @param  DevAddr          The target device address.
347  @param  EpAddr           The target endpoint address, with direction encoded in
348                           bit 7.
349  @param  DevSpeed         The device's speed.
350  @param  MaxPacket        The endpoint's max packet size.
351  @param  BufferNum        The number of data buffer.
352  @param  Data             Array of pointers to data buffer.
353  @param  DataLength       The length of data buffer.
354  @param  DataToggle       On input, the initial data toggle to use, also  return
355                           the next toggle on output.
356  @param  TimeOut          The time to wait until timeout.
357  @param  Translator       The transaction translator for low/full speed device.
358  @param  UsbResult        The result of USB execution.
359
360  @retval EFI_SUCCESS      The bulk transfer is finished without error.
361  @retval Others           Failed to execute bulk transfer, result in UsbResult.
362
363**/
364EFI_STATUS
365UsbHcBulkTransfer (
366  IN  USB_BUS                             *UsbBus,
367  IN  UINT8                               DevAddr,
368  IN  UINT8                               EpAddr,
369  IN  UINT8                               DevSpeed,
370  IN  UINTN                               MaxPacket,
371  IN  UINT8                               BufferNum,
372  IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
373  IN  OUT UINTN                           *DataLength,
374  IN  OUT UINT8                           *DataToggle,
375  IN  UINTN                               TimeOut,
376  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
377  OUT UINT32                              *UsbResult
378  )
379{
380  EFI_STATUS              Status;
381
382  if (UsbBus->Usb2Hc != NULL) {
383    Status = UsbBus->Usb2Hc->BulkTransfer (
384                               UsbBus->Usb2Hc,
385                               DevAddr,
386                               EpAddr,
387                               DevSpeed,
388                               MaxPacket,
389                               BufferNum,
390                               Data,
391                               DataLength,
392                               DataToggle,
393                               TimeOut,
394                               Translator,
395                               UsbResult
396                               );
397  } else {
398    Status = UsbBus->UsbHc->BulkTransfer (
399                              UsbBus->UsbHc,
400                              DevAddr,
401                              EpAddr,
402                              (UINT8) MaxPacket,
403                              *Data,
404                              DataLength,
405                              DataToggle,
406                              TimeOut,
407                              UsbResult
408                              );
409  }
410
411  return Status;
412}
413
414
415/**
416  Queue or cancel an asynchronous interrupt transfer.
417
418  @param  UsbBus           The USB bus driver.
419  @param  DevAddr          The target device address.
420  @param  EpAddr           The target endpoint address, with direction encoded in
421                           bit 7.
422  @param  DevSpeed         The device's speed.
423  @param  MaxPacket        The endpoint's max packet size.
424  @param  IsNewTransfer    Whether this is a new request. If not, cancel the old
425                           request.
426  @param  DataToggle       Data toggle to use on input, next toggle on output.
427  @param  PollingInterval  The interval to poll the interrupt transfer (in ms).
428  @param  DataLength       The length of periodical data receive.
429  @param  Translator       The transaction translator for low/full speed device.
430  @param  Callback         Function to call when data is received.
431  @param  Context          The context to the callback.
432
433  @retval EFI_SUCCESS      The asynchronous transfer is queued.
434  @retval Others           Failed to queue the transfer.
435
436**/
437EFI_STATUS
438UsbHcAsyncInterruptTransfer (
439  IN  USB_BUS                             *UsbBus,
440  IN  UINT8                               DevAddr,
441  IN  UINT8                               EpAddr,
442  IN  UINT8                               DevSpeed,
443  IN  UINTN                               MaxPacket,
444  IN  BOOLEAN                             IsNewTransfer,
445  IN OUT UINT8                            *DataToggle,
446  IN  UINTN                               PollingInterval,
447  IN  UINTN                               DataLength,
448  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
449  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     Callback,
450  IN  VOID                                *Context OPTIONAL
451  )
452{
453  EFI_STATUS              Status;
454  BOOLEAN                 IsSlowDevice;
455
456  if (UsbBus->Usb2Hc != NULL) {
457    Status = UsbBus->Usb2Hc->AsyncInterruptTransfer (
458                               UsbBus->Usb2Hc,
459                               DevAddr,
460                               EpAddr,
461                               DevSpeed,
462                               MaxPacket,
463                               IsNewTransfer,
464                               DataToggle,
465                               PollingInterval,
466                               DataLength,
467                               Translator,
468                               Callback,
469                               Context
470                               );
471  } else {
472    IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
473
474    Status = UsbBus->UsbHc->AsyncInterruptTransfer (
475                              UsbBus->UsbHc,
476                              DevAddr,
477                              EpAddr,
478                              IsSlowDevice,
479                              (UINT8) MaxPacket,
480                              IsNewTransfer,
481                              DataToggle,
482                              PollingInterval,
483                              DataLength,
484                              Callback,
485                              Context
486                              );
487  }
488
489  return Status;
490}
491
492
493/**
494  Execute a synchronous interrupt transfer to the target endpoint.
495
496  @param  UsbBus           The USB bus driver.
497  @param  DevAddr          The target device address.
498  @param  EpAddr           The target endpoint address, with direction encoded in
499                           bit 7.
500  @param  DevSpeed         The device's speed.
501  @param  MaxPacket        The endpoint's max packet size.
502  @param  Data             Pointer to data buffer.
503  @param  DataLength       The length of data buffer.
504  @param  DataToggle       On input, the initial data toggle to use, also  return
505                           the next toggle on output.
506  @param  TimeOut          The time to wait until timeout.
507  @param  Translator       The transaction translator for low/full speed device.
508  @param  UsbResult        The result of USB execution.
509
510  @retval EFI_SUCCESS      The synchronous interrupt transfer is OK.
511  @retval Others           Failed to execute the synchronous interrupt transfer.
512
513**/
514EFI_STATUS
515UsbHcSyncInterruptTransfer (
516  IN  USB_BUS                             *UsbBus,
517  IN  UINT8                               DevAddr,
518  IN  UINT8                               EpAddr,
519  IN  UINT8                               DevSpeed,
520  IN  UINTN                               MaxPacket,
521  IN OUT VOID                             *Data,
522  IN OUT UINTN                            *DataLength,
523  IN OUT UINT8                            *DataToggle,
524  IN  UINTN                               TimeOut,
525  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
526  OUT UINT32                              *UsbResult
527  )
528{
529  EFI_STATUS              Status;
530  BOOLEAN                 IsSlowDevice;
531
532  if (UsbBus->Usb2Hc != NULL) {
533    Status = UsbBus->Usb2Hc->SyncInterruptTransfer (
534                               UsbBus->Usb2Hc,
535                               DevAddr,
536                               EpAddr,
537                               DevSpeed,
538                               MaxPacket,
539                               Data,
540                               DataLength,
541                               DataToggle,
542                               TimeOut,
543                               Translator,
544                               UsbResult
545                               );
546  } else {
547    IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DevSpeed) ? TRUE : FALSE);
548    Status = UsbBus->UsbHc->SyncInterruptTransfer (
549                              UsbBus->UsbHc,
550                              DevAddr,
551                              EpAddr,
552                              IsSlowDevice,
553                              (UINT8) MaxPacket,
554                              Data,
555                              DataLength,
556                              DataToggle,
557                              TimeOut,
558                              UsbResult
559                              );
560  }
561
562  return Status;
563}
564
565
566/**
567  Execute a synchronous Isochronous USB transfer.
568
569  @param  UsbBus           The USB bus driver.
570  @param  DevAddr          The target device address.
571  @param  EpAddr           The target endpoint address, with direction encoded in
572                           bit 7.
573  @param  DevSpeed         The device's speed.
574  @param  MaxPacket        The endpoint's max packet size.
575  @param  BufferNum        The number of data buffer.
576  @param  Data             Array of pointers to data buffer.
577  @param  DataLength       The length of data buffer.
578  @param  Translator       The transaction translator for low/full speed device.
579  @param  UsbResult        The result of USB execution.
580
581  @retval EFI_UNSUPPORTED  The isochronous transfer isn't supported now.
582
583**/
584EFI_STATUS
585UsbHcIsochronousTransfer (
586  IN  USB_BUS                             *UsbBus,
587  IN  UINT8                               DevAddr,
588  IN  UINT8                               EpAddr,
589  IN  UINT8                               DevSpeed,
590  IN  UINTN                               MaxPacket,
591  IN  UINT8                               BufferNum,
592  IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
593  IN  UINTN                               DataLength,
594  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
595  OUT UINT32                              *UsbResult
596  )
597{
598  return EFI_UNSUPPORTED;
599}
600
601
602/**
603  Queue an asynchronous isochronous transfer.
604
605  @param  UsbBus           The USB bus driver.
606  @param  DevAddr          The target device address.
607  @param  EpAddr           The target endpoint address, with direction encoded in
608                           bit 7.
609  @param  DevSpeed         The device's speed.
610  @param  MaxPacket        The endpoint's max packet size.
611  @param  BufferNum        The number of data buffer.
612  @param  Data             Array of pointers to data buffer.
613  @param  DataLength       The length of data buffer.
614  @param  Translator       The transaction translator for low/full speed device.
615  @param  Callback         The function to call when data is transferred.
616  @param  Context          The context to the callback function.
617
618  @retval EFI_UNSUPPORTED  The asynchronous isochronous transfer isn't supported.
619
620**/
621EFI_STATUS
622UsbHcAsyncIsochronousTransfer (
623  IN  USB_BUS                             *UsbBus,
624  IN  UINT8                               DevAddr,
625  IN  UINT8                               EpAddr,
626  IN  UINT8                               DevSpeed,
627  IN  UINTN                               MaxPacket,
628  IN  UINT8                               BufferNum,
629  IN OUT VOID                             *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
630  IN  UINTN                               DataLength,
631  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
632  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     Callback,
633  IN  VOID                                *Context
634  )
635{
636  return EFI_UNSUPPORTED;
637}
638
639
640/**
641  Open the USB host controller protocol BY_CHILD.
642
643  @param  Bus              The USB bus driver.
644  @param  Child            The child handle.
645
646  @return The open protocol return.
647
648**/
649EFI_STATUS
650UsbOpenHostProtoByChild (
651  IN USB_BUS              *Bus,
652  IN EFI_HANDLE           Child
653  )
654{
655  EFI_USB_HC_PROTOCOL     *UsbHc;
656  EFI_USB2_HC_PROTOCOL    *Usb2Hc;
657  EFI_STATUS              Status;
658
659  if (Bus->Usb2Hc != NULL) {
660    Status = gBS->OpenProtocol (
661                    Bus->HostHandle,
662                    &gEfiUsb2HcProtocolGuid,
663                    (VOID **) &Usb2Hc,
664                    mUsbBusDriverBinding.DriverBindingHandle,
665                    Child,
666                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
667                    );
668
669  } else {
670    Status = gBS->OpenProtocol (
671                    Bus->HostHandle,
672                    &gEfiUsbHcProtocolGuid,
673                    (VOID **) &UsbHc,
674                    mUsbBusDriverBinding.DriverBindingHandle,
675                    Child,
676                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
677                    );
678  }
679
680  return Status;
681}
682
683
684/**
685  Close the USB host controller protocol BY_CHILD.
686
687  @param  Bus              The USB bus driver.
688  @param  Child            The child handle.
689
690**/
691VOID
692UsbCloseHostProtoByChild (
693  IN USB_BUS              *Bus,
694  IN EFI_HANDLE           Child
695  )
696{
697  if (Bus->Usb2Hc != NULL) {
698    gBS->CloseProtocol (
699           Bus->HostHandle,
700           &gEfiUsb2HcProtocolGuid,
701           mUsbBusDriverBinding.DriverBindingHandle,
702           Child
703           );
704
705  } else {
706    gBS->CloseProtocol (
707           Bus->HostHandle,
708           &gEfiUsbHcProtocolGuid,
709           mUsbBusDriverBinding.DriverBindingHandle,
710           Child
711           );
712  }
713}
714
715
716/**
717  return the current TPL, copied from the EDKII glue lib.
718
719  @param  VOID.
720
721  @return Current TPL.
722
723**/
724EFI_TPL
725UsbGetCurrentTpl (
726  VOID
727  )
728{
729  EFI_TPL                 Tpl;
730
731  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
732  gBS->RestoreTPL (Tpl);
733
734  return Tpl;
735}
736
737/**
738  Create a new device path which only contain the first Usb part of the DevicePath.
739
740  @param DevicePath  A full device path which contain the usb nodes.
741
742  @return            A new device path which only contain the Usb part of the DevicePath.
743
744**/
745EFI_DEVICE_PATH_PROTOCOL *
746EFIAPI
747GetUsbDPFromFullDP (
748  IN EFI_DEVICE_PATH_PROTOCOL     *DevicePath
749  )
750{
751  EFI_DEVICE_PATH_PROTOCOL    *UsbDevicePathPtr;
752  EFI_DEVICE_PATH_PROTOCOL    *UsbDevicePathBeginPtr;
753  EFI_DEVICE_PATH_PROTOCOL    *UsbDevicePathEndPtr;
754  UINTN                       Size;
755
756  //
757  // Get the Usb part first Begin node in full device path
758  //
759  UsbDevicePathBeginPtr = DevicePath;
760  while ( (!IsDevicePathEnd (UsbDevicePathBeginPtr))&&
761         ((UsbDevicePathBeginPtr->Type != MESSAGING_DEVICE_PATH) ||
762         (UsbDevicePathBeginPtr->SubType != MSG_USB_DP &&
763          UsbDevicePathBeginPtr->SubType != MSG_USB_CLASS_DP
764          && UsbDevicePathBeginPtr->SubType != MSG_USB_WWID_DP
765          ))) {
766
767    UsbDevicePathBeginPtr = NextDevicePathNode(UsbDevicePathBeginPtr);
768  }
769
770  //
771  // Get the Usb part first End node in full device path
772  //
773  UsbDevicePathEndPtr = UsbDevicePathBeginPtr;
774  while ((!IsDevicePathEnd (UsbDevicePathEndPtr))&&
775         (UsbDevicePathEndPtr->Type == MESSAGING_DEVICE_PATH) &&
776         (UsbDevicePathEndPtr->SubType == MSG_USB_DP ||
777          UsbDevicePathEndPtr->SubType == MSG_USB_CLASS_DP
778          || UsbDevicePathEndPtr->SubType == MSG_USB_WWID_DP
779          )) {
780
781    UsbDevicePathEndPtr = NextDevicePathNode(UsbDevicePathEndPtr);
782  }
783
784  Size  = GetDevicePathSize (UsbDevicePathBeginPtr);
785  Size -= GetDevicePathSize (UsbDevicePathEndPtr);
786  if (Size ==0){
787    //
788    // The passed in DevicePath does not contain the usb nodes
789    //
790    return NULL;
791  }
792
793  //
794  // Create a new device path which only contain the above Usb part
795  //
796  UsbDevicePathPtr = AllocateZeroPool (Size + sizeof (EFI_DEVICE_PATH_PROTOCOL));
797  ASSERT (UsbDevicePathPtr != NULL);
798  CopyMem (UsbDevicePathPtr, UsbDevicePathBeginPtr, Size);
799  //
800  // Append end device path node
801  //
802  UsbDevicePathEndPtr = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) UsbDevicePathPtr + Size);
803  SetDevicePathEndNode (UsbDevicePathEndPtr);
804  return UsbDevicePathPtr;
805}
806
807/**
808  Check whether a usb device path is in a DEVICE_PATH_LIST_ITEM list.
809
810  @param UsbDP       a usb device path of DEVICE_PATH_LIST_ITEM.
811  @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list.
812
813  @retval TRUE       there is a DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP.
814  @retval FALSE      there is no DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP.
815
816**/
817BOOLEAN
818EFIAPI
819SearchUsbDPInList (
820  IN EFI_DEVICE_PATH_PROTOCOL     *UsbDP,
821  IN LIST_ENTRY                   *UsbIoDPList
822  )
823{
824  LIST_ENTRY                  *ListIndex;
825  DEVICE_PATH_LIST_ITEM       *ListItem;
826  BOOLEAN                     Found;
827  UINTN                       UsbDpDevicePathSize;
828
829  //
830  // Check that UsbDP and UsbIoDPList are valid
831  //
832  if ((UsbIoDPList == NULL) || (UsbDP == NULL)) {
833    return FALSE;
834  }
835
836  Found = FALSE;
837  ListIndex = UsbIoDPList->ForwardLink;
838  while (ListIndex != UsbIoDPList){
839    ListItem = CR(ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
840    //
841    // Compare DEVICE_PATH_LIST_ITEM.DevicePath[]
842    //
843    ASSERT (ListItem->DevicePath != NULL);
844
845    UsbDpDevicePathSize  = GetDevicePathSize (UsbDP);
846    if (UsbDpDevicePathSize == GetDevicePathSize (ListItem->DevicePath)) {
847      if ((CompareMem (UsbDP, ListItem->DevicePath, UsbDpDevicePathSize)) == 0) {
848        Found = TRUE;
849        break;
850      }
851    }
852    ListIndex =  ListIndex->ForwardLink;
853  }
854
855  return Found;
856}
857
858/**
859  Add a usb device path into the DEVICE_PATH_LIST_ITEM list.
860
861  @param UsbDP                   a usb device path of DEVICE_PATH_LIST_ITEM.
862  @param UsbIoDPList             a DEVICE_PATH_LIST_ITEM list.
863
864  @retval EFI_INVALID_PARAMETER  If parameters are invalid, return this value.
865  @retval EFI_SUCCESS            If Add operation is successful, return this value.
866
867**/
868EFI_STATUS
869EFIAPI
870AddUsbDPToList (
871  IN EFI_DEVICE_PATH_PROTOCOL     *UsbDP,
872  IN LIST_ENTRY                   *UsbIoDPList
873  )
874{
875  DEVICE_PATH_LIST_ITEM       *ListItem;
876
877  //
878  // Check that UsbDP and UsbIoDPList are valid
879  //
880  if ((UsbIoDPList == NULL) || (UsbDP == NULL)) {
881    return EFI_INVALID_PARAMETER;
882  }
883
884  if (SearchUsbDPInList (UsbDP, UsbIoDPList)){
885    return EFI_SUCCESS;
886  }
887
888  //
889  // Prepare the usbio device path DEVICE_PATH_LIST_ITEM structure.
890  //
891  ListItem = AllocateZeroPool (sizeof (DEVICE_PATH_LIST_ITEM));
892  ASSERT (ListItem != NULL);
893  ListItem->Signature = DEVICE_PATH_LIST_ITEM_SIGNATURE;
894  ListItem->DevicePath = DuplicateDevicePath (UsbDP);
895
896  InsertTailList (UsbIoDPList, &ListItem->Link);
897
898  return EFI_SUCCESS;
899}
900
901/**
902  Check whether usb device, whose interface is UsbIf, matches the usb class which indicated by
903  UsbClassDevicePathPtr whose is a short form usb class device path.
904
905  @param UsbClassDevicePathPtr    a short form usb class device path.
906  @param UsbIf                    a usb device interface.
907
908  @retval TRUE                    the usb device match the usb class.
909  @retval FALSE                   the usb device does not match the usb class.
910
911**/
912BOOLEAN
913EFIAPI
914MatchUsbClass (
915  IN USB_CLASS_DEVICE_PATH      *UsbClassDevicePathPtr,
916  IN USB_INTERFACE              *UsbIf
917  )
918{
919  USB_INTERFACE_DESC            *IfDesc;
920  EFI_USB_INTERFACE_DESCRIPTOR  *ActIfDesc;
921  EFI_USB_DEVICE_DESCRIPTOR     *DevDesc;
922
923
924  if ((UsbClassDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) ||
925      (UsbClassDevicePathPtr->Header.SubType != MSG_USB_CLASS_DP)){
926    ASSERT (0);
927    return FALSE;
928  }
929
930  IfDesc       = UsbIf->IfDesc;
931  ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
932  ActIfDesc    = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc);
933  DevDesc      = &(UsbIf->Device->DevDesc->Desc);
934
935  //
936  // If connect class policy, determine whether to create device handle by the five fields
937  // in class device path node.
938  //
939  // In addtion, hub interface is always matched for this policy.
940  //
941  if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) &&
942      (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
943    return TRUE;
944  }
945
946  //
947  // If vendor id or product id is 0xffff, they will be ignored.
948  //
949  if ((UsbClassDevicePathPtr->VendorId == 0xffff || UsbClassDevicePathPtr->VendorId == DevDesc->IdVendor) &&
950      (UsbClassDevicePathPtr->ProductId == 0xffff || UsbClassDevicePathPtr->ProductId == DevDesc->IdProduct)) {
951
952    //
953    // If Class in Device Descriptor is set to 0, the counterparts in interface should be checked.
954    //
955    if (DevDesc->DeviceClass == 0) {
956      if ((UsbClassDevicePathPtr->DeviceClass == ActIfDesc->InterfaceClass ||
957                                          UsbClassDevicePathPtr->DeviceClass == 0xff) &&
958          (UsbClassDevicePathPtr->DeviceSubClass == ActIfDesc->InterfaceSubClass ||
959                                       UsbClassDevicePathPtr->DeviceSubClass == 0xff) &&
960          (UsbClassDevicePathPtr->DeviceProtocol == ActIfDesc->InterfaceProtocol ||
961                                       UsbClassDevicePathPtr->DeviceProtocol == 0xff)) {
962        return TRUE;
963      }
964
965    } else if ((UsbClassDevicePathPtr->DeviceClass == DevDesc->DeviceClass ||
966                                         UsbClassDevicePathPtr->DeviceClass == 0xff) &&
967               (UsbClassDevicePathPtr->DeviceSubClass == DevDesc->DeviceSubClass ||
968                                      UsbClassDevicePathPtr->DeviceSubClass == 0xff) &&
969               (UsbClassDevicePathPtr->DeviceProtocol == DevDesc->DeviceProtocol ||
970                                      UsbClassDevicePathPtr->DeviceProtocol == 0xff)) {
971
972      return TRUE;
973    }
974  }
975
976  return FALSE;
977}
978
979/**
980  Check whether usb device, whose interface is UsbIf, matches the usb WWID requirement which indicated by
981  UsbWWIDDevicePathPtr whose is a short form usb WWID device path.
982
983  @param UsbWWIDDevicePathPtr    a short form usb WWID device path.
984  @param UsbIf                   a usb device interface.
985
986  @retval TRUE                   the usb device match the usb WWID requirement.
987  @retval FALSE                  the usb device does not match the usb WWID requirement.
988
989**/
990BOOLEAN
991MatchUsbWwid (
992  IN USB_WWID_DEVICE_PATH       *UsbWWIDDevicePathPtr,
993  IN USB_INTERFACE              *UsbIf
994  )
995{
996  USB_INTERFACE_DESC            *IfDesc;
997  EFI_USB_INTERFACE_DESCRIPTOR  *ActIfDesc;
998  EFI_USB_DEVICE_DESCRIPTOR     *DevDesc;
999  EFI_USB_STRING_DESCRIPTOR     *StrDesc;
1000  UINT16                        Index;
1001  CHAR16                        *CompareStr;
1002  UINTN                         CompareLen;
1003  UINTN                         Length;
1004
1005  if ((UsbWWIDDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) ||
1006     (UsbWWIDDevicePathPtr->Header.SubType != MSG_USB_WWID_DP )){
1007    ASSERT (0);
1008    return FALSE;
1009  }
1010
1011  IfDesc       = UsbIf->IfDesc;
1012  ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
1013  ActIfDesc    = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc);
1014  DevDesc      = &(UsbIf->Device->DevDesc->Desc);
1015
1016  //
1017  // In addition, Hub interface is always matched for this policy.
1018  //
1019  if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) &&
1020      (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
1021    return TRUE;
1022  }
1023
1024  //
1025  // Check Vendor Id, Product Id and Interface Number.
1026  //
1027  if ((DevDesc->IdVendor != UsbWWIDDevicePathPtr->VendorId) ||
1028      (DevDesc->IdProduct != UsbWWIDDevicePathPtr->ProductId) ||
1029      (ActIfDesc->InterfaceNumber != UsbWWIDDevicePathPtr->InterfaceNumber)) {
1030    return FALSE;
1031  }
1032
1033  //
1034  // Check SerialNumber.
1035  //
1036  if (DevDesc->StrSerialNumber == 0) {
1037    return FALSE;
1038  }
1039
1040  //
1041  // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
1042  //
1043  CompareStr = (CHAR16 *) (UINTN) (UsbWWIDDevicePathPtr + 1);
1044  CompareLen = (DevicePathNodeLength (UsbWWIDDevicePathPtr) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
1045  if (CompareStr[CompareLen - 1] == L'\0') {
1046    CompareLen--;
1047  }
1048
1049  //
1050  // Compare serial number in each supported language.
1051  //
1052  for (Index = 0; Index < UsbIf->Device->TotalLangId; Index++) {
1053    StrDesc = UsbGetOneString (UsbIf->Device, DevDesc->StrSerialNumber, UsbIf->Device->LangId[Index]);
1054    if (StrDesc == NULL) {
1055      continue;
1056    }
1057
1058    Length = (StrDesc->Length - 2) / sizeof (CHAR16);
1059    if ((Length >= CompareLen) &&
1060        (CompareMem (StrDesc->String + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
1061      return TRUE;
1062    }
1063  }
1064
1065  return FALSE;
1066}
1067
1068/**
1069  Free a DEVICE_PATH_LIST_ITEM list.
1070
1071  @param  UsbIoDPList            a DEVICE_PATH_LIST_ITEM list pointer.
1072
1073  @retval EFI_INVALID_PARAMETER  If parameters are invalid, return this value.
1074  @retval EFI_SUCCESS            If free operation is successful, return this value.
1075
1076**/
1077EFI_STATUS
1078EFIAPI
1079UsbBusFreeUsbDPList (
1080  IN LIST_ENTRY          *UsbIoDPList
1081  )
1082{
1083  LIST_ENTRY                  *ListIndex;
1084  DEVICE_PATH_LIST_ITEM       *ListItem;
1085
1086  //
1087  // Check that ControllerHandle is a valid handle
1088  //
1089  if (UsbIoDPList == NULL) {
1090    return EFI_INVALID_PARAMETER;
1091  }
1092
1093  ListIndex = UsbIoDPList->ForwardLink;
1094  while (ListIndex != UsbIoDPList){
1095    ListItem = CR(ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
1096    //
1097    // Free DEVICE_PATH_LIST_ITEM.DevicePath[]
1098    //
1099    if (ListItem->DevicePath != NULL){
1100      FreePool(ListItem->DevicePath);
1101    }
1102    //
1103    // Free DEVICE_PATH_LIST_ITEM itself
1104    //
1105    ListIndex =  ListIndex->ForwardLink;
1106    RemoveEntryList (&ListItem->Link);
1107    FreePool (ListItem);
1108  }
1109
1110  InitializeListHead (UsbIoDPList);
1111  return EFI_SUCCESS;
1112}
1113
1114/**
1115  Store a wanted usb child device info (its Usb part of device path) which is indicated by
1116  RemainingDevicePath in a Usb bus which  is indicated by UsbBusId.
1117
1118  @param  UsbBusId               Point to EFI_USB_BUS_PROTOCOL interface.
1119  @param  RemainingDevicePath    The remaining device patch.
1120
1121  @retval EFI_SUCCESS            Add operation is successful.
1122  @retval EFI_INVALID_PARAMETER  The parameters are invalid.
1123
1124**/
1125EFI_STATUS
1126EFIAPI
1127UsbBusAddWantedUsbIoDP (
1128  IN EFI_USB_BUS_PROTOCOL         *UsbBusId,
1129  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
1130  )
1131{
1132  USB_BUS                       *Bus;
1133  EFI_STATUS                    Status;
1134  EFI_DEVICE_PATH_PROTOCOL      *DevicePathPtr;
1135
1136  //
1137  // Check whether remaining device path is valid
1138  //
1139  if (RemainingDevicePath != NULL && !IsDevicePathEnd (RemainingDevicePath)) {
1140    if ((RemainingDevicePath->Type    != MESSAGING_DEVICE_PATH) ||
1141        (RemainingDevicePath->SubType != MSG_USB_DP &&
1142         RemainingDevicePath->SubType != MSG_USB_CLASS_DP
1143         && RemainingDevicePath->SubType != MSG_USB_WWID_DP
1144         )) {
1145      return EFI_INVALID_PARAMETER;
1146    }
1147  }
1148
1149  if (UsbBusId == NULL){
1150    return EFI_INVALID_PARAMETER;
1151  }
1152
1153  Bus = USB_BUS_FROM_THIS (UsbBusId);
1154
1155  if (RemainingDevicePath == NULL) {
1156    //
1157    // RemainingDevicePath == NULL means all Usb devices in this bus are wanted.
1158    // Here use a Usb class Device Path in WantedUsbIoDPList to indicate all Usb devices
1159    // are wanted Usb devices
1160    //
1161    Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);
1162    ASSERT (!EFI_ERROR (Status));
1163    DevicePathPtr = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) &mAllUsbClassDevicePath);
1164  } else if (!IsDevicePathEnd (RemainingDevicePath)) {
1165    //
1166    // If RemainingDevicePath isn't the End of Device Path Node,
1167    // Create new Usb device path according to the usb part in remaining device path
1168    //
1169    DevicePathPtr = GetUsbDPFromFullDP (RemainingDevicePath);
1170  } else {
1171    //
1172    // If RemainingDevicePath is the End of Device Path Node,
1173    // skip enumerate any device and return EFI_SUCESSS
1174    //
1175    return EFI_SUCCESS;
1176  }
1177
1178  ASSERT (DevicePathPtr != NULL);
1179  Status = AddUsbDPToList (DevicePathPtr, &Bus->WantedUsbIoDPList);
1180  ASSERT (!EFI_ERROR (Status));
1181  FreePool (DevicePathPtr);
1182  return EFI_SUCCESS;
1183}
1184
1185/**
1186  Check whether a usb child device is the wanted device in a bus.
1187
1188  @param  Bus     The Usb bus's private data pointer.
1189  @param  UsbIf   The usb child device inferface.
1190
1191  @retval True    If a usb child device is the wanted device in a bus.
1192  @retval False   If a usb child device is *NOT* the wanted device in a bus.
1193
1194**/
1195BOOLEAN
1196EFIAPI
1197UsbBusIsWantedUsbIO (
1198  IN USB_BUS                 *Bus,
1199  IN USB_INTERFACE           *UsbIf
1200  )
1201{
1202  EFI_DEVICE_PATH_PROTOCOL      *DevicePathPtr;
1203  LIST_ENTRY                    *WantedUsbIoDPListPtr;
1204  LIST_ENTRY                    *WantedListIndex;
1205  DEVICE_PATH_LIST_ITEM         *WantedListItem;
1206  BOOLEAN                       DoConvert;
1207  UINTN                         FirstDevicePathSize;
1208
1209  //
1210  // Check whether passed in parameters are valid
1211  //
1212  if ((UsbIf == NULL) || (Bus == NULL)) {
1213    return FALSE;
1214  }
1215  //
1216  // Check whether UsbIf is Hub
1217  //
1218  if (UsbIf->IsHub) {
1219    return TRUE;
1220  }
1221
1222  //
1223  // Check whether all Usb devices in this bus are wanted
1224  //
1225  if (SearchUsbDPInList ((EFI_DEVICE_PATH_PROTOCOL *)&mAllUsbClassDevicePath, &Bus->WantedUsbIoDPList)){
1226    return TRUE;
1227  }
1228
1229  //
1230  // Check whether the Usb device match any item in WantedUsbIoDPList
1231  //
1232  WantedUsbIoDPListPtr = &Bus->WantedUsbIoDPList;
1233  //
1234  // Create new Usb device path according to the usb part in UsbIo full device path
1235  //
1236  DevicePathPtr = GetUsbDPFromFullDP (UsbIf->DevicePath);
1237  ASSERT (DevicePathPtr != NULL);
1238
1239  DoConvert = FALSE;
1240  WantedListIndex = WantedUsbIoDPListPtr->ForwardLink;
1241  while (WantedListIndex != WantedUsbIoDPListPtr){
1242    WantedListItem = CR(WantedListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE);
1243    ASSERT (WantedListItem->DevicePath->Type == MESSAGING_DEVICE_PATH);
1244    switch (WantedListItem->DevicePath->SubType) {
1245    case MSG_USB_DP:
1246      FirstDevicePathSize = GetDevicePathSize (WantedListItem->DevicePath);
1247      if (FirstDevicePathSize == GetDevicePathSize (DevicePathPtr)) {
1248        if (CompareMem (
1249              WantedListItem->DevicePath,
1250              DevicePathPtr,
1251              GetDevicePathSize (DevicePathPtr)) == 0
1252            ) {
1253          DoConvert = TRUE;
1254        }
1255      }
1256      break;
1257    case MSG_USB_CLASS_DP:
1258      if (MatchUsbClass((USB_CLASS_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) {
1259        DoConvert = TRUE;
1260      }
1261      break;
1262   case MSG_USB_WWID_DP:
1263      if (MatchUsbWwid((USB_WWID_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) {
1264        DoConvert = TRUE;
1265      }
1266      break;
1267    default:
1268      ASSERT (0);
1269      break;
1270    }
1271
1272    if (DoConvert) {
1273      break;
1274    }
1275
1276    WantedListIndex =  WantedListIndex->ForwardLink;
1277  }
1278  gBS->FreePool (DevicePathPtr);
1279
1280  //
1281  // Check whether the new Usb device path is wanted
1282  //
1283  if (DoConvert){
1284    return TRUE;
1285  } else {
1286    return FALSE;
1287  }
1288}
1289
1290/**
1291  Recursively connnect every wanted usb child device to ensure they all fully connected.
1292  Check all the child Usb IO handles in this bus, recursively connecte if it is wanted usb child device.
1293
1294  @param  UsbBusId                  Point to EFI_USB_BUS_PROTOCOL interface.
1295
1296  @retval EFI_SUCCESS               Connect is done successfully.
1297  @retval EFI_INVALID_PARAMETER     The parameter is invalid.
1298
1299**/
1300EFI_STATUS
1301EFIAPI
1302UsbBusRecursivelyConnectWantedUsbIo (
1303  IN EFI_USB_BUS_PROTOCOL         *UsbBusId
1304  )
1305{
1306  USB_BUS                       *Bus;
1307  EFI_STATUS                    Status;
1308  UINTN                         Index;
1309  EFI_USB_IO_PROTOCOL           *UsbIo;
1310  USB_INTERFACE                 *UsbIf;
1311  UINTN                         UsbIoHandleCount;
1312  EFI_HANDLE                    *UsbIoBuffer;
1313  EFI_DEVICE_PATH_PROTOCOL      *UsbIoDevicePath;
1314
1315  if (UsbBusId == NULL){
1316    return EFI_INVALID_PARAMETER;
1317  }
1318
1319  Bus = USB_BUS_FROM_THIS (UsbBusId);
1320
1321  //
1322  // Get all Usb IO handles in system
1323  //
1324  UsbIoHandleCount = 0;
1325  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
1326  if (Status == EFI_NOT_FOUND || UsbIoHandleCount == 0) {
1327    return EFI_SUCCESS;
1328  }
1329  ASSERT (!EFI_ERROR (Status));
1330
1331  for (Index = 0; Index < UsbIoHandleCount; Index++) {
1332    //
1333    // Check whether the USB IO handle is a child of this bus
1334    // Note: The usb child handle maybe invalid because of hot plugged out during the loop
1335    //
1336    UsbIoDevicePath = NULL;
1337    Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &UsbIoDevicePath);
1338    if (EFI_ERROR (Status) || UsbIoDevicePath == NULL) {
1339      continue;
1340    }
1341    if (CompareMem (
1342            UsbIoDevicePath,
1343            Bus->DevicePath,
1344            (GetDevicePathSize (Bus->DevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL))
1345            ) != 0) {
1346      continue;
1347    }
1348
1349    //
1350    // Get the child Usb IO interface
1351    //
1352    Status = gBS->HandleProtocol(
1353                     UsbIoBuffer[Index],
1354                     &gEfiUsbIoProtocolGuid,
1355                     (VOID **) &UsbIo
1356                     );
1357    if (EFI_ERROR (Status)) {
1358      continue;
1359    }
1360    UsbIf   = USB_INTERFACE_FROM_USBIO (UsbIo);
1361
1362    if (UsbBusIsWantedUsbIO (Bus, UsbIf)) {
1363      if (!UsbIf->IsManaged) {
1364        //
1365        // Recursively connect the wanted Usb Io handle
1366        //
1367        DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d\n", (UINT32)UsbGetCurrentTpl ()));
1368        Status            = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
1369        UsbIf->IsManaged  = (BOOLEAN)!EFI_ERROR (Status);
1370        DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl()));
1371      }
1372    }
1373  }
1374
1375  FreePool (UsbIoBuffer);
1376
1377  return EFI_SUCCESS;
1378}
1379
1380