diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe')
15 files changed, 5053 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c new file mode 100644 index 000000000..dff3d3a7b --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c @@ -0,0 +1,156 @@ +/** @file
+ UEFI Component Name(2) protocol implementation for USB Mass Storage Driver.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName = {
+ UsbMassStorageGetDriverName,
+ UsbMassStorageGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbMassStorageComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbMassStorageGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbMassStorageGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
+mUsbMassStorageDriverNameTable[] = {
+ {"eng;en", L"Usb Mass Storage Driver"},
+ {NULL, NULL}
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param 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.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassStorageGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUsbMassStorageDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbMassStorageComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param 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.
+ @param 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.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param 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.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+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
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h new file mode 100644 index 000000000..fccb203a3 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h @@ -0,0 +1,187 @@ +/** @file
+ Definition of USB Mass Storage Class and its value, USB Mass Transport Protocol,
+ and other common definitions.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_H_
+#define _EFI_USBMASS_H_
+
+
+#include <Uefi.h>
+#include <IndustryStandard/Scsi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DiskInfo.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+
+typedef struct _USB_MASS_TRANSPORT USB_MASS_TRANSPORT;
+typedef struct _USB_MASS_DEVICE USB_MASS_DEVICE;
+
+#include "UsbMassBot.h"
+#include "UsbMassCbi.h"
+#include "UsbMassBoot.h"
+#include "UsbMassDiskInfo.h"
+#include "UsbMassImpl.h"
+
+#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == BIT7)
+#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == 0)
+#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)
+#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT)
+#define USB_IS_ERROR(Result, Error) (((Result) & (Error)) != 0)
+
+#define USB_MASS_1_MILLISECOND 1000
+#define USB_MASS_1_SECOND (1000 * USB_MASS_1_MILLISECOND)
+
+#define USB_MASS_CMD_SUCCESS 0
+#define USB_MASS_CMD_FAIL 1
+#define USB_MASS_CMD_PERSISTENT 2
+
+/**
+ Initializes USB transport protocol.
+
+ This function initializes the USB mass storage class transport protocol.
+ It will save its context in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB transport initialization fails.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_INIT_TRANSPORT) (
+ IN EFI_USB_IO_PROTOCOL *Usb,
+ OUT VOID **Context OPTIONAL
+ );
+
+/**
+ Execute USB mass storage command through the transport protocol.
+
+ @param Context The USB Transport Protocol.
+ @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 Lun Should be 0, this field for bot only
+ @param Timeout The time to wait
+ @param CmdStatus The result of the command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute the command
+
+**/
+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 UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ );
+
+/**
+ Reset the USB mass storage device by Transport protocol.
+
+ @param Context The USB Transport Protocol
+ @param ExtendedVerification The flag controlling the rule of reset.
+ Not used here.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_RESET) (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Get the max LUN (Logical Unit Number) of USB mass storage device.
+
+ @param Context The context of the transport protocol.
+ @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
+ LUN1 in all.)
+
+ @retval EFI_SUCCESS Max LUN is got successfully.
+ @retval Others Fail to execute this request.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_GET_MAX_LUN) (
+ IN VOID *Context,
+ IN UINT8 *MaxLun
+ );
+
+/**
+ Clean up the transport protocol's resource.
+
+ @param Context The instance of transport protocol.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+typedef
+EFI_STATUS
+(*USB_MASS_CLEAN_UP) (
+ 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.
+///
+struct _USB_MASS_TRANSPORT {
+ 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_GET_MAX_LUN GetMaxLun; ///< Get max lun, only for bot
+ USB_MASS_CLEAN_UP CleanUp; ///< Clean up the resources.
+};
+
+struct _USB_MASS_DEVICE {
+ UINT32 Signature;
+ EFI_HANDLE Controller;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ 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;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+ USB_BOOT_INQUIRY_DATA InquiryData;
+ BOOLEAN Cdb16Byte;
+};
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c new file mode 100644 index 000000000..aab4061e1 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c @@ -0,0 +1,998 @@ +/** @file
+ Implementation of the command set of USB Mass Storage Specification
+ for Bootability, Revision 1.0.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+/**
+ Execute REQUEST SENSE Command to retrieve sense data from device.
+
+ @param UsbMass The device whose sense data is requested.
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval EFI_DEVICE_ERROR Failed to request sense.
+ @retval EFI_NO_RESPONSE The device media doesn't response this request.
+ @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.
+
+**/
+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
+ //
+ 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 = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+ SenseCmd.AllocLen = (UINT8) 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),
+ UsbMass->Lun,
+ USB_BOOT_GENERAL_CMD_TIMEOUT,
+ &CmdResult
+ );
+ if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+ }
+
+ //
+ // If sense data is retrieved successfully, 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:
+ if (SenseData.Asc == USB_BOOT_ASC_NO_ADDITIONAL_SENSE_INFORMATION) {
+ //
+ // It is not an error if a device does not have additional sense information
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_NO_RESPONSE;
+ }
+ break;
+
+ 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:
+ Status = EFI_DEVICE_ERROR;
+ if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
+ Media->MediaPresent = FALSE;
+ Status = EFI_NO_MEDIA;
+ } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
+ 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) {
+ //
+ // If MediaChange, reset ReadOnly and new MediaId
+ //
+ Status = EFI_MEDIA_CHANGED;
+ Media->ReadOnly = FALSE;
+ Media->MediaId++;
+ } else if (SenseData.Asc == USB_BOOT_ASC_NOT_READY) {
+ Status = EFI_NOT_READY;
+ } else if (SenseData.Asc == USB_BOOT_ASC_NO_MEDIA) {
+ Status = EFI_NOT_READY;
+ }
+ break;
+
+ case USB_BOOT_SENSE_DATA_PROTECT:
+ Status = EFI_WRITE_PROTECTED;
+ Media->ReadOnly = TRUE;
+ break;
+
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ DEBUG ((EFI_D_INFO, "UsbBootRequestSense: (%r) with error code (%x) sense key %x/%x/%x\n",
+ Status,
+ SenseData.ErrorCode,
+ USB_BOOT_SENSE_KEY (SenseData.SenseKey),
+ SenseData.Asc,
+ SenseData.Ascq
+ ));
+
+ return Status;
+}
+
+
+/**
+ Execute the USB mass storage bootability commands.
+
+ This function executes 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 Command is executed successfully
+ @retval Others Command execution failed.
+
+**/
+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,
+ UsbMass->Lun,
+ Timeout,
+ &CmdResult
+ );
+
+ if (Status == EFI_TIMEOUT) {
+ DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd\n", Status, *(UINT8 *)Cmd));
+ return EFI_TIMEOUT;
+ }
+
+ //
+ // If ExecCommand() returns no error and CmdResult is success,
+ // then the command transfer is successful.
+ //
+ if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If command execution failed, then retrieve error info via sense request.
+ //
+ DEBUG ((EFI_D_ERROR, "UsbBootExecCmd: %r to Exec 0x%x Cmd (Result = %x)\n", Status, *(UINT8 *)Cmd, CmdResult));
+ return UsbBootRequestSense (UsbMass);
+}
+
+
+/**
+ Execute the USB mass storage bootability commands with retrial.
+
+ This function executes USB mass storage bootability commands.
+ If the device isn't ready, wait for it. If the device is ready
+ and error occurs, retry the command again until it exceeds the
+ limit of retrial times.
+
+ @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 executed successfully.
+ @retval EFI_NO_MEDIA The device media is removed.
+ @retval Others Command execution failed after retrial.
+
+**/
+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;
+ UINTN Retry;
+ EFI_EVENT TimeoutEvt;
+
+ Retry = 0;
+ Status = EFI_SUCCESS;
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeoutEvt
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(60));
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Execute the cmd and retry if it fails.
+ //
+ while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {
+ Status = UsbBootExecCmd (
+ UsbMass,
+ Cmd,
+ CmdLen,
+ DataDir,
+ Data,
+ DataLen,
+ Timeout
+ );
+ if (Status == EFI_SUCCESS || Status == EFI_NO_MEDIA) {
+ break;
+ }
+ //
+ // If the sense data shows the drive is not ready, we need execute the cmd again.
+ // We limit the upper boundary to 60 seconds.
+ //
+ if (Status == EFI_NOT_READY) {
+ continue;
+ }
+ //
+ // If the status is other error, then just retry 5 times.
+ //
+ if (Retry++ >= USB_BOOT_COMMAND_RETRY) {
+ break;
+ }
+ }
+
+EXIT:
+ if (TimeoutEvt != NULL) {
+ gBS->CloseEvent (TimeoutEvt);
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute TEST UNIT READY command to check if the device is ready.
+
+ @param UsbMass The device to test
+
+ @retval EFI_SUCCESS The device is ready.
+ @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 = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+
+ return UsbBootExecCmdWithRetry (
+ UsbMass,
+ &TestCmd,
+ (UINT8) sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
+ EfiUsbNoData,
+ NULL,
+ 0,
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+}
+
+
+/**
+ Execute INQUIRY Command to request information regarding parameters of
+ the device be sent to the host computer.
+
+ @param UsbMass The device to inquire.
+
+ @retval EFI_SUCCESS INQUIRY Command is executed successfully.
+ @retval Others INQUIRY Command is not executed successfully.
+
+**/
+EFI_STATUS
+UsbBootInquiry (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ USB_BOOT_INQUIRY_CMD InquiryCmd;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &(UsbMass->BlockIoMedia);
+
+ ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
+ ZeroMem (&UsbMass->InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
+
+ InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;
+ InquiryCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+ InquiryCmd.AllocLen = (UINT8) sizeof (USB_BOOT_INQUIRY_DATA);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &InquiryCmd,
+ (UINT8) sizeof (USB_BOOT_INQUIRY_CMD),
+ EfiUsbDataIn,
+ &UsbMass->InquiryData,
+ sizeof (USB_BOOT_INQUIRY_DATA),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit
+ // from the inquiry data.
+ //
+ UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (UsbMass->InquiryData.Pdt));
+ Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (UsbMass->InquiryData.Removable));
+ //
+ // Set block size to the default value of 512 Bytes, in case no media is present at first time.
+ //
+ Media->BlockSize = 0x0200;
+
+ return Status;
+}
+
+/**
+ Execute READ CAPACITY 16 bytes command to request information regarding
+ the capacity of the installed medium of the device.
+
+ This function executes READ CAPACITY 16 bytes command to get the capacity
+ of the USB mass storage media, including the presence, block size,
+ and last block number.
+
+ @param UsbMass The device to retireve disk gemotric.
+
+ @retval EFI_SUCCESS The disk geometry is successfully retrieved.
+ @retval EFI_NOT_READY The returned block size is zero.
+ @retval Other READ CAPACITY 16 bytes command execution failed.
+
+**/
+EFI_STATUS
+UsbBootReadCapacity16 (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ UINT8 CapacityCmd[16];
+ EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ Media->MediaPresent = FALSE;
+ Media->LastBlock = 0;
+ Media->BlockSize = 0;
+
+ ZeroMem (CapacityCmd, sizeof (CapacityCmd));
+ ZeroMem (&CapacityData, sizeof (CapacityData));
+
+ CapacityCmd[0] = EFI_SCSI_OP_READ_CAPACITY16;
+ CapacityCmd[1] = 0x10;
+ //
+ // Partial medium indicator, set the bytes 2 ~ 9 of the Cdb as ZERO.
+ //
+ ZeroMem ((CapacityCmd + 2), 8);
+
+ CapacityCmd[13] = sizeof (CapacityData);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ CapacityCmd,
+ (UINT8) sizeof (CapacityCmd),
+ EfiUsbDataIn,
+ &CapacityData,
+ sizeof (CapacityData),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the information on media presence, block size, and last block number
+ // from READ CAPACITY data.
+ //
+ Media->MediaPresent = TRUE;
+ Media->LastBlock = SwapBytes64 (ReadUnaligned64 ((CONST UINT64 *) &(CapacityData.LastLba7)));
+
+ BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) &(CapacityData.BlockSize3)));
+
+ Media->LowestAlignedLba = (CapacityData.LowestAlignLogic2 << 8) |
+ CapacityData.LowestAlignLogic1;
+ Media->LogicalBlocksPerPhysicalBlock = (1 << CapacityData.LogicPerPhysical);
+ if (BlockSize == 0) {
+ //
+ // Get sense data
+ //
+ return UsbBootRequestSense (UsbMass);
+ } else {
+ Media->BlockSize = BlockSize;
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute READ CAPACITY command to request information regarding
+ the capacity of the installed medium of the device.
+
+ This function executes READ CAPACITY command to get the capacity
+ of the USB mass storage media, including the presence, block size,
+ and last block number.
+
+ @param UsbMass The device to retireve disk gemotric.
+
+ @retval EFI_SUCCESS The disk geometry is successfully retrieved.
+ @retval EFI_NOT_READY The returned block size is zero.
+ @retval Other READ CAPACITY command execution failed.
+
+**/
+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;
+ UINT32 BlockSize;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ 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 = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &CapacityCmd,
+ (UINT8) 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;
+ }
+
+ //
+ // Get the information on media presence, block size, and last block number
+ // from READ CAPACITY data.
+ //
+ Media->MediaPresent = TRUE;
+ Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));
+
+ BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));
+ if (BlockSize == 0) {
+ //
+ // Get sense data
+ //
+ return UsbBootRequestSense (UsbMass);
+ } else {
+ Media->BlockSize = BlockSize;
+ }
+
+ if (Media->LastBlock == 0xFFFFFFFF) {
+ Status = UsbBootReadCapacity16 (UsbMass);
+ if (!EFI_ERROR (Status)) {
+ UsbMass->Cdb16Byte = TRUE;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves SCSI mode sense information via MODE SENSE(6) command.
+
+ @param UsbMass The device whose sense data is requested.
+
+ @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.
+ @retval Other Command execution failed.
+
+**/
+EFI_STATUS
+UsbScsiModeSense (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_STATUS Status;
+ USB_SCSI_MODE_SENSE6_CMD ModeSenseCmd;
+ USB_SCSI_MODE_SENSE6_PARA_HEADER ModeParaHeader;
+ EFI_BLOCK_IO_MEDIA *Media;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ ZeroMem (&ModeSenseCmd, sizeof (USB_SCSI_MODE_SENSE6_CMD));
+ ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));
+
+ //
+ // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec
+ //
+ ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;
+ ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);
+ ModeSenseCmd.PageCode = 0x3F;
+ ModeSenseCmd.AllocateLen = (UINT8) sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER);
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &ModeSenseCmd,
+ (UINT8) sizeof (USB_SCSI_MODE_SENSE6_CMD),
+ EfiUsbDataIn,
+ &ModeParaHeader,
+ sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER),
+ USB_BOOT_GENERAL_CMD_TIMEOUT
+ );
+
+ //
+ // Format of device-specific parameter byte of the mode parameter header is defined in
+ // Section 8.2.10 of SCSI-2 Spec.
+ // BIT7 of this byte is indicates whether the medium is write protected.
+ //
+ if (!EFI_ERROR (Status)) {
+ Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the parameters for the USB mass storage media.
+
+ This function get the parameters for the USB mass storage media,
+ It is used both to initialize the media during the Start() phase
+ of Driver Binding Protocol and to re-initialize it when the media is
+ changed. Although the RemoveableMedia is unlikely to change,
+ it is also included here.
+
+ @param UsbMass The device to retrieve disk gemotric.
+
+ @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
+ @retval Other Failed to get the parameters.
+
+**/
+EFI_STATUS
+UsbBootGetParams (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Media = &(UsbMass->BlockIoMedia);
+
+ Status = UsbBootInquiry (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
+ return Status;
+ }
+
+ //
+ // According to USB Mass Storage Specification for Bootability, only following
+ // 4 Peripheral Device Types are in spec.
+ //
+ if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
+ (UsbMass->Pdt != USB_PDT_CDROM) &&
+ (UsbMass->Pdt != USB_PDT_OPTICAL) &&
+ (UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootGetParams: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Don't use the Removable bit in inquiry data 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 device and Non-CD optical device
+ //
+ UsbMass->OpticalStorage = TRUE;
+ //
+ // Default value 2048 Bytes, in case no media present at first time
+ //
+ Media->BlockSize = 0x0800;
+ }
+
+ Status = UsbBootDetectMedia (UsbMass);
+
+ return Status;
+}
+
+
+/**
+ Detect whether the removable media is present and whether it has changed.
+
+ @param UsbMass The device to check.
+
+ @retval EFI_SUCCESS The media status is successfully checked.
+ @retval Other Failed to detect media.
+
+**/
+EFI_STATUS
+UsbBootDetectMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ EFI_BLOCK_IO_MEDIA OldMedia;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINT8 CmdSet;
+ EFI_STATUS Status;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));
+
+ CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
+
+ Status = UsbBootIsUnitReady (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status));
+ }
+
+ //
+ // Status could be:
+ // EFI_SUCCESS: all good.
+ // EFI_NO_MEDIA: media is not present.
+ // others: HW error.
+ // For either EFI_NO_MEDIA, or HW error, skip to get WriteProtected and capacity information.
+ //
+ if (!EFI_ERROR (Status)) {
+ if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
+ //
+ // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,
+ // according to Section 4 of USB Mass Storage Specification for Bootability.
+ // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI
+ // could get the information of Write Protected.
+ // Since not all device support this command, skip if fail.
+ //
+ UsbScsiModeSense (UsbMass);
+ }
+
+ Status = UsbBootReadCapacity (UsbMass);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootReadCapacity (%r)\n", Status));
+ }
+ }
+
+ if (EFI_ERROR (Status) && Status != EFI_NO_MEDIA) {
+ //
+ // For NoMedia, BlockIo is still needed.
+ //
+ return Status;
+ }
+
+ //
+ // Simply reject device whose block size is unacceptable small (==0) or large (>64K).
+ //
+ if ((Media->BlockSize == 0) || (Media->BlockSize > USB_BOOT_MAX_CARRY_SIZE)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Detect whether it is necessary to reinstall the Block I/O Protocol.
+ //
+ // MediaId may change in RequestSense for MediaChanged
+ // MediaPresent may change in RequestSense for NoMedia
+ // MediaReadOnly may change in RequestSense for WriteProtected or MediaChanged
+ // MediaPresent/BlockSize/LastBlock may change in ReadCapacity
+ //
+ if ((Media->MediaId != OldMedia.MediaId) ||
+ (Media->MediaPresent != OldMedia.MediaPresent) ||
+ (Media->ReadOnly != OldMedia.ReadOnly) ||
+ (Media->BlockSize != OldMedia.BlockSize) ||
+ (Media->LastBlock != OldMedia.LastBlock)) {
+
+ //
+ // This function is called from:
+ // Block I/O Protocol APIs, which run at TPL_CALLBACK.
+ // DriverBindingStart(), which raises to TPL_CALLBACK.
+ ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);
+
+ //
+ // When it is called from DriverBindingStart(), below reinstall fails.
+ // So ignore the return status check.
+ //
+ gBS->ReinstallProtocolInterface (
+ UsbMass->Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &UsbMass->BlockIo
+ );
+
+ //
+ // Reset MediaId after reinstalling Block I/O Protocol.
+ //
+ if (Media->MediaPresent != OldMedia.MediaPresent) {
+ if (Media->MediaPresent) {
+ Media->MediaId = 1;
+ } else {
+ Media->MediaId = 0;
+ }
+ }
+
+ if ((Media->ReadOnly != OldMedia.ReadOnly) ||
+ (Media->BlockSize != OldMedia.BlockSize) ||
+ (Media->LastBlock != OldMedia.LastBlock)) {
+ Media->MediaId++;
+ }
+
+ Status = Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA;
+ }
+
+ return Status;
+}
+
+
+/**
+ Read or write some blocks from the device.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ )
+{
+ USB_BOOT_READ_WRITE_10_CMD Cmd;
+ EFI_STATUS Status;
+ UINT32 Count;
+ UINT32 CountMax;
+ UINT32 BlockSize;
+ UINT32 ByteSize;
+ UINT32 Timeout;
+
+ BlockSize = UsbMass->BlockIoMedia.BlockSize;
+ CountMax = USB_BOOT_MAX_CARRY_SIZE / 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 = (UINT32)MIN (TotalBlock, CountMax);
+ Count = MIN (MAX_UINT16, Count);
+ ByteSize = Count * BlockSize;
+
+ //
+ // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
+ //
+ Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
+
+ //
+ // Fill in the command then execute
+ //
+ ZeroMem (&Cmd, sizeof (USB_BOOT_READ_WRITE_10_CMD));
+
+ Cmd.OpCode = Write ? USB_BOOT_WRITE10_OPCODE : USB_BOOT_READ10_OPCODE;
+ Cmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
+ WriteUnaligned32 ((UINT32 *) Cmd.Lba, SwapBytes32 (Lba));
+ WriteUnaligned16 ((UINT16 *) Cmd.TransferLen, SwapBytes16 ((UINT16)Count));
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ &Cmd,
+ (UINT8) sizeof (USB_BOOT_READ_WRITE_10_CMD),
+ Write ? EfiUsbDataOut : EfiUsbDataIn,
+ Buffer,
+ ByteSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((
+ DEBUG_BLKIO, "UsbBoot%sBlocks: LBA (0x%lx), Blk (0x%x)\n",
+ Write ? L"Write" : L"Read",
+ Lba, Count
+ ));
+ Lba += Count;
+ Buffer += ByteSize;
+ TotalBlock -= Count;
+ }
+
+ return Status;
+}
+
+/**
+ Read or write some blocks from the device by SCSI 16 byte cmd.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks16 (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT64 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ )
+{
+ UINT8 Cmd[16];
+ EFI_STATUS Status;
+ UINT32 Count;
+ UINT32 CountMax;
+ UINT32 BlockSize;
+ UINT32 ByteSize;
+ UINT32 Timeout;
+
+ BlockSize = UsbMass->BlockIoMedia.BlockSize;
+ CountMax = USB_BOOT_MAX_CARRY_SIZE / BlockSize;
+ Status = EFI_SUCCESS;
+
+ while (TotalBlock > 0) {
+ //
+ // Split the total blocks into smaller pieces.
+ //
+ Count = (UINT32)MIN (TotalBlock, CountMax);
+ ByteSize = Count * BlockSize;
+
+ //
+ // USB command's upper limit timeout is 5s. [USB2.0-9.2.6.1]
+ //
+ Timeout = (UINT32) USB_BOOT_GENERAL_CMD_TIMEOUT;
+
+ //
+ // Fill in the command then execute
+ //
+ ZeroMem (Cmd, sizeof (Cmd));
+
+ Cmd[0] = Write ? EFI_SCSI_OP_WRITE16 : EFI_SCSI_OP_READ16;
+ Cmd[1] = (UINT8) ((USB_BOOT_LUN (UsbMass->Lun) & 0xE0));
+ WriteUnaligned64 ((UINT64 *) &Cmd[2], SwapBytes64 (Lba));
+ WriteUnaligned32 ((UINT32 *) &Cmd[10], SwapBytes32 (Count));
+
+ Status = UsbBootExecCmdWithRetry (
+ UsbMass,
+ Cmd,
+ (UINT8) sizeof (Cmd),
+ Write ? EfiUsbDataOut : EfiUsbDataIn,
+ Buffer,
+ ByteSize,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((
+ DEBUG_BLKIO, "UsbBoot%sBlocks16: LBA (0x%lx), Blk (0x%x)\n",
+ Write ? L"Write" : L"Read",
+ Lba, Count
+ ));
+ Lba += Count;
+ Buffer += ByteSize;
+ TotalBlock -= Count;
+ }
+
+ return Status;
+}
+
+/**
+ Use the USB clear feature control transfer to clear the endpoint stall condition.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param EndpointAddr The endpoint to clear stall for
+
+ @retval EFI_SUCCESS The endpoint stall condition is cleared.
+ @retval Others Failed to clear the endpoint stall condition.
+
+**/
+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_1_MILLISECOND;
+
+ Status = UsbIo->UsbControlTransfer (
+ UsbIo,
+ &Request,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0,
+ &CmdResult
+ );
+
+ return Status;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h new file mode 100644 index 000000000..f34a41284 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h @@ -0,0 +1,338 @@ +/** @file
+ Definition of the command set of USB Mass Storage Specification
+ for Bootability, Revision 1.0.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USB_MASS_BOOT_H_
+#define _EFI_USB_MASS_BOOT_H_
+
+//
+// The opcodes of various USB boot commands:
+// INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified
+// by Multi-Media Commands (MMC) set.
+// Others are "Group 1 Timeout Commands". That is,
+// they should be retried if driver is ready.
+//
+#define USB_BOOT_INQUIRY_OPCODE 0x12
+#define USB_BOOT_REQUEST_SENSE_OPCODE 0x03
+#define USB_BOOT_MODE_SENSE10_OPCODE 0x5A
+#define USB_BOOT_READ_CAPACITY_OPCODE 0x25
+#define USB_BOOT_TEST_UNIT_READY_OPCODE 0x00
+#define USB_BOOT_READ10_OPCODE 0x28
+#define USB_BOOT_WRITE10_OPCODE 0x2A
+
+#define USB_SCSI_MODE_SENSE6_OPCODE 0x1A
+
+//
+// The Sense Key part of the sense data. Sense data has three levels:
+// Sense key, Additional Sense Code and Additional Sense Code Qualifier
+//
+#define USB_BOOT_SENSE_NO_SENSE 0x00 ///< No sense key
+#define USB_BOOT_SENSE_RECOVERED 0x01 ///< Last command succeed with recovery actions
+#define USB_BOOT_SENSE_NOT_READY 0x02 ///< Device not ready
+#define USB_BOOT_SNESE_MEDIUM_ERROR 0X03 ///< Failed probably because flaw in the media
+#define USB_BOOT_SENSE_HARDWARE_ERROR 0X04 ///< Non-recoverable hardware failure
+#define USB_BOOT_SENSE_ILLEGAL_REQUEST 0X05 ///< Illegal parameters in the request
+#define USB_BOOT_SENSE_UNIT_ATTENTION 0X06 ///< Removable medium may have been changed
+#define USB_BOOT_SENSE_DATA_PROTECT 0X07 ///< Write protected
+#define USB_BOOT_SENSE_BLANK_CHECK 0X08 ///< Blank/non-blank medium while reading/writing
+#define USB_BOOT_SENSE_VENDOR 0X09 ///< Vendor specific sense key
+#define USB_BOOT_SENSE_ABORTED 0X0B ///< Command aborted by the device
+#define USB_BOOT_SENSE_VOLUME_OVERFLOW 0x0D ///< Partition overflow
+#define USB_BOOT_SENSE_MISCOMPARE 0x0E ///< Source data mis-match while verfying.
+
+#define USB_BOOT_ASC_NO_ADDITIONAL_SENSE_INFORMATION 0x00
+#define USB_BOOT_ASC_NOT_READY 0x04
+#define USB_BOOT_ASC_NO_MEDIA 0x3A
+#define USB_BOOT_ASC_MEDIA_CHANGE 0x28
+
+//
+// Supported PDT codes, or Peripheral Device Type
+//
+#define USB_PDT_DIRECT_ACCESS 0x00 ///< Direct access device
+#define USB_PDT_CDROM 0x05 ///< CDROM
+#define USB_PDT_OPTICAL 0x07 ///< Non-CD optical disks
+#define USB_PDT_SIMPLE_DIRECT 0x0E ///< Simplified direct access device
+
+//
+// Other parameters, Max carried size is 64KB.
+//
+#define USB_BOOT_MAX_CARRY_SIZE SIZE_64KB
+
+//
+// Retry mass command times, set by experience
+//
+#define USB_BOOT_COMMAND_RETRY 5
+
+//
+// Wait for unit ready command, set by experience
+//
+#define USB_BOOT_RETRY_UNIT_READY_STALL (500 * USB_MASS_1_MILLISECOND)
+
+//
+// Mass command timeout, refers to specification[USB20-9.2.6.1]
+//
+// USB2.0 Spec define the up-limit timeout 5s for all command. USB floppy,
+// USB CD-Rom and iPod devices are much slower than USB key when response
+// most of commands, So we set 5s as timeout here.
+//
+#define USB_BOOT_GENERAL_CMD_TIMEOUT (5 * USB_MASS_1_SECOND)
+
+//
+// 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_SENSE10_CMD;
+
+typedef struct {
+ UINT8 ModeDataLenMsb;
+ UINT8 ModeDataLenLsb;
+ UINT8 Reserved0[4];
+ UINT8 BlkDesLenMsb;
+ UINT8 BlkDesLenLsb;
+} USB_BOOT_MODE_SENSE10_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_READ_WRITE_10_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;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Lun;
+ UINT8 PageCode;
+ UINT8 Reserved0;
+ UINT8 AllocateLen;
+ UINT8 Control;
+} USB_SCSI_MODE_SENSE6_CMD;
+
+typedef struct {
+ UINT8 ModeDataLen;
+ UINT8 MediumType;
+ UINT8 DevicePara;
+ UINT8 BlkDesLen;
+} USB_SCSI_MODE_SENSE6_PARA_HEADER;
+#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) & BIT7) != 0)
+#define USB_BOOT_PDT(Pdt) ((Pdt) & 0x1f)
+#define USB_BOOT_SENSE_KEY(Key) ((Key) & 0x0f)
+
+/**
+ Get the parameters for the USB mass storage media.
+
+ This function get the parameters for the USB mass storage media,
+ It is used both to initialize the media during the Start() phase
+ of Driver Binding Protocol and to re-initialize it when the media is
+ changed. Although the RemoveableMedia is unlikely to change,
+ it is also included here.
+
+ @param UsbMass The device to retrieve disk gemotric.
+
+ @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
+ @retval Other Failed to get the parameters.
+
+**/
+EFI_STATUS
+UsbBootGetParams (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+/**
+ Execute TEST UNIT READY command to check if the device is ready.
+
+ @param UsbMass The device to test
+
+ @retval EFI_SUCCESS The device is ready.
+ @retval Others Device not ready.
+
+**/
+EFI_STATUS
+UsbBootIsUnitReady (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+/**
+ Detect whether the removable media is present and whether it has changed.
+
+ @param UsbMass The device to check.
+
+ @retval EFI_SUCCESS The media status is successfully checked.
+ @retval Other Failed to detect media.
+
+**/
+EFI_STATUS
+UsbBootDetectMedia (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+/**
+ 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
+ );
+
+/**
+ Read or write some blocks from the device.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT32 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ );
+
+/**
+ Read or write some blocks from the device by SCSI 16 byte cmd.
+
+ @param UsbMass The USB mass storage device to access
+ @param Write TRUE for write operation.
+ @param Lba The start block number
+ @param TotalBlock Total block number to read or write
+ @param Buffer The buffer to read to or write from
+
+ @retval EFI_SUCCESS Data are read into the buffer or writen into the device.
+ @retval Others Failed to read or write all the data
+**/
+EFI_STATUS
+UsbBootReadWriteBlocks16 (
+ IN USB_MASS_DEVICE *UsbMass,
+ IN BOOLEAN Write,
+ IN UINT64 Lba,
+ IN UINTN TotalBlock,
+ IN OUT UINT8 *Buffer
+ );
+
+/**
+ Use the USB clear feature control transfer to clear the endpoint stall condition.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param EndpointAddr The endpoint to clear stall for
+
+ @retval EFI_SUCCESS The endpoint stall condition is cleared.
+ @retval Others Failed to clear the endpoint stall condition.
+
+**/
+EFI_STATUS
+UsbClearEndpointStall (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN UINT8 EndpointAddr
+ );
+
+#endif
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c new file mode 100644 index 000000000..1e878a1bd --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c @@ -0,0 +1,607 @@ +/** @file
+ Implementation of the USB mass storage Bulk-Only Transport protocol,
+ according to USB Mass Storage Class Bulk-Only Transport, Revision 1.0.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+//
+// Definition of USB BOT Transport Protocol
+//
+USB_MASS_TRANSPORT mUsbBotTransport = {
+ USB_MASS_STORE_BOT,
+ UsbBotInit,
+ UsbBotExecCommand,
+ UsbBotResetDevice,
+ UsbBotGetMaxLun,
+ UsbBotCleanUp
+};
+
+/**
+ Initializes USB BOT protocol.
+
+ This function initializes the USB mass storage class BOT 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 I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB BOT initialization fails.
+
+**/
+EFI_STATUS
+UsbBotInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ 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 for USB_BOT_PROTOCOL and two endpoint descriptors.
+ //
+ UsbBot = AllocateZeroPool (sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR));
+ ASSERT (UsbBot != NULL);
+
+ UsbBot->UsbIo = UsbIo;
+
+ //
+ // Get the interface descriptor and validate that it
+ // is a USB Mass Storage BOT interface.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface);
+
+ if (EFI_ERROR (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);
+ CopyMem(UsbBot->BulkInEndpoint, &EndPoint, sizeof (EndPoint));
+ }
+
+ if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbBot->BulkOutEndpoint == NULL)) {
+
+ UsbBot->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1) + 1;
+ CopyMem (UsbBot->BulkOutEndpoint, &EndPoint, sizeof(EndPoint));
+ }
+ }
+
+ //
+ // If bulk-in or bulk-out endpoint is not found, report error.
+ //
+ if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ //
+ // The USB BOT protocol uses CBWTag to match the CBW and CSW.
+ //
+ UsbBot->CbwTag = 0x01;
+
+ if (Context != NULL) {
+ *Context = UsbBot;
+ } else {
+ FreePool (UsbBot);
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ FreePool (UsbBot);
+ return Status;
+}
+
+/**
+ Send the command to the device using Bulk-Out endpoint.
+
+ This function sends the command to the device using Bulk-Out endpoint.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Command phase.
+
+ @param 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
+ @param Lun The number of logic unit
+
+ @retval EFI_SUCCESS The command is sent to the device.
+ @retval EFI_NOT_READY The device return NAK to the transfer
+ @retval Others Failed to send the command to device
+
+**/
+EFI_STATUS
+UsbBotSendCommand (
+ IN USB_BOT_PROTOCOL *UsbBot,
+ IN UINT8 *Cmd,
+ IN UINT8 CmdLen,
+ IN EFI_USB_DATA_DIRECTION DataDir,
+ IN UINT32 TransLen,
+ IN UINT8 Lun
+ )
+{
+ USB_BOT_CBW Cbw;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINTN DataLen;
+ UINTN Timeout;
+
+ ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN));
+
+ //
+ // Fill in the Command Block Wrapper.
+ //
+ Cbw.Signature = USB_BOT_CBW_SIGNATURE;
+ Cbw.Tag = UsbBot->CbwTag;
+ Cbw.DataLen = TransLen;
+ Cbw.Flag = (UINT8) ((DataDir == EfiUsbDataIn) ? BIT7 : 0);
+ Cbw.Lun = Lun;
+ 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_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ //
+ // Use USB I/O Protocol to send the Command Block Wrapper to the device.
+ //
+ Status = UsbBot->UsbIo->UsbBulkTransfer (
+ UsbBot->UsbIo,
+ UsbBot->BulkOutEndpoint->EndpointAddress,
+ &Cbw,
+ &DataLen,
+ Timeout,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) {
+ //
+ // Respond to Bulk-Out endpoint stall with a Reset Recovery,
+ // according to section 5.3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
+ //
+ 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.
+
+ This function transfers the data between the device and host.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Data phase.
+
+ @param 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 EFI_SUCCESS No data to transfer
+ @retval EFI_NOT_READY The device return NAK to the transfer
+ @retval Others Failed to transfer data
+
+**/
+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;
+
+ //
+ // If no data to transfer, just return EFI_SUCCESS.
+ //
+ 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_1_MILLISECOND;
+
+ Status = UsbBot->UsbIo->UsbBulkTransfer (
+ UsbBot->UsbIo,
+ Endpoint->EndpointAddress,
+ Data,
+ TransLen,
+ Timeout,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
+ DEBUG ((EFI_D_INFO, "UsbBotDataTransfer: (%r)\n", Status));
+ DEBUG ((EFI_D_INFO, "UsbBotDataTransfer: DataIn Stall\n"));
+ UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress);
+ } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
+ Status = EFI_NOT_READY;
+ } else {
+ DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: (%r)\n", Status));
+ }
+ if(Status == EFI_TIMEOUT){
+ UsbBotResetDevice(UsbBot, FALSE);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the command execution status from device.
+
+ This function gets the command execution status from device.
+ BOT transfer is composed of three phases: Command, Data, and Status.
+ This is the Status phase.
+
+ This function returns the transfer status of the BOT's CSW status,
+ and returns the high level command execution result in Result. So
+ even if EFI_SUCCESS is returned, the command may still have failed.
+
+ @param UsbBot The USB BOT device.
+ @param TransLen The expected length of the data.
+ @param CmdStatus The result of the command execution.
+
+ @retval EFI_SUCCESS Command execute result is retrieved and in the Result.
+ @retval Other Error occurred when trying to get status.
+
+**/
+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_RECV_CSW_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ for (Index = 0; Index < USB_BOT_RECV_CSW_RETRY; Index++) {
+ //
+ // Attempt to the read Command Status Wrapper 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)) {
+ if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
+ UsbClearEndpointStall (UsbIo, Endpoint);
+ }
+ continue;
+ }
+
+ if (Csw.Signature != USB_BOT_CSW_SIGNATURE) {
+ //
+ // CSW is invalid, so perform reset recovery
+ //
+ Status = UsbBotResetDevice (UsbBot, FALSE);
+ } else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) {
+ //
+ // Respond phase error also needs reset recovery
+ //
+ Status = UsbBotResetDevice (UsbBot, FALSE);
+ } else {
+ *CmdStatus = Csw.CmdStatus;
+ break;
+ }
+ }
+ //
+ //The tag is increased even if there is an error.
+ //
+ UsbBot->CbwTag++;
+
+ return Status;
+}
+
+
+/**
+ Call the USB Mass Storage Class BOT 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 Lun The number of logic unit
+ @param Timeout The time to wait command
+ @param CmdStatus The result of high level command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute command
+
+**/
+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 UINT8 Lun,
+ 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, Lun);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "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 fails.
+ //
+ 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 ((EFI_D_ERROR, "UsbBotExecCommand: UsbBotGetStatus (%r)\n", Status));
+ return Status;
+ }
+
+ if (Result == 0) {
+ *CmdStatus = USB_MASS_CMD_SUCCESS;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the USB mass storage device by BOT protocol.
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL.
+ @param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request.
+ If TRUE, additionally reset parent hub port.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device..
+
+**/
+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 EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Issue a class specific Bulk-Only Mass Storage Reset request,
+ // according to section 3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
+ //
+ Request.RequestType = 0x21;
+ Request.Request = USB_BOT_RESET_REQUEST;
+ Request.Value = 0;
+ Request.Index = UsbBot->Interface.InterfaceNumber;
+ Request.Length = 0;
+ Timeout = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ Status = UsbBot->UsbIo->UsbControlTransfer (
+ UsbBot->UsbIo,
+ &Request,
+ EfiUsbNoData,
+ Timeout,
+ NULL,
+ 0,
+ &Result
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // 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 for the device.
+ //
+ gBS->Stall (USB_BOT_RESET_DEVICE_STALL);
+
+ //
+ // Clear the Bulk-In and Bulk-Out stall condition.
+ //
+ UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress);
+ UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress);
+
+ return Status;
+}
+
+
+/**
+ Get the max LUN (Logical Unit Number) of USB mass storage device.
+
+ @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL
+ @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
+ LUN1 in all.)
+
+ @retval EFI_SUCCESS Max LUN is got successfully.
+ @retval Others Fail to execute this request.
+
+**/
+EFI_STATUS
+UsbBotGetMaxLun (
+ IN VOID *Context,
+ OUT UINT8 *MaxLun
+ )
+{
+ USB_BOT_PROTOCOL *UsbBot;
+ EFI_USB_DEVICE_REQUEST Request;
+ EFI_STATUS Status;
+ UINT32 Result;
+ UINT32 Timeout;
+
+ if (Context == NULL || MaxLun == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UsbBot = (USB_BOT_PROTOCOL *) Context;
+
+ //
+ // Issue a class specific Bulk-Only Mass Storage get max lun request.
+ // according to section 3.2 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
+ //
+ Request.RequestType = 0xA1;
+ Request.Request = USB_BOT_GETLUN_REQUEST;
+ Request.Value = 0;
+ Request.Index = UsbBot->Interface.InterfaceNumber;
+ Request.Length = 1;
+ Timeout = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ Status = UsbBot->UsbIo->UsbControlTransfer (
+ UsbBot->UsbIo,
+ &Request,
+ EfiUsbDataIn,
+ Timeout,
+ (VOID *) MaxLun,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status) || *MaxLun > USB_BOT_MAX_LUN) {
+ //
+ // If the Get LUN request returns an error or the MaxLun is larger than
+ // the maximum LUN value (0x0f) supported by the USB Mass Storage Class
+ // Bulk-Only Transport Spec, then set MaxLun to 0.
+ //
+ // This improves compatibility with USB FLASH drives that have a single LUN
+ // and either do not return a max LUN value or return an invalid maximum LUN
+ // value.
+ //
+ *MaxLun = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+**/
+EFI_STATUS
+UsbBotCleanUp (
+ IN VOID *Context
+ )
+{
+ FreePool (Context);
+ return EFI_SUCCESS;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h new file mode 100644 index 000000000..3ef8f240a --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h @@ -0,0 +1,187 @@ +/** @file
+ Definition for the USB mass storage Bulk-Only Transport protocol,
+ based on the "Universal Serial Bus Mass Storage Class Bulk-Only
+ Transport" Revision 1.0, September 31, 1999.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_BOT_H_
+#define _EFI_USBMASS_BOT_H_
+
+extern USB_MASS_TRANSPORT mUsbBotTransport;
+
+//
+// Usb Bulk-Only class specific request
+//
+#define USB_BOT_RESET_REQUEST 0xFF ///< Bulk-Only Mass Storage Reset
+#define USB_BOT_GETLUN_REQUEST 0xFE ///< Get Max Lun
+#define USB_BOT_CBW_SIGNATURE 0x43425355 ///< dCBWSignature, tag the packet as CBW
+#define USB_BOT_CSW_SIGNATURE 0x53425355 ///< dCSWSignature, tag the packet as CSW
+#define USB_BOT_MAX_LUN 0x0F ///< Lun number is from 0 to 15
+#define USB_BOT_MAX_CMDLEN 16 ///< Maximum number of command from command set
+
+//
+// Usb BOT command block status values
+//
+#define USB_BOT_COMMAND_OK 0x00 ///< Command passed, good status
+#define USB_BOT_COMMAND_FAILED 0x01 ///< Command failed
+#define USB_BOT_COMMAND_ERROR 0x02 ///< Phase error, need to reset the device
+
+//
+// Usb Bot retry to get CSW, refers to specification[BOT10-5.3, it says 2 times]
+//
+#define USB_BOT_RECV_CSW_RETRY 3
+
+//
+// Usb Bot wait device reset complete, set by experience
+//
+#define USB_BOT_RESET_DEVICE_STALL (100 * USB_MASS_1_MILLISECOND)
+
+//
+// Usb Bot transport timeout, set by experience
+//
+#define USB_BOT_SEND_CBW_TIMEOUT (3 * USB_MASS_1_SECOND)
+#define USB_BOT_RECV_CSW_TIMEOUT (3 * USB_MASS_1_SECOND)
+#define USB_BOT_RESET_DEVICE_TIMEOUT (3 * USB_MASS_1_SECOND)
+
+#pragma pack(1)
+///
+/// The CBW (Command Block Wrapper) structures used by the USB BOT protocol.
+///
+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;
+
+///
+/// The and CSW (Command Status Wrapper) structures used by the USB BOT protocol.
+///
+typedef struct {
+ UINT32 Signature;
+ UINT32 Tag;
+ UINT32 DataResidue;
+ UINT8 CmdStatus;
+} USB_BOT_CSW;
+#pragma pack()
+
+typedef struct {
+ //
+ // Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance
+ //
+ 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;
+
+/**
+ Initializes USB BOT protocol.
+
+ This function initializes the USB mass storage class BOT 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 I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB BOT initialization fails.
+
+**/
+EFI_STATUS
+UsbBotInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT VOID **Context OPTIONAL
+ );
+
+/**
+ Call the USB Mass Storage Class BOT 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 Lun The number of logic unit
+ @param Timeout The time to wait command
+ @param CmdStatus The result of high level command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute command
+
+**/
+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 UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ );
+
+/**
+ Reset the USB mass storage device by BOT protocol.
+
+ @param Context The context of the BOT protocol, that is,
+ USB_BOT_PROTOCOL.
+ @param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request.
+ If TRUE, additionally reset parent hub port.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device..
+
+**/
+EFI_STATUS
+UsbBotResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Get the max LUN (Logical Unit Number) of USB mass storage device.
+
+ @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL
+ @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
+ LUN1 in all.)
+
+ @retval EFI_SUCCESS Max LUN is got successfully.
+ @retval Others Fail to execute this request.
+
+**/
+EFI_STATUS
+UsbBotGetMaxLun (
+ IN VOID *Context,
+ OUT UINT8 *MaxLun
+ );
+
+/**
+ 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.
+
+**/
+EFI_STATUS
+UsbBotCleanUp (
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c new file mode 100644 index 000000000..477f0536d --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c @@ -0,0 +1,606 @@ +/** @file
+ Implementation of the USB mass storage Control/Bulk/Interrupt transport,
+ according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.
+ Notice: it is being obsoleted by the standard body in favor of the BOT
+ (Bulk-Only Transport).
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+//
+// Definition of USB CBI0 Transport Protocol
+//
+USB_MASS_TRANSPORT mUsbCbi0Transport = {
+ USB_MASS_STORE_CBI0,
+ UsbCbiInit,
+ UsbCbiExecCommand,
+ UsbCbiResetDevice,
+ NULL,
+ UsbCbiCleanUp
+};
+
+//
+// Definition of USB CBI1 Transport Protocol
+//
+USB_MASS_TRANSPORT mUsbCbi1Transport = {
+ USB_MASS_STORE_CBI1,
+ UsbCbiInit,
+ UsbCbiExecCommand,
+ UsbCbiResetDevice,
+ NULL,
+ UsbCbiCleanUp
+};
+
+/**
+ Initializes USB CBI protocol.
+
+ This function initializes the USB mass storage class CBI protocol.
+ It will save its context which is a USB_CBI_PROTOCOL structure
+ in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB CBI initialization fails.
+
+**/
+EFI_STATUS
+UsbCbiInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ 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 for USB_CBI_PROTOCOL and 3 endpoint descriptors.
+ //
+ UsbCbi = AllocateZeroPool (
+ sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
+ );
+ ASSERT (UsbCbi != NULL);
+
+ UsbCbi->UsbIo = UsbIo;
+
+ //
+ // Get the interface descriptor and validate that it
+ // is a USB Mass Storage 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);
+ CopyMem(UsbCbi->BulkInEndpoint, &EndPoint, sizeof (EndPoint));;
+ }
+
+ if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
+ (UsbCbi->BulkOutEndpoint == NULL)) {
+
+ UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1;
+ CopyMem(UsbCbi->BulkOutEndpoint, &EndPoint, sizeof (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;
+ CopyMem(UsbCbi->InterruptEndpoint, &EndPoint, sizeof (EndPoint));
+ }
+ }
+ }
+
+ if ((UsbCbi->BulkInEndpoint == NULL) || (UsbCbi->BulkOutEndpoint == NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+ if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) && (UsbCbi->InterruptEndpoint == NULL)) {
+ Status = EFI_UNSUPPORTED;
+ goto ON_ERROR;
+ }
+
+ if (Context != NULL) {
+ *Context = UsbCbi;
+ } else {
+ FreePool (UsbCbi);
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ FreePool (UsbCbi);
+ return Status;
+}
+
+/**
+ Send the command to the device using class specific control transfer.
+
+ This function sends command to the device using class specific control transfer.
+ The CBI contains three phases: Command, Data, and Status. This is Command phase.
+
+ @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 sent to the device.
+ @retval Others The command failed to transfer to device
+
+**/
+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_1_MILLISECOND;
+
+ for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
+ //
+ // Use USB I/O Protocol 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.
+
+ This function transfers data between the device and host.
+ The CBI contains three phases: 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 for input or output.
+ @param TransLen On input, the expected transfer length.
+ On output, the length of data actually transferred.
+ @param Timeout The time to wait for the command to execute
+
+ @retval EFI_SUCCESS The data transferred successfully.
+ @retval EFI_SUCCESS No data to transfer
+ @retval Others Failed to transfer all the data
+
+**/
+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;
+
+ //
+ // If no data to transfer, just return EFI_SUCCESS.
+ //
+ 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_1_MILLISECOND;
+
+ //
+ // Transfer the data with a loop. The length of data transferred once is restricted.
+ //
+ 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
+ // available or the command is in-progress.
+ // If data are partially transferred, we just ignore NAK and continue.
+ // If all data have been transferred and status is NAK, then we retry for several times.
+ // If retry exceeds the USB_CBI_MAX_RETRY, then return error status.
+ //
+ 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;
+}
+
+
+/**
+ Gets 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.
+ The CBI contains three phases: Command, Data, and Status. This is Status phase.
+
+ @param UsbCbi The USB CBI protocol
+ @param Timeout The time to wait for the command to execute
+ @param Result The result of the command execution.
+
+ @retval EFI_SUCCESS The high level command execution result is
+ retrieved in Result.
+ @retval Others Failed to retrieve the result.
+
+**/
+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_1_MILLISECOND;
+
+ //
+ // Attempt 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 Protocol.
+ @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 Lun Should be 0, this field for bot only
+ @param Timeout The time to wait
+ @param CmdStatus The result of the command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute the command
+
+**/
+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 UINT8 Lun,
+ 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)) {
+ gBS->Stall(10 * USB_MASS_1_MILLISECOND);
+ DEBUG ((EFI_D_ERROR, "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 ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiDataTransfer (%r)\n",Status));
+ return Status;
+ }
+
+ //
+ // Get the status. If it succeeds, interpret the result.
+ //
+ Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status));
+ return Status;
+ }
+
+ if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) {
+ //
+ // For UFI device, ASC and ASCQ are returned.
+ //
+ // Do not set the USB_MASS_CMD_FAIL for a request sense command
+ // as a bad result type doesn't mean a cmd failure
+ //
+ if (Result.Type != 0 && *(UINT8*)Cmd != 0x03) {
+ *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.
+ // No break here to 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;
+}
+
+
+/**
+ Reset the USB mass storage device by CBI protocol.
+
+ This function resets the USB mass storage device by CBI protocol.
+ 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 protocol
+ @param ExtendedVerification The flag controlling the rule of reset.
+ Not used here.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device.
+
+**/
+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_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;
+
+ //
+ // 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 EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Just retrieve the status and ignore that. Then stall
+ // 50ms to wait for it to complete.
+ //
+ UsbCbiGetStatus (UsbCbi, Timeout, &Result);
+ gBS->Stall (USB_CBI_RESET_DEVICE_STALL);
+
+ //
+ // 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 instance of CBI protocol.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+EFI_STATUS
+UsbCbiCleanUp (
+ IN VOID *Context
+ )
+{
+ FreePool (Context);
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h new file mode 100644 index 000000000..b79b9c243 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h @@ -0,0 +1,134 @@ +/** @file
+ Definition for the USB mass storage Control/Bulk/Interrupt (CBI) transport,
+ according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_CBI_H_
+#define _EFI_USBMASS_CBI_H_
+
+extern USB_MASS_TRANSPORT mUsbCbi0Transport;
+extern USB_MASS_TRANSPORT mUsbCbi1Transport;
+
+#define USB_CBI_MAX_PACKET_NUM 16
+#define USB_CBI_RESET_CMD_LEN 12
+//
+// USB CBI retry C/B/I transport times, set by experience
+//
+#define USB_CBI_MAX_RETRY 3
+//
+// Time to wait for USB CBI reset to complete, set by experience
+//
+#define USB_CBI_RESET_DEVICE_STALL (50 * USB_MASS_1_MILLISECOND)
+//
+// USB CBI transport timeout, set by experience
+//
+#define USB_CBI_RESET_DEVICE_TIMEOUT (1 * USB_MASS_1_SECOND)
+
+typedef struct {
+ //
+ // Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance
+ //
+ 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()
+
+/**
+ Initializes USB CBI protocol.
+
+ This function initializes the USB mass storage class CBI protocol.
+ It will save its context which is a USB_CBI_PROTOCOL structure
+ in the Context if Context isn't NULL.
+
+ @param UsbIo The USB I/O Protocol instance
+ @param Context The buffer to save the context to
+
+ @retval EFI_SUCCESS The device is successfully initialized.
+ @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
+ @retval Other The USB CBI initialization fails.
+
+**/
+EFI_STATUS
+UsbCbiInit (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ OUT VOID **Context OPTIONAL
+ );
+
+/**
+ Execute USB mass storage command through the CBI0/CBI1 transport protocol.
+
+ @param Context The USB CBI Protocol.
+ @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 Lun Should be 0, this field for bot only
+ @param Timeout The time to wait
+ @param CmdStatus The result of the command execution
+
+ @retval EFI_SUCCESS The command is executed successfully.
+ @retval Other Failed to execute the command
+
+**/
+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 UINT8 Lun,
+ IN UINT32 Timeout,
+ OUT UINT32 *CmdStatus
+ );
+
+/**
+ Reset the USB mass storage device by CBI protocol.
+
+ This function resets the USB mass storage device by CBI protocol.
+ 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 protocol
+ @param ExtendedVerification The flag controlling the rule of reset.
+ Not used here.
+
+ @retval EFI_SUCCESS The device is reset.
+ @retval Others Failed to reset the device.
+
+**/
+EFI_STATUS
+UsbCbiResetDevice (
+ IN VOID *Context,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Clean up the CBI protocol's resource.
+
+ @param Context The instance of CBI protocol.
+
+ @retval EFI_SUCCESS The resource is cleaned up.
+
+**/
+EFI_STATUS
+UsbCbiCleanUp (
+ IN VOID *Context
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.c new file mode 100644 index 000000000..44e1d0c01 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.c @@ -0,0 +1,156 @@ +/** @file
+ This file is used to implement the EFI_DISK_INFO_PROTOCOL interface.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+EFI_DISK_INFO_PROTOCOL gUsbDiskInfoProtocolTemplate = {
+ EFI_DISK_INFO_USB_INTERFACE_GUID,
+ UsbDiskInfoInquiry,
+ UsbDiskInfoIdentify,
+ UsbDiskInfoSenseData,
+ UsbDiskInfoWhichIde
+};
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with USB interface GUID.
+
+ @param[in] UsbMass The pointer of USB_MASS_DEVICE.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN USB_MASS_DEVICE *UsbMass
+ )
+{
+ CopyMem (&UsbMass->DiskInfo, &gUsbDiskInfoProtocolTemplate, sizeof (gUsbDiskInfoProtocolTemplate));
+}
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ EFI_STATUS Status;
+ USB_MASS_DEVICE *UsbMass;
+
+ UsbMass = USB_MASS_DEVICE_FROM_DISK_INFO (This);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*InquiryDataSize >= sizeof (UsbMass->InquiryData)) {
+ Status = EFI_SUCCESS;
+ CopyMem (InquiryData, &UsbMass->InquiryData, sizeof (UsbMass->InquiryData));
+ }
+ *InquiryDataSize = sizeof (UsbMass->InquiryData);
+ return Status;
+}
+
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] IdentifyDataSize Pointer to the value for the identify data
+ size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function is used to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
+ @retval EFI_UNSUPPORTED This is not an IDE device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.h new file mode 100644 index 000000000..2571cc541 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassDiskInfo.h @@ -0,0 +1,123 @@ +/** @file
+ Header file for EFI_DISK_INFO_PROTOCOL interface.
+
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_DISKINFO_H_
+#define _EFI_USBMASS_DISKINFO_H_
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with USB interface GUID.
+
+ @param UsbMass The pointer of USB_MASS_DEVICE.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN USB_MASS_DEVICE *UsbMass
+ );
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] IdentifyDataSize Pointer to the value for the identify data
+ size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+
+/**
+ This function is used to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
+ @retval EFI_UNSUPPORTED This is not an IDE device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c new file mode 100644 index 000000000..bbd19e044 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c @@ -0,0 +1,1108 @@ +/** @file
+ USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbMass.h"
+
+#define USB_MASS_TRANSPORT_COUNT 3
+//
+// Array of USB transport interfaces.
+//
+USB_MASS_TRANSPORT *mUsbMassTransport[USB_MASS_TRANSPORT_COUNT] = {
+ &mUsbCbi0Transport,
+ &mUsbCbi1Transport,
+ &mUsbBotTransport,
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
+ USBMassDriverBindingSupported,
+ USBMassDriverBindingStart,
+ USBMassDriverBindingStop,
+ 0x11,
+ NULL,
+ NULL
+};
+
+/**
+ Reset the block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+ It resets the block device hardware.
+ ExtendedVerification is ignored in this implementation.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The block device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // Raise TPL to TPL_CALLBACK to serialize all its operations
+ // to protect shared data structures.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
+ Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Reads the requested number of blocks from the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+ It reads the requested number of blocks from the device.
+ All the blocks are read, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+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;
+ EFI_TPL OldTpl;
+ UINTN TotalBlock;
+
+ //
+ // Raise TPL to TPL_CALLBACK to serialize all its operations
+ // to protect shared data structures.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // If it is a removable media, such as CD-Rom or Usb-Floppy,
+ // need to detect the media before each read/write. While some of
+ // Usb-Flash is marked as removable media.
+ //
+ if (Media->RemovableMedia) {
+ Status = UsbBootDetectMedia (UsbMass);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto ON_EXIT;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto ON_EXIT;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // BufferSize must be a multiple of the intrinsic block size of the device.
+ //
+ if ((BufferSize % Media->BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto ON_EXIT;
+ }
+
+ TotalBlock = BufferSize / Media->BlockSize;
+
+ //
+ // Make sure the range to read is valid.
+ //
+ if (Lba + TotalBlock - 1 > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ if (UsbMass->Cdb16Byte) {
+ Status = UsbBootReadWriteBlocks16 (UsbMass, FALSE, Lba, TotalBlock, Buffer);
+ } else {
+ Status = UsbBootReadWriteBlocks (UsbMass, FALSE, (UINT32) Lba, TotalBlock, Buffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
+ UsbMassReset (This, TRUE);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Writes a specified number of blocks to the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+ It writes a specified number of blocks to the device.
+ All blocks are written, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer Pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data were written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
+ block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+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;
+ EFI_TPL OldTpl;
+ UINTN TotalBlock;
+
+ //
+ // Raise TPL to TPL_CALLBACK to serialize all its operations
+ // to protect shared data structures.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // If it is a removable media, such as CD-Rom or Usb-Floppy,
+ // need to detect the media before each read/write. Some of
+ // USB Flash is marked as removable media.
+ //
+ if (Media->RemovableMedia) {
+ Status = UsbBootDetectMedia (UsbMass);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ if (!(Media->MediaPresent)) {
+ Status = EFI_NO_MEDIA;
+ goto ON_EXIT;
+ }
+
+ if (MediaId != Media->MediaId) {
+ Status = EFI_MEDIA_CHANGED;
+ goto ON_EXIT;
+ }
+
+ if (BufferSize == 0) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ if (Buffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // BufferSize must be a multiple of the intrinsic block size of the device.
+ //
+ if ((BufferSize % Media->BlockSize) != 0) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto ON_EXIT;
+ }
+
+ TotalBlock = BufferSize / Media->BlockSize;
+
+ //
+ // Make sure the range to write is valid.
+ //
+ if (Lba + TotalBlock - 1 > Media->LastBlock) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ //
+ // Try to write the data even the device is marked as ReadOnly,
+ // and clear the status should the write succeed.
+ //
+ if (UsbMass->Cdb16Byte) {
+ Status = UsbBootReadWriteBlocks16 (UsbMass, TRUE, Lba, TotalBlock, Buffer);
+ } else {
+ Status = UsbBootReadWriteBlocks (UsbMass, TRUE, (UINT32) Lba, TotalBlock, Buffer);
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
+ UsbMassReset (This, TRUE);
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Flushes all modified data to a physical block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
+ USB mass storage device doesn't support write cache,
+ so return EFI_SUCCESS directly.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
+
+ @param UsbMass The USB mass storage device
+
+ @retval EFI_SUCCESS The media parameters are 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;
+
+ Media = &UsbMass->BlockIoMedia;
+
+ //
+ // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,
+ // section for Block I/O Protocol.
+ //
+ Media->MediaPresent = FALSE;
+ Media->LogicalPartition = FALSE;
+ Media->ReadOnly = FALSE;
+ Media->WriteCaching = FALSE;
+ Media->IoAlign = 0;
+ Media->MediaId = 1;
+
+ Status = UsbBootGetParams (UsbMass);
+ DEBUG ((DEBUG_INFO, "UsbMassInitMedia: UsbBootGetParams (%r)\n", Status));
+ if (Status == EFI_MEDIA_CHANGED) {
+ //
+ // Some USB storage devices may report MEDIA_CHANGED sense key when hot-plugged.
+ // Treat it as SUCCESS
+ //
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Initialize the USB Mass Storage transport.
+
+ This function tries to find the matching USB Mass Storage transport
+ protocol for USB device. If found, initializes the matching transport.
+
+ @param This The USB mass driver's driver binding.
+ @param Controller The device to test.
+ @param Transport The pointer to pointer to USB_MASS_TRANSPORT.
+ @param Context The parameter for USB_MASS_DEVICE.Context.
+ @param MaxLun Get the MaxLun if is BOT dev.
+
+ @retval EFI_SUCCESS The initialization is successful.
+ @retval EFI_UNSUPPORTED No matching transport protocol is found.
+ @retval Others Failed to initialize dev.
+
+**/
+EFI_STATUS
+UsbMassInitTransport (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ OUT USB_MASS_TRANSPORT **Transport,
+ OUT VOID **Context,
+ OUT UINT8 *MaxLun
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_INTERFACE_DESCRIPTOR Interface;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Traverse the USB_MASS_TRANSPORT arrary and try to find the
+ // matching transport protocol.
+ // If not found, return EFI_UNSUPPORTED.
+ // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
+ //
+ for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
+ *Transport = mUsbMassTransport[Index];
+
+ if (Interface.InterfaceProtocol == (*Transport)->Protocol) {
+ Status = (*Transport)->Init (UsbIo, Context);
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // For BOT device, try to get its max LUN.
+ // If max LUN is 0, then it is a non-lun device.
+ // Otherwise, it is a multi-lun device.
+ //
+ if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
+ (*Transport)->GetMaxLun (*Context, MaxLun);
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+}
+
+/**
+ Initialize data for device that supports multiple LUNSs.
+
+ @param This The Driver Binding Protocol instance.
+ @param Controller The device to initialize.
+ @param Transport Pointer to USB_MASS_TRANSPORT.
+ @param Context Parameter for USB_MASS_DEVICE.Context.
+ @param DevicePath The remaining device path.
+ @param MaxLun The max LUN number.
+
+ @retval EFI_SUCCESS At least one LUN is initialized successfully.
+ @retval EFI_NOT_FOUND Fail to initialize any of multiple LUNs.
+
+**/
+EFI_STATUS
+UsbMassInitMultiLun (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN USB_MASS_TRANSPORT *Transport,
+ IN VOID *Context,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT8 MaxLun
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ DEVICE_LOGICAL_UNIT_DEVICE_PATH LunNode;
+ UINT8 Index;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ ASSERT (MaxLun > 0);
+ ReturnStatus = EFI_NOT_FOUND;
+
+ for (Index = 0; Index <= MaxLun; Index++) {
+
+ DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Start to initialize No.%d logic unit\n", Index));
+
+ UsbIo = NULL;
+ UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
+ ASSERT (UsbMass != NULL);
+
+ UsbMass->Signature = USB_MASS_SIGNATURE;
+ 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;
+ UsbMass->Transport = Transport;
+ UsbMass->Context = Context;
+ UsbMass->Lun = Index;
+
+ //
+ // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
+ //
+ Status = UsbMassInitMedia (UsbMass);
+ if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: UsbMassInitMedia (%r)\n", Status));
+ FreePool (UsbMass);
+ continue;
+ }
+
+ //
+ // Create a device path node for device logic unit, and append it.
+ //
+ LunNode.Header.Type = MESSAGING_DEVICE_PATH;
+ LunNode.Header.SubType = MSG_DEVICE_LOGICAL_UNIT_DP;
+ LunNode.Lun = UsbMass->Lun;
+
+ SetDevicePathNodeLength (&LunNode.Header, sizeof (LunNode));
+
+ UsbMass->DevicePath = AppendDevicePathNode (DevicePath, &LunNode.Header);
+
+ if (UsbMass->DevicePath == NULL) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: failed to create device logic unit device path\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ FreePool (UsbMass);
+ continue;
+ }
+
+ InitializeDiskInfo (UsbMass);
+
+ //
+ // Create a new handle for each LUN, and install Block I/O Protocol and Device Path Protocol.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &UsbMass->Controller,
+ &gEfiDevicePathProtocolGuid,
+ UsbMass->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: InstallMultipleProtocolInterfaces (%r)\n", Status));
+ FreePool (UsbMass->DevicePath);
+ FreePool (UsbMass);
+ continue;
+ }
+
+ //
+ // Open USB I/O Protocol by child to setup a parent-child relationship.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ UsbMass->Controller,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitMultiLun: OpenUsbIoProtocol By Child (%r)\n", Status));
+ gBS->UninstallMultipleProtocolInterfaces (
+ UsbMass->Controller,
+ &gEfiDevicePathProtocolGuid,
+ UsbMass->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+ FreePool (UsbMass->DevicePath);
+ FreePool (UsbMass);
+ continue;
+ }
+ ReturnStatus = EFI_SUCCESS;
+ DEBUG ((EFI_D_INFO, "UsbMassInitMultiLun: Success to initialize No.%d logic unit\n", Index));
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Initialize data for device that does not support multiple LUNSs.
+
+ @param This The Driver Binding Protocol instance.
+ @param Controller The device to initialize.
+ @param Transport Pointer to USB_MASS_TRANSPORT.
+ @param Context Parameter for USB_MASS_DEVICE.Context.
+
+ @retval EFI_SUCCESS Initialization succeeds.
+ @retval Other Initialization fails.
+
+**/
+EFI_STATUS
+UsbMassInitNonLun (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN USB_MASS_TRANSPORT *Transport,
+ IN VOID *Context
+ )
+{
+ USB_MASS_DEVICE *UsbMass;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_STATUS Status;
+
+ UsbIo = NULL;
+ UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
+ ASSERT (UsbMass != NULL);
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: OpenUsbIoProtocol By Driver (%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;
+ UsbMass->Transport = Transport;
+ UsbMass->Context = Context;
+
+ //
+ // Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
+ //
+ Status = UsbMassInitMedia (UsbMass);
+ if ((EFI_ERROR (Status)) && (Status != EFI_NO_MEDIA)) {
+ DEBUG ((EFI_D_ERROR, "UsbMassInitNonLun: UsbMassInitMedia (%r)\n", Status));
+ goto ON_ERROR;
+ }
+
+ InitializeDiskInfo (UsbMass);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+ if (UsbMass != NULL) {
+ FreePool (UsbMass);
+ }
+ if (UsbIo != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ return Status;
+}
+
+
+/**
+ Check whether the controller is a supported USB mass storage.
+
+ @param This The USB mass storage driver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+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;
+ UINTN Index;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the interface descriptor 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;
+ }
+
+ //
+ // Traverse the USB_MASS_TRANSPORT arrary and try to find the
+ // matching transport method.
+ // If not found, return EFI_UNSUPPORTED.
+ // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
+ //
+ for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) {
+ Transport = mUsbMassTransport[Index];
+ if (Interface.InterfaceProtocol == Transport->Protocol) {
+ Status = Transport->Init (UsbIo, NULL);
+ break;
+ }
+ }
+
+ON_EXIT:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the USB mass storage device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mass storage device,
+ installs Block I/O Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mass storage device.
+
+ @param This The USB mass storage driver binding protocol.
+ @param Controller The USB mass storage device to start on
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ USB_MASS_TRANSPORT *Transport;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ VOID *Context;
+ UINT8 MaxLun;
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Transport = NULL;
+ Context = NULL;
+ MaxLun = 0;
+
+ Status = UsbMassInitTransport (This, Controller, &Transport, &Context, &MaxLun);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitTransport (%r)\n", Status));
+ goto Exit;
+ }
+ if (MaxLun == 0) {
+ //
+ // Initialize data for device that does not support multiple LUNSs.
+ //
+ Status = UsbMassInitNonLun (This, Controller, Transport, Context);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitNonLun (%r)\n", Status));
+ }
+ } else {
+ //
+ // Open device path to prepare for appending Device Logic Unit node.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenDevicePathProtocol By Driver (%r)\n", Status));
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: OpenUsbIoProtocol By Driver (%r)\n", Status));
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ goto Exit;
+ }
+
+ //
+ // Initialize data for device that supports multiple LUNs.
+ // EFI_SUCCESS is returned if at least 1 LUN is initialized successfully.
+ //
+ Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ DEBUG ((EFI_D_ERROR, "USBMassDriverBindingStart: UsbMassInitMultiLun (%r) with Maxlun=%d\n", Status, MaxLun));
+ }
+ }
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ 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 EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller.
+ @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_USB_IO_PROTOCOL *UsbIo;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+
+ //
+ // This is a bus driver stop function since multi-lun is supported.
+ // There are three kinds of device handles that might be passed:
+ // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun)
+ // 2nd is a handle with Device Path & USB I/O installed (multi-lun root)
+ // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun).
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // A handle without any children, might be 1st and 2nd type.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR(Status)) {
+ //
+ // This is a 2nd type handle(multi-lun root), it needs to close devicepath
+ // and usbio protocol.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This is a 1st type handle(non-multi-lun), which only needs to uninstall
+ // Block I/O Protocol, close USB I/O Protocol and free mass device.
+ //
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
+
+ //
+ // Uninstall Block I/O protocol from the device handle,
+ // then call the transport protocol to stop itself.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ UsbMass->Transport->CleanUp (UsbMass->Context);
+ FreePool (UsbMass);
+
+ DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This is a 3rd type handle(multi-lun), which needs uninstall
+ // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and
+ // free mass device for all children.
+ //
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index));
+ continue;
+ }
+
+ UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ UsbMass->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &UsbMass->BlockIo,
+ &gEfiDiskInfoProtocolGuid,
+ &UsbMass->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child.
+ //
+ AllChildrenStopped = FALSE;
+ DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index));
+
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ //
+ // Succeed to stop this multi-lun handle, so go on with next child.
+ //
+ if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
+ UsbMass->Transport->CleanUp (UsbMass->Context);
+ }
+ FreePool (UsbMass);
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren));
+ return EFI_SUCCESS;
+}
+
+/**
+ Entrypoint of USB Mass Storage Driver.
+
+ This function is the entrypoint of USB Mass Storage Driver. It installs Driver Binding
+ Protocol together with Component Name Protocols.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassStorageEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver binding protocol
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUSBMassDriverBinding,
+ ImageHandle,
+ &gUsbMassStorageComponentName,
+ &gUsbMassStorageComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h new file mode 100644 index 000000000..283bed705 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h @@ -0,0 +1,327 @@ +/** @file
+ Definitions of functions for Driver Binding Protocol and Block I/O Protocol,
+ and other internal definitions.
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USBMASS_IMPL_H_
+#define _EFI_USBMASS_IMPL_H_
+
+#define USB_MASS_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'M')
+
+#define USB_MASS_DEVICE_FROM_BLOCK_IO(a) \
+ CR (a, USB_MASS_DEVICE, BlockIo, USB_MASS_SIGNATURE)
+
+#define USB_MASS_DEVICE_FROM_DISK_INFO(a) \
+ CR (a, USB_MASS_DEVICE, DiskInfo, USB_MASS_SIGNATURE)
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMassStorageComponentName2;
+
+//
+// Functions for Driver Binding Protocol
+//
+
+/**
+ Check whether the controller is a supported USB mass storage.
+
+ @param This The USB mass storage driver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the USB mass storage device with this driver.
+
+ This function consumes USB I/O Protocol, initializes USB mass storage device,
+ installs Block I/O Protocol, and submits Asynchronous Interrupt
+ Transfer to manage the USB mass storage device.
+
+ @param This The USB mass storage driver binding protocol.
+ @param Controller The USB mass storage device to start on
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+ @retval EFI_ALREADY_STARTED This driver has been started.
+
+**/
+EFI_STATUS
+EFIAPI
+USBMassDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ 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 EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller.
+ @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
+ );
+
+//
+// Functions for Block I/O Protocol
+//
+
+/**
+ Reset the block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+ It resets the block device hardware.
+ ExtendedVerification is ignored in this implementation.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The block device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the requested number of blocks from the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+ It reads the requested number of blocks from the device.
+ All the blocks are read, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of blocks to the device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+ It writes a specified number of blocks to the device.
+ All blocks are written, or an error is returned.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written.
+ @param BufferSize The size of the Buffer in bytes.
+ This must be a multiple of the intrinsic block size of the device.
+ @param Buffer Pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data were written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
+ block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to a physical block device.
+
+ This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
+ USB mass storage device doesn't support write cache,
+ so return EFI_SUCCESS directly.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data were written correctly to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+//
+// EFI Component Name Functions
+//
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param 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.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbMassStorageGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param 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.
+ @param 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.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name 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. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param 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.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+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
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf new file mode 100644 index 000000000..54039389f --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf @@ -0,0 +1,81 @@ +## @file
+# USB Mass Storage Driver that manages USB mass storage devices and produces Block I/O Protocol.
+#
+# 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 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.
+# This module refers to following specifications:
+# 1. USB Mass Storage Specification for Bootability, Revision 1.0
+# 2. USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1
+# 3. USB Mass Storage Class Bulk-Only Transport, Revision 1.0.
+# 4. UEFI Specification, v2.1
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbMassStorageDxe
+ MODULE_UNI_FILE = UsbMassStorageDxe.uni
+ FILE_GUID = 9FB4B4A7-42C0-4bcd-8540-9BCC6711F83E
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = USBMassStorageEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUSBMassDriverBinding
+# COMPONENT_NAME = gUsbMassStorageComponentName
+# COMPONENT_NAME2 = gUsbMassStorageComponentName2
+#
+
+[Sources]
+ UsbMassBoot.h
+ UsbMassImpl.h
+ UsbMassBot.h
+ UsbMassBot.c
+ ComponentName.c
+ UsbMassImpl.c
+ UsbMassBoot.c
+ UsbMassCbi.h
+ UsbMass.h
+ UsbMassCbi.c
+ UsbMassDiskInfo.h
+ UsbMassDiskInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+
+
+[Protocols]
+ gEfiUsbIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiDiskInfoProtocolGuid ## BY_START
+
+# [Event]
+# EVENT_TYPE_RELATIVE_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbMassStorageDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.uni new file mode 100644 index 000000000..161395761 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.uni @@ -0,0 +1,31 @@ +// /** @file
+// USB Mass Storage Driver that manages USB mass storage devices and produces Block I/O Protocol.
+//
+// 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 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.
+// This module refers to following specifications:
+// 1. USB Mass Storage Specification for Bootability, Revision 1.0
+// 2. USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1
+// 3. USB Mass Storage Class Bulk-Only Transport, Revision 1.0.
+// 4. UEFI Specification, v2.1
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manages USB mass storage devices and produces Block I/O Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "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 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.<BR><BR>\n"
+ "This module refers to following specifications:<BR>\n"
+ "1. USB Mass Storage Specification for Bootability, Revision 1.0<BR>\n"
+ "2. USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1<BR>\n"
+ "3. USB Mass Storage Class Bulk-Only Transport, Revision 1.0.<BR>\n"
+ "4. UEFI Specification, v2.1<BR>"
+
diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxeExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxeExtra.uni new file mode 100644 index 000000000..d5751e6b1 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// UsbMassStorageDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Mass Storage DXE Driver"
+
+
|