ehci.c

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

C
2,436
字号
        Status = EFI_DEVICE_ERROR;
        goto exit;
      }
    }
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg |= PORTSC_PR;
    //
    // Set one to PortReset bit must also set zero to PortEnable bit
    //
    PortStatusControlReg &= ~PORTSC_PED;
    break;

  case EfiUsbPortPower:

    //
    // No support, no operation
    //
    goto exit;

  case EfiUsbPortOwner:

    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg |= PORTSC_PO;
    break;

  default:

    Status = EFI_INVALID_PARAMETER;
    goto exit;
  }

  Status = WriteEhcOperationalReg (
             HcDev,
             PortStatusControlAddr,
             PortStatusControlReg
             );
  if (EFI_ERROR (Status)) {
    Status = EFI_DEVICE_ERROR;
  }

exit:
  return Status;
}

EFI_STATUS
EFIAPI
EhciClearRootHubPortFeature (
  IN  EFI_USB2_HC_PROTOCOL     *This,
  IN  UINT8                    PortNumber,
  IN  EFI_USB_PORT_FEATURE     PortFeature
  )
/*++

  Routine Description:

    Clears a feature for the specified root hub port.

  Arguments:

    This        - A pointer to the EFI_USB2_HC_PROTOCOL instance.
    PortNumber  - Specifies the root hub port whose feature
                  is requested to be cleared.
    PortFeature - Indicates the feature selector associated with the
                  feature clear request.

  Returns:

    EFI_SUCCESS
        The feature specified by PortFeature was cleared for the
        USB root hub port specified by PortNumber.
    EFI_INVALID_PARAMETER
        PortNumber is invalid or PortFeature is invalid.
    EFI_DEVICE_ERROR
        Can't read register

--*/
{
  EFI_STATUS  Status;
  USB2_HC_DEV *HcDev;
  UINT32      PortStatusControlAddr;
  UINT32      PortStatusControlReg;
  UINT8       MaxSpeed;
  UINT8       TotalPortNumber;
  UINT8       Is64BitCapable;

  EhciGetCapability (
    This,
    &MaxSpeed,
    &TotalPortNumber,
    &Is64BitCapable
    );

  if (PortNumber >= TotalPortNumber) {
    Status = EFI_INVALID_PARAMETER;
    goto exit;
  }

  HcDev                 = USB2_HC_DEV_FROM_THIS (This);
  PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNumber));

  Status = ReadEhcOperationalReg (
             HcDev,
             PortStatusControlAddr,
             &PortStatusControlReg
             );
  if (EFI_ERROR (Status)) {
    Status = EFI_DEVICE_ERROR;
    goto exit;
  }

  switch (PortFeature) {

  case EfiUsbPortEnable:

    //
    // Clear PORT_ENABLE feature means disable port.
    //
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg &= ~PORTSC_PED;
    break;

  case EfiUsbPortSuspend:

    //
    // A write of zero to this bit is ignored by the host controller.
    // The host controller will unconditionally set this bit to a zero when:
    //   1. software sets the Forct Port Resume bit to a zero from a one.
    //   2. software sets the Port Reset bit to a one frome a zero.
    //
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg &= ~PORTSC_FPR;
    break;

  case EfiUsbPortReset:

    //
    // Clear PORT_RESET means clear the reset signal.
    //
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg &= ~PORTSC_PR;
    break;

  case EfiUsbPortPower:

    //
    // No support, no operation
    //
    goto exit;

  case EfiUsbPortOwner:

    //
    // Clear port owner means this port owned by EHC
    //
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg &= ~PORTSC_PO;
    break;

  case EfiUsbPortConnectChange:

    //
    // Clear connect status change
    //
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg |= PORTSC_CSC;
    break;

  case EfiUsbPortEnableChange:

    //
    // Clear enable status change
    //
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg |= PORTSC_PEDC;
    break;

  case EfiUsbPortSuspendChange:

    //
    // No related bit, no operation
    //
    goto exit;

  case EfiUsbPortOverCurrentChange:

    //
    // Clear PortOverCurrent change
    //
    PortStatusControlReg &= 0xffffffd5;
    PortStatusControlReg |= PORTSC_OCC;
    break;

  case EfiUsbPortResetChange:

    //
    // No related bit, no operation
    //
    goto exit;

  default:

    Status = EFI_INVALID_PARAMETER;
    goto exit;
  }

  Status = WriteEhcOperationalReg (
             HcDev,
             PortStatusControlAddr,
             PortStatusControlReg
             );
  if (EFI_ERROR (Status)) {
    Status = EFI_DEVICE_ERROR;
    goto exit;
  }

exit:
  return Status;
}

EFI_STATUS
EFIAPI
EhciControlTransfer (
  IN  EFI_USB2_HC_PROTOCOL                 *This,
  IN  UINT8                                DeviceAddress,
  IN  UINT8                                DeviceSpeed,
  IN  UINTN                                MaximumPacketLength,
  IN  EFI_USB_DEVICE_REQUEST               *Request,
  IN  EFI_USB_DATA_DIRECTION               TransferDirection,
  IN  OUT VOID                             *Data,
  IN  OUT UINTN                            *DataLength,
  IN  UINTN                                TimeOut,
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,
  OUT UINT32                               *TransferResult
  )
