Home | History | Annotate | Download | only in UsbBusDxe
      1 /** @file
      2 
      3     Usb bus enumeration support.
      4 
      5 Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "UsbBus.h"
     17 
     18 /**
     19   Return the endpoint descriptor in this interface.
     20 
     21   @param  UsbIf                 The interface to search in.
     22   @param  EpAddr                The address of the endpoint to return.
     23 
     24   @return The endpoint descriptor or NULL.
     25 
     26 **/
     27 USB_ENDPOINT_DESC *
     28 UsbGetEndpointDesc (
     29   IN USB_INTERFACE        *UsbIf,
     30   IN UINT8                EpAddr
     31   )
     32 {
     33   USB_ENDPOINT_DESC       *EpDesc;
     34   UINT8                   Index;
     35   UINT8                   NumEndpoints;
     36 
     37   NumEndpoints = UsbIf->IfSetting->Desc.NumEndpoints;
     38 
     39   for (Index = 0; Index < NumEndpoints; Index++) {
     40     EpDesc = UsbIf->IfSetting->Endpoints[Index];
     41 
     42     if (EpDesc->Desc.EndpointAddress == EpAddr) {
     43       return EpDesc;
     44     }
     45   }
     46 
     47   return NULL;
     48 }
     49 
     50 
     51 /**
     52   Free the resource used by USB interface.
     53 
     54   @param  UsbIf                 The USB interface to free.
     55 
     56 **/
     57 VOID
     58 UsbFreeInterface (
     59   IN USB_INTERFACE        *UsbIf
     60   )
     61 {
     62   UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
     63 
     64   gBS->UninstallMultipleProtocolInterfaces (
     65          UsbIf->Handle,
     66          &gEfiDevicePathProtocolGuid,
     67          UsbIf->DevicePath,
     68          &gEfiUsbIoProtocolGuid,
     69          &UsbIf->UsbIo,
     70          NULL
     71          );
     72 
     73   if (UsbIf->DevicePath != NULL) {
     74     FreePool (UsbIf->DevicePath);
     75   }
     76 
     77   FreePool (UsbIf);
     78 }
     79 
     80 
     81 /**
     82   Create an interface for the descriptor IfDesc. Each
     83   device's configuration can have several interfaces.
     84 
     85   @param  Device                The device has the interface descriptor.
     86   @param  IfDesc                The interface descriptor.
     87 
     88   @return The created USB interface for the descriptor, or NULL.
     89 
     90 **/
     91 USB_INTERFACE *
     92 UsbCreateInterface (
     93   IN USB_DEVICE           *Device,
     94   IN USB_INTERFACE_DESC   *IfDesc
     95   )
     96 {
     97   USB_DEVICE_PATH         UsbNode;
     98   USB_INTERFACE           *UsbIf;
     99   USB_INTERFACE           *HubIf;
    100   EFI_STATUS              Status;
    101 
    102   UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));
    103 
    104   if (UsbIf == NULL) {
    105     return NULL;
    106   }
    107 
    108   UsbIf->Signature  = USB_INTERFACE_SIGNATURE;
    109   UsbIf->Device     = Device;
    110   UsbIf->IfDesc     = IfDesc;
    111   ASSERT (IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
    112   UsbIf->IfSetting  = IfDesc->Settings[IfDesc->ActiveIndex];
    113 
    114   CopyMem (
    115     &(UsbIf->UsbIo),
    116     &mUsbIoProtocol,
    117     sizeof (EFI_USB_IO_PROTOCOL)
    118     );
    119 
    120   //
    121   // Install protocols for USBIO and device path
    122   //
    123   UsbNode.Header.Type       = MESSAGING_DEVICE_PATH;
    124   UsbNode.Header.SubType    = MSG_USB_DP;
    125   UsbNode.ParentPortNumber  = Device->ParentPort;
    126   UsbNode.InterfaceNumber   = UsbIf->IfSetting->Desc.InterfaceNumber;
    127 
    128   SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
    129 
    130   HubIf = Device->ParentIf;
    131   ASSERT (HubIf != NULL);
    132 
    133   UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);
    134 
    135   if (UsbIf->DevicePath == NULL) {
    136     DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to create device path\n"));
    137 
    138     Status = EFI_OUT_OF_RESOURCES;
    139     goto ON_ERROR;
    140   }
    141 
    142   Status = gBS->InstallMultipleProtocolInterfaces (
    143                   &UsbIf->Handle,
    144                   &gEfiDevicePathProtocolGuid,
    145                   UsbIf->DevicePath,
    146                   &gEfiUsbIoProtocolGuid,
    147                   &UsbIf->UsbIo,
    148                   NULL
    149                   );
    150 
    151   if (EFI_ERROR (Status)) {
    152     DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to install UsbIo - %r\n", Status));
    153     goto ON_ERROR;
    154   }
    155 
    156   //
    157   // Open USB Host Controller Protocol by Child
    158   //
    159   Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);
    160 
    161   if (EFI_ERROR (Status)) {
    162     gBS->UninstallMultipleProtocolInterfaces (
    163            &UsbIf->Handle,
    164            &gEfiDevicePathProtocolGuid,
    165            UsbIf->DevicePath,
    166            &gEfiUsbIoProtocolGuid,
    167            &UsbIf->UsbIo,
    168            NULL
    169            );
    170 
    171     DEBUG ((EFI_D_ERROR, "UsbCreateInterface: failed to open host for child - %r\n", Status));
    172     goto ON_ERROR;
    173   }
    174 
    175   return UsbIf;
    176 
    177 ON_ERROR:
    178   if (UsbIf->DevicePath != NULL) {
    179     FreePool (UsbIf->DevicePath);
    180   }
    181 
    182   FreePool (UsbIf);
    183   return NULL;
    184 }
    185 
    186 
    187 /**
    188   Free the resource used by this USB device.
    189 
    190   @param  Device                The USB device to free.
    191 
    192 **/
    193 VOID
    194 UsbFreeDevice (
    195   IN USB_DEVICE           *Device
    196   )
    197 {
    198   if (Device->DevDesc != NULL) {
    199     UsbFreeDevDesc (Device->DevDesc);
    200   }
    201 
    202   gBS->FreePool (Device);
    203 }
    204 
    205 
    206 /**
    207   Create a device which is on the parent's ParentPort port.
    208 
    209   @param  ParentIf              The parent HUB interface.
    210   @param  ParentPort            The port on the HUB this device is connected to.
    211 
    212   @return Created USB device, Or NULL.
    213 
    214 **/
    215 USB_DEVICE *
    216 UsbCreateDevice (
    217   IN USB_INTERFACE        *ParentIf,
    218   IN UINT8                ParentPort
    219   )
    220 {
    221   USB_DEVICE              *Device;
    222 
    223   ASSERT (ParentIf != NULL);
    224 
    225   Device = AllocateZeroPool (sizeof (USB_DEVICE));
    226 
    227   if (Device == NULL) {
    228     return NULL;
    229   }
    230 
    231   Device->Bus         = ParentIf->Device->Bus;
    232   Device->MaxPacket0  = 8;
    233   Device->ParentAddr  = ParentIf->Device->Address;
    234   Device->ParentIf    = ParentIf;
    235   Device->ParentPort  = ParentPort;
    236   Device->Tier        = (UINT8)(ParentIf->Device->Tier + 1);
    237   return Device;
    238 }
    239 
    240 
    241 /**
    242   Connect the USB interface with its driver. EFI USB bus will
    243   create a USB interface for each separate interface descriptor.
    244 
    245   @param  UsbIf             The interface to connect driver to.
    246 
    247   @return EFI_SUCCESS       Interface is managed by some driver.
    248   @return Others            Failed to locate a driver for this interface.
    249 
    250 **/
    251 EFI_STATUS
    252 UsbConnectDriver (
    253   IN USB_INTERFACE        *UsbIf
    254   )
    255 {
    256   EFI_STATUS              Status;
    257   EFI_TPL                 OldTpl;
    258 
    259   Status = EFI_SUCCESS;
    260 
    261   //
    262   // Hub is maintained by the USB bus driver. Otherwise try to
    263   // connect drivers with this interface
    264   //
    265   if (UsbIsHubInterface (UsbIf)) {
    266     DEBUG ((EFI_D_INFO, "UsbConnectDriver: found a hub device\n"));
    267     Status = mUsbHubApi.Init (UsbIf);
    268 
    269   } else {
    270     //
    271     // This function is called in both UsbIoControlTransfer and
    272     // the timer callback in hub enumeration. So, at least it is
    273     // called at TPL_CALLBACK. Some driver sitting on USB has
    274     // twisted TPL used. It should be no problem for us to connect
    275     // or disconnect at CALLBACK.
    276     //
    277 
    278     //
    279     // Only recursively wanted usb child device
    280     //
    281     if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) {
    282       OldTpl            = UsbGetCurrentTpl ();
    283       DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));
    284 
    285       gBS->RestoreTPL (TPL_CALLBACK);
    286 
    287       Status            = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
    288       UsbIf->IsManaged  = (BOOLEAN)!EFI_ERROR (Status);
    289 
    290       DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl()));
    291       ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
    292 
    293       gBS->RaiseTPL (OldTpl);
    294     }
    295   }
    296 
    297   return Status;
    298 }
    299 
    300 
    301 /**
    302   Select an alternate setting for the interface.
    303   Each interface can have several mutually exclusive
    304   settings. Only one setting is active. It will
    305   also reset its endpoints' toggle to zero.
    306 
    307   @param  IfDesc                The interface descriptor to set.
    308   @param  Alternate             The alternate setting number to locate.
    309 
    310   @retval EFI_NOT_FOUND         There is no setting with this alternate index.
    311   @retval EFI_SUCCESS           The interface is set to Alternate setting.
    312 
    313 **/
    314 EFI_STATUS
    315 UsbSelectSetting (
    316   IN USB_INTERFACE_DESC   *IfDesc,
    317   IN UINT8                Alternate
    318   )
    319 {
    320   USB_INTERFACE_SETTING   *Setting;
    321   UINTN                   Index;
    322 
    323   //
    324   // Locate the active alternate setting
    325   //
    326   Setting = NULL;
    327 
    328   for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {
    329     ASSERT (Index < USB_MAX_INTERFACE_SETTING);
    330     Setting = IfDesc->Settings[Index];
    331 
    332     if (Setting->Desc.AlternateSetting == Alternate) {
    333       break;
    334     }
    335   }
    336 
    337   if (Index == IfDesc->NumOfSetting) {
    338     return EFI_NOT_FOUND;
    339   }
    340 
    341   IfDesc->ActiveIndex = Index;
    342 
    343   ASSERT (Setting != NULL);
    344   DEBUG ((EFI_D_INFO, "UsbSelectSetting: setting %d selected for interface %d\n",
    345               Alternate, Setting->Desc.InterfaceNumber));
    346 
    347   //
    348   // Reset the endpoint toggle to zero
    349   //
    350   for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
    351     Setting->Endpoints[Index]->Toggle = 0;
    352   }
    353 
    354   return EFI_SUCCESS;
    355 }
    356 
    357 
    358 /**
    359   Select a new configuration for the device. Each
    360   device may support several configurations.
    361 
    362   @param  Device                The device to select configuration.
    363   @param  ConfigValue           The index of the configuration ( != 0).
    364 
    365   @retval EFI_NOT_FOUND         There is no configuration with the index.
    366   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource.
    367   @retval EFI_SUCCESS           The configuration is selected.
    368 
    369 **/
    370 EFI_STATUS
    371 UsbSelectConfig (
    372   IN USB_DEVICE           *Device,
    373   IN UINT8                ConfigValue
    374   )
    375 {
    376   USB_DEVICE_DESC         *DevDesc;
    377   USB_CONFIG_DESC         *ConfigDesc;
    378   USB_INTERFACE_DESC      *IfDesc;
    379   USB_INTERFACE           *UsbIf;
    380   EFI_STATUS              Status;
    381   UINT8                   Index;
    382 
    383   //
    384   // Locate the active config, then set the device's pointer
    385   //
    386   DevDesc     = Device->DevDesc;
    387   ConfigDesc  = NULL;
    388 
    389   for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
    390     ConfigDesc = DevDesc->Configs[Index];
    391 
    392     if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {
    393       break;
    394     }
    395   }
    396 
    397   if (Index == DevDesc->Desc.NumConfigurations) {
    398     return EFI_NOT_FOUND;
    399   }
    400 
    401   Device->ActiveConfig = ConfigDesc;
    402 
    403   DEBUG ((EFI_D_INFO, "UsbSelectConfig: config %d selected for device %d\n",
    404               ConfigValue, Device->Address));
    405 
    406   //
    407   // Create interfaces for each USB interface descriptor.
    408   //
    409   for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {
    410     //
    411     // First select the default interface setting, and reset
    412     // the endpoint toggles to zero for its endpoints.
    413     //
    414     IfDesc = ConfigDesc->Interfaces[Index];
    415     UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);
    416 
    417     //
    418     // Create a USB_INTERFACE and install USB_IO and other protocols
    419     //
    420     UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);
    421 
    422     if (UsbIf == NULL) {
    423       Device->NumOfInterface = Index;
    424       return EFI_OUT_OF_RESOURCES;
    425     }
    426 
    427     ASSERT (Index < USB_MAX_INTERFACE);
    428     Device->Interfaces[Index] = UsbIf;
    429 
    430     //
    431     // Connect the device to drivers, if it failed, ignore
    432     // the error. Don't let the unsupported interfaces to block
    433     // the supported interfaces.
    434     //
    435     Status = UsbConnectDriver (UsbIf);
    436 
    437     if (EFI_ERROR (Status)) {
    438       DEBUG ((EFI_D_ERROR, "UsbSelectConfig: failed to connect driver %r, ignored\n", Status));
    439     }
    440   }
    441 
    442   Device->NumOfInterface = Index;
    443 
    444   return EFI_SUCCESS;
    445 }
    446 
    447 
    448 /**
    449   Disconnect the USB interface with its driver.
    450 
    451   @param  UsbIf                 The interface to disconnect driver from.
    452 
    453 **/
    454 EFI_STATUS
    455 UsbDisconnectDriver (
    456   IN USB_INTERFACE        *UsbIf
    457   )
    458 {
    459   EFI_TPL                 OldTpl;
    460   EFI_STATUS              Status;
    461 
    462   //
    463   // Release the hub if it's a hub controller, otherwise
    464   // disconnect the driver if it is managed by other drivers.
    465   //
    466   Status = EFI_SUCCESS;
    467   if (UsbIf->IsHub) {
    468     Status = UsbIf->HubApi->Release (UsbIf);
    469 
    470   } else if (UsbIf->IsManaged) {
    471     //
    472     // This function is called in both UsbIoControlTransfer and
    473     // the timer callback in hub enumeration. So, at least it is
    474     // called at TPL_CALLBACK. Some driver sitting on USB has
    475     // twisted TPL used. It should be no problem for us to connect
    476     // or disconnect at CALLBACK.
    477     //
    478     OldTpl           = UsbGetCurrentTpl ();
    479     DEBUG ((EFI_D_INFO, "UsbDisconnectDriver: old TPL is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));
    480 
    481     gBS->RestoreTPL (TPL_CALLBACK);
    482 
    483     Status = gBS->DisconnectController (UsbIf->Handle, NULL, NULL);
    484     if (!EFI_ERROR (Status)) {
    485       UsbIf->IsManaged = FALSE;
    486     }
    487 
    488     DEBUG (( EFI_D_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl(), Status));
    489     ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
    490 
    491     gBS->RaiseTPL (OldTpl);
    492   }
    493 
    494   return Status;
    495 }
    496 
    497 
    498 /**
    499   Remove the current device configuration.
    500 
    501   @param  Device                The USB device to remove configuration from.
    502 
    503 **/
    504 EFI_STATUS
    505 UsbRemoveConfig (
    506   IN USB_DEVICE           *Device
    507   )
    508 {
    509   USB_INTERFACE           *UsbIf;
    510   UINTN                   Index;
    511   EFI_STATUS              Status;
    512   EFI_STATUS              ReturnStatus;
    513 
    514   //
    515   // Remove each interface of the device
    516   //
    517   ReturnStatus = EFI_SUCCESS;
    518   for (Index = 0; Index < Device->NumOfInterface; Index++) {
    519     ASSERT (Index < USB_MAX_INTERFACE);
    520     UsbIf = Device->Interfaces[Index];
    521 
    522     if (UsbIf == NULL) {
    523       continue;
    524     }
    525 
    526     Status = UsbDisconnectDriver (UsbIf);
    527     if (!EFI_ERROR (Status)) {
    528       UsbFreeInterface (UsbIf);
    529       Device->Interfaces[Index] = NULL;
    530     } else {
    531       ReturnStatus = Status;
    532     }
    533   }
    534 
    535   Device->ActiveConfig    = NULL;
    536   return ReturnStatus;
    537 }
    538 
    539 
    540 /**
    541   Remove the device and all its children from the bus.
    542 
    543   @param  Device                The device to remove.
    544 
    545   @retval EFI_SUCCESS           The device is removed.
    546 
    547 **/
    548 EFI_STATUS
    549 UsbRemoveDevice (
    550   IN USB_DEVICE           *Device
    551   )
    552 {
    553   USB_BUS                 *Bus;
    554   USB_DEVICE              *Child;
    555   EFI_STATUS              Status;
    556   EFI_STATUS              ReturnStatus;
    557   UINTN                   Index;
    558 
    559   Bus = Device->Bus;
    560 
    561   //
    562   // Remove all the devices on its downstream ports. Search from devices[1].
    563   // Devices[0] is the root hub.
    564   //
    565   ReturnStatus = EFI_SUCCESS;
    566   for (Index = 1; Index < Bus->MaxDevices; Index++) {
    567     Child = Bus->Devices[Index];
    568 
    569     if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {
    570       continue;
    571     }
    572 
    573     Status = UsbRemoveDevice (Child);
    574 
    575     if (!EFI_ERROR (Status)) {
    576       Bus->Devices[Index] = NULL;
    577     } else {
    578       Bus->Devices[Index]->DisconnectFail = TRUE;
    579       ReturnStatus = Status;
    580       DEBUG ((EFI_D_INFO, "UsbRemoveDevice: failed to remove child %p at parent %p\n", Child, Device));
    581     }
    582   }
    583 
    584   if (EFI_ERROR (ReturnStatus)) {
    585     return ReturnStatus;
    586   }
    587 
    588   Status = UsbRemoveConfig (Device);
    589 
    590   if (!EFI_ERROR (Status)) {
    591     DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));
    592 
    593     ASSERT (Device->Address < Bus->MaxDevices);
    594     Bus->Devices[Device->Address] = NULL;
    595     UsbFreeDevice (Device);
    596   } else {
    597     Bus->Devices[Device->Address]->DisconnectFail = TRUE;
    598   }
    599   return Status;
    600 }
    601 
    602 
    603 /**
    604   Find the child device on the hub's port.
    605 
    606   @param  HubIf                 The hub interface.
    607   @param  Port                  The port of the hub this child is connected to.
    608 
    609   @return The device on the hub's port, or NULL if there is none.
    610 
    611 **/
    612 USB_DEVICE *
    613 UsbFindChild (
    614   IN USB_INTERFACE        *HubIf,
    615   IN UINT8                Port
    616   )
    617 {
    618   USB_DEVICE              *Device;
    619   USB_BUS                 *Bus;
    620   UINTN                   Index;
    621 
    622   Bus = HubIf->Device->Bus;
    623 
    624   //
    625   // Start checking from device 1, device 0 is the root hub
    626   //
    627   for (Index = 1; Index < Bus->MaxDevices; Index++) {
    628     Device = Bus->Devices[Index];
    629 
    630     if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&
    631         (Device->ParentPort == Port)) {
    632 
    633       return Device;
    634     }
    635   }
    636 
    637   return NULL;
    638 }
    639 
    640 
    641 /**
    642   Enumerate and configure the new device on the port of this HUB interface.
    643 
    644   @param  HubIf                 The HUB that has the device connected.
    645   @param  Port                  The port index of the hub (started with zero).
    646 
    647   @retval EFI_SUCCESS           The device is enumerated (added or removed).
    648   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device.
    649   @retval Others                Failed to enumerate the device.
    650 
    651 **/
    652 EFI_STATUS
    653 UsbEnumerateNewDev (
    654   IN USB_INTERFACE        *HubIf,
    655   IN UINT8                Port
    656   )
    657 {
    658   USB_BUS                 *Bus;
    659   USB_HUB_API             *HubApi;
    660   USB_DEVICE              *Child;
    661   USB_DEVICE              *Parent;
    662   EFI_USB_PORT_STATUS     PortState;
    663   UINTN                   Address;
    664   UINT8                   Config;
    665   EFI_STATUS              Status;
    666 
    667   Parent  = HubIf->Device;
    668   Bus     = Parent->Bus;
    669   HubApi  = HubIf->HubApi;
    670   Address = Bus->MaxDevices;
    671 
    672   gBS->Stall (USB_WAIT_PORT_STABLE_STALL);
    673 
    674   //
    675   // Hub resets the device for at least 10 milliseconds.
    676   // Host learns device speed. If device is of low/full speed
    677   // and the hub is a EHCI root hub, ResetPort will release
    678   // the device to its companion UHCI and return an error.
    679   //
    680   Status = HubApi->ResetPort (HubIf, Port);
    681 
    682   if (EFI_ERROR (Status)) {
    683     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));
    684 
    685     return Status;
    686   }
    687 
    688   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: hub port %d is reset\n", Port));
    689 
    690   Child = UsbCreateDevice (HubIf, Port);
    691 
    692   if (Child == NULL) {
    693     return EFI_OUT_OF_RESOURCES;
    694   }
    695 
    696   //
    697   // OK, now identify the device speed. After reset, hub
    698   // fully knows the actual device speed.
    699   //
    700   Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
    701 
    702   if (EFI_ERROR (Status)) {
    703     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
    704     goto ON_ERROR;
    705   }
    706 
    707   if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
    708     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: No device present at port %d\n", Port));
    709     goto ON_ERROR;
    710   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_SUPER_SPEED)){
    711     Child->Speed      = EFI_USB_SPEED_SUPER;
    712     Child->MaxPacket0 = 512;
    713   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
    714     Child->Speed      = EFI_USB_SPEED_HIGH;
    715     Child->MaxPacket0 = 64;
    716   } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
    717     Child->Speed      = EFI_USB_SPEED_LOW;
    718     Child->MaxPacket0 = 8;
    719   } else {
    720     Child->Speed      = EFI_USB_SPEED_FULL;
    721     Child->MaxPacket0 = 8;
    722   }
    723 
    724   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));
    725 
    726   if (((Child->Speed == EFI_USB_SPEED_LOW) || (Child->Speed == EFI_USB_SPEED_FULL)) &&
    727       (Parent->Speed == EFI_USB_SPEED_HIGH)) {
    728     //
    729     // If the child is a low or full speed device, it is necessary to
    730     // set the transaction translator. Port TT is 1-based.
    731     // This is quite simple:
    732     //  1. if parent is of high speed, then parent is our translator
    733     //  2. otherwise use parent's translator.
    734     //
    735     Child->Translator.TranslatorHubAddress  = Parent->Address;
    736     Child->Translator.TranslatorPortNumber  = (UINT8) (Port + 1);
    737   } else {
    738     Child->Translator = Parent->Translator;
    739   }
    740   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device uses translator (%d, %d)\n",
    741            Child->Translator.TranslatorHubAddress,
    742            Child->Translator.TranslatorPortNumber));
    743 
    744   //
    745   // After port is reset, hub establishes a signal path between
    746   // the device and host (DEFALUT state). Device's registers are
    747   // reset, use default address 0 (host enumerates one device at
    748   // a time) , and ready to respond to control transfer at EP 0.
    749   //
    750 
    751   //
    752   // Host assigns an address to the device. Device completes the
    753   // status stage with default address, then switches to new address.
    754   // ADDRESS state. Address zero is reserved for root hub.
    755   //
    756   ASSERT (Bus->MaxDevices <= 256);
    757   for (Address = 1; Address < Bus->MaxDevices; Address++) {
    758     if (Bus->Devices[Address] == NULL) {
    759       break;
    760     }
    761   }
    762 
    763   if (Address >= Bus->MaxDevices) {
    764     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: address pool is full for port %d\n", Port));
    765 
    766     Status = EFI_ACCESS_DENIED;
    767     goto ON_ERROR;
    768   }
    769 
    770   Status                = UsbSetAddress (Child, (UINT8)Address);
    771   Child->Address        = (UINT8)Address;
    772   Bus->Devices[Address] = Child;
    773 
    774   if (EFI_ERROR (Status)) {
    775     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set device address - %r\n", Status));
    776     goto ON_ERROR;
    777   }
    778 
    779   gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
    780 
    781   DEBUG ((EFI_D_INFO, "UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));
    782 
    783   //
    784   // Host sends a Get_Descriptor request to learn the max packet
    785   // size of default pipe (only part of the device's descriptor).
    786   //
    787   Status = UsbGetMaxPacketSize0 (Child);
    788 
    789   if (EFI_ERROR (Status)) {
    790     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
    791     goto ON_ERROR;
    792   }
    793 
    794   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
    795 
    796   //
    797   // Host learns about the device's abilities by requesting device's
    798   // entire descriptions.
    799   //
    800   Status = UsbBuildDescTable (Child);
    801 
    802   if (EFI_ERROR (Status)) {
    803     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
    804     goto ON_ERROR;
    805   }
    806 
    807   //
    808   // Select a default configuration: UEFI must set the configuration
    809   // before the driver can connect to the device.
    810   //
    811   Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
    812   Status = UsbSetConfig (Child, Config);
    813 
    814   if (EFI_ERROR (Status)) {
    815     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
    816     goto ON_ERROR;
    817   }
    818 
    819   DEBUG (( EFI_D_INFO, "UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
    820 
    821   //
    822   // Host assigns and loads a device driver.
    823   //
    824   Status = UsbSelectConfig (Child, Config);
    825 
    826   if (EFI_ERROR (Status)) {
    827     DEBUG ((EFI_D_ERROR, "UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));
    828     goto ON_ERROR;
    829   }
    830 
    831   //
    832   // Report Status Code to indicate USB device has been detected by hotplug
    833   //
    834   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    835     EFI_PROGRESS_CODE,
    836     (EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG),
    837     Bus->DevicePath
    838     );
    839   return EFI_SUCCESS;
    840 
    841 ON_ERROR:
    842   //
    843   // If reach here, it means the enumeration process on a given port is interrupted due to error.
    844   // The s/w resources, including the assigned address(Address) and the allocated usb device data
    845   // structure(Bus->Devices[Address]), will NOT be freed here. These resources will be freed when
    846   // the device is unplugged from the port or DriverBindingStop() is invoked.
    847   //
    848   // This way is used to co-work with the lower layer EDKII UHCI/EHCI/XHCI host controller driver.
    849   // It's mainly because to keep UEFI spec unchanged EDKII XHCI driver have to maintain a state machine
    850   // to keep track of the mapping between actual address and request address. If the request address
    851   // (Address) is freed here, the Address value will be used by next enumerated device. Then EDKII XHCI
    852   // host controller driver will have wrong information, which will cause further transaction error.
    853   //
    854   // EDKII UHCI/EHCI doesn't get impacted as it's make sense to reserve s/w resource till it gets unplugged.
    855   //
    856   return Status;
    857 }
    858 
    859 
    860 /**
    861   Process the events on the port.
    862 
    863   @param  HubIf                 The HUB that has the device connected.
    864   @param  Port                  The port index of the hub (started with zero).
    865 
    866   @retval EFI_SUCCESS           The device is enumerated (added or removed).
    867   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device.
    868   @retval Others                Failed to enumerate the device.
    869 
    870 **/
    871 EFI_STATUS
    872 UsbEnumeratePort (
    873   IN USB_INTERFACE        *HubIf,
    874   IN UINT8                Port
    875   )
    876 {
    877   USB_HUB_API             *HubApi;
    878   USB_DEVICE              *Child;
    879   EFI_USB_PORT_STATUS     PortState;
    880   EFI_STATUS              Status;
    881 
    882   Child   = NULL;
    883   HubApi  = HubIf->HubApi;
    884 
    885   //
    886   // Host learns of the new device by polling the hub for port changes.
    887   //
    888   Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
    889 
    890   if (EFI_ERROR (Status)) {
    891     DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));
    892     return Status;
    893   }
    894 
    895   //
    896   // Only handle connection/enable/overcurrent/reset change.
    897   // Usb super speed hub may report other changes, such as warm reset change. Ignore them.
    898   //
    899   if ((PortState.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
    900     return EFI_SUCCESS;
    901   }
    902 
    903   DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n",
    904               Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf));
    905 
    906   //
    907   // This driver only process two kinds of events now: over current and
    908   // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
    909   // ENABLE/RESET is used to reset port. SUSPEND isn't supported.
    910   //
    911 
    912   if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {
    913 
    914     if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
    915       //
    916       // Case1:
    917       //   Both OverCurrent and OverCurrentChange set, means over current occurs,
    918       //   which probably is caused by short circuit. It has to wait system hardware
    919       //   to perform recovery.
    920       //
    921       DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port));
    922       return EFI_DEVICE_ERROR;
    923 
    924     }
    925     //
    926     // Case2:
    927     //   Only OverCurrentChange set, means system has been recoveried from
    928     //   over current. As a result, all ports are nearly power-off, so
    929     //   it's necessary to detach and enumerate all ports again.
    930     //
    931     DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port));
    932   }
    933 
    934   if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) {
    935     //
    936     // Case3:
    937     //   1.1 roothub port reg doesn't reflect over-current state, while its counterpart
    938     //   on 2.0 roothub does. When over-current has influence on 1.1 device, the port
    939     //   would be disabled, so it's also necessary to detach and enumerate again.
    940     //
    941     DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port));
    942   }
    943 
    944   if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
    945     //
    946     // Case4:
    947     //   Device connected or disconnected normally.
    948     //
    949     DEBUG ((EFI_D_INFO, "UsbEnumeratePort: Device Connect/Disconnect Normally\n", Port));
    950   }
    951 
    952   //
    953   // Following as the above cases, it's safety to remove and create again.
    954   //
    955   Child = UsbFindChild (HubIf, Port);
    956 
    957   if (Child != NULL) {
    958     DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from root hub %p\n", Port, HubIf));
    959     UsbRemoveDevice (Child);
    960   }
    961 
    962   if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
    963     //
    964     // Now, new device connected, enumerate and configure the device
    965     //
    966     DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
    967     Status = UsbEnumerateNewDev (HubIf, Port);
    968 
    969   } else {
    970     DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port));
    971   }
    972 
    973   HubApi->ClearPortChange (HubIf, Port);
    974   return Status;
    975 }
    976 
    977 
    978 /**
    979   Enumerate all the changed hub ports.
    980 
    981   @param  Event                 The event that is triggered.
    982   @param  Context               The context to the event.
    983 
    984 **/
    985 VOID
    986 EFIAPI
    987 UsbHubEnumeration (
    988   IN EFI_EVENT            Event,
    989   IN VOID                 *Context
    990   )
    991 {
    992   USB_INTERFACE           *HubIf;
    993   UINT8                   Byte;
    994   UINT8                   Bit;
    995   UINT8                   Index;
    996   USB_DEVICE              *Child;
    997 
    998   ASSERT (Context != NULL);
    999 
   1000   HubIf = (USB_INTERFACE *) Context;
   1001 
   1002   for (Index = 0; Index < HubIf->NumOfPort; Index++) {
   1003     Child = UsbFindChild (HubIf, Index);
   1004     if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
   1005       DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf));
   1006       UsbRemoveDevice (Child);
   1007     }
   1008   }
   1009 
   1010   if (HubIf->ChangeMap == NULL) {
   1011     return ;
   1012   }
   1013 
   1014   //
   1015   // HUB starts its port index with 1.
   1016   //
   1017   Byte  = 0;
   1018   Bit   = 1;
   1019 
   1020   for (Index = 0; Index < HubIf->NumOfPort; Index++) {
   1021     if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
   1022       UsbEnumeratePort (HubIf, Index);
   1023     }
   1024 
   1025     USB_NEXT_BIT (Byte, Bit);
   1026   }
   1027 
   1028   UsbHubAckHubStatus (HubIf->Device);
   1029 
   1030   gBS->FreePool (HubIf->ChangeMap);
   1031   HubIf->ChangeMap = NULL;
   1032   return ;
   1033 }
   1034 
   1035 
   1036 /**
   1037   Enumerate all the changed hub ports.
   1038 
   1039   @param  Event                 The event that is triggered.
   1040   @param  Context               The context to the event.
   1041 
   1042 **/
   1043 VOID
   1044 EFIAPI
   1045 UsbRootHubEnumeration (
   1046   IN EFI_EVENT            Event,
   1047   IN VOID                 *Context
   1048   )
   1049 {
   1050   USB_INTERFACE           *RootHub;
   1051   UINT8                   Index;
   1052   USB_DEVICE              *Child;
   1053 
   1054   RootHub = (USB_INTERFACE *) Context;
   1055 
   1056   for (Index = 0; Index < RootHub->NumOfPort; Index++) {
   1057     Child = UsbFindChild (RootHub, Index);
   1058     if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
   1059       DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub));
   1060       UsbRemoveDevice (Child);
   1061     }
   1062 
   1063     UsbEnumeratePort (RootHub, Index);
   1064   }
   1065 }
   1066