ehcisched.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,975 行 · 第 1/5 页

C
2,975
字号
            HcDev,
            StatusPktId,
            &StatusQtdPtr
            );
  if (EFI_ERROR (Status)) {
    Status = EFI_OUT_OF_RESOURCES;
    goto destory_qtds;
  }

  //
  // Link setup Qtd -> data Qtds -> status Qtd
  //
  if (FirstDataQtdPtr != NULL) {
    LinkQtdToQtd (SetupQtdPtr, FirstDataQtdPtr);
    LinkQtdToQtd (LastDataQtdPtr, StatusQtdPtr);
  } else {
    LinkQtdToQtd (SetupQtdPtr, StatusQtdPtr);
  }

  *ControlQtdsHead = SetupQtdPtr;

  goto exit;

destory_qtds:
  DestoryQtds (HcDev, FirstDataQtdPtr);
destory_setup_qtd:
  DestoryQtds (HcDev, SetupQtdPtr);
exit:
  return Status;
}

EFI_STATUS
CreateBulkOrInterruptQtds (
  IN  USB2_HC_DEV                         *HcDev,
  IN  UINT8                               PktId,
  IN  UINT8                               *DataCursor,
  IN  UINTN                               DataLen,
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
  OUT EHCI_QTD_ENTITY                     **QtdsHead
  )
/*++

Routine Description:

  Create Qtds list for Bulk or Interrupt Transfer

Arguments:

  HcDev        - USB2_HC_DEV
  PktId        - Packet Identification of Qtds
  DataCursor   - A pointer to user data buffer to transfer
  DataLen      - Length of user data to transfer
  DataToggle   - Data Toggle to start
  Translator   - Translator Transaction for SplitX
  QtdsHead     - A pointer of pointer to first Qtd for control tranfer for return

Returns:

  EFI_SUCCESS            Success
  EFI_OUT_OF_RESOURCES   Cannot allocate resources

--*/
{
  EFI_STATUS      Status;
  EHCI_QTD_ENTITY *QtdPtr;
  EHCI_QTD_ENTITY *PreQtdPtr;
  EHCI_QTD_ENTITY *FirstQtdPtr;
  EHCI_QTD_ENTITY *AltQtdPtr;
  UINTN           DataCount;
  UINTN           CapacityOfQtd;
  UINTN           SizePerQtd;

  Status        = EFI_SUCCESS;
  QtdPtr        = NULL;
  PreQtdPtr     = NULL;
  FirstQtdPtr   = NULL;
  AltQtdPtr     = NULL;
  CapacityOfQtd = 0;

  DataCount   = DataLen;
  while (DataCount > 0) {

    CapacityOfQtd = GetCapacityOfQtd (DataCursor);
    SizePerQtd    = DataCount;
    if (DataCount > CapacityOfQtd) {
      SizePerQtd = CapacityOfQtd;
    }

    Status = CreateDataQtd (
              HcDev,
              DataCursor,
              SizePerQtd,
              PktId,
              0,
              &QtdPtr
              );
    if (EFI_ERROR (Status)) {
      Status = EFI_OUT_OF_RESOURCES;
      if (NULL == FirstQtdPtr) {
        goto exit;
      } else {
        goto destory_qtds;
      }
    }

    if (NULL == FirstQtdPtr) {
      FirstQtdPtr = QtdPtr;
    } else {
      LinkQtdToQtd (PreQtdPtr, QtdPtr);
    }

    PreQtdPtr = QtdPtr;
    DataCursor += SizePerQtd;
    DataCount -= SizePerQtd;
  }

  //
  // Set Alternate Qtd
  //
  if (INPUT_PACKET_ID == PktId && 0 < GetNumberOfQtd (FirstQtdPtr)) {
    Status = CreateAltQtd (
              HcDev,
              PktId,
              &AltQtdPtr
              );
    if (EFI_ERROR (Status)) {
      Status = EFI_OUT_OF_RESOURCES;
      goto destory_qtds;
    }

    LinkQtdsToAltQtd (FirstQtdPtr, AltQtdPtr);
  }

  *QtdsHead = FirstQtdPtr;
  goto exit;

destory_qtds:
  DestoryQtds (HcDev, FirstQtdPtr);
exit:
  return Status;
}

VOID
DestoryQtds (
  IN USB2_HC_DEV          *HcDev,
  IN EHCI_QTD_ENTITY      *FirstQtdPtr
  )
