uhchlp.c

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

C
3,348
字号
    //
    ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
    if (ScrollNum & 0x1) {
      *DataToggle ^= 1;
    }

    return EFI_DEVICE_ERROR;
  }

  return EFI_SUCCESS;
}

VOID
DelLinkSingleQH (
  IN  USB_HC_DEV     *HcDev,
  IN  QH_STRUCT      *PtrQH,
  IN  UINT16         FrameListIndex,
  IN  BOOLEAN        SearchOther,
  IN  BOOLEAN        Delete
  )
/*++

Routine Description:

  Unlink from frame list and delete single QH
Arguments:

  HcDev            - USB_HC_DEV
  PtrQH            - QH_STRUCT
  FrameListIndex   - Frame List Index
  SearchOther      - Search Other QH
  Delete           - TRUE is to delete the QH
Returns:
  VOID
--*/
{
  FRAMELIST_ENTRY *pCurFrame;
  UINTN           Index;
  UINTN           BeginFrame;
  UINTN           EndFrame;
  QH_STRUCT       *CurrentQH;
  QH_STRUCT       *NextQH;
  TD_STRUCT       *CurrentTD;
  VOID            *PtrPreQH;
  BOOLEAN         Found;

  NextQH    = NULL;
  PtrPreQH  = NULL;
  Found     = FALSE;

  if (PtrQH == NULL) {
    return ;
  }

  if (SearchOther) {
    BeginFrame  = 0;
    EndFrame    = 1024;
  } else {
    BeginFrame  = FrameListIndex;
    EndFrame    = FrameListIndex + 1;
  }

  for (Index = BeginFrame; Index < EndFrame; Index++) {

    pCurFrame = HcDev->FrameListEntry + (Index & 0x3FF);

    if (GetCurFrameListTerminate (pCurFrame)) {
      //
      // current frame list is empty,search next frame list entry
      //
      continue;
    }

    if (!IsCurFrameListQHorTD (pCurFrame)) {
      //
      // TD linked to current framelist
      //
      CurrentTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);

      while (GetTDLinkPtrValidorInvalid (CurrentTD)) {

        if (IsTDLinkPtrQHOrTD (CurrentTD)) {
          //
          // QH linked next to the TD,break while ()
          //
          break;
        }

        CurrentTD = (TD_STRUCT *) GetTDLinkPtr (CurrentTD);
      }

      if (!GetTDLinkPtrValidorInvalid (CurrentTD)) {
        //
        // no QH linked next to the last TD,
        // search next frame list
        //
        continue;
      }
      
      //
      // a QH linked next to the last TD
      //
      CurrentQH = (QH_STRUCT *) GetTDLinkPtr (CurrentTD);

      PtrPreQH  = CurrentTD;

    } else {
      //
      // a QH linked to current framelist
      //
      CurrentQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);

      PtrPreQH  = NULL;
    }

    if (CurrentQH == PtrQH) {

      if (GetQHHorizontalValidorInvalid (PtrQH)) {
        //
        // there is QH connected after the QH found
        //
        //
        // retrieve nex qh pointer of the qh found.
        //
        NextQH = GetQHHorizontalLinkPtr (PtrQH);
      } else {
        NextQH = NULL;
      }

      if (PtrPreQH) {
        //
        // QH linked to a TD struct
        //
        CurrentTD = (TD_STRUCT *) PtrPreQH;

        SetTDLinkPtrValidorInvalid (CurrentTD, (BOOLEAN) ((NextQH == NULL) ? FALSE : TRUE));
        SetTDLinkPtr (CurrentTD, NextQH);
        CurrentTD->ptrNextQH = NextQH;

      } else {
        //
        // QH linked directly to current framelist entry
        //
        SetorClearCurFrameListTerminate (pCurFrame, (BOOLEAN) ((NextQH == NULL) ? TRUE : FALSE));
        SetCurFrameListPointer (pCurFrame, (UINT8 *) NextQH);
      }

      Found = TRUE;
      //
      // search next framelist entry
      //
      continue;
    }

    while (GetQHHorizontalValidorInvalid (CurrentQH)) {

      PtrPreQH = CurrentQH;
      //
      // Get next horizontal linked QH
      //
      CurrentQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (CurrentQH);
      //
      // the qh is found
      //
      if (CurrentQH == PtrQH) {
        break;
      }
    }
    
    //
    // search next frame list entry
    //
    if (CurrentQH != PtrQH) {
      //
      // Not find the QH
      //
      continue;
    }
    //
    // find the specified qh, then delink it from
    // the horizontal QH list in the frame entry.
    //
    
    if (GetQHHorizontalValidorInvalid (PtrQH)) {
      //
      // there is QH connected after the QH found
      //
      //
      // retrieve nex qh pointer of the qh found.
      //
      NextQH = GetQHHorizontalLinkPtr (PtrQH);

    } else {
      //
      // NO QH connected after the QH found
      //
      NextQH = NULL;
      //
      // NULL the previous QH's link ptr and set Terminate field.
      //
      SetQHHorizontalValidorInvalid ((QH_STRUCT *) PtrPreQH, FALSE);
    }

    SetQHHorizontalLinkPtr ((QH_STRUCT *) PtrPreQH, NextQH);
    ((QH_STRUCT *) PtrPreQH)->ptrNext = NextQH;

    Found = TRUE;
  }

  if (Found && Delete) {
    //
    // free memory once used by the specific QH
    //
    UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
  }

  return ;
}


