summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Usb/UsbBotPei
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-27 23:30:55 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-27 23:30:55 +0000
commit4b1bf81c20d5523554a83f6604df7930396f7c21 (patch)
tree8764ce333f14a1e5722b9d0f75ac1e09f1e0df29 /MdeModulePkg/Bus/Usb/UsbBotPei
parent366f81a016c11a59669cdfb5adb714e6f036f65f (diff)
downloadedk2-platforms-4b1bf81c20d5523554a83f6604df7930396f7c21.tar.xz
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
Diffstat (limited to 'MdeModulePkg/Bus/Usb/UsbBotPei')
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c401
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.h224
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c630
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.c331
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/PeiUsbLib.h248
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPei.inf65
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.c720
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/UsbBotPeim.h233
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBotPei/UsbPeim.h179
9 files changed, 3031 insertions, 0 deletions
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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UsbBotPeim.h"
+#include "BotPeim.h"
+#include "PeiUsbLib.h"
+
+/**
+ Reset the given usb device.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+
+ @retval EFI_INVALID_PARAMETER Can not get usb io ppi.
+ @retval EFI_SUCCESS Failed to reset the given usb device.
+
+**/
+EFI_STATUS
+BotRecoveryReset (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev
+ )
+{
+ EFI_USB_DEVICE_REQUEST DevReq;
+ UINT32 Timeout;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT8 EndpointAddr;
+ EFI_STATUS Status;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ if (UsbIoPpi == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
+
+ DevReq.RequestType = 0x21;
+ DevReq.Request = 0xFF;
+ DevReq.Value = 0;
+ DevReq.Index = 0;
+ DevReq.Length = 0;
+
+ Timeout = 3000;
+
+ Status = UsbIoPpi->UsbControlTransfer (
+ PeiServices,
+ UsbIoPpi,
+ &DevReq,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0
+ );
+
+ //
+ // clear bulk in endpoint stall feature
+ //
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
+
+ //
+ // clear bulk out endpoint stall feature
+ //
+ EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
+
+ return Status;
+}
+
+/**
+ Send the command to the device using Bulk-Out endpoint.
+
+ This function sends the command to the device using Bulk-Out endpoint.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Command phase.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param Command The command to transfer to device.
+ @param CommandSize The length of the command.
+ @param DataTransferLength The expected length of the data.
+ @param Direction The direction of the data.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to send the command to device.
+ @retval EFI_SUCCESS Failed to send the command to device.
+
+**/
+EFI_STATUS
+BotCommandPhase (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ IN VOID *Command,
+ IN UINT8 CommandSize,
+ IN UINT32 DataTransferLength,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT16 Timeout
+ )
+{
+ CBW Cbw;
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINTN DataSize;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ ZeroMem (&Cbw, sizeof (CBW));
+
+ //
+ // Fill the command block, detailed see BOT spec
+ //
+ Cbw.Signature = CBWSIG;
+ Cbw.Tag = 0x01;
+ Cbw.DataTransferLength = DataTransferLength;
+ Cbw.Flags = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0);
+ Cbw.Lun = 0;
+ Cbw.CmdLen = CommandSize;
+
+ CopyMem (Cbw.CmdBlock, Command, CommandSize);
+
+ DataSize = sizeof (CBW);
+
+ Status = UsbIoPpi->UsbBulkTransfer (
+ PeiServices,
+ UsbIoPpi,
+ (PeiBotDev->BulkOutEndpoint)->EndpointAddress,
+ (UINT8 *) &Cbw,
+ &DataSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Command phase fail, we need to recovery reset this device
+ //
+ BotRecoveryReset (PeiServices, PeiBotDev);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer the data between the device and host.
+
+ This function transfers the data between the device and host.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Data phase.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param DataSize The length of the data.
+ @param DataBuffer The pointer to the data.
+ @param Direction The direction of the data.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to send the data to device.
+ @retval EFI_SUCCESS Failed to send the data to device.
+
+**/
+EFI_STATUS
+BotDataPhase (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ IN UINT32 *DataSize,
+ IN OUT VOID *DataBuffer,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT16 Timeout
+ )
+{
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT8 EndpointAddr;
+ UINTN Remain;
+ UINTN Increment;
+ UINT32 MaxPacketLen;
+ UINT8 *BufferPtr;
+ UINTN TransferredSize;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ Remain = *DataSize;
+ BufferPtr = (UINT8 *) DataBuffer;
+ TransferredSize = 0;
+
+ //
+ // retrieve the the max packet length of the given endpoint
+ //
+ if (Direction == EfiUsbDataIn) {
+ MaxPacketLen = (PeiBotDev->BulkInEndpoint)->MaxPacketSize;
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
+ } else {
+ MaxPacketLen = (PeiBotDev->BulkOutEndpoint)->MaxPacketSize;
+ EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
+ }
+
+ while (Remain > 0) {
+ //
+ // Using 15 packets to avoid Bitstuff error
+ //
+ if (Remain > 16 * MaxPacketLen) {
+ Increment = 16 * MaxPacketLen;
+ } else {
+ Increment = Remain;
+ }
+
+ Status = UsbIoPpi->UsbBulkTransfer (
+ PeiServices,
+ UsbIoPpi,
+ EndpointAddr,
+ BufferPtr,
+ &Increment,
+ Timeout
+ );
+
+ TransferredSize += Increment;
+
+ if (EFI_ERROR (Status)) {
+ PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
+ return Status;
+ }
+
+ BufferPtr += Increment;
+ Remain -= Increment;
+ }
+
+ *DataSize = (UINT32) TransferredSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the command execution status from device.
+
+ This function gets the command execution status from device.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Status phase.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param TransferStatus The status of the transaction.
+ @param Timeout Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.
+ @retval EFI_SUCCESS Failed to get the status of device.
+
+**/
+EFI_STATUS
+BotStatusPhase (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ OUT UINT8 *TransferStatus,
+ IN UINT16 Timeout
+ )
+{
+ CSW Csw;
+ EFI_STATUS Status;
+ PEI_USB_IO_PPI *UsbIoPpi;
+ UINT8 EndpointAddr;
+ UINTN DataSize;
+
+ UsbIoPpi = PeiBotDev->UsbIoPpi;
+
+ ZeroMem (&Csw, sizeof (CSW));
+
+ EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
+
+ DataSize = sizeof (CSW);
+
+ //
+ // Get the status field from bulk transfer
+ //
+ Status = UsbIoPpi->UsbBulkTransfer (
+ PeiServices,
+ UsbIoPpi,
+ EndpointAddr,
+ &Csw,
+ &DataSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Csw.Signature == CSWSIG) {
+ *TransferStatus = Csw.Status;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send ATAPI command using BOT protocol.
+
+ @param PeiServices The pointer of EFI_PEI_SERVICES.
+ @param PeiBotDev The instance to PEI_BOT_DEVICE.
+ @param Command The command to be sent to ATAPI device.
+ @param CommandSize The length of the data to be sent.
+ @param DataBuffer The pointer to the data.
+ @param BufferLength The length of the data.
+ @param Direction The direction of the data.
+ @param TimeOutInMilliSeconds Indicates the maximum time, in millisecond, which the
+ transfer is allowed to complete.
+
+ @retval EFI_DEVICE_ERROR Successful to get the status of device.
+ @retval EFI_SUCCESS Failed to get the status of device.
+
+**/
+EFI_STATUS
+PeiAtapiCommand (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_BOT_DEVICE *PeiBotDev,
+ IN VOID *Command,
+ IN UINT8 CommandSize,
+ IN VOID *DataBuffer,
+ IN UINT32 BufferLength,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT16 TimeOutInMilliSeconds
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS BotDataStatus;
+ UINT8 TransferStatus;
+ UINT32 BufferSize;
+
+ BotDataStatus = EFI_SUCCESS;
+ //
+ // First send ATAPI command through Bot
+ //
+ Status = BotCommandPhase (
+ PeiServices,
+ PeiBotDev,
+ Command,
+ CommandSize,
+ BufferLength,
+ Direction,
+ TimeOutInMilliSeconds
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Send/Get Data if there is a Data Stage
+ //
+ switch (Direction) {
+ case EfiUsbDataIn:
+ case EfiUsbDataOut:
+ BufferSize = BufferLength;
+
+ BotDataStatus = BotDataPhase (
+ PeiServices,
+ PeiBotDev,
+ &BufferSize,
+ DataBuffer,
+ Direction,
+ TimeOutInMilliSeconds
+ );
+ break;
+
+ case EfiUsbNoData:
+ break;
+ }
+ //
+ // Status Phase
+ //
+ Status = BotStatusPhase (
+ PeiServices,
+ PeiBotDev,
+ &TransferStatus,
+ TimeOutInMilliSeconds
+ );
+ if (EFI_ERROR (Status)) {
+ BotRecoveryReset (PeiServices, PeiBotDev);
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (TransferStatus == 0x01) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return BotDataStatus;
+}
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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_BOT_PEIM_H_
+#define _PEI_BOT_PEIM_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/UsbIo.h>
+#include <Ppi/UsbHostController.h>
+#include <Ppi/BlockIo.h>
+
+//#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <IndustryStandard/Atapi.h>
+
+#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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UsbBotPeim.h"
+#include "BotPeim.h"
+
+#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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UsbBotPeim.h"
+#include "BotPeim.h"
+
+//
+// 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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_USB_BOT_PEIM_H_
+#define _PEI_USB_BOT_PEIM_H_
+
+#include <PiPei.h>
+
+#include <Ppi/UsbIo.h>
+#include <Ppi/UsbHostController.h>
+#include <Ppi/BlockIo.h>
+
+#include <Library/DebugLib.h>
+
+#include <IndustryStandard/Usb.h>
+#include <IndustryStandard/Atapi.h>
+
+#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.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_USB_PEIM_H_
+#define _PEI_USB_PEIM_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/UsbIo.h>
+#include <Ppi/UsbHostController.h>
+#include <Ppi/BlockIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/Usb.h>
+
+#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