MdeModulePkg: Add PEI USB drivers and related PPIs
Signed-off-by: jljusten Reviewed-by: mdkinney Reviewed-by: geekboy15a git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11901 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
401
MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c
Normal file
401
MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/** @file
|
||||
BOT Transportation implementation.
|
||||
|
||||
Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions
|
||||
of the BSD License which accompanies this distribution. The
|
||||
full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#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 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;
|
||||
}
|
Reference in New Issue
Block a user