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 +++++ MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c | 537 +++++++++++++ MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h | 279 +++++++ MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c | 333 ++++++++ MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h | 250 +++++++ MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf | 66 ++ MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c | 325 ++++++++ MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c | 1041 ++++++++++++++++++++++++++ MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h | 203 +++++ 17 files changed, 6065 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 create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c create mode 100644 MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h (limited to 'MdeModulePkg/Bus/Usb') 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 diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c new file mode 100644 index 0000000000..5b7ebfad90 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c @@ -0,0 +1,537 @@ +/** @file +Usb Hub Request Support In PEI Phase + +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 "UsbPeim.h" +#include "HubPeim.h" +#include "PeiUsbLib.h" + +/** + Get a given hub port status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param PortStatus Current Hub port status and change status. + + @retval EFI_SUCCESS Port status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + OUT UINT32 *PortStatus + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE; + DeviceRequest.Request = USB_HUB_GET_PORT_STATUS; + DeviceRequest.Index = Port; + DeviceRequest.Length = (UINT16) sizeof (UINT32); + + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + PortStatus, + sizeof (UINT32) + ); + +} + +/** + Set specified feature to a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value New feature value. + + @retval EFI_SUCCESS Port feature is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubSetPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE; + DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE; + DeviceRequest.Value = Value; + DeviceRequest.Index = Port; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Clear specified feature on a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Port feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE; + DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT; + DeviceRequest.Value = Value; + DeviceRequest.Index = Port; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Get a given hub status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param HubStatus Current Hub status and change status. + + @retval EFI_SUCCESS Hub status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetHubStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + OUT UINT32 *HubStatus + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE; + DeviceRequest.Request = USB_HUB_GET_HUB_STATUS; + DeviceRequest.Length = (UINT16) sizeof (UINT32); + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + HubStatus, + sizeof (UINT32) + ); +} + +/** + Set specified feature to a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value New feature value. + + @retval EFI_SUCCESS Port feature is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubSetHubFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Value + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_SET_HUB_FEATURE_REQ_TYPE; + DeviceRequest.Request = USB_HUB_SET_HUB_FEATURE; + DeviceRequest.Value = Value; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Clear specified feature on a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Hub feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearHubFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Value + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE; + DeviceRequest.Request = USB_HUB_CLEAR_FEATURE; + DeviceRequest.Value = Value; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Get a given hub descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param DescriptorSize The length of Hub Descriptor buffer. + @param HubDescriptor Caller allocated buffer to store the hub descriptor if + successfully returned. + + @retval EFI_SUCCESS Hub descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiGetHubDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = USB_RT_HUB | 0x80; + DevReq.Request = USB_HUB_GET_DESCRIPTOR; + DevReq.Value = USB_DT_HUB << 8; + DevReq.Length = (UINT16)DescriptorSize; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + HubDescriptor, + (UINT16)DescriptorSize + ); +} + +/** + Configure a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicating the hub controller device that will be configured + + @retval EFI_SUCCESS Hub configuration is done successfully. + @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error. + +**/ +EFI_STATUS +PeiDoHubConfig ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ) +{ + EFI_USB_HUB_DESCRIPTOR HubDescriptor; + EFI_STATUS Status; + EFI_USB_HUB_STATUS HubStatus; + UINTN Index; + UINT32 PortStatus; + PEI_USB_IO_PPI *UsbIoPpi; + + ZeroMem (&HubDescriptor, sizeof (HubDescriptor)); + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + + // + // First get the hub descriptor length + // + Status = PeiGetHubDescriptor ( + PeiServices, + UsbIoPpi, + 2, + &HubDescriptor + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // First get the whole descriptor, then + // get the number of hub ports + // + Status = PeiGetHubDescriptor ( + PeiServices, + UsbIoPpi, + HubDescriptor.Length, + &HubDescriptor + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts; + + Status = PeiHubGetHubStatus ( + PeiServices, + UsbIoPpi, + (UINT32 *) &HubStatus + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Get all hub ports status + // + for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { + + Status = PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + &PortStatus + ); + if (EFI_ERROR (Status)) { + continue; + } + } + // + // Power all the hub ports + // + for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { + Status = PeiHubSetPortFeature ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + EfiUsbPortPower + ); + if (EFI_ERROR (Status)) { + continue; + } + } + // + // Clear Hub Status Change + // + Status = PeiHubGetHubStatus ( + PeiServices, + UsbIoPpi, + (UINT32 *) &HubStatus + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } else { + // + // Hub power supply change happens + // + if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) { + PeiHubClearHubFeature ( + PeiServices, + UsbIoPpi, + C_HUB_LOCAL_POWER + ); + } + // + // Hub change overcurrent happens + // + if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) { + PeiHubClearHubFeature ( + PeiServices, + UsbIoPpi, + C_HUB_OVER_CURRENT + ); + } + } + + return EFI_SUCCESS; +} + +/** + Send reset signal over the given root hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param PortNum Usb hub port number (starting from 1). + +**/ +VOID +PeiResetHubPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 PortNum + ) +{ + UINT8 Try; + EFI_USB_PORT_STATUS HubPortStatus; + + + MicroSecondDelay (100 * 1000); + + // + // reset root port + // + PeiHubSetPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortReset + ); + + Try = 10; + do { + PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + PortNum, + (UINT32 *) &HubPortStatus + ); + + MicroSecondDelay (2 * 1000); + Try -= 1; + } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0); + + // + // clear reset root port + // + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortReset + ); + + MicroSecondDelay (1 * 1000); + + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortConnectChange + ); + + // + // Set port enable + // + PeiHubSetPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortEnable + ); + + // + // Clear any change status + // + + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortEnableChange + ); + + MicroSecondDelay (10 * 1000); + + return; +} diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h new file mode 100644 index 0000000000..273a26c1ae --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h @@ -0,0 +1,279 @@ +/** @file +Constants definitions for Usb Hub Peim + +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_HUB_PEIM_H_ +#define _PEI_HUB_PEIM_H_ + + +// +// Hub feature numbers +// +#define C_HUB_LOCAL_POWER 0 +#define C_HUB_OVER_CURRENT 1 + +// +// Hub class code & sub class code +// +#define CLASS_CODE_HUB 0x09 +#define SUB_CLASS_CODE_HUB 0 + +// +// Hub Status & Hub Change bit masks +// +#define HUB_STATUS_LOCAL_POWER 0x0001 +#define HUB_STATUS_OVERCURRENT 0x0002 + +#define HUB_CHANGE_LOCAL_POWER 0x0001 +#define HUB_CHANGE_OVERCURRENT 0x0002 + +// +// Hub Characteristics +// +#define HUB_CHAR_LPSM 0x0003 +#define HUB_CHAR_COMPOUND 0x0004 +#define HUB_CHAR_OCPM 0x0018 + +// +// Standard hub request and request type +// By [Spec-USB20/Chapter-11.24] +// +#define USB_HUB_CLEAR_FEATURE 0x01 +#define USB_HUB_CLEAR_FEATURE_REQ_TYPE 0x20 + +#define USB_HUB_CLEAR_FEATURE_PORT 0x01 +#define USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE 0x23 + +#define USB_HUB_GET_BUS_STATE 0x02 +#define USB_HUB_GET_BUS_STATE_REQ_TYPE 0xA3 + +#define USB_HUB_GET_DESCRIPTOR 0x06 +#define USB_HUB_GET_DESCRIPTOR_REQ_TYPE 0xA0 + +#define USB_HUB_GET_HUB_STATUS 0x00 +#define USB_HUB_GET_HUB_STATUS_REQ_TYPE 0xA0 + +#define USB_HUB_GET_PORT_STATUS 0x00 +#define USB_HUB_GET_PORT_STATUS_REQ_TYPE 0xA3 + +#define USB_HUB_SET_DESCRIPTOR 0x07 +#define USB_HUB_SET_DESCRIPTOR_REQ_TYPE 0x20 + +#define USB_HUB_SET_HUB_FEATURE 0x03 +#define USB_HUB_SET_HUB_FEATURE_REQ_TYPE 0x20 + +#define USB_HUB_SET_PORT_FEATURE 0x03 +#define USB_HUB_SET_PORT_FEATURE_REQ_TYPE 0x23 + +#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) +#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) + +#define MAXBYTES 8 +#pragma pack(1) +// +// Hub descriptor, the last two fields are of variable lenght. +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT8 NbrPorts; + UINT8 HubCharacteristics[2]; + UINT8 PwrOn2PwrGood; + UINT8 HubContrCurrent; + UINT8 Filler[MAXBYTES]; +} EFI_USB_HUB_DESCRIPTOR; + +typedef struct { + UINT16 HubStatus; + UINT16 HubChangeStatus; +} EFI_USB_HUB_STATUS; + +#pragma pack() +/** + Get a given hub port status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param PortStatus Current Hub port status and change status. + + @retval EFI_SUCCESS Port status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + OUT UINT32 *PortStatus + ); + +/** + Set specified feature to a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value New feature value. + + @retval EFI_SUCCESS Port feature is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubSetPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ); + +/** + Set specified feature to a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value New feature value. + + @retval EFI_SUCCESS Port feature is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubSetHubFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Value + ); + +/** + Get a given hub status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param HubStatus Current Hub status and change status. + + @retval EFI_SUCCESS Hub status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetHubStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + OUT UINT32 *HubStatus + ); + +/** + Clear specified feature on a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Port feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ); + +/** + Clear specified feature on a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Hub feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearHubFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Value + ); + +/** + Get a given hub descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param DescriptorSize The length of Hub Descriptor buffer. + @param HubDescriptor Caller allocated buffer to store the hub descriptor if + successfully returned. + + @retval EFI_SUCCESS Hub descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiGetHubDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ); + +/** + Configure a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicating the hub controller device that will be configured + + @retval EFI_SUCCESS Hub configuration is done successfully. + @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error. + +**/ +EFI_STATUS +PeiDoHubConfig ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ); + +/** + Send reset signal over the given root hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param PortNum Usb hub port number (starting from 1). + +**/ +VOID +PeiResetHubPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 PortNum + ); + +#endif + + diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c new file mode 100644 index 0000000000..2ac8d7bae3 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c @@ -0,0 +1,333 @@ +/** @file +Common Libarary for PEI USB + +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 "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. + +**/ +UINTN +IsPortLowSpeedDeviceAttached ( + IN UINT16 PortStatus + ) +{ + // + // return the bit 9 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) { + return EFI_USB_SPEED_LOW; + } else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){ + return EFI_USB_SPEED_HIGH; + } else { + return EFI_USB_SPEED_FULL; + } +} + +/** + 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/UsbBusPei/PeiUsbLib.h b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h new file mode 100644 index 0000000000..dd4ce1befc --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h @@ -0,0 +1,250 @@ +/** @file +Common Libarary for PEI USB + +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. + +**/ + +#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. + +**/ +UINTN +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/UsbBusPei/UsbBusPei.inf b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf new file mode 100644 index 0000000000..e4a2cb449a --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf @@ -0,0 +1,66 @@ +## @file +# Component description file for UsbPeim module. +# +# Usb Bus 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 = UsbBusPei + FILE_GUID = 8401A045-6F70-4505-8471-7015B40355E3 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimInitializeUsb + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PeiUsbLib.c + HubPeim.c + UsbIoPeim.c + UsbPeim.c + UsbPeim.h + PeiUsbLib.h + HubPeim.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + TimerLib + BaseMemoryLib + PeiServicesLib + PeimEntryPoint + DebugLib + PcdLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue + +[Ppis] + gPeiUsbIoPpiGuid # PPI ALWAYS_PRODUCED + gPeiUsbHostControllerPpiGuid # PPI ALWAYS_CONSUMED + gPeiUsb2HostControllerPpiGuid # PPI ALWAYS_CONSUMED + + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid AND gPeiUsb2HostControllerPpiGuid OR gPeiUsbHostControllerPpiGuid + diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c new file mode 100644 index 0000000000..897b22896a --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c @@ -0,0 +1,325 @@ +/** @file +The module is used to implement Usb Io PPI interfaces. + +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 "UsbPeim.h" +#include "PeiUsbLib.h" + +/** + 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 + ) +{ + EFI_STATUS Status; + PEI_USB_DEVICE *PeiUsbDev; + UINT32 TransferResult; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + if (PeiUsbDev->Usb2HcPpi != NULL) { + Status = PeiUsbDev->Usb2HcPpi->ControlTransfer ( + PeiServices, + PeiUsbDev->Usb2HcPpi, + PeiUsbDev->DeviceAddress, + PeiUsbDev->DeviceSpeed, + PeiUsbDev->MaxPacketSize0, + Request, + Direction, + Data, + &DataLength, + Timeout, + &(PeiUsbDev->Translator), + &TransferResult + ); + } else { + Status = PeiUsbDev->UsbHcPpi->ControlTransfer ( + PeiServices, + PeiUsbDev->UsbHcPpi, + PeiUsbDev->DeviceAddress, + PeiUsbDev->DeviceSpeed, + PeiUsbDev->MaxPacketSize0, + Request, + Direction, + Data, + &DataLength, + Timeout, + &TransferResult + ); + } + return Status; +} + +/** + 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 + ) +{ + EFI_STATUS Status; + PEI_USB_DEVICE *PeiUsbDev; + UINT32 TransferResult; + UINTN MaxPacketLength; + UINT8 DataToggle; + UINT8 OldToggle; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; + UINT8 EndpointIndex; + VOID *Data2[EFI_USB_MAX_BULK_BUFFER_NUM]; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + EndpointDescriptor = NULL; + EndpointIndex = 0; + Data2[0] = Data; + Data2[1] = NULL; + + while (EndpointIndex < MAX_ENDPOINT) { + Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) { + break; + } + + EndpointIndex++; + } + + if (EndpointIndex == MAX_ENDPOINT) { + return EFI_INVALID_PARAMETER; + } + + MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize; + if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) { + DataToggle = 1; + } else { + DataToggle = 0; + } + + OldToggle = DataToggle; + + if (PeiUsbDev->Usb2HcPpi != NULL) { + Status = PeiUsbDev->Usb2HcPpi->BulkTransfer ( + PeiServices, + PeiUsbDev->Usb2HcPpi, + PeiUsbDev->DeviceAddress, + DeviceEndpoint, + PeiUsbDev->DeviceSpeed, + MaxPacketLength, + Data2, + DataLength, + &DataToggle, + Timeout, + &(PeiUsbDev->Translator), + &TransferResult + ); + } else { + Status = PeiUsbDev->UsbHcPpi->BulkTransfer ( + PeiServices, + PeiUsbDev->UsbHcPpi, + PeiUsbDev->DeviceAddress, + DeviceEndpoint, + (UINT8) MaxPacketLength, + Data, + DataLength, + &DataToggle, + Timeout, + &TransferResult + ); + } + + if (OldToggle != DataToggle) { + PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex)); + } + + return Status; +} + +/** + 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 + ) +{ + PEI_USB_DEVICE *PeiUsbDev; + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + *InterfaceDescriptor = PeiUsbDev->InterfaceDesc; + return EFI_SUCCESS; +} + +/** + 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 + ) +{ + PEI_USB_DEVICE *PeiUsbDev; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + ASSERT (EndpointDescriptor != NULL); + + // + // The valid range of EndpointIndex is 0..15 + // If EndpointIndex is lesser than 15 but larger than the number of interfaces, + // a EFI_NOT_FOUND should be returned + // + ASSERT (EndpointIndex <= 15); + + if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) { + return EFI_NOT_FOUND; + } + + *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex]; + + return EFI_SUCCESS; +} + +/** + 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 + ) +{ + PEI_USB_DEVICE *PeiUsbDev; + EFI_STATUS Status; + UINT8 Address; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + ResetRootPort ( + PeiServices, + PeiUsbDev->UsbHcPpi, + PeiUsbDev->Usb2HcPpi, + PeiUsbDev->DeviceAddress, + 0 + ); + + // + // Set address + // + Address = PeiUsbDev->DeviceAddress; + PeiUsbDev->DeviceAddress = 0; + + Status = PeiUsbSetDeviceAddress ( + PeiServices, + This, + Address + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + PeiUsbDev->DeviceAddress = Address; + + // + // Set default configuration + // + Status = PeiUsbSetConfiguration ( + PeiServices, + This + ); + + return Status; +} diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c new file mode 100644 index 0000000000..4a5d8e8bc4 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c @@ -0,0 +1,1041 @@ +/** @file +The module to produce Usb Bus PPI. + +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 "UsbPeim.h" +#include "HubPeim.h" +#include "PeiUsbLib.h" + +// +// UsbIo PPI interface function +// +PEI_USB_IO_PPI mUsbIoPpi = { + PeiUsbControlTransfer, + PeiUsbBulkTransfer, + PeiUsbGetInterfaceDescriptor, + PeiUsbGetEndpointDescriptor, + PeiUsbPortReset +}; + +EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiUsbIoPpiGuid, + NULL +}; + +/** + The enumeration routine to detect device change. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + + @retval EFI_SUCCESS The usb is enumerated successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbEnumeration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi + ); + +/** + Configure new detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + @param Port The port to be configured. + @param DeviceAddress The device address to be configured. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiConfigureUsbDevice ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN UINT8 Port, + IN OUT UINT8 *DeviceAddress + ); + +/** + Get all configurations from a detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetAllConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ); + +/** + Get the start position of next wanted descriptor. + + @param Buffer Buffer containing data to parse. + @param Length Buffer length. + @param DescType Descriptor type. + @param DescLength Descriptor length. + @param ParsedBytes Bytes has been parsed. + + @retval EFI_SUCCESS Get wanted descriptor successfully. + @retval EFI_DEVICE_ERROR Error occurred. + +**/ +EFI_STATUS +GetExpectedDescriptor ( + IN UINT8 *Buffer, + IN UINTN Length, + IN UINT8 DescType, + IN UINT8 DescLength, + OUT UINTN *ParsedBytes + ); + +/** + The entrypoint of the module, it will enumerate all HCs. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Usb initialization is done successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval EFI_UNSUPPORTED Can't find required PPI. + +**/ +EFI_STATUS +EFIAPI +PeimInitializeUsb ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINTN Index; + PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi; + PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi; + + if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { + return EFI_SUCCESS; + } + + // + // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not + // be produced at the same time + // + Index = 0; + while (TRUE) { + // + // Get UsbHcPpi at first. + // + Status = PeiServicesLocatePpi ( + &gPeiUsbHostControllerPpiGuid, + Index, + NULL, + (VOID **) &UsbHcPpi + ); + if (EFI_ERROR (Status)) { + // + // No more host controller, break out + // + break; + } + PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL); + Index++; + } + + if (Index == 0) { + // + // Then try to get Usb2HcPpi. + // + while (TRUE) { + Status = PeiServicesLocatePpi ( + &gPeiUsb2HostControllerPpiGuid, + Index, + NULL, + (VOID **) &Usb2HcPpi + ); + if (EFI_ERROR (Status)) { + // + // No more host controller, break out + // + break; + } + PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi); + Index++; + } + } + + if (Index == 0) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + The Hub Enumeration just scans the hub ports one time. It also + doesn't support hot-plug. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + @param CurrentAddress The DeviceAddress of usb device. + + @retval EFI_SUCCESS The usb hub is enumerated successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubEnumeration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN UINT8 *CurrentAddress + ) +{ + UINTN Index; + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + EFI_USB_PORT_STATUS PortStatus; + UINTN MemPages; + EFI_PHYSICAL_ADDRESS AllocateAddress; + PEI_USB_DEVICE *NewPeiUsbDevice; + + + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + + for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { + + Status = PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + (UINT32 *) &PortStatus + ); + + if (EFI_ERROR (Status)) { + continue; + } + + if (IsPortConnectChange (PortStatus.PortChangeStatus)) { + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + EfiUsbPortConnectChange + ); + + MicroSecondDelay (100 * 1000); + + if (IsPortConnect (PortStatus.PortStatus)) { + + PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + (UINT32 *) &PortStatus + ); + + // + // Begin to deal with the new device + // + MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE)); + + NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; + NewPeiUsbDevice->DeviceAddress = 0; + NewPeiUsbDevice->MaxPacketSize0 = 8; + NewPeiUsbDevice->DataToggle = 0; + CopyMem ( + &(NewPeiUsbDevice->UsbIoPpi), + &mUsbIoPpi, + sizeof (PEI_USB_IO_PPI) + ); + CopyMem ( + &(NewPeiUsbDevice->UsbIoPpiList), + &mUsbIoPpiList, + sizeof (EFI_PEI_PPI_DESCRIPTOR) + ); + NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi; + NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress; + NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi; + NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi; + NewPeiUsbDevice->IsHub = 0x0; + NewPeiUsbDevice->DownStreamPortNo = 0x0; + + PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1)); + + PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + (UINT32 *) &PortStatus + ); + + NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus); + + if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) { + if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) { + NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index; + NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress; + } else { + CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR)); + } + } + + // + // Configure that Usb Device + // + Status = PeiConfigureUsbDevice ( + PeiServices, + NewPeiUsbDevice, + (UINT8) (Index + 1), + CurrentAddress + ); + + if (EFI_ERROR (Status)) { + continue; + } + + Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList); + + if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { + NewPeiUsbDevice->IsHub = 0x1; + + Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress); + } + } + + } + } + + + return EFI_SUCCESS; +} + +/** + The enumeration routine to detect device change. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + + @retval EFI_SUCCESS The usb is enumerated successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbEnumeration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi + ) +{ + UINT8 NumOfRootPort; + EFI_STATUS Status; + UINT8 Index; + EFI_USB_PORT_STATUS PortStatus; + PEI_USB_DEVICE *PeiUsbDevice; + UINTN MemPages; + EFI_PHYSICAL_ADDRESS AllocateAddress; + UINT8 CurrentAddress; + + + CurrentAddress = 0; + if (Usb2HcPpi != NULL){ + Usb2HcPpi->GetRootHubPortNumber ( + PeiServices, + Usb2HcPpi, + (UINT8 *) &NumOfRootPort + ); + } else { + UsbHcPpi->GetRootHubPortNumber ( + PeiServices, + UsbHcPpi, + (UINT8 *) &NumOfRootPort + ); + } + + for (Index = 0; Index < NumOfRootPort; Index++) { + // + // First get root port status to detect changes happen + // + if (Usb2HcPpi != NULL) { + Usb2HcPpi->GetRootHubPortStatus ( + PeiServices, + Usb2HcPpi, + (UINT8) Index, + &PortStatus + ); + } else { + UsbHcPpi->GetRootHubPortStatus ( + PeiServices, + UsbHcPpi, + (UINT8) Index, + &PortStatus + ); + } + DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus)); + if (IsPortConnectChange (PortStatus.PortChangeStatus)) { + // + // Changes happen, first clear this change status + // + if (Usb2HcPpi != NULL) { + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + (UINT8) Index, + EfiUsbPortConnectChange + ); + } else { + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + (UINT8) Index, + EfiUsbPortConnectChange + ); + } + MicroSecondDelay (100 * 1000); + + if (IsPortConnect (PortStatus.PortStatus)) { + if (Usb2HcPpi != NULL) { + Usb2HcPpi->GetRootHubPortStatus ( + PeiServices, + Usb2HcPpi, + (UINT8) Index, + &PortStatus + ); + } else { + UsbHcPpi->GetRootHubPortStatus ( + PeiServices, + UsbHcPpi, + (UINT8) Index, + &PortStatus + ); + } + + // + // Connect change happen + // + MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE)); + + PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; + PeiUsbDevice->DeviceAddress = 0; + PeiUsbDevice->MaxPacketSize0 = 8; + PeiUsbDevice->DataToggle = 0; + CopyMem ( + &(PeiUsbDevice->UsbIoPpi), + &mUsbIoPpi, + sizeof (PEI_USB_IO_PPI) + ); + CopyMem ( + &(PeiUsbDevice->UsbIoPpiList), + &mUsbIoPpiList, + sizeof (EFI_PEI_PPI_DESCRIPTOR) + ); + PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi; + PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress; + PeiUsbDevice->UsbHcPpi = UsbHcPpi; + PeiUsbDevice->Usb2HcPpi = Usb2HcPpi; + PeiUsbDevice->IsHub = 0x0; + PeiUsbDevice->DownStreamPortNo = 0x0; + + ResetRootPort ( + PeiServices, + PeiUsbDevice->UsbHcPpi, + PeiUsbDevice->Usb2HcPpi, + Index, + 0 + ); + + if (Usb2HcPpi != NULL) { + Usb2HcPpi->GetRootHubPortStatus ( + PeiServices, + Usb2HcPpi, + (UINT8) Index, + &PortStatus + ); + } else { + UsbHcPpi->GetRootHubPortStatus ( + PeiServices, + UsbHcPpi, + (UINT8) Index, + &PortStatus + ); + } + + PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus); + DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed)); + + // + // Configure that Usb Device + // + Status = PeiConfigureUsbDevice ( + PeiServices, + PeiUsbDevice, + Index, + &CurrentAddress + ); + + if (EFI_ERROR (Status)) { + continue; + } + DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n")); + + Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); + + if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { + PeiUsbDevice->IsHub = 0x1; + + Status = PeiDoHubConfig (PeiServices, PeiUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress); + } + } else { + // + // Disconnect change happen, currently we don't support + // + } + } + } + + return EFI_SUCCESS; +} + +/** + Configure new detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + @param Port The port to be configured. + @param DeviceAddress The device address to be configured. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiConfigureUsbDevice ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN UINT8 Port, + IN OUT UINT8 *DeviceAddress + ) +{ + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + UINT8 Retry; + + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + Status = EFI_SUCCESS; + ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR)); + // + // Get USB device descriptor + // + + for (Retry = 0; Retry < 3; Retry ++) { + + PeiUsbDevice->MaxPacketSize0 = 8; + + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_DEVICE << 8), + 0, + 8, + &DeviceDescriptor + ); + + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry)); + break; + } + } + + if (Retry == 3) { + DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry)); + return Status; + } + + PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0; + + (*DeviceAddress) ++; + + Status = PeiUsbSetDeviceAddress ( + PeiServices, + UsbIoPpi, + *DeviceAddress + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n")); + return Status; + } + + PeiUsbDevice->DeviceAddress = *DeviceAddress; + + // + // Get whole USB device descriptor + // + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_DEVICE << 8), + 0, + (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR), + &DeviceDescriptor + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n")); + return Status; + } + // + // Get its default configuration and its first interface + // + Status = PeiUsbGetAllConfiguration ( + PeiServices, + PeiUsbDevice + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PeiUsbSetConfiguration ( + PeiServices, + UsbIoPpi + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Get all configurations from a detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetAllConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ) +{ + EFI_STATUS Status; + EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc; + PEI_USB_IO_PPI *UsbIoPpi; + UINT16 ConfigDescLength; + UINT8 *Ptr; + UINTN SkipBytes; + UINTN LengthLeft; + UINTN Index; + UINTN NumOfEndpoint; + + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + + // + // First get its 4-byte configuration descriptor + // + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_CONFIG << 8), // Value + 0, // Index + 4, // Length + PeiUsbDevice->ConfigurationData + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n")); + return Status; + } + + ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData; + ConfigDescLength = ConfigDesc->TotalLength; + + // + // Then we get the total descriptors for this configuration + // + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_CONFIG << 8), + 0, + ConfigDescLength, + PeiUsbDevice->ConfigurationData + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n")); + return Status; + } + // + // Parse this configuration descriptor + // First get the current config descriptor; + // + Status = GetExpectedDescriptor ( + PeiUsbDevice->ConfigurationData, + ConfigDescLength, + USB_DT_CONFIG, + (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr = PeiUsbDevice->ConfigurationData + SkipBytes; + PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr; + + Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR); + LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR); + + // + // Get the first interface descriptor + // + Status = GetExpectedDescriptor ( + Ptr, + LengthLeft, + USB_DT_INTERFACE, + (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr += SkipBytes; + PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr; + + Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + LengthLeft -= SkipBytes; + LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + + // + // Parse all the endpoint descriptor within this interface + // + NumOfEndpoint = PeiUsbDevice->InterfaceDesc->NumEndpoints; + ASSERT (NumOfEndpoint <= MAX_ENDPOINT); + + for (Index = 0; Index < NumOfEndpoint; Index++) { + // + // Get the endpoint descriptor + // + Status = GetExpectedDescriptor ( + Ptr, + LengthLeft, + USB_DT_ENDPOINT, + (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr += SkipBytes; + PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr; + + Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + LengthLeft -= SkipBytes; + LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + } + + return EFI_SUCCESS; +} + +/** + Get the start position of next wanted descriptor. + + @param Buffer Buffer containing data to parse. + @param Length Buffer length. + @param DescType Descriptor type. + @param DescLength Descriptor length. + @param ParsedBytes Bytes has been parsed. + + @retval EFI_SUCCESS Get wanted descriptor successfully. + @retval EFI_DEVICE_ERROR Error occurred. + +**/ +EFI_STATUS +GetExpectedDescriptor ( + IN UINT8 *Buffer, + IN UINTN Length, + IN UINT8 DescType, + IN UINT8 DescLength, + OUT UINTN *ParsedBytes + ) +{ + UINT16 DescriptorHeader; + UINT8 Len; + UINT8 *Ptr; + UINTN Parsed; + + Parsed = 0; + Ptr = Buffer; + + while (TRUE) { + // + // Buffer length should not less than Desc length + // + if (Length < DescLength) { + return EFI_DEVICE_ERROR; + } + + DescriptorHeader = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8)); + + Len = Buffer[0]; + + // + // Check to see if it is a start of expected descriptor + // + if (DescriptorHeader == ((DescType << 8) | DescLength)) { + break; + } + + if ((UINT8) (DescriptorHeader >> 8) == DescType) { + if (Len > DescLength) { + return EFI_DEVICE_ERROR; + } + } + // + // Descriptor length should be at least 2 + // and should not exceed the buffer length + // + if (Len < 2) { + return EFI_DEVICE_ERROR; + } + + if (Len > Length) { + return EFI_DEVICE_ERROR; + } + // + // Skip this mismatch descriptor + // + Length -= Len; + Ptr += Len; + Parsed += Len; + } + + *ParsedBytes = Parsed; + + return EFI_SUCCESS; +} + +/** + Send reset signal over the given root hub port. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + @param PortNum The port to be reset. + @param RetryIndex The retry times. + +**/ +VOID +ResetRootPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi, + IN UINT8 PortNum, + IN UINT8 RetryIndex + ) +{ + EFI_STATUS Status; + + + if (Usb2HcPpi != NULL) { + MicroSecondDelay (200 * 1000); + + // + // reset root port + // + Status = Usb2HcPpi->SetRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + MicroSecondDelay (200 * 1000); + + // + // clear reset root port + // + Status = Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + MicroSecondDelay (1 * 1000); + + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortConnectChange + ); + + // + // Set port enable + // + Usb2HcPpi->SetRootHubPortFeature( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortEnable + ); + + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortEnableChange + ); + + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); + } else { + MicroSecondDelay (200 * 1000); + + // + // reset root port + // + Status = UsbHcPpi->SetRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + MicroSecondDelay (200 * 1000); + + // + // clear reset root port + // + Status = UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + MicroSecondDelay (1 * 1000); + + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortConnectChange + ); + + // + // Set port enable + // + UsbHcPpi->SetRootHubPortFeature( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortEnable + ); + + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortEnableChange + ); + + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); + } + return; +} + + diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h new file mode 100644 index 0000000000..c9e75bad53 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h @@ -0,0 +1,203 @@ +/** @file +Usb Peim definition. + +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. + +**/ + +#ifndef _PEI_USB_PEIM_H_ +#define _PEI_USB_PEIM_H_ + + +#include + +#include +#include +#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; + PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi; + UINT8 ConfigurationData[1024]; + EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT]; + EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator; +} 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 + ); + +/** + Send reset signal over the given root hub port. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + @param PortNum The port to be reset. + @param RetryIndex The retry times. + +**/ +VOID +ResetRootPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi, + IN UINT8 PortNum, + IN UINT8 RetryIndex + ); + +#endif -- cgit v1.2.3