cbi0.c

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

C
1,088
字号
                  This->DriverBindingHandle,
                  ControllerHandle
                  );
  //
  // Free all allocated resources
  //
  if (UsbCbiDev->ControllerNameTable) {
    EfiLibFreeUnicodeStringTable (UsbCbiDev->ControllerNameTable);
  }

  gBS->FreePool (UsbCbiDev);

  return Status;
}


STATIC
EFI_STATUS
Cbi0RecoveryReset (
  IN  USB_CBI_DEVICE   *UsbCbiDev
  )
/*++

Routine Description:

  Cbi0 Recovery Reset routine

Arguments:

  UsbCbiDev - Cbi0RecoveryReset

Returns:

  EFI_SUCCESS - Success

--*/
{
  UINT8               ResetCommand[12];
  UINT8               Index;
  EFI_STATUS          Status;
  EFI_USB_IO_PROTOCOL *UsbIo;
  UINT8               EndpointAddress;
  UINT32              Result;
  UINT16              Timeout;

  UsbIo = UsbCbiDev->UsbIo;

  Cbi0ReportStatusCode (
    UsbCbiDev->DevicePath,
    EFI_PROGRESS_CODE,
    (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET)
    );
  //
  // CBI reset command protocol
  //
  ResetCommand[0] = 0x1d;
  ResetCommand[1] = 0x04;
  for (Index = 2; Index < 12; Index++) {
    ResetCommand[Index] = 0xff;
  }

  //
  // (in millisecond unit)
  //
  Timeout = STALL_1_SECOND;

  Status = Cbi0AtapiCommand (
            &UsbCbiDev->UsbAtapiProtocol,
            ResetCommand,
            12,
            NULL,
            0,
            EfiUsbNoData,
            Timeout
            );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  gBS->Stall (100 * 1000);
  //
  // clear bulk in endpoint stall feature
  //
  EndpointAddress = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress;
  Status = UsbClearEndpointHalt (
            UsbIo,
            EndpointAddress,
            &Result
            );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // clear bulk out endpoint stall feature
  //
  EndpointAddress = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress;
  Status = UsbClearEndpointHalt (
            UsbIo,
            EndpointAddress,
            &Result
            );
  //
  // according to CBI spec, no need to clear interrupt endpoint feature.
  //
  return Status;
}

STATIC
EFI_STATUS
Cbi0CommandPhase (
  IN  USB_CBI_DEVICE          *UsbCbiDev,
  IN  VOID                    *Command,
  IN  UINT8                   CommandSize,
  IN  UINT16                  Timeout
  )
/*++

  Routine Description:
    Send ATAPI command through CBI0 interface.

  Arguments:
    UsbCbiDev   - USB_CBI_DEVICE
    Command     - Command to send
    CommandSize - Command size
    Timeout     - Time out value in milliseconds
  Returns:
    EFI_SUCCESS      - Success
    EFI_DEVICE_ERROR - Fail
    Others

--*/
{
  EFI_STATUS              Status;
  UINT32                  Result;
  EFI_USB_IO_PROTOCOL     *UsbIo;
  EFI_USB_DEVICE_REQUEST  Request;

  UsbIo = UsbCbiDev->UsbIo;

  EfiZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST));

  //
  // Device request see CBI specification
  //
  Request.RequestType = 0x21;
  Request.Request     = 0x00;
  Request.Value       = 0;
  Request.Index       = 0;
  Request.Length      = CommandSize;

  Status = UsbIo->UsbControlTransfer (
                    UsbIo,
                    &Request,
                    EfiUsbDataOut,
                    Timeout,
                    Command,
                    CommandSize,
                    &Result
                    );
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }

  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
Cbi0DataPhase (
  IN      USB_CBI_DEVICE             *UsbCbiDev,
  IN      UINT32                     *DataSize,
  IN  OUT VOID                       *DataBuffer,
  IN      EFI_USB_DATA_DIRECTION     Direction,
  IN      UINT16                     Timeout
  )