/*++

  Routine Description:

    Submits control transfer to a target USB device.

  Arguments:

    This            - A pointer to the EFI_USB2_HC_PROTOCOL instance.
    DeviceAddress   - Represents the address of the target device on the USB,
                      which is assigned during USB enumeration.
    DeviceSpeed     - Indicates target device speed.
    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.
    Translator      - A pointr to the transaction translator data.
    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.

--*/
{
  EFI_STATUS      Status;
  USB2_HC_DEV     *HcDev;
  UINT8           PktId;
  EHCI_QH_ENTITY  *QhPtr;
  EHCI_QTD_ENTITY *ControlQtdsPtr;
  UINT8           *DataCursor;
  VOID            *DataMap;
  UINT8           *RequestCursor;
  VOID            *RequestMap;

  QhPtr           = NULL;
  ControlQtdsPtr  = NULL;
  DataCursor      = NULL;
  DataMap         = NULL;
  RequestCursor   = NULL;
  RequestMap      = NULL;
  HcDev           = USB2_HC_DEV_FROM_THIS (This);

  //
  // Parameters Checking
  //
  if (TransferDirection != EfiUsbDataIn &&
    TransferDirection != EfiUsbDataOut &&
    TransferDirection != EfiUsbNoData
    ) {
    Status = EFI_INVALID_PARAMETER;
    goto exit;
  }

  if (EfiUsbNoData == TransferDirection) {
    if (NULL != Data || 0 != *DataLength) {
      Status = EFI_INVALID_PARAMETER;
      goto exit;
    }
  } else {
    if (NULL == Data || 0 == *DataLength) {
      Status = EFI_INVALID_PARAMETER;
      goto exit;
    }
  }

  if (Request == NULL || TransferResult == NULL) {
    Status = EFI_INVALID_PARAMETER;
    goto exit;
  }

  if (EFI_USB_SPEED_LOW == DeviceSpeed) {
    if (MaximumPacketLength != 8) {
      Status = EFI_INVALID_PARAMETER;
      goto exit;
    }
  } else if (MaximumPacketLength != 8 &&
           MaximumPacketLength != 16 &&
           MaximumPacketLength != 32 &&
           MaximumPacketLength != 64
          ) {
    Status = EFI_INVALID_PARAMETER;
    goto exit;
  }

  //
  // If errors exist that cause host controller halt,
  // then return EFI_DEVICE_ERROR.
  //
  if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
    ClearEhcAllStatus (HcDev);
    *TransferResult = EFI_USB_ERR_SYSTEM;
    Status          = EFI_DEVICE_ERROR;
    goto exit;
  }

  //
  // Map the Request for bus master access.
  // BusMasterRead means cpu write
  //
  Status = MapRequestBuffer (
             HcDev,
             Request,
             &RequestCursor,
             &RequestMap
             );
  if (EFI_ERROR (Status)) {
    *TransferResult = EFI_USB_ERR_SYSTEM;
    Status          = EFI_DEVICE_ERROR;
    goto exit;
  }

  //
  // Map the source data buffer for bus master access.
  //
  Status = MapDataBuffer (
             HcDev,
             TransferDirection,
             Data,
             DataLength,
             &PktId,
             &DataCursor,
             &DataMap
             );
  if (EFI_ERROR (Status)) {
    *TransferResult = EFI_USB_ERR_SYSTEM;
    Status          = EFI_DEVICE_ERROR;
    goto unmap_request;
  }

  //
  // Create and init control Qh
  //
  Status = CreateControlQh (
             HcDev,
             DeviceAddress,
             DeviceSpeed,
             MaximumPacketLength,
             Translator,
             &QhPtr
             );
  if (EFI_ERROR (Status)) {
    *TransferResult = EFI_USB_ERR_SYSTEM;
    Status          = EFI_OUT_OF_RESOURCES;
    goto unmap_data;
  }

  //
  // Create and init control Qtds
  //
  Status = CreateControlQtds (
             HcDev,
             PktId,
             RequestCursor,
             DataCursor,
             *DataLength,
             Translator,
             &ControlQtdsPtr
             );
  if (EFI_ERROR (Status)) {
    *TransferResult = EFI_USB_ERR_SYSTEM;
    Status          = EFI_OUT_OF_RESOURCES;
    goto destory_qh;
  }

  //
  // Link Qtds to Qh
  //
  LinkQtdToQh (QhPtr, ControlQtdsPtr);

  ClearEhcAllStatus (HcDev);

  //
  // Link Qh and Qtds to Async Schedule List
  //
  Status = LinkQhToAsyncList (HcDev, QhPtr);
  if (EFI_ERROR (Status)) {
    *TransferResult = EFI_USB_ERR_SYSTEM;
    Status          = EFI_DEVICE_ERROR;
    goto destory_qtds;
  }

  //
  // Poll Qh-Qtds execution and get result.
  // detail status is returned
  //
  Status = ExecuteTransfer (
             HcDev,
             TRUE,
             QhPtr,
             DataLength,
             0,
             TimeOut,
             TransferResult
             );
  if (EFI_ERROR (Status)) {
    goto destory_qtds;
  }

  //
  // If has errors that cause host controller halt,
  // then return EFI_DEVICE_ERROR directly.
  //
  if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
    *TransferResult |= EFI_USB_ERR_SYSTEM;
  }

  ClearEhcAllStatus (HcDev);

destory_qtds:
  UnlinkQhFromAsyncList (HcDev, QhPtr);
  DestoryQtds (HcDev, ControlQtdsPtr);
destory_qh:
  DestoryQh (HcDev, QhPtr);
unmap_data:
  HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);
unmap_request:
  HcDev->PciIo->Unmap (HcDev->PciIo, RequestMap);
exit:
  HcDev->PciIo->Flush (HcDev->PciIo);
  return Status;
}

EFI_STATUS
EFIAPI
EhciBulkTransfer (
  IN  EFI_USB2_HC_PROTOCOL                *This,
  IN  UINT8                               DeviceAddress,
  IN  UINT8                               EndPointAddress,
  IN  UINT8                               DeviceSpeed,
  IN  UINTN                               MaximumPacketLength,
  IN  UINT8                               DataBuffersNumber,
  IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],

⌨️ 快捷键说明

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