/*++

Routine Description:

  Destory all Qtds in the list

Arguments:

  HcDev         - USB2_HC_DEV
  FirstQtdPtr   - A pointer to first Qtd in the list

Returns:

  VOID

--*/
{
  EHCI_QTD_ENTITY *PrevQtd;
  EHCI_QTD_ENTITY *NextQtd;

  if (!FirstQtdPtr) {
    goto exit;
  }

  PrevQtd = FirstQtdPtr;

  //
  // Delete all the Qtds.
  //
  do {
    NextQtd = PrevQtd->Next;
    EhciFreePool (HcDev, (UINT8 *) PrevQtd, sizeof (EHCI_QTD_ENTITY));
    PrevQtd = NextQtd;
  } while (NULL != PrevQtd);

exit:
  return ;
}

UINTN
GetNumberOfQtd (
  IN EHCI_QTD_ENTITY    *FirstQtdPtr
  )
/*++

Routine Description:

  Number of Qtds in the list

Arguments:

  FirstQtdPtr - A pointer to first Qtd in the list

Returns:

  Number of Qtds in the list

--*/
{
  UINTN           Count;
  EHCI_QTD_ENTITY *QtdPtr;
  Count   = 0;
  QtdPtr  = FirstQtdPtr;

  while (NULL != QtdPtr) {
    Count++;
    QtdPtr = QtdPtr->Next;
  }

  return Count;
}

UINTN
GetCapacityOfQtd (
  IN UINT8    *BufferCursor
  )
/*++

Routine Description:

  Get Size of First Qtd

Arguments:

  BufferCursor       - BufferCursor of the Qtd

Returns:

  Size of First Qtd

--*/
{
 
 if (EFI_PAGE_MASK & GET_0B_TO_31B (BufferCursor)) {
   return EFI_PAGE_SIZE * 4;
 } else {
   return EFI_PAGE_SIZE * 5;
 }

}

UINTN
GetApproxiOfInterval (
  IN UINTN  Interval
  )
/*++

Routine Description:

  Get the approximate value in the 2 index sequence

Arguments:

  Interval  - the value of interval

Returns:

  approximate value of interval in the 2 index sequence

--*/
{
  UINTN Orignate;
  UINTN Approxi;

  Orignate  = Interval;
  Approxi   = 1;

  while (Orignate != 1 && Orignate != 0) {
    Orignate  = Orignate >> 1;
    Approxi   = Approxi << 1;
  }

  if (Interval & (Approxi >> 1)) {
    Approxi = Approxi << 1;
  }

  return Approxi;
}

EHCI_QTD_HW *
GetQtdAlternateNextPointer (
  IN EHCI_QTD_HW  *HwQtdPtr
  )
/*++

Routine Description:

  Get Qtd alternate next pointer field

Arguments:

  HwQtdPtr - A pointer to hardware Qtd structure

Returns:

  A pointer to hardware alternate Qtd

--*/
{
  EHCI_QTD_HW *Value;

  Value = NULL;

  if (!HwQtdPtr->AltNextQtdTerminate) {
    Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);
  }

  return Value;
}

EHCI_QTD_HW *
GetQtdNextPointer (
  IN EHCI_QTD_HW  *HwQtdPtr
  )
/*++

Routine Description:

  Get Qtd next pointer field

Arguments:

  HwQtdPtr - A pointer to hardware Qtd structure

Returns:

  A pointer to next hardware Qtd structure

--*/
{
  EHCI_QTD_HW *Value;

  Value = NULL;

  if (!HwQtdPtr->NextQtdTerminate) {
    Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);
  }

  return Value;
}

VOID 
LinkQtdToQtd (
  IN EHCI_QTD_ENTITY * PreQtdPtr,
  IN EHCI_QTD_ENTITY * QtdPtr
  )
/*++

Routine Description:

  Link Qtds together

Arguments:

  PreQtdPtr   - A pointer to pre Qtd
  QtdPtr      - A pointer to next Qtd

Returns:

  VOID

--*/
{
  EHCI_QTD_HW *QtdHwPtr;

  ASSERT(PreQtdPtr);
  ASSERT(QtdPtr);

  //
  // Software link
  //
  PreQtdPtr->Next = QtdPtr;
  QtdPtr->Prev    = PreQtdPtr;

  //
  // Hardware link
  //
  QtdHwPtr                        = &(QtdPtr->Qtd);
  PreQtdPtr->Qtd.NextQtdPointer   = (UINT32) (GET_0B_TO_31B(QtdHwPtr) >> 5);
  PreQtdPtr->Qtd.NextQtdTerminate = FALSE;

  return ;
}



VOID 
LinkQtdsToAltQtd (
  IN EHCI_QTD_ENTITY  * FirstQtdPtr,
  IN EHCI_QTD_ENTITY  * AltQtdPtr
  )
