Home | History | Annotate | Download | only in UhciPei
      1 /** @file
      2 PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid
      3 which is used to enable recovery function from USB Drivers.
      4 
      5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved. <BR>
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions
      9 of the BSD License which accompanies this distribution.  The
     10 full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "UhcPeim.h"
     19 
     20 /**
     21   Initializes Usb Host Controller.
     22 
     23   @param  FileHandle  Handle of the file being invoked.
     24   @param  PeiServices Describes the list of possible PEI Services.
     25 
     26   @retval EFI_SUCCESS            PPI successfully installed.
     27   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
     28 
     29 **/
     30 EFI_STATUS
     31 EFIAPI
     32 UhcPeimEntry (
     33   IN EFI_PEI_FILE_HANDLE        FileHandle,
     34   IN CONST EFI_PEI_SERVICES     **PeiServices
     35   )
     36 {
     37   PEI_USB_CONTROLLER_PPI      *ChipSetUsbControllerPpi;
     38   EFI_STATUS                  Status;
     39   UINT8                       Index;
     40   UINTN                       ControllerType;
     41   UINTN                       BaseAddress;
     42   UINTN                       MemPages;
     43   USB_UHC_DEV                 *UhcDev;
     44   EFI_PHYSICAL_ADDRESS        TempPtr;
     45 
     46   //
     47   // Shadow this PEIM to run from memory
     48   //
     49   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
     50     return EFI_SUCCESS;
     51   }
     52 
     53   Status = PeiServicesLocatePpi (
     54              &gPeiUsbControllerPpiGuid,
     55              0,
     56              NULL,
     57              (VOID **) &ChipSetUsbControllerPpi
     58              );
     59   //
     60   // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.
     61   //
     62   ASSERT_EFI_ERROR (Status);
     63 
     64   Index = 0;
     65   while (TRUE) {
     66     Status = ChipSetUsbControllerPpi->GetUsbController (
     67                                         (EFI_PEI_SERVICES **) PeiServices,
     68                                         ChipSetUsbControllerPpi,
     69                                         Index,
     70                                         &ControllerType,
     71                                         &BaseAddress
     72                                         );
     73     //
     74     // When status is error, meant no controller is found
     75     //
     76     if (EFI_ERROR (Status)) {
     77       break;
     78     }
     79 
     80     //
     81     // This PEIM is for UHC type controller.
     82     //
     83     if (ControllerType != PEI_UHCI_CONTROLLER) {
     84       Index++;
     85       continue;
     86     }
     87 
     88     MemPages = sizeof (USB_UHC_DEV) / EFI_PAGE_SIZE + 1;
     89 
     90     Status = PeiServicesAllocatePages (
     91                EfiBootServicesData,
     92                MemPages,
     93                &TempPtr
     94                );
     95     if (EFI_ERROR (Status)) {
     96       return EFI_OUT_OF_RESOURCES;
     97     }
     98 
     99     UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);
    100     UhcDev->Signature   = USB_UHC_DEV_SIGNATURE;
    101     UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
    102 
    103     //
    104     // Init local memory management service
    105     //
    106     Status = InitializeMemoryManagement (UhcDev);
    107     if (EFI_ERROR (Status)) {
    108       return Status;
    109     }
    110 
    111     //
    112     // Initialize Uhc's hardware
    113     //
    114     Status = InitializeUsbHC (UhcDev);
    115     if (EFI_ERROR (Status)) {
    116       return Status;
    117     }
    118 
    119     UhcDev->UsbHostControllerPpi.ControlTransfer          = UhcControlTransfer;
    120     UhcDev->UsbHostControllerPpi.BulkTransfer             = UhcBulkTransfer;
    121     UhcDev->UsbHostControllerPpi.GetRootHubPortNumber     = UhcGetRootHubPortNumber;
    122     UhcDev->UsbHostControllerPpi.GetRootHubPortStatus     = UhcGetRootHubPortStatus;
    123     UhcDev->UsbHostControllerPpi.SetRootHubPortFeature    = UhcSetRootHubPortFeature;
    124     UhcDev->UsbHostControllerPpi.ClearRootHubPortFeature  = UhcClearRootHubPortFeature;
    125 
    126     UhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
    127     UhcDev->PpiDescriptor.Guid  = &gPeiUsbHostControllerPpiGuid;
    128     UhcDev->PpiDescriptor.Ppi   = &UhcDev->UsbHostControllerPpi;
    129 
    130     Status = PeiServicesInstallPpi (&UhcDev->PpiDescriptor);
    131     if (EFI_ERROR (Status)) {
    132       Index++;
    133       continue;
    134     }
    135 
    136     Index++;
    137   }
    138 
    139   return EFI_SUCCESS;
    140 }
    141 
    142 /**
    143   Submits control transfer to a target USB device.
    144 
    145   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
    146   @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
    147   @param  DeviceAddress          The target device address.
    148   @param  DeviceSpeed            Target device speed.
    149   @param  MaximumPacketLength    Maximum packet size the default control transfer
    150                                  endpoint is capable of sending or receiving.
    151   @param  Request                USB device request to send.
    152   @param  TransferDirection      Specifies the data direction for the data stage.
    153   @param  Data                   Data buffer to be transmitted or received from USB device.
    154   @param  DataLength             The size (in bytes) of the data buffer.
    155   @param  TimeOut                Indicates the maximum timeout, in millisecond.
    156                                  If Timeout is 0, then the caller must wait for the function
    157                                  to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
    158   @param  TransferResult         Return the result of this control transfer.
    159 
    160   @retval EFI_SUCCESS            Transfer was completed successfully.
    161   @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
    162   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
    163   @retval EFI_TIMEOUT            Transfer failed due to timeout.
    164   @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
    165 
    166 **/
    167 EFI_STATUS
    168 EFIAPI
    169 UhcControlTransfer (
    170   IN     EFI_PEI_SERVICES               **PeiServices,
    171   IN     PEI_USB_HOST_CONTROLLER_PPI    *This,
    172   IN     UINT8                          DeviceAddress,
    173   IN     UINT8                          DeviceSpeed,
    174   IN     UINT8                          MaximumPacketLength,
    175   IN     EFI_USB_DEVICE_REQUEST         *Request,
    176   IN     EFI_USB_DATA_DIRECTION         TransferDirection,
    177   IN OUT VOID                           *Data                 OPTIONAL,
    178   IN OUT UINTN                          *DataLength           OPTIONAL,
    179   IN     UINTN                          TimeOut,
    180   OUT    UINT32                         *TransferResult
    181   )
    182 {
    183   USB_UHC_DEV *UhcDev;
    184   UINT32      StatusReg;
    185   UINT8       PktID;
    186   QH_STRUCT   *PtrQH;
    187   TD_STRUCT   *PtrTD;
    188   TD_STRUCT   *PtrPreTD;
    189   TD_STRUCT   *PtrSetupTD;
    190   TD_STRUCT   *PtrStatusTD;
    191   EFI_STATUS  Status;
    192   UINT32      DataLen;
    193   UINT8       *PtrDataSource;
    194   UINT8       *Ptr;
    195   UINT8       DataToggle;
    196 
    197   UhcDev      = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
    198 
    199   StatusReg   = UhcDev->UsbHostControllerBaseAddress + USBSTS;
    200 
    201   PktID       = INPUT_PACKET_ID;
    202 
    203   if (Request == NULL || TransferResult == NULL) {
    204     return EFI_INVALID_PARAMETER;
    205   }
    206   //
    207   // if errors exist that cause host controller halt,
    208   // then return EFI_DEVICE_ERROR.
    209   //
    210 
    211   if (!IsStatusOK (UhcDev, StatusReg)) {
    212     ClearStatusReg (UhcDev, StatusReg);
    213     *TransferResult = EFI_USB_ERR_SYSTEM;
    214     return EFI_DEVICE_ERROR;
    215   }
    216 
    217   ClearStatusReg (UhcDev, StatusReg);
    218 
    219   //
    220   // generate Setup Stage TD
    221   //
    222 
    223   PtrQH = UhcDev->ConfigQH;
    224 
    225   GenSetupStageTD (
    226     UhcDev,
    227     DeviceAddress,
    228     0,
    229     DeviceSpeed,
    230     (UINT8 *) Request,
    231     (UINT8) sizeof (EFI_USB_DEVICE_REQUEST),
    232     &PtrSetupTD
    233     );
    234 
    235   //
    236   // link setup TD structures to QH structure
    237   //
    238   LinkTDToQH (PtrQH, PtrSetupTD);
    239 
    240   PtrPreTD = PtrSetupTD;
    241 
    242   //
    243   //  Data Stage of Control Transfer
    244   //
    245   switch (TransferDirection) {
    246 
    247   case EfiUsbDataIn:
    248     PktID         = INPUT_PACKET_ID;
    249     PtrDataSource = Data;
    250     DataLen       = (UINT32) *DataLength;
    251     Ptr           = PtrDataSource;
    252     break;
    253 
    254   case EfiUsbDataOut:
    255     PktID         = OUTPUT_PACKET_ID;
    256     PtrDataSource = Data;
    257     DataLen       = (UINT32) *DataLength;
    258     Ptr           = PtrDataSource;
    259     break;
    260 
    261   //
    262   // no data stage
    263   //
    264   case EfiUsbNoData:
    265     if (*DataLength != 0) {
    266       return EFI_INVALID_PARAMETER;
    267     }
    268 
    269     PktID         = OUTPUT_PACKET_ID;
    270     PtrDataSource = NULL;
    271     DataLen       = 0;
    272     Ptr           = NULL;
    273     break;
    274 
    275   default:
    276     return EFI_INVALID_PARAMETER;
    277   }
    278 
    279   DataToggle  = 1;
    280 
    281   PtrTD       = PtrSetupTD;
    282   while (DataLen > 0) {
    283     //
    284     // create TD structures and link together
    285     //
    286     UINT8 PacketSize;
    287 
    288     //
    289     // PacketSize is the data load size of each TD carries.
    290     //
    291     PacketSize = (UINT8) DataLen;
    292     if (DataLen > MaximumPacketLength) {
    293       PacketSize = MaximumPacketLength;
    294     }
    295 
    296     GenDataTD (
    297       UhcDev,
    298       DeviceAddress,
    299       0,
    300       Ptr,
    301       PacketSize,
    302       PktID,
    303       DataToggle,
    304       DeviceSpeed,
    305       &PtrTD
    306       );
    307 
    308     //
    309     // Link two TDs in vertical depth
    310     //
    311     LinkTDToTD (PtrPreTD, PtrTD);
    312     PtrPreTD = PtrTD;
    313 
    314     DataToggle ^= 1;
    315     Ptr += PacketSize;
    316     DataLen -= PacketSize;
    317   }
    318 
    319   //
    320   // PtrPreTD points to the last TD before the Setup-Stage TD.
    321   //
    322   PtrPreTD = PtrTD;
    323 
    324   //
    325   // Status Stage of Control Transfer
    326   //
    327   if (PktID == OUTPUT_PACKET_ID) {
    328     PktID = INPUT_PACKET_ID;
    329   } else {
    330     PktID = OUTPUT_PACKET_ID;
    331   }
    332   //
    333   // create Status Stage TD structure
    334   //
    335   CreateStatusTD (
    336     UhcDev,
    337     DeviceAddress,
    338     0,
    339     PktID,
    340     DeviceSpeed,
    341     &PtrStatusTD
    342     );
    343 
    344   LinkTDToTD (PtrPreTD, PtrStatusTD);
    345 
    346   //
    347   // Poll QH-TDs execution and get result.
    348   // detail status is returned
    349   //
    350   Status = ExecuteControlTransfer (
    351             UhcDev,
    352             PtrSetupTD,
    353             DataLength,
    354             TimeOut,
    355             TransferResult
    356             );
    357 
    358   //
    359   // TRUE means must search other framelistindex
    360   //
    361   SetQHVerticalValidorInvalid(PtrQH, FALSE);
    362   DeleteQueuedTDs (UhcDev, PtrSetupTD);
    363 
    364   //
    365   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
    366   //
    367   if (!IsStatusOK (UhcDev, StatusReg)) {
    368 
    369     ClearStatusReg (UhcDev, StatusReg);
    370     *TransferResult |= EFI_USB_ERR_SYSTEM;
    371     return EFI_DEVICE_ERROR;
    372   }
    373 
    374   ClearStatusReg (UhcDev, StatusReg);
    375 
    376   return Status;
    377 }
    378 
    379 /**
    380   Submits bulk transfer to a bulk endpoint of a USB device.
    381 
    382   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
    383   @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
    384   @param  DeviceAddress         Target device address.
    385   @param  EndPointAddress       Endpoint number and its direction in bit 7.
    386   @param  MaximumPacketLength   Maximum packet size the endpoint is capable of
    387                                 sending or receiving.
    388   @param  Data                  Array of pointers to the buffers of data to transmit
    389                                 from or receive into.
    390   @param  DataLength            The lenght of the data buffer.
    391   @param  DataToggle            On input, the initial data toggle for the transfer;
    392                                 On output, it is updated to to next data toggle to use of
    393                                 the subsequent bulk transfer.
    394   @param  TimeOut               Indicates the maximum time, in millisecond, which the
    395                                 transfer is allowed to complete.
    396                                 If Timeout is 0, then the caller must wait for the function
    397                                 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
    398   @param  TransferResult        A pointer to the detailed result information of the
    399                                 bulk transfer.
    400 
    401   @retval EFI_SUCCESS           The transfer was completed successfully.
    402   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
    403   @retval EFI_INVALID_PARAMETER Parameters are invalid.
    404   @retval EFI_TIMEOUT           The transfer failed due to timeout.
    405   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
    406 
    407 **/
    408 EFI_STATUS
    409 EFIAPI
    410 UhcBulkTransfer (
    411   IN     EFI_PEI_SERVICES               **PeiServices,
    412   IN     PEI_USB_HOST_CONTROLLER_PPI    *This,
    413   IN     UINT8                          DeviceAddress,
    414   IN     UINT8                          EndPointAddress,
    415   IN     UINT8                          MaximumPacketLength,
    416   IN OUT VOID                           *Data,
    417   IN OUT UINTN                          *DataLength,
    418   IN OUT UINT8                          *DataToggle,
    419   IN     UINTN                          TimeOut,
    420   OUT    UINT32                         *TransferResult
    421   )
    422 {
    423   USB_UHC_DEV             *UhcDev;
    424   UINT32                  StatusReg;
    425 
    426   UINT32                  DataLen;
    427 
    428   QH_STRUCT               *PtrQH;
    429   TD_STRUCT               *PtrFirstTD;
    430   TD_STRUCT               *PtrTD;
    431   TD_STRUCT               *PtrPreTD;
    432 
    433   UINT8                   PktID;
    434   UINT8                   *PtrDataSource;
    435   UINT8                   *Ptr;
    436 
    437   BOOLEAN                 IsFirstTD;
    438 
    439   EFI_STATUS              Status;
    440 
    441   EFI_USB_DATA_DIRECTION  TransferDirection;
    442 
    443   BOOLEAN                 ShortPacketEnable;
    444 
    445   UINT16                  CommandContent;
    446 
    447   UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
    448 
    449   //
    450   // Enable the maximum packet size (64bytes)
    451   // that can be used for full speed bandwidth reclamation
    452   // at the end of a frame.
    453   //
    454   CommandContent = USBReadPortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD);
    455   if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {
    456     CommandContent |= USBCMD_MAXP;
    457     USBWritePortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD, CommandContent);
    458   }
    459 
    460   StatusReg   = UhcDev->UsbHostControllerBaseAddress + USBSTS;
    461 
    462   //
    463   // these code lines are added here per complier's strict demand
    464   //
    465   PktID             = INPUT_PACKET_ID;
    466   PtrTD             = NULL;
    467   PtrFirstTD        = NULL;
    468   PtrPreTD          = NULL;
    469   DataLen           = 0;
    470   Ptr               = NULL;
    471 
    472   ShortPacketEnable = FALSE;
    473 
    474   if ((DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
    475     return EFI_INVALID_PARAMETER;
    476   }
    477 
    478   if ((*DataToggle != 1) && (*DataToggle != 0)) {
    479     return EFI_INVALID_PARAMETER;
    480   }
    481 
    482   if (MaximumPacketLength != 8 && MaximumPacketLength != 16
    483       && MaximumPacketLength != 32 && MaximumPacketLength != 64) {
    484     return EFI_INVALID_PARAMETER;
    485   }
    486   //
    487   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
    488   //
    489   if (!IsStatusOK (UhcDev, StatusReg)) {
    490 
    491     ClearStatusReg (UhcDev, StatusReg);
    492     *TransferResult = EFI_USB_ERR_SYSTEM;
    493     return EFI_DEVICE_ERROR;
    494   }
    495 
    496   ClearStatusReg (UhcDev, StatusReg);
    497 
    498   if ((EndPointAddress & 0x80) != 0) {
    499     TransferDirection = EfiUsbDataIn;
    500   } else {
    501     TransferDirection = EfiUsbDataOut;
    502   }
    503 
    504   switch (TransferDirection) {
    505 
    506   case EfiUsbDataIn:
    507     ShortPacketEnable = TRUE;
    508     PktID             = INPUT_PACKET_ID;
    509     PtrDataSource     = Data;
    510     DataLen           = (UINT32) *DataLength;
    511     Ptr               = PtrDataSource;
    512     break;
    513 
    514   case EfiUsbDataOut:
    515     PktID         = OUTPUT_PACKET_ID;
    516     PtrDataSource = Data;
    517     DataLen       = (UINT32) *DataLength;
    518     Ptr           = PtrDataSource;
    519     break;
    520 
    521   default:
    522     break;
    523   }
    524 
    525   PtrQH = UhcDev->BulkQH;
    526 
    527   IsFirstTD = TRUE;
    528   while (DataLen > 0) {
    529     //
    530     // create TD structures and link together
    531     //
    532     UINT8 PacketSize;
    533 
    534     PacketSize = (UINT8) DataLen;
    535     if (DataLen > MaximumPacketLength) {
    536       PacketSize = MaximumPacketLength;
    537     }
    538 
    539     GenDataTD (
    540       UhcDev,
    541       DeviceAddress,
    542       EndPointAddress,
    543       Ptr,
    544       PacketSize,
    545       PktID,
    546       *DataToggle,
    547       USB_FULL_SPEED_DEVICE,
    548       &PtrTD
    549       );
    550 
    551     //
    552     // Enable short packet detection.
    553     // (default action is disabling short packet detection)
    554     //
    555     if (ShortPacketEnable) {
    556       EnableorDisableTDShortPacket (PtrTD, TRUE);
    557     }
    558 
    559     if (IsFirstTD) {
    560       PtrFirstTD            = PtrTD;
    561       PtrFirstTD->PtrNextTD = NULL;
    562       IsFirstTD             = FALSE;
    563     } else {
    564       //
    565       // Link two TDs in vertical depth
    566       //
    567       LinkTDToTD (PtrPreTD, PtrTD);
    568     }
    569 
    570     PtrPreTD = PtrTD;
    571 
    572     *DataToggle ^= 1;
    573     Ptr += PacketSize;
    574     DataLen -= PacketSize;
    575   }
    576   //
    577   // link TD structures to QH structure
    578   //
    579   LinkTDToQH (PtrQH, PtrFirstTD);
    580 
    581   //
    582   // Execute QH-TD and get result
    583   //
    584   //
    585   // detail status is put into the Result field in the pIRP
    586   // the Data Toggle value is also re-updated to the value
    587   // of the last successful TD
    588   //
    589   Status = ExecBulkTransfer (
    590             UhcDev,
    591             PtrFirstTD,
    592             DataLength,
    593             DataToggle,
    594             TimeOut,
    595             TransferResult
    596             );
    597 
    598   //
    599   // Delete Bulk transfer TD structure
    600   //
    601   DeleteQueuedTDs (UhcDev, PtrFirstTD);
    602 
    603   //
    604   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
    605   //
    606   if (!IsStatusOK (UhcDev, StatusReg)) {
    607 
    608     ClearStatusReg (UhcDev, StatusReg);
    609     *TransferResult |= EFI_USB_ERR_SYSTEM;
    610     return EFI_DEVICE_ERROR;
    611   }
    612 
    613   ClearStatusReg (UhcDev, StatusReg);
    614 
    615   return Status;
    616 }
    617 
    618 /**
    619   Retrieves the number of root hub ports.
    620 
    621   @param[in]  PeiServices   The pointer to the PEI Services Table.
    622   @param[in]  This          The pointer to this instance of the
    623                             PEI_USB_HOST_CONTROLLER_PPI.
    624   @param[out] PortNumber    The pointer to the number of the root hub ports.
    625 
    626   @retval EFI_SUCCESS           The port number was retrieved successfully.
    627   @retval EFI_INVALID_PARAMETER PortNumber is NULL.
    628 
    629 **/
    630 EFI_STATUS
    631 EFIAPI
    632 UhcGetRootHubPortNumber (
    633   IN EFI_PEI_SERVICES               **PeiServices,
    634   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
    635   OUT UINT8                         *PortNumber
    636   )
    637 {
    638   USB_UHC_DEV *UhcDev;
    639   UINT32      PSAddr;
    640   UINT16      RHPortControl;
    641   UINT32      Index;
    642 
    643   UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
    644 
    645   if (PortNumber == NULL) {
    646     return EFI_INVALID_PARAMETER;
    647   }
    648 
    649   *PortNumber = 0;
    650 
    651   for (Index = 0; Index < 2; Index++) {
    652     PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + Index * 2;
    653     RHPortControl = USBReadPortW (UhcDev, PSAddr);
    654     //
    655     // Port Register content is valid
    656     //
    657     if (RHPortControl != 0xff) {
    658       (*PortNumber)++;
    659     }
    660   }
    661 
    662   return EFI_SUCCESS;
    663 }
    664 
    665 /**
    666   Retrieves the current status of a USB root hub port.
    667 
    668   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
    669   @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
    670   @param  PortNumber             The root hub port to retrieve the state from.
    671   @param  PortStatus             Variable to receive the port state.
    672 
    673   @retval EFI_SUCCESS            The status of the USB root hub port specified.
    674                                  by PortNumber was returned in PortStatus.
    675   @retval EFI_INVALID_PARAMETER  PortNumber is invalid.
    676 
    677 **/
    678 EFI_STATUS
    679 EFIAPI
    680 UhcGetRootHubPortStatus (
    681   IN EFI_PEI_SERVICES               **PeiServices,
    682   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
    683   IN  UINT8                         PortNumber,
    684   OUT EFI_USB_PORT_STATUS           *PortStatus
    685   )
    686 {
    687   USB_UHC_DEV *UhcDev;
    688   UINT32      PSAddr;
    689   UINT16      RHPortStatus;
    690   UINT8       TotalPortNumber;
    691 
    692   if (PortStatus == NULL) {
    693     return EFI_INVALID_PARAMETER;
    694   }
    695 
    696   UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
    697   if (PortNumber > TotalPortNumber) {
    698     return EFI_INVALID_PARAMETER;
    699   }
    700 
    701   UhcDev                        = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
    702   PSAddr                        = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
    703 
    704   PortStatus->PortStatus        = 0;
    705   PortStatus->PortChangeStatus  = 0;
    706 
    707   RHPortStatus = USBReadPortW (UhcDev, PSAddr);
    708 
    709   //
    710   // Current Connect Status
    711   //
    712   if ((RHPortStatus & USBPORTSC_CCS) != 0) {
    713     PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
    714   }
    715   //
    716   // Port Enabled/Disabled
    717   //
    718   if ((RHPortStatus & USBPORTSC_PED) != 0) {
    719     PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
    720   }
    721   //
    722   // Port Suspend
    723   //
    724   if ((RHPortStatus & USBPORTSC_SUSP) != 0) {
    725     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
    726   }
    727   //
    728   // Port Reset
    729   //
    730   if ((RHPortStatus & USBPORTSC_PR) != 0) {
    731     PortStatus->PortStatus |= USB_PORT_STAT_RESET;
    732   }
    733   //
    734   // Low Speed Device Attached
    735   //
    736   if ((RHPortStatus & USBPORTSC_LSDA) != 0) {
    737     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
    738   }
    739   //
    740   //   Fill Port Status Change bits
    741   //
    742   //
    743   // Connect Status Change
    744   //
    745   if ((RHPortStatus & USBPORTSC_CSC) != 0) {
    746     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
    747   }
    748   //
    749   // Port Enabled/Disabled Change
    750   //
    751   if ((RHPortStatus & USBPORTSC_PEDC) != 0) {
    752     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
    753   }
    754 
    755   return EFI_SUCCESS;
    756 }
    757 
    758 /**
    759   Sets a feature for the specified root hub port.
    760 
    761   @param  PeiServices           The pointer of EFI_PEI_SERVICES
    762   @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI
    763   @param  PortNumber            Root hub port to set.
    764   @param  PortFeature           Feature to set.
    765 
    766   @retval EFI_SUCCESS            The feature specified by PortFeature was set.
    767   @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
    768   @retval EFI_TIMEOUT            The time out occurred.
    769 
    770 **/
    771 EFI_STATUS
    772 EFIAPI
    773 UhcSetRootHubPortFeature (
    774   IN EFI_PEI_SERVICES               **PeiServices,
    775   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
    776   IN UINT8                          PortNumber,
    777   IN EFI_USB_PORT_FEATURE           PortFeature
    778   )
    779 {
    780   USB_UHC_DEV *UhcDev;
    781   UINT32      PSAddr;
    782   UINT32      CommandRegAddr;
    783   UINT16      RHPortControl;
    784   UINT8       TotalPortNumber;
    785 
    786   UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
    787   if (PortNumber > TotalPortNumber) {
    788     return EFI_INVALID_PARAMETER;
    789   }
    790 
    791   UhcDev          = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
    792   PSAddr          = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
    793   CommandRegAddr  = UhcDev->UsbHostControllerBaseAddress + USBCMD;
    794 
    795   RHPortControl = USBReadPortW (UhcDev, PSAddr);
    796 
    797   switch (PortFeature) {
    798 
    799   case EfiUsbPortSuspend:
    800     if ((USBReadPortW (UhcDev, CommandRegAddr) & USBCMD_EGSM) == 0) {
    801       //
    802       // if global suspend is not active, can set port suspend
    803       //
    804       RHPortControl &= 0xfff5;
    805       RHPortControl |= USBPORTSC_SUSP;
    806     }
    807     break;
    808 
    809   case EfiUsbPortReset:
    810     RHPortControl &= 0xfff5;
    811     RHPortControl |= USBPORTSC_PR;
    812     //
    813     // Set the reset bit
    814     //
    815     break;
    816 
    817   case EfiUsbPortPower:
    818     break;
    819 
    820   case EfiUsbPortEnable:
    821     RHPortControl &= 0xfff5;
    822     RHPortControl |= USBPORTSC_PED;
    823     break;
    824 
    825   default:
    826     return EFI_INVALID_PARAMETER;
    827   }
    828 
    829   USBWritePortW (UhcDev, PSAddr, RHPortControl);
    830 
    831   return EFI_SUCCESS;
    832 }
    833 
    834 /**
    835   Clears a feature for the specified root hub port.
    836 
    837   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
    838   @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
    839   @param  PortNumber            Specifies the root hub port whose feature
    840                                 is requested to be cleared.
    841   @param  PortFeature           Indicates the feature selector associated with the
    842                                 feature clear request.
    843 
    844   @retval EFI_SUCCESS            The feature specified by PortFeature was cleared
    845                                  for the USB root hub port specified by PortNumber.
    846   @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
    847 
    848 **/
    849 EFI_STATUS
    850 EFIAPI
    851 UhcClearRootHubPortFeature (
    852   IN EFI_PEI_SERVICES               **PeiServices,
    853   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
    854   IN UINT8                          PortNumber,
    855   IN EFI_USB_PORT_FEATURE           PortFeature
    856   )
    857 {
    858   USB_UHC_DEV *UhcDev;
    859   UINT32      PSAddr;
    860   UINT16      RHPortControl;
    861   UINT8       TotalPortNumber;
    862 
    863   UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
    864 
    865   if (PortNumber > TotalPortNumber) {
    866     return EFI_INVALID_PARAMETER;
    867   }
    868 
    869   UhcDev  = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
    870   PSAddr  = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
    871 
    872   RHPortControl = USBReadPortW (UhcDev, PSAddr);
    873 
    874   switch (PortFeature) {
    875   //
    876   // clear PORT_ENABLE feature means disable port.
    877   //
    878   case EfiUsbPortEnable:
    879     RHPortControl &= 0xfff5;
    880     RHPortControl &= ~USBPORTSC_PED;
    881     break;
    882 
    883   //
    884   // clear PORT_SUSPEND feature means resume the port.
    885   // (cause a resume on the specified port if in suspend mode)
    886   //
    887   case EfiUsbPortSuspend:
    888     RHPortControl &= 0xfff5;
    889     RHPortControl &= ~USBPORTSC_SUSP;
    890     break;
    891 
    892   //
    893   // no operation
    894   //
    895   case EfiUsbPortPower:
    896     break;
    897 
    898   //
    899   // clear PORT_RESET means clear the reset signal.
    900   //
    901   case EfiUsbPortReset:
    902     RHPortControl &= 0xfff5;
    903     RHPortControl &= ~USBPORTSC_PR;
    904     break;
    905 
    906   //
    907   // clear connect status change
    908   //
    909   case EfiUsbPortConnectChange:
    910     RHPortControl &= 0xfff5;
    911     RHPortControl |= USBPORTSC_CSC;
    912     break;
    913 
    914   //
    915   // clear enable/disable status change
    916   //
    917   case EfiUsbPortEnableChange:
    918     RHPortControl &= 0xfff5;
    919     RHPortControl |= USBPORTSC_PEDC;
    920     break;
    921 
    922   //
    923   // root hub does not support this request
    924   //
    925   case EfiUsbPortSuspendChange:
    926     break;
    927 
    928   //
    929   // root hub does not support this request
    930   //
    931   case EfiUsbPortOverCurrentChange:
    932     break;
    933 
    934   //
    935   // root hub does not support this request
    936   //
    937   case EfiUsbPortResetChange:
    938     break;
    939 
    940   default:
    941     return EFI_INVALID_PARAMETER;
    942   }
    943 
    944   USBWritePortW (UhcDev, PSAddr, RHPortControl);
    945 
    946   return EFI_SUCCESS;
    947 }
    948 
    949 /**
    950   Initialize UHCI.
    951 
    952   @param  UhcDev                 UHCI Device.
    953 
    954   @retval EFI_SUCCESS            UHCI successfully initialized.
    955   @retval EFI_OUT_OF_RESOURCES   Resource can not be allocated.
    956 
    957 **/
    958 EFI_STATUS
    959 InitializeUsbHC (
    960   IN USB_UHC_DEV          *UhcDev
    961   )
    962 {
    963   EFI_STATUS  Status;
    964   UINT32      FrameListBaseAddrReg;
    965   UINT32      CommandReg;
    966   UINT16      Command;
    967 
    968   //
    969   // Create and Initialize Frame List For the Host Controller.
    970   //
    971   Status = CreateFrameList (UhcDev);
    972   if (EFI_ERROR (Status)) {
    973     return Status;
    974   }
    975 
    976   FrameListBaseAddrReg  = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD;
    977   CommandReg            = UhcDev->UsbHostControllerBaseAddress + USBCMD;
    978 
    979   //
    980   // Set Frame List Base Address to the specific register to inform the hardware.
    981   //
    982   SetFrameListBaseAddress (UhcDev, FrameListBaseAddrReg, (UINT32) (UINTN) (UhcDev->FrameListEntry));
    983 
    984   Command = USBReadPortW (UhcDev, CommandReg);
    985   Command |= USBCMD_GRESET;
    986   USBWritePortW (UhcDev, CommandReg, Command);
    987 
    988   MicroSecondDelay (50 * 1000);
    989 
    990 
    991   Command &= ~USBCMD_GRESET;
    992 
    993   USBWritePortW (UhcDev, CommandReg, Command);
    994 
    995   //
    996   //UHCI spec page120 reset recovery time
    997   //
    998   MicroSecondDelay (20 * 1000);
    999 
   1000   //
   1001   // Set Run/Stop bit to 1.
   1002   //
   1003   Command = USBReadPortW (UhcDev, CommandReg);
   1004   Command |= USBCMD_RS | USBCMD_MAXP;
   1005   USBWritePortW (UhcDev, CommandReg, Command);
   1006 
   1007   return EFI_SUCCESS;
   1008 }
   1009 
   1010 /**
   1011   Create Frame List Structure.
   1012 
   1013   @param  UhcDev                 UHCI device.
   1014 
   1015   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
   1016   @retval EFI_SUCCESS            Success.
   1017 
   1018 **/
   1019 EFI_STATUS
   1020 CreateFrameList (
   1021   USB_UHC_DEV             *UhcDev
   1022   )
   1023 {
   1024   EFI_STATUS            Status;
   1025   EFI_PHYSICAL_ADDRESS  FrameListBaseAddr;
   1026   FRAMELIST_ENTRY       *FrameListPtr;
   1027   UINTN                 Index;
   1028 
   1029   //
   1030   // The Frame List ocupies 4K bytes,
   1031   // and must be aligned on 4-Kbyte boundaries.
   1032   //
   1033   Status = PeiServicesAllocatePages (
   1034              EfiBootServicesData,
   1035              1,
   1036              &FrameListBaseAddr
   1037              );
   1038 
   1039   if (Status != EFI_SUCCESS) {
   1040     return EFI_OUT_OF_RESOURCES;
   1041   }
   1042 
   1043   //
   1044   //Create Control QH and Bulk QH and link them into Framelist Entry
   1045   //
   1046   Status = CreateQH(UhcDev, &UhcDev->ConfigQH);
   1047   if (Status != EFI_SUCCESS) {
   1048     return EFI_OUT_OF_RESOURCES;
   1049   }
   1050   ASSERT (UhcDev->ConfigQH != NULL);
   1051 
   1052   Status = CreateQH(UhcDev, &UhcDev->BulkQH);
   1053   if (Status != EFI_SUCCESS) {
   1054     return EFI_OUT_OF_RESOURCES;
   1055   }
   1056   ASSERT (UhcDev->BulkQH != NULL);
   1057 
   1058   //
   1059   //Set the corresponding QH pointer
   1060   //
   1061   SetQHHorizontalLinkPtr(UhcDev->ConfigQH, UhcDev->BulkQH);
   1062   SetQHHorizontalQHorTDSelect (UhcDev->ConfigQH, TRUE);
   1063   SetQHHorizontalValidorInvalid (UhcDev->ConfigQH, TRUE);
   1064 
   1065   UhcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) FrameListBaseAddr);
   1066 
   1067   FrameListPtr = UhcDev->FrameListEntry;
   1068 
   1069   for (Index = 0; Index < 1024; Index++) {
   1070     FrameListPtr->FrameListPtrTerminate = 0;
   1071     FrameListPtr->FrameListPtr          = (UINT32)(UINTN)UhcDev->ConfigQH >> 4;
   1072     FrameListPtr->FrameListPtrQSelect   = 1;
   1073     FrameListPtr->FrameListRsvd         = 0;
   1074     FrameListPtr ++;
   1075   }
   1076 
   1077   return EFI_SUCCESS;
   1078 }
   1079 
   1080 /**
   1081   Read a 16bit width data from Uhc HC IO space register.
   1082 
   1083   @param  UhcDev  The UHCI device.
   1084   @param  Port    The IO space address of the register.
   1085 
   1086   @retval the register content read.
   1087 
   1088 **/
   1089 UINT16
   1090 USBReadPortW (
   1091   IN  USB_UHC_DEV   *UhcDev,
   1092   IN  UINT32        Port
   1093   )
   1094 {
   1095   return IoRead16 (Port);
   1096 }
   1097 
   1098 /**
   1099   Write a 16bit width data into Uhc HC IO space register.
   1100 
   1101   @param  UhcDev  The UHCI device.
   1102   @param  Port    The IO space address of the register.
   1103   @param  Data    The data written into the register.
   1104 
   1105 **/
   1106 VOID
   1107 USBWritePortW (
   1108   IN  USB_UHC_DEV   *UhcDev,
   1109   IN  UINT32        Port,
   1110   IN  UINT16        Data
   1111   )
   1112 {
   1113   IoWrite16 (Port, Data);
   1114 }
   1115 
   1116 /**
   1117   Write a 32bit width data into Uhc HC IO space register.
   1118 
   1119   @param  UhcDev  The UHCI device.
   1120   @param  Port    The IO space address of the register.
   1121   @param  Data    The data written into the register.
   1122 
   1123 **/
   1124 VOID
   1125 USBWritePortDW (
   1126   IN  USB_UHC_DEV   *UhcDev,
   1127   IN  UINT32        Port,
   1128   IN  UINT32        Data
   1129   )
   1130 {
   1131   IoWrite32 (Port, Data);
   1132 }
   1133 
   1134 /**
   1135   Clear the content of UHCI's Status Register.
   1136 
   1137   @param  UhcDev       The UHCI device.
   1138   @param  StatusAddr   The IO space address of the register.
   1139 
   1140 **/
   1141 VOID
   1142 ClearStatusReg (
   1143   IN  USB_UHC_DEV   *UhcDev,
   1144   IN  UINT32        StatusAddr
   1145   )
   1146 {
   1147   //
   1148   // Clear the content of UHCI's Status Register
   1149   //
   1150   USBWritePortW (UhcDev, StatusAddr, 0x003F);
   1151 }
   1152 
   1153 /**
   1154   Check whether the host controller operates well.
   1155 
   1156   @param  UhcDev        The UHCI device.
   1157   @param  StatusRegAddr The io address of status register.
   1158 
   1159   @retval TRUE          Host controller is working.
   1160   @retval FALSE         Host controller is halted or system error.
   1161 
   1162 **/
   1163 BOOLEAN
   1164 IsStatusOK (
   1165   IN USB_UHC_DEV     *UhcDev,
   1166   IN UINT32          StatusRegAddr
   1167   )
   1168 {
   1169   UINT16  StatusValue;
   1170 
   1171   StatusValue = USBReadPortW (UhcDev, StatusRegAddr);
   1172 
   1173   if ((StatusValue & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {
   1174     return FALSE;
   1175   } else {
   1176     return TRUE;
   1177   }
   1178 }
   1179 
   1180 /**
   1181   Get Current Frame Number.
   1182 
   1183   @param  UhcDev          The UHCI device.
   1184   @param  FrameNumberAddr The address of frame list register.
   1185 
   1186   @retval The content of the frame list register.
   1187 
   1188 **/
   1189 UINT16
   1190 GetCurrentFrameNumber (
   1191   IN USB_UHC_DEV   *UhcDev,
   1192   IN UINT32        FrameNumberAddr
   1193   )
   1194 {
   1195   //
   1196   // Gets value in the USB frame number register.
   1197   //
   1198   return (UINT16) (USBReadPortW (UhcDev, FrameNumberAddr) & 0x03FF);
   1199 }
   1200 
   1201 /**
   1202   Set Frame List Base Address.
   1203 
   1204   @param  UhcDev           The UHCI device.
   1205   @param  FrameListRegAddr The address of frame list register.
   1206   @param  Addr             The address of frame list table.
   1207 
   1208 **/
   1209 VOID
   1210 SetFrameListBaseAddress (
   1211   IN USB_UHC_DEV   *UhcDev,
   1212   IN UINT32        FrameListRegAddr,
   1213   IN UINT32        Addr
   1214   )
   1215 {
   1216   //
   1217   // Sets value in the USB Frame List Base Address register.
   1218   //
   1219   USBWritePortDW (UhcDev, FrameListRegAddr, (UINT32) (Addr & 0xFFFFF000));
   1220 }
   1221 
   1222 /**
   1223   Create QH and initialize.
   1224 
   1225   @param  UhcDev               The UHCI device.
   1226   @param  PtrQH                Place to store QH_STRUCT pointer.
   1227 
   1228   @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
   1229   @retval EFI_SUCCESS        Success.
   1230 
   1231 **/
   1232 EFI_STATUS
   1233 CreateQH (
   1234   IN  USB_UHC_DEV   *UhcDev,
   1235   OUT QH_STRUCT     **PtrQH
   1236   )
   1237 {
   1238   EFI_STATUS  Status;
   1239 
   1240   //
   1241   // allocate align memory for QH_STRUCT
   1242   //
   1243   Status = AllocateTDorQHStruct (UhcDev, sizeof(QH_STRUCT), (void **)PtrQH);
   1244   if (EFI_ERROR (Status)) {
   1245     return EFI_OUT_OF_RESOURCES;
   1246   }
   1247   //
   1248   // init each field of the QH_STRUCT
   1249   //
   1250   SetQHHorizontalValidorInvalid (*PtrQH, FALSE);
   1251   SetQHVerticalValidorInvalid (*PtrQH, FALSE);
   1252 
   1253   return EFI_SUCCESS;
   1254 }
   1255 
   1256 /**
   1257   Set the horizontal link pointer in QH.
   1258 
   1259   @param  PtrQH               Place to store QH_STRUCT pointer.
   1260   @param  PtrNext             Place to the next QH_STRUCT.
   1261 
   1262 **/
   1263 VOID
   1264 SetQHHorizontalLinkPtr (
   1265   IN QH_STRUCT  *PtrQH,
   1266   IN VOID       *PtrNext
   1267   )
   1268 {
   1269   //
   1270   // Since the QH_STRUCT is aligned on 16-byte boundaries,
   1271   // Only the highest 28bit of the address is valid
   1272   // (take 32bit address as an example).
   1273   //
   1274   PtrQH->QueueHead.QHHorizontalPtr = (UINT32) (UINTN) PtrNext >> 4;
   1275 }
   1276 
   1277 /**
   1278   Get the horizontal link pointer in QH.
   1279 
   1280   @param  PtrQH     Place to store QH_STRUCT pointer.
   1281 
   1282   @retval The horizontal link pointer in QH.
   1283 
   1284 **/
   1285 VOID *
   1286 GetQHHorizontalLinkPtr (
   1287   IN QH_STRUCT  *PtrQH
   1288   )
   1289 {
   1290   //
   1291   // Restore the 28bit address to 32bit address
   1292   // (take 32bit address as an example)
   1293   //
   1294   return (VOID *) (UINTN) ((PtrQH->QueueHead.QHHorizontalPtr) << 4);
   1295 }
   1296 
   1297 /**
   1298   Set a QH or TD horizontally to be connected with a specific QH.
   1299 
   1300   @param  PtrQH      Place to store QH_STRUCT pointer.
   1301   @param  IsQH       Specify QH or TD is connected.
   1302 
   1303 **/
   1304 VOID
   1305 SetQHHorizontalQHorTDSelect (
   1306   IN QH_STRUCT  *PtrQH,
   1307   IN BOOLEAN    IsQH
   1308   )
   1309 {
   1310   //
   1311   // if QH is connected, the specified bit is set,
   1312   // if TD is connected, the specified bit is cleared.
   1313   //
   1314   PtrQH->QueueHead.QHHorizontalQSelect = IsQH ? 1 : 0;
   1315 }
   1316 
   1317 /**
   1318   Set the horizontal validor bit in QH.
   1319 
   1320   @param  PtrQH      Place to store QH_STRUCT pointer.
   1321   @param  IsValid    Specify the horizontal linker is valid or not.
   1322 
   1323 **/
   1324 VOID
   1325 SetQHHorizontalValidorInvalid (
   1326   IN QH_STRUCT  *PtrQH,
   1327   IN BOOLEAN    IsValid
   1328   )
   1329 {
   1330   //
   1331   // Valid means the horizontal link pointer is valid,
   1332   // else, it's invalid.
   1333   //
   1334   PtrQH->QueueHead.QHHorizontalTerminate = IsValid ? 0 : 1;
   1335 }
   1336 
   1337 /**
   1338   Set the vertical link pointer in QH.
   1339 
   1340   @param  PtrQH       Place to store QH_STRUCT pointer.
   1341   @param  PtrNext     Place to the next QH_STRUCT.
   1342 
   1343 **/
   1344 VOID
   1345 SetQHVerticalLinkPtr (
   1346   IN QH_STRUCT  *PtrQH,
   1347   IN VOID       *PtrNext
   1348   )
   1349 {
   1350   //
   1351   // Since the QH_STRUCT is aligned on 16-byte boundaries,
   1352   // Only the highest 28bit of the address is valid
   1353   // (take 32bit address as an example).
   1354   //
   1355   PtrQH->QueueHead.QHVerticalPtr = (UINT32) (UINTN) PtrNext >> 4;
   1356 }
   1357 
   1358 /**
   1359   Set a QH or TD vertically to be connected with a specific QH.
   1360 
   1361   @param  PtrQH      Place to store QH_STRUCT pointer.
   1362   @param  IsQH       Specify QH or TD is connected.
   1363 
   1364 **/
   1365 VOID
   1366 SetQHVerticalQHorTDSelect (
   1367   IN QH_STRUCT  *PtrQH,
   1368   IN BOOLEAN    IsQH
   1369   )
   1370 {
   1371   //
   1372   // Set the specified bit if the Vertical Link Pointer pointing to a QH,
   1373   // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
   1374   //
   1375   PtrQH->QueueHead.QHVerticalQSelect = IsQH ? 1 : 0;
   1376 }
   1377 
   1378 /**
   1379   Set the vertical validor bit in QH.
   1380 
   1381   @param  PtrQH      Place to store QH_STRUCT pointer.
   1382   @param  IsValid    Specify the vertical linker is valid or not.
   1383 
   1384 **/
   1385 VOID
   1386 SetQHVerticalValidorInvalid (
   1387   IN QH_STRUCT  *PtrQH,
   1388   IN BOOLEAN    IsValid
   1389   )
   1390 {
   1391   //
   1392   // If TRUE, meaning the Vertical Link Pointer field is valid,
   1393   // else, the field is invalid.
   1394   //
   1395   PtrQH->QueueHead.QHVerticalTerminate = IsValid ? 0 : 1;
   1396 }
   1397 
   1398 /**
   1399   Get the vertical validor bit in QH.
   1400 
   1401   @param  PtrQH      Place to store QH_STRUCT pointer.
   1402 
   1403   @retval The vertical linker is valid or not.
   1404 
   1405 **/
   1406 BOOLEAN
   1407 GetQHHorizontalValidorInvalid (
   1408   IN QH_STRUCT  *PtrQH
   1409   )
   1410 {
   1411   //
   1412   // If TRUE, meaning the Horizontal Link Pointer field is valid,
   1413   // else, the field is invalid.
   1414   //
   1415   return (BOOLEAN) (!(PtrQH->QueueHead.QHHorizontalTerminate));
   1416 }
   1417 
   1418 /**
   1419   Allocate TD or QH Struct.
   1420 
   1421   @param  UhcDev                 The UHCI device.
   1422   @param  Size                   The size of allocation.
   1423   @param  PtrStruct              Place to store TD_STRUCT pointer.
   1424 
   1425   @return EFI_SUCCESS            Allocate successfully.
   1426   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
   1427 
   1428 **/
   1429 EFI_STATUS
   1430 AllocateTDorQHStruct (
   1431   IN  USB_UHC_DEV     *UhcDev,
   1432   IN  UINT32          Size,
   1433   OUT VOID            **PtrStruct
   1434   )
   1435 {
   1436   EFI_STATUS  Status;
   1437 
   1438   Status      = EFI_SUCCESS;
   1439   *PtrStruct  = NULL;
   1440 
   1441   Status = UhcAllocatePool (
   1442             UhcDev,
   1443             (UINT8 **) PtrStruct,
   1444             Size
   1445             );
   1446   if (EFI_ERROR (Status)) {
   1447     return Status;
   1448   }
   1449 
   1450   ZeroMem (*PtrStruct, Size);
   1451 
   1452   return Status;
   1453 }
   1454 
   1455 /**
   1456   Create a TD Struct.
   1457 
   1458   @param  UhcDev                 The UHCI device.
   1459   @param  PtrTD                  Place to store TD_STRUCT pointer.
   1460 
   1461   @return EFI_SUCCESS            Allocate successfully.
   1462   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
   1463 
   1464 **/
   1465 EFI_STATUS
   1466 CreateTD (
   1467   IN  USB_UHC_DEV     *UhcDev,
   1468   OUT TD_STRUCT       **PtrTD
   1469   )
   1470 {
   1471   EFI_STATUS  Status;
   1472   //
   1473   // create memory for TD_STRUCT, and align the memory.
   1474   //
   1475   Status = AllocateTDorQHStruct (UhcDev, sizeof(TD_STRUCT), (void **)PtrTD);
   1476   if (EFI_ERROR (Status)) {
   1477     return Status;
   1478   }
   1479 
   1480   //
   1481   // Make TD ready.
   1482   //
   1483   SetTDLinkPtrValidorInvalid (*PtrTD, FALSE);
   1484 
   1485   return EFI_SUCCESS;
   1486 }
   1487 
   1488 /**
   1489   Generate Setup Stage TD.
   1490 
   1491   @param  UhcDev       The UHCI device.
   1492   @param  DevAddr      Device address.
   1493   @param  Endpoint     Endpoint number.
   1494   @param  DeviceSpeed  Device Speed.
   1495   @param  DevRequest   Device reuquest.
   1496   @param  RequestLen   Request length.
   1497   @param  PtrTD        TD_STRUCT generated.
   1498 
   1499   @return EFI_SUCCESS            Generate setup stage TD successfully.
   1500   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
   1501 
   1502 **/
   1503 EFI_STATUS
   1504 GenSetupStageTD (
   1505   IN  USB_UHC_DEV     *UhcDev,
   1506   IN  UINT8           DevAddr,
   1507   IN  UINT8           Endpoint,
   1508   IN  UINT8           DeviceSpeed,
   1509   IN  UINT8           *DevRequest,
   1510   IN  UINT8           RequestLen,
   1511   OUT TD_STRUCT       **PtrTD
   1512   )
   1513 {
   1514   TD_STRUCT   *TdStruct;
   1515   EFI_STATUS  Status;
   1516 
   1517   Status = CreateTD (UhcDev, &TdStruct);
   1518   if (EFI_ERROR (Status)) {
   1519     return Status;
   1520   }
   1521 
   1522   SetTDLinkPtr (TdStruct, NULL);
   1523 
   1524   //
   1525   // Depth first fashion
   1526   //
   1527   SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
   1528 
   1529   //
   1530   // initialize as the last TD in the QH context,
   1531   // this field will be updated in the TD linkage process.
   1532   //
   1533   SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
   1534 
   1535   //
   1536   // Disable Short Packet Detection by default
   1537   //
   1538   EnableorDisableTDShortPacket (TdStruct, FALSE);
   1539 
   1540   //
   1541   // Max error counter is 3, retry 3 times when error encountered.
   1542   //
   1543   SetTDControlErrorCounter (TdStruct, 3);
   1544 
   1545   //
   1546   // set device speed attribute
   1547   // (TRUE - Slow Device; FALSE - Full Speed Device)
   1548   //
   1549   switch (DeviceSpeed) {
   1550   case USB_SLOW_SPEED_DEVICE:
   1551     SetTDLoworFullSpeedDevice (TdStruct, TRUE);
   1552     break;
   1553 
   1554   case USB_FULL_SPEED_DEVICE:
   1555     SetTDLoworFullSpeedDevice (TdStruct, FALSE);
   1556     break;
   1557   }
   1558   //
   1559   // Non isochronous transfer TD
   1560   //
   1561   SetTDControlIsochronousorNot (TdStruct, FALSE);
   1562 
   1563   //
   1564   // Interrupt On Complete bit be set to zero,
   1565   // Disable IOC interrupt.
   1566   //
   1567   SetorClearTDControlIOC (TdStruct, FALSE);
   1568 
   1569   //
   1570   // Set TD Active bit
   1571   //
   1572   SetTDStatusActiveorInactive (TdStruct, TRUE);
   1573 
   1574   SetTDTokenMaxLength (TdStruct, RequestLen);
   1575 
   1576   SetTDTokenDataToggle0 (TdStruct);
   1577 
   1578   SetTDTokenEndPoint (TdStruct, Endpoint);
   1579 
   1580   SetTDTokenDeviceAddress (TdStruct, DevAddr);
   1581 
   1582   SetTDTokenPacketID (TdStruct, SETUP_PACKET_ID);
   1583 
   1584   TdStruct->PtrTDBuffer      = (UINT8 *) DevRequest;
   1585   TdStruct->TDBufferLength = RequestLen;
   1586   SetTDDataBuffer (TdStruct);
   1587 
   1588   *PtrTD = TdStruct;
   1589 
   1590   return EFI_SUCCESS;
   1591 }
   1592 
   1593 /**
   1594   Generate Data Stage TD.
   1595 
   1596   @param  UhcDev       The UHCI device.
   1597   @param  DevAddr      Device address.
   1598   @param  Endpoint     Endpoint number.
   1599   @param  PtrData      Data buffer.
   1600   @param  Len          Data length.
   1601   @param  PktID        PacketID.
   1602   @param  Toggle       Data toggle value.
   1603   @param  DeviceSpeed  Device Speed.
   1604   @param  PtrTD        TD_STRUCT generated.
   1605 
   1606   @return EFI_SUCCESS            Generate data stage TD successfully.
   1607   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
   1608 
   1609 **/
   1610 EFI_STATUS
   1611 GenDataTD (
   1612   IN  USB_UHC_DEV     *UhcDev,
   1613   IN  UINT8           DevAddr,
   1614   IN  UINT8           Endpoint,
   1615   IN  UINT8           *PtrData,
   1616   IN  UINT8           Len,
   1617   IN  UINT8           PktID,
   1618   IN  UINT8           Toggle,
   1619   IN  UINT8           DeviceSpeed,
   1620   OUT TD_STRUCT       **PtrTD
   1621   )
   1622 {
   1623   TD_STRUCT   *TdStruct;
   1624   EFI_STATUS  Status;
   1625 
   1626   Status = CreateTD (UhcDev, &TdStruct);
   1627   if (EFI_ERROR (Status)) {
   1628     return Status;
   1629   }
   1630 
   1631   SetTDLinkPtr (TdStruct, NULL);
   1632 
   1633   //
   1634   // Depth first fashion
   1635   //
   1636   SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
   1637 
   1638   //
   1639   // Link pointer pointing to TD struct
   1640   //
   1641   SetTDLinkPtrQHorTDSelect (TdStruct, FALSE);
   1642 
   1643   //
   1644   // initialize as the last TD in the QH context,
   1645   // this field will be updated in the TD linkage process.
   1646   //
   1647   SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
   1648 
   1649   //
   1650   // Disable short packet detect
   1651   //
   1652   EnableorDisableTDShortPacket (TdStruct, FALSE);
   1653   //
   1654   // Max error counter is 3
   1655   //
   1656   SetTDControlErrorCounter (TdStruct, 3);
   1657 
   1658   //
   1659   // set device speed attribute
   1660   // (TRUE - Slow Device; FALSE - Full Speed Device)
   1661   //
   1662   switch (DeviceSpeed) {
   1663   case USB_SLOW_SPEED_DEVICE:
   1664     SetTDLoworFullSpeedDevice (TdStruct, TRUE);
   1665     break;
   1666 
   1667   case USB_FULL_SPEED_DEVICE:
   1668     SetTDLoworFullSpeedDevice (TdStruct, FALSE);
   1669     break;
   1670   }
   1671   //
   1672   // Non isochronous transfer TD
   1673   //
   1674   SetTDControlIsochronousorNot (TdStruct, FALSE);
   1675 
   1676   //
   1677   // Disable Interrupt On Complete
   1678   // Disable IOC interrupt.
   1679   //
   1680   SetorClearTDControlIOC (TdStruct, FALSE);
   1681 
   1682   //
   1683   // Set Active bit
   1684   //
   1685   SetTDStatusActiveorInactive (TdStruct, TRUE);
   1686 
   1687   SetTDTokenMaxLength (TdStruct, Len);
   1688 
   1689   if (Toggle != 0) {
   1690     SetTDTokenDataToggle1 (TdStruct);
   1691   } else {
   1692     SetTDTokenDataToggle0 (TdStruct);
   1693   }
   1694 
   1695   SetTDTokenEndPoint (TdStruct, Endpoint);
   1696 
   1697   SetTDTokenDeviceAddress (TdStruct, DevAddr);
   1698 
   1699   SetTDTokenPacketID (TdStruct, PktID);
   1700 
   1701   TdStruct->PtrTDBuffer      = (UINT8 *) PtrData;
   1702   TdStruct->TDBufferLength = Len;
   1703   SetTDDataBuffer (TdStruct);
   1704 
   1705   *PtrTD = TdStruct;
   1706 
   1707   return EFI_SUCCESS;
   1708 }
   1709 
   1710 /**
   1711   Generate Status Stage TD.
   1712 
   1713   @param  UhcDev       The UHCI device.
   1714   @param  DevAddr      Device address.
   1715   @param  Endpoint     Endpoint number.
   1716   @param  PktID        PacketID.
   1717   @param  DeviceSpeed  Device Speed.
   1718   @param  PtrTD        TD_STRUCT generated.
   1719 
   1720   @return EFI_SUCCESS            Generate status stage TD successfully.
   1721   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
   1722 
   1723 **/
   1724 EFI_STATUS
   1725 CreateStatusTD (
   1726   IN  USB_UHC_DEV     *UhcDev,
   1727   IN  UINT8           DevAddr,
   1728   IN  UINT8           Endpoint,
   1729   IN  UINT8           PktID,
   1730   IN  UINT8           DeviceSpeed,
   1731   OUT TD_STRUCT       **PtrTD
   1732   )
   1733 {
   1734   TD_STRUCT   *PtrTDStruct;
   1735   EFI_STATUS  Status;
   1736 
   1737   Status = CreateTD (UhcDev, &PtrTDStruct);
   1738   if (EFI_ERROR (Status)) {
   1739     return Status;
   1740   }
   1741 
   1742   SetTDLinkPtr (PtrTDStruct, NULL);
   1743 
   1744   //
   1745   // Depth first fashion
   1746   //
   1747   SetTDLinkPtrDepthorBreadth (PtrTDStruct, TRUE);
   1748 
   1749   //
   1750   // initialize as the last TD in the QH context,
   1751   // this field will be updated in the TD linkage process.
   1752   //
   1753   SetTDLinkPtrValidorInvalid (PtrTDStruct, FALSE);
   1754 
   1755   //
   1756   // Disable short packet detect
   1757   //
   1758   EnableorDisableTDShortPacket (PtrTDStruct, FALSE);
   1759 
   1760   //
   1761   // Max error counter is 3
   1762   //
   1763   SetTDControlErrorCounter (PtrTDStruct, 3);
   1764 
   1765   //
   1766   // set device speed attribute
   1767   // (TRUE - Slow Device; FALSE - Full Speed Device)
   1768   //
   1769   switch (DeviceSpeed) {
   1770   case USB_SLOW_SPEED_DEVICE:
   1771     SetTDLoworFullSpeedDevice (PtrTDStruct, TRUE);
   1772     break;
   1773 
   1774   case USB_FULL_SPEED_DEVICE:
   1775     SetTDLoworFullSpeedDevice (PtrTDStruct, FALSE);
   1776     break;
   1777   }
   1778   //
   1779   // Non isochronous transfer TD
   1780   //
   1781   SetTDControlIsochronousorNot (PtrTDStruct, FALSE);
   1782 
   1783   //
   1784   // Disable Interrupt On Complete
   1785   // Disable IOC interrupt.
   1786   //
   1787   SetorClearTDControlIOC (PtrTDStruct, FALSE);
   1788 
   1789   //
   1790   // Set TD Active bit
   1791   //
   1792   SetTDStatusActiveorInactive (PtrTDStruct, TRUE);
   1793 
   1794   SetTDTokenMaxLength (PtrTDStruct, 0);
   1795 
   1796   SetTDTokenDataToggle1 (PtrTDStruct);
   1797 
   1798   SetTDTokenEndPoint (PtrTDStruct, Endpoint);
   1799 
   1800   SetTDTokenDeviceAddress (PtrTDStruct, DevAddr);
   1801 
   1802   SetTDTokenPacketID (PtrTDStruct, PktID);
   1803 
   1804   PtrTDStruct->PtrTDBuffer      = NULL;
   1805   PtrTDStruct->TDBufferLength = 0;
   1806   SetTDDataBuffer (PtrTDStruct);
   1807 
   1808   *PtrTD = PtrTDStruct;
   1809 
   1810   return EFI_SUCCESS;
   1811 }
   1812 
   1813 /**
   1814   Set the link pointer validor bit in TD.
   1815 
   1816   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
   1817   @param  IsValid      Specify the linker pointer is valid or not.
   1818 
   1819 **/
   1820 VOID
   1821 SetTDLinkPtrValidorInvalid (
   1822   IN  TD_STRUCT *PtrTDStruct,
   1823   IN  BOOLEAN   IsValid
   1824   )
   1825 {
   1826   //
   1827   // Valid means the link pointer is valid,
   1828   // else, it's invalid.
   1829   //
   1830   PtrTDStruct->TDData.TDLinkPtrTerminate = (IsValid ? 0 : 1);
   1831 }
   1832 
   1833 /**
   1834   Set the Link Pointer pointing to a QH or TD.
   1835 
   1836   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   1837   @param  IsQH          Specify QH or TD is connected.
   1838 
   1839 **/
   1840 VOID
   1841 SetTDLinkPtrQHorTDSelect (
   1842   IN  TD_STRUCT *PtrTDStruct,
   1843   IN  BOOLEAN   IsQH
   1844   )
   1845 {
   1846   //
   1847   // Indicate whether the Link Pointer pointing to a QH or TD
   1848   //
   1849   PtrTDStruct->TDData.TDLinkPtrQSelect = (IsQH ? 1 : 0);
   1850 }
   1851 
   1852 /**
   1853   Set the traverse is depth-first or breadth-first.
   1854 
   1855   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   1856   @param  IsDepth       Specify the traverse is depth-first or breadth-first.
   1857 
   1858 **/
   1859 VOID
   1860 SetTDLinkPtrDepthorBreadth (
   1861   IN  TD_STRUCT *PtrTDStruct,
   1862   IN  BOOLEAN   IsDepth
   1863   )
   1864 {
   1865   //
   1866   // If TRUE, indicating the host controller should process in depth first fashion,
   1867   // else, the host controller should process in breadth first fashion
   1868   //
   1869   PtrTDStruct->TDData.TDLinkPtrDepthSelect = (IsDepth ? 1 : 0);
   1870 }
   1871 
   1872 /**
   1873   Set TD Link Pointer in TD.
   1874 
   1875   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
   1876   @param  PtrNext      Place to the next TD_STRUCT.
   1877 
   1878 **/
   1879 VOID
   1880 SetTDLinkPtr (
   1881   IN  TD_STRUCT *PtrTDStruct,
   1882   IN  VOID      *PtrNext
   1883   )
   1884 {
   1885   //
   1886   // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
   1887   // only the highest 28 bits are valid. (if take 32bit address as an example)
   1888   //
   1889   PtrTDStruct->TDData.TDLinkPtr = (UINT32) (UINTN) PtrNext >> 4;
   1890 }
   1891 
   1892 /**
   1893   Get TD Link Pointer.
   1894 
   1895   @param  PtrTDStruct     Place to store TD_STRUCT pointer.
   1896 
   1897   @retval Get TD Link Pointer in TD.
   1898 
   1899 **/
   1900 VOID *
   1901 GetTDLinkPtr (
   1902   IN  TD_STRUCT *PtrTDStruct
   1903   )
   1904 {
   1905   //
   1906   // Get TD Link Pointer. Restore it back to 32bit
   1907   // (if take 32bit address as an example)
   1908   //
   1909   return (VOID *) (UINTN) ((PtrTDStruct->TDData.TDLinkPtr) << 4);
   1910 }
   1911 
   1912 /**
   1913   Get the information about whether the Link Pointer field pointing to
   1914   a QH or a TD.
   1915 
   1916   @param  PtrTDStruct     Place to store TD_STRUCT pointer.
   1917 
   1918   @retval whether the Link Pointer field pointing to a QH or a TD.
   1919 
   1920 **/
   1921 BOOLEAN
   1922 IsTDLinkPtrQHOrTD (
   1923   IN  TD_STRUCT *PtrTDStruct
   1924   )
   1925 {
   1926   //
   1927   // Get the information about whether the Link Pointer field pointing to
   1928   // a QH or a TD.
   1929   //
   1930   return (BOOLEAN) (PtrTDStruct->TDData.TDLinkPtrQSelect);
   1931 }
   1932 
   1933 /**
   1934   Enable/Disable short packet detection mechanism.
   1935 
   1936   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
   1937   @param  IsEnable     Enable or disable short packet detection mechanism.
   1938 
   1939 **/
   1940 VOID
   1941 EnableorDisableTDShortPacket (
   1942   IN  TD_STRUCT *PtrTDStruct,
   1943   IN  BOOLEAN   IsEnable
   1944   )
   1945 {
   1946   //
   1947   // TRUE means enable short packet detection mechanism.
   1948   //
   1949   PtrTDStruct->TDData.TDStatusSPD = (IsEnable ? 1 : 0);
   1950 }
   1951 
   1952 /**
   1953   Set the max error counter in TD.
   1954 
   1955   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
   1956   @param  MaxErrors    The number of allowable error.
   1957 
   1958 **/
   1959 VOID
   1960 SetTDControlErrorCounter (
   1961   IN  TD_STRUCT *PtrTDStruct,
   1962   IN  UINT8     MaxErrors
   1963   )
   1964 {
   1965   //
   1966   // valid value of MaxErrors is 0,1,2,3
   1967   //
   1968   if (MaxErrors > 3) {
   1969     MaxErrors = 3;
   1970   }
   1971 
   1972   PtrTDStruct->TDData.TDStatusErr = MaxErrors;
   1973 }
   1974 
   1975 /**
   1976   Set the TD is targeting a low-speed device or not.
   1977 
   1978   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
   1979   @param  IsLowSpeedDevice  Whether The device is low-speed.
   1980 
   1981 **/
   1982 VOID
   1983 SetTDLoworFullSpeedDevice (
   1984   IN  TD_STRUCT *PtrTDStruct,
   1985   IN  BOOLEAN   IsLowSpeedDevice
   1986   )
   1987 {
   1988   //
   1989   // TRUE means the TD is targeting at a Low-speed device
   1990   //
   1991   PtrTDStruct->TDData.TDStatusLS = (IsLowSpeedDevice ? 1 : 0);
   1992 }
   1993 
   1994 /**
   1995   Set the TD is isochronous transfer type or not.
   1996 
   1997   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
   1998   @param  IsIsochronous     Whether the transaction isochronous transfer type.
   1999 
   2000 **/
   2001 VOID
   2002 SetTDControlIsochronousorNot (
   2003   IN  TD_STRUCT   *PtrTDStruct,
   2004   IN  BOOLEAN     IsIsochronous
   2005   )
   2006 {
   2007   //
   2008   // TRUE means the TD belongs to Isochronous transfer type.
   2009   //
   2010   PtrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);
   2011 }
   2012 
   2013 /**
   2014   Set if UCHI should issue an interrupt on completion of the frame
   2015   in which this TD is executed
   2016 
   2017   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
   2018   @param  IsSet             Whether HC should issue an interrupt on completion.
   2019 
   2020 **/
   2021 VOID
   2022 SetorClearTDControlIOC (
   2023   IN  TD_STRUCT *PtrTDStruct,
   2024   IN  BOOLEAN   IsSet
   2025   )
   2026 {
   2027   //
   2028   // If this bit is set, it indicates that the host controller should issue
   2029   // an interrupt on completion of the frame in which this TD is executed.
   2030   //
   2031   PtrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;
   2032 }
   2033 
   2034 /**
   2035   Set if the TD is active and can be executed.
   2036 
   2037   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
   2038   @param  IsActive          Whether the TD is active and can be executed.
   2039 
   2040 **/
   2041 VOID
   2042 SetTDStatusActiveorInactive (
   2043   IN  TD_STRUCT *PtrTDStruct,
   2044   IN  BOOLEAN   IsActive
   2045   )
   2046 {
   2047   //
   2048   // If this bit is set, it indicates that the TD is active and can be
   2049   // executed.
   2050   //
   2051   if (IsActive) {
   2052     PtrTDStruct->TDData.TDStatus |= 0x80;
   2053   } else {
   2054     PtrTDStruct->TDData.TDStatus &= 0x7F;
   2055   }
   2056 }
   2057 
   2058 /**
   2059   Specifies the maximum number of data bytes allowed for the transfer.
   2060 
   2061   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2062   @param  MaxLen        The maximum number of data bytes allowed.
   2063 
   2064   @retval The allowed maximum number of data.
   2065 **/
   2066 UINT16
   2067 SetTDTokenMaxLength (
   2068   IN  TD_STRUCT *PtrTDStruct,
   2069   IN  UINT16    MaxLen
   2070   )
   2071 {
   2072   //
   2073   // Specifies the maximum number of data bytes allowed for the transfer.
   2074   // the legal value extent is 0 ~ 0x500.
   2075   //
   2076   if (MaxLen > 0x500) {
   2077     MaxLen = 0x500;
   2078   }
   2079 
   2080   PtrTDStruct->TDData.TDTokenMaxLen = MaxLen - 1;
   2081 
   2082   return MaxLen;
   2083 }
   2084 
   2085 /**
   2086   Set the data toggle bit to DATA1.
   2087 
   2088   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2089 
   2090 **/
   2091 VOID
   2092 SetTDTokenDataToggle1 (
   2093   IN  TD_STRUCT *PtrTDStruct
   2094   )
   2095 {
   2096   //
   2097   // Set the data toggle bit to DATA1
   2098   //
   2099   PtrTDStruct->TDData.TDTokenDataToggle = 1;
   2100 }
   2101 
   2102 /**
   2103   Set the data toggle bit to DATA0.
   2104 
   2105   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2106 
   2107 **/
   2108 VOID
   2109 SetTDTokenDataToggle0 (
   2110   IN  TD_STRUCT *PtrTDStruct
   2111   )
   2112 {
   2113   //
   2114   // Set the data toggle bit to DATA0
   2115   //
   2116   PtrTDStruct->TDData.TDTokenDataToggle = 0;
   2117 }
   2118 
   2119 /**
   2120   Set EndPoint Number the TD is targeting at.
   2121 
   2122   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2123   @param  EndPoint      The Endport number of the target.
   2124 
   2125 **/
   2126 VOID
   2127 SetTDTokenEndPoint (
   2128   IN  TD_STRUCT *PtrTDStruct,
   2129   IN  UINTN     EndPoint
   2130   )
   2131 {
   2132   //
   2133   // Set EndPoint Number the TD is targeting at.
   2134   //
   2135   PtrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;
   2136 }
   2137 
   2138 /**
   2139   Set Device Address the TD is targeting at.
   2140 
   2141   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2142   @param  DevAddr       The Device Address of the target.
   2143 
   2144 **/
   2145 VOID
   2146 SetTDTokenDeviceAddress (
   2147   IN  TD_STRUCT *PtrTDStruct,
   2148   IN  UINTN     DevAddr
   2149   )
   2150 {
   2151   //
   2152   // Set Device Address the TD is targeting at.
   2153   //
   2154   PtrTDStruct->TDData.TDTokenDevAddr = (UINT8) DevAddr;
   2155 }
   2156 
   2157 /**
   2158   Set Packet Identification the TD is targeting at.
   2159 
   2160   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2161   @param  PacketID      The Packet Identification of the target.
   2162 
   2163 **/
   2164 VOID
   2165 SetTDTokenPacketID (
   2166   IN  TD_STRUCT *PtrTDStruct,
   2167   IN  UINT8     PacketID
   2168   )
   2169 {
   2170   //
   2171   // Set the Packet Identification to be used for this transaction.
   2172   //
   2173   PtrTDStruct->TDData.TDTokenPID = PacketID;
   2174 }
   2175 
   2176 /**
   2177   Set the beginning address of the data buffer that will be used
   2178   during the transaction.
   2179 
   2180   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2181 
   2182 **/
   2183 VOID
   2184 SetTDDataBuffer (
   2185   IN  TD_STRUCT *PtrTDStruct
   2186   )
   2187 {
   2188   //
   2189   // Set the beginning address of the data buffer that will be used
   2190   // during the transaction.
   2191   //
   2192   PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);
   2193 }
   2194 
   2195 /**
   2196   Detect whether the TD is active.
   2197 
   2198   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2199 
   2200   @retval The TD is active or not.
   2201 
   2202 **/
   2203 BOOLEAN
   2204 IsTDStatusActive (
   2205   IN  TD_STRUCT *PtrTDStruct
   2206   )
   2207 {
   2208   UINT8 TDStatus;
   2209 
   2210   //
   2211   // Detect whether the TD is active.
   2212   //
   2213   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
   2214   return (BOOLEAN) (TDStatus & 0x80);
   2215 }
   2216 
   2217 /**
   2218   Detect whether the TD is stalled.
   2219 
   2220   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2221 
   2222   @retval The TD is stalled or not.
   2223 
   2224 **/
   2225 BOOLEAN
   2226 IsTDStatusStalled (
   2227   IN  TD_STRUCT *PtrTDStruct
   2228   )
   2229 {
   2230   UINT8 TDStatus;
   2231 
   2232   //
   2233   // Detect whether the device/endpoint addressed by this TD is stalled.
   2234   //
   2235   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
   2236   return (BOOLEAN) (TDStatus & 0x40);
   2237 }
   2238 
   2239 /**
   2240   Detect whether Data Buffer Error is happened.
   2241 
   2242   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2243 
   2244   @retval The Data Buffer Error is happened or not.
   2245 
   2246 **/
   2247 BOOLEAN
   2248 IsTDStatusBufferError (
   2249   IN  TD_STRUCT *PtrTDStruct
   2250   )
   2251 {
   2252   UINT8 TDStatus;
   2253 
   2254   //
   2255   // Detect whether Data Buffer Error is happened.
   2256   //
   2257   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
   2258   return (BOOLEAN) (TDStatus & 0x20);
   2259 }
   2260 
   2261 /**
   2262   Detect whether Babble Error is happened.
   2263 
   2264   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2265 
   2266   @retval The Babble Error is happened or not.
   2267 
   2268 **/
   2269 BOOLEAN
   2270 IsTDStatusBabbleError (
   2271   IN  TD_STRUCT *PtrTDStruct
   2272   )
   2273 {
   2274   UINT8 TDStatus;
   2275 
   2276   //
   2277   // Detect whether Babble Error is happened.
   2278   //
   2279   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
   2280   return (BOOLEAN) (TDStatus & 0x10);
   2281 }
   2282 
   2283 /**
   2284   Detect whether NAK is received.
   2285 
   2286   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2287 
   2288   @retval The NAK is received or not.
   2289 
   2290 **/
   2291 BOOLEAN
   2292 IsTDStatusNAKReceived (
   2293   IN  TD_STRUCT *PtrTDStruct
   2294   )
   2295 {
   2296   UINT8 TDStatus;
   2297 
   2298   //
   2299   // Detect whether NAK is received.
   2300   //
   2301   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
   2302   return (BOOLEAN) (TDStatus & 0x08);
   2303 }
   2304 
   2305 /**
   2306   Detect whether CRC/Time Out Error is encountered.
   2307 
   2308   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2309 
   2310   @retval The CRC/Time Out Error is encountered or not.
   2311 
   2312 **/
   2313 BOOLEAN
   2314 IsTDStatusCRCTimeOutError (
   2315   IN  TD_STRUCT *PtrTDStruct
   2316   )
   2317 {
   2318   UINT8 TDStatus;
   2319 
   2320   //
   2321   // Detect whether CRC/Time Out Error is encountered.
   2322   //
   2323   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
   2324   return (BOOLEAN) (TDStatus & 0x04);
   2325 }
   2326 
   2327 /**
   2328   Detect whether Bitstuff Error is received.
   2329 
   2330   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2331 
   2332   @retval The Bitstuff Error is received or not.
   2333 
   2334 **/
   2335 BOOLEAN
   2336 IsTDStatusBitStuffError (
   2337   IN  TD_STRUCT *PtrTDStruct
   2338   )
   2339 {
   2340   UINT8 TDStatus;
   2341 
   2342   //
   2343   // Detect whether Bitstuff Error is received.
   2344   //
   2345   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
   2346   return (BOOLEAN) (TDStatus & 0x02);
   2347 }
   2348 
   2349 /**
   2350   Retrieve the actual number of bytes that were tansferred.
   2351 
   2352   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2353 
   2354   @retval The actual number of bytes that were tansferred.
   2355 
   2356 **/
   2357 UINT16
   2358 GetTDStatusActualLength (
   2359   IN  TD_STRUCT *PtrTDStruct
   2360   )
   2361 {
   2362   //
   2363   // Retrieve the actual number of bytes that were tansferred.
   2364   // the value is encoded as n-1. so return the decoded value.
   2365   //
   2366   return (UINT16) ((PtrTDStruct->TDData.TDStatusActualLength) + 1);
   2367 }
   2368 
   2369 /**
   2370   Retrieve the information of whether the Link Pointer field is valid or not.
   2371 
   2372   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
   2373 
   2374   @retval The linker pointer field is valid or not.
   2375 
   2376 **/
   2377 BOOLEAN
   2378 GetTDLinkPtrValidorInvalid (
   2379   IN  TD_STRUCT *PtrTDStruct
   2380   )
   2381 {
   2382   //
   2383   // Retrieve the information of whether the Link Pointer field
   2384   // is valid or not.
   2385   //
   2386   if ((PtrTDStruct->TDData.TDLinkPtrTerminate & BIT0) != 0) {
   2387     return FALSE;
   2388   } else {
   2389     return TRUE;
   2390   }
   2391 
   2392 }
   2393 
   2394 /**
   2395   Count TD Number from PtrFirstTD.
   2396 
   2397   @param  PtrFirstTD   Place to store TD_STRUCT pointer.
   2398 
   2399   @retval The queued TDs number.
   2400 
   2401 **/
   2402 UINTN
   2403 CountTDsNumber (
   2404   IN  TD_STRUCT *PtrFirstTD
   2405   )
   2406 {
   2407   UINTN     Number;
   2408   TD_STRUCT *Ptr;
   2409 
   2410   //
   2411   // Count the queued TDs number.
   2412   //
   2413   Number  = 0;
   2414   Ptr     = PtrFirstTD;
   2415   while (Ptr != 0) {
   2416     Ptr = (TD_STRUCT *) Ptr->PtrNextTD;
   2417     Number++;
   2418   }
   2419 
   2420   return Number;
   2421 }
   2422 
   2423 /**
   2424   Link TD To QH.
   2425 
   2426   @param  PtrQH   Place to store QH_STRUCT pointer.
   2427   @param  PtrTD   Place to store TD_STRUCT pointer.
   2428 
   2429 **/
   2430 VOID
   2431 LinkTDToQH (
   2432   IN  QH_STRUCT *PtrQH,
   2433   IN  TD_STRUCT *PtrTD
   2434   )
   2435 {
   2436   if (PtrQH == NULL || PtrTD == NULL) {
   2437     return ;
   2438   }
   2439   //
   2440   //  Validate QH Vertical Ptr field
   2441   //
   2442   SetQHVerticalValidorInvalid (PtrQH, TRUE);
   2443 
   2444   //
   2445   //  Vertical Ptr pointing to TD structure
   2446   //
   2447   SetQHVerticalQHorTDSelect (PtrQH, FALSE);
   2448 
   2449   SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);
   2450 
   2451   PtrQH->PtrDown = (VOID *) PtrTD;
   2452 }
   2453 
   2454 /**
   2455   Link TD To TD.
   2456 
   2457   @param  PtrPreTD  Place to store TD_STRUCT pointer.
   2458   @param  PtrTD     Place to store TD_STRUCT pointer.
   2459 
   2460 **/
   2461 VOID
   2462 LinkTDToTD (
   2463   IN  TD_STRUCT *PtrPreTD,
   2464   IN  TD_STRUCT *PtrTD
   2465   )
   2466 {
   2467   if (PtrPreTD == NULL || PtrTD == NULL) {
   2468     return ;
   2469   }
   2470   //
   2471   // Depth first fashion
   2472   //
   2473   SetTDLinkPtrDepthorBreadth (PtrPreTD, TRUE);
   2474 
   2475   //
   2476   // Link pointer pointing to TD struct
   2477   //
   2478   SetTDLinkPtrQHorTDSelect (PtrPreTD, FALSE);
   2479 
   2480   //
   2481   // Validate the link pointer valid bit
   2482   //
   2483   SetTDLinkPtrValidorInvalid (PtrPreTD, TRUE);
   2484 
   2485   SetTDLinkPtr (PtrPreTD, PtrTD);
   2486 
   2487   PtrPreTD->PtrNextTD = (VOID *) PtrTD;
   2488 
   2489   PtrTD->PtrNextTD    = NULL;
   2490 }
   2491 
   2492 /**
   2493   Execute Control Transfer.
   2494 
   2495   @param  UhcDev            The UCHI device.
   2496   @param  PtrTD             A pointer to TD_STRUCT data.
   2497   @param  ActualLen         Actual transfer Length.
   2498   @param  TimeOut           TimeOut value.
   2499   @param  TransferResult    Transfer Result.
   2500 
   2501   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
   2502   @return EFI_TIMEOUT       The transfer failed due to time out.
   2503   @return EFI_SUCCESS       The transfer finished OK.
   2504 
   2505 **/
   2506 EFI_STATUS
   2507 ExecuteControlTransfer (
   2508   IN  USB_UHC_DEV *UhcDev,
   2509   IN  TD_STRUCT   *PtrTD,
   2510   OUT UINTN       *ActualLen,
   2511   IN  UINTN       TimeOut,
   2512   OUT UINT32      *TransferResult
   2513   )
   2514 {
   2515   UINTN   ErrTDPos;
   2516   UINTN   Delay;
   2517   BOOLEAN InfiniteLoop;
   2518 
   2519   ErrTDPos          = 0;
   2520   *TransferResult   = EFI_USB_NOERROR;
   2521   *ActualLen        = 0;
   2522   InfiniteLoop      = FALSE;
   2523 
   2524   Delay = TimeOut * STALL_1_MILLI_SECOND;
   2525   //
   2526   // If Timeout is 0, then the caller must wait for the function to be completed
   2527   // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
   2528   //
   2529   if (TimeOut == 0) {
   2530     InfiniteLoop = TRUE;
   2531   }
   2532 
   2533   do {
   2534 
   2535     CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
   2536 
   2537     //
   2538     // TD is inactive, means the control transfer is end.
   2539     //
   2540     if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
   2541       break;
   2542     }
   2543     MicroSecondDelay (STALL_1_MICRO_SECOND);
   2544     Delay--;
   2545 
   2546   } while (InfiniteLoop || (Delay != 0));
   2547 
   2548   if (*TransferResult != EFI_USB_NOERROR) {
   2549     return EFI_DEVICE_ERROR;
   2550   }
   2551 
   2552   return EFI_SUCCESS;
   2553 }
   2554 
   2555 /**
   2556   Execute Bulk Transfer.
   2557 
   2558   @param  UhcDev            The UCHI device.
   2559   @param  PtrTD             A pointer to TD_STRUCT data.
   2560   @param  ActualLen         Actual transfer Length.
   2561   @param  DataToggle        DataToggle value.
   2562   @param  TimeOut           TimeOut value.
   2563   @param  TransferResult    Transfer Result.
   2564 
   2565   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
   2566   @return EFI_TIMEOUT       The transfer failed due to time out.
   2567   @return EFI_SUCCESS       The transfer finished OK.
   2568 
   2569 **/
   2570 EFI_STATUS
   2571 ExecBulkTransfer (
   2572   IN     USB_UHC_DEV *UhcDev,
   2573   IN     TD_STRUCT   *PtrTD,
   2574   IN OUT UINTN       *ActualLen,
   2575   IN     UINT8       *DataToggle,
   2576   IN     UINTN       TimeOut,
   2577   OUT    UINT32      *TransferResult
   2578   )
   2579 {
   2580   UINTN   ErrTDPos;
   2581   UINTN   ScrollNum;
   2582   UINTN   Delay;
   2583   BOOLEAN InfiniteLoop;
   2584 
   2585   ErrTDPos          = 0;
   2586   *TransferResult   = EFI_USB_NOERROR;
   2587   *ActualLen        = 0;
   2588   InfiniteLoop      = FALSE;
   2589 
   2590   Delay = TimeOut * STALL_1_MILLI_SECOND;
   2591   //
   2592   // If Timeout is 0, then the caller must wait for the function to be completed
   2593   // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
   2594   //
   2595   if (TimeOut == 0) {
   2596     InfiniteLoop = TRUE;
   2597   }
   2598 
   2599   do {
   2600 
   2601     CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
   2602     //
   2603     // TD is inactive, thus meaning bulk transfer's end.
   2604     //
   2605     if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
   2606       break;
   2607     }
   2608     MicroSecondDelay (STALL_1_MICRO_SECOND);
   2609     Delay--;
   2610 
   2611   } while (InfiniteLoop || (Delay != 0));
   2612 
   2613   //
   2614   // has error
   2615   //
   2616   if (*TransferResult != EFI_USB_NOERROR) {
   2617     //
   2618     // scroll the Data Toggle back to the last success TD
   2619     //
   2620     ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
   2621     if ((ScrollNum % 2) != 0) {
   2622       *DataToggle ^= 1;
   2623     }
   2624 
   2625   //
   2626   // If error, wait 100ms to retry by upper layer
   2627   //
   2628     MicroSecondDelay (100 * 1000);
   2629     return EFI_DEVICE_ERROR;
   2630   }
   2631 
   2632   return EFI_SUCCESS;
   2633 }
   2634 
   2635 /**
   2636   Delete Queued TDs.
   2637 
   2638   @param  UhcDev       The UCHI device.
   2639   @param  PtrFirstTD   Place to store TD_STRUCT pointer.
   2640 
   2641 **/
   2642 VOID
   2643 DeleteQueuedTDs (
   2644   IN USB_UHC_DEV     *UhcDev,
   2645   IN TD_STRUCT       *PtrFirstTD
   2646   )
   2647 {
   2648   TD_STRUCT *Tptr1;
   2649 
   2650   TD_STRUCT *Tptr2;
   2651 
   2652   Tptr1 = PtrFirstTD;
   2653   //
   2654   // Delete all the TDs in a queue.
   2655   //
   2656   while (Tptr1 != NULL) {
   2657 
   2658     Tptr2 = Tptr1;
   2659 
   2660     if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
   2661       Tptr1 = NULL;
   2662     } else {
   2663       //
   2664       // has more than one TD in the queue.
   2665       //
   2666       Tptr1 = GetTDLinkPtr (Tptr2);
   2667     }
   2668 
   2669     UhcFreePool (UhcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));
   2670   }
   2671 
   2672   return ;
   2673 }
   2674 
   2675 /**
   2676   Check TDs Results.
   2677 
   2678   @param  PtrTD               A pointer to TD_STRUCT data.
   2679   @param  Result              The result to return.
   2680   @param  ErrTDPos            The Error TD position.
   2681   @param  ActualTransferSize  Actual transfer size.
   2682 
   2683   @retval The TD is executed successfully or not.
   2684 
   2685 **/
   2686 BOOLEAN
   2687 CheckTDsResults (
   2688   IN  TD_STRUCT               *PtrTD,
   2689   OUT UINT32                  *Result,
   2690   OUT UINTN                   *ErrTDPos,
   2691   OUT UINTN                   *ActualTransferSize
   2692   )
   2693 {
   2694   UINTN Len;
   2695 
   2696   *Result   = EFI_USB_NOERROR;
   2697   *ErrTDPos = 0;
   2698 
   2699   //
   2700   // Init to zero.
   2701   //
   2702   *ActualTransferSize = 0;
   2703 
   2704   while (PtrTD != NULL) {
   2705 
   2706     if (IsTDStatusActive (PtrTD)) {
   2707       *Result |= EFI_USB_ERR_NOTEXECUTE;
   2708     }
   2709 
   2710     if (IsTDStatusStalled (PtrTD)) {
   2711       *Result |= EFI_USB_ERR_STALL;
   2712     }
   2713 
   2714     if (IsTDStatusBufferError (PtrTD)) {
   2715       *Result |= EFI_USB_ERR_BUFFER;
   2716     }
   2717 
   2718     if (IsTDStatusBabbleError (PtrTD)) {
   2719       *Result |= EFI_USB_ERR_BABBLE;
   2720     }
   2721 
   2722     if (IsTDStatusNAKReceived (PtrTD)) {
   2723       *Result |= EFI_USB_ERR_NAK;
   2724     }
   2725 
   2726     if (IsTDStatusCRCTimeOutError (PtrTD)) {
   2727       *Result |= EFI_USB_ERR_TIMEOUT;
   2728     }
   2729 
   2730     if (IsTDStatusBitStuffError (PtrTD)) {
   2731       *Result |= EFI_USB_ERR_BITSTUFF;
   2732     }
   2733     //
   2734     // Accumulate actual transferred data length in each TD.
   2735     //
   2736     Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
   2737     *ActualTransferSize += Len;
   2738 
   2739     //
   2740     // if any error encountered, stop processing the left TDs.
   2741     //
   2742     if ((*Result) != 0) {
   2743       return FALSE;
   2744     }
   2745 
   2746     PtrTD = (TD_STRUCT *) (PtrTD->PtrNextTD);
   2747     //
   2748     // Record the first Error TD's position in the queue,
   2749     // this value is zero-based.
   2750     //
   2751     (*ErrTDPos)++;
   2752   }
   2753 
   2754   return TRUE;
   2755 }
   2756 
   2757 /**
   2758   Create Memory Block.
   2759 
   2760   @param  UhcDev                   The UCHI device.
   2761   @param  MemoryHeader             The Pointer to allocated memory block.
   2762   @param  MemoryBlockSizeInPages   The page size of memory block to be allocated.
   2763 
   2764   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
   2765   @retval EFI_SUCCESS            Success.
   2766 
   2767 **/
   2768 EFI_STATUS
   2769 CreateMemoryBlock (
   2770   IN  USB_UHC_DEV           *UhcDev,
   2771   OUT MEMORY_MANAGE_HEADER  **MemoryHeader,
   2772   IN  UINTN                 MemoryBlockSizeInPages
   2773   )
   2774 {
   2775   EFI_STATUS            Status;
   2776   EFI_PHYSICAL_ADDRESS  TempPtr;
   2777   UINTN                 MemPages;
   2778   UINT8                 *Ptr;
   2779 
   2780   //
   2781   // Memory Block uses MemoryBlockSizeInPages pages,
   2782   // memory management header and bit array use 1 page
   2783   //
   2784   MemPages = MemoryBlockSizeInPages + 1;
   2785   Status = PeiServicesAllocatePages (
   2786              EfiBootServicesData,
   2787              MemPages,
   2788              &TempPtr
   2789              );
   2790   if (EFI_ERROR (Status)) {
   2791     return Status;
   2792   }
   2793 
   2794   Ptr = (UINT8 *) ((UINTN) TempPtr);
   2795 
   2796   ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);
   2797 
   2798   *MemoryHeader = (MEMORY_MANAGE_HEADER *) Ptr;
   2799   //
   2800   // adjust Ptr pointer to the next empty memory
   2801   //
   2802   Ptr += sizeof (MEMORY_MANAGE_HEADER);
   2803   //
   2804   // Set Bit Array initial address
   2805   //
   2806   (*MemoryHeader)->BitArrayPtr  = Ptr;
   2807 
   2808   (*MemoryHeader)->Next         = NULL;
   2809 
   2810   //
   2811   // Memory block initial address
   2812   //
   2813   Ptr = (UINT8 *) ((UINTN) TempPtr);
   2814   Ptr += EFI_PAGE_SIZE;
   2815   (*MemoryHeader)->MemoryBlockPtr = Ptr;
   2816   //
   2817   // set Memory block size
   2818   //
   2819   (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * EFI_PAGE_SIZE;
   2820   //
   2821   // each bit in Bit Array will manage 32byte memory in memory block
   2822   //
   2823   (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
   2824 
   2825   return EFI_SUCCESS;
   2826 }
   2827 
   2828 /**
   2829   Initialize UHCI memory management.
   2830 
   2831   @param  UhcDev                 The UCHI device.
   2832 
   2833   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
   2834   @retval EFI_SUCCESS            Success.
   2835 
   2836 **/
   2837 EFI_STATUS
   2838 InitializeMemoryManagement (
   2839   IN USB_UHC_DEV           *UhcDev
   2840   )
   2841 {
   2842   MEMORY_MANAGE_HEADER  *MemoryHeader;
   2843   EFI_STATUS            Status;
   2844   UINTN                 MemPages;
   2845 
   2846   MemPages  = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
   2847   Status    = CreateMemoryBlock (UhcDev, &MemoryHeader, MemPages);
   2848   if (EFI_ERROR (Status)) {
   2849     return Status;
   2850   }
   2851 
   2852   UhcDev->Header1 = MemoryHeader;
   2853 
   2854   return EFI_SUCCESS;
   2855 }
   2856 
   2857 /**
   2858   Initialize UHCI memory management.
   2859 
   2860   @param  UhcDev           The UCHI device.
   2861   @param  Pool             Buffer pointer to store the buffer pointer.
   2862   @param  AllocSize        The size of the pool to be allocated.
   2863 
   2864   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
   2865   @retval EFI_SUCCESS            Success.
   2866 
   2867 **/
   2868 EFI_STATUS
   2869 UhcAllocatePool (
   2870   IN  USB_UHC_DEV     *UhcDev,
   2871   OUT UINT8           **Pool,
   2872   IN  UINTN           AllocSize
   2873   )
   2874 {
   2875   MEMORY_MANAGE_HEADER  *MemoryHeader;
   2876   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
   2877   MEMORY_MANAGE_HEADER  *NewMemoryHeader;
   2878   UINTN                 RealAllocSize;
   2879   UINTN                 MemoryBlockSizeInPages;
   2880   EFI_STATUS            Status;
   2881 
   2882   *Pool = NULL;
   2883 
   2884   MemoryHeader = UhcDev->Header1;
   2885 
   2886   //
   2887   // allocate unit is 32 byte (align on 32 byte)
   2888   //
   2889   if ((AllocSize & 0x1F) != 0) {
   2890     RealAllocSize = (AllocSize / 32 + 1) * 32;
   2891   } else {
   2892     RealAllocSize = AllocSize;
   2893   }
   2894 
   2895   Status = EFI_NOT_FOUND;
   2896   for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
   2897 
   2898     Status = AllocMemInMemoryBlock (
   2899               TempHeaderPtr,
   2900               (VOID **) Pool,
   2901               RealAllocSize / 32
   2902               );
   2903     if (!EFI_ERROR (Status)) {
   2904       return EFI_SUCCESS;
   2905     }
   2906   }
   2907   //
   2908   // There is no enough memory,
   2909   // Create a new Memory Block
   2910   //
   2911   //
   2912   // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
   2913   // just allocate a large enough memory block.
   2914   //
   2915   if (RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * EFI_PAGE_SIZE)) {
   2916     MemoryBlockSizeInPages = RealAllocSize / EFI_PAGE_SIZE + 1;
   2917   } else {
   2918     MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
   2919   }
   2920 
   2921   Status = CreateMemoryBlock (UhcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
   2922   if (EFI_ERROR (Status)) {
   2923     return Status;
   2924   }
   2925   //
   2926   // Link the new Memory Block to the Memory Header list
   2927   //
   2928   InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);
   2929 
   2930   Status = AllocMemInMemoryBlock (
   2931             NewMemoryHeader,
   2932             (VOID **) Pool,
   2933             RealAllocSize / 32
   2934             );
   2935   return Status;
   2936 }
   2937 
   2938 /**
   2939   Alloc Memory In MemoryBlock.
   2940 
   2941   @param  MemoryHeader           The pointer to memory manage header.
   2942   @param  Pool                   Buffer pointer to store the buffer pointer.
   2943   @param  NumberOfMemoryUnit     The size of the pool to be allocated.
   2944 
   2945   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
   2946   @retval EFI_SUCCESS            Success.
   2947 
   2948 **/
   2949 EFI_STATUS
   2950 AllocMemInMemoryBlock (
   2951   IN  MEMORY_MANAGE_HEADER  *MemoryHeader,
   2952   OUT VOID                  **Pool,
   2953   IN  UINTN                 NumberOfMemoryUnit
   2954   )
   2955 {
   2956   UINTN TempBytePos;
   2957   UINTN FoundBytePos;
   2958   UINT8 Index;
   2959   UINT8 FoundBitPos;
   2960   UINT8 ByteValue;
   2961   UINT8 BitValue;
   2962   UINTN NumberOfZeros;
   2963   UINTN Count;
   2964 
   2965   FoundBytePos  = 0;
   2966   FoundBitPos   = 0;
   2967 
   2968   ByteValue     = MemoryHeader->BitArrayPtr[0];
   2969   NumberOfZeros = 0;
   2970   Index             = 0;
   2971   for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {
   2972     //
   2973     // Pop out BitValue from a byte in TempBytePos.
   2974     //
   2975     BitValue = (UINT8)(ByteValue & 0x1);
   2976 
   2977     if (BitValue == 0) {
   2978       //
   2979       // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
   2980       //
   2981       NumberOfZeros++;
   2982       //
   2983       // Found enough consecutive free space, break the loop
   2984       //
   2985       if (NumberOfZeros >= NumberOfMemoryUnit) {
   2986         break;
   2987       }
   2988     } else {
   2989       //
   2990       // Encountering a '1', meant the bit is ocupied.
   2991       //
   2992       if (NumberOfZeros >= NumberOfMemoryUnit) {
   2993         //
   2994         // Found enough consecutive free space,break the loop
   2995         //
   2996         break;
   2997       } else {
   2998         //
   2999         // the NumberOfZeros only record the number of those consecutive zeros,
   3000         // so reset the NumberOfZeros to 0 when encountering '1' before finding
   3001         // enough consecutive '0's
   3002         //
   3003         NumberOfZeros = 0;
   3004         //
   3005         // reset the (FoundBytePos,FoundBitPos) to the position of '1'
   3006         //
   3007         FoundBytePos  = TempBytePos;
   3008         FoundBitPos   = Index;
   3009       }
   3010     }
   3011     //
   3012     // right shift the byte
   3013     //
   3014     ByteValue /= 2;
   3015 
   3016     //
   3017     // step forward a bit
   3018     //
   3019     Index++;
   3020     if (Index == 8) {
   3021       //
   3022       // step forward a byte, getting the byte value,
   3023       // and reset the bit pos.
   3024       //
   3025       TempBytePos += 1;
   3026       ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];
   3027       Index     = 0;
   3028     }
   3029   }
   3030 
   3031   if (NumberOfZeros < NumberOfMemoryUnit) {
   3032     return EFI_NOT_FOUND;
   3033   }
   3034   //
   3035   // Found enough free space.
   3036   //
   3037   //
   3038   // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
   3039   //  1)(FoundBytePos,FoundBitPos) record the position
   3040   //    of the last '1' before the consecutive '0's, it must
   3041   //    be adjusted to the start position of the consecutive '0's.
   3042   //  2)the start address of the consecutive '0's is just the start of
   3043   //    the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
   3044   //
   3045   if ((MemoryHeader->BitArrayPtr[0] & BIT0) != 0) {
   3046     FoundBitPos += 1;
   3047   }
   3048   //
   3049   // Have the (FoundBytePos,FoundBitPos) make sense.
   3050   //
   3051   if (FoundBitPos > 7) {
   3052     FoundBytePos += 1;
   3053     FoundBitPos -= 8;
   3054   }
   3055   //
   3056   // Set the memory as allocated
   3057   //
   3058   for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {
   3059 
   3060     MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8) (MemoryHeader->BitArrayPtr[TempBytePos] | (1 << Index));
   3061     Index++;
   3062     if (Index == 8) {
   3063       TempBytePos += 1;
   3064       Index = 0;
   3065     }
   3066   }
   3067 
   3068   *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;
   3069 
   3070   return EFI_SUCCESS;
   3071 }
   3072 
   3073 /**
   3074   Uhci Free Pool.
   3075 
   3076   @param  UhcDev                 The UHCI device.
   3077   @param  Pool                   A pointer to store the buffer address.
   3078   @param  AllocSize              The size of the pool to be freed.
   3079 
   3080 **/
   3081 VOID
   3082 UhcFreePool (
   3083   IN USB_UHC_DEV     *UhcDev,
   3084   IN UINT8           *Pool,
   3085   IN UINTN           AllocSize
   3086   )
   3087 {
   3088   MEMORY_MANAGE_HEADER  *MemoryHeader;
   3089   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
   3090   UINTN                 StartBytePos;
   3091   UINTN                 Index;
   3092   UINT8                 StartBitPos;
   3093   UINT8                 Index2;
   3094   UINTN                 Count;
   3095   UINTN                 RealAllocSize;
   3096 
   3097   MemoryHeader = UhcDev->Header1;
   3098 
   3099   //
   3100   // allocate unit is 32 byte (align on 32 byte)
   3101   //
   3102   if ((AllocSize & 0x1F) != 0) {
   3103     RealAllocSize = (AllocSize / 32 + 1) * 32;
   3104   } else {
   3105     RealAllocSize = AllocSize;
   3106   }
   3107 
   3108   for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;
   3109        TempHeaderPtr = TempHeaderPtr->Next) {
   3110 
   3111     if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
   3112         ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr +
   3113                                     TempHeaderPtr->MemoryBlockSizeInBytes))) {
   3114 
   3115       //
   3116       // Pool is in the Memory Block area,
   3117       // find the start byte and bit in the bit array
   3118       //
   3119       StartBytePos  = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;
   3120       StartBitPos   = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);
   3121 
   3122       //
   3123       // reset associated bits in bit array
   3124       //
   3125       for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {
   3126 
   3127         TempHeaderPtr->BitArrayPtr[Index] = (UINT8) (TempHeaderPtr->BitArrayPtr[Index] ^ (1 << Index2));
   3128         Index2++;
   3129         if (Index2 == 8) {
   3130           Index += 1;
   3131           Index2 = 0;
   3132         }
   3133       }
   3134       //
   3135       // break the loop
   3136       //
   3137       break;
   3138     }
   3139   }
   3140 
   3141 }
   3142 
   3143 /**
   3144   Insert a new memory header into list.
   3145 
   3146   @param  MemoryHeader         A pointer to the memory header list.
   3147   @param  NewMemoryHeader      A new memory header to be inserted into the list.
   3148 
   3149 **/
   3150 VOID
   3151 InsertMemoryHeaderToList (
   3152   IN MEMORY_MANAGE_HEADER  *MemoryHeader,
   3153   IN MEMORY_MANAGE_HEADER  *NewMemoryHeader
   3154   )
   3155 {
   3156   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
   3157 
   3158   for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
   3159     if (TempHeaderPtr->Next == NULL) {
   3160       TempHeaderPtr->Next = NewMemoryHeader;
   3161       break;
   3162     }
   3163   }
   3164 }
   3165 
   3166 /**
   3167   Judge the memory block in the memory header is empty or not.
   3168 
   3169   @param  MemoryHeaderPtr   A pointer to the memory header list.
   3170 
   3171   @retval Whether the memory block in the memory header is empty or not.
   3172 
   3173 **/
   3174 BOOLEAN
   3175 IsMemoryBlockEmptied (
   3176   IN MEMORY_MANAGE_HEADER  *MemoryHeaderPtr
   3177   )
   3178 {
   3179   UINTN Index;
   3180 
   3181   for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {
   3182     if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {
   3183       return FALSE;
   3184     }
   3185   }
   3186 
   3187   return TRUE;
   3188 }
   3189 
   3190 /**
   3191   remove a memory header from list.
   3192 
   3193   @param  FirstMemoryHeader   A pointer to the memory header list.
   3194   @param  FreeMemoryHeader    A memory header to be removed into the list.
   3195 
   3196 **/
   3197 VOID
   3198 DelinkMemoryBlock (
   3199   IN MEMORY_MANAGE_HEADER    *FirstMemoryHeader,
   3200   IN MEMORY_MANAGE_HEADER    *FreeMemoryHeader
   3201   )
   3202 {
   3203   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
   3204 
   3205   if ((FirstMemoryHeader == NULL) || (FreeMemoryHeader == NULL)) {
   3206     return ;
   3207   }
   3208 
   3209   for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
   3210 
   3211     if (TempHeaderPtr->Next == FreeMemoryHeader) {
   3212       //
   3213       // Link the before and after
   3214       //
   3215       TempHeaderPtr->Next = FreeMemoryHeader->Next;
   3216       break;
   3217     }
   3218   }
   3219 }
   3220