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