From 4b1bf81c20d5523554a83f6604df7930396f7c21 Mon Sep 17 00:00:00 2001 From: jljusten Date: Mon, 27 Jun 2011 23:30:55 +0000 Subject: 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 --- MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c | 401 +++++++++++++++ MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h | 224 +++++++++ MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c | 630 +++++++++++++++++++++++ MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c | 331 ++++++++++++ MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h | 248 +++++++++ MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf | 65 +++ MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c | 720 +++++++++++++++++++++++++++ MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h | 233 +++++++++ MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h | 179 +++++++ 9 files changed, 3031 insertions(+) create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h create mode 100644 MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h (limited to 'MdeModulePkg/Bus/Usb/UsbBotPei') diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c b/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c new file mode 100644 index 0000000000..55c4a537fa --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c @@ -0,0 +1,401 @@ +/** @file +BOT Transportation implementation. + +Copyright (c) 2006, Intel Corporation. All rights reserved.
+ +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; +} diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h b/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h new file mode 100644 index 0000000000..07235c397b --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h @@ -0,0 +1,224 @@ +/** @file +BOT Transportation implementation. + +Copyright (c) 2006, Intel Corporation. All rights reserved.
+ +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. + +**/ + +#ifndef _PEI_BOT_PEIM_H_ +#define _PEI_BOT_PEIM_H_ + + +#include + +#include +#include +#include + +//#include +#include +#include +#include + +#include + +#pragma pack(1) +// +// Bulk Only device protocol +// +typedef struct { + UINT32 Signature; + UINT32 Tag; + UINT32 DataTransferLength; + UINT8 Flags; + UINT8 Lun; + UINT8 CmdLen; + UINT8 CmdBlock[16]; +} CBW; + +typedef struct { + UINT32 Signature; + UINT32 Tag; + UINT32 DataResidue; + UINT8 Status; +} CSW; + +#pragma pack() +// +// Status code, see Usb Bot device spec +// +#define CSWSIG 0x53425355 +#define CBWSIG 0x43425355 + +/** + Sends out ATAPI Inquiry Packet Command to the specified device. This command will + return INQUIRY data of the device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS Inquiry command completes successfully. + @retval EFI_DEVICE_ERROR Inquiry command failed. + +**/ +EFI_STATUS +PeiUsbInquiry ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ); + +/** + Sends out ATAPI Test Unit Ready Packet Command to the specified device + to find out whether device is accessible. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS TestUnit command executed successfully. + @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully. + +**/ +EFI_STATUS +PeiUsbTestUnitReady ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ); + +/** + Sends out ATAPI Request Sense Packet Command to the specified device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + @param SenseCounts Length of sense buffer. + @param SenseKeyBuffer Pointer to sense buffer. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbRequestSense ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice, + OUT UINTN *SenseCounts, + IN UINT8 *SenseKeyBuffer + ); + +/** + Sends out ATAPI Read Capacity Packet Command to the specified device. + This command will return the information regarding the capacity of the + media in the device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbReadCapacity ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ); + +/** + Sends out ATAPI Read Format Capacity Data Command to the specified device. + This command will return the information regarding the capacity of the + media in the device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbReadFormattedCapacity ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ); + +/** + Execute Read(10) ATAPI command on a specific SCSI target. + + Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + @param Buffer The pointer to data buffer. + @param Lba The start logic block address of reading. + @param NumberOfBlocks The block number of reading. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbRead10 ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice, + IN VOID *Buffer, + IN EFI_PEI_LBA Lba, + IN UINTN NumberOfBlocks + ); + +/** + Check if there is media according to sense data. + + @param SenseData Pointer to sense data. + @param SenseCounts Count of sense data. + + @retval TRUE No media + @retval FALSE Media exists + +**/ +BOOLEAN +IsNoMedia ( + IN ATAPI_REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +/** + Check if there is media error according to sense data. + + @param SenseData Pointer to sense data. + @param SenseCounts Count of sense data. + + @retval TRUE Media error + @retval FALSE No media error + +**/ +BOOLEAN +IsMediaError ( + IN ATAPI_REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +/** + Check if media is changed according to sense data. + + @param SenseData Pointer to sense data. + @param SenseCounts Count of sense data. + + @retval TRUE There is media change event. + @retval FALSE media is NOT changed. + +**/ +BOOLEAN +IsMediaChange ( + IN ATAPI_REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +#endif diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c new file mode 100644 index 0000000000..28574d07e1 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c @@ -0,0 +1,630 @@ +/** @file +Pei USB ATATPI command implementations. + +Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.
+ +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" + +#define MAXSENSEKEY 5 + +/** + Sends out ATAPI Inquiry Packet Command to the specified device. This command will + return INQUIRY data of the device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS Inquiry command completes successfully. + @retval EFI_DEVICE_ERROR Inquiry command failed. + +**/ +EFI_STATUS +PeiUsbInquiry ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ) +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + ATAPI_INQUIRY_DATA Idata; + + // + // fill command packet + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA)); + + Packet.Inquiry.opcode = ATA_CMD_INQUIRY; + Packet.Inquiry.page_code = 0; + Packet.Inquiry.allocation_length = 36; + + // + // Send scsi INQUIRY command packet. + // According to SCSI Primary Commands-2 spec, host only needs to + // retrieve the first 36 bytes for standard INQUIRY data. + // + Status = PeiAtapiCommand ( + PeiServices, + PeiBotDevice, + &Packet, + (UINT8) sizeof (ATAPI_PACKET_COMMAND), + &Idata, + 36, + EfiUsbDataIn, + 2000 + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if ((Idata.peripheral_type & 0x1f) == 0x05) { + PeiBotDevice->DeviceType = USBCDROM; + PeiBotDevice->Media.BlockSize = 0x800; + } else { + PeiBotDevice->DeviceType = USBFLOPPY; + PeiBotDevice->Media.BlockSize = 0x200; + } + + return EFI_SUCCESS; +} + +/** + Sends out ATAPI Test Unit Ready Packet Command to the specified device + to find out whether device is accessible. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS TestUnit command executed successfully. + @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully. + +**/ +EFI_STATUS +PeiUsbTestUnitReady ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ) +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + + // + // fill command packet + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY; + + // + // send command packet + // + Status = PeiAtapiCommand ( + PeiServices, + PeiBotDevice, + &Packet, + (UINT8) sizeof (ATAPI_PACKET_COMMAND), + NULL, + 0, + EfiUsbNoData, + 2000 + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Sends out ATAPI Request Sense Packet Command to the specified device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + @param SenseCounts Length of sense buffer. + @param SenseKeyBuffer Pointer to sense buffer. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbRequestSense ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice, + OUT UINTN *SenseCounts, + IN UINT8 *SenseKeyBuffer + ) +{ + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + UINT8 *Ptr; + BOOLEAN SenseReq; + ATAPI_REQUEST_SENSE_DATA *Sense; + + *SenseCounts = 0; + + // + // fill command packet for Request Sense Packet Command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE; + Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA); + + Ptr = SenseKeyBuffer; + + SenseReq = TRUE; + + // + // request sense data from device continuously + // until no sense data exists in the device. + // + while (SenseReq) { + Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr; + + // + // send out Request Sense Packet Command and get one Sense + // data form device. + // + Status = PeiAtapiCommand ( + PeiServices, + PeiBotDevice, + &Packet, + (UINT8) sizeof (ATAPI_PACKET_COMMAND), + (VOID *) Ptr, + sizeof (ATAPI_REQUEST_SENSE_DATA), + EfiUsbDataIn, + 2000 + ); + + // + // failed to get Sense data + // + if (EFI_ERROR (Status)) { + if (*SenseCounts == 0) { + return EFI_DEVICE_ERROR; + } else { + return EFI_SUCCESS; + } + } + + if (Sense->sense_key != ATA_SK_NO_SENSE) { + + Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA); + // + // Ptr is byte based pointer + // + (*SenseCounts)++; + + if (*SenseCounts == MAXSENSEKEY) { + break; + } + + } else { + // + // when no sense key, skip out the loop + // + SenseReq = FALSE; + } + } + + return EFI_SUCCESS; +} + +/** + Sends out ATAPI Read Capacity Packet Command to the specified device. + This command will return the information regarding the capacity of the + media in the device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbReadCapacity ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ) +{ + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + ATAPI_READ_CAPACITY_DATA Data; + + ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA)); + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + + Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY; + + // + // send command packet + // + Status = PeiAtapiCommand ( + PeiServices, + PeiBotDevice, + &Packet, + (UINT8) sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &Data, + sizeof (ATAPI_READ_CAPACITY_DATA), + EfiUsbDataIn, + 2000 + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + PeiBotDevice->Media.LastBlock = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0; + + PeiBotDevice->Media.MediaPresent = TRUE; + + return EFI_SUCCESS; +} + +/** + Sends out ATAPI Read Format Capacity Data Command to the specified device. + This command will return the information regarding the capacity of the + media in the device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbReadFormattedCapacity ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice + ) +{ + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + ATAPI_READ_FORMAT_CAPACITY_DATA FormatData; + + ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA)); + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + + Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY; + Packet.ReadFormatCapacity.allocation_length_lo = 12; + + // + // send command packet + // + Status = PeiAtapiCommand ( + PeiServices, + PeiBotDevice, + &Packet, + (UINT8) sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &FormatData, + sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA), + EfiUsbDataIn, + 2000 + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (FormatData.DesCode == 3) { + // + // Media is not present + // + PeiBotDevice->Media.MediaPresent = FALSE; + PeiBotDevice->Media.LastBlock = 0; + + } else { + + PeiBotDevice->Media.LastBlock = (FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0; + + PeiBotDevice->Media.LastBlock--; + + PeiBotDevice->Media.MediaPresent = TRUE; + } + + return EFI_SUCCESS; +} + +/** + Execute Read(10) ATAPI command on a specific SCSI target. + + Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance. + @param Buffer The pointer to data buffer. + @param Lba The start logic block address of reading. + @param NumberOfBlocks The block number of reading. + + @retval EFI_SUCCESS Command executed successfully. + @retval EFI_DEVICE_ERROR Some device errors happen. + +**/ +EFI_STATUS +PeiUsbRead10 ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDevice, + IN VOID *Buffer, + IN EFI_PEI_LBA Lba, + IN UINTN NumberOfBlocks + ) +{ + ATAPI_PACKET_COMMAND Packet; + ATAPI_READ10_CMD *Read10Packet; + UINT16 MaxBlock; + UINT16 BlocksRemaining; + UINT16 SectorCount; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + VOID *PtrBuffer; + EFI_STATUS Status; + UINT16 TimeOut; + + // + // prepare command packet for the Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + PtrBuffer = Buffer; + + BlockSize = (UINT32) PeiBotDevice->Media.BlockSize; + + MaxBlock = (UINT16) (65535 / BlockSize); + BlocksRemaining = (UINT16) NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = BlocksRemaining; + + } else { + + SectorCount = MaxBlock; + } + // + // fill the Packet data structure + // + Read10Packet->opcode = ATA_CMD_READ_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + TimeOut = (UINT16) (SectorCount * 2000); + + // + // send command packet + // + Status = PeiAtapiCommand ( + PeiServices, + PeiBotDevice, + &Packet, + (UINT8) sizeof (ATAPI_PACKET_COMMAND), + (VOID *) PtrBuffer, + ByteCount, + EfiUsbDataIn, + TimeOut + ); + + if (Status != EFI_SUCCESS) { + return Status; + } + + Lba32 += SectorCount; + PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize; + BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); + } + + return Status; +} + +/** + Check if there is media according to sense data. + + @param SenseData Pointer to sense data. + @param SenseCounts Count of sense data. + + @retval TRUE No media + @retval FALSE Media exists + +**/ +BOOLEAN +IsNoMedia ( + IN ATAPI_REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + ATAPI_REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN NoMedia; + + NoMedia = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePtr->sense_key) { + + case ATA_SK_NOT_READY: + switch (SensePtr->addnl_sense_code) { + // + // if no media, fill IdeDev parameter with specific info. + // + case ATA_ASC_NO_MEDIA: + NoMedia = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + SensePtr++; + } + + return NoMedia; +} + +/** + Check if there is media error according to sense data. + + @param SenseData Pointer to sense data. + @param SenseCounts Count of sense data. + + @retval TRUE Media error + @retval FALSE No media error + +**/ +BOOLEAN +IsMediaError ( + IN ATAPI_REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + ATAPI_REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN Error; + + SensePtr = SenseData; + Error = FALSE; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePtr->sense_key) { + // + // Medium error case + // + case ATA_SK_MEDIUM_ERROR: + switch (SensePtr->addnl_sense_code) { + case ATA_ASC_MEDIA_ERR1: + // + // fall through + // + case ATA_ASC_MEDIA_ERR2: + // + // fall through + // + case ATA_ASC_MEDIA_ERR3: + // + // fall through + // + case ATA_ASC_MEDIA_ERR4: + Error = TRUE; + break; + + default: + break; + } + + break; + + // + // Medium upside-down case + // + case ATA_SK_NOT_READY: + switch (SensePtr->addnl_sense_code) { + case ATA_ASC_MEDIA_UPSIDE_DOWN: + Error = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + SensePtr++; + } + + return Error; +} + +/** + Check if media is changed according to sense data. + + @param SenseData Pointer to sense data. + @param SenseCounts Count of sense data. + + @retval TRUE There is media change event. + @retval FALSE media is NOT changed. + +**/ +BOOLEAN +IsMediaChange ( + IN ATAPI_REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + ATAPI_REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN MediaChange; + + MediaChange = FALSE; + + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + // + // catch media change sense key and addition sense data + // + switch (SensePtr->sense_key) { + case ATA_SK_UNIT_ATTENTION: + switch (SensePtr->addnl_sense_code) { + case ATA_ASC_MEDIA_CHANGE: + MediaChange = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + SensePtr++; + } + + return MediaChange; +} diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c new file mode 100644 index 0000000000..2a8fde07ff --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c @@ -0,0 +1,331 @@ +/** @file +Common Libarary for PEI USB. + +Copyright (c) 2006, Intel Corporation. All rights reserved.
+ +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 "UsbPeim.h" +#include "PeiUsbLib.h" + +/** + Get a given usb descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Request Value. + @param Index Request Index. + @param DescriptorLength Request descriptor Length. + @param Descriptor Request descriptor. + + + @retval EFI_SUCCESS Usb descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + OUT VOID *Descriptor + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + + ASSERT (UsbIoPpi != NULL); + + DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE; + DevReq.Request = USB_DEV_GET_DESCRIPTOR; + DevReq.Value = Value; + DevReq.Index = Index; + DevReq.Length = DescriptorLength; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + Descriptor, + DescriptorLength + ); +} + +/** + Set a usb device with a specified address. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param AddressValue The address to assign. + + @retval EFI_SUCCESS Usb device address is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetDeviceAddress ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 AddressValue + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + + ASSERT (UsbIoPpi != NULL); + + DevReq.RequestType = USB_DEV_SET_ADDRESS_REQ_TYPE; + DevReq.Request = USB_DEV_SET_ADDRESS; + DevReq.Value = AddressValue; + DevReq.Index = 0; + DevReq.Length = 0; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Clear a given usb feature. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint. + @param Value Request Value. + @param Target Request Index. + + @retval EFI_SUCCESS Usb feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbClearDeviceFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Value, + IN UINT16 Target + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + + ASSERT (UsbIoPpi != NULL); + + switch (Recipient) { + case EfiUsbDevice: + DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_D; + break; + + case EfiUsbInterface: + DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_I; + break; + + case EfiUsbEndpoint: + DevReq.RequestType = USB_DEV_CLEAR_FEATURE_REQ_TYPE_E; + break; + } + + DevReq.Request = USB_DEV_CLEAR_FEATURE; + DevReq.Value = Value; + DevReq.Index = Target; + DevReq.Length = 0; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Configure a usb device to Configuration 1. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_SET_CONFIGURATION_REQ_TYPE; + DevReq.Request = USB_DEV_SET_CONFIGURATION; + DevReq.Value = 1; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Clear Endpoint Halt. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param EndpointAddress The endpoint address. + + @retval EFI_SUCCESS Endpoint halt is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbClearEndpointHalt ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 EndpointAddress + ) +{ + EFI_STATUS Status; + PEI_USB_DEVICE *PeiUsbDev; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; + UINT8 EndpointIndex; + + EndpointIndex = 0; + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (UsbIoPpi); + + while (EndpointIndex < MAX_ENDPOINT) { + Status = UsbIoPpi->UsbGetEndpointDescriptor (PeiServices, UsbIoPpi, EndpointIndex, &EndpointDescriptor); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + if (EndpointDescriptor->EndpointAddress == EndpointAddress) { + break; + } + + EndpointIndex++; + } + + if (EndpointIndex == MAX_ENDPOINT) { + return EFI_INVALID_PARAMETER; + } + + Status = PeiUsbClearDeviceFeature ( + PeiServices, + UsbIoPpi, + EfiUsbEndpoint, + EfiUsbEndpointHalt, + EndpointAddress + ); + + // + // set data toggle to zero. + // + if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) { + PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex)); + } + + return Status; +} + +/** + Judge if the port is connected with a usb device or not. + + @param PortStatus The usb port status gotten. + + @retval TRUE A usb device is connected with the port. + @retval FALSE No usb device is connected with the port. + +**/ +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ) +{ + // + // return the bit 0 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Judge if the port is connected with a low-speed usb device or not. + + @param PortStatus The usb port status gotten. + + @retval TRUE A low-speed usb device is connected with the port. + @retval FALSE No low-speed usb device is connected with the port. + +**/ +BOOLEAN +IsPortLowSpeedDeviceAttached ( + IN UINT16 PortStatus + ) +{ + // + // return the bit 9 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Judge if the port is in "connection change" status or not. + + @param PortChangeStatus The usb port change status gotten. + + @retval TRUE The port is in "connection change" status. + @retval FALSE The port is NOT in "connection change" status. + +**/ +BOOLEAN +IsPortConnectChange ( + IN UINT16 PortChangeStatus + ) +{ + // + // return the bit 0 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_CONNECTION) != 0) { + return TRUE; + } else { + return FALSE; + } +} diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h new file mode 100644 index 0000000000..eafccfdbf8 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h @@ -0,0 +1,248 @@ +/** @file +Common Libarary for PEI USB. + +Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.
+ +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. + +**/ + +#ifndef _PEI_USB_LIB_H_ +#define _PEI_USB_LIB_H_ +// +// Standard device request and request type +// By [Spec-USB20/Chapter-9.4] +// +#define USB_DEV_GET_STATUS 0x00 +#define USB_DEV_GET_STATUS_REQ_TYPE_D 0x80 // Receiver : Device +#define USB_DEV_GET_STATUS_REQ_TYPE_I 0x81 // Receiver : Interface +#define USB_DEV_GET_STATUS_REQ_TYPE_E 0x82 // Receiver : Endpoint + +#define USB_DEV_CLEAR_FEATURE 0x01 +#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device +#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface +#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint + +#define USB_DEV_SET_FEATURE 0x03 +#define USB_DEV_SET_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device +#define USB_DEV_SET_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface +#define USB_DEV_SET_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint + +#define USB_DEV_SET_ADDRESS 0x05 +#define USB_DEV_SET_ADDRESS_REQ_TYPE 0x00 + +#define USB_DEV_GET_DESCRIPTOR 0x06 +#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE 0x80 + +#define USB_DEV_SET_DESCRIPTOR 0x07 +#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE 0x00 + +#define USB_DEV_GET_CONFIGURATION 0x08 +#define USB_DEV_GET_CONFIGURATION_REQ_TYPE 0x80 + +#define USB_DEV_SET_CONFIGURATION 0x09 +#define USB_DEV_SET_CONFIGURATION_REQ_TYPE 0x00 + +#define USB_DEV_GET_INTERFACE 0x0A +#define USB_DEV_GET_INTERFACE_REQ_TYPE 0x81 + +#define USB_DEV_SET_INTERFACE 0x0B +#define USB_DEV_SET_INTERFACE_REQ_TYPE 0x01 + +#define USB_DEV_SYNCH_FRAME 0x0C +#define USB_DEV_SYNCH_FRAME_REQ_TYPE 0x82 + +// +// USB Descriptor types +// +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_HUB 0x29 +#define USB_DT_HID 0x21 + +// +// USB request type +// +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +// +// USB request targer device +// +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +typedef enum { + EfiUsbEndpointHalt, + EfiUsbDeviceRemoteWakeup +} EFI_USB_STANDARD_FEATURE_SELECTOR; + +// +// Usb Data recipient type +// +typedef enum { + EfiUsbDevice, + EfiUsbInterface, + EfiUsbEndpoint +} EFI_USB_RECIPIENT; + +/** + Get a given usb descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Request Value. + @param Index Request Index. + @param DescriptorLength Request descriptor Length. + @param Descriptor Request descriptor. + + + @retval EFI_SUCCESS Usb descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + OUT VOID *Descriptor + ); + +/** + Set a usb device with a specified address. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param AddressValue The address to assign. + + @retval EFI_SUCCESS Usb device address is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetDeviceAddress ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 AddressValue + ); + +/** + Clear a given usb feature. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Recipient The recipient of ClearFeature Request, should be one of Device/Interface/Endpoint. + @param Value Request Value. + @param Target Request Index. + + @retval EFI_SUCCESS Usb feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the usb feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbClearDeviceFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN EFI_USB_RECIPIENT Recipient, + IN UINT16 Value, + IN UINT16 Target + ); + +/** + Configure a usb device to Configuration 1. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi + ); + +/** + Clear Endpoint Halt. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param EndpointAddress The endpoint address. + + @retval EFI_SUCCESS Endpoint halt is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbClearEndpointHalt ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 EndpointAddress + ); + +/** + Judge if the port is connected with a usb device or not. + + @param PortStatus The usb port status gotten. + + @retval TRUE A usb device is connected with the port. + @retval FALSE No usb device is connected with the port. + +**/ +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ); + +/** + Judge if the port is connected with a low-speed usb device or not. + + @param PortStatus The usb port status gotten. + + @retval TRUE A low-speed usb device is connected with the port. + @retval FALSE No low-speed usb device is connected with the port. + +**/ +BOOLEAN +IsPortLowSpeedDeviceAttached ( + IN UINT16 PortStatus + ); + +/** + Judge if the port is in "connection change" status or not. + + @param PortChangeStatus The usb port change status gotten. + + @retval TRUE The port is in "connection change" status. + @retval FALSE The port is NOT in "connection change" status. + +**/ +BOOLEAN +IsPortConnectChange ( + IN UINT16 PortChangeStatus + ); +#endif diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf new file mode 100644 index 0000000000..a2442c112e --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf @@ -0,0 +1,65 @@ +## @file +# Component description file for UsbBotPei module. +# +# Usb mass storage device Peim driver to support recovery from USB device. +# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# +# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UsbBotPei + FILE_GUID = 8401A046-6F70-4505-8471-7015B40355E3 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimInitializeUsbBot + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PeiUsbLib.c + PeiAtapi.c + BotPeim.c + UsbBotPeim.c + UsbPeim.h + UsbBotPeim.h + PeiUsbLib.h + BotPeim.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + BaseMemoryLib + PeiServicesLib + PeimEntryPoint + DebugLib + PcdLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue + +[Ppis] + gEfiPeiVirtualBlockIoPpiGuid # PPI ALWAYS_PRODUCED + gPeiUsbIoPpiGuid # PPI ALWAYS_CONSUMED + + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbIoPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid + diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c new file mode 100644 index 0000000000..b04bd42cff --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c @@ -0,0 +1,720 @@ +/** @file + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +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" + +// +// Global function +// +EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiUsbIoPpiGuid, + NotifyOnUsbIoPpi +}; + +EFI_PEI_RECOVERY_BLOCK_IO_PPI mRecoveryBlkIoPpi = { + BotGetNumberOfBlockDevices, + BotGetMediaInfo, + BotReadBlocks +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gEfiPeiVirtualBlockIoPpiGuid, + NULL +}; + +/** + Detect whether the removable media is present and whether it has changed. + + @param[in] PeiServices General-purpose services that are available to every + PEIM. + @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS The media status is successfully checked. + @retval Other Failed to detect media. + +**/ +EFI_STATUS +PeiBotDetectMedia ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDev + ); + +/** + Initializes the Usb Bot. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Usb bot driver is successfully initialized. + @retval EFI_OUT_OF_RESOURCES Can't initialize the driver. + +**/ +EFI_STATUS +EFIAPI +PeimInitializeUsbBot ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINTN UsbIoPpiInstance; + EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor; + PEI_USB_IO_PPI *UsbIoPpi; + + // + // Shadow this PEIM to run from memory + // + if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { + return EFI_SUCCESS; + } + + // + // locate all usb io PPIs + // + for (UsbIoPpiInstance = 0; UsbIoPpiInstance < PEI_FAT_MAX_USB_IO_PPI; UsbIoPpiInstance++) { + + Status = PeiServicesLocatePpi ( + &gPeiUsbIoPpiGuid, + UsbIoPpiInstance, + &TempPpiDescriptor, + (VOID **) &UsbIoPpi + ); + if (EFI_ERROR (Status)) { + break; + } + } + // + // Register a notify function + // + return PeiServicesNotifyPpi (&mNotifyList); +} + +/** + UsbIo installation notification function. + + This function finds out all the current USB IO PPIs in the system and add them + into private data. + + @param PeiServices Indirect reference to the PEI Services Table. + @param NotifyDesc Address of the notification descriptor data structure. + @param InvokePpi Address of the PPI that was invoked. + + @retval EFI_SUCCESS The function completes successfully. + +**/ +EFI_STATUS +EFIAPI +NotifyOnUsbIoPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *InvokePpi + ) +{ + PEI_USB_IO_PPI *UsbIoPpi; + + UsbIoPpi = (PEI_USB_IO_PPI *) InvokePpi; + + InitUsbBot (PeiServices, UsbIoPpi); + + return EFI_SUCCESS; +} + +/** + Initialize the usb bot device. + + @param[in] PeiServices General-purpose services that are available to every + PEIM. + @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS The usb bot device is initialized successfully. + @retval Other Failed to initialize media. + +**/ +EFI_STATUS +InitUsbBot ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi + ) +{ + PEI_BOT_DEVICE *PeiBotDevice; + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc; + UINTN MemPages; + EFI_PHYSICAL_ADDRESS AllocateAddress; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc; + UINT8 Index; + + // + // Check its interface + // + Status = UsbIoPpi->UsbGetInterfaceDescriptor ( + PeiServices, + UsbIoPpi, + &InterfaceDesc + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if it is the BOT device we support + // + if ((InterfaceDesc->InterfaceClass != 0x08) || (InterfaceDesc->InterfaceProtocol != 0x50)) { + + return EFI_NOT_FOUND; + } + + MemPages = sizeof (PEI_BOT_DEVICE) / EFI_PAGE_SIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiBotDevice = (PEI_BOT_DEVICE *) ((UINTN) AllocateAddress); + + PeiBotDevice->Signature = PEI_BOT_DEVICE_SIGNATURE; + PeiBotDevice->UsbIoPpi = UsbIoPpi; + PeiBotDevice->AllocateAddress = (UINTN) AllocateAddress; + PeiBotDevice->BotInterface = InterfaceDesc; + + // + // Default value + // + PeiBotDevice->Media.DeviceType = UsbMassStorage; + PeiBotDevice->Media.BlockSize = 0x200; + + // + // Check its Bulk-in/Bulk-out endpoint + // + for (Index = 0; Index < 2; Index++) { + Status = UsbIoPpi->UsbGetEndpointDescriptor ( + PeiServices, + UsbIoPpi, + Index, + &EndpointDesc + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((EndpointDesc->EndpointAddress & 0x80) != 0) { + PeiBotDevice->BulkInEndpoint = EndpointDesc; + } else { + PeiBotDevice->BulkOutEndpoint = EndpointDesc; + } + } + + CopyMem ( + &(PeiBotDevice->BlkIoPpi), + &mRecoveryBlkIoPpi, + sizeof (EFI_PEI_RECOVERY_BLOCK_IO_PPI) + ); + CopyMem ( + &(PeiBotDevice->BlkIoPpiList), + &mPpiList, + sizeof (EFI_PEI_PPI_DESCRIPTOR) + ); + PeiBotDevice->BlkIoPpiList.Ppi = &PeiBotDevice->BlkIoPpi; + + Status = PeiUsbInquiry (PeiServices, PeiBotDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + 1, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiBotDevice->SensePtr = (ATAPI_REQUEST_SENSE_DATA *) ((UINTN) AllocateAddress); + + Status = PeiServicesInstallPpi (&PeiBotDevice->BlkIoPpiList); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS Operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +BotGetNumberOfBlockDevices ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + OUT UINTN *NumberBlockDevices + ) +{ + // + // For Usb devices, this value should be always 1 + // + *NumberBlockDevices = 1; + return EFI_SUCCESS; +} + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +BotGetMediaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo + ) +{ + PEI_BOT_DEVICE *PeiBotDev; + EFI_STATUS Status; + + PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This); + + // + // First test unit ready + // + PeiUsbTestUnitReady ( + PeiServices, + PeiBotDev + ); + + Status = PeiBotDetectMedia ( + PeiServices, + PeiBotDev + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + CopyMem ( + MediaInfo, + &(PeiBotDev->Media), + sizeof (EFI_PEI_BLOCK_IO_MEDIA) + ); + + return EFI_SUCCESS; +} + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the ownership of the + buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +BotReadBlocks ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + PEI_BOT_DEVICE *PeiBotDev; + EFI_STATUS Status; + UINTN BlockSize; + UINTN NumberOfBlocks; + + Status = EFI_SUCCESS; + PeiBotDev = PEI_BOT_DEVICE_FROM_THIS (This); + + // + // Check parameters + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + if (!PeiBotDev->Media.MediaPresent) { + return EFI_NO_MEDIA; + } + + BlockSize = PeiBotDev->Media.BlockSize; + + if (BufferSize % BlockSize != 0) { + Status = EFI_BAD_BUFFER_SIZE; + } + + if (StartLBA > PeiBotDev->Media.LastBlock) { + Status = EFI_INVALID_PARAMETER; + } + + NumberOfBlocks = BufferSize / (PeiBotDev->Media.BlockSize); + + if (Status == EFI_SUCCESS) { + + Status = PeiUsbTestUnitReady ( + PeiServices, + PeiBotDev + ); + if (Status == EFI_SUCCESS) { + Status = PeiUsbRead10 ( + PeiServices, + PeiBotDev, + Buffer, + StartLBA, + 1 + ); + } + } else { + // + // To generate sense data for DetectMedia use. + // + PeiUsbTestUnitReady ( + PeiServices, + PeiBotDev + ); + } + + if (EFI_ERROR (Status)) { + // + // if any error encountered, detect what happened to the media and + // update the media info accordingly. + // + Status = PeiBotDetectMedia ( + PeiServices, + PeiBotDev + ); + if (Status != EFI_SUCCESS) { + return EFI_DEVICE_ERROR; + } + + NumberOfBlocks = BufferSize / PeiBotDev->Media.BlockSize; + + if (!(PeiBotDev->Media.MediaPresent)) { + return EFI_NO_MEDIA; + } + + if (BufferSize % (PeiBotDev->Media.BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (StartLBA > PeiBotDev->Media.LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((StartLBA + NumberOfBlocks - 1) > PeiBotDev->Media.LastBlock) { + return EFI_INVALID_PARAMETER; + } + + Status = PeiUsbRead10 ( + PeiServices, + PeiBotDev, + Buffer, + StartLBA, + NumberOfBlocks + ); + + switch (Status) { + + case EFI_SUCCESS: + return EFI_SUCCESS; + + default: + return EFI_DEVICE_ERROR; + } + } else { + StartLBA += 1; + NumberOfBlocks -= 1; + Buffer = (UINT8 *) Buffer + PeiBotDev->Media.BlockSize; + + if (NumberOfBlocks == 0) { + return EFI_SUCCESS; + } + + Status = PeiUsbRead10 ( + PeiServices, + PeiBotDev, + Buffer, + StartLBA, + NumberOfBlocks + ); + switch (Status) { + + case EFI_SUCCESS: + return EFI_SUCCESS; + + default: + return EFI_DEVICE_ERROR; + + } + } +} + +/** + Detect whether the removable media is present and whether it has changed. + + @param[in] PeiServices General-purpose services that are available to every + PEIM. + @param[in] PeiBotDev Indicates the PEI_BOT_DEVICE instance. + + @retval EFI_SUCCESS The media status is successfully checked. + @retval Other Failed to detect media. + +**/ +EFI_STATUS +PeiBotDetectMedia ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_BOT_DEVICE *PeiBotDev + ) +{ + EFI_STATUS Status; + EFI_STATUS FloppyStatus; + UINTN SenseCounts; + BOOLEAN NeedReadCapacity; + EFI_PHYSICAL_ADDRESS AllocateAddress; + ATAPI_REQUEST_SENSE_DATA *SensePtr; + UINTN Retry; + + // + // if there is no media present,or media not changed, + // the request sense command will detect faster than read capacity command. + // read capacity command can be bypassed, thus improve performance. + // + SenseCounts = 0; + NeedReadCapacity = TRUE; + + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + 1, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + SensePtr = PeiBotDev->SensePtr; + ZeroMem (SensePtr, EFI_PAGE_SIZE); + + Status = PeiUsbRequestSense ( + PeiServices, + PeiBotDev, + &SenseCounts, + (UINT8 *) SensePtr + ); + + if (Status == EFI_SUCCESS) { + // + // No Media + // + if (IsNoMedia (SensePtr, SenseCounts)) { + NeedReadCapacity = FALSE; + PeiBotDev->Media.MediaPresent = FALSE; + PeiBotDev->Media.LastBlock = 0; + } else { + // + // Media Changed + // + if (IsMediaChange (SensePtr, SenseCounts)) { + PeiBotDev->Media.MediaPresent = TRUE; + } + // + // Media Error + // + if (IsMediaError (SensePtr, SenseCounts)) { + // + // if media error encountered, make it look like no media present. + // + PeiBotDev->Media.MediaPresent = FALSE; + PeiBotDev->Media.LastBlock = 0; + } + + } + + } + + if (NeedReadCapacity) { + // + // Retry at most 4 times to detect media info + // + for (Retry = 0; Retry < 4; Retry++) { + switch (PeiBotDev->DeviceType) { + case USBCDROM: + Status = PeiUsbReadCapacity ( + PeiServices, + PeiBotDev + ); + break; + + case USBFLOPPY2: + Status = PeiUsbReadFormattedCapacity ( + PeiServices, + PeiBotDev + ); + if (EFI_ERROR(Status)|| + !PeiBotDev->Media.MediaPresent) { + // + // retry the ReadCapacity command + // + PeiBotDev->DeviceType = USBFLOPPY; + Status = EFI_DEVICE_ERROR; + } + break; + + case USBFLOPPY: + Status = PeiUsbReadCapacity ( + PeiServices, + PeiBotDev + ); + // + // retry the ReadFormatCapacity command + // + PeiBotDev->DeviceType = USBFLOPPY2; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + SenseCounts = 0; + ZeroMem (SensePtr, EFI_PAGE_SIZE); + + if (Status == EFI_SUCCESS) { + break; + } + + FloppyStatus = PeiUsbRequestSense ( + PeiServices, + PeiBotDev, + &SenseCounts, + (UINT8 *) SensePtr + ); + + // + // If Request Sense data failed,retry. + // + if (EFI_ERROR (FloppyStatus)) { + continue; + } + // + // No Media + // + if (IsNoMedia (SensePtr, SenseCounts)) { + PeiBotDev->Media.MediaPresent = FALSE; + PeiBotDev->Media.LastBlock = 0; + break; + } + + if (IsMediaError (SensePtr, SenseCounts)) { + // + // if media error encountered, make it look like no media present. + // + PeiBotDev->Media.MediaPresent = FALSE; + PeiBotDev->Media.LastBlock = 0; + break; + } + } + // + // ENDFOR + // + // tell whether the readcapacity process is successful or not + // ("Status" variable record the latest status returned + // by ReadCapacity ) + // + if (Status != EFI_SUCCESS) { + return EFI_DEVICE_ERROR; + } + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h new file mode 100644 index 0000000000..26d08dfd56 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h @@ -0,0 +1,233 @@ +/** @file +Usb BOT Peim definition. + +Copyright (c) 2006, Intel Corporation. All rights reserved.
+ +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. + +**/ + +#ifndef _PEI_USB_BOT_PEIM_H_ +#define _PEI_USB_BOT_PEIM_H_ + +#include + +#include +#include +#include + +#include + +#include +#include + +#define PEI_FAT_MAX_USB_IO_PPI 127 + +/** + Gets the count of block I/O devices that one specific block driver detects. + + This function is used for getting the count of block I/O devices that one + specific block driver detects. To the PEI ATAPI driver, it returns the number + of all the detected ATAPI devices it detects during the enumeration process. + To the PEI legacy floppy driver, it returns the number of all the legacy + devices it finds during its enumeration process. If no device is detected, + then the function will return zero. + + @param[in] PeiServices General-purpose services that are available + to every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI + instance. + @param[out] NumberBlockDevices The number of block I/O devices discovered. + + @retval EFI_SUCCESS Operation performed successfully. + +**/ +EFI_STATUS +EFIAPI +BotGetNumberOfBlockDevices ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + OUT UINTN *NumberBlockDevices + ); + +/** + Gets a block device's media information. + + This function will provide the caller with the specified block device's media + information. If the media changes, calling this function will update the media + information accordingly. + + @param[in] PeiServices General-purpose services that are available to every + PEIM + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the + device index that was assigned during the enumeration + process. This index is a number from one to + NumberBlockDevices. + @param[out] MediaInfo The media information of the specified block media. + The caller is responsible for the ownership of this + data structure. + + @retval EFI_SUCCESS Media information about the specified block device + was obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware + error. + +**/ +EFI_STATUS +EFIAPI +BotGetMediaInfo ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo + ); + +/** + Reads the requested number of blocks from the specified block device. + + The function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. If there is no media in the device, + the function returns EFI_NO_MEDIA. + + @param[in] PeiServices General-purpose services that are available to + every PEIM. + @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance. + @param[in] DeviceIndex Specifies the block device to which the function wants + to talk. Because the driver that implements Block I/O + PPIs will manage multiple block devices, the PPIs that + want to talk to a single device must specify the device + index that was assigned during the enumeration process. + This index is a number from one to NumberBlockDevices. + @param[in] StartLBA The starting logical block address (LBA) to read from + on the device + @param[in] BufferSize The size of the Buffer in bytes. This number must be + a multiple of the intrinsic block size of the device. + @param[out] Buffer A pointer to the destination buffer for the data. + The caller is responsible for the ownership of the + buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting + to perform the read operation. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not + valid, or the buffer is not properly aligned. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of + the intrinsic block size of the device. + +**/ +EFI_STATUS +EFIAPI +BotReadBlocks ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This, + IN UINTN DeviceIndex, + IN EFI_PEI_LBA StartLBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + UsbIo installation notification function. + + This function finds out all the current USB IO PPIs in the system and add them + into private data. + + @param PeiServices Indirect reference to the PEI Services Table. + @param NotifyDesc Address of the notification descriptor data structure. + @param InvokePpi Address of the PPI that was invoked. + + @retval EFI_SUCCESS The function completes successfully. + +**/ +EFI_STATUS +EFIAPI +NotifyOnUsbIoPpi ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *InvokePpi + ); + +/** + Initialize the usb bot device. + + @param[in] PeiServices General-purpose services that are available to every + PEIM. + @param[in] UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS The usb bot device is initialized successfully. + @retval Other Failed to initialize media. + +**/ +EFI_STATUS +InitUsbBot ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi + ); + +#define USBCDROM 1 // let the device type value equal to USBCDROM, which is defined by PI spec. + // Therefore the CdExpressPei module can do recovery on UsbCdrom. +#define USBFLOPPY 2 // for those that use ReadCapacity(0x25) command to retrieve media capacity +#define USBFLOPPY2 3 // for those that use ReadFormatCapacity(0x23) command to retrieve media capacity + +// +// Bot device structure +// +#define PEI_BOT_DEVICE_SIGNATURE SIGNATURE_32 ('U', 'B', 'O', 'T') +typedef struct { + UINTN Signature; + EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi; + EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList; + EFI_PEI_BLOCK_IO_MEDIA Media; + PEI_USB_IO_PPI *UsbIoPpi; + EFI_USB_INTERFACE_DESCRIPTOR *BotInterface; + EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint; + EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint; + UINTN AllocateAddress; + UINTN DeviceType; + ATAPI_REQUEST_SENSE_DATA *SensePtr; +} PEI_BOT_DEVICE; + +#define PEI_BOT_DEVICE_FROM_THIS(a) CR (a, PEI_BOT_DEVICE, BlkIoPpi, PEI_BOT_DEVICE_SIGNATURE) + +/** + 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 + ); + +#endif diff --git a/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h new file mode 100644 index 0000000000..4f3f57f0bc --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h @@ -0,0 +1,179 @@ +/** @file +Usb Peim definition. + +Copyright (c) 2006, Intel Corporation. All rights reserved.
+ +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. + +**/ + +#ifndef _PEI_USB_PEIM_H_ +#define _PEI_USB_PEIM_H_ + + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#define MAX_ROOT_PORT 2 +#define MAX_ENDPOINT 16 + +#define USB_SLOW_SPEED_DEVICE 0x01 +#define USB_FULL_SPEED_DEVICE 0x02 + +#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D') +typedef struct { + UINTN Signature; + PEI_USB_IO_PPI UsbIoPpi; + EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList; + UINT8 DeviceAddress; + UINT8 MaxPacketSize0; + UINT8 DeviceSpeed; + UINT8 DataToggle; + UINT8 IsHub; + UINT8 DownStreamPortNo; + UINT8 Reserved[2]; // Padding for IPF + UINTN AllocateAddress; + PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi; + UINT8 ConfigurationData[1024]; + EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT]; +} PEI_USB_DEVICE; + +#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE) + + +/** + Submits control transfer to a target USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_IO_PPI. + @param Request USB device request to send. + @param Direction Specifies the data direction for the data stage. + @param Timeout Indicates the maximum timeout, in millisecond. + @param Data Data buffer to be transmitted or received from USB device. + @param DataLength The size (in bytes) of the data buffer. + + @retval EFI_SUCCESS Transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT Transfer failed due to timeout. + @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +PeiUsbControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT32 Timeout, + IN OUT VOID *Data, OPTIONAL + IN UINTN DataLength OPTIONAL + ); + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_IO_PPI. + @param DeviceEndpoint Endpoint number and its direction in bit 7. + @param Data A pointer to the buffer of data to transmit + from or receive into. + @param DataLength The lenght of the data buffer. + @param Timeout Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. + + @retval EFI_SUCCESS The transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. + @retval EFI_INVALID_PARAMETER Parameters are invalid. + @retval EFI_TIMEOUT The transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. + +**/ +EFI_STATUS +EFIAPI +PeiUsbBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout + ); + +/** + Get the usb interface descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + @param InterfaceDescriptor Request interface descriptor. + + + @retval EFI_SUCCESS Usb interface descriptor is obtained successfully. + +**/ +EFI_STATUS +EFIAPI +PeiUsbGetInterfaceDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor + ); + +/** + Get the usb endpoint descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + @param EndpointIndex The valid index of the specified endpoint. + @param EndpointDescriptor Request endpoint descriptor. + + @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully. + @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found. + +**/ +EFI_STATUS +EFIAPI +PeiUsbGetEndpointDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN UINT8 EndpointIndex, + OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor + ); + +/** + Reset the port and re-configure the usb device. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Usb device is reset and configured successfully. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +EFIAPI +PeiUsbPortReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This + ); + +#endif -- cgit v1.2.3