/*++

  Routine Description:
    Get/Send Data through CBI0 interface

  Arguments:
    UsbCbiDev   - USB_CBI_DEVICE
    DataSize    - Data size
    DataBuffer  - Data buffer
    Direction   - IN/OUT/NODATA
    Timeout     - Time out value in milliseconds
  Returns:
    EFI_SUCCESS
    Others

--*/
{
  EFI_STATUS          Status;
  EFI_USB_IO_PROTOCOL *UsbIo;
  UINT8               EndpointAddress;
  UINTN               Remain;
  UINTN               Increment;
  UINT32              MaxPacketLength;
  UINT8               *BufferPtr;
  UINT32              Result;
  UINTN               TransferredSize;

  UsbIo           = UsbCbiDev->UsbIo;

  Remain          = *DataSize;
  BufferPtr       = (UINT8 *) DataBuffer;
  TransferredSize = 0;
  //
  // retrieve the the max packet length of the given endpoint
  //
  if (Direction == EfiUsbDataIn) {
    MaxPacketLength = UsbCbiDev->BulkInEndpointDescriptor.MaxPacketSize;
    EndpointAddress = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress;
  } else {
    MaxPacketLength = UsbCbiDev->BulkOutEndpointDescriptor.MaxPacketSize;
    EndpointAddress = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress;
  }

  while (Remain > 0) {

    if (Remain > 16 * MaxPacketLength) {
      Increment = 16 * MaxPacketLength;
    } else {
      Increment = Remain;
    }

    Status = UsbIo->UsbBulkTransfer (
                      UsbIo,
                      EndpointAddress,
                      BufferPtr,
                      &Increment,
                      Timeout,
                      &Result
                      );
    TransferredSize += Increment;

    if (EFI_ERROR (Status)) {
      goto ErrorExit;
    }

    BufferPtr += Increment;
    Remain -= Increment;
  }

  return EFI_SUCCESS;

ErrorExit:

  if (Direction == EfiUsbDataIn) {
    Cbi0ReportStatusCode (
      UsbCbiDev->DevicePath,
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
      (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_INPUT_ERROR)
      );
  } else {
    Cbi0ReportStatusCode (
      UsbCbiDev->DevicePath,
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
      (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_OUTPUT_ERROR)
      );
  }

  if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
    Status = Cbi0RecoveryReset (UsbCbiDev);
  }

  *DataSize = (UINT32) TransferredSize;
  return Status;
}

STATIC
EFI_STATUS
Cbi0StatusPhase (
  IN  USB_CBI_DEVICE        *UsbCbiDev,
  OUT INTERRUPT_DATA_BLOCK  *InterruptDataBlock,
  IN  UINT16                Timeout
  )
/*++

  Routine Description:
    Get transfer status through BOT interface

  Arguments:
    UsbCbiDev           -  USB_CBI_DEVICE
    InterruptDataBlock  -  Interrupt Data Block for interrupt transfer
    Timeout             -  Time out value in milliseconds  
  Returns:
    EFI_SUCCESS
    Others

--*/
{
  UINT8       EndpointAddress;
  UINTN       InterruptDataBlockLength;
  UINT32      Result;
  EFI_STATUS  Status;

  EfiZeroMem (InterruptDataBlock, sizeof (INTERRUPT_DATA_BLOCK));

  EndpointAddress           = UsbCbiDev->InterruptEndpointDescriptor.EndpointAddress;
  InterruptDataBlockLength  = sizeof (INTERRUPT_DATA_BLOCK);

  Status = UsbCbiDev->UsbIo->UsbSyncInterruptTransfer (
                              UsbCbiDev->UsbIo,
                              EndpointAddress,
                              InterruptDataBlock,
                              &InterruptDataBlockLength,
                              Timeout,
                              &Result
                              );
  if (EFI_ERROR (Status)) {
    if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
      //
      // just endpoint stall happens
      //
      UsbClearEndpointHalt (
        UsbCbiDev->UsbIo,
        EndpointAddress,
        &Result
        );
      gBS->Stall (100 * 1000);
    }

    return Status;
  }

  return EFI_SUCCESS;
}
//
// Cbi0 Atapi Protocol Implementation
//
STATIC
EFI_STATUS
EFIAPI
Cbi0MassStorageReset (
  IN  EFI_USB_ATAPI_PROTOCOL      *This,
  IN  BOOLEAN                     ExtendedVerification
  )
/*++

  Routine Description:
    Reset CBI Devices
    
  Arguments:
    This                    - Protocol instance pointer.
    ExtendedVerification    - TRUE if we need to do strictly reset.

  Returns:
    EFI_SUCCESS         - Command succeeded.
    EFI_DEVICE_ERROR    - Command failed.

--*/
{
  EFI_STATUS          Status;
  EFI_USB_IO_PROTOCOL *UsbIo;
  USB_CBI_DEVICE      *UsbCbiDev;

  UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This);
  UsbIo     = UsbCbiDev->UsbIo;

  if (ExtendedVerification) {
    //
    //    UsbIo->UsbPortReset (UsbIo);
    //
  }

  Status = Cbi0RecoveryReset (UsbCbiDev);
  return Status;
}

