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

📄 uhci.c

📁 Next BIOS Source code : Extensible Firmware Interface
💻 C
📖 第 1 页 / 共 5 页
字号:
  return EFI_SUCCESS ;
}    

EFI_STATUS
UHCIControlTransfer (
  IN  EFI_USB_HC_PROTOCOL    *This,
  IN  UINT8                  DeviceAddress,
  IN  BOOLEAN                IsSlowDevice,
  IN  UINT8                  MaximumPacketLength,
  IN  EFI_USB_DEVICE_REQUEST *Request,
  IN  EFI_USB_DATA_DIRECTION TransferDirection,
  IN  OUT VOID               *Data                 OPTIONAL,
  IN  OUT UINTN              *DataLength           OPTIONAL,  
  IN  UINTN                  TimeOut,
  OUT UINT32                 *TransferResult
  )
/*++
  
  Routine Description:
    Submits control transfer to a target USB device.
  
  Arguments:
    
    This          A pointer to the EFI_USB_HC_PROTOCOL instance.

    DeviceAddress Represents the address of the target device on the USB,
                  which is assigned during USB enumeration.

    IsSlowDevice  Indicates whether the target device is slow device 
                  or full-speed device.
    
    MaximumPacketLength Indicates the maximum packet size that the 
                        default control transfer endpoint is capable of 
                        sending or receiving.
    
    Request       A pointer to the USB device request that will be sent 
                  to the USB device. 
    
    TransferDirection Specifies the data direction for the transfer.
                      There are three values available, DataIn, DataOut 
                      and NoData.
    
    Data          A pointer to the buffer of data that will be transmitted 
                  to USB device or received from USB device.
    
    DataLength    Indicates the size, in bytes, of the data buffer 
                  specified by Data.
    
    TimeOut       Indicates the maximum time, in microseconds, 
                  which the transfer is allowed to complete.
    
    TransferResult  A pointer to the detailed result information generated 
                    by this control transfer.
                    
  Returns:
    EFI_SUCCESS 
        The control transfer was completed successfully.
    EFI_OUT_OF_RESOURCES  
        The control transfer could not be completed due to a lack of resources.
    EFI_INVALID_PARAMETER 
        Some parameters are invalid.
    EFI_TIMEOUT 
        The control transfer failed due to timeout.
    EFI_DEVICE_ERROR  
        The control transfer failed due to host controller or device error. 
        Caller should check TranferResult for detailed error information.

--*/
{
  USB_HC_DEV    *HcDev;
  UINT32        StatusReg;
  UINT32        FrameNumReg;
  UINT8         PktID;
  QH_STRUCT     *ptrQH;
  TD_STRUCT     *ptrTD;
  TD_STRUCT     *ptrPreTD;
  TD_STRUCT     *ptrSetupTD;
  TD_STRUCT     *ptrStatusTD;
  EFI_STATUS    Status;  
  UINTN         i;
  UINTN         DataLen;
  UINT8         *ptrDataSource;
  UINT8         *ptr;
  UINT8         DataToggle;
  UINT16        LoadFrameListIndex;
  UINT8         pktsize;
  
  UINT8         *RequestMappedAddress = NULL;
  VOID          *RequestMapping = NULL;
  UINTN         RequestLen;
  
  EFI_PHYSICAL_ADDRESS    TempPtr;
  VOID                    *Mapping = NULL;
  
  TD_STRUCT     *ptrFirstDataTD = NULL;
  TD_STRUCT     *ptrLastDataTD = NULL;
  BOOLEAN       FirstTD = FALSE;
  
  PktID       = INPUT_PACKET_ID;
  Mapping     = NULL;  
  HcDev       = USB_HC_DEV_FROM_THIS(This);  
  StatusReg   = (UINT32)(USBSTS);
  FrameNumReg = (UINT32)(USBFRNUM);
  ptrPreTD    = NULL;
  ptrTD       = NULL;
  
  //
  // Parameters Checking
  //
  
  if (Request == NULL || TransferResult == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  
  //
  // if errors exist that cause host controller halt, 
  // then return EFI_DEVICE_ERROR.
  //
  if(IsHCHalted(HcDev->PciIo,StatusReg)       || 
     IsHCProcessErr(HcDev->PciIo,StatusReg)   ||
     IsHostSysErr(HcDev->PciIo,StatusReg)) {      
    
    ClearStatusReg(HcDev->PciIo,StatusReg);
    *TransferResult = EFI_USB_ERR_SYSTEM;
    return EFI_DEVICE_ERROR;
  }
  
  //
  // low speed usb devices are limited to only an eight-byte 
  // maximum data payload size
  //
  if (IsSlowDevice && (MaximumPacketLength != 8)) {
    return EFI_INVALID_PARAMETER;
  }
  
  if (MaximumPacketLength != 8 && MaximumPacketLength != 16 
      && MaximumPacketLength != 32 && MaximumPacketLength != 64) {
    return EFI_INVALID_PARAMETER;
  }
  
  if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) {
    return EFI_INVALID_PARAMETER;
  }
  
  switch(TransferDirection) {
    
    case EfiUsbDataIn:
      PktID         = INPUT_PACKET_ID;
      ptrDataSource = Data;
      DataLen       = *DataLength;
      
      //
      // map the source data buffer for bus master access.
      // BusMasterWrite means cpu read
      //
      Status = HcDev->PciIo->Map (
                        HcDev->PciIo,
                        EfiPciIoOperationBusMasterWrite,
                        ptrDataSource,
                        &DataLen,
                        &TempPtr,
                        &Mapping
                        );
      if (EFI_ERROR(Status)) {
        return Status;
      }
      ptr = (UINT8*)((UINTN)TempPtr);
      break;
      
    case EfiUsbDataOut:
      PktID         = OUTPUT_PACKET_ID;
      ptrDataSource = Data;
      DataLen       = *DataLength;
      
      //
      // map the source data buffer for bus master access.
      // BusMasterRead means cpu write
      //
      Status = HcDev->PciIo->Map (HcDev->PciIo,
                        EfiPciIoOperationBusMasterRead,
                        ptrDataSource,
                        &DataLen,
                        &TempPtr,
                        &Mapping
                        );
      if (EFI_ERROR(Status)) {
        return Status;
      }
      ptr = (UINT8*)((UINTN)TempPtr);
      break;

    //
    // no data stage
    //
    case EfiUsbNoData:
      if ((DataLength != NULL) && (*DataLength != 0) ) {
        return EFI_INVALID_PARAMETER;
      }
      PktID         = OUTPUT_PACKET_ID;
      ptrDataSource = NULL;
      DataLen       = 0;
      ptr           = NULL;
      break;
      
    default:
      return EFI_INVALID_PARAMETER;      
  }
  
  ClearStatusReg(HcDev->PciIo,StatusReg);
  
  //  
  // create QH structure and init
  //
  Status = CreateQH(HcDev,&ptrQH);
  if(EFI_ERROR(Status)) {
    HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
    return Status;
  }
  
  //
  // map the Request for bus master access.
  // BusMasterRead means cpu write
  //
  
  RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);
  Status = HcDev->PciIo->Map (HcDev->PciIo,
                     EfiPciIoOperationBusMasterRead,
                     (UINT8*)Request,
                     &RequestLen,
                     &TempPtr,
                     &RequestMapping
                     );
  if (EFI_ERROR(Status)) {
    HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
    UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
    return Status;
  }
  RequestMappedAddress = (UINT8*)((UINTN)TempPtr);
  
  //
  // generate Setup Stage TD
  //
  
  Status = GenSetupStageTD(HcDev,DeviceAddress,0,
                  IsSlowDevice, (UINT8*)RequestMappedAddress, 
                  sizeof(EFI_USB_DEVICE_REQUEST), &ptrSetupTD);
  if (EFI_ERROR(Status)) {
    HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
    UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
    HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
    return Status;
  }  
  
  //
  //  Data Stage of Control Transfer
  //   
  DataToggle = 1;
  FirstTD = TRUE;
  while(DataLen > 0) {
    //
    // create TD structures and link together
    //    
    
    //
    // pktsize is the data load size that each TD carries. 
    //
    pktsize = (UINT8)DataLen;
    if (DataLen > MaximumPacketLength) {
      pktsize = MaximumPacketLength;
    }
    Status = GenDataTD(HcDev,DeviceAddress, 0, ptr, pktsize, PktID, DataToggle, IsSlowDevice,&ptrTD);
    if (EFI_ERROR(Status)) {
      //
      // free all resources occupied
      //
      HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
      UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
      HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
      DeleteQueuedTDs (HcDev, ptrSetupTD);
      DeleteQueuedTDs (HcDev,ptrFirstDataTD);
      return Status;
    }
    
    //
    // Link two TDs in vertical depth
    //
    if (FirstTD) {
      ptrFirstDataTD            = ptrTD ;
      ptrFirstDataTD->ptrNextTD = NULL;
      FirstTD = FALSE;
    } else {
      LinkTDToTD(ptrPreTD,ptrTD);      
    }
    ptrPreTD = ptrTD;
    
    DataToggle ^= 1;
    ptr += pktsize;
    DataLen -= pktsize;
  }
  ptrLastDataTD = ptrTD;
  
  
  //
  // Status Stage of Control Transfer
  //
  if(PktID == OUTPUT_PACKET_ID) {
    PktID = INPUT_PACKET_ID;
  } else {
    PktID = OUTPUT_PACKET_ID;
  }
  
  //
  // create Status Stage TD structure
  //
  Status = CreateStatusTD(HcDev,DeviceAddress,0,PktID,IsSlowDevice,&ptrStatusTD);
  if (EFI_ERROR(Status)) {
    HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
    UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
    HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
    DeleteQueuedTDs (HcDev, ptrSetupTD);
    DeleteQueuedTDs (HcDev,ptrFirstDataTD);
    return Status;
  }
  
  if (IsSlowDevice) {
    //
    // link setup TD structures to QH structure
    //
    LinkTDToQH(ptrQH,ptrSetupTD);
    
    LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
  
    //
    // link QH-TDs to total 50 frame list entry to speed up the execution.
    //
    for(i = 0; i < 100; i ++) {
      LinkQHToFrameList(HcDev->FrameListEntry,
                        (UINT16)((LoadFrameListIndex + i) % 1024),
                         ptrQH) ;
    }
  
    //
    // Poll QH-TDs execution and get result.
    // detail status is returned
    //
    Status = ExecuteControlTransfer (HcDev,ptrSetupTD,
                                      LoadFrameListIndex,DataLength,
                                      TimeOut,TransferResult);
    //
    // Remove Control Transfer QH-TDs structure from the frame list
    // and update the pointers in the Frame List
    // and other pointers in other related QH structures.
    //
    for (i = 0; i < 100; i ++) {
      DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
    }
    //
    // delete setup stage TD; the QH is reserved for the next stages.
    //
    DeleteQueuedTDs (HcDev,ptrSetupTD);
    
    //
    // some control transfers do not have Data Stage
    //
    if (ptrFirstDataTD != NULL) {
    
      LinkTDToQH (ptrQH,ptrFirstDataTD);
      LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
    
      for(i = 0; i < 500; i ++) {
        LinkQHToFrameList(HcDev->FrameListEntry,
                          (UINT16)((LoadFrameListIndex + i) % 1024),
                           ptrQH) ;
      }
    
      Status = ExecuteControlTransfer (HcDev,ptrFirstDataTD,
                                        LoadFrameListIndex,DataLength,
                                        TimeOut,TransferResult);
    
      for (i = 0; i < 500; i ++) {
        DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
      }
      //
      // delete data stage TD; the QH is reserved for the next stage.
      //
      DeleteQueuedTDs (HcDev,ptrFirstDataTD);
    }
    
    LinkTDToQH(ptrQH,ptrStatusTD);  
    //
    // get the frame list index that the QH-TDs will be linked to.
    //  
    LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
  
    for(i = 0; i < 100; i ++) {
      
      //
      // put the QH-TDs directly or indirectly into the proper place 
      // in the Frame List 
      //
      LinkQHToFrameList(HcDev->FrameListEntry,
                        (UINT16)((LoadFrameListIndex + i) % 1024),
                         ptrQH) ;
    }
  
    //
    // Poll QH-TDs execution and get result.
    // detail status is returned
    //
    Status = ExecuteControlTransfer (HcDev,ptrStatusTD,
                                      LoadFrameListIndex,DataLength,
                                      TimeOut,TransferResult);
  
    //
    // Delete Control Transfer QH-TDs structure
    // and update the pointers in the Frame List
    // and other pointers in other related QH structures.
    //
    // TRUE means must search other framelistindex
    //
    for (i = 0; i < 100; i ++) {
      DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
    }
    DeleteQueuedTDs (HcDev,ptrStatusTD);
    
  } else {    
    //
    // link setup stage TD with data stage TD
    //
    ptrPreTD = ptrSetupTD;
    if (ptrFirstDataTD != NULL) {
      LinkTDToTD (ptrSetupTD, ptrFirstDataTD);
      ptrPreTD = ptrLastDataTD;
    }
    
    //
    // link status TD with previous TD
    //
    LinkTDToTD (ptrPreTD, ptrStatusTD);
    
    //
    // link QH with TD
    //
    LinkTDToQH (ptrQH, ptrSetupTD);
    
    LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
    for(i = 0; i < 500; i ++) {
    
      //
      // put the QH-TDs directly or indirectly into the proper place 
      // in the Frame List 
      //
      LinkQHToFrameList(HcDev->FrameListEntry,
                        (UINT16)((LoadFrameListIndex + i) % 1024),
                         ptrQH) ;
    }
    
    //
    // Poll QH-TDs execution and get result.
    // detail status is returned
    //
    Status = ExecuteControlTransfer (HcDev,ptrSetupTD,
                                      LoadFrameListIndex,DataLength,
                                      TimeOut,TransferResult);
    //
    // Remove Control Transfer QH-TDs structure from the frame list

⌨️ 快捷键说明

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