summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Usb/UsbMassStorageDxe
diff options
context:
space:
mode:
authorvanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-11 08:47:37 +0000
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-11 08:47:37 +0000
commite237e7ae9fc23f32a25040d49cc9a16f2a7f3b4c (patch)
treef7c7ea55cac3b9816f5f6f2a39fbc09406e7a134 /MdeModulePkg/Bus/Usb/UsbMassStorageDxe
parentf183b4f349e207768bfbf3287b9d37ac7b16d101 (diff)
downloadedk2-platforms-e237e7ae9fc23f32a25040d49cc9a16f2a7f3b4c.tar.xz
Import Usb/UsbBusDxe and Usb/UsbMassStorageDxe into MdeModulePkg.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3193 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Bus/Usb/UsbMassStorageDxe')
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c153
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h149
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c886
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h268
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c561
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h102
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c619
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h64
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c640
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h57
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf95
-rw-r--r--MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.msa75
12 files changed, 3669 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c
new file mode 100644
index 0000000000..bd0f939225
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c
@@ -0,0 +1,153 @@
+ /*++
+
+Copyright (c) 2004 - 2007, 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.
+
+Module Name:
+
+ ComponentName.c
+
+Abstract:
+
+--*/
+
+//
+// The package level header files this module uses
+//
+#include <PiDxe.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/UefiLib.h>
+
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+EFIAPI
+UsbMassStorageGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+UsbMassStorageGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName = {
+ UsbMassStorageGetDriverName,
+ UsbMassStorageGetControllerName,
+ "eng"
+};
+
+STATIC EFI_UNICODE_STRING_TABLE
+mUsbMassStorageDriverNameTable[] = {
+ {"eng", L"Usb Mass Storage Driver"},
+ {NULL, NULL}
+};
+
+EFI_STATUS
+EFIAPI
+UsbMassStorageGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ Language - A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ DriverName - A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ Returns:
+ EFI_SUCCESS - The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ EFI_INVALID_PARAMETER - Language is NULL.
+ EFI_INVALID_PARAMETER - DriverName is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return LookupUnicodeString (
+ Language,
+ gUsbMassStorageComponentName.SupportedLanguages,
+ mUsbMassStorageDriverNameTable,
+ DriverName
+ );
+}
+
+EFI_STATUS
+EFIAPI
+UsbMassStorageGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+/*++
+
+ Routine Description:
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ Arguments:
+ This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ ControllerHandle - The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ ChildHandle - The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ ControllerName - A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language from the point of view of the driver specified
+ by This.
+
+ Returns:
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+
+--*/
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h
new file mode 100644
index 0000000000..c48dee5a7b
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h
@@ -0,0 +1,149 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMass.h
+
+Abstract:
+
+ Defination for the USB mass storage class driver. The USB mass storage
+ class is specified in two layers: the bottom layer is the transportation
+ protocol. The top layer is the command set. The transportation layer
+ provides the transportation of the command, data and result. The command
+ set defines what the command, data and result. The Bulk-Only-Transport and
+ Control/Bulk/Interrupt transport are two transportation protocol. USB mass
+ storage class adopts various industrial standard as its command set.
+
+Revision History
+
+
+**/
+
+#ifndef _EFI_USBMASS_H_
+#define _EFI_USBMASS_H_
+
+//
+// The package level header files this module uses
+//
+#include <PiDxe.h>
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Protocol/BlockIo.h>
+#include <Protocol/UsbIo.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0x80)
+#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0)
+#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x02)
+#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x03)
+#define USB_IS_ERROR(Result, Error) (((Result) & (Error)) != 0)
+
+enum {
+ //
+ // Usb mass storage class code
+ //
+ USB_MASS_STORE_CLASS = 0x08,
+
+ //
+ // Usb mass storage subclass code, specify the command set used.
+ //
+ USB_MASS_STORE_RBC = 0x01, // Reduced Block Commands
+ USB_MASS_STORE_8020I = 0x02, // SFF-8020i, typically a CD/DVD device
+ USB_MASS_STORE_QIC = 0x03, // Typically a tape device
+ USB_MASS_STORE_UFI = 0x04, // Typically a floopy disk driver device
+ USB_MASS_STORE_8070I = 0x05, // SFF-8070i, typically a floppy disk driver device.
+ USB_MASS_STORE_SCSI = 0x06, // SCSI transparent command set
+
+ //
+ // Usb mass storage protocol code, specify the transport protocol
+ //
+ USB_MASS_STORE_CBI0 = 0x00, // CBI protocol with command completion interrupt
+ USB_MASS_STORE_CBI1 = 0x01, // CBI protocol without command completion interrupt
+ USB_MASS_STORE_BOT = 0x50, // Bulk-Only Transport
+
+ USB_MASS_STALL_1_MS = 1000,
+ USB_MASS_STALL_1_S = 1000 * USB_MASS_STALL_1_MS,
+
+ USB_MASS_CMD_SUCCESS = 0,
+ USB_MASS_CMD_FAIL,
+ USB_MASS_CMD_PERSISTENT,
+};
+
+typedef
+EFI_STATUS
+(*USB_MASS_INIT_TRANSPORT) (
+ IN EFI_USB_IO_PROTOCOL *Usb,
+ IN EFI_HANDLE Controller,
+ OUT VOID **Context OPTIONAL
+ );
+
+typedef
+EFI_STATUS
+(*USB_MASS_EXEC_COMMAND) (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ );
+
+typedef
+EFI_STATUS
+(*USB_MASS_RESET) (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+typedef
+EFI_STATUS
+(*USB_MASS_FINI) (
+ IN VOID *Context
+ );
+
+//
+// This structure contains information necessary to select the
+// proper transport protocol. The mass storage class defines
+// two transport protocols. One is the CBI, and the other is BOT.
+// CBI is being obseleted. The design is made modular by this
+// structure so that the CBI protocol can be easily removed when
+// it is no longer necessary.
+//
+typedef struct {
+ UINT8 Protocol;
+ USB_MASS_INIT_TRANSPORT Init; // Initialize the mass storage transport protocol
+ USB_MASS_EXEC_COMMAND ExecCommand; // Transport command to the device then get result
+ USB_MASS_RESET Reset; // Reset the device
+ USB_MASS_FINI Fini; // Clean up the resources.
+} USB_MASS_TRANSPORT;
+
+
+EFI_STATUS
+UsbClearEndpointStall (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN UINT8 EndpointAddress
+ );
+
+extern UINTN mUsbMscInfo;
+extern UINTN mUsbMscError;
+#endif
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
new file mode 100644
index 0000000000..980f8b2895
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
@@ -0,0 +1,886 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassBoot.c
+
+Abstract:
+
+ This file implement the command set of "USB Mass Storage Specification
+ for Bootability".
+
+Revision History
+
+
+**/
+
+#include "UsbMassImpl.h"
+
+
+/**
+ Read an UINT32 from the buffer to avoid byte alignment problems, then
+ convert that to the little endia. The USB mass storage bootability spec
+ use big endia
+
+ @param Buf The buffer contains the first byte of the UINT32
+ in big endia.
+
+ @return The UINT32 value read from the buffer in little endia.
+
+**/
+STATIC
+UINT32
+UsbBootGetUint32 (
+ IN UINT8 *Buf
+ )
+{
+ UINT32 Value;
+
+ CopyMem (&Value, Buf, sizeof (UINT32));
+ return USB_BOOT_SWAP32 (Value);
+}
+
+
+/**
+ Put an UINT32 in little endia to the buffer. The data is converted to
+ big endia before writing.
+
+ @param Buf The buffer to write data to
+ @param Data32 The data to write.
+
+ @return None
+
+**/
+STATIC
+VOID
+UsbBootPutUint32 (
+ IN UINT8 *Buf,
+ IN UINT32 Data32
+ )
+{
+ Data32 = USB_BOOT_SWAP32 (Data32);
+ CopyMem (Buf, &Data32, sizeof (UINT32));
+}
+
+
+/**
+ Put an UINT16 in little endia to the buffer. The data is converted to
+ big endia before writing.
+
+ @param Buf The buffer to write data to
+ @param Data16 The data to write
+
+ @return None
+
+**/
+STATIC
+VOID
+UsbBootPutUint16 (
+ IN UINT8 *Buf,
+ IN UINT16 Data16
+ )
+{
+ Data16 = USB_BOOT_SWAP16 (Data16);
+ CopyMem (Buf, &Data16, sizeof (UINT16));
+}
+
+
+/**
+ Request sense information via sending Request Sense
+ Packet Command.
+
+ @param UsbMass The device to be requested sense data
+
+ @retval EFI_DEVICE_ERROR Hardware error
+ @retval EFI_SUCCESS Success
+
+**/
+EFI_STATUS
+UsbBootRequestSense (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_REQUEST_SENSE_CMD SenseCmd;
+ USB_BOOT_REQUEST_SENSE_DATA SenseData;
+ EFI_BLOCK_IO_MEDIA *Media;
+ USB_MASS_TRANSPORT *Transport;
+ EFI_STATUS Status;
+ UINT32 CmdResult;
+
+ Transport = UsbMass->Transport;
+
+ //
+ // Request the sense data from the device if command failed
+ //
+ ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
+ ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
+
+ SenseCmd.OpCode = USB_BOOT_REQUEST_SENSE_OPCODE;
+ SenseCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
+ SenseCmd.AllocLen = sizeof (USB_BOOT_REQUEST_SENSE_DATA);
+
+ Status = Transport->ExecCommand (
+ UsbMass->Context,
+ &SenseCmd,
+ sizeof (USB_BOOT_REQUEST_SENSE_CMD),
+ EfiUsbDataIn,
+ &SenseData,
+ sizeof (USB_BOOT_REQUEST_SENSE_DATA),
+ USB_BOOT_GENERAL_CMD_TIMEOUT,
+ &CmdResult
+ );
+ if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
+ DEBUG ((mUsbMscError, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Interpret the sense data and update the media status if necessary.
+ //
+ Media = &UsbMass->BlockIoMedia;
+
+ switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {
+
+ case USB_BOOT_SENSE_NO_SENSE:
+ case USB_BOOT_SENSE_RECOVERED:
+ //
+ // Suppose hardware can handle this case, and recover later by itself
+ //
+ Status = EFI_NOT_READY;
+ break;
+
+ case USB_BOOT_SENSE_NOT_READY:
+ switch (SenseData.ASC) {
+ case USB_BOOT_ASC_NO_MEDIA:
+ Status = EFI_NO_MEDIA;
+ Media->MediaPresent = FALSE;
+ break;
+
+ case USB_BOOT_ASC_MEDIA_UPSIDE_DOWN:
+ Status = EFI_DEVICE_ERROR;
+ Media->MediaPresent = FALSE;
+ break;
+
+ case USB_BOOT_ASC_NOT_READY:
+ if (SenseData.ASCQ == USB_BOOT_ASCQ_IN_PROGRESS ||
+ SenseData.ASCQ == USB_BOOT_ASCQ_DEVICE_BUSY) {
+ //
+ // Regular timeout, and need retry once more
+ //
+ DEBUG ((mUsbMscInfo, "UsbBootRequestSense: Not ready and need retry once more\n"));
+ Status = EFI_NOT_READY;
+ }
+ }
+ break;
+
+ case USB_BOOT_SENSE_ILLEGAL_REQUEST:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+
+ case USB_BOOT_SENSE_UNIT_ATTENTION:
+ Status = EFI_DEVICE_ERROR;
+ if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) {
+ Status = EFI_MEDIA_CHANGED;
+ UsbMass->BlockIoMedia.MediaId++;
+ }
+ break;
+
+ case USB_BOOT_SNESE_DATA_PROTECT:
+ Status = EFI_WRITE_PROTECTED;
+ UsbMass->BlockIoMedia.ReadOnly = TRUE;
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ DEBUG ((mUsbMscInfo, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",
+ Status,
+ USB_BOOT_SENSE_KEY (SenseData.SenseKey),
+ SenseData.ASC,
+ SenseData.ASCQ
+ ));
+
+ return Status;
+}
+
+
+/**
+ Execute the USB mass storage bootability commands. If execution
+ failed, retrieve the error by REQUEST_SENSE then update the device's
+ status, such as ReadyOnly.
+
+ @param UsbMass The device to issue commands to
+ @param Cmd The command to execute
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of expected data
+ @param Timeout The timeout used to transfer
+
+ @retval EFI_SUCCESS The command is excuted OK
+ @retval EFI_DEVICE_ERROR Failed to request sense
+ @retval EFI_INVALID_PARAMETER The command has some invalid parameters
+ @retval EFI_WRITE_PROTECTED The device is write protected
+ @retval EFI_MEDIA_CHANGED The device media has been changed
+
+**/
+STATIC
+EFI_STATUS
+UsbBootExecCmd (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT32 Timeout
+ )
+{
+ USB_MASS_TRANSPORT *Transport;
+ EFI_STATUS Status;
+ UINT32 CmdResult;
+
+ Transport = UsbMass->Transport;
+ Status = Transport->ExecCommand (
+ UsbMass->Context,
+ Cmd,
+ CmdLen,
+ DataDir,
+ Data,
+ DataLen,
+ Timeout,
+ &CmdResult
+ );
+ //
+ // ExecCommand return success and get the right CmdResult means
+ // the commnad transfer is OK.
+ //
+ if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR(Status)) {
+ return EFI_SUCCESS;
+ }
+
+ return UsbBootRequestSense (UsbMass);
+}
+
+
+/**
+ Execute the USB mass storage bootability commands. If execution
+ failed, retrieve the error by REQUEST_SENSE then update the device's
+ status, such as ReadyOnly.
+
+ @param UsbMass The device to issue commands to
+ @param Cmd The command to execute
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of expected data
+
+ @retval EFI_SUCCESS The command is excuted OK
+ @retval EFI_DEVICE_ERROR Failed to request sense
+ @retval EFI_INVALID_PARAMETER The command has some invalid parameters
+ @retval EFI_WRITE_PROTECTED The device is write protected
+ @retval EFI_MEDIA_CHANGED The device media has been changed
+
+**/
+STATIC
+EFI_STATUS
+UsbBootExecCmdWithRetry (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_STATUS Status;
+ INT16 Index;
+
+ //
+ // If the device isn't ready, wait some time. If the device is ready,
+ // retry the command again.
+ //
+ Status = EFI_SUCCESS;
+
+ for (Index = 0; Index < USB_BOOT_COMMAND_RETRY; Index++) {
+ //
+ // Execute the command with an increasingly larger timeout value.
+ //
+ Status = UsbBootExecCmd (
+ UsbMass,
+ Cmd,
+ CmdLen,
+ DataDir,
+ Data,
+ DataLen,
+ Timeout * (Index + 1)
+ );
+ if (Status == EFI_SUCCESS ||
+ Status == EFI_MEDIA_CHANGED) {
+ break;
+ }
+ //
+ // Need retry once more, so reset index
+ //
+ if (Status == EFI_NOT_READY) {
+ Index = 0;
+ }
+ }
+
+ return Status;
+}
+
+
+
+/**
+ Use the TEST UNIT READY command to check whether it is ready.
+ If it is ready, update the parameters.
+
+ @param UsbMass The device to test
+
+ @retval EFI_SUCCESS The device is ready and parameters are updated.
+ @retval Others Device not ready.
+
+**/
+EFI_STATUS
+UsbBootIsUnitReady (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_TEST_UNIT_READY_CMD TestCmd;
+
+ ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));
+
+ TestCmd.OpCode = USB_BOOT_TEST_UNIT_READY_OPCODE;
+ TestCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
+
+ return UsbBootExecCmdWithRetry (
+ UsbMass,
+ &TestCmd,
+ sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
+ EfiUsbNoData,
+ NULL,
+ 0,
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+}
+
+
+/**
+ Inquiry Command requests that information regrarding parameters of
+ the Device be sent to the Host.
+
+ @param UsbMass The device to inquiry.
+
+ @retval EFI_SUCCESS The device is ready and parameters are updated.
+ @retval Others Device not ready.
+
+**/
+EFI_STATUS
+UsbBootInquiry (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_INQUIRY_CMD InquiryCmd;
+ USB_BOOT_INQUIRY_DATA InquiryData;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &(UsbMass->BlockIoMedia);
+
+ //
+ // Use the Inquiry command to get the RemovableMedia setting.
+ //
+ ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
+ ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
+
+ InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;
+ InquiryCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
+ InquiryCmd.AllocLen = sizeof (InquiryData);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &InquiryCmd,
+ sizeof (USB_BOOT_INQUIRY_CMD),
+ EfiUsbDataIn,
+ &InquiryData,
+ sizeof (USB_BOOT_INQUIRY_DATA),
+ USB_BOOT_INQUIRY_CMD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbMass->Pdt = USB_BOOT_PDT (InquiryData.Pdt);
+ Media->RemovableMedia = USB_BOOT_REMOVABLE (InquiryData.Removable);
+ //
+ // Default value 512 Bytes, in case no media present at first time
+ //
+ Media->BlockSize = 0x0200;
+
+ return Status;
+}
+
+
+/**
+ Get the capacity of the USB mass storage media, including
+ the presentation, block size, and last block number. This
+ function is used to get the disk parameters at the start if
+ it is a non-removable media or to detect the media if it is
+ removable.
+
+ @param UsbMass The device to retireve disk gemotric.
+
+ @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
+ @retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.
+
+**/
+EFI_STATUS
+UsbBootReadCapacity (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_READ_CAPACITY_CMD CapacityCmd;
+ USB_BOOT_READ_CAPACITY_DATA CapacityData;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // Use the READ CAPACITY command to get the block length and last blockno
+ //
+ ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
+ ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
+
+ CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;
+ CapacityCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &CapacityCmd,
+ sizeof (USB_BOOT_READ_CAPACITY_CMD),
+ EfiUsbDataIn,
+ &CapacityData,
+ sizeof (USB_BOOT_READ_CAPACITY_DATA),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Media->MediaPresent = TRUE;
+ Media->LastBlock = UsbBootGetUint32 (CapacityData.LastLba);
+ Media->BlockSize = UsbBootGetUint32 (CapacityData.BlockLen);
+
+ DEBUG ((mUsbMscInfo, "UsbBootReadCapacity Success LBA=%d BlockSize=%d\n",
+ Media->LastBlock, Media->BlockSize));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieves mode sense information via sending Mode Sense
+ Packet Command.
+
+ @param UsbMass The USB_FLOPPY_DEV instance.
+
+ @retval EFI_DEVICE_ERROR Hardware error
+ @retval EFI_SUCCESS Success
+
+**/
+EFI_STATUS
+UsbBootModeSense (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_STATUS Status;
+ USB_BOOT_MODE_SENSE_CMD ModeSenseCmd;
+ USB_BOOT_MODE_PARA_HEADER ModeParaHeader;
+ UINT8 CommandSet;
+
+ ZeroMem (&ModeSenseCmd, sizeof (USB_BOOT_MODE_SENSE_CMD));
+ ZeroMem (&ModeParaHeader, sizeof (USB_BOOT_MODE_PARA_HEADER));
+
+ //
+ // overuse Context Pointer, the first field of Bot or Cbi is EFI_USB_INTERFACE_DESCRIPTOR
+ //
+ CommandSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
+
+ if (CommandSet == USB_MASS_STORE_SCSI) {
+ //
+ // Not UFI Command Set, no ModeSense Command
+ //
+ return EFI_SUCCESS;
+ }
+
+ ModeSenseCmd.OpCode = USB_BOOT_MODE_SENSE10_OPCODE;
+ ModeSenseCmd.PageCode = 0x3f;
+ ModeSenseCmd.ParaListLenLsb = (UINT8) sizeof (USB_BOOT_MODE_PARA_HEADER);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &ModeSenseCmd,
+ sizeof (USB_BOOT_MODE_SENSE_CMD),
+ EfiUsbDataIn,
+ &ModeParaHeader,
+ sizeof (USB_BOOT_MODE_PARA_HEADER),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+ //
+ // Did nothing with the Header here
+ // But probably should
+ //
+
+ return Status;
+}
+
+
+/**
+ Get the parameters for the USB mass storage media, including
+ the RemovableMedia, block size, and last block number. This
+ function is used both to initialize the media during the
+ DriverBindingStart and to re-initialize it when the media is
+ changed. Althought the RemoveableMedia is unlikely to change,
+ I include it here.
+
+ @param UsbMass The device to retireve disk gemotric.
+
+ @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
+ @retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.
+
+**/
+EFI_STATUS
+UsbBootGetParams (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Status = UsbBootInquiry (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
+ return Status;
+ }
+
+ Media = &(UsbMass->BlockIoMedia);
+ //
+ // Don't use the Removable bit in inquirydata to test whether the media
+ // is removable because many flash disks wrongly set this bit.
+ //
+ if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
+ //
+ // CD-Rom or Optical device
+ //
+ UsbMass->OpticalStorage = TRUE;
+ //
+ // Default value 2048 Bytes, in case no media present at first time
+ //
+ Media->BlockSize = 0x0800;
+ } else {
+ //
+ // Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd
+ //
+ Status = UsbBootModeSense (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "UsbBootGetParams: UsbBootModeSense (%r)\n", Status));
+ return Status;
+ }
+ }
+
+ return UsbBootReadCapacity (UsbMass);
+}
+
+
+/**
+ Detect whether the removable media is present and whether it has changed.
+ The Non-removable media doesn't need it.
+
+ @param UsbMass The device to retireve disk gemotric.
+
+ @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
+ @retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.
+
+**/
+EFI_STATUS
+UsbBootDetectMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA OldMedia;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &UsbMass->BlockIoMedia;
+ OldMedia = UsbMass->BlockIoMedia;
+
+ //
+ // First test whether the device is ready and get status
+ // If media changed or ready, need read the device's capacity
+ //
+ Status = UsbBootIsUnitReady (UsbMass);
+ if ((Status == EFI_SUCCESS && Media->MediaPresent) ||
+ (Status == EFI_MEDIA_CHANGED)) {
+ if ((UsbMass->Pdt != USB_PDT_CDROM) &&
+ (UsbMass->Pdt != USB_PDT_OPTICAL)) {
+ //
+ // Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd
+ //
+ UsbBootModeSense (UsbMass);
+ }
+ DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need Read Capacity\n"));
+ Status = UsbBootReadCapacity (UsbMass);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Detect whether it is necessary to reinstall the BlockIO
+ //
+ if ((Media->MediaId != OldMedia.MediaId) ||
+ (Media->MediaPresent != OldMedia.MediaPresent) ||
+ (Media->ReadOnly != OldMedia.ReadOnly) ||
+ (Media->BlockSize != OldMedia.BlockSize) ||
+ (Media->LastBlock != OldMedia.LastBlock)) {
+ DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need reinstall BlockIoProtocol\n"));
+ Media->MediaId++;
+ gBS->ReinstallProtocolInterface (
+ UsbMass->Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &UsbMass->BlockIo
+ );
+ //
+ // Check whether media present or media changed or write protected
+ //
+ if (Media->MediaPresent == FALSE) {
+ Status = EFI_NO_MEDIA;
+ }
+ if (Media->MediaId != OldMedia.MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ }
+ if (Media->ReadOnly != OldMedia.ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Read some blocks from the device.
+
+ @param UsbMass The USB mass storage device to read from
+ @param Lba The start block number
+ @param TotalBlock Total block number to read
+ @param Buffer The buffer to read to
+
+ @retval EFI_SUCCESS Data are read into the buffer
+ @retval Others Failed to read all the data
+
+**/
+EFI_STATUS
+UsbBootReadBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ OUT UINT8 *Buffer
+ )
+{
+ USB_BOOT_READ10_CMD ReadCmd;
+ EFI_STATUS Status;
+ UINT16 Count;
+ UINT32 BlockSize;
+ UINT32 ByteSize;
+ UINT32 Timeout;
+
+ BlockSize = UsbMass->BlockIoMedia.BlockSize;
+ Status = EFI_SUCCESS;
+
+ while (TotalBlock > 0) {
+ //
+ // Split the total blocks into smaller pieces to ease the pressure
+ // on the device. We must split the total block because the READ10
+ // command only has 16 bit transfer length (in the unit of block).
+ //
+ Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
+ ByteSize = (UINT32)Count * BlockSize;
+
+ //
+ // Optical device need longer timeout than other device
+ //
+ if (UsbMass->OpticalStorage == TRUE) {
+ Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;
+ } else {
+ Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;
+ }
+
+ //
+ // Fill in the command then execute
+ //
+ ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));
+
+ ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;
+ ReadCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
+ UsbBootPutUint32 (ReadCmd.Lba, Lba);
+ UsbBootPutUint16 (ReadCmd.TransferLen, Count);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &ReadCmd,
+ sizeof (USB_BOOT_READ10_CMD),
+ EfiUsbDataIn,
+ Buffer,
+ ByteSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba += Count;
+ Buffer += Count * BlockSize;
+ TotalBlock -= Count;
+ }
+
+ return Status;
+}
+
+
+/**
+ Write some blocks to the device.
+
+ @param UsbMass The USB mass storage device to write to
+ @param Lba The start block number
+ @param TotalBlock Total block number to write
+ @param Buffer The buffer to write to
+
+ @retval EFI_SUCCESS Data are written into the buffer
+ @retval Others Failed to write all the data
+
+**/
+EFI_STATUS
+UsbBootWriteBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ OUT UINT8 *Buffer
+ )
+{
+ USB_BOOT_WRITE10_CMD WriteCmd;
+ EFI_STATUS Status;
+ UINT16 Count;
+ UINT32 BlockSize;
+ UINT32 ByteSize;
+ UINT32 Timeout;
+
+ BlockSize = UsbMass->BlockIoMedia.BlockSize;
+ Status = EFI_SUCCESS;
+
+ while (TotalBlock > 0) {
+ //
+ // Split the total blocks into smaller pieces to ease the pressure
+ // on the device. We must split the total block because the WRITE10
+ // command only has 16 bit transfer length (in the unit of block).
+ //
+ Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
+ ByteSize = (UINT32)Count * BlockSize;
+
+ //
+ // Optical device need longer timeout than other device
+ //
+ if (UsbMass->OpticalStorage == TRUE) {
+ Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;
+ } else {
+ Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;
+ }
+
+ //
+ // Fill in the write10 command block
+ //
+ ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));
+
+ WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;
+ WriteCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
+ UsbBootPutUint32 (WriteCmd.Lba, Lba);
+ UsbBootPutUint16 (WriteCmd.TransferLen, Count);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &WriteCmd,
+ sizeof (USB_BOOT_WRITE10_CMD),
+ EfiUsbDataOut,
+ Buffer,
+ ByteSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba += Count;
+ Buffer += Count * BlockSize;
+ TotalBlock -= Count;
+ }
+
+ return Status;
+}
+
+
+/**
+ Use the USB clear feature control transfer to clear the endpoint
+ stall condition.
+
+ @param UsbIo The USB IO protocol to use
+ @param EndpointAddr The endpoint to clear stall for
+
+ @retval EFI_SUCCESS The endpoint stall condtion is clear
+ @retval Others Failed to clear the endpoint stall condtion
+
+**/
+EFI_STATUS
+UsbClearEndpointStall (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN UINT8 EndpointAddr
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 CmdResult;
+ UINT32 Timeout;
+
+ Request.RequestType = 0x02;
+ Request.Request = USB_REQ_CLEAR_FEATURE;
+ Request.Value = USB_FEATURE_ENDPOINT_HALT;
+ Request.Index = EndpointAddr;
+ Request.Length = 0;
+ Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_STALL_1_MS;
+
+ Status = UsbIo->UsbControlTransfer (
+ UsbIo,
+ &Request,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0,
+ &CmdResult
+ );
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h
new file mode 100644
index 0000000000..cee70be412
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h
@@ -0,0 +1,268 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassBoot.h
+
+Abstract:
+
+ The definition of command and data of the USB mass storage for
+ bootability command set.
+
+Revision History
+
+
+**/
+
+#ifndef _EFI_USB_MASS_BOOT_H_
+#define _EFI_USB_MASS_BOOT_H_
+
+enum {
+ //
+ // The opcodes of various usb boot commands:
+ // INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified
+ // by MMC command set. Others are "Group 1 Timeout Commands". That
+ // is they should be retried if driver is ready.
+ // We can't use the Peripheral Device Type in Inquiry data to
+ // determine the timeout used. For example, both floppy and flash
+ // are likely set their PDT to 0, or Direct Access Device.
+ //
+ USB_BOOT_INQUIRY_OPCODE = 0x12,
+ USB_BOOT_REQUEST_SENSE_OPCODE = 0x03,
+
+ USB_BOOT_MODE_SENSE10_OPCODE = 0x5a,
+ USB_BOOT_READ_CAPACITY_OPCODE = 0x25,
+ USB_BOOT_TEST_UNIT_READY_OPCODE = 0x00,
+ USB_BOOT_READ10_OPCODE = 0x28,
+ USB_BOOT_WRITE10_OPCODE = 0x2a,
+
+ //
+ // The Sense Key part of the sense data. Sense data has three levels:
+ // Sense key, Additional Sense Code and Additional Sense Code Qualifier
+ //
+ USB_BOOT_SENSE_NO_SENSE = 0x00, // No sense key
+ USB_BOOT_SENSE_RECOVERED = 0x01, // Last command succeed with recovery actions
+ USB_BOOT_SENSE_NOT_READY = 0x02, // Device not ready
+ USB_BOOT_SNESE_MEDIUM_ERROR = 0X03, // Failed probably because flaw in the media
+ USB_BOOT_SENSE_HARDWARE_ERROR = 0X04, // Non-recoverable hardware failure
+ USB_BOOT_SENSE_ILLEGAL_REQUEST = 0X05, // Illegal parameters in the request
+ USB_BOOT_SENSE_UNIT_ATTENTION = 0X06, // Removable medium may have been changed
+ USB_BOOT_SNESE_DATA_PROTECT = 0X07, // Write protected
+ USB_BOOT_SENSE_BLANK_CHECK = 0X08, // Blank/non-blank medium while reading/writing
+ USB_BOOT_SENSE_VENDOR = 0X09, // Vendor specific sense key
+ USB_BOOT_SENSE_ABORTED = 0X0B, // Command aborted by the device
+ USB_BOOT_SENSE_VOLUME_OVERFLOW = 0x0D, // Partition overflow
+ USB_BOOT_SENSE_MISCOMPARE = 0x0E, // Source data mis-match while verfying.
+
+ USB_BOOT_ASC_NOT_READY = 0x04,
+ USB_BOOT_ASC_MEDIA_UPSIDE_DOWN = 0x06,
+ USB_BOOT_ASC_NO_MEDIA = 0x3A,
+ USB_BOOT_ASC_MEDIA_CHANGE = 0x28,
+
+ USB_BOOT_ASCQ_IN_PROGRESS = 0x01,
+ USB_BOOT_ASCQ_DEVICE_BUSY = 0xFF,
+
+ //
+ // Other parameters
+ //
+ USB_BOOT_IO_BLOCKS = 64,
+
+ //
+ // Boot Retry times
+ //
+ USB_BOOT_COMMAND_RETRY = 5,
+ USB_BOOT_WAIT_RETRY = 5,
+
+ //
+ // Boot Stall time
+ //
+ USB_BOOT_UNIT_READY_STALL = 50 * USB_MASS_STALL_1_MS,
+
+ //
+ // Boot Transfer timeout
+ //
+ USB_BOOT_GENERAL_BLOCK_TIMEOUT = 200 * USB_MASS_STALL_1_MS,
+ USB_BOOT_OPTICAL_BLOCK_TIMEOUT = 1 * USB_MASS_STALL_1_S,
+ USB_BOOT_GENERAL_CMD_TIMEOUT = 1 * USB_MASS_STALL_1_S,
+ USB_BOOT_INQUIRY_CMD_TIMEOUT = 3 * USB_MASS_STALL_1_S,
+
+ //
+ // Supported PDT codes, or Peripheral Device Type
+ //
+ USB_PDT_DIRECT_ACCESS = 0x00, // Direct access device
+ USB_PDT_CDROM = 0x05, // CDROM
+ USB_PDT_OPTICAL = 0x07, // Non-CD optical disks
+ USB_PDT_SIMPLE_DIRECT = 0x0E, // Simplified direct access device
+};
+
+//
+// The required commands are INQUIRY, READ CAPACITY, TEST UNIT READY,
+// READ10, WRITE10, and REQUEST SENSE. The BLOCK_IO protocol uses LBA
+// so it isn't necessary to issue MODE SENSE / READ FORMAT CAPACITY
+// command to retrieve the disk gemotrics.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun; // Lun (high 3 bits)
+ UINT8 Reserved0[2];
+ UINT8 AllocLen;
+ UINT8 Reserved1;
+ UINT8 Pad[6];
+} USB_BOOT_INQUIRY_CMD;
+
+typedef struct {
+ UINT8 Pdt; // Peripheral Device Type (low 5 bits)
+ UINT8 Removable; // Removable Media (highest bit)
+ UINT8 Reserved0[2];
+ UINT8 AddLen; // Additional length
+ UINT8 Reserved1[3];
+ UINT8 VendorID[8];
+ UINT8 ProductID[16];
+ UINT8 ProductRevision[4];
+} USB_BOOT_INQUIRY_DATA;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 Reserved0[8];
+ UINT8 Pad[2];
+} USB_BOOT_READ_CAPACITY_CMD;
+
+typedef struct {
+ UINT8 LastLba[4];
+ UINT8 BlockLen[4];
+} USB_BOOT_READ_CAPACITY_DATA;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 Reserved[4];
+ UINT8 Pad[6];
+} USB_BOOT_TEST_UNIT_READY_CMD;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 PageCode;
+ UINT8 Reserved0[4];
+ UINT8 ParaListLenMsb;
+ UINT8 ParaListLenLsb;
+ UINT8 Reserved1;
+ UINT8 Pad[2];
+} USB_BOOT_MODE_SENSE_CMD;
+
+typedef struct {
+ UINT8 ModeDataLenMsb;
+ UINT8 ModeDataLenLsb;
+ UINT8 Reserved0[4];
+ UINT8 BlkDesLenMsb;
+ UINT8 BlkDesLenLsb;
+} USB_BOOT_MODE_PARA_HEADER;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun; // Lun (High 3 bits)
+ UINT8 Lba[4]; // Logical block address
+ UINT8 Reserved0;
+ UINT8 TransferLen[2]; // Transfer length
+ UINT8 Reserverd1;
+ UINT8 Pad[2];
+} USB_BOOT_READ10_CMD;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 Lba[4];
+ UINT8 Reserved0;
+ UINT8 TransferLen[2];
+ UINT8 Reserverd1;
+ UINT8 Pad[2];
+} USB_BOOT_WRITE10_CMD;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun; // Lun (High 3 bits)
+ UINT8 Reserved0[2];
+ UINT8 AllocLen; // Allocation length
+ UINT8 Reserved1;
+ UINT8 Pad[6];
+} USB_BOOT_REQUEST_SENSE_CMD;
+
+typedef struct {
+ UINT8 ErrorCode;
+ UINT8 Reserved0;
+ UINT8 SenseKey; // Sense key (low 4 bits)
+ UINT8 Infor[4];
+ UINT8 AddLen; // Additional Sense length, 10
+ UINT8 Reserved1[4];
+ UINT8 ASC; // Additional Sense Code
+ UINT8 ASCQ; // Additional Sense Code Qualifier
+ UINT8 Reserverd2[4];
+} USB_BOOT_REQUEST_SENSE_DATA;
+#pragma pack()
+
+//
+// Convert a LUN number to that in the command
+//
+#define USB_BOOT_LUN(Lun) ((Lun) << 5)
+
+//
+// Get the removable, PDT, and sense key bits from the command data
+//
+#define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & 0x80) != 0)
+#define USB_BOOT_PDT(Pdt) ((Pdt) & 0x1f)
+#define USB_BOOT_SENSE_KEY(Key) ((Key) & 0x0f)
+
+//
+// Swap the byte sequence of a UINT32. Intel CPU uses little endian
+// in UEFI environment, but USB boot uses big endian.
+//
+#define USB_BOOT_SWAP32(Data32) \
+ ((((Data32) & 0x000000ff) << 24) | (((Data32) & 0xff000000) >> 24) | \
+ (((Data32) & 0x0000ff00) << 8) | (((Data32) & 0x00ff0000) >> 8))
+
+#define USB_BOOT_SWAP16(Data16) \
+ ((((Data16) & 0x00ff) << 8) | (((Data16) & 0xff00) >> 8))
+
+EFI_STATUS
+UsbBootGetParams (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+EFI_STATUS
+UsbBootIsUnitReady (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+EFI_STATUS
+UsbBootDetectMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+EFI_STATUS
+UsbBootReadBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ OUT UINT8 *Buffer
+ );
+
+EFI_STATUS
+UsbBootWriteBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ OUT UINT8 *Buffer
+ );
+#endif
+
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c
new file mode 100644
index 0000000000..0d6cca167b
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c
@@ -0,0 +1,561 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassBot.c
+
+Abstract:
+
+ Implementation of the USB mass storage Bulk-Only Transport protocol.
+
+Revision History
+
+
+**/
+
+#include "UsbMass.h"
+#include "UsbMassBot.h"
+
+UINTN mUsbBotInfo = DEBUG_INFO;
+UINTN mUsbBotError = DEBUG_ERROR;
+
+STATIC
+EFI_STATUS
+UsbBotResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+
+/**
+ Initialize the USB mass storage class BOT transport protocol.
+ It will save its context which is a USB_BOT_PROTOCOL structure
+ in the Context if Context isn't NULL.
+
+ @param UsbIo The USB IO protocol to use
+ @param Controller The controller to init
+ @param Context The variable to save the context to
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval EFI_SUCCESS The device is supported and protocol initialized.
+
+**/
+STATIC
+EFI_STATUS
+UsbBotInit (
+ IN EFI_USB_IO_PROTOCOL * UsbIo,
+ IN EFI_HANDLE Controller,
+ OUT VOID **Context OPTIONAL
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_USB_INTERFACE_DESCRIPTOR *Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndPoint;
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ //
+ // Allocate the BOT context, append two endpoint descriptors to it
+ //
+ UsbBot = AllocateZeroPool (
+ sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
+ );
+ if (UsbBot == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UsbBot->UsbIo = UsbIo;
+
+ //
+ // Get the interface descriptor and validate that it
+ // is a USB MSC BOT interface.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbBotError, "UsbBotInit: Get invalid BOT interface (%r)\n", Status));
+ goto ON_ERROR;
+ }
+
+ Interface = &UsbBot->Interface;
+
+ if (Interface->InterfaceProtocol != USB_MASS_STORE_BOT) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ //
+ // Locate and save the first bulk-in and bulk-out endpoint
+ //
+ for (Index = 0; Index < Interface->NumEndpoints; Index++) {
+ Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);
+
+ if (EFI_ERROR (Status) || !USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {
+ continue;
+ }
+
+ if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbBot->BulkInEndpoint == NULL)) {
+
+ UsbBot->BulkInEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1);
+ *UsbBot->BulkInEndpoint = EndPoint;
+ }
+
+ if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbBot->BulkOutEndpoint == NULL)) {
+
+ UsbBot->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1) + 1;
+ *UsbBot->BulkOutEndpoint = EndPoint;
+ }
+ }
+
+ if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) {
+ DEBUG ((mUsbBotError, "UsbBotInit: In/Out Endpoint invalid\n"));
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ //
+ // The USB BOT protocol uses dCBWTag to match the CBW and CSW.
+ //
+ UsbBot->CbwTag = 0x01;
+
+ if (Context != NULL) {
+ *Context = UsbBot;
+ } else {
+ gBS->FreePool (UsbBot);
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ gBS->FreePool (UsbBot);
+ return Status;
+}
+
+
+/**
+ Send the command to the device using Bulk-Out endpoint
+
+ @param UsbBot The USB BOT device
+ @param Cmd The command to transfer to device
+ @param CmdLen the length of the command
+ @param DataDir The direction of the data
+ @param TransLen The expected length of the data
+
+ @retval EFI_NOT_READY The device return NAK to the transfer
+ @retval EFI_SUCCESS The command is sent to the device.
+ @retval Others Failed to send the command to device
+
+**/
+STATIC
+EFI_STATUS
+UsbBotSendCommand (
+ IN USB_BOT_PROTOCOL *UsbBot,
+ IN UINT8 *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN UINT32 TransLen
+ )
+{
+ USB_BOT_CBW Cbw;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINTN DataLen;
+ UINTN Timeout;
+
+ ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN));
+
+ //
+ // Fill in the CSW. Only the first LUN is supported now.
+ //
+ Cbw.Signature = USB_BOT_CBW_SIGNATURE;
+ Cbw.Tag = UsbBot->CbwTag;
+ Cbw.DataLen = TransLen;
+ Cbw.Flag = ((DataDir == EfiUsbDataIn) ? 0x80 : 0);
+ Cbw.Lun = 0;
+ Cbw.CmdLen = CmdLen;
+
+ ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN);
+ CopyMem (Cbw.CmdBlock, Cmd, CmdLen);
+
+ Result = 0;
+ DataLen = sizeof (USB_BOT_CBW);
+ Timeout = USB_BOT_CBW_TIMEOUT / USB_MASS_STALL_1_MS;
+
+ //
+ // Use the UsbIo to send the command to the device. The default
+ // time out is enough.
+ //
+ Status = UsbBot->UsbIo->UsbBulkTransfer (
+ UsbBot->UsbIo,
+ UsbBot->BulkOutEndpoint->EndpointAddress,
+ &Cbw,
+ &DataLen,
+ Timeout,
+ &Result
+ );
+ //
+ // Respond to Bulk-Out endpoint stall with a Reset Recovery,
+ // see the spec section 5.3.1
+ //
+ if (EFI_ERROR (Status)) {
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) {
+ UsbBotResetDevice (UsbBot, FALSE);
+ } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
+ Status = EFI_NOT_READY;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Transfer the data between the device and host. BOT transfer
+ is composed of three phase, command, data, and status.
+
+ @param UsbBot The USB BOT device
+ @param DataDir The direction of the data
+ @param Data The buffer to hold data
+ @param TransLen The expected length of the data
+ @param Timeout The time to wait the command to complete
+
+ @retval EFI_SUCCESS The data is transferred
+ @retval Others Failed to transfer data
+
+**/
+STATIC
+EFI_STATUS
+UsbBotDataTransfer (
+ IN USB_BOT_PROTOCOL *UsbBot,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN OUT UINT8 *Data,
+ IN OUT UINTN *TransLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
+ EFI_STATUS Status;
+ UINT32 Result;
+
+ //
+ // It's OK if no data to transfer
+ //
+ if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Select the endpoint then issue the transfer
+ //
+ if (DataDir == EfiUsbDataIn) {
+ Endpoint = UsbBot->BulkInEndpoint;
+ } else {
+ Endpoint = UsbBot->BulkOutEndpoint;
+ }
+
+ Result = 0;
+ Timeout = Timeout / USB_MASS_STALL_1_MS;
+
+ Status = UsbBot->UsbIo->UsbBulkTransfer (
+ UsbBot->UsbIo,
+ Endpoint->EndpointAddress,
+ Data,
+ TransLen,
+ Timeout,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbBotError, "UsbBotDataTransfer: (%r)\n", Status));
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
+ DEBUG ((mUsbBotError, "UsbBotDataTransfer: DataIn Stall\n"));
+ UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress);
+ } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
+ Status = EFI_NOT_READY;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the command execution status from device. BOT transfer is
+ composed of three phase, command, data, and status.
+ This function return the transfer status of the BOT's CSW status,
+ and return the high level command execution result in Result. So
+ even it returns EFI_SUCCESS, the command may still have failed.
+
+ @param UsbBot The USB BOT device
+ @param TransLen The expected length of the data
+ @param Timeout The time to wait the command to complete
+ @param CmdStatus The result of the command execution.
+
+ @retval EFI_DEVICE_ERROR Failed to retrieve the command execute result
+ @retval EFI_SUCCESS Command execute result is retrieved and in the
+ Result.
+
+**/
+STATIC
+EFI_STATUS
+UsbBotGetStatus (
+ IN USB_BOT_PROTOCOL *UsbBot,
+ IN UINT32 TransLen,
+ OUT UINT8 *CmdStatus
+ )
+{
+ USB_BOT_CSW Csw;
+ UINTN Len;
+ UINT8 Endpoint;
+ EFI_STATUS Status;
+ UINT32 Result;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT32 Index;
+ UINTN Timeout;
+
+ *CmdStatus = USB_BOT_COMMAND_ERROR;
+ Status = EFI_DEVICE_ERROR;
+ Endpoint = UsbBot->BulkInEndpoint->EndpointAddress;
+ UsbIo = UsbBot->UsbIo;
+ Timeout = USB_BOT_CSW_TIMEOUT / USB_MASS_STALL_1_MS;
+
+ for (Index = 0; Index < USB_BOT_GET_STATUS_RETRY; Index++) {
+ //
+ // Attemp to the read CSW from bulk in endpoint
+ //
+ ZeroMem (&Csw, sizeof (USB_BOT_CSW));
+ Result = 0;
+ Len = sizeof (USB_BOT_CSW);
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ Endpoint,
+ &Csw,
+ &Len,
+ Timeout,
+ &Result
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((mUsbBotError, "UsbBotGetStatus (%r)\n", Status));
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
+ DEBUG ((mUsbBotError, "UsbBotGetStatus: DataIn Stall\n"));
+ UsbClearEndpointStall (UsbIo, Endpoint);
+ }
+ continue;
+ }
+
+ if (Csw.Signature != USB_BOT_CSW_SIGNATURE) {
+ //
+ // Invalid Csw need perform reset recovery
+ //
+ DEBUG ((mUsbBotError, "UsbBotGetStatus: Device return a invalid signature\n"));
+ Status = UsbBotResetDevice (UsbBot, FALSE);
+ } else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) {
+ //
+ // Respond phase error need perform reset recovery
+ //
+ DEBUG ((mUsbBotError, "UsbBotGetStatus: Device return a phase error\n"));
+ Status = UsbBotResetDevice (UsbBot, FALSE);
+ } else {
+
+ *CmdStatus = Csw.CmdStatus;
+ break;
+ }
+ }
+ //
+ //The tag is increased even there is an error.
+ //
+ UsbBot->CbwTag++;
+
+ return Status;
+}
+
+
+/**
+ Call the Usb mass storage class transport protocol to issue
+ the command/data/status circle to execute the commands
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL
+ @param Cmd The high level command
+ @param CmdLen The command length
+ @param DataDir The direction of the data transfer
+ @param Data The buffer to hold data
+ @param DataLen The length of the data
+ @param Timeout The time to wait command
+ @param CmdStatus The result of high level command execution
+
+ @retval EFI_DEVICE_ERROR Failed to excute command
+ @retval EFI_SUCCESS The command is executed OK, and result in CmdStatus
+
+**/
+STATIC
+EFI_STATUS
+UsbBotExecCommand (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_STATUS Status;
+ UINTN TransLen;
+ UINT8 Result;
+
+ *CmdStatus = USB_MASS_CMD_FAIL;
+ UsbBot = (USB_BOT_PROTOCOL *) Context;
+
+ //
+ // Send the command to the device. Return immediately if device
+ // rejects the command.
+ //
+ Status = UsbBotSendCommand (UsbBot, Cmd, CmdLen, DataDir, DataLen);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbBotError, "UsbBotExecCommand: UsbBotSendCommand (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // Transfer the data. Don't return immediately even data transfer
+ // failed. The host should attempt to receive the CSW no matter
+ // whether it succeeds or failed.
+ //
+ TransLen = (UINTN) DataLen;
+ UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout);
+
+ //
+ // Get the status, if that succeeds, interpret the result
+ //
+ Status = UsbBotGetStatus (UsbBot, DataLen, &Result);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbBotError, "UsbBotExecCommand: UsbBotGetStatus (%r)\n", Status));
+ return Status;
+ }
+
+ if (Result == 0) {
+ *CmdStatus = USB_MASS_CMD_SUCCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the mass storage device by BOT protocol
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL
+
+ @retval EFI_SUCCESS The device is reset
+ @retval Others Failed to reset the device.
+
+**/
+STATIC
+EFI_STATUS
+UsbBotResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINT32 Timeout;
+
+ UsbBot = (USB_BOT_PROTOCOL *) Context;
+
+ if (ExtendedVerification) {
+ //
+ // If we need to do strictly reset, reset its parent hub port
+ //
+ Status = UsbBot->UsbIo->UsbPortReset (UsbBot->UsbIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Issue a class specific "Bulk-Only Mass Storage Reset reqest.
+ // See the spec section 3.1
+ //
+ Request.RequestType = 0x21;
+ Request.Request = USB_BOT_RESET_REQUEST;
+ Request.Value = 0;
+ Request.Index = UsbBot->Interface.InterfaceNumber;
+ Request.Length = 0;
+ Timeout = USB_BOT_RESET_TIMEOUT / USB_MASS_STALL_1_MS;
+
+ Status = UsbBot->UsbIo->UsbControlTransfer (
+ UsbBot->UsbIo,
+ &Request,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0,
+ &Result
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbBotError, "UsbBotResetDevice: (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // The device shall NAK the host's request until the reset is
+ // complete. We can use this to sync the device and host. For
+ // now just stall 100ms to wait the device.
+ //
+ gBS->Stall (USB_BOT_RESET_STALL);
+
+ //
+ // Clear the Bulk-In and Bulk-Out stall condition.
+ //
+ UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress);
+ UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress);
+ return Status;
+}
+
+
+/**
+ Clean up the resource used by this BOT protocol
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+STATIC
+EFI_STATUS
+UsbBotFini (
+ IN VOID *Context
+ )
+{
+ gBS->FreePool (Context);
+ return EFI_SUCCESS;
+}
+
+USB_MASS_TRANSPORT
+mUsbBotTransport = {
+ USB_MASS_STORE_BOT,
+ UsbBotInit,
+ UsbBotExecCommand,
+ UsbBotResetDevice,
+ UsbBotFini
+};
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h
new file mode 100644
index 0000000000..e11e9c5108
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h
@@ -0,0 +1,102 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassBot.h
+
+Abstract:
+
+ Defination for the USB mass storage Bulk-Only Transport protocol.
+ This implementation is based on the "Universal Serial Bus Mass
+ Storage Class Bulk-Only Transport" Revision 1.0, September 31, 1999.
+
+Revision History
+
+
+**/
+
+#ifndef _EFI_USBMASS_BOT_H_
+#define _EFI_USBMASS_BOT_H_
+
+enum {
+ //
+ // Usb Bulk-Only class specfic request
+ //
+ USB_BOT_RESET_REQUEST = 0xFF, // Bulk-Only Mass Storage Reset
+ USB_BOT_GETLUN_REQUEST = 0xFE, // Get Max Lun
+ USB_BOT_CBW_SIGNATURE = 0x43425355, // dCBWSignature, tag the packet as CBW
+ USB_BOT_CSW_SIGNATURE = 0x53425355, // dCSWSignature, tag the packet as CSW
+ USB_BOT_MAX_LUN = 0x0F, // Lun number is from 0 to 15
+ USB_BOT_MAX_CMDLEN = 16, // Maxium number of command from command set
+
+ //
+ // Usb BOT command block status values
+ //
+ USB_BOT_COMMAND_OK = 0x00, // Command passed, good status
+ USB_BOT_COMMAND_FAILED = 0x01, // Command failed
+ USB_BOT_COMMAND_ERROR = 0x02, // Phase error, need to reset the device
+
+ //
+ // Usb Bot retry times
+ //
+ USB_BOT_GET_STATUS_RETRY = 3,
+
+ //
+ // Usb Bot stall time
+ //
+ USB_BOT_RESET_STALL = 100 * USB_MASS_STALL_1_MS,
+
+ //
+ // Usb Bot transfer timeout
+ //
+ USB_BOT_CBW_TIMEOUT = 1 * USB_MASS_STALL_1_S,
+ USB_BOT_CSW_TIMEOUT = 1 * USB_MASS_STALL_1_S,
+ USB_BOT_RESET_TIMEOUT = 3 * USB_MASS_STALL_1_S,
+};
+
+//
+// The CBW (Command Block Wrapper) and CSW (Command Status Wrapper)
+// structures used by the Usb BOT protocol.
+//
+#pragma pack(1)
+typedef struct {
+ UINT32 Signature;
+ UINT32 Tag;
+ UINT32 DataLen; // Length of data between CBW and CSW
+ UINT8 Flag; // Bit 7, 0 ~ Data-Out, 1 ~ Data-In
+ UINT8 Lun; // Lun number. Bits 0~3 are used
+ UINT8 CmdLen; // Length of the command. Bits 0~4 are used
+ UINT8 CmdBlock[USB_BOT_MAX_CMDLEN];
+} USB_BOT_CBW;
+
+typedef struct {
+ UINT32 Signature;
+ UINT32 Tag;
+ UINT32 DataResidue;
+ UINT8 CmdStatus;
+} USB_BOT_CSW;
+#pragma pack()
+
+//
+// Put Interface at the first field is to make it easy to get by Context, which
+// could be BOT/CBI Protocol instance
+//
+typedef struct {
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
+ UINT32 CbwTag;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+} USB_BOT_PROTOCOL;
+
+extern USB_MASS_TRANSPORT mUsbBotTransport;
+#endif
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c
new file mode 100644
index 0000000000..1028e201c2
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c
@@ -0,0 +1,619 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassCbi.c
+
+Abstract:
+
+ Implementation of the USB mass storage Control/Bulk/Interrupt transpor.
+ Notice: it is being obseleted by the standard body in favor of the BOT
+ (Bulk-Only Transport).
+
+Revision History
+
+
+**/
+
+#include "UsbMass.h"
+#include "UsbMassCbi.h"
+
+UINTN mUsbCbiInfo = DEBUG_INFO;
+UINTN mUsbCbiError = DEBUG_ERROR;
+
+STATIC
+EFI_STATUS
+UsbCbiResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+
+/**
+ Initialize the USB mass storage class CBI transport protocol.
+ If Context isn't NULL, it will save its context in it.
+
+ @param UsbIo The USB IO to use
+ @param Controller The device controller
+ @param Context The variable to save context in
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
+ @retval EFI_UNSUPPORTED The device isn't supported
+ @retval EFI_SUCCESS The CBI protocol is initialized.
+
+**/
+STATIC
+EFI_STATUS
+UsbCbiInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN EFI_HANDLE Controller,
+ OUT VOID **Context OPTIONAL
+ )
+{
+ USB_CBI_PROTOCOL *UsbCbi;
+ EFI_USB_INTERFACE_DESCRIPTOR *Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR EndPoint;
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ //
+ // Allocate the CBI context
+ //
+ UsbCbi = AllocateZeroPool (
+ sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
+ );
+
+ if (UsbCbi == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UsbCbi->UsbIo = UsbIo;
+
+ //
+ // Get the interface descriptor and validate that it is a USB mass
+ // storage class CBI interface.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ Interface = &UsbCbi->Interface;
+ if ((Interface->InterfaceProtocol != USB_MASS_STORE_CBI0)
+ && (Interface->InterfaceProtocol != USB_MASS_STORE_CBI1)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ //
+ // Locate and save the bulk-in, bulk-out, and interrupt endpoint
+ //
+ for (Index = 0; Index < Interface->NumEndpoints; Index++) {
+ Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {
+ //
+ // Use the first Bulk-In and Bulk-Out endpoints
+ //
+ if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbCbi->BulkInEndpoint == NULL)) {
+
+ UsbCbi->BulkInEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1);
+ *UsbCbi->BulkInEndpoint = EndPoint;
+ }
+
+ if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbCbi->BulkOutEndpoint == NULL)) {
+
+ UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1;
+ *UsbCbi->BulkOutEndpoint = EndPoint;
+ }
+
+ } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) {
+ //
+ // Use the first interrupt endpoint if it is CBI0
+ //
+ if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) &&
+ (UsbCbi->InterruptEndpoint == NULL)) {
+
+ UsbCbi->InterruptEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 2;
+ *UsbCbi->InterruptEndpoint = EndPoint;
+ }
+ }
+ }
+
+ if ((UsbCbi->BulkInEndpoint == NULL)
+ || (UsbCbi->BulkOutEndpoint == NULL)
+ || ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0)
+ && (UsbCbi->InterruptEndpoint == NULL))) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ if (Context != NULL) {
+ *Context = UsbCbi;
+ } else {
+ gBS->FreePool (UsbCbi);
+ }
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ gBS->FreePool (UsbCbi);
+ return Status;
+}
+
+
+
+/**
+ Send the command to the device using class specific control transfer.
+
+ @param UsbCbi The USB CBI protocol
+ @param Cmd The high level command to transfer to device
+ @param CmdLen The length of the command
+ @param Timeout The time to wait the command to finish
+
+ @retval EFI_SUCCESS The command is transferred to device
+ @retval Others The command failed to transfer to device
+
+**/
+STATIC
+EFI_STATUS
+UsbCbiSendCommand (
+ IN USB_CBI_PROTOCOL *UsbCbi,
+ IN UINT8 *Cmd,
+ IN UINT8 CmdLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ UINTN DataLen;
+ INTN Retry;
+
+ //
+ // Fill in the device request, CBI use the "Accept Device-Specific
+ // Cmd" (ADSC) class specific request to send commands
+ //
+ Request.RequestType = 0x21;
+ Request.Request = 0;
+ Request.Value = 0;
+ Request.Index = UsbCbi->Interface.InterfaceNumber;
+ Request.Length = CmdLen;
+
+ Status = EFI_SUCCESS;
+ Timeout = Timeout / USB_MASS_STALL_1_MS;
+
+ for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
+ //
+ // Use the UsbIo to send the command to the device
+ //
+ TransStatus = 0;
+ DataLen = CmdLen;
+
+ Status = UsbCbi->UsbIo->UsbControlTransfer (
+ UsbCbi->UsbIo,
+ &Request,
+ EfiUsbDataOut,
+ Timeout,
+ Cmd,
+ DataLen,
+ &TransStatus
+ );
+ //
+ // The device can fail the command by STALL the control endpoint.
+ // It can delay the command by NAK the data or status stage, this
+ // is a "class-specific exemption to the USB specification". Retry
+ // if the command is NAKed.
+ //
+ if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
+ continue;
+ }
+
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Transfer data between the device and host. The CBI contains three phase,
+ command, data, and status. This is data phase.
+
+ @param UsbCbi The USB CBI device
+ @param DataDir The direction of the data transfer
+ @param Data The buffer to hold the data
+ @param TransLen The expected transfer length
+ @param Timeout The time to wait the command to execute
+
+ @retval EFI_SUCCESS The data transfer succeeded
+ @retval Others Failed to transfer all the data
+
+**/
+STATIC
+EFI_STATUS
+UsbCbiDataTransfer (
+ IN USB_CBI_PROTOCOL *UsbCbi,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN OUT UINT8 *Data,
+ IN OUT UINTN *TransLen,
+ IN UINT32 Timeout
+ )
+{
+ EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ UINTN Remain;
+ UINTN Increment;
+ UINT8 *Next;
+ UINTN Retry;
+
+ //
+ // It's OK if no data to transfer
+ //
+ if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Select the endpoint then issue the transfer
+ //
+ if (DataDir == EfiUsbDataIn) {
+ Endpoint = UsbCbi->BulkInEndpoint;
+ } else {
+ Endpoint = UsbCbi->BulkOutEndpoint;
+ }
+
+ Next = Data;
+ Remain = *TransLen;
+ Retry = 0;
+ Status = EFI_SUCCESS;
+ Timeout = Timeout / USB_MASS_STALL_1_MS;
+
+ //
+ // Transfer the data, if the device returns NAK, retry it.
+ //
+ while (Remain > 0) {
+ TransStatus = 0;
+
+ if (Remain > (UINTN) USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize) {
+ Increment = USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize;
+ } else {
+ Increment = Remain;
+ }
+
+ Status = UsbCbi->UsbIo->UsbBulkTransfer (
+ UsbCbi->UsbIo,
+ Endpoint->EndpointAddress,
+ Next,
+ &Increment,
+ Timeout,
+ &TransStatus
+ );
+ if (EFI_ERROR (Status)) {
+ if (TransStatus == EFI_USB_ERR_NAK) {
+ //
+ // The device can NAK the host if either the data/buffer isn't
+ // aviable or the command is in-progress. The data can be partly
+ // transferred. The transfer is aborted if several succssive data
+ // transfer commands are NAKed.
+ //
+ if (Increment == 0) {
+ if (++Retry > USB_CBI_MAX_RETRY) {
+ goto ON_EXIT;
+ }
+
+ } else {
+ Next += Increment;
+ Remain -= Increment;
+ Retry = 0;
+ }
+
+ continue;
+ }
+
+ //
+ // The device can fail the command by STALL the bulk endpoint.
+ // Clear the stall if that is the case.
+ //
+ if (TransStatus == EFI_USB_ERR_STALL) {
+ UsbClearEndpointStall (UsbCbi->UsbIo, Endpoint->EndpointAddress);
+ }
+
+ goto ON_EXIT;
+ }
+
+ Next += Increment;
+ Remain -= Increment;
+ }
+
+ON_EXIT:
+ *TransLen -= Remain;
+ return Status;
+}
+
+
+/**
+ Get the result of high level command execution from interrupt
+ endpoint. This function returns the USB transfer status, and
+ put the high level command execution result in Result.
+
+ @param UsbCbi The USB CBI protocol
+ @param Timeout The time to wait the command to execute
+ @param Result GC_TODO: add argument description
+
+ @retval EFI_SUCCESS The high level command execution result is
+ retrieved in Result.
+ @retval Others Failed to retrieve the result.
+
+**/
+STATIC
+EFI_STATUS
+UsbCbiGetStatus (
+ IN USB_CBI_PROTOCOL *UsbCbi,
+ IN UINT32 Timeout,
+ OUT USB_CBI_STATUS *Result
+ )
+{
+ UINTN Len;
+ UINT8 Endpoint;
+ EFI_STATUS Status;
+ UINT32 TransStatus;
+ INTN Retry;
+
+ Endpoint = UsbCbi->InterruptEndpoint->EndpointAddress;
+ Status = EFI_SUCCESS;
+ Timeout = Timeout / USB_MASS_STALL_1_MS;
+
+ //
+ // Attemp to the read the result from interrupt endpoint
+ //
+ for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
+ TransStatus = 0;
+ Len = sizeof (USB_CBI_STATUS);
+
+ Status = UsbCbi->UsbIo->UsbSyncInterruptTransfer (
+ UsbCbi->UsbIo,
+ Endpoint,
+ Result,
+ &Len,
+ Timeout,
+ &TransStatus
+ );
+ //
+ // The CBI can NAK the interrupt endpoint if the command is in-progress.
+ //
+ if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
+ continue;
+ }
+
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute USB mass storage command through the CBI0/CBI1 transport protocol
+
+ @param Context The USB CBI device
+ @param Cmd The command to transfer to device
+ @param CmdLen The length of the command
+ @param DataDir The direction of data transfer
+ @param Data The buffer to hold the data
+ @param DataLen The length of the buffer
+ @param Timeout The time to wait
+ @param CmdStatus The result of the command execution
+
+ @retval EFI_SUCCESS The command is executed OK and result in CmdStatus.
+ @retval EFI_DEVICE_ERROR Failed to execute the command
+
+**/
+STATIC
+EFI_STATUS
+UsbCbiExecCommand (
+ IN VOID *Context,
+ IN VOID *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN VOID *Data,
+ IN UINT32 DataLen,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ )
+{
+ USB_CBI_PROTOCOL *UsbCbi;
+ USB_CBI_STATUS Result;
+ EFI_STATUS Status;
+ UINTN TransLen;
+
+ *CmdStatus = USB_MASS_CMD_SUCCESS;
+ UsbCbi = (USB_CBI_PROTOCOL *) Context;
+
+ //
+ // Send the command to the device. Return immediately if device
+ // rejects the command.
+ //
+ Status = UsbCbiSendCommand (UsbCbi, Cmd, CmdLen, Timeout);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbCbiError, "UsbCbiExecCommand: UsbCbiSendCommand (%r)\n",Status));
+ return Status;
+ }
+
+ //
+ // Transfer the data, return this status if no interrupt endpoint
+ // is used to report the transfer status.
+ //
+ TransLen = (UINTN) DataLen;
+
+ Status = UsbCbiDataTransfer (UsbCbi, DataDir, Data, &TransLen, Timeout);
+ if (UsbCbi->InterruptEndpoint == NULL) {
+ DEBUG ((mUsbCbiError, "UsbCbiExecCommand: UsbCbiDataTransfer (%r)\n",Status));
+ return Status;
+ }
+
+ //
+ // Get the status, if that succeeds, interpret the result
+ //
+ Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbCbiError, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) {
+ //
+ // For UFI device, ASC and ASCQ are returned.
+ //
+ if (Result.Type != 0) {
+ *CmdStatus = USB_MASS_CMD_FAIL;
+ }
+
+ } else {
+ //
+ // Check page 27, CBI spec 1.1 for vaious reture status.
+ //
+ switch (Result.Value & 0x03) {
+ case 0x00:
+ //
+ // Pass
+ //
+ *CmdStatus = USB_MASS_CMD_SUCCESS;
+ break;
+
+ case 0x02:
+ //
+ // Phase Error, response with reset. Fall through to Fail.
+ //
+ UsbCbiResetDevice (UsbCbi, FALSE);
+
+ case 0x01:
+ //
+ // Fail
+ //
+ *CmdStatus = USB_MASS_CMD_FAIL;
+ break;
+
+ case 0x03:
+ //
+ // Persistent Fail, need to send REQUEST SENSE.
+ //
+ *CmdStatus = USB_MASS_CMD_PERSISTENT;
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Call the Usb mass storage class transport protocol to
+ reset the device. The reset is defined as a Non-Data
+ command. Don't use UsbCbiExecCommand to send the command
+ to device because that may introduce recursive loop.
+
+ @param Context The USB CBI device protocol
+
+ @retval EFI_SUCCESS the device is reset
+ @retval Others Failed to reset the device
+
+**/
+STATIC
+EFI_STATUS
+UsbCbiResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ UINT8 ResetCmd[USB_CBI_RESET_CMD_LEN];
+ USB_CBI_PROTOCOL *UsbCbi;
+ USB_CBI_STATUS Result;
+ EFI_STATUS Status;
+ UINT32 Timeout;
+
+ UsbCbi = (USB_CBI_PROTOCOL *) Context;
+
+ //
+ // Fill in the reset command.
+ //
+ SetMem (ResetCmd, USB_CBI_RESET_CMD_LEN, 0xFF);
+
+ ResetCmd[0] = 0x1D;
+ ResetCmd[1] = 0x04;
+ Timeout = USB_CBI_RESET_TIMEOUT / USB_MASS_STALL_1_MS;
+
+ //
+ // Send the command to the device. Don't use UsbCbiExecCommand here.
+ //
+ Status = UsbCbiSendCommand (UsbCbi, ResetCmd, USB_CBI_RESET_CMD_LEN, Timeout);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Just retrieve the status and ignore that. Then stall
+ // 50ms to wait it complete
+ //
+ UsbCbiGetStatus (UsbCbi, Timeout, &Result);
+ gBS->Stall (50 * 1000);
+
+ //
+ // Clear the Bulk-In and Bulk-Out stall condition and
+ // init data toggle.
+ //
+ UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress);
+ UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress);
+ return Status;
+}
+
+
+/**
+ Clean up the CBI protocol's resource
+
+ @param Context The CBI protocol
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+STATIC
+EFI_STATUS
+UsbCbiFini (
+ IN VOID *Context
+ )
+{
+ gBS->FreePool (Context);
+ return EFI_SUCCESS;
+}
+
+USB_MASS_TRANSPORT
+mUsbCbi0Transport = {
+ USB_MASS_STORE_CBI0,
+ UsbCbiInit,
+ UsbCbiExecCommand,
+ UsbCbiResetDevice,
+ UsbCbiFini
+};
+
+USB_MASS_TRANSPORT
+mUsbCbi1Transport = {
+ USB_MASS_STORE_CBI1,
+ UsbCbiInit,
+ UsbCbiExecCommand,
+ UsbCbiResetDevice,
+ UsbCbiFini
+};
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h
new file mode 100644
index 0000000000..d4a9f700ad
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h
@@ -0,0 +1,64 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassCbi.h
+
+Abstract:
+
+ Defination for the USB mass storage Control/Bulk/Interrupt transpor.
+
+Revision History
+
+
+**/
+
+#ifndef _EFI_USBMASS_CBI_H_
+#define _EFI_USBMASS_CBI_H_
+
+enum {
+ USB_CBI_MAX_PACKET_NUM = 16,
+ USB_CBI_RESET_CMD_LEN = 12,
+
+ //
+ // Usb CBI retry times
+ //
+ USB_CBI_MAX_RETRY = 3,
+
+ //
+ // Usb Cbi transfer timeout
+ //
+ USB_CBI_RESET_TIMEOUT = 1 * USB_MASS_STALL_1_S,
+};
+
+//
+// Put Interface at the first field is to make it easy to get by Context, which
+// could be BOT/CBI Protocol instance
+//
+typedef struct {
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
+ EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
+ EFI_USB_ENDPOINT_DESCRIPTOR *InterruptEndpoint;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+} USB_CBI_PROTOCOL;
+
+#pragma pack(1)
+typedef struct {
+ UINT8 Type;
+ UINT8 Value;
+} USB_CBI_STATUS;
+#pragma pack()
+
+extern USB_MASS_TRANSPORT mUsbCbi0Transport;
+extern USB_MASS_TRANSPORT mUsbCbi1Transport;
+#endif
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
new file mode 100644
index 0000000000..a7c3e82f98
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c
@@ -0,0 +1,640 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassImpl.c
+
+Abstract:
+
+ The implementation of USB mass storage class device driver.
+ The command set supported is "USB Mass Storage Specification
+ for Bootability".
+
+Revision History
+
+
+**/
+
+#include "UsbMassImpl.h"
+
+//
+// The underlying transport protocol. CBI support isn't included
+// in the current build. It is being obseleted by the standard
+// body. If you want to enable it, remove the if directive here,
+// then add the UsbMassCbi.c/.h to the driver's inf file.
+//
+STATIC
+USB_MASS_TRANSPORT *mUsbMassTransport[] = {
+ &mUsbCbi0Transport,
+ &mUsbCbi1Transport,
+ &mUsbBotTransport,
+ NULL
+};
+
+UINTN mUsbMscInfo = DEBUG_INFO;
+UINTN mUsbMscError = DEBUG_ERROR;
+
+
+/**
+ Retrieve the media parameters such as disk gemotric for the
+ device's BLOCK IO protocol.
+
+ @param UsbMass The USB mass storage device
+
+ @retval EFI_SUCCESS The media parameters is updated successfully.
+ @retval Others Failed to get the media parameters.
+
+**/
+EFI_STATUS
+UsbMassInitMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // Initialize the MediaPrsent/ReadOnly and others to the default.
+ // We are not forced to get it right at this time, check UEFI2.0
+ // spec for more information:
+ //
+ // MediaPresent: This field shows the media present status as
+ // of the most recent ReadBlocks or WriteBlocks call.
+ //
+ // ReadOnly : This field shows the read-only status as of the
+ // recent WriteBlocks call.
+ //
+ // but remember to update MediaId/MediaPresent/ReadOnly status
+ // after ReadBlocks and WriteBlocks
+ //
+ Media->MediaPresent = FALSE;
+ Media->LogicalPartition = FALSE;
+ Media->ReadOnly = FALSE;
+ Media->WriteCaching = FALSE;
+ Media->IoAlign = 0;
+
+ //
+ // Some device may spend several seconds before it is ready.
+ // Try several times before giving up. Wait 5s at most.
+ //
+ Status = EFI_SUCCESS;
+
+ for (Index = 0; Index < USB_BOOT_WAIT_RETRY; Index++) {
+
+ Status = UsbBootGetParams (UsbMass);
+ if ((Status != EFI_MEDIA_CHANGED)
+ && (Status != EFI_NOT_READY)
+ && (Status != EFI_TIMEOUT)) {
+ break;
+ }
+
+ Status = UsbBootIsUnitReady (UsbMass);
+ if (EFI_ERROR (Status)) {
+ gBS->Stall (USB_BOOT_UNIT_READY_STALL * (Index + 1));
+ }
+
+ }
+
+ return Status;
+}
+
+
+/**
+ Reset the block device. ExtendedVerification is ignored for this.
+
+ @param This The BLOCK IO protocol
+ @param ExtendedVerification Whether to execute extended verfication.
+
+ @retval EFI_SUCCESS The device is successfully resetted.
+ @retval Others Failed to reset the device.
+
+**/
+EFI_STATUS
+UsbMassReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
+ return UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
+}
+
+
+/**
+ Read some blocks of data from the block device.
+
+ @param This The Block IO protocol
+ @param MediaId The media's ID of the device for current request
+ @param Lba The start block number
+ @param BufferSize The size of buffer to read data in
+ @param Buffer The buffer to read data to
+
+ @retval EFI_SUCCESS The data is successfully read
+ @retval EFI_NO_MEDIA Media isn't present
+ @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
+ MediaId changed
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
+ NULL.
+ @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
+ size, or overflow the last block number.
+
+**/
+EFI_STATUS
+UsbMassReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN TotalBlock;
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // First, validate the parameters
+ //
+ if ((Buffer == NULL) || (BufferSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If it is a remoable media, such as CD-Rom or Usb-Floppy,
+ // if, need to detect the media before each rw, while Usb-Flash
+ // needn't. However, it's hard to identify Usb-Floppy between
+ // Usb-Flash by now, so detect media every time.
+ //
+ Status = UsbBootDetectMedia (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // Make sure BlockSize and LBA is consistent with BufferSize
+ //
+ if ((BufferSize % Media->BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ TotalBlock = BufferSize / Media->BlockSize;
+
+ if (Lba + TotalBlock - 1 > Media->LastBlock) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
+ UsbMassReset (This, TRUE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Write some blocks of data to the block device.
+
+ @param This The Block IO protocol
+ @param MediaId The media's ID of the device for current request
+ @param Lba The start block number
+ @param BufferSize The size of buffer to write data to
+ @param Buffer The buffer to write data to
+
+ @retval EFI_SUCCESS The data is successfully written
+ @retval EFI_NO_MEDIA Media isn't present
+ @retval EFI_MEDIA_CHANGED The device media has been changed, that is,
+ MediaId changed
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
+ NULL.
+ @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
+ size,
+
+**/
+EFI_STATUS
+UsbMassWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINTN TotalBlock;
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // First, validate the parameters
+ //
+ if ((Buffer == NULL) || (BufferSize == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If it is a remoable media, such as CD-Rom or Usb-Floppy,
+ // if, need to detect the media before each rw, while Usb-Flash
+ // needn't. However, it's hard to identify Usb-Floppy between
+ // Usb-Flash by now, so detect media every time.
+ //
+ Status = UsbBootDetectMedia (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // Make sure BlockSize and LBA is consistent with BufferSize
+ //
+ if ((BufferSize % Media->BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ TotalBlock = BufferSize / Media->BlockSize;
+
+ if (Lba + TotalBlock - 1 > Media->LastBlock) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ //
+ // Try to write the data even the device is marked as ReadOnly,
+ // and clear the status should the write succeed.
+ //
+ Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
+ UsbMassReset (This, TRUE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Flush the cached writes to disks. USB mass storage device doesn't
+ support write cache, so return EFI_SUCCESS directly.
+
+ @param This The BLOCK IO protocol
+
+ @retval EFI_SUCCESS Always returns success
+
+**/
+EFI_STATUS
+UsbMassFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether the controller is a supported USB mass storage.
+
+ @param This The USB mass driver's driver binding.
+ @param Controller The device to test against.
+ @param RemainingDevicePath The remaining device path
+
+ @retval EFI_SUCCESS This device is a supported USB mass storage.
+ @retval EFI_UNSUPPORTED The device isn't supported
+ @retval Others Some error happened.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ USB_MASS_TRANSPORT *Transport;
+ EFI_STATUS Status;
+ INTN Index;
+
+ //
+ // Check whether the controlelr support USB_IO
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the interface to check the USB class and find a transport
+ // protocol handler.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
+ goto ON_EXIT;
+ }
+
+ for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
+ Transport = mUsbMassTransport[Index];
+ if (Interface.InterfaceProtocol == Transport->Protocol) {
+ Status = Transport->Init (UsbIo, Controller, NULL);
+ break;
+ }
+ }
+
+ DEBUG ((mUsbMscInfo, "Found a USB mass store device %r\n", Status));
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Start the USB mass storage device on the controller. It will
+ install a BLOCK_IO protocol on the device if everything is OK.
+
+ @param This The USB mass storage driver binding.
+ @param Controller The USB mass storage device to start on
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver has started on the device.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
+ @retval Others Failed to start the driver on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ USB_MASS_DEVICE *UsbMass;
+ USB_MASS_TRANSPORT *Transport;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
+ if (UsbMass == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize the transport protocols
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));
+ goto ON_ERROR;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
+ Transport = mUsbMassTransport[Index];
+
+ if (Interface.InterfaceProtocol == Transport->Protocol) {
+ UsbMass->Transport = Transport;
+ Status = Transport->Init (UsbIo, Controller, &UsbMass->Context);
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status));
+ goto ON_ERROR;
+ }
+
+ UsbMass->Signature = USB_MASS_SIGNATURE;
+ UsbMass->Controller = Controller;
+ UsbMass->UsbIo = UsbIo;
+ UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
+ UsbMass->BlockIo.Reset = UsbMassReset;
+ UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
+ UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
+ UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
+ UsbMass->OpticalStorage = FALSE;
+
+ //
+ // Get the storage's parameters, such as last block number.
+ // then install the BLOCK_IO
+ //
+ Status = UsbMassInitMedia (UsbMass);
+ if (!EFI_ERROR (Status)) {
+ if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
+ (UsbMass->Pdt != USB_PDT_CDROM) &&
+ (UsbMass->Pdt != USB_PDT_OPTICAL) &&
+ (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
+ DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
+ goto ON_ERROR;
+ }
+ } else if (Status != EFI_NO_MEDIA){
+ DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status));
+ goto ON_ERROR;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiBlockIoProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &UsbMass->BlockIo
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ gBS->FreePool (UsbMass);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Stop controlling the device.
+
+ @param This The USB mass storage driver binding
+ @param Controller The device controller controlled by the driver.
+ @param NumberOfChildren The number of children of this device
+ @param ChildHandleBuffer The buffer of children handle.
+
+ @retval EFI_SUCCESS The driver stopped from controlling the device.
+ @retval Others Failed to stop the driver
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ USB_MASS_DEVICE *UsbMass;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // First, get our context back from the BLOCK_IO
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);
+
+ //
+ // Uninstall Block I/O protocol from the device handle,
+ // then call the transport protocol to stop itself.
+ //
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ UsbMass->Transport->Fini (UsbMass->Context);
+ gBS->FreePool (UsbMass);
+
+ return EFI_SUCCESS;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
+ USBMassDriverBindingSupported,
+ USBMassDriverBindingStart,
+ USBMassDriverBindingStop,
+ 0x11,
+ NULL,
+ NULL
+};
+
+//@MT: EFI_DRIVER_ENTRY_POINT (USBMassStorageEntryPoint)
+
+EFI_STATUS
+EFIAPI
+USBMassStorageEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ The entry point for the driver, which will install the driver binding and
+ component name protocol
+
+Arguments:
+
+ ImageHandle - The image handle of this driver
+ SystemTable - The system table
+
+Returns:
+
+ EFI_SUCCESS - the protocols are installed OK
+ Others - Failed to install protocols.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver binding protocol
+ //
+ Status = EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &gUSBMassDriverBinding,
+ ImageHandle,
+ &gUsbMassStorageComponentName,
+ NULL,
+ NULL
+ );
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h
new file mode 100644
index 0000000000..39bc87ca9e
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h
@@ -0,0 +1,57 @@
+/** @file
+
+Copyright (c) 2007, 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.
+
+Module Name:
+
+ UsbMassImpl.h
+
+Abstract:
+
+ The implementation of USB mass storage class device driver.
+
+Revision History
+
+
+**/
+
+#ifndef _EFI_USBMASS_IMPL_H_
+#define _EFI_USBMASS_IMPL_H_
+
+typedef struct _USB_MASS_DEVICE USB_MASS_DEVICE;
+
+#include "UsbMass.h"
+#include "UsbMassBot.h"
+#include "UsbMassCbi.h"
+#include "UsbMassBoot.h"
+
+enum {
+ USB_MASS_SIGNATURE= EFI_SIGNATURE_32 ('U', 's', 'b', 'K'),
+};
+
+typedef struct _USB_MASS_DEVICE {
+ UINT32 Signature;
+ EFI_HANDLE Controller;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO_MEDIA BlockIoMedia;
+ BOOLEAN OpticalStorage;
+ UINT8 Lun; // Logical Unit Number
+ UINT8 Pdt; // Peripheral Device Type
+ USB_MASS_TRANSPORT *Transport; // USB mass storage transport protocol
+ VOID *Context; // Opaque storage for mass transport
+};
+
+#define USB_MASS_DEVICE_FROM_BLOCKIO(a) \
+ CR (a, USB_MASS_DEVICE, BlockIo, USB_MASS_SIGNATURE)
+
+extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName;
+
+#endif
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
new file mode 100644
index 0000000000..7636db7028
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
@@ -0,0 +1,95 @@
+#/** @file
+# Component name for module UsbMassStorage
+#
+# Copyright (c) 2006, Intel Corporation. All right reserved.
+#
+# 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 Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbMassStorageDxe
+ FILE_GUID = 9FB4B4A7-42C0-4bcd-8540-9BCC6711F83E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = USBMassStorageEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+
+[Sources.common]
+ UsbMassBoot.h
+ UsbMassImpl.h
+ UsbMassBot.h
+ UsbMassBot.c
+ ComponentName.c
+ UsbMassImpl.c
+ UsbMassBoot.c
+ UsbMassCbi.h
+ UsbMass.h
+ UsbMassCbi.c
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+################################################################################
+#
+# Library Class Section - list of Library Classes that are required for
+# this module.
+#
+################################################################################
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+
+
+################################################################################
+#
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names
+# that this module uses or produces.
+#
+################################################################################
+
+[Protocols]
+ gEfiUsbIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiBlockIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.msa b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.msa
new file mode 100644
index 0000000000..ca7f3db911
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.msa
@@ -0,0 +1,75 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>UsbMassStorageDxe</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>9FB4B4A7-42C0-4bcd-8540-9BCC6711F83E</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component name for module UsbMassStorage</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>
+ <License>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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>UsbMassStorageDxe</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>UsbMassCbi.c</Filename>
+ <Filename>UsbMass.h</Filename>
+ <Filename>UsbMassCbi.h</Filename>
+ <Filename>UsbMassBoot.c</Filename>
+ <Filename>UsbMassImpl.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>UsbMassBot.c</Filename>
+ <Filename>UsbMassBot.h</Filename>
+ <Filename>UsbMassImpl.h</Filename>
+ <Filename>UsbMassBoot.h</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiBlockIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">
+ <ProtocolCName>gEfiUsbIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <ModuleEntryPoint>USBMassStorageEntryPoint</ModuleEntryPoint>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea> \ No newline at end of file