STATIC
EFI_STATUS
EFIAPI
Cbi0AtapiCommand (
  IN  EFI_USB_ATAPI_PROTOCOL      *This,
  IN  VOID                        *Command,
  IN  UINT8                       CommandSize,
  IN  VOID                        *DataBuffer,
  IN  UINT32                      BufferLength,
  IN  EFI_USB_DATA_DIRECTION      Direction,
  IN  UINT16                      TimeOutInMilliSeconds
  )
/*++

  Routine Description:
    Send ATAPI command using BOT protocol.

  Arguments:
    This                  - Protocol instance pointer.
    Command               - Command buffer
    CommandSize           - Size of Command Buffer
    DataBuffer            - Data buffer
    BufferLength          - Length of Data buffer
    Direction             - Data direction of this command
    TimeOutInMilliSeconds - Timeout value in ms

  Returns:
    EFI_SUCCESS           - Command succeeded.
    EFI_DEVICE_ERROR      - Command failed.
    EFI_INVALID_PARAMETER - Invalidate parameter 
--*/
{
  EFI_STATUS            Status;
  USB_CBI_DEVICE        *UsbCbiDev;
  UINT32                BufferSize;
  INTERRUPT_DATA_BLOCK  InterruptDataBlock;
  EFI_STATUS            DataPhaseStatus;

  if (Direction != EfiUsbNoData) {
    if (DataBuffer == NULL || BufferLength == 0) {
      return EFI_INVALID_PARAMETER;
    }
  }

  DataPhaseStatus = EFI_SUCCESS;
  //
  // Get the context
  //
  UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This);

  //
  // First send ATAPI command through Cbi
  //
  Status = Cbi0CommandPhase (
            UsbCbiDev,
            Command,
            CommandSize,
            TimeOutInMilliSeconds
            );
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }
  //
  // Send/Get Data if there is a Data Stage
  //
  switch (Direction) {

  case EfiUsbDataIn:
  case EfiUsbDataOut:
    BufferSize = BufferLength;

    DataPhaseStatus = Cbi0DataPhase (
                        UsbCbiDev,
                        &BufferSize,
                        DataBuffer,
                        Direction,
                        TimeOutInMilliSeconds
                        );
    break;

  case EfiUsbNoData:
    break;
  }

  if (EFI_ERROR (DataPhaseStatus)) {
    return EFI_DEVICE_ERROR;
  }
  
  //
  // Status Phase
  //
  Status = Cbi0StatusPhase (
            UsbCbiDev,
            &InterruptDataBlock,
            TimeOutInMilliSeconds
            );
  if (EFI_ERROR (Status)) {
    return EFI_DEVICE_ERROR;
  }

  if (This->CommandProtocol != EFI_USB_SUBCLASS_UFI) {

    if (InterruptDataBlock.bType == 0) {
      //
      // indicates command completion
      //
      switch (InterruptDataBlock.bValue & 0x03) {

      case 0:
        Status = EFI_SUCCESS;
        break;

      case 1:
        Status = EFI_DEVICE_ERROR;
        break;

      case 2:
        Status = Cbi0RecoveryReset (UsbCbiDev);
        if (EFI_ERROR (Status)) {
          UsbCbiDev->UsbIo->UsbPortReset (UsbCbiDev->UsbIo);
        }

        Status = EFI_DEVICE_ERROR;
        break;

      case 3:
        Status = EFI_DEVICE_ERROR;
      }
    } else {
      Status = DataPhaseStatus;
    }

  } else {
    //
    // UFI device, InterruptDataBlock.bType: ASC (Additional Sense Code)
    //             InterruptDataBlock.bValue: ASCQ (Additional Snese Code Qualifier)
    //
    Status = DataPhaseStatus;
  }

  return Status;
}

VOID
Cbi0ReportStatusCode (
  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
  IN EFI_STATUS_CODE_TYPE      CodeType,
  IN EFI_STATUS_CODE_VALUE     Value
  )
/*++

  Routine Description:
    Report Status Code in Usb Cbi0 Driver

  Arguments:
    DevicePath   - Use this to get Device Path
    CodeType     - Status Code Type
    CodeValue    - Status Code Value

  Returns:
    None

--*/
{

  ReportStatusCodeWithDevicePath (
    CodeType,
    Value,
    0,
    &gEfiUsbCbi0DriverGuid,
    DevicePath
    );
}

⌨️ 快捷键说明

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