Home | History | Annotate | Download | only in UsbBusDxe
      1 /** @file
      2 
      3     Wrapper function for usb host controller interface.
      4 
      5 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 
     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 //
     24 USB_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 **/
     64 EFI_STATUS
     65 UsbHcGetCapability (
     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 **/
    105 EFI_STATUS
    106 UsbHcReset (
    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 **/
    133 EFI_STATUS
    134 UsbHcGetState (
    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 **/
    161 EFI_STATUS
    162 UsbHcSetState (
    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 **/
    190 EFI_STATUS
    191 UsbHcGetRootHubPortStatus (
    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 **/
    220 EFI_STATUS
    221 UsbHcSetRootHubPortFeature (
    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 **/
    251 EFI_STATUS
    252 UsbHcClearRootHubPortFeature (
    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 **/
    289 EFI_STATUS
    290 UsbHcControlTransfer (
    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 **/
    364 EFI_STATUS
    365 UsbHcBulkTransfer (
    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 **/
    437 EFI_STATUS
    438 UsbHcAsyncInterruptTransfer (
    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 **/
    514 EFI_STATUS
    515 UsbHcSyncInterruptTransfer (
    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 **/
    584 EFI_STATUS
    585 UsbHcIsochronousTransfer (
    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 **/
    621 EFI_STATUS
    622 UsbHcAsyncIsochronousTransfer (
    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 **/
    649 EFI_STATUS
    650 UsbOpenHostProtoByChild (
    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 **/
    691 VOID
    692 UsbCloseHostProtoByChild (
    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 **/
    724 EFI_TPL
    725 UsbGetCurrentTpl (
    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 **/
    745 EFI_DEVICE_PATH_PROTOCOL *
    746 EFIAPI
    747 GetUsbDPFromFullDP (
    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 **/
    817 BOOLEAN
    818 EFIAPI
    819 SearchUsbDPInList (
    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 **/
    868 EFI_STATUS
    869 EFIAPI
    870 AddUsbDPToList (
    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 **/
    912 BOOLEAN
    913 EFIAPI
    914 MatchUsbClass (
    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 **/
    990 BOOLEAN
    991 MatchUsbWwid (
    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 **/
   1077 EFI_STATUS
   1078 EFIAPI
   1079 UsbBusFreeUsbDPList (
   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 **/
   1125 EFI_STATUS
   1126 EFIAPI
   1127 UsbBusAddWantedUsbIoDP (
   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 **/
   1195 BOOLEAN
   1196 EFIAPI
   1197 UsbBusIsWantedUsbIO (
   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 **/
   1300 EFI_STATUS
   1301 EFIAPI
   1302 UsbBusRecursivelyConnectWantedUsbIo (
   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   return EFI_SUCCESS;
   1376 }
   1377 
   1378