VOID
DeleteQueuedTDs (
  IN USB_HC_DEV     *HcDev,
  IN TD_STRUCT      *PtrFirstTD
  )
/*++
Routine Description:

  Delete Queued TDs
Arguments:

  HcDev       - USB_HC_DEV
  PtrFirstTD  - TD link list head

Returns:
  VOID

--*/
{
  TD_STRUCT *Tptr1;
  TD_STRUCT *Tptr2;

  Tptr1 = PtrFirstTD;
  //
  // Delete all the TDs in a queue.
  //
  while (Tptr1) {

    Tptr2 = Tptr1;

    if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
      Tptr1 = NULL;
    } else {

      Tptr1 = GetTDLinkPtr (Tptr2);

      //
      // TD link to itself
      //
      if (Tptr1 == Tptr2) {
        Tptr1 = NULL;
      }
    }

    UhciFreePool (HcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));
  }

  return ;
}

VOID
InsertQHTDToINTList (
  IN USB_HC_DEV                          *HcDev,
  IN QH_STRUCT                           *PtrQH,
  IN TD_STRUCT                           *PtrFirstTD,
  IN UINT8                               DeviceAddress,
  IN UINT8                               EndPointAddress,
  IN UINT8                               DataToggle,
  IN UINTN                               DataLength,
  IN UINTN                               PollingInterval,
  IN VOID                                *Mapping,
  IN UINT8                               *DataBuffer,
  IN EFI_ASYNC_USB_TRANSFER_CALLBACK     CallBackFunction,
  IN VOID                                *Context
  )
/*++
Routine Description:
  Insert QH and TD To Interrupt List
Arguments:

  HcDev           - USB_HC_DEV
  PtrQH           - QH_STRUCT
  PtrFirstTD      - First TD_STRUCT
  DeviceAddress   - Device Address
  EndPointAddress - EndPoint Address
  DataToggle      - Data Toggle
  DataLength      - Data length 
  PollingInterval - Polling Interval when inserted to frame list
  Mapping         - Mapping alue  
  DataBuffer      - Data buffer
  CallBackFunction- CallBackFunction after interrupt transfeer
  Context         - CallBackFunction Context passed as function parameter
Returns:
  EFI_SUCCESS            - Sucess
  EFI_INVALID_PARAMETER  - Paremeter is error 

--*/
{
  INTERRUPT_LIST  *Node;

  Node = EfiLibAllocatePool (sizeof (INTERRUPT_LIST));
  if (Node == NULL) {
    return ;
  }
  
  //
  // Fill Node field
  //
  Node->Signature     = INTERRUPT_LIST_SIGNATURE;
  Node->DevAddr       = DeviceAddress;
  Node->EndPoint      = EndPointAddress;
  Node->PtrQH         = PtrQH;
  Node->PtrFirstTD    = PtrFirstTD;
  Node->DataToggle    = DataToggle;
  Node->DataLen       = DataLength;
  Node->PollInterval  = PollingInterval;
  Node->Mapping       = Mapping;
  //
  // DataBuffer is allocated host memory, not mapped memory
  //
  Node->DataBuffer        = DataBuffer;
  Node->InterruptCallBack = CallBackFunction;
  Node->InterruptContext  = Context;

  //
  // insert the new interrupt transfer to the head of the list.
  // The interrupt transfer's monitor function scans the whole list from head
  // to tail. The new interrupt transfer MUST be added to the head of the list
  // for the sake of error recovery.
  //
  InsertHeadList (&(HcDev->InterruptListHead), &(Node->Link));

  return ;
}


