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

📄 uhci.c

📁 Next BIOS Source code : Extensible Firmware Interface
💻 C
📖 第 1 页 / 共 5 页
字号:
    // and update the pointers in the Frame List
    // and other pointers in other related QH structures.
    //
    for (i = 0; i < 500; i ++) {
      DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
    }    
    DeleteQueuedTDs (HcDev,ptrSetupTD);
  }
  
  UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
  
  if (Mapping != NULL) {
    HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
  }
  
  if (RequestMapping != NULL) {
    HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
  }
  //
  // if has errors that cause host controller halt, 
  // then return EFI_DEVICE_ERROR directly.
  //
  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;
  }
  
  ClearStatusReg(HcDev->PciIo,StatusReg);
  
  return Status ;
}

EFI_STATUS
UHCIBulkTransfer (
  IN  EFI_USB_HC_PROTOCOL    *This,
  IN  UINT8                  DeviceAddress,
  IN  UINT8                  EndPointAddress,
  IN  UINT8                  MaximumPacketLength,
  IN OUT VOID                *Data,
  IN OUT UINTN               *DataLength,  
  IN OUT UINT8               *DataToggle,
  IN  UINTN                  TimeOut,
  OUT UINT32                 *TransferResult
  )
/*++
  
  Routine Description:
    Submits bulk transfer to a bulk endpoint of a 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.
    EndPointAddress   The combination of an endpoint number and an 
                      endpoint direction of the target USB device. 
                      Each endpoint address supports data transfer in 
                      one direction except the control endpoint 
                      (whose default endpoint address is 0). 
                      It is the caller's responsibility to make sure that 
                      the EndPointAddress represents a bulk endpoint. 
                      
    MaximumPacketLength Indicates the maximum packet size the target endpoint
                        is capable of sending or receiving.
                        
    Data          A pointer to the buffer of data that will be transmitted 
                  to USB device or received from USB device.
    DataLength    When input, indicates the size, in bytes, of the data buffer
                  specified by Data. When output, indicates the actually 
                  transferred data size.
                  
    DataToggle    A pointer to the data toggle value. On input, it indicates 
                  the initial data toggle value the bulk transfer should adopt;
                  on output, it is updated to indicate the data toggle value 
                  of the subsequent bulk transfer. 
                  
    TimeOut       Indicates the maximum time, in microseconds, which the 
                  transfer is allowed to complete.
                  
    TransferResult  A pointer to the detailed result information of the 
                    bulk transfer.

  Returns:
    EFI_SUCCESS 
        The bulk transfer was completed successfully.
    EFI_OUT_OF_RESOURCES  
        The bulk transfer could not be submitted due to lack of resource.
    EFI_INVALID_PARAMETER 
        Some parameters are invalid.
    EFI_TIMEOUT 
        The bulk transfer failed due to timeout.
    EFI_DEVICE_ERROR  
        The bulk 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;        
  UINTN                   DataLen;            
  QH_STRUCT               *ptrQH ;            
  TD_STRUCT               *ptrFirstTD;        
  TD_STRUCT               *ptrTD;             
  TD_STRUCT               *ptrPreTD;          
  UINT16                  LoadFrameListIndex; 
  UINT16                  SavedFrameListIndex;
  UINT8                   PktID;              
  UINT8                   *ptrDataSource;     
  UINT8                   *ptr;               
  BOOLEAN                 IsFirstTD;          
  EFI_STATUS              Status ;            
  UINT32                  i;
  UINT8                   pktsize;
                                          
  EFI_USB_DATA_DIRECTION TransferDirection;
  //
  //  Used to calculate how many entries are linked to the 
  //  specified bulk transfer QH-TDs 
  //
  UINT32                  LinkTimes;
  
  BOOLEAN                 ShortPacketEnable;  
  EFI_PHYSICAL_ADDRESS    TempPtr;
  VOID                    *Mapping;
  
  HcDev             = USB_HC_DEV_FROM_THIS(This);  
  StatusReg         = (UINT32)(USBSTS);
  FrameNumReg       = (UINT32)(USBFRNUM);
  PktID             = INPUT_PACKET_ID;
  ptrTD             = NULL;
  ptrFirstTD        = NULL;
  ptrPreTD          = NULL;
  LinkTimes         = 1;
  DataLen           = 0;
  ptr               = NULL;  
  ShortPacketEnable = FALSE;
  Mapping           = NULL;  
  
  //
  // Parameters Checking
  //
  
  if ((DataLength == NULL) || (Data == NULL) 
      || (TransferResult == NULL)) {
    return EFI_INVALID_PARAMETER;
  }
  
  //
  // if has errors that cause host controller halt, 
  // then return EFI_DEVICE_ERROR directly.
  //
  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;
  }
  
  if (*DataLength == 0) {
    return EFI_INVALID_PARAMETER;
  }
  
  if ((*DataToggle != 1) && (*DataToggle != 0)) {
    return EFI_INVALID_PARAMETER;
  } 
  
  if(MaximumPacketLength != 8 && MaximumPacketLength != 16 
      && MaximumPacketLength != 32 && MaximumPacketLength != 64) {
    return EFI_INVALID_PARAMETER;
  }
  
  //
  // Enable the maximum packet size (64bytes)
  // that can be used for full speed bandwidth reclamation 
  // at the end of a frame.
  //
  EnableMaxPacketSize (HcDev);  
  
  ClearStatusReg(HcDev->PciIo,StatusReg);

  //
  // construct QH and TD data structures,
  // and link them together
  //
  if (EndPointAddress & 0x80) {
    TransferDirection = EfiUsbDataIn;
  } else {
    TransferDirection = EfiUsbDataOut;
  }
  
  switch(TransferDirection) {
    
    case EfiUsbDataIn:
      ShortPacketEnable = TRUE;
      PktID             = INPUT_PACKET_ID;  
      ptrDataSource     = Data;
      DataLen           = *DataLength;
      
      //
      // 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;
      
      //
      // 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;
      
    default:
      return EFI_INVALID_PARAMETER;
  }
  
  //
  //  create QH structure and init
  //
  Status = CreateQH(HcDev,&ptrQH);
  if(EFI_ERROR(Status)) {
    HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
    return Status;
  }
  
  //
  // i is used to calculate the total number of TDs.
  //
  i = 0;
  
  IsFirstTD = TRUE ;
  while(DataLen > 0) {
    
    //
    // create TD structures and link together 
    //
    
    pktsize = (UINT8)DataLen;
    if(DataLen > MaximumPacketLength) {
      pktsize = MaximumPacketLength;
    }
    
    Status = GenDataTD(HcDev,DeviceAddress,EndPointAddress, ptr, 
                       pktsize, PktID, *DataToggle, FALSE,&ptrTD);
    if (EFI_ERROR(Status)) {
      HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
      UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
      DeleteQueuedTDs (HcDev,ptrFirstTD);
      return Status;
    }
    
    //
    // Enable short packet detection. 
    // (default action is disabling short packet detection)
    //
    if(ShortPacketEnable) {
      EnableorDisableTDShortPacket (ptrTD, TRUE) ;
    }
    
    if(IsFirstTD) {
      ptrFirstTD            = ptrTD ;
      ptrFirstTD->ptrNextTD = NULL;
      IsFirstTD             = FALSE ;
    } else {    
      //
      // Link two TDs in vertical depth
      //
      LinkTDToTD(ptrPreTD,ptrTD) ;
    }
    
    i ++ ;
    
    ptrPreTD = ptrTD ;      
    
    *DataToggle ^= 1;
    ptr += pktsize;
    DataLen -= pktsize;
  }
  
  //
  // link TD structures to QH structure
  //
  LinkTDToQH(ptrQH,ptrFirstTD);
  
  //
  // calculate how many entries are linked to the specified bulk transfer QH-TDs 
  // the below values are referred to the USB spec revision1.1.
  //
  switch(MaximumPacketLength) {
    case 8:
      LinkTimes = i / 71 + 1;
      break;
    case 16:
      LinkTimes = i / 51 + 1;
      break;
    case 32:
      LinkTimes = i / 33 + 1;
      break;
    case 64:
      LinkTimes = i / 19 + 1;
      break;
  }
  LinkTimes += 500;   // redundant
  
  //
  // put QH-TDs into  Frame list
  //

  LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
  SavedFrameListIndex = LoadFrameListIndex;

  for(i = 0; i <= LinkTimes ; i ++) {
    
    //
    // put the QH-TD directly or indirectly into the proper place 
    // in the Frame List 
    //
    LinkQHToFrameList(HcDev->FrameListEntry,LoadFrameListIndex,ptrQH) ;

    LoadFrameListIndex += 1 ;
    LoadFrameListIndex %= 1024 ;
  }
  
  LoadFrameListIndex = SavedFrameListIndex;
  
  //
  // Execute QH-TD and get result
  //
  //
  // detail status is put into the Result field in the pIRP
  // the Data Toggle value is also re-updated to the value
  // of the last successful TD
  //
  Status = ExecBulkorSyncInterruptTransfer (HcDev,ptrFirstTD,
                                                LoadFrameListIndex,DataLength,
                                                DataToggle,TimeOut,TransferResult);

  //
  // Delete Bulk transfer QH-TD structure
  // and maitain the pointers in the Frame List
  // and other pointers in related QH structure
  //
  // TRUE means must search other framelistindex
  //
  for(i = 0; i <= LinkTimes ; i ++) {
    DelLinkSingleQH (HcDev,ptrQH,LoadFrameListIndex,FALSE,FALSE);
    LoadFrameListIndex += 1;
    LoadFrameListIndex %= 1024 ;
  }
  
  UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
  
  DeleteQueuedTDs (HcDev,ptrFirstTD);
  
  if (Mapping != NULL) {
    HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
  }
  
  //
  // if has errors that cause host controller halt, 
  // then return EFI_DEVICE_ERROR directly.
  //
  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;
  }
  
  ClearStatusReg(HcDev->PciIo,StatusReg);
  
  return Status ;  
}

EFI_STATUS
UHCIAsyncInterruptTransfer (
  IN  EFI_USB_HC_PROTOCOL               *This,
  IN  UINT8                             DeviceAddress,
  IN  UINT8                             EndPointAddress,
  IN  BOOLEAN                           IsSlowDevice,
  IN  UINT8                             MaxiumPacketLength,
  IN  BOOLEAN                           IsNewTransfer,
  IN OUT UINT8                          *DataToggle,
  IN  UINTN                             PollingInterval  OPTIONAL,
  IN  UINTN                             DataLength       OPTIONAL,
  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK   CallBackFunction OPTIONAL,
  IN  VOID                              *Context         OPTIONAL  
  )
/*++
  
  Routine Description:
    Submits an asynchronous interrupt transfer to an 
    interrupt endpoint of a 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.
                    
    EndPointAddress The combination of an endpoint number and an endpoint 
                    direction of the target USB device. Each endpoint address 
                    supports data transfer in one direction except the 
                    control endpoint (whose default endpoint address is 0). 
                    It is the caller's responsibility to make sure that 
                    the EndPointAddress represents an interrupt endpoint.
                    
    IsSlowDevice    Indicates whether the target device is slow device 
                    or full-speed device.
                    
    MaxiumPacketLength  Indicates the maximum packet size the target endpoint
                        is capable of sending or receiving.
                        
    IsNewTransfer   If TRUE, an asynchronous interrupt pipe is built between
                    the host and the target interrupt endpoint. 
                    If FALSE, the specified asynchronous interrupt pipe 
                    is canceled.
                    
    DataToggle      A pointer to the data toggle value.  On input, it is valid 
                    when IsNewTransfer is TRUE, and it indicates the initial 
                    data toggle value the asynchronous interrupt transfer 
                    should adopt.  
                    On output, it is valid when IsNewTransfer is FALSE, 
                    and it is updated to indicate the data toggle value of 
                    the subsequent asynchronous interrupt transfer.
                    
    PollingInterval Indicates the interval, in milliseconds, that the 
                    asynchronous interrupt transfer is polled.  
                    This parameter is required when IsNewTransfer is TRUE.
                    
    DataLength      Indicates the length of data to be r

⌨️ 快捷键说明

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