diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c new file mode 100644 index 00000000..d1526f9d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c @@ -0,0 +1,394 @@ +/** @file +BOT Transportation implementation. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbBotPeim.h" +#include "BotPeim.h" +#include "PeiUsbLib.h" + +/** + Reset the given usb device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDev The instance to PEI_BOT_DEVICE. + + @retval EFI_INVALID_PARAMETER Can not get usb io ppi. + @retval EFI_SUCCESS Failed to reset the given usb device. + +**/ +EFI_STATUS +BotRecoveryReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDev + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + UINT32 Timeout; + PEI_USB_IO_PPI *UsbIoPpi; + UINT8 EndpointAddr; + EFI_STATUS Status; + + UsbIoPpi = PeiBotDev->UsbIoPpi; + + if (UsbIoPpi == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = 0x21; + DevReq.Request = 0xFF; + DevReq.Value = 0; + DevReq.Index = 0; + DevReq.Length = 0; + + Timeout = 3000; + + Status = UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0 + ); + + // + // clear bulk in endpoint stall feature + // + EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress; + PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr); + + // + // clear bulk out endpoint stall feature + // + EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress; + PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr); + + return Status; +} + +/** + Send the command to the device using Bulk-Out endpoint. + + This function sends the command to the device using Bulk-Out endpoint. + BOT transfer is composed of three phases: Command, Data, and Status. + This is the Command phase. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDev The instance to PEI_BOT_DEVICE. + @param Command The command to transfer to device. + @param CommandSize The length of the command. + @param DataTransferLength The expected length of the data. + @param Direction The direction of the data. + @param Timeout Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. + + @retval EFI_DEVICE_ERROR Successful to send the command to device. + @retval EFI_SUCCESS Failed to send the command to device. + +**/ +EFI_STATUS +BotCommandPhase ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT32 DataTransferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +{ + CBW Cbw; + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + UINTN DataSize; + + UsbIoPpi = PeiBotDev->UsbIoPpi; + + ZeroMem (&Cbw, sizeof (CBW)); + + // + // Fill the command block, detailed see BOT spec + // + Cbw.Signature = CBWSIG; + Cbw.Tag = 0x01; + Cbw.DataTransferLength = DataTransferLength; + Cbw.Flags = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0); + Cbw.Lun = 0; + Cbw.CmdLen = CommandSize; + + CopyMem (Cbw.CmdBlock, Command, CommandSize); + + DataSize = sizeof (CBW); + + Status = UsbIoPpi->UsbBulkTransfer ( + PeiServices, + UsbIoPpi, + (PeiBotDev->BulkOutEndpoint)->EndpointAddress, + (UINT8 *) &Cbw, + &DataSize, + Timeout + ); + if (EFI_ERROR (Status)) { + // + // Command phase fail, we need to recovery reset this device + // + BotRecoveryReset (PeiServices, PeiBotDev); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Transfer the data between the device and host. + + This function transfers the data between the device and host. + BOT transfer is composed of three phases: Command, Data, and Status. + This is the Data phase. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDev The instance to PEI_BOT_DEVICE. + @param DataSize The length of the data. + @param DataBuffer The pointer to the data. + @param Direction The direction of the data. + @param Timeout Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. + + @retval EFI_DEVICE_ERROR Successful to send the data to device. + @retval EFI_SUCCESS Failed to send the data to device. + +**/ +EFI_STATUS +BotDataPhase ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +{ + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + UINT8 EndpointAddr; + UINTN Remain; + UINTN Increment; + UINT32 MaxPacketLen; + UINT8 *BufferPtr; + UINTN TransferredSize; + + UsbIoPpi = PeiBotDev->UsbIoPpi; + + Remain = *DataSize; + BufferPtr = (UINT8 *) DataBuffer; + TransferredSize = 0; + + // + // retrieve the max packet length of the given endpoint + // + if (Direction == EfiUsbDataIn) { + MaxPacketLen = (PeiBotDev->BulkInEndpoint)->MaxPacketSize; + EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress; + } else { + MaxPacketLen = (PeiBotDev->BulkOutEndpoint)->MaxPacketSize; + EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress; + } + + while (Remain > 0) { + // + // Using 15 packets to avoid Bitstuff error + // + if (Remain > 16 * MaxPacketLen) { + Increment = 16 * MaxPacketLen; + } else { + Increment = Remain; + } + + Status = UsbIoPpi->UsbBulkTransfer ( + PeiServices, + UsbIoPpi, + EndpointAddr, + BufferPtr, + &Increment, + Timeout + ); + + TransferredSize += Increment; + + if (EFI_ERROR (Status)) { + PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr); + return Status; + } + + BufferPtr += Increment; + Remain -= Increment; + } + + *DataSize = (UINT32) TransferredSize; + + return EFI_SUCCESS; +} + +/** + Get the command execution status from device. + + This function gets the command execution status from device. + BOT transfer is composed of three phases: Command, Data, and Status. + This is the Status phase. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDev The instance to PEI_BOT_DEVICE. + @param TransferStatus The status of the transaction. + @param Timeout Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. + + @retval EFI_DEVICE_ERROR Successful to get the status of device. + @retval EFI_SUCCESS Failed to get the status of device. + +**/ +EFI_STATUS +BotStatusPhase ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDev, + OUT UINT8 *TransferStatus, + IN UINT16 Timeout + ) +{ + CSW Csw; + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + UINT8 EndpointAddr; + UINTN DataSize; + + UsbIoPpi = PeiBotDev->UsbIoPpi; + + ZeroMem (&Csw, sizeof (CSW)); + + EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress; + + DataSize = sizeof (CSW); + + // + // Get the status field from bulk transfer + // + Status = UsbIoPpi->UsbBulkTransfer ( + PeiServices, + UsbIoPpi, + EndpointAddr, + &Csw, + &DataSize, + Timeout + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Csw.Signature == CSWSIG) { + *TransferStatus = Csw.Status; + } else { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Send ATAPI command using BOT protocol. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDev The instance to PEI_BOT_DEVICE. + @param Command The command to be sent to ATAPI device. + @param CommandSize The length of the data to be sent. + @param DataBuffer The pointer to the data. + @param BufferLength The length of the data. + @param Direction The direction of the data. + @param TimeOutInMilliSeconds Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. + + @retval EFI_DEVICE_ERROR Successful to get the status of device. + @retval EFI_SUCCESS Failed to get the status of device. + +**/ +EFI_STATUS +PeiAtapiCommand ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ) +{ + EFI_STATUS Status; + EFI_STATUS BotDataStatus; + UINT8 TransferStatus; + UINT32 BufferSize; + + BotDataStatus = EFI_SUCCESS; + // + // First send ATAPI command through Bot + // + Status = BotCommandPhase ( + PeiServices, + PeiBotDev, + Command, + CommandSize, + BufferLength, + Direction, + 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; + + BotDataStatus = BotDataPhase ( + PeiServices, + PeiBotDev, + &BufferSize, + DataBuffer, + Direction, + TimeOutInMilliSeconds + ); + break; + + case EfiUsbNoData: + break; + } + // + // Status Phase + // + Status = BotStatusPhase ( + PeiServices, + PeiBotDev, + &TransferStatus, + TimeOutInMilliSeconds + ); + if (EFI_ERROR (Status)) { + BotRecoveryReset (PeiServices, PeiBotDev); + return EFI_DEVICE_ERROR; + } + + if (TransferStatus == 0x01) { + return EFI_DEVICE_ERROR; + } + + return BotDataStatus; +} |