EFI_STATUS
DeleteAsyncINTQHTDs (
  IN  USB_HC_DEV     *HcDev,
  IN  UINT8          DeviceAddress,
  IN  UINT8          EndPointAddress,
  OUT UINT8          *DataToggle
  )
/*++
Routine Description:

  Delete Async INT QH and TDs
Arguments:

  HcDev           - USB_HC_DEV
  DeviceAddress   - Device Address
  EndPointAddress - EndPoint Address
  DataToggle      - Data Toggle

Returns:
  EFI_SUCCESS            - Sucess
  EFI_INVALID_PARAMETER  - Paremeter is error 

--*/
{
  QH_STRUCT       *MatchQH;
  QH_STRUCT       *ptrNextQH;
  TD_STRUCT       *MatchTD;
  EFI_LIST_ENTRY  *Link;
  INTERRUPT_LIST  *MatchList;
  INTERRUPT_LIST  *PtrList;
  BOOLEAN         Found;

  UINT32          Result;
  UINTN           ErrTDPos;
  UINTN           ActualLen;

  MatchQH   = NULL;
  MatchTD   = NULL;
  MatchList = NULL;

  //
  // no interrupt transaction exists
  //
  if (IsListEmpty (&(HcDev->InterruptListHead))) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // find the correct QH-TD that need to delete
  // (by matching Device address and EndPoint number to match QH-TD )
  //
  Found = FALSE;
  Link  = &(HcDev->InterruptListHead);
  do {

    Link    = Link->ForwardLink;
    PtrList = INTERRUPT_LIST_FROM_LINK (Link);

    if ((PtrList->DevAddr == DeviceAddress) && ((PtrList->EndPoint & 0x0f) == (EndPointAddress & 0x0f))) {
      MatchList = PtrList;

      Found     = TRUE;
      break;
    }

  } while (Link->ForwardLink != &(HcDev->InterruptListHead));

  if (!Found) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // get current endpoint's data toggle bit and save.
  //
  ExecuteAsyncINTTDs (HcDev, MatchList, &Result, &ErrTDPos, &ActualLen);
  UpdateAsyncINTQHTDs (MatchList, Result, (UINT32) ErrTDPos);
  *DataToggle = MatchList->DataToggle;

  MatchTD     = MatchList->PtrFirstTD;
  MatchQH     = MatchList->PtrQH;
  //
  // find the first matching QH position in the FrameList
  //
  while (MatchQH) {

    ptrNextQH = MatchQH->ptrNextIntQH;

    //
    // Search all the entries
    //
    DelLinkSingleQH (HcDev, MatchQH, 0, TRUE, TRUE);

    MatchQH = ptrNextQH;
  }
  
  //
  // Call PciIo->Unmap() to unmap the busmaster read/write
  //
  HcDev->PciIo->Unmap (HcDev->PciIo, MatchList->Mapping);

  //
  // free host data buffer allocated,
  // mapped data buffer is freed by Unmap
  //
  if (MatchList->DataBuffer != NULL) {
    gBS->FreePool (MatchList->DataBuffer);
  }
  
  //
  // at last delete the TDs, to aVOID problems
  //
  DeleteQueuedTDs (HcDev, MatchTD);

  //
  // remove Match node from interrupt list
  //
  RemoveEntryList (&(MatchList->Link));
  gBS->FreePool (MatchList);
  return EFI_SUCCESS;
}

BOOLEAN
CheckTDsResults (
  IN  TD_STRUCT     *PtrTD,
  IN  UINTN         RequiredLen,
  OUT UINT32        *Result,
  OUT UINTN         *ErrTDPos,
  OUT UINTN         *ActualTransferSize
  )
/*++

Routine Description:

  Check TDs Results

Arguments:

  PtrTD               - TD_STRUCT to check
  RequiredLen         - Required Len
  Result              - Transfer result
  ErrTDPos            - Error TD Position
  ActualTransferSize  - Actual Transfer Size

Returns:

  TRUE  - Sucess
  FALSE - Fail

--*/
{
  UINTN Len;

  *Result   = EFI_USB_NOERROR;
  *ErrTDPos = 0;

  //
  // Init to zero.
  //
  *ActualTransferSize = 0;

  while (PtrTD) {

    if (IsTDStatusActive (PtrTD)) {
      *Result |= EFI_USB_ERR_NOTEXECUTE;
    }

    if (IsTDStatusStalled (PtrTD)) {
      *Result |= EFI_USB_ERR_STALL;
    }

    if (IsTDStatusBufferError (PtrTD)) {
      *Result |= EFI_USB_ERR_BUFFER;
    }

    if (IsTDStatusBabbleError (PtrTD)) {
      *Result |= EFI_USB_ERR_BABBLE;
    }

    if (IsTDStatusNAKReceived (PtrTD)) {
      *Result |= EFI_USB_ERR_NAK;
    }

    if (IsTDStatusCRCTimeOutError (PtrTD)) {
      *Result |= EFI_USB_ERR_TIMEOUT;
    }

    if (IsTDStatusBitStuffError (PtrTD)) {
      *Result |= EFI_USB_ERR_BITSTUFF;
    }
   
    //
    // if any error encountered, stop processing the left TDs.
    //
    if (*Result) {
      return FALSE;
    }

    Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
    *ActualTransferSize += Len;

    if (*ActualTransferSize <= RequiredLen && Len < PtrTD->TDData.TDTokenMaxLen) {
      //
      // transter finished and actural length less than required length
      //
      goto Done;
    }
    //
    // Accumulate actual transferred data length in each TD.
    //
    PtrTD = (TD_STRUCT *) (PtrTD->ptrNextTD);
    //
    // Record the first Error TD's position in the queue,
    // this value is zero-based.
    //
    (*ErrTDPos)++;
  }

Done:
  return TRUE;
}


VOID
ExecuteAsyncINTTDs (
  IN  USB_HC_DEV         *HcDev,
  IN  INTERRUPT_LIST     *PtrList,
  OUT UINT32             *Result,
  OUT UINTN              *ErrTDPos,
  OUT UINTN              *ActualLen
  )
/*++

Routine Description:

  Execute Async Interrupt TDs

Arguments:

  HcDev     - USB_HC_DEV
  PtrList   - INTERRUPT_LIST
  Result    - Transfer result
  ErrTDPos  - Error TD Position
  ActualTransferSize  - Actual Transfer Size
  
Returns:

  VOID

--*/
{
  //
  // *ErrTDPos is zero-based value, indicating the first error TD's position
  // in the TDs' sequence.
  // *ErrTDPos value is only valid when *Result is not equal NOERROR.
  //
  UINTN RequiredLen;

  RequiredLen = *ActualLen;
  CheckTDsResults (PtrList->PtrFirstTD, RequiredLen, Result, ErrTDPos, ActualLen);

  return ;
}


VOID
UpdateAsyncINTQHTDs (
  IN INTERRUPT_LIST     *PtrList,
  IN UINT32             Result,
  IN UINT32             ErrTDPos
  )
/*++

Routine Description:

  Update Async Interrupt QH and TDs

Arguments:

  PtrList   - INTERRUPT_LIST
  Result    - Transfer reslut
  ErrTDPos  - Error TD Position

Returns:

  VOID

--*/
{
  QH_STRUCT *PtrFirstQH;
  QH_STRUCT *PtrQH;
  TD_STRUCT *PtrFirstTD;
  TD_STRUCT *PtrTD;
  UINT8     DataToggle;
  UINT32    Index;

  PtrFirstQH  = PtrList->PtrQH;
  PtrFirstTD  = PtrList->PtrFirstTD;

  DataToggle  = 0;

  if (Result == EFI_USB_NOERROR) {

    PtrTD = PtrFirstTD;
    while (PtrTD) {
      DataToggle  = GetTDTokenDataToggle (PtrTD);
      PtrTD       = PtrTD->ptrNextTD;
    }
    
    //
    // save current DataToggle value to interrupt list.
    // this value is used for tracing the interrupt endpoint DataToggle.
    // when this interrupt transfer is deleted, the last DataToggle is saved
    //
    PtrList->DataToggle = DataToggle;

    PtrTD               = PtrFirstTD;

    //
    // Since DataToggle bit should toggle after each success transaction,
    // the First TD's DataToggle bit will be updated to XOR of Last TD's
    // DataToggle bit. If the First TD's DataToggle bit is not equal Last
    // TD's DataToggle bit, that means it already be the XOR of Last TD's,
    // so no update is needed.
    /

⌨️ 快捷键说明

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