Home | History | Annotate | Download | only in UsbBusDxe
      1 /** @file
      2 
      3     Unified interface for RootHub and Hub.
      4 
      5 Copyright (c) 2007 - 2016, 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 // Array that maps the change bit to feature value which is
     20 // used to clear these change bit. USB HUB API will clear
     21 // these change bit automatically. For non-root hub, these
     22 // bits determine whether hub will report the port in changed
     23 // bit maps.
     24 //
     25 USB_CHANGE_FEATURE_MAP  mHubFeatureMap[] = {
     26   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},
     27   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},
     28   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},
     29   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
     30   {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange}
     31 };
     32 
     33 USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[] = {
     34   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},
     35   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},
     36   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},
     37   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
     38   {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange},
     39 };
     40 
     41 //
     42 // USB hub class specific requests. Although USB hub
     43 // is related to an interface, these requests are sent
     44 // to the control endpoint of the device.
     45 //
     46 /**
     47   USB hub control transfer to set the hub depth.
     48 
     49   @param  HubDev                The device of the hub.
     50   @param  Depth                 The depth to set.
     51 
     52   @retval EFI_SUCCESS           Depth of the hub is set.
     53   @retval Others                Failed to set the depth.
     54 
     55 **/
     56 EFI_STATUS
     57 UsbHubCtrlSetHubDepth (
     58   IN  USB_DEVICE          *HubDev,
     59   IN  UINT16              Depth
     60   )
     61 {
     62   EFI_STATUS              Status;
     63 
     64   Status = UsbCtrlRequest (
     65              HubDev,
     66              EfiUsbNoData,
     67              USB_REQ_TYPE_CLASS,
     68              USB_HUB_TARGET_HUB,
     69              USB_HUB_REQ_SET_DEPTH,
     70              Depth,
     71              0,
     72              NULL,
     73              0
     74              );
     75 
     76   return Status;
     77 }
     78 
     79 /**
     80   USB hub control transfer to clear the hub feature.
     81 
     82   @param  HubDev                The device of the hub.
     83   @param  Feature               The feature to clear.
     84 
     85   @retval EFI_SUCCESS           Feature of the hub is cleared.
     86   @retval Others                Failed to clear the feature.
     87 
     88 **/
     89 EFI_STATUS
     90 UsbHubCtrlClearHubFeature (
     91   IN USB_DEVICE           *HubDev,
     92   IN UINT16               Feature
     93   )
     94 {
     95   EFI_STATUS              Status;
     96 
     97   Status = UsbCtrlRequest (
     98              HubDev,
     99              EfiUsbNoData,
    100              USB_REQ_TYPE_CLASS,
    101              USB_HUB_TARGET_HUB,
    102              USB_HUB_REQ_CLEAR_FEATURE,
    103              Feature,
    104              0,
    105              NULL,
    106              0
    107              );
    108 
    109   return Status;
    110 }
    111 
    112 
    113 /**
    114   Clear the feature of the device's port.
    115 
    116   @param  HubDev                The hub device.
    117   @param  Port                  The port to clear feature.
    118   @param  Feature               The feature to clear.
    119 
    120   @retval EFI_SUCCESS           The feature of the port is cleared.
    121   @retval Others                Failed to clear the feature.
    122 
    123 **/
    124 EFI_STATUS
    125 UsbHubCtrlClearPortFeature (
    126   IN USB_DEVICE           *HubDev,
    127   IN UINT8                Port,
    128   IN UINT16               Feature
    129   )
    130 {
    131   EFI_STATUS              Status;
    132 
    133   //
    134   // In USB bus, all the port index starts from 0. But HUB
    135   // indexes its port from 1. So, port number is added one.
    136   //
    137   Status = UsbCtrlRequest (
    138              HubDev,
    139              EfiUsbNoData,
    140              USB_REQ_TYPE_CLASS,
    141              USB_HUB_TARGET_PORT,
    142              USB_HUB_REQ_CLEAR_FEATURE,
    143              Feature,
    144              (UINT16) (Port + 1),
    145              NULL,
    146              0
    147              );
    148 
    149   return Status;
    150 }
    151 
    152 
    153 /**
    154   Clear the transaction translate buffer if full/low
    155   speed control/bulk transfer failed and the transfer
    156   uses this hub as translator.Remember to clear the TT
    157   buffer of transaction translator, not that of the
    158   parent.
    159 
    160   @param  HubDev                The hub device.
    161   @param  Port                  The port of the hub.
    162   @param  DevAddr               Address of the failed transaction.
    163   @param  EpNum                 The endpoint number of the failed transaction.
    164   @param  EpType                The type of failed transaction.
    165 
    166   @retval EFI_SUCCESS           The TT buffer is cleared.
    167   @retval Others                Failed to clear the TT buffer.
    168 
    169 **/
    170 EFI_STATUS
    171 UsbHubCtrlClearTTBuffer (
    172   IN USB_DEVICE           *HubDev,
    173   IN UINT8                Port,
    174   IN UINT16               DevAddr,
    175   IN UINT16               EpNum,
    176   IN UINT16               EpType
    177   )
    178 {
    179   EFI_STATUS              Status;
    180   UINT16                  Value;
    181 
    182   //
    183   // Check USB2.0 spec page 424 for wValue's encoding
    184   //
    185   Value = (UINT16) ((EpNum & 0x0F) | (DevAddr << 4) |
    186           ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));
    187 
    188   Status = UsbCtrlRequest (
    189              HubDev,
    190              EfiUsbNoData,
    191              USB_REQ_TYPE_CLASS,
    192              USB_HUB_TARGET_PORT,
    193              USB_HUB_REQ_CLEAR_TT,
    194              Value,
    195              (UINT16) (Port + 1),
    196              NULL,
    197              0
    198              );
    199 
    200   return Status;
    201 }
    202 
    203 /**
    204   Usb hub control transfer to get the super speed hub descriptor.
    205 
    206   @param  HubDev                The hub device.
    207   @param  Buf                   The buffer to hold the descriptor.
    208 
    209   @retval EFI_SUCCESS           The hub descriptor is retrieved.
    210   @retval Others                Failed to retrieve the hub descriptor.
    211 
    212 **/
    213 EFI_STATUS
    214 UsbHubCtrlGetSuperSpeedHubDesc (
    215   IN  USB_DEVICE          *HubDev,
    216   OUT VOID                *Buf
    217   )
    218 {
    219   EFI_STATUS              Status;
    220 
    221   Status = EFI_INVALID_PARAMETER;
    222 
    223   Status = UsbCtrlRequest (
    224              HubDev,
    225              EfiUsbDataIn,
    226              USB_REQ_TYPE_CLASS,
    227              USB_HUB_TARGET_HUB,
    228              USB_HUB_REQ_GET_DESC,
    229              (UINT16) (USB_DESC_TYPE_HUB_SUPER_SPEED << 8),
    230              0,
    231              Buf,
    232              32
    233              );
    234 
    235   return Status;
    236 }
    237 
    238 /**
    239   Usb hub control transfer to get the hub descriptor.
    240 
    241   @param  HubDev                The hub device.
    242   @param  Buf                   The buffer to hold the descriptor.
    243   @param  Len                   The length to retrieve.
    244 
    245   @retval EFI_SUCCESS           The hub descriptor is retrieved.
    246   @retval Others                Failed to retrieve the hub descriptor.
    247 
    248 **/
    249 EFI_STATUS
    250 UsbHubCtrlGetHubDesc (
    251   IN  USB_DEVICE          *HubDev,
    252   OUT VOID                *Buf,
    253   IN  UINTN               Len
    254   )
    255 {
    256   EFI_STATUS              Status;
    257 
    258   Status = UsbCtrlRequest (
    259              HubDev,
    260              EfiUsbDataIn,
    261              USB_REQ_TYPE_CLASS,
    262              USB_HUB_TARGET_HUB,
    263              USB_HUB_REQ_GET_DESC,
    264              (UINT16) (USB_DESC_TYPE_HUB << 8),
    265              0,
    266              Buf,
    267              Len
    268              );
    269 
    270   return Status;
    271 }
    272 
    273 
    274 /**
    275   Usb hub control transfer to get the hub status.
    276 
    277   @param  HubDev                The hub device.
    278   @param  State                 The variable to return the status.
    279 
    280   @retval EFI_SUCCESS           The hub status is returned in State.
    281   @retval Others                Failed to get the hub status.
    282 
    283 **/
    284 EFI_STATUS
    285 UsbHubCtrlGetHubStatus (
    286   IN  USB_DEVICE          *HubDev,
    287   OUT UINT32              *State
    288   )
    289 {
    290   EFI_STATUS              Status;
    291 
    292   Status = UsbCtrlRequest (
    293              HubDev,
    294              EfiUsbDataIn,
    295              USB_REQ_TYPE_CLASS,
    296              USB_HUB_TARGET_HUB,
    297              USB_HUB_REQ_GET_STATUS,
    298              0,
    299              0,
    300              State,
    301              4
    302              );
    303 
    304   return Status;
    305 }
    306 
    307 
    308 /**
    309   Usb hub control transfer to get the port status.
    310 
    311   @param  HubDev                The hub device.
    312   @param  Port                  The port of the hub.
    313   @param  State                 Variable to return the hub port state.
    314 
    315   @retval EFI_SUCCESS           The port state is returned in State.
    316   @retval Others                Failed to retrieve the port state.
    317 
    318 **/
    319 EFI_STATUS
    320 UsbHubCtrlGetPortStatus (
    321   IN  USB_DEVICE          *HubDev,
    322   IN  UINT8               Port,
    323   OUT VOID                *State
    324   )
    325 {
    326   EFI_STATUS              Status;
    327 
    328   //
    329   // In USB bus, all the port index starts from 0. But HUB
    330   // indexes its port from 1. So, port number is added one.
    331   // No need to convert the hub bit to UEFI definition, they
    332   // are the same
    333   //
    334   Status = UsbCtrlRequest (
    335              HubDev,
    336              EfiUsbDataIn,
    337              USB_REQ_TYPE_CLASS,
    338              USB_HUB_TARGET_PORT,
    339              USB_HUB_REQ_GET_STATUS,
    340              0,
    341              (UINT16) (Port + 1),
    342              State,
    343              4
    344              );
    345 
    346   return Status;
    347 }
    348 
    349 
    350 /**
    351   Usb hub control transfer to reset the TT (Transaction Transaltor).
    352 
    353   @param  HubDev                The hub device.
    354   @param  Port                  The port of the hub.
    355 
    356   @retval EFI_SUCCESS           The TT of the hub is reset.
    357   @retval Others                Failed to reset the port.
    358 
    359 **/
    360 EFI_STATUS
    361 UsbHubCtrlResetTT (
    362   IN  USB_DEVICE          *HubDev,
    363   IN  UINT8               Port
    364   )
    365 {
    366   EFI_STATUS              Status;
    367 
    368   Status = UsbCtrlRequest (
    369              HubDev,
    370              EfiUsbNoData,
    371              USB_REQ_TYPE_CLASS,
    372              USB_HUB_TARGET_HUB,
    373              USB_HUB_REQ_RESET_TT,
    374              0,
    375              (UINT16) (Port + 1),
    376              NULL,
    377              0
    378              );
    379 
    380   return Status;
    381 }
    382 
    383 
    384 /**
    385   Usb hub control transfer to set the hub feature.
    386 
    387   @param  HubDev                The hub device.
    388   @param  Feature               The feature to set.
    389 
    390   @retval EFI_SUCESS            The feature is set for the hub.
    391   @retval Others                Failed to set the feature.
    392 
    393 **/
    394 EFI_STATUS
    395 UsbHubCtrlSetHubFeature (
    396   IN  USB_DEVICE          *HubDev,
    397   IN  UINT8               Feature
    398   )
    399 {
    400   EFI_STATUS              Status;
    401 
    402   Status = UsbCtrlRequest (
    403              HubDev,
    404              EfiUsbNoData,
    405              USB_REQ_TYPE_CLASS,
    406              USB_HUB_TARGET_HUB,
    407              USB_HUB_REQ_SET_FEATURE,
    408              Feature,
    409              0,
    410              NULL,
    411              0
    412              );
    413 
    414   return Status;
    415 }
    416 
    417 
    418 /**
    419   Usb hub control transfer to set the port feature.
    420 
    421   @param  HubDev                The Usb hub device.
    422   @param  Port                  The Usb port to set feature for.
    423   @param  Feature               The feature to set.
    424 
    425   @retval EFI_SUCCESS           The feature is set for the port.
    426   @retval Others                Failed to set the feature.
    427 
    428 **/
    429 EFI_STATUS
    430 UsbHubCtrlSetPortFeature (
    431   IN USB_DEVICE           *HubDev,
    432   IN UINT8                Port,
    433   IN UINT8                Feature
    434   )
    435 {
    436   EFI_STATUS              Status;
    437 
    438   //
    439   // In USB bus, all the port index starts from 0. But HUB
    440   // indexes its port from 1. So, port number is added one.
    441   //
    442   Status = UsbCtrlRequest (
    443              HubDev,
    444              EfiUsbNoData,
    445              USB_REQ_TYPE_CLASS,
    446              USB_HUB_TARGET_PORT,
    447              USB_HUB_REQ_SET_FEATURE,
    448              Feature,
    449              (UINT16) (Port + 1),
    450              NULL,
    451              0
    452              );
    453 
    454   return Status;
    455 }
    456 
    457 
    458 /**
    459   Read the whole usb hub descriptor. It is necessary
    460   to do it in two steps because hub descriptor is of
    461   variable length.
    462 
    463   @param  HubDev                The hub device.
    464   @param  HubDesc               The variable to return the descriptor.
    465 
    466   @retval EFI_SUCCESS           The hub descriptor is read.
    467   @retval Others                Failed to read the hub descriptor.
    468 
    469 **/
    470 EFI_STATUS
    471 UsbHubReadDesc (
    472   IN  USB_DEVICE              *HubDev,
    473   OUT EFI_USB_HUB_DESCRIPTOR  *HubDesc
    474   )
    475 {
    476   EFI_STATUS              Status;
    477 
    478   if (HubDev->Speed == EFI_USB_SPEED_SUPER) {
    479     //
    480     // Get the super speed hub descriptor
    481     //
    482     Status = UsbHubCtrlGetSuperSpeedHubDesc (HubDev, HubDesc);
    483   } else {
    484 
    485     //
    486     // First get the hub descriptor length
    487     //
    488     Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
    489 
    490     if (EFI_ERROR (Status)) {
    491       return Status;
    492     }
    493 
    494     //
    495     // Get the whole hub descriptor
    496     //
    497     Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
    498   }
    499 
    500   return Status;
    501 }
    502 
    503 
    504 
    505 /**
    506   Ack the hub change bits. If these bits are not ACKed, Hub will
    507   always return changed bit map from its interrupt endpoint.
    508 
    509   @param  HubDev                The hub device.
    510 
    511   @retval EFI_SUCCESS           The hub change status is ACKed.
    512   @retval Others                Failed to ACK the hub status.
    513 
    514 **/
    515 EFI_STATUS
    516 UsbHubAckHubStatus (
    517   IN  USB_DEVICE         *HubDev
    518   )
    519 {
    520   EFI_USB_PORT_STATUS     HubState;
    521   EFI_STATUS              Status;
    522 
    523   Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);
    524 
    525   if (EFI_ERROR (Status)) {
    526     return Status;
    527   }
    528 
    529   if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
    530     UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
    531   }
    532 
    533   if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
    534     UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
    535   }
    536 
    537   return EFI_SUCCESS;
    538 }
    539 
    540 
    541 /**
    542   Test whether the interface is a hub interface.
    543 
    544   @param  UsbIf                 The interface to test.
    545 
    546   @retval TRUE                  The interface is a hub interface.
    547   @retval FALSE                 The interface isn't a hub interface.
    548 
    549 **/
    550 BOOLEAN
    551 UsbIsHubInterface (
    552   IN USB_INTERFACE        *UsbIf
    553   )
    554 {
    555   EFI_USB_INTERFACE_DESCRIPTOR  *Setting;
    556 
    557   //
    558   // If the hub is a high-speed hub with multiple TT,
    559   // the hub will has a default setting of single TT.
    560   //
    561   Setting = &UsbIf->IfSetting->Desc;
    562 
    563   if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
    564       (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
    565 
    566     return TRUE;
    567   }
    568 
    569   return FALSE;
    570 }
    571 
    572 
    573 /**
    574   The callback function to the USB hub status change
    575   interrupt endpoint. It is called periodically by
    576   the underlying host controller.
    577 
    578   @param  Data                  The data read.
    579   @param  DataLength            The length of the data read.
    580   @param  Context               The context.
    581   @param  Result                The result of the last interrupt transfer.
    582 
    583   @retval EFI_SUCCESS           The process is OK.
    584   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource.
    585 
    586 **/
    587 EFI_STATUS
    588 EFIAPI
    589 UsbOnHubInterrupt (
    590   IN  VOID                *Data,
    591   IN  UINTN               DataLength,
    592   IN  VOID                *Context,
    593   IN  UINT32              Result
    594   )
    595 {
    596   USB_INTERFACE               *HubIf;
    597   EFI_USB_IO_PROTOCOL         *UsbIo;
    598   EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
    599   EFI_STATUS                  Status;
    600 
    601   HubIf   = (USB_INTERFACE *) Context;
    602   UsbIo   = &(HubIf->UsbIo);
    603   EpDesc  = &(HubIf->HubEp->Desc);
    604 
    605   if (Result != EFI_USB_NOERROR) {
    606     //
    607     // If endpoint is stalled, clear the stall. Use UsbIo to access
    608     // the control transfer so internal status are maintained.
    609     //
    610     if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
    611       UsbIoClearFeature (
    612         UsbIo,
    613         USB_TARGET_ENDPOINT,
    614         USB_FEATURE_ENDPOINT_HALT,
    615         EpDesc->EndpointAddress
    616         );
    617     }
    618 
    619     //
    620     // Delete and submit a new async interrupt
    621     //
    622     Status = UsbIo->UsbAsyncInterruptTransfer (
    623                       UsbIo,
    624                       EpDesc->EndpointAddress,
    625                       FALSE,
    626                       0,
    627                       0,
    628                       NULL,
    629                       NULL
    630                       );
    631 
    632     if (EFI_ERROR (Status)) {
    633       DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
    634       return Status;
    635     }
    636 
    637     Status = UsbIo->UsbAsyncInterruptTransfer (
    638                       UsbIo,
    639                       EpDesc->EndpointAddress,
    640                       TRUE,
    641                       USB_HUB_POLL_INTERVAL,
    642                       HubIf->NumOfPort / 8 + 1,
    643                       UsbOnHubInterrupt,
    644                       HubIf
    645                       );
    646 
    647     if (EFI_ERROR (Status)) {
    648       DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
    649     }
    650 
    651     return Status;
    652   }
    653 
    654   if ((DataLength == 0) || (Data == NULL)) {
    655     return EFI_SUCCESS;
    656   }
    657 
    658   //
    659   // OK, actually something is changed, save the change map
    660   // then signal the HUB to do enumeration. This is a good
    661   // practise since UsbOnHubInterrupt is called in the context
    662   // of host contrller's AsyncInterrupt monitor.
    663   //
    664   HubIf->ChangeMap = AllocateZeroPool (DataLength);
    665 
    666   if (HubIf->ChangeMap == NULL) {
    667     return EFI_OUT_OF_RESOURCES;
    668   }
    669 
    670   CopyMem (HubIf->ChangeMap, Data, DataLength);
    671   gBS->SignalEvent (HubIf->HubNotify);
    672 
    673   return EFI_SUCCESS;
    674 }
    675 
    676 
    677 
    678 
    679 /**
    680   Initialize the device for a non-root hub.
    681 
    682   @param  HubIf                 The USB hub interface.
    683 
    684   @retval EFI_SUCCESS           The hub is initialized.
    685   @retval EFI_DEVICE_ERROR      Failed to initialize the hub.
    686 
    687 **/
    688 EFI_STATUS
    689 UsbHubInit (
    690   IN USB_INTERFACE        *HubIf
    691   )
    692 {
    693   EFI_USB_HUB_DESCRIPTOR  HubDesc;
    694   USB_ENDPOINT_DESC       *EpDesc;
    695   USB_INTERFACE_SETTING   *Setting;
    696   EFI_USB_IO_PROTOCOL     *UsbIo;
    697   USB_DEVICE              *HubDev;
    698   EFI_STATUS              Status;
    699   UINT8                   Index;
    700   UINT8                   NumEndpoints;
    701   UINT16                  Depth;
    702 
    703   //
    704   // Locate the interrupt endpoint for port change map
    705   //
    706   HubIf->IsHub  = FALSE;
    707   Setting       = HubIf->IfSetting;
    708   HubDev        = HubIf->Device;
    709   EpDesc        = NULL;
    710   NumEndpoints  = Setting->Desc.NumEndpoints;
    711 
    712   for (Index = 0; Index < NumEndpoints; Index++) {
    713     ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
    714 
    715     EpDesc = Setting->Endpoints[Index];
    716 
    717     if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
    718        (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {
    719       break;
    720     }
    721   }
    722 
    723   if (Index == NumEndpoints) {
    724     DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
    725     return EFI_DEVICE_ERROR;
    726   }
    727 
    728   Status = UsbHubReadDesc (HubDev, &HubDesc);
    729 
    730   if (EFI_ERROR (Status)) {
    731     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));
    732     return Status;
    733   }
    734 
    735   HubIf->NumOfPort = HubDesc.NumPorts;
    736 
    737   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));
    738 
    739   //
    740   // OK, set IsHub to TRUE. Now usb bus can handle this device
    741   // as a working HUB. If failed eariler, bus driver will not
    742   // recognize it as a hub. Other parts of the bus should be able
    743   // to work.
    744   //
    745   HubIf->IsHub  = TRUE;
    746   HubIf->HubApi = &mUsbHubApi;
    747   HubIf->HubEp  = EpDesc;
    748 
    749   if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
    750     Depth = (UINT16)(HubIf->Device->Tier - 1);
    751     DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));
    752     UsbHubCtrlSetHubDepth (HubIf->Device, Depth);
    753 
    754     for (Index = 0; Index < HubDesc.NumPorts; Index++) {
    755       UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);
    756     }
    757   } else {
    758     //
    759     // Feed power to all the hub ports. It should be ok
    760     // for both gang/individual powered hubs.
    761     //
    762     for (Index = 0; Index < HubDesc.NumPorts; Index++) {
    763       UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);
    764     }
    765 
    766     //
    767     // Update for the usb hub has no power on delay requirement
    768     //
    769     if (HubDesc.PwrOn2PwrGood > 0) {
    770       gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
    771     }
    772     UsbHubAckHubStatus (HubIf->Device);
    773   }
    774 
    775   //
    776   // Create an event to enumerate the hub's port. On
    777   //
    778   Status = gBS->CreateEvent (
    779                   EVT_NOTIFY_SIGNAL,
    780                   TPL_CALLBACK,
    781                   UsbHubEnumeration,
    782                   HubIf,
    783                   &HubIf->HubNotify
    784                   );
    785 
    786   if (EFI_ERROR (Status)) {
    787     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",
    788                 HubDev->Address, Status));
    789 
    790     return Status;
    791   }
    792 
    793   //
    794   // Create AsyncInterrupt to query hub port change endpoint
    795   // periodically. If the hub ports are changed, hub will return
    796   // changed port map from the interrupt endpoint. The port map
    797   // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
    798   // host change status).
    799   //
    800   UsbIo  = &HubIf->UsbIo;
    801   Status = UsbIo->UsbAsyncInterruptTransfer (
    802                     UsbIo,
    803                     EpDesc->Desc.EndpointAddress,
    804                     TRUE,
    805                     USB_HUB_POLL_INTERVAL,
    806                     HubIf->NumOfPort / 8 + 1,
    807                     UsbOnHubInterrupt,
    808                     HubIf
    809                     );
    810 
    811   if (EFI_ERROR (Status)) {
    812     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
    813                 HubDev->Address, Status));
    814 
    815     gBS->CloseEvent (HubIf->HubNotify);
    816     HubIf->HubNotify = NULL;
    817 
    818     return Status;
    819   }
    820 
    821   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));
    822   return Status;
    823 }
    824 
    825 
    826 
    827 /**
    828   Get the port status. This function is required to
    829   ACK the port change bits although it will return
    830   the port changes in PortState. Bus enumeration code
    831   doesn't need to ACK the port change bits.
    832 
    833   @param  HubIf                 The hub interface.
    834   @param  Port                  The port of the hub to get state.
    835   @param  PortState             Variable to return the port state.
    836 
    837   @retval EFI_SUCCESS           The port status is successfully returned.
    838   @retval Others                Failed to return the status.
    839 
    840 **/
    841 EFI_STATUS
    842 UsbHubGetPortStatus (
    843   IN  USB_INTERFACE       *HubIf,
    844   IN  UINT8               Port,
    845   OUT EFI_USB_PORT_STATUS *PortState
    846   )
    847 {
    848   EFI_STATUS              Status;
    849 
    850   Status  = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
    851 
    852   return Status;
    853 }
    854 
    855 
    856 
    857 /**
    858   Clear the port change status.
    859 
    860   @param  HubIf                 The hub interface.
    861   @param  Port                  The hub port.
    862 
    863 **/
    864 VOID
    865 UsbHubClearPortChange (
    866   IN USB_INTERFACE        *HubIf,
    867   IN UINT8                Port
    868   )
    869 {
    870   EFI_USB_PORT_STATUS     PortState;
    871   USB_CHANGE_FEATURE_MAP  *Map;
    872   UINTN                   Index;
    873   EFI_STATUS              Status;
    874 
    875   Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
    876 
    877   if (EFI_ERROR (Status)) {
    878     return;
    879   }
    880 
    881   //
    882   // OK, get the usb port status, now ACK the change bits.
    883   // Don't return error when failed to clear the change bits.
    884   // It may lead to extra port state report. USB bus should
    885   // be able to handle this.
    886   //
    887   for (Index = 0; Index < ARRAY_SIZE (mHubFeatureMap); Index++) {
    888     Map = &mHubFeatureMap[Index];
    889 
    890     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
    891       UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16) Map->Feature);
    892     }
    893   }
    894 }
    895 
    896 
    897 
    898 /**
    899   Function to set the port feature for non-root hub.
    900 
    901   @param  HubIf                 The hub interface.
    902   @param  Port                  The port of the hub.
    903   @param  Feature               The feature of the port to set.
    904 
    905   @retval EFI_SUCCESS           The hub port feature is set.
    906   @retval Others                Failed to set the port feature.
    907 
    908 **/
    909 EFI_STATUS
    910 UsbHubSetPortFeature (
    911   IN USB_INTERFACE        *HubIf,
    912   IN UINT8                Port,
    913   IN EFI_USB_PORT_FEATURE Feature
    914   )
    915 {
    916   EFI_STATUS              Status;
    917 
    918   Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);
    919 
    920   return Status;
    921 }
    922 
    923 
    924 /**
    925   Interface function to clear the port feature for non-root hub.
    926 
    927   @param  HubIf                 The hub interface.
    928   @param  Port                  The port of the hub to clear feature for.
    929   @param  Feature               The feature to clear.
    930 
    931   @retval EFI_SUCCESS           The port feature is cleared.
    932   @retval Others                Failed to clear the port feature.
    933 
    934 **/
    935 EFI_STATUS
    936 UsbHubClearPortFeature (
    937   IN USB_INTERFACE        *HubIf,
    938   IN UINT8                Port,
    939   IN EFI_USB_PORT_FEATURE Feature
    940   )
    941 {
    942   EFI_STATUS              Status;
    943 
    944   Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);
    945 
    946   return Status;
    947 }
    948 
    949 
    950 /**
    951   Interface function to reset the port.
    952 
    953   @param  HubIf                 The hub interface.
    954   @param  Port                  The port to reset.
    955 
    956   @retval EFI_SUCCESS           The hub port is reset.
    957   @retval EFI_TIMEOUT           Failed to reset the port in time.
    958   @retval Others                Failed to reset the port.
    959 
    960 **/
    961 EFI_STATUS
    962 UsbHubResetPort (
    963   IN USB_INTERFACE        *HubIf,
    964   IN UINT8                Port
    965   )
    966 {
    967   EFI_USB_PORT_STATUS     PortState;
    968   UINTN                   Index;
    969   EFI_STATUS              Status;
    970 
    971   Status  = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);
    972 
    973   if (EFI_ERROR (Status)) {
    974     return Status;
    975   }
    976 
    977   //
    978   // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
    979   // section 7.1.7.5 for timing requirements.
    980   //
    981   gBS->Stall (USB_SET_PORT_RESET_STALL);
    982 
    983   //
    984   // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
    985   //
    986   ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
    987 
    988   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
    989     Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
    990 
    991     if (EFI_ERROR (Status)) {
    992       return Status;
    993     }
    994 
    995     if (!EFI_ERROR (Status) &&
    996         USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
    997       gBS->Stall (USB_SET_PORT_RECOVERY_STALL);
    998       return EFI_SUCCESS;
    999     }
   1000 
   1001     gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
   1002   }
   1003 
   1004   return EFI_TIMEOUT;
   1005 }
   1006 
   1007 
   1008 /**
   1009   Release the hub's control of the interface.
   1010 
   1011   @param  HubIf                 The hub interface.
   1012 
   1013   @retval EFI_SUCCESS           The interface is release of hub control.
   1014 
   1015 **/
   1016 EFI_STATUS
   1017 UsbHubRelease (
   1018   IN USB_INTERFACE        *HubIf
   1019   )
   1020 {
   1021   EFI_USB_IO_PROTOCOL     *UsbIo;
   1022   EFI_STATUS              Status;
   1023 
   1024   UsbIo  = &HubIf->UsbIo;
   1025   Status = UsbIo->UsbAsyncInterruptTransfer (
   1026                     UsbIo,
   1027                     HubIf->HubEp->Desc.EndpointAddress,
   1028                     FALSE,
   1029                     USB_HUB_POLL_INTERVAL,
   1030                     0,
   1031                     NULL,
   1032                     0
   1033                     );
   1034 
   1035   if (EFI_ERROR (Status)) {
   1036     return Status;
   1037   }
   1038 
   1039   gBS->CloseEvent (HubIf->HubNotify);
   1040 
   1041   HubIf->IsHub      = FALSE;
   1042   HubIf->HubApi     = NULL;
   1043   HubIf->HubEp      = NULL;
   1044   HubIf->HubNotify  = NULL;
   1045 
   1046   DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
   1047   return EFI_SUCCESS;
   1048 }
   1049 
   1050 
   1051 
   1052 /**
   1053   Initialize the interface for root hub.
   1054 
   1055   @param  HubIf                 The root hub interface.
   1056 
   1057   @retval EFI_SUCCESS           The interface is initialized for root hub.
   1058   @retval Others                Failed to initialize the hub.
   1059 
   1060 **/
   1061 EFI_STATUS
   1062 UsbRootHubInit (
   1063   IN USB_INTERFACE        *HubIf
   1064   )
   1065 {
   1066   EFI_STATUS              Status;
   1067   UINT8                   MaxSpeed;
   1068   UINT8                   NumOfPort;
   1069   UINT8                   Support64;
   1070 
   1071   Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
   1072 
   1073   if (EFI_ERROR (Status)) {
   1074     return Status;
   1075   }
   1076 
   1077   DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",
   1078               HubIf, MaxSpeed, NumOfPort));
   1079 
   1080   HubIf->IsHub      = TRUE;
   1081   HubIf->HubApi     = &mUsbRootHubApi;
   1082   HubIf->HubEp      = NULL;
   1083   HubIf->MaxSpeed   = MaxSpeed;
   1084   HubIf->NumOfPort  = NumOfPort;
   1085   HubIf->HubNotify  = NULL;
   1086 
   1087   //
   1088   // Create a timer to poll root hub ports periodically
   1089   //
   1090   Status = gBS->CreateEvent (
   1091                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
   1092                   TPL_CALLBACK,
   1093                   UsbRootHubEnumeration,
   1094                   HubIf,
   1095                   &HubIf->HubNotify
   1096                   );
   1097 
   1098   if (EFI_ERROR (Status)) {
   1099     return Status;
   1100   }
   1101 
   1102   //
   1103   // It should signal the event immediately here, or device detection
   1104   // by bus enumeration might be delayed by the timer interval.
   1105   //
   1106   gBS->SignalEvent (HubIf->HubNotify);
   1107 
   1108   Status = gBS->SetTimer (
   1109                   HubIf->HubNotify,
   1110                   TimerPeriodic,
   1111                   USB_ROOTHUB_POLL_INTERVAL
   1112                   );
   1113 
   1114   if (EFI_ERROR (Status)) {
   1115     gBS->CloseEvent (HubIf->HubNotify);
   1116   }
   1117 
   1118   return Status;
   1119 }
   1120 
   1121 
   1122 /**
   1123   Get the port status. This function is required to
   1124   ACK the port change bits although it will return
   1125   the port changes in PortState. Bus enumeration code
   1126   doesn't need to ACK the port change bits.
   1127 
   1128   @param  HubIf                 The root hub interface.
   1129   @param  Port                  The root hub port to get the state.
   1130   @param  PortState             Variable to return the port state.
   1131 
   1132   @retval EFI_SUCCESS           The port state is returned.
   1133   @retval Others                Failed to retrieve the port state.
   1134 
   1135 **/
   1136 EFI_STATUS
   1137 UsbRootHubGetPortStatus (
   1138   IN  USB_INTERFACE       *HubIf,
   1139   IN  UINT8               Port,
   1140   OUT EFI_USB_PORT_STATUS *PortState
   1141   )
   1142 {
   1143   USB_BUS                 *Bus;
   1144   EFI_STATUS              Status;
   1145 
   1146   Bus     = HubIf->Device->Bus;
   1147   Status  = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
   1148 
   1149   return Status;
   1150 }
   1151 
   1152 
   1153 /**
   1154   Clear the port change status.
   1155 
   1156   @param  HubIf                 The root hub interface.
   1157   @param  Port                  The root hub port.
   1158 
   1159 **/
   1160 VOID
   1161 UsbRootHubClearPortChange (
   1162   IN USB_INTERFACE        *HubIf,
   1163   IN UINT8                Port
   1164   )
   1165 {
   1166   EFI_USB_PORT_STATUS     PortState;
   1167   USB_CHANGE_FEATURE_MAP  *Map;
   1168   UINTN                   Index;
   1169   EFI_STATUS              Status;
   1170 
   1171   Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
   1172 
   1173   if (EFI_ERROR (Status)) {
   1174     return;
   1175   }
   1176 
   1177   //
   1178   // OK, get the usb port status, now ACK the change bits.
   1179   // Don't return error when failed to clear the change bits.
   1180   // It may lead to extra port state report. USB bus should
   1181   // be able to handle this.
   1182   //
   1183   for (Index = 0; Index < ARRAY_SIZE (mRootHubFeatureMap); Index++) {
   1184     Map = &mRootHubFeatureMap[Index];
   1185 
   1186     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
   1187       UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);
   1188     }
   1189   }
   1190 }
   1191 
   1192 
   1193 /**
   1194   Set the root hub port feature.
   1195 
   1196   @param  HubIf                 The Usb hub interface.
   1197   @param  Port                  The hub port.
   1198   @param  Feature               The feature to set.
   1199 
   1200   @retval EFI_SUCCESS           The root hub port is set with the feature.
   1201   @retval Others                Failed to set the feature.
   1202 
   1203 **/
   1204 EFI_STATUS
   1205 UsbRootHubSetPortFeature (
   1206   IN USB_INTERFACE        *HubIf,
   1207   IN UINT8                Port,
   1208   IN EFI_USB_PORT_FEATURE Feature
   1209   )
   1210 {
   1211   EFI_STATUS              Status;
   1212 
   1213   Status  = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
   1214 
   1215   return Status;
   1216 }
   1217 
   1218 
   1219 /**
   1220   Clear the root hub port feature.
   1221 
   1222   @param  HubIf                 The root hub interface.
   1223   @param  Port                  The root hub port.
   1224   @param  Feature               The feature to clear.
   1225 
   1226   @retval EFI_SUCCESS           The root hub port is cleared of the feature.
   1227   @retval Others                Failed to clear the feature.
   1228 
   1229 **/
   1230 EFI_STATUS
   1231 UsbRootHubClearPortFeature (
   1232   IN USB_INTERFACE        *HubIf,
   1233   IN UINT8                Port,
   1234   IN EFI_USB_PORT_FEATURE Feature
   1235   )
   1236 {
   1237   EFI_STATUS              Status;
   1238 
   1239   Status  = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
   1240 
   1241   return Status;
   1242 }
   1243 
   1244 
   1245 /**
   1246   Interface function to reset the root hub port.
   1247 
   1248   @param  RootIf                The root hub interface.
   1249   @param  Port                  The port to reset.
   1250 
   1251   @retval EFI_SUCCESS           The hub port is reset.
   1252   @retval EFI_TIMEOUT           Failed to reset the port in time.
   1253   @retval EFI_NOT_FOUND         The low/full speed device connected to high  speed.
   1254                                 root hub is released to the companion UHCI.
   1255   @retval Others                Failed to reset the port.
   1256 
   1257 **/
   1258 EFI_STATUS
   1259 UsbRootHubResetPort (
   1260   IN USB_INTERFACE        *RootIf,
   1261   IN UINT8                Port
   1262   )
   1263 {
   1264   USB_BUS                 *Bus;
   1265   EFI_STATUS              Status;
   1266   EFI_USB_PORT_STATUS     PortState;
   1267   UINTN                   Index;
   1268 
   1269   //
   1270   // Notice: although EHCI requires that ENABLED bit be cleared
   1271   // when reset the port, we don't need to care that here. It
   1272   // should be handled in the EHCI driver.
   1273   //
   1274   Bus     = RootIf->Device->Bus;
   1275 
   1276   Status  = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
   1277 
   1278   if (EFI_ERROR (Status)) {
   1279     DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));
   1280     return Status;
   1281   }
   1282 
   1283   //
   1284   // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
   1285   // section 7.1.7.5 for timing requirements.
   1286   //
   1287   gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);
   1288 
   1289   Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
   1290 
   1291   if (EFI_ERROR (Status)) {
   1292     DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
   1293     return Status;
   1294   }
   1295 
   1296   gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);
   1297 
   1298   //
   1299   // USB host controller won't clear the RESET bit until
   1300   // reset is actually finished.
   1301   //
   1302   ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
   1303 
   1304   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
   1305     Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
   1306 
   1307     if (EFI_ERROR (Status)) {
   1308       return Status;
   1309     }
   1310 
   1311     if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
   1312       break;
   1313     }
   1314 
   1315     gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
   1316   }
   1317 
   1318   if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
   1319     DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
   1320     return EFI_TIMEOUT;
   1321   }
   1322 
   1323   if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
   1324     //
   1325     // OK, the port is reset. If root hub is of high speed and
   1326     // the device is of low/full speed, release the ownership to
   1327     // companion UHCI. If root hub is of full speed, it won't
   1328     // automatically enable the port, we need to enable it manually.
   1329     //
   1330     if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
   1331       DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
   1332 
   1333       UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
   1334       return EFI_NOT_FOUND;
   1335 
   1336     } else {
   1337 
   1338       Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
   1339 
   1340       if (EFI_ERROR (Status)) {
   1341         DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
   1342         return Status;
   1343       }
   1344 
   1345       gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);
   1346     }
   1347   }
   1348 
   1349   return EFI_SUCCESS;
   1350 }
   1351 
   1352 
   1353 /**
   1354   Release the root hub's control of the interface.
   1355 
   1356   @param  HubIf                 The root hub interface.
   1357 
   1358   @retval EFI_SUCCESS           The root hub's control of the interface is
   1359                                 released.
   1360 
   1361 **/
   1362 EFI_STATUS
   1363 UsbRootHubRelease (
   1364   IN USB_INTERFACE        *HubIf
   1365   )
   1366 {
   1367   DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));
   1368 
   1369   gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
   1370   gBS->CloseEvent (HubIf->HubNotify);
   1371 
   1372   return EFI_SUCCESS;
   1373 }
   1374 
   1375 USB_HUB_API mUsbHubApi = {
   1376   UsbHubInit,
   1377   UsbHubGetPortStatus,
   1378   UsbHubClearPortChange,
   1379   UsbHubSetPortFeature,
   1380   UsbHubClearPortFeature,
   1381   UsbHubResetPort,
   1382   UsbHubRelease
   1383 };
   1384 
   1385 USB_HUB_API mUsbRootHubApi = {
   1386   UsbRootHubInit,
   1387   UsbRootHubGetPortStatus,
   1388   UsbRootHubClearPortChange,
   1389   UsbRootHubSetPortFeature,
   1390   UsbRootHubClearPortFeature,
   1391   UsbRootHubResetPort,
   1392   UsbRootHubRelease
   1393 };
   1394