/*++

Routine Description:

  Link AlterQtds together

Arguments:

  FirstQtdPtr  - A pointer to first Qtd in the list
  AltQtdPtr    - A pointer to alternative Qtd

Returns:

  VOID

--*/
{
  EHCI_QTD_ENTITY *QtdPtr;
  EHCI_QTD_HW     *AltQtdHwPtr;

  ASSERT(FirstQtdPtr);
  ASSERT(AltQtdPtr);

  AltQtdHwPtr = &(AltQtdPtr->Qtd);
  QtdPtr      = FirstQtdPtr;

  while (NULL != QtdPtr) {
    //
    // Software link
    //
    QtdPtr->AltNext = AltQtdPtr;
    //
    // Hardware link
    //
    QtdPtr->Qtd.AltNextQtdPointer   = (UINT32) (GET_0B_TO_31B(AltQtdHwPtr) >> 5);
    QtdPtr->Qtd.AltNextQtdTerminate = FALSE;
    QtdPtr                          = QtdPtr->Next;
  }

  return ;
}

VOID
LinkQtdToQh (
  IN EHCI_QH_ENTITY      *QhPtr,
  IN EHCI_QTD_ENTITY     *QtdPtr
  )
/*++

Routine Description:

  Link Qtds list to Qh

Arguments:

  QhPtr    - A pointer to Qh
  QtdPtr   - A pointer to first Qtd in the list

Returns:

  VOID

--*/
{
  EHCI_QTD_ENTITY *Cursor;
  EHCI_QTD_HW     *QtdHwPtr;

  ASSERT (QhPtr);
  ASSERT (QtdPtr);

  QhPtr->FirstQtdPtr = QtdPtr;
  if (NULL != QtdPtr->AltNext) {
    QhPtr->AltQtdPtr = QtdPtr->AltNext;
  }

  Cursor = QtdPtr;
  while (NULL != Cursor) {
    Cursor->SelfQh = QhPtr;
    if (NULL == Cursor->Next) {
      QhPtr->LastQtdPtr = Cursor;
    }

    Cursor = Cursor->Next;
  }

  QtdHwPtr                    = &(QtdPtr->Qtd);
  QhPtr->Qh.NextQtdPointer    = (UINT32) (GET_0B_TO_31B (QtdHwPtr) >> 5);
  QhPtr->Qh.NextQtdTerminate  = FALSE;

  QhPtr->Qh.AltNextQtdPointer    = 0;
  QhPtr->Qh.AltNextQtdTerminate  = TRUE;


  if ((QtdPtr->Qtd.PidCode == OUTPUT_PACKET_PID_CODE) && 
      (QhPtr->TransferType == BULK_TRANSFER)) {
      //
      //Start PING first
      //     
      QhPtr->Qh.Status |= QTD_STATUS_DO_PING;
    }

  return ;
}

EFI_STATUS
LinkQhToAsyncList (
  IN  USB2_HC_DEV       *HcDev,
  IN EHCI_QH_ENTITY     *QhPtr
  )
/*++

Routine Description:

  Link Qh to Async Schedule List

Arguments:

  HcDev  - USB2_HC_DEV
  QhPtr  - A pointer to Qh

Returns:

  EFI_SUCCESS       Success
  EFI_DEVICE_ERROR  Fail

--*/
{
  EFI_STATUS  Status;

  ASSERT (HcDev);
  ASSERT (QhPtr);


  //
  // NULL QH created before
  //

  HcDev->NULLQH->Next = QhPtr;
  HcDev->NULLQH->Prev = QhPtr;

  QhPtr->Next = HcDev->NULLQH;
  QhPtr->Prev = HcDev->NULLQH;
  
  
  HcDev->NULLQH->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&(QhPtr->Qh) >> 5));
  QhPtr->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&(HcDev->NULLQH->Qh) >> 5));


  Status = SetAsyncListAddr (HcDev, HcDev->NULLQH);
  if (EFI_ERROR (Status)) {
    Status = EFI_DEVICE_ERROR;
    goto exit;
  }

  if (!IsAsyncScheduleEnabled (HcDev)) {

    Status = EnableAsynchronousSchedule (HcDev);
    if (EFI_ERROR (Status)) {
      Status = EFI_DEVICE_ERROR;
      goto exit;
    }

    Status = WaitForAsyncScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
    if (EFI_ERROR (Status)) {
      DEBUG ((gEHCDebugLevel, "EHCI: WaitForAsyncScheduleEnable TimeOut"));
      Status = EFI_TIMEOUT;
      goto exit;
    }

    if (IsEhcHalted (HcDev)) {
      Status = StartScheduleExecution (HcDev);
      if (EFI_ERROR (Status)) {
        Status = EFI_DEVICE_ERROR;
      }
    }

  }

exit:
  return Status;
}

EFI_STATUS
UnlinkQhFromAsyncList (
  IN USB2_HC_DEV        *HcDev,
  IN EHCI_QH_ENTITY     *QhPtr
  )
/*++

Routine Description:

  Unlink Qh from Async Schedule List

Arguments:

  HcDev  - USB2_HC_DEV
  QhPtr  - A pointer to Qh

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?