⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uhchlp.c

📁 Next BIOS Source code : Extensible Firmware Interface
💻 C
📖 第 1 页 / 共 5 页
字号:
  //
  // 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
  ) 
{
  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,
  OUT UINT32                  *Result,
  OUT UINTN                   *ErrTDPos,
  OUT UINTN                   *ActualTransferSize
  )
{
  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;
    }
    
    //
    // Accumulate actual transferred data length in each TD.
    //
    Len = GetTDStatusActualLength (ptrTD) % 0x800;
    *ActualTransferSize += Len;
    
    //
    // if any error encountered, stop processing the left TDs.
    //
    if(*Result) {
      return FALSE;
    }
    
    ptrTD = (TD_STRUCT*)(ptrTD->ptrNextTD);
    //
    // Record the first Error TD's position in the queue,
    // this value is zero-based.
    //
    (*ErrTDPos) ++ ;
  }
  
  return TRUE ;
}


VOID
ExecuteAsyncINTTDs(
  IN  USB_HC_DEV      *HcDev,
  IN  INTERRUPT_LIST  *ptrList,
  OUT UINT32          *Result,
  OUT UINTN           *ErrTDPos,
  OUT UINTN           *ActualLen
  ) 
{
  //
  // *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.
  //
  CheckTDsResults(ptrList->ptrFirstTD,Result,ErrTDPos,ActualLen) ;

  return ;
}


VOID
UpdateAsyncINTQHTDs(
  IN  INTERRUPT_LIST  *ptrList,
  IN  UINT32          Result,
  IN  UINT32          ErrTDPos
  )
{
  QH_STRUCT       *ptrFirstQH;
  QH_STRUCT       *ptrQH;
  TD_STRUCT       *ptrFirstTD;
  TD_STRUCT       *ptrTD;
  UINT8           DataToggle;
  UINT32          i;
  
  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.
    //
    if(DataToggle == GetTDTokenDataToggle(ptrFirstTD)) {
      ptrTD = ptrFirstTD ;
      while(ptrTD) {
        
        DataToggle ^= 1 ;
        if(DataToggle) {
          SetTDTokenDataToggle1(ptrTD);
        } else {
          SetTDTokenDataToggle0(ptrTD);
        }
        ptrTD = ptrTD->ptrNextTD ;
      }
    }
    
    //
    // restore Link Pointer of QH to First TD
    // (because QH's Link Pointer will change during TD execution)
    //
    ptrQH = ptrFirstQH;
    while(ptrQH) {
      
      LinkTDToQH(ptrQH,ptrFirstTD) ;
      ptrQH = ptrQH->ptrNextIntQH;
    }
    
    //
    // set all the TDs active
    //
    ptrTD = ptrFirstTD;
    while(ptrTD) {
      SetTDStatusActiveorInactive(ptrTD, TRUE);
      ptrTD = ptrTD->ptrNextTD ;      
    }
    
    return ;
  }

  else if(((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE) 
            || ((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK))
  {
    // no update
    return;
  }
  // Have Errors
  else
  { 
    ptrTD = ptrFirstTD ;
    if(ErrTDPos != 0)   // not first TD error
    {
      //
      // get the last success TD
      //
      for( i = 1 ; i < ErrTDPos ; i ++) {
        ptrTD = ptrTD->ptrNextTD ;
      }

      //
      // update Data Toggle in the interrupt list node
      //
      ptrList->DataToggle = GetTDTokenDataToggle(ptrTD);

      //
      // get the error TD
      //
      ptrTD = ptrTD->ptrNextTD ;

    } else {
      ptrList->DataToggle = GetTDTokenDataToggle(ptrTD);
    }
    //
    // do not restore the QH's vertical link pointer,
    // let the callback function do the rest of error handling.
    //
    return;
  }
}

VOID
ClearTDStatus(
  IN  TD_STRUCT *ptrTD
  )
{
  //
  // clear all the status bit in TD.
  //
  if(!ptrTD) {
    return ;
  }
  
  ptrTD->TDData.TDStatus = 0 ;
  return ;
}


VOID
ReleaseInterruptList(
  IN  USB_HC_DEV      *HcDev,
  IN  EFI_LIST_ENTRY  *ListHead
  )
{
  EFI_LIST_ENTRY  *Link;
  EFI_LIST_ENTRY  *SavedLink;
  INTERRUPT_LIST  *pNode;
  TD_STRUCT       *ptrTD;
  TD_STRUCT       *ptrNextTD;
  QH_STRUCT       *ptrQH; 
  QH_STRUCT       *SavedQH;
  
  if (ListHead == NULL) {
    return;
  }
  
  Link = ListHead;
  
  //
  // Free all the resources in the interrupt list
  //
  SavedLink = Link->ForwardLink;
  while (!IsListEmpty (ListHead)) {
    
    Link = SavedLink;
    
    SavedLink = Link->ForwardLink;
    
    pNode = INTERRUPT_LIST_FROM_LINK(Link);
    
    RemoveEntryList (&pNode->Link);
    
    SavedQH = pNode->ptrQH;
    for (ptrQH = SavedQH;ptrQH != NULL;ptrQH = SavedQH) {
      SavedQH = ptrQH->ptrNextIntQH;
      UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
    }

    ptrTD = pNode->ptrFirstTD ;
    while (!ptrTD) {
      
      ptrNextTD = ptrTD->ptrNextTD ;
      UhciFreePool(HcDev,(UINT8*)ptrTD,sizeof(TD_STRUCT));
      ptrTD = ptrNextTD ;     
    }
    
    gBS->FreePool(pNode);
  }
}


EFI_STATUS
InitializeMemoryManagement (
  USB_HC_DEV           *HcDev
  )
{
  MEMORY_MANAGE_HEADER    *MemoryHeader;
  EFI_STATUS              Status;
  UINTN                   MemPages;
  
  MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
  Status = CreateMemoryBlock (HcDev,&MemoryHeader,MemPages);
  if (EFI_ERROR(Status)) {
    return Status;
  }
  
  HcDev->MemoryHeader = MemoryHeader;  

  return EFI_SUCCESS;
}

EFI_STATUS
CreateMemoryBlock (
  USB_HC_DEV            *HcDev,
  MEMORY_MANAGE_HEADER  **MemoryHeader,
  UINTN                 MemoryBlockSizeInPages
  )
/*
  Use PciIo->AllocateBuffer to allocate common buffer for the memory block,
  and use PciIo->Map to map the common buffer for Bus Master Read/Write.
*/
{
  EFI_STATUS              Status;
  VOID                    *CommonBuffer;
  EFI_PHYSICAL_ADDRESS    MappedAddress;
  UINTN                   MemoryBlockSizeInBytes;
  void                    *Mapping;
  
  //
  // Allocate memory for MemoryHeader
  //
  Status = gBS->AllocatePool (EfiBootServicesData, sizeof(MEMORY_MANAGE_HEADER),MemoryHeader);
  if (EFI_ERROR(Status)) {
    return Status;
  }
  EfiZeroMem (*MemoryHeader,sizeof(MEMORY_MANAGE_HEADER));
  
  (*MemoryHeader)->Next = NULL;
  
  //
  // set Memory block size
  //
  (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);
  
  //
  // each bit in Bit Array will manage 32 bytes memory in memory block
  //
  (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
  
  //
  // Allocate memory for BitArray
  //
  Status = gBS->AllocatePool (EfiBootServicesData, 
                              (*MemoryHeader)->BitArraySizeInBytes,
                              &((*MemoryHeader)->BitArrayPtr)
                              );
  if (EFI_ERROR(Status)) {
    gBS->FreePool (*MemoryHeader);
    return Status;
  }
  EfiZeroMem ((*MemoryHeader)->BitArrayPtr,(*MemoryHeader)->BitArraySizeInBytes);
  
  //
  // Memory Block uses MemoryBlockSizeInPages pages,
  // and it is allocated as common buffer use.
  //  
  Status = HcDev->PciIo->AllocateBuffer (
                             HcDev->PciIo,
                             AllocateAnyPages,
                             EfiBootServicesData,
                             MemoryBlockSizeInPages,
                             &CommonBuffer,
                             0
                             );
  if (EFI_ERROR(Status)) {
    gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
    gBS->FreePool (*MemoryHeader);
    return Status;
  }
  
  MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE(MemoryBlockSizeInPages);
  Status = HcDev->PciIo->Map (HcDev->PciIo,
                              EfiPciIoOperationBusMasterCommonBuffer,
                              CommonBuffer,
                              &MemoryBlockSizeInBytes,
                              &MappedAddress,
                              &Mapping
                              );
  //
  // if returned Mapped size is less than the size we request,do not support.
  //
  if (EFI_ERROR(Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE(MemoryBlockSizeInPages))) {
    HcDev->PciIo->FreeBuffer (HcDev->PciIo,MemoryBlockSizeInPages,CommonBuffer);
    gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
    gBS->FreePool (*MemoryHeader);
    return EFI_UNSUPPORTED;
  }
  //
  // Set Memory block initial address
  //
  (*MemoryHeader)->MemoryBlockPtr = (UINT8*)((UINTN)MappedAddress);
  (*MemoryHeader)->Mapping = Mapping;  
  
  EfiZeroMem (
        (*MemoryHeader)->MemoryBlockPtr,
        EFI_PAGES_TO_SIZE(MemoryBlockSizeInPages)
        ); 
  
  return EFI_SUCCESS;
}

EFI_STATUS
FreeMemoryHeader (
  USB_HC_DEV            *HcDev,
  MEMORY_MANAGE_HEADER  *MemoryHeader
  )
{
  if ((MemoryHeader == NULL) || (HcDev == NULL)) {
    return EFI_INVALID_PARAMETER;
  }
  
  //
  // unmap the common buffer used by the memory block
  //
  HcDev->PciIo->Unmap (HcDev->PciIo,MemoryHeader->Mapping);
  
  //
  // free common buffer
  //
  HcDev->PciIo->FreeBuffer (
                      HcDev->PciIo,
                      EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),
                      MemoryHeader->MemoryBlockPtr
                      );
  //
  // free bit array
  //
  gBS->FreePool (MemoryHeader->BitArrayPtr);
  //
  // free memory header
  //
  gBS->FreePool (MemoryHeader);
  
  return EFI_SUCCESS;
}

EFI_STATUS
UhciAllocatePool (
  USB_HC_DEV      *HcDev,
  UINT8           **Pool,
  UINTN           AllocSize
  )
{
  MEMORY_MANAGE_HEADER    *MemoryHeader;
  MEMORY_MANAGE_HEADER    *TempHeaderPtr;
  MEMORY_MANAGE_HEADER    *NewMemoryHeader;
  UINTN                   RealAllocSize;
  UINTN                   MemoryBlockSizeInPages;
  EFI_STATUS              Status;
  
  *Pool = NULL;
  
  MemoryHeader = HcDev->MemoryHeader;

  //
  // allocate unit is 32 bytes (align on 32 byte)
  //
  if (AllocSize % 32) {
    RealAllocSize = (AllocSize / 32 + 1) * 32;
  } else {
    RealAllocSize = AllocSize;
  }
  
  //
  // There may be linked MemoryHeaders.
  // To allocate a free pool in Memory blocks,
  // must search in the MemoryHeader link list
  // until enough free pool is found.
  //
  Status = EFI_NOT_FOUND;
  for (TempHeaderPtr = MemoryHeader;TempHeaderPtr != NULL;
      TempHeaderPtr = TempHeaderPtr->Next) {
    
    Status

⌨️ 快捷键说明

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