Code scrub for USB Mass Storage Driver.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7243 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
xli24 2009-01-12 03:11:00 +00:00
parent cdfdbb970a
commit d80ed2a76e
9 changed files with 949 additions and 691 deletions

View File

@ -37,10 +37,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/MemoryAllocationLib.h> #include <Library/MemoryAllocationLib.h>
#include <Library/DevicePathLib.h> #include <Library/DevicePathLib.h>
#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0x80) #define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == BIT7)
#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0) #define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == 0)
#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x02) #define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK)
#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x03) #define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT)
#define USB_IS_ERROR(Result, Error) (((Result) & (Error)) != 0) #define USB_IS_ERROR(Result, Error) (((Result) & (Error)) != 0)
typedef enum { typedef enum {
@ -52,19 +52,19 @@ typedef enum {
// //
// Usb mass storage subclass code, specify the command set used. // Usb mass storage subclass code, specify the command set used.
// //
USB_MASS_STORE_RBC = 0x01, // Reduced Block Commands USB_MASS_STORE_RBC = 0x01, ///< Reduced Block Commands
USB_MASS_STORE_8020I = 0x02, // SFF-8020i, typically a CD/DVD device USB_MASS_STORE_8020I = 0x02, ///< SFF-8020i, typically a CD/DVD device
USB_MASS_STORE_QIC = 0x03, // Typically a tape device USB_MASS_STORE_QIC = 0x03, ///< Typically a tape device
USB_MASS_STORE_UFI = 0x04, // Typically a floppy disk driver device USB_MASS_STORE_UFI = 0x04, ///< Typically a floppy disk driver device
USB_MASS_STORE_8070I = 0x05, // SFF-8070i, typically a floppy 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_STORE_SCSI = 0x06, ///< SCSI transparent command set
// //
// Usb mass storage protocol code, specify the transport protocol // Usb mass storage protocol code, specify the transport protocol
// //
USB_MASS_STORE_CBI0 = 0x00, // CBI protocol with command completion interrupt 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_CBI1 = 0x01, ///< CBI protocol without command completion interrupt
USB_MASS_STORE_BOT = 0x50, // Bulk-Only Transport USB_MASS_STORE_BOT = 0x50, ///< Bulk-Only Transport
USB_MASS_1_MILLISECOND = 1000, USB_MASS_1_MILLISECOND = 1000,
USB_MASS_1_SECOND = 1000 * USB_MASS_1_MILLISECOND, USB_MASS_1_SECOND = 1000 * USB_MASS_1_MILLISECOND,
@ -111,25 +111,25 @@ EFI_STATUS
typedef typedef
EFI_STATUS EFI_STATUS
(*USB_MASS_FINI) ( (*USB_MASS_CLEAN_UP) (
IN VOID *Context IN VOID *Context
); );
// ///
// This structure contains information necessary to select the /// This structure contains information necessary to select the
// proper transport protocol. The mass storage class defines /// proper transport protocol. The mass storage class defines
// two transport protocols. One is the CBI, and the other is BOT. /// two transport protocols. One is the CBI, and the other is BOT.
// CBI is being obseleted. The design is made modular by this /// CBI is being obseleted. The design is made modular by this
// structure so that the CBI protocol can be easily removed when /// structure so that the CBI protocol can be easily removed when
// it is no longer necessary. /// it is no longer necessary.
// ///
typedef struct { typedef struct {
UINT8 Protocol; UINT8 Protocol;
USB_MASS_INIT_TRANSPORT Init; // Initialize the mass storage transport 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_EXEC_COMMAND ExecCommand; ///< Transport command to the device then get result
USB_MASS_RESET Reset; // Reset the device USB_MASS_RESET Reset; ///< Reset the device
USB_MASS_GET_MAX_LUN GetMaxLun; // Get max lun, only for bot USB_MASS_GET_MAX_LUN GetMaxLun; ///< Get max lun, only for bot
USB_MASS_FINI Fini; // Clean up the resources. USB_MASS_CLEAN_UP CleanUp; ///< Clean up the resources.
} USB_MASS_TRANSPORT; } USB_MASS_TRANSPORT;

View File

@ -1,7 +1,6 @@
/** @file /** @file
Implementation of the command set of USB Mass Storage Specification
This file implement the command set of "USB Mass Storage Specification for Bootability, Revision 1.0.
for Bootability".
Copyright (c) 2007 - 2008, Intel Corporation Copyright (c) 2007 - 2008, Intel Corporation
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
@ -16,96 +15,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "UsbMassImpl.h" #include "UsbMassImpl.h"
/** /**
Return the current TPL. Execute REQUEST SENSE Command to retrieve sense data from device.
@return Current TPL. @param UsbMass The device whose sense data is requested.
**/ @retval EFI_SUCCESS The command is excuted successfully.
EFI_TPL
UsbGetCurrentTpl (
VOID
)
{
EFI_TPL Tpl;
Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
gBS->RestoreTPL (Tpl);
return Tpl;
}
/**
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.
**/
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.
**/
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.
**/
VOID
UsbBootPutUint16 (
IN UINT8 *Buf,
IN UINT16 Data16
)
{
Data16 = (UINT16) (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_SUCCESS The command is excuted OK.
@retval EFI_DEVICE_ERROR Failed to request sense. @retval EFI_DEVICE_ERROR Failed to request sense.
@retval EFI_NO_RESPONSE The device media doesn't response this request. @retval EFI_NO_RESPONSE The device media doesn't response this request.
@retval EFI_INVALID_PARAMETER The command has some invalid parameters. @retval EFI_INVALID_PARAMETER The command has some invalid parameters.
@ -128,7 +43,7 @@ UsbBootRequestSense (
Transport = UsbMass->Transport; Transport = UsbMass->Transport;
// //
// Request the sense data from the device if command failed // Request the sense data from the device
// //
ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD)); ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA)); ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
@ -154,7 +69,8 @@ UsbBootRequestSense (
} }
// //
// Interpret the sense data and update the media status if necessary. // If sense data is retrieved successfully, interpret the sense data
// and update the media status if necessary.
// //
Media = &UsbMass->BlockIoMedia; Media = &UsbMass->BlockIoMedia;
@ -174,10 +90,10 @@ UsbBootRequestSense (
case USB_BOOT_SENSE_NOT_READY: case USB_BOOT_SENSE_NOT_READY:
Status = EFI_DEVICE_ERROR; Status = EFI_DEVICE_ERROR;
if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) { if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) {
Media->MediaPresent = FALSE; Media->MediaPresent = FALSE;
Status = EFI_NO_MEDIA; Status = EFI_NO_MEDIA;
} else if (SenseData.ASC == USB_BOOT_ASC_NOT_READY) { } else if (SenseData.ASC == USB_BOOT_ASC_NOT_READY) {
Status = EFI_NOT_READY; Status = EFI_NOT_READY;
} }
break; break;
@ -189,16 +105,16 @@ UsbBootRequestSense (
Status = EFI_DEVICE_ERROR; Status = EFI_DEVICE_ERROR;
if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) { if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) {
// //
// If MediaChange, reset ReadOnly and new MediId // If MediaChange, reset ReadOnly and new MediaId
// //
Status = EFI_MEDIA_CHANGED; Status = EFI_MEDIA_CHANGED;
Media->ReadOnly = FALSE; Media->ReadOnly = FALSE;
Media->MediaId++; Media->MediaId++;
} }
break; break;
case USB_BOOT_SNESE_DATA_PROTECT: case USB_BOOT_SENSE_DATA_PROTECT:
Status = EFI_WRITE_PROTECTED; Status = EFI_WRITE_PROTECTED;
Media->ReadOnly = TRUE; Media->ReadOnly = TRUE;
break; break;
@ -219,9 +135,11 @@ UsbBootRequestSense (
/** /**
Execute the USB mass storage bootability commands. If execution Execute the USB mass storage bootability commands.
failed, retrieve the error by REQUEST_SENSE then update the device's
status, such as ReadyOnly. This function executes the USB mass storage bootability commands.
If execution failed, retrieve the error by REQUEST_SENSE, then
update the device's status, such as ReadyOnly.
@param UsbMass The device to issue commands to @param UsbMass The device to issue commands to
@param Cmd The command to execute @param Cmd The command to execute
@ -231,11 +149,8 @@ UsbBootRequestSense (
@param DataLen The length of expected data @param DataLen The length of expected data
@param Timeout The timeout used to transfer @param Timeout The timeout used to transfer
@retval EFI_SUCCESS The command is excuted OK @retval EFI_SUCCESS Command is excuted successfully
@retval EFI_DEVICE_ERROR Failed to request sense @retval Others Command execution failed.
@retval EFI_INVALID_PARAMETER The command has some invalid parameters
@retval EFI_WRITE_PROTECTED The device is write protected
@retval EFI_MEDIA_CHANGED The device media has been changed
**/ **/
EFI_STATUS EFI_STATUS
@ -266,25 +181,31 @@ UsbBootExecCmd (
&CmdResult &CmdResult
); );
// //
// ExecCommand return success and get the right CmdResult means // If ExecCommand() returns no error and CmdResult is success,
// the commnad transfer is OK. // then the commnad transfer is successful.
// //
if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR(Status)) { if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) {
return EFI_SUCCESS; return EFI_SUCCESS;
} }
DEBUG ((EFI_D_INFO, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n", DEBUG ((EFI_D_INFO, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n",
*(UINT8 *)Cmd ,Status)); *(UINT8 *)Cmd ,Status));
//
// If command execution failed, then retrieve error info via sense request.
//
return UsbBootRequestSense (UsbMass); return UsbBootRequestSense (UsbMass);
} }
/** /**
Execute the USB mass storage bootability commands. If execution Execute the USB mass storage bootability commands with retrial.
failed, retrieve the error by REQUEST_SENSE then update the device's
status, such as ReadyOnly.
This function executes USB mass storage bootability commands.
If the device isn't ready, wait for it. If the device is ready
and error occurs, retry the command again until it exceeds the
limit of retrial times.
@param UsbMass The device to issue commands to @param UsbMass The device to issue commands to
@param Cmd The command to execute @param Cmd The command to execute
@param CmdLen The length of the command @param CmdLen The length of the command
@ -293,11 +214,9 @@ UsbBootExecCmd (
@param DataLen The length of expected data @param DataLen The length of expected data
@param Timeout The timeout used to transfer @param Timeout The timeout used to transfer
@retval EFI_SUCCESS The command is excuted OK @retval EFI_SUCCESS The command is executed successfully.
@retval EFI_DEVICE_ERROR Failed to request sense @retval EFI_MEDIA_CHANGED The device media has been changed.
@retval EFI_INVALID_PARAMETER The command has some invalid parameters @retval Others Command execution failed after retrial.
@retval EFI_WRITE_PROTECTED The device is write protected
@retval EFI_MEDIA_CHANGED The device media has been changed
**/ **/
EFI_STATUS EFI_STATUS
@ -312,18 +231,12 @@ UsbBootExecCmdWithRetry (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
INT16 Index; UINTN Retry;
//
// If the device isn't ready, wait some time. If the device is ready,
// retry the command again.
//
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
for (Index = 0; Index < USB_BOOT_COMMAND_RETRY; Index++) { for (Retry = 0; Retry < USB_BOOT_COMMAND_RETRY; Retry++) {
//
// Execute the command with an increasingly larger timeout value.
//
Status = UsbBootExecCmd ( Status = UsbBootExecCmd (
UsbMass, UsbMass,
Cmd, Cmd,
@ -333,15 +246,14 @@ UsbBootExecCmdWithRetry (
DataLen, DataLen,
Timeout Timeout
); );
if (Status == EFI_SUCCESS || if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED) {
Status == EFI_MEDIA_CHANGED) {
break; break;
} }
// //
// Need retry once more, so reset index // If the device isn't ready, just wait for it without limit on retrial times.
// //
if (Status == EFI_NOT_READY) { if (Status == EFI_NOT_READY) {
Index = 0; Retry = 0;
} }
} }
@ -350,12 +262,11 @@ UsbBootExecCmdWithRetry (
/** /**
Use the TEST UNIT READY command to check whether it is ready. Execute TEST UNIT READY command to check if the device is ready.
If it is ready, update the parameters.
@param UsbMass The device to test @param UsbMass The device to test
@retval EFI_SUCCESS The device is ready and parameters are updated. @retval EFI_SUCCESS The device is ready.
@retval Others Device not ready. @retval Others Device not ready.
**/ **/
@ -384,13 +295,13 @@ UsbBootIsUnitReady (
/** /**
Inquiry Command requests that information regrarding parameters of Execute INQUIRY Command to request information regarding parameters of
the Device be sent to the Host. the device be sent to the host computer.
@param UsbMass The device to inquiry. @param UsbMass The device to inquire.
@retval EFI_SUCCESS The device is ready and parameters are updated. @retval EFI_SUCCESS INQUIRY Command is executed successfully.
@retval Others Device not ready. @retval Others INQUIRY Command is not executed successfully.
**/ **/
EFI_STATUS EFI_STATUS
@ -405,9 +316,6 @@ UsbBootInquiry (
Media = &(UsbMass->BlockIoMedia); Media = &(UsbMass->BlockIoMedia);
//
// Use the Inquiry command to get the RemovableMedia setting.
//
ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD)); ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA)); ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
@ -428,10 +336,14 @@ UsbBootInquiry (
return Status; return Status;
} }
//
// Get information from PDT (Peripheral Device Type) field and Removable Medium Bit
// from the inquiry data.
//
UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (InquiryData.Pdt)); UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (InquiryData.Pdt));
Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (InquiryData.Removable)); Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (InquiryData.Removable));
// //
// Default value 512 Bytes, in case no media present at first time // Set block size to the default value of 512 Bytes, in case no media is present at first time.
// //
Media->BlockSize = 0x0200; Media->BlockSize = 0x0200;
@ -440,17 +352,18 @@ UsbBootInquiry (
/** /**
Get the capacity of the USB mass storage media, including Execute READ CAPACITY command to request information regarding
the presentation, block size, and last block number. This the capacity of the installed medium of the device.
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 This function executes READ CAPACITY command to get the capacity
removable. of the USB mass storage media, including the presence, block size,
and last block number.
@param UsbMass The device to retireve disk gemotric. @param UsbMass The device to retireve disk gemotric.
@retval EFI_SUCCESS The disk gemotric is successfully retrieved. @retval EFI_SUCCESS The disk geometry is successfully retrieved.
@retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric. @retval EFI_NOT_READY The returned block size is zero.
@retval Other Read capacity request fails. @retval Other READ CAPACITY command execution failed.
**/ **/
EFI_STATUS EFI_STATUS
@ -465,9 +378,6 @@ UsbBootReadCapacity (
Media = &UsbMass->BlockIoMedia; 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 (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA)); ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
@ -487,9 +397,13 @@ UsbBootReadCapacity (
return Status; return Status;
} }
//
// Get the information on media presence, block size, and last block number
// from READ CAPACITY data.
//
Media->MediaPresent = TRUE; Media->MediaPresent = TRUE;
Media->LastBlock = UsbBootGetUint32 (CapacityData.LastLba); Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba));
Media->BlockSize = UsbBootGetUint32 (CapacityData.BlockLen); Media->BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen));
if (Media->BlockSize == 0) { if (Media->BlockSize == 0) {
return EFI_NOT_READY; return EFI_NOT_READY;
@ -502,13 +416,12 @@ UsbBootReadCapacity (
} }
/** /**
Retrieves mode sense information via sending Mode Sense Retrieves SCSI mode sense information via MODE SENSE(6) command.
Packet Command.
@param UsbMass The USB_FLOPPY_DEV instance. @param UsbMass The device whose sense data is requested.
@retval EFI_SUCCESS Success @retval EFI_SUCCESS SCSI mode sense information retrieved successfully.
@retval Other Execute Request command fails. @retval Other Command execution failed.
**/ **/
EFI_STATUS EFI_STATUS
@ -527,7 +440,7 @@ UsbScsiModeSense (
ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER)); ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER));
// //
// ModeSense6 command is defined in [SCSI2Spec-Page151] // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec
// //
ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE; ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE;
ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun); ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun);
@ -545,11 +458,12 @@ UsbScsiModeSense (
); );
// //
// ModeSense(6) is used to get the information of WriteProtected. While only some of // Format of device-specific parameter byte of the mode parameter header is defined in
// devices support this command, so have a try here. // Section 8.2.10 of SCSI-2 Spec.
// BIT7 of this byte is indicates whether the medium is write protected.
// //
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
Media->ReadOnly = (BOOLEAN) (((ModeParaHeader.DevicePara & 0x80) != 0) ? TRUE : FALSE); Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0);
} }
return Status; return Status;
@ -557,17 +471,18 @@ UsbScsiModeSense (
/** /**
Get the parameters for the USB mass storage media, including Get the parameters for the USB mass storage media.
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. This function get the parameters for the USB mass storage media,
It is used both to initialize the media during the Start() phase
of Driver Binding Protocol and to re-initialize it when the media is
changed. Althought the RemoveableMedia is unlikely to change,
it is also included here.
@param UsbMass The device to retrieve disk gemotric.
@retval EFI_SUCCESS The disk gemotric is successfully retrieved. @retval EFI_SUCCESS The disk gemotric is successfully retrieved.
@retval Other Get the parameters failed. @retval Other Failed to get the parameters.
**/ **/
EFI_STATUS EFI_STATUS
@ -589,7 +504,7 @@ UsbBootGetParams (
} }
// //
// Don't use the Removable bit in inquirydata to test whether the media // Don't use the Removable bit in inquiry data to test whether the media
// is removable because many flash disks wrongly set this bit. // is removable because many flash disks wrongly set this bit.
// //
if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) { if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
@ -620,12 +535,11 @@ UsbBootGetParams (
/** /**
Detect whether the removable media is present and whether it has changed. 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. @param UsbMass The device to check.
@retval EFI_SUCCESS The disk gemotric is successfully retrieved. @retval EFI_SUCCESS The media status is successfully checked.
@retval Other Decect media fails. @retval Other Failed to detect media.
**/ **/
EFI_STATUS EFI_STATUS
@ -641,27 +555,22 @@ UsbBootDetectMedia (
Media = &UsbMass->BlockIoMedia; Media = &UsbMass->BlockIoMedia;
CopyMem ( CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA));
&OldMedia,
&(UsbMass->BlockIoMedia),
sizeof (EFI_BLOCK_IO_MEDIA)
);
CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass; CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
Status = UsbBootIsUnitReady (UsbMass); Status = UsbBootIsUnitReady (UsbMass);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status));
goto ON_ERROR; goto ON_ERROR;
} }
if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) { if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) {
// //
// ModeSense is required for the device with PDT of 0x00/0x07/0x0E, // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E,
// which is from [MassStorageBootabilitySpec-Page7]. // according to Section 4 of USB Mass Storage Specification for Bootability.
// ModeSense(10) is useless here, while ModeSense(6) defined in SCSI // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI
// could get the information of WriteProtected. // could get the information of Write Protected.
// Since not all device support this command, so skip if fail. // Since not all device support this command, skip if fail.
// //
UsbScsiModeSense (UsbMass); UsbScsiModeSense (UsbMass);
} }
@ -676,7 +585,7 @@ UsbBootDetectMedia (
ON_ERROR: ON_ERROR:
// //
// Detect whether it is necessary to reinstall the BlockIO // Detect whether it is necessary to reinstall the Block I/O Protocol.
// //
// MediaId may change in RequestSense for MediaChanged // MediaId may change in RequestSense for MediaChanged
// MediaPresent may change in RequestSense for NoMedia // MediaPresent may change in RequestSense for NoMedia
@ -689,9 +598,11 @@ ON_ERROR:
(Media->BlockSize != OldMedia.BlockSize) || (Media->BlockSize != OldMedia.BlockSize) ||
(Media->LastBlock != OldMedia.LastBlock)) { (Media->LastBlock != OldMedia.LastBlock)) {
OldTpl = UsbGetCurrentTpl (); //
DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL before reinstall BlockIoProtocol is %d\n", (UINT32)OldTpl)); // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY.
// Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface().
//
OldTpl = EfiGetCurrentTpl ();
gBS->RestoreTPL (TPL_CALLBACK); gBS->RestoreTPL (TPL_CALLBACK);
gBS->ReinstallProtocolInterface ( gBS->ReinstallProtocolInterface (
@ -701,16 +612,14 @@ ON_ERROR:
&UsbMass->BlockIo &UsbMass->BlockIo
); );
DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL after reinstall is %d\n", (UINT32)UsbGetCurrentTpl())); ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK);
ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
gBS->RaiseTPL (OldTpl); gBS->RaiseTPL (OldTpl);
// //
// Update MediaId after reinstall BLOCK_IO_PROTOCOL // Update MediaId after reinstalling Block I/O Protocol.
// //
if (Media->MediaPresent != OldMedia.MediaPresent) { if (Media->MediaPresent != OldMedia.MediaPresent) {
if (Media->MediaPresent == TRUE) { if (Media->MediaPresent) {
Media->MediaId = 1; Media->MediaId = 1;
} else { } else {
Media->MediaId = 0; Media->MediaId = 0;
@ -779,8 +688,8 @@ UsbBootReadBlocks (
ReadCmd.OpCode = USB_BOOT_READ10_OPCODE; ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;
ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
UsbBootPutUint32 (ReadCmd.Lba, Lba); WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba));
UsbBootPutUint16 (ReadCmd.TransferLen, Count); WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count));
Status = UsbBootExecCmdWithRetry ( Status = UsbBootExecCmdWithRetry (
UsbMass, UsbMass,
@ -810,7 +719,7 @@ UsbBootReadBlocks (
@param UsbMass The USB mass storage device to write to @param UsbMass The USB mass storage device to write to
@param Lba The start block number @param Lba The start block number
@param TotalBlock Total block number to write @param TotalBlock Total block number to write
@param Buffer The buffer to write to @param Buffer Pointer to the source buffer for the data.
@retval EFI_SUCCESS Data are written into the buffer @retval EFI_SUCCESS Data are written into the buffer
@retval Others Failed to write all the data @retval Others Failed to write all the data
@ -821,7 +730,7 @@ UsbBootWriteBlocks (
IN USB_MASS_DEVICE *UsbMass, IN USB_MASS_DEVICE *UsbMass,
IN UINT32 Lba, IN UINT32 Lba,
IN UINTN TotalBlock, IN UINTN TotalBlock,
OUT UINT8 *Buffer IN UINT8 *Buffer
) )
{ {
USB_BOOT_WRITE10_CMD WriteCmd; USB_BOOT_WRITE10_CMD WriteCmd;
@ -855,8 +764,8 @@ UsbBootWriteBlocks (
WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE; WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;
WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun));
UsbBootPutUint32 (WriteCmd.Lba, Lba); WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba));
UsbBootPutUint16 (WriteCmd.TransferLen, Count); WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count));
Status = UsbBootExecCmdWithRetry ( Status = UsbBootExecCmdWithRetry (
UsbMass, UsbMass,
@ -881,14 +790,13 @@ UsbBootWriteBlocks (
/** /**
Use the USB clear feature control transfer to clear the endpoint Use the USB clear feature control transfer to clear the endpoint stall condition.
stall condition.
@param UsbIo The USB IO protocol to use @param UsbIo The USB I/O Protocol instance
@param EndpointAddr The endpoint to clear stall for @param EndpointAddr The endpoint to clear stall for
@retval EFI_SUCCESS The endpoint stall condtion is clear @retval EFI_SUCCESS The endpoint stall condition is cleared.
@retval Others Failed to clear the endpoint stall condtion @retval Others Failed to clear the endpoint stall condition.
**/ **/
EFI_STATUS EFI_STATUS

View File

@ -1,6 +1,8 @@
/** @file /** @file
Definition of the command set of USB Mass Storage Specification
for Bootability, Revision 1.0.
Copyright (c) 2007, Intel Corporation Copyright (c) 2007 - 2008, Intel Corporation
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 which accompanies this distribution. The full text of the license may be found at
@ -9,18 +11,6 @@ http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 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_ #ifndef _EFI_USB_MASS_BOOT_H_
@ -28,13 +18,11 @@ Revision History
typedef enum { typedef enum {
// //
// The opcodes of various usb boot commands: // The opcodes of various USB boot commands:
// INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified // INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified
// by MMC command set. Others are "Group 1 Timeout Commands". That // by Multi-Media Commands (MMC) set.
// is they should be retried if driver is ready. // Others are "Group 1 Timeout Commands". That is,
// We can't use the Peripheral Device Type in Inquiry data to // they should be retried if driver is ready.
// 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_INQUIRY_OPCODE = 0x12,
USB_BOOT_REQUEST_SENSE_OPCODE = 0x03, USB_BOOT_REQUEST_SENSE_OPCODE = 0x03,
@ -50,19 +38,19 @@ typedef enum {
// The Sense Key part of the sense data. Sense data has three levels: // The Sense Key part of the sense data. Sense data has three levels:
// Sense key, Additional Sense Code and Additional Sense Code Qualifier // Sense key, Additional Sense Code and Additional Sense Code Qualifier
// //
USB_BOOT_SENSE_NO_SENSE = 0x00, // No sense key USB_BOOT_SENSE_NO_SENSE = 0x00, ///< No sense key
USB_BOOT_SENSE_RECOVERED = 0x01, // Last command succeed with recovery actions USB_BOOT_SENSE_RECOVERED = 0x01, ///< Last command succeed with recovery actions
USB_BOOT_SENSE_NOT_READY = 0x02, // Device not ready USB_BOOT_SENSE_NOT_READY = 0x02, ///< Device not ready
USB_BOOT_SNESE_MEDIUM_ERROR = 0X03, // Failed probably because flaw in the media 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_HARDWARE_ERROR = 0X04, ///< Non-recoverable hardware failure
USB_BOOT_SENSE_ILLEGAL_REQUEST = 0X05, // Illegal parameters in the request 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_SENSE_UNIT_ATTENTION = 0X06, ///< Removable medium may have been changed
USB_BOOT_SNESE_DATA_PROTECT = 0X07, // Write protected USB_BOOT_SENSE_DATA_PROTECT = 0X07, ///< Write protected
USB_BOOT_SENSE_BLANK_CHECK = 0X08, // Blank/non-blank medium while reading/writing 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_VENDOR = 0X09, ///< Vendor specific sense key
USB_BOOT_SENSE_ABORTED = 0X0B, // Command aborted by the device USB_BOOT_SENSE_ABORTED = 0X0B, ///< Command aborted by the device
USB_BOOT_SENSE_VOLUME_OVERFLOW = 0x0D, // Partition overflow USB_BOOT_SENSE_VOLUME_OVERFLOW = 0x0D, ///< Partition overflow
USB_BOOT_SENSE_MISCOMPARE = 0x0E, // Source data mis-match while verfying. USB_BOOT_SENSE_MISCOMPARE = 0x0E, ///< Source data mis-match while verfying.
USB_BOOT_ASC_NOT_READY = 0x04, USB_BOOT_ASC_NOT_READY = 0x04,
USB_BOOT_ASC_NO_MEDIA = 0x3A, USB_BOOT_ASC_NO_MEDIA = 0x3A,
@ -71,10 +59,10 @@ typedef enum {
// //
// Supported PDT codes, or Peripheral Device Type // Supported PDT codes, or Peripheral Device Type
// //
USB_PDT_DIRECT_ACCESS = 0x00, // Direct access device USB_PDT_DIRECT_ACCESS = 0x00, ///< Direct access device
USB_PDT_CDROM = 0x05, // CDROM USB_PDT_CDROM = 0x05, ///< CDROM
USB_PDT_OPTICAL = 0x07, // Non-CD optical disks USB_PDT_OPTICAL = 0x07, ///< Non-CD optical disks
USB_PDT_SIMPLE_DIRECT = 0x0E, // Simplified direct access device USB_PDT_SIMPLE_DIRECT = 0x0E, ///< Simplified direct access device
// //
// Other parameters, Max carried size is 512B * 128 = 64KB // Other parameters, Max carried size is 512B * 128 = 64KB
@ -99,7 +87,6 @@ typedef enum {
// USB CD-Rom and iPod devices are much slower than USB key when reponse // USB CD-Rom and iPod devices are much slower than USB key when reponse
// most of commands, So we set 5s as timeout here. // most of commands, So we set 5s as timeout here.
// //
//
USB_BOOT_GENERAL_CMD_TIMEOUT = 5 * USB_MASS_1_SECOND USB_BOOT_GENERAL_CMD_TIMEOUT = 5 * USB_MASS_1_SECOND
}USB_BOOT_OPTCODE; }USB_BOOT_OPTCODE;
@ -112,7 +99,7 @@ typedef enum {
#pragma pack(1) #pragma pack(1)
typedef struct { typedef struct {
UINT8 OpCode; UINT8 OpCode;
UINT8 Lun; // Lun (high 3 bits) UINT8 Lun; ///< Lun (high 3 bits)
UINT8 Reserved0[2]; UINT8 Reserved0[2];
UINT8 AllocLen; UINT8 AllocLen;
UINT8 Reserved1; UINT8 Reserved1;
@ -120,10 +107,10 @@ typedef struct {
} USB_BOOT_INQUIRY_CMD; } USB_BOOT_INQUIRY_CMD;
typedef struct { typedef struct {
UINT8 Pdt; // Peripheral Device Type (low 5 bits) UINT8 Pdt; ///< Peripheral Device Type (low 5 bits)
UINT8 Removable; // Removable Media (highest bit) UINT8 Removable; ///< Removable Media (highest bit)
UINT8 Reserved0[2]; UINT8 Reserved0[2];
UINT8 AddLen; // Additional length UINT8 AddLen; ///< Additional length
UINT8 Reserved1[3]; UINT8 Reserved1[3];
UINT8 VendorID[8]; UINT8 VendorID[8];
UINT8 ProductID[16]; UINT8 ProductID[16];
@ -170,10 +157,10 @@ typedef struct {
typedef struct { typedef struct {
UINT8 OpCode; UINT8 OpCode;
UINT8 Lun; // Lun (High 3 bits) UINT8 Lun; ///< Lun (High 3 bits)
UINT8 Lba[4]; // Logical block address UINT8 Lba[4]; ///< Logical block address
UINT8 Reserved0; UINT8 Reserved0;
UINT8 TransferLen[2]; // Transfer length UINT8 TransferLen[2]; ///< Transfer length
UINT8 Reserverd1; UINT8 Reserverd1;
UINT8 Pad[2]; UINT8 Pad[2];
} USB_BOOT_READ10_CMD; } USB_BOOT_READ10_CMD;
@ -190,9 +177,9 @@ typedef struct {
typedef struct { typedef struct {
UINT8 OpCode; UINT8 OpCode;
UINT8 Lun; // Lun (High 3 bits) UINT8 Lun; ///< Lun (High 3 bits)
UINT8 Reserved0[2]; UINT8 Reserved0[2];
UINT8 AllocLen; // Allocation length UINT8 AllocLen; ///< Allocation length
UINT8 Reserved1; UINT8 Reserved1;
UINT8 Pad[6]; UINT8 Pad[6];
} USB_BOOT_REQUEST_SENSE_CMD; } USB_BOOT_REQUEST_SENSE_CMD;
@ -200,12 +187,12 @@ typedef struct {
typedef struct { typedef struct {
UINT8 ErrorCode; UINT8 ErrorCode;
UINT8 Reserved0; UINT8 Reserved0;
UINT8 SenseKey; // Sense key (low 4 bits) UINT8 SenseKey; ///< Sense key (low 4 bits)
UINT8 Infor[4]; UINT8 Infor[4];
UINT8 AddLen; // Additional Sense length, 10 UINT8 AddLen; ///< Additional Sense length, 10
UINT8 Reserved1[4]; UINT8 Reserved1[4];
UINT8 ASC; // Additional Sense Code UINT8 ASC; ///< Additional Sense Code
UINT8 ASCQ; // Additional Sense Code Qualifier UINT8 ASCQ; ///< Additional Sense Code Qualifier
UINT8 Reserverd2[4]; UINT8 Reserverd2[4];
} USB_BOOT_REQUEST_SENSE_DATA; } USB_BOOT_REQUEST_SENSE_DATA;
@ -234,22 +221,10 @@ typedef struct {
// //
// Get the removable, PDT, and sense key bits from the command data // Get the removable, PDT, and sense key bits from the command data
// //
#define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & 0x80) != 0) #define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & BIT7) != 0)
#define USB_BOOT_PDT(Pdt) ((Pdt) & 0x1f) #define USB_BOOT_PDT(Pdt) ((Pdt) & 0x1f)
#define USB_BOOT_SENSE_KEY(Key) ((Key) & 0x0f) #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))
/** /**
Get the parameters for the USB mass storage media, including Get the parameters for the USB mass storage media, including
the RemovableMedia, block size, and last block number. This the RemovableMedia, block size, and last block number. This

View File

@ -1,6 +1,6 @@
/** @file /** @file
Implementation of the USB mass storage Bulk-Only Transport protocol,
Implementation of the USB mass storage Bulk-Only Transport protocol. according to USB Mass Storage Class Bulk-Only Transport, Revision 1.0.
Copyright (c) 2007 - 2008, Intel Corporation Copyright (c) 2007 - 2008, Intel Corporation
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
@ -16,41 +16,36 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "UsbMass.h" #include "UsbMass.h"
#include "UsbMassBot.h" #include "UsbMassBot.h"
/** //
Reset the mass storage device by BOT protocol. // Definition of USB BOT Transport Protocol
//
@param Context The context of the BOT protocol, that is, USB_MASS_TRANSPORT mUsbBotTransport = {
USB_BOT_PROTOCOL. USB_MASS_STORE_BOT,
@param ExtendedVerification The flag controlling the rule of reset dev. UsbBotInit,
UsbBotExecCommand,
@retval EFI_SUCCESS The device is reset. UsbBotResetDevice,
@retval Others Failed to reset the device.. UsbBotGetMaxLun,
UsbBotCleanUp
**/ };
EFI_STATUS
UsbBotResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
);
/** /**
Initialize the USB mass storage class BOT transport protocol. Initializes USB BOT protocol.
This function initializes the USB mass storage class BOT protocol.
It will save its context which is a USB_BOT_PROTOCOL structure It will save its context which is a USB_BOT_PROTOCOL structure
in the Context if Context isn't NULL. in the Context if Context isn't NULL.
@param UsbIo The USB IO protocol to use @param UsbIo The USB I/O Protocol instance
@param Context The variable to save the context to @param Context The buffer to save the context to
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory @retval EFI_SUCCESS The device is successfully initialized.
@retval EFI_UNSUPPORTED The transport protocol doesn't support the device. @retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
@retval EFI_SUCCESS The device is supported and protocol initialized. @retval Other The USB BOT initialization fails.
@retval Other The UBS BOT initialization fails.
**/ **/
EFI_STATUS EFI_STATUS
UsbBotInit ( UsbBotInit (
IN EFI_USB_IO_PROTOCOL * UsbIo, IN EFI_USB_IO_PROTOCOL *UsbIo,
OUT VOID **Context OPTIONAL OUT VOID **Context OPTIONAL
) )
{ {
@ -61,25 +56,22 @@ UsbBotInit (
UINT8 Index; UINT8 Index;
// //
// Allocate the BOT context, append two endpoint descriptors to it // Allocate the BOT context for USB_BOT_PROTOCOL and two endpoint descriptors.
// //
UsbBot = AllocateZeroPool ( UsbBot = AllocateZeroPool (
sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
); );
if (UsbBot == NULL) { ASSERT (UsbBot != NULL);
return EFI_OUT_OF_RESOURCES;
}
UsbBot->UsbIo = UsbIo; UsbBot->UsbIo = UsbIo;
// //
// Get the interface descriptor and validate that it // Get the interface descriptor and validate that it
// is a USB MSC BOT interface. // is a USB Mass Storage BOT interface.
// //
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface); Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbBotInit: Get invalid BOT interface (%r)\n", Status));
goto ON_ERROR; goto ON_ERROR;
} }
@ -115,14 +107,16 @@ UsbBotInit (
} }
} }
//
// If bulk-in or bulk-out endpoint is not found, report error.
//
if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) { if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) {
DEBUG ((EFI_D_ERROR, "UsbBotInit: In/Out Endpoint invalid\n"));
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;
goto ON_ERROR; goto ON_ERROR;
} }
// //
// The USB BOT protocol uses dCBWTag to match the CBW and CSW. // The USB BOT protocol uses CBWTag to match the CBW and CSW.
// //
UsbBot->CbwTag = 0x01; UsbBot->CbwTag = 0x01;
@ -139,19 +133,22 @@ ON_ERROR:
return Status; return Status;
} }
/** /**
Send the command to the device using Bulk-Out endpoint. Send the command to the device using Bulk-Out endpoint.
This function sends the command to the device using Bulk-Out endpoint.
BOT transfer is composed of three phases: Command, Data, and Status.
This is the Command phase.
@param UsbBot The USB BOT device @param UsbBot The USB BOT device
@param Cmd The command to transfer to device @param Cmd The command to transfer to device
@param CmdLen the length of the command @param CmdLen The length of the command
@param DataDir The direction of the data @param DataDir The direction of the data
@param TransLen The expected length of the data @param TransLen The expected length of the data
@param Lun The number of logic unit @param Lun The number of logic unit
@retval EFI_NOT_READY The device return NAK to the transfer
@retval EFI_SUCCESS The command is sent to the device. @retval EFI_SUCCESS The command is sent to the device.
@retval EFI_NOT_READY The device return NAK to the transfer
@retval Others Failed to send the command to device @retval Others Failed to send the command to device
**/ **/
@ -174,25 +171,24 @@ UsbBotSendCommand (
ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN)); ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN));
// //
// Fill in the CSW. Only the first LUN is supported now. // Fill in the Command Block Wrapper.
// //
Cbw.Signature = USB_BOT_CBW_SIGNATURE; Cbw.Signature = USB_BOT_CBW_SIGNATURE;
Cbw.Tag = UsbBot->CbwTag; Cbw.Tag = UsbBot->CbwTag;
Cbw.DataLen = TransLen; Cbw.DataLen = TransLen;
Cbw.Flag = (UINT8) ((DataDir == EfiUsbDataIn) ? 0x80 : 0); Cbw.Flag = (UINT8) ((DataDir == EfiUsbDataIn) ? BIT7 : 0);
Cbw.Lun = Lun; Cbw.Lun = Lun;
Cbw.CmdLen = CmdLen; Cbw.CmdLen = CmdLen;
ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN); ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN);
CopyMem (Cbw.CmdBlock, Cmd, CmdLen); CopyMem (Cbw.CmdBlock, Cmd, CmdLen);
Result = 0; Result = 0;
DataLen = sizeof (USB_BOT_CBW); DataLen = sizeof (USB_BOT_CBW);
Timeout = USB_BOT_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND; Timeout = USB_BOT_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND;
// //
// Use the UsbIo to send the command to the device. The default // Use USB I/O Protocol to send the Command Block Wrapper to the device.
// time out is enough.
// //
Status = UsbBot->UsbIo->UsbBulkTransfer ( Status = UsbBot->UsbIo->UsbBulkTransfer (
UsbBot->UsbIo, UsbBot->UsbIo,
@ -202,12 +198,12 @@ UsbBotSendCommand (
Timeout, Timeout,
&Result &Result
); );
//
// Respond to Bulk-Out endpoint stall with a Reset Recovery,
// see the spec section 5.3.1
//
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) { if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) {
//
// Respond to Bulk-Out endpoint stall with a Reset Recovery,
// according to section 5.3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
//
UsbBotResetDevice (UsbBot, FALSE); UsbBotResetDevice (UsbBot, FALSE);
} else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) { } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
Status = EFI_NOT_READY; Status = EFI_NOT_READY;
@ -219,8 +215,11 @@ UsbBotSendCommand (
/** /**
Transfer the data between the device and host. BOT transfer Transfer the data between the device and host.
is composed of three phase, command, data, and status.
This function transfers the data between the device and host.
BOT transfer is composed of three phases: Command, Data, and Status.
This is the Data phase.
@param UsbBot The USB BOT device @param UsbBot The USB BOT device
@param DataDir The direction of the data @param DataDir The direction of the data
@ -229,6 +228,8 @@ UsbBotSendCommand (
@param Timeout The time to wait the command to complete @param Timeout The time to wait the command to complete
@retval EFI_SUCCESS The data is transferred @retval EFI_SUCCESS The data is transferred
@retval EFI_SUCCESS No data to transfer
@retval EFI_NOT_READY The device return NAK to the transfer
@retval Others Failed to transfer data @retval Others Failed to transfer data
**/ **/
@ -246,7 +247,7 @@ UsbBotDataTransfer (
UINT32 Result; UINT32 Result;
// //
// It's OK if no data to transfer // If no data to transfer, just return EFI_SUCCESS.
// //
if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) { if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
return EFI_SUCCESS; return EFI_SUCCESS;
@ -273,9 +274,7 @@ UsbBotDataTransfer (
&Result &Result
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: (%r)\n", Status));
if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) { if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: DataIn Stall\n"));
UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress); UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress);
} else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) { } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
Status = EFI_NOT_READY; Status = EFI_NOT_READY;
@ -287,19 +286,22 @@ UsbBotDataTransfer (
/** /**
Get the command execution status from device. BOT transfer is Get the command execution status from device.
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. This function gets the command execution status from device.
@param TransLen The expected length of the data. BOT transfer is composed of three phases: Command, Data, and Status.
@param CmdStatus The result of the command execution. This is the Status phase.
@retval EFI_SUCCESS Command execute result is retrieved and in the This function returns the transfer status of the BOT's CSW status,
Result. and returns the high level command execution result in Result. So
@retval Other Failed to get status. even if EFI_SUCCESS is returned, the command may still have failed.
@param UsbBot The USB BOT device.
@param TransLen The expected length of the data.
@param CmdStatus The result of the command execution.
@retval EFI_SUCCESS Command execute result is retrieved and in the Result.
@retval Other Error occurred when trying to get status.
**/ **/
EFI_STATUS EFI_STATUS
@ -326,7 +328,7 @@ UsbBotGetStatus (
for (Index = 0; Index < USB_BOT_RECV_CSW_RETRY; Index++) { for (Index = 0; Index < USB_BOT_RECV_CSW_RETRY; Index++) {
// //
// Attemp to the read CSW from bulk in endpoint // Attemp to the read Command Status Wrapper from bulk in endpoint
// //
ZeroMem (&Csw, sizeof (USB_BOT_CSW)); ZeroMem (&Csw, sizeof (USB_BOT_CSW));
Result = 0; Result = 0;
@ -340,9 +342,7 @@ UsbBotGetStatus (
&Result &Result
); );
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "UsbBotGetStatus (%r)\n", Status));
if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) { if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: DataIn Stall\n"));
UsbClearEndpointStall (UsbIo, Endpoint); UsbClearEndpointStall (UsbIo, Endpoint);
} }
continue; continue;
@ -350,24 +350,21 @@ UsbBotGetStatus (
if (Csw.Signature != USB_BOT_CSW_SIGNATURE) { if (Csw.Signature != USB_BOT_CSW_SIGNATURE) {
// //
// Invalid Csw need perform reset recovery // CSW is invalid, so perform reset recovery
// //
DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: Device return a invalid signature\n"));
Status = UsbBotResetDevice (UsbBot, FALSE); Status = UsbBotResetDevice (UsbBot, FALSE);
} else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) { } else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) {
// //
// Respond phase error need perform reset recovery // Respond phase error also needs reset recovery
// //
DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: Device return a phase error\n"));
Status = UsbBotResetDevice (UsbBot, FALSE); Status = UsbBotResetDevice (UsbBot, FALSE);
} else { } else {
*CmdStatus = Csw.CmdStatus; *CmdStatus = Csw.CmdStatus;
break; break;
} }
} }
// //
//The tag is increased even there is an error. //The tag is increased even if there is an error.
// //
UsbBot->CbwTag++; UsbBot->CbwTag++;
@ -376,7 +373,7 @@ UsbBotGetStatus (
/** /**
Call the Usb mass storage class transport protocol to issue Call the USB Mass Storage Class BOT protocol to issue
the command/data/status circle to execute the commands. the command/data/status circle to execute the commands.
@param Context The context of the BOT protocol, that is, @param Context The context of the BOT protocol, that is,
@ -390,7 +387,7 @@ UsbBotGetStatus (
@param Timeout The time to wait command @param Timeout The time to wait command
@param CmdStatus The result of high level command execution @param CmdStatus The result of high level command execution
@retval EFI_SUCCESS The command is executed OK, and result in CmdStatus @retval EFI_SUCCESS The command is executed successfully.
@retval Other Failed to excute command @retval Other Failed to excute command
**/ **/
@ -428,7 +425,7 @@ UsbBotExecCommand (
// //
// Transfer the data. Don't return immediately even data transfer // Transfer the data. Don't return immediately even data transfer
// failed. The host should attempt to receive the CSW no matter // failed. The host should attempt to receive the CSW no matter
// whether it succeeds or failed. // whether it succeeds or fails.
// //
TransLen = (UINTN) DataLen; TransLen = (UINTN) DataLen;
UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout); UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout);
@ -451,11 +448,12 @@ UsbBotExecCommand (
/** /**
Reset the mass storage device by BOT protocol. Reset the USB mass storage device by BOT protocol.
@param Context The context of the BOT protocol, that is, @param Context The context of the BOT protocol, that is,
USB_BOT_PROTOCOL. USB_BOT_PROTOCOL.
@param ExtendedVerification The flag controlling the rule of reset dev. @param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request.
If TRUE, additionally reset parent hub port.
@retval EFI_SUCCESS The device is reset. @retval EFI_SUCCESS The device is reset.
@retval Others Failed to reset the device.. @retval Others Failed to reset the device..
@ -464,7 +462,7 @@ UsbBotExecCommand (
EFI_STATUS EFI_STATUS
UsbBotResetDevice ( UsbBotResetDevice (
IN VOID *Context, IN VOID *Context,
IN BOOLEAN ExtendedVerification IN BOOLEAN ExtendedVerification
) )
{ {
USB_BOT_PROTOCOL *UsbBot; USB_BOT_PROTOCOL *UsbBot;
@ -486,10 +484,10 @@ UsbBotResetDevice (
} }
// //
// Issue a class specific Bulk-Only Mass Storage Reset reqest. // Issue a class specific Bulk-Only Mass Storage Reset request,
// See the spec section 3.1 // according to section 3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
// //
Request.RequestType = 0x21; // Class, Interface, Host to Device Request.RequestType = 0x21;
Request.Request = USB_BOT_RESET_REQUEST; Request.Request = USB_BOT_RESET_REQUEST;
Request.Value = 0; Request.Value = 0;
Request.Index = UsbBot->Interface.InterfaceNumber; Request.Index = UsbBot->Interface.InterfaceNumber;
@ -507,14 +505,13 @@ UsbBotResetDevice (
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbBotResetDevice: (%r)\n", Status));
return Status; return Status;
} }
// //
// The device shall NAK the host's request until the reset is // The device shall NAK the host's request until the reset is
// complete. We can use this to sync the device and host. For // complete. We can use this to sync the device and host. For
// now just stall 100ms to wait the device. // now just stall 100ms to wait for the device.
// //
gBS->Stall (USB_BOT_RESET_DEVICE_STALL); gBS->Stall (USB_BOT_RESET_DEVICE_STALL);
@ -523,25 +520,26 @@ UsbBotResetDevice (
// //
UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress); UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress);
UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress); UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress);
return Status; return Status;
} }
/** /**
Get the max lun of mass storage device. Get the max LUN (Logical Unit Number) of USB mass storage device.
@param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL
@param MaxLun Return pointer to the max number of lun. Maxlun=1 means lun0 and @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
lun1 in all. LUN1 in all.)
@retval EFI_SUCCESS Get max lun success. @retval EFI_SUCCESS Max LUN is got successfully.
@retval Others Failed to execute this request. @retval Others Fail to execute this request.
**/ **/
EFI_STATUS EFI_STATUS
UsbBotGetMaxLun ( UsbBotGetMaxLun (
IN VOID *Context, IN VOID *Context,
IN UINT8 *MaxLun OUT UINT8 *MaxLun
) )
{ {
USB_BOT_PROTOCOL *UsbBot; USB_BOT_PROTOCOL *UsbBot;
@ -556,9 +554,9 @@ UsbBotGetMaxLun (
// //
// Issue a class specific Bulk-Only Mass Storage get max lun reqest. // Issue a class specific Bulk-Only Mass Storage get max lun reqest.
// See the spec section 3.2 // according to section 3.2 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0.
// //
Request.RequestType = 0xA1; // Class, Interface, Device to Host Request.RequestType = 0xA1;
Request.Request = USB_BOT_GETLUN_REQUEST; Request.Request = USB_BOT_GETLUN_REQUEST;
Request.Value = 0; Request.Value = 0;
Request.Index = UsbBot->Interface.InterfaceNumber; Request.Index = UsbBot->Interface.InterfaceNumber;
@ -570,29 +568,24 @@ UsbBotGetMaxLun (
&Request, &Request,
EfiUsbDataIn, EfiUsbDataIn,
Timeout, Timeout,
(VOID *)MaxLun, (VOID *) MaxLun,
1, 1,
&Result &Result
); );
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbBotGetMaxLun: (%r)\n", Status));
}
return Status; return Status;
} }
/** /**
Clean up the resource used by this BOT protocol. Clean up the resource used by this BOT protocol.
@param Context The context of the BOT protocol, that is, @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL.
USB_BOT_PROTOCOL.
@retval EFI_SUCCESS The resource is cleaned up. @retval EFI_SUCCESS The resource is cleaned up.
**/ **/
EFI_STATUS EFI_STATUS
UsbBotFini ( UsbBotCleanUp (
IN VOID *Context IN VOID *Context
) )
{ {
@ -600,13 +593,3 @@ UsbBotFini (
return EFI_SUCCESS; return EFI_SUCCESS;
} }
USB_MASS_TRANSPORT
mUsbBotTransport = {
USB_MASS_STORE_BOT,
UsbBotInit,
UsbBotExecCommand,
UsbBotResetDevice,
UsbBotGetMaxLun,
UsbBotFini
};

View File

@ -1,8 +1,7 @@
/** @file /** @file
Definition for the USB mass storage Bulk-Only Transport protocol,
Defination for the USB mass storage Bulk-Only Transport protocol. based on the "Universal Serial Bus Mass Storage Class Bulk-Only
This implementation is based on the "Universal Serial Bus Mass Transport" Revision 1.0, September 31, 1999.
Storage Class Bulk-Only Transport" Revision 1.0, September 31, 1999.
Copyright (c) 2007 - 2008, Intel Corporation Copyright (c) 2007 - 2008, Intel Corporation
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
@ -18,33 +17,35 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#ifndef _EFI_USBMASS_BOT_H_ #ifndef _EFI_USBMASS_BOT_H_
#define _EFI_USBMASS_BOT_H_ #define _EFI_USBMASS_BOT_H_
extern USB_MASS_TRANSPORT mUsbBotTransport;
typedef enum { typedef enum {
// //
// Usb Bulk-Only class specfic request // Usb Bulk-Only class specfic request
// //
USB_BOT_RESET_REQUEST = 0xFF, // Bulk-Only Mass Storage Reset USB_BOT_RESET_REQUEST = 0xFF, ///< Bulk-Only Mass Storage Reset
USB_BOT_GETLUN_REQUEST = 0xFE, // Get Max Lun USB_BOT_GETLUN_REQUEST = 0xFE, ///< Get Max Lun
USB_BOT_CBW_SIGNATURE = 0x43425355, // dCBWSignature, tag the packet as CBW USB_BOT_CBW_SIGNATURE = 0x43425355, ///< dCBWSignature, tag the packet as CBW
USB_BOT_CSW_SIGNATURE = 0x53425355, // dCSWSignature, tag the packet as CSW 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_LUN = 0x0F, ///< Lun number is from 0 to 15
USB_BOT_MAX_CMDLEN = 16, // Maxium number of command from command set USB_BOT_MAX_CMDLEN = 16, ///< Maxium number of command from command set
// //
// Usb BOT command block status values // Usb BOT command block status values
// //
USB_BOT_COMMAND_OK = 0x00, // Command passed, good status USB_BOT_COMMAND_OK = 0x00, ///< Command passed, good status
USB_BOT_COMMAND_FAILED = 0x01, // Command failed USB_BOT_COMMAND_FAILED = 0x01, ///< Command failed
USB_BOT_COMMAND_ERROR = 0x02, // Phase error, need to reset the device USB_BOT_COMMAND_ERROR = 0x02, ///< Phase error, need to reset the device
// //
// Usb Bot retry to get CSW, refers to specification[BOT10-5.3, it says 2 times] // Usb Bot retry to get CSW, refers to specification[BOT10-5.3, it says 2 times]
// //
USB_BOT_RECV_CSW_RETRY = 3, USB_BOT_RECV_CSW_RETRY = 3,
// //
// Usb Bot wait device reset complete, set by experience // Usb Bot wait device reset complete, set by experience
// //
USB_BOT_RESET_DEVICE_STALL = 100 * USB_MASS_1_MILLISECOND, USB_BOT_RESET_DEVICE_STALL = 100 * USB_MASS_1_MILLISECOND,
// //
// Usb Bot transport timeout, set by experience // Usb Bot transport timeout, set by experience
@ -52,23 +53,25 @@ typedef enum {
USB_BOT_SEND_CBW_TIMEOUT = 3 * USB_MASS_1_SECOND, USB_BOT_SEND_CBW_TIMEOUT = 3 * USB_MASS_1_SECOND,
USB_BOT_RECV_CSW_TIMEOUT = 3 * USB_MASS_1_SECOND, USB_BOT_RECV_CSW_TIMEOUT = 3 * USB_MASS_1_SECOND,
USB_BOT_RESET_DEVICE_TIMEOUT = 3 * USB_MASS_1_SECOND USB_BOT_RESET_DEVICE_TIMEOUT = 3 * USB_MASS_1_SECOND
}USB_BOT_SUBCLASS; } USB_BOT_SUBCLASS;
//
// The CBW (Command Block Wrapper) and CSW (Command Status Wrapper)
// structures used by the Usb BOT protocol.
//
#pragma pack(1) #pragma pack(1)
///
/// The CBW (Command Block Wrapper) structures used by the USB BOT protocol.
///
typedef struct { typedef struct {
UINT32 Signature; UINT32 Signature;
UINT32 Tag; UINT32 Tag;
UINT32 DataLen; // Length of data between CBW and CSW UINT32 DataLen; ///< Length of data between CBW and CSW
UINT8 Flag; // Bit 7, 0 ~ Data-Out, 1 ~ Data-In UINT8 Flag; ///< Bit 7, 0 ~ Data-Out, 1 ~ Data-In
UINT8 Lun; // Lun number. Bits 0~3 are used UINT8 Lun; ///< Lun number. Bits 0~3 are used
UINT8 CmdLen; // Length of the command. Bits 0~4 are used UINT8 CmdLen; ///< Length of the command. Bits 0~4 are used
UINT8 CmdBlock[USB_BOT_MAX_CMDLEN]; UINT8 CmdBlock[USB_BOT_MAX_CMDLEN];
} USB_BOT_CBW; } USB_BOT_CBW;
///
/// The and CSW (Command Status Wrapper) structures used by the USB BOT protocol.
///
typedef struct { typedef struct {
UINT32 Signature; UINT32 Signature;
UINT32 Tag; UINT32 Tag;
@ -77,11 +80,10 @@ typedef struct {
} USB_BOT_CSW; } USB_BOT_CSW;
#pragma pack() #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 { typedef struct {
//
// Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance
//
EFI_USB_INTERFACE_DESCRIPTOR Interface; EFI_USB_INTERFACE_DESCRIPTOR Interface;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint; EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint; EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
@ -89,5 +91,105 @@ typedef struct {
EFI_USB_IO_PROTOCOL *UsbIo; EFI_USB_IO_PROTOCOL *UsbIo;
} USB_BOT_PROTOCOL; } USB_BOT_PROTOCOL;
extern USB_MASS_TRANSPORT mUsbBotTransport; /**
Initializes USB BOT protocol.
This function initializes the USB mass storage class BOT protocol.
It will save its context which is a USB_BOT_PROTOCOL structure
in the Context if Context isn't NULL.
@param UsbIo The USB I/O Protocol instance
@param Context The buffer to save the context to
@retval EFI_SUCCESS The device is successfully initialized.
@retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
@retval Other The USB BOT initialization fails.
**/
EFI_STATUS
UsbBotInit (
IN EFI_USB_IO_PROTOCOL *UsbIo,
OUT VOID **Context OPTIONAL
);
/**
Call the USB Mass Storage Class BOT protocol to issue
the command/data/status circle to execute the commands.
@param Context The context of the BOT protocol, that is,
USB_BOT_PROTOCOL
@param Cmd The high level command
@param CmdLen The command length
@param DataDir The direction of the data transfer
@param Data The buffer to hold data
@param DataLen The length of the data
@param Lun The number of logic unit
@param Timeout The time to wait command
@param CmdStatus The result of high level command execution
@retval EFI_SUCCESS The command is executed successfully.
@retval Other Failed to excute command
**/
EFI_STATUS
UsbBotExecCommand (
IN VOID *Context,
IN VOID *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN VOID *Data,
IN UINT32 DataLen,
IN UINT8 Lun,
IN UINT32 Timeout,
OUT UINT32 *CmdStatus
);
/**
Reset the USB mass storage device by BOT protocol.
@param Context The context of the BOT protocol, that is,
USB_BOT_PROTOCOL.
@param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request.
If TRUE, additionally reset parent hub port.
@retval EFI_SUCCESS The device is reset.
@retval Others Failed to reset the device..
**/
EFI_STATUS
UsbBotResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
);
/**
Get the max LUN (Logical Unit Number) of USB mass storage device.
@param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL
@param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and
LUN1 in all.)
@retval EFI_SUCCESS Max LUN is got successfully.
@retval Others Fail to execute this request.
**/
EFI_STATUS
UsbBotGetMaxLun (
IN VOID *Context,
OUT UINT8 *MaxLun
);
/**
Clean up the resource used by this BOT protocol.
@param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL.
@retval EFI_SUCCESS The resource is cleaned up.
**/
EFI_STATUS
UsbBotCleanUp (
IN VOID *Context
);
#endif #endif

View File

@ -1,6 +1,6 @@
/** @file /** @file
Implementation of the USB mass storage Control/Bulk/Interrupt transport,
Implementation of the USB mass storage Control/Bulk/Interrupt transport. according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.
Notice: it is being obsoleted by the standard body in favor of the BOT Notice: it is being obsoleted by the standard body in favor of the BOT
(Bulk-Only Transport). (Bulk-Only Transport).
@ -18,37 +18,43 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "UsbMass.h" #include "UsbMass.h"
#include "UsbMassCbi.h" #include "UsbMassCbi.h"
/** //
Call the Usb mass storage class transport protocol to // Definition of USB CBI0 Transport Protocol
reset the device. The reset is defined as a Non-Data //
command. Don't use UsbCbiExecCommand to send the command USB_MASS_TRANSPORT mUsbCbi0Transport = {
to device because that may introduce recursive loop. USB_MASS_STORE_CBI0,
UsbCbiInit,
@param Context The USB CBI device protocol UsbCbiExecCommand,
@param ExtendedVerification The flag controlling the rule of reset UsbCbiResetDevice,
NULL,
@retval EFI_SUCCESS the device is reset UsbCbiCleanUp
@retval Others Failed to reset the device };
**/
EFI_STATUS
UsbCbiResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
);
//
// Definition of USB CBI1 Transport Protocol
//
USB_MASS_TRANSPORT mUsbCbi1Transport = {
USB_MASS_STORE_CBI1,
UsbCbiInit,
UsbCbiExecCommand,
UsbCbiResetDevice,
NULL,
UsbCbiCleanUp
};
/** /**
Initialize the USB mass storage class CBI transport protocol. Initializes USB CBI protocol.
If Context isn't NULL, it will save its context in it.
@param UsbIo The USB IO to use This function initializes the USB mass storage class CBI protocol.
@param Context The variable to save context in It will save its context which is a USB_CBI_PROTOCOL structure
in the Context if Context isn't NULL.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory @param UsbIo The USB I/O Protocol instance
@retval EFI_UNSUPPORTED The device isn't supported @param Context The buffer to save the context to
@retval EFI_SUCCESS The CBI protocol is initialized.
@retval Other The Usb cbi init failed. @retval EFI_SUCCESS The device is successfully initialized.
@retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
@retval Other The USB CBI initialization fails.
**/ **/
EFI_STATUS EFI_STATUS
@ -64,21 +70,18 @@ UsbCbiInit (
UINT8 Index; UINT8 Index;
// //
// Allocate the CBI context // Allocate the CBI context for USB_CBI_PROTOCOL and 3 endpoint descriptors.
// //
UsbCbi = AllocateZeroPool ( UsbCbi = AllocateZeroPool (
sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
); );
ASSERT (UsbCbi != NULL);
if (UsbCbi == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UsbCbi->UsbIo = UsbIo; UsbCbi->UsbIo = UsbIo;
// //
// Get the interface descriptor and validate that it is a USB mass // Get the interface descriptor and validate that it
// storage class CBI interface. // is a USB Mass Storage CBI interface.
// //
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface); Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
@ -118,7 +121,6 @@ UsbCbiInit (
UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1; UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1;
CopyMem(UsbCbi->BulkOutEndpoint, &EndPoint, sizeof (EndPoint)); CopyMem(UsbCbi->BulkOutEndpoint, &EndPoint, sizeof (EndPoint));
} }
} else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) { } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) {
// //
// Use the first interrupt endpoint if it is CBI0 // Use the first interrupt endpoint if it is CBI0
@ -132,10 +134,11 @@ UsbCbiInit (
} }
} }
if ((UsbCbi->BulkInEndpoint == NULL) if ((UsbCbi->BulkInEndpoint == NULL) || (UsbCbi->BulkOutEndpoint == NULL)) {
|| (UsbCbi->BulkOutEndpoint == NULL) Status = EFI_UNSUPPORTED;
|| ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) goto ON_ERROR;
&& (UsbCbi->InterruptEndpoint == NULL))) { }
if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) && (UsbCbi->InterruptEndpoint == NULL)) {
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;
goto ON_ERROR; goto ON_ERROR;
} }
@ -145,6 +148,7 @@ UsbCbiInit (
} else { } else {
gBS->FreePool (UsbCbi); gBS->FreePool (UsbCbi);
} }
return EFI_SUCCESS; return EFI_SUCCESS;
ON_ERROR: ON_ERROR:
@ -152,16 +156,18 @@ ON_ERROR:
return Status; return Status;
} }
/** /**
Send the command to the device using class specific control transfer. Send the command to the device using class specific control transfer.
This function sends command to the device using class specific control transfer.
The CBI contains three phases: Command, Data, and Status. This is Command phase.
@param UsbCbi The USB CBI protocol @param UsbCbi The USB CBI protocol
@param Cmd The high level command to transfer to device @param Cmd The high level command to transfer to device
@param CmdLen The length of the command @param CmdLen The length of the command
@param Timeout The time to wait the command to finish @param Timeout The time to wait the command to finish
@retval EFI_SUCCESS The command is transferred to device @retval EFI_SUCCESS The command is sent to the device.
@retval Others The command failed to transfer to device @retval Others The command failed to transfer to device
**/ **/
@ -181,7 +187,7 @@ UsbCbiSendCommand (
// //
// Fill in the device request, CBI use the "Accept Device-Specific // Fill in the device request, CBI use the "Accept Device-Specific
// Cmd" (ADSC) class specific request to send commands // Cmd" (ADSC) class specific request to send commands.
// //
Request.RequestType = 0x21; Request.RequestType = 0x21;
Request.Request = 0; Request.Request = 0;
@ -194,7 +200,7 @@ UsbCbiSendCommand (
for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) { for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
// //
// Use the UsbIo to send the command to the device // Use USB I/O Protocol to send the command to the device
// //
TransStatus = 0; TransStatus = 0;
DataLen = CmdLen; DataLen = CmdLen;
@ -226,16 +232,20 @@ UsbCbiSendCommand (
/** /**
Transfer data between the device and host. The CBI contains three phase, Transfer data between the device and host.
command, data, and status. This is data phase.
This function transfers data between the device and host.
The CBI contains three phases: Command, Data, and Status. This is Data phase.
@param UsbCbi The USB CBI device @param UsbCbi The USB CBI device
@param DataDir The direction of the data transfer @param DataDir The direction of the data transfer
@param Data The buffer to hold the data @param Data The buffer to hold the data for input or output.
@param TransLen The expected transfer length @param TransLen On input, the expected transfer length.
@param Timeout The time to wait the command to execute On output, the length of data actually transferred.
@param Timeout The time to wait for the command to execute
@retval EFI_SUCCESS The data transfer succeeded @retval EFI_SUCCESS The data transferred successfully.
@retval EFI_SUCCESS No data to transfer
@retval Others Failed to transfer all the data @retval Others Failed to transfer all the data
**/ **/
@ -257,7 +267,7 @@ UsbCbiDataTransfer (
UINTN Retry; UINTN Retry;
// //
// It's OK if no data to transfer // If no data to transfer, just return EFI_SUCCESS.
// //
if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) { if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
return EFI_SUCCESS; return EFI_SUCCESS;
@ -279,7 +289,7 @@ UsbCbiDataTransfer (
Timeout = Timeout / USB_MASS_1_MILLISECOND; Timeout = Timeout / USB_MASS_1_MILLISECOND;
// //
// Transfer the data, if the device returns NAK, retry it. // Transfer the data with a loop. The length of data transferred once is restricted.
// //
while (Remain > 0) { while (Remain > 0) {
TransStatus = 0; TransStatus = 0;
@ -302,15 +312,15 @@ UsbCbiDataTransfer (
if (TransStatus == EFI_USB_ERR_NAK) { if (TransStatus == EFI_USB_ERR_NAK) {
// //
// The device can NAK the host if either the data/buffer isn't // 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 // aviable or the command is in-progress.
// transferred. The transfer is aborted if several succssive data // If data are partially transferred, we just ignore NAK and continue.
// transfer commands are NAKed. // If all data have been transferred and status is NAK, then we retry for several times.
// If retry exceeds the USB_CBI_MAX_RETRY, then return error status.
// //
if (Increment == 0) { if (Increment == 0) {
if (++Retry > USB_CBI_MAX_RETRY) { if (++Retry > USB_CBI_MAX_RETRY) {
goto ON_EXIT; goto ON_EXIT;
} }
} else { } else {
Next += Increment; Next += Increment;
Remain -= Increment; Remain -= Increment;
@ -342,13 +352,15 @@ ON_EXIT:
/** /**
Get the result of high level command execution from interrupt Gets the result of high level command execution from interrupt endpoint.
endpoint. This function returns the USB transfer status, and
put the high level command execution result in Result. This function returns the USB transfer status, and put the high level
command execution result in Result.
The CBI contains three phases: Command, Data, and Status. This is Status phase.
@param UsbCbi The USB CBI protocol @param UsbCbi The USB CBI protocol
@param Timeout The time to wait the command to execute @param Timeout The time to wait for the command to execute
@param Result GC_TODO: add argument description @param Result The result of the command execution.
@retval EFI_SUCCESS The high level command execution result is @retval EFI_SUCCESS The high level command execution result is
retrieved in Result. retrieved in Result.
@ -404,7 +416,7 @@ UsbCbiGetStatus (
/** /**
Execute USB mass storage command through the CBI0/CBI1 transport protocol. Execute USB mass storage command through the CBI0/CBI1 transport protocol.
@param Context The USB CBI device @param Context The USB CBI Protocol.
@param Cmd The command to transfer to device @param Cmd The command to transfer to device
@param CmdLen The length of the command @param CmdLen The length of the command
@param DataDir The direction of data transfer @param DataDir The direction of data transfer
@ -414,7 +426,7 @@ UsbCbiGetStatus (
@param Timeout The time to wait @param Timeout The time to wait
@param CmdStatus The result of the command execution @param CmdStatus The result of the command execution
@retval EFI_SUCCESS The command is executed OK and result in CmdStatus. @retval EFI_SUCCESS The command is executed successfully.
@retval Other Failed to execute the command @retval Other Failed to execute the command
**/ **/
@ -450,7 +462,7 @@ UsbCbiExecCommand (
} }
// //
// Transfer the data, return this status if no interrupt endpoint // Transfer the data. Return this status if no interrupt endpoint
// is used to report the transfer status. // is used to report the transfer status.
// //
TransLen = (UINTN) DataLen; TransLen = (UINTN) DataLen;
@ -462,12 +474,12 @@ UsbCbiExecCommand (
} }
// //
// Get the status, if that succeeds, interpret the result // Get the status. If it succeeds, interpret the result.
// //
Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result); Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status)); DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status));
return EFI_DEVICE_ERROR; return Status;
} }
if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) { if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) {
@ -492,7 +504,8 @@ UsbCbiExecCommand (
case 0x02: case 0x02:
// //
// Phase Error, response with reset. Fall through to Fail. // Phase Error, response with reset.
// No break here to fall through to "Fail".
// //
UsbCbiResetDevice (UsbCbi, FALSE); UsbCbiResetDevice (UsbCbi, FALSE);
@ -505,7 +518,7 @@ UsbCbiExecCommand (
case 0x03: case 0x03:
// //
// Persistent Fail, need to send REQUEST SENSE. // Persistent Fail. Need to send REQUEST SENSE.
// //
*CmdStatus = USB_MASS_CMD_PERSISTENT; *CmdStatus = USB_MASS_CMD_PERSISTENT;
break; break;
@ -517,16 +530,18 @@ UsbCbiExecCommand (
/** /**
Call the Usb mass storage class transport protocol to Reset the USB mass storage device by CBI protocol.
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 This function resets the USB mass storage device by CBI protocol.
@param ExtendedVerification The flag controlling the rule of reset 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.
@retval EFI_SUCCESS the device is reset @param Context The USB CBI protocol
@retval Others Failed to reset the device @param ExtendedVerification The flag controlling the rule of reset.
Not used here.
@retval EFI_SUCCESS The device is reset.
@retval Others Failed to reset the device.
**/ **/
EFI_STATUS EFI_STATUS
@ -562,17 +577,17 @@ UsbCbiResetDevice (
// //
// Just retrieve the status and ignore that. Then stall // Just retrieve the status and ignore that. Then stall
// 50ms to wait it complete // 50ms to wait for it to complete.
// //
UsbCbiGetStatus (UsbCbi, Timeout, &Result); UsbCbiGetStatus (UsbCbi, Timeout, &Result);
gBS->Stall (USB_CBI_RESET_DEVICE_STALL); gBS->Stall (USB_CBI_RESET_DEVICE_STALL);
// //
// Clear the Bulk-In and Bulk-Out stall condition and // Clear the Bulk-In and Bulk-Out stall condition and init data toggle.
// init data toggle.
// //
UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress); UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress);
UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress); UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress);
return Status; return Status;
} }
@ -586,30 +601,10 @@ UsbCbiResetDevice (
**/ **/
EFI_STATUS EFI_STATUS
UsbCbiFini ( UsbCbiCleanUp (
IN VOID *Context IN VOID *Context
) )
{ {
gBS->FreePool (Context); gBS->FreePool (Context);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
USB_MASS_TRANSPORT
mUsbCbi0Transport = {
USB_MASS_STORE_CBI0,
UsbCbiInit,
UsbCbiExecCommand,
UsbCbiResetDevice,
NULL,
UsbCbiFini
};
USB_MASS_TRANSPORT
mUsbCbi1Transport = {
USB_MASS_STORE_CBI1,
UsbCbiInit,
UsbCbiExecCommand,
UsbCbiResetDevice,
NULL,
UsbCbiFini
};

View File

@ -1,6 +1,6 @@
/** @file /** @file
Defination for the USB mass storage Control/Bulk/Interrupt (CBI) transport,
Defination for the USB mass storage Control/Bulk/Interrupt transport. according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.
Copyright (c) 2007 - 2008, Intel Corporation Copyright (c) 2007 - 2008, Intel Corporation
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
@ -16,31 +16,33 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#ifndef _EFI_USBMASS_CBI_H_ #ifndef _EFI_USBMASS_CBI_H_
#define _EFI_USBMASS_CBI_H_ #define _EFI_USBMASS_CBI_H_
extern USB_MASS_TRANSPORT mUsbCbi0Transport;
extern USB_MASS_TRANSPORT mUsbCbi1Transport;
typedef enum { typedef enum {
USB_CBI_MAX_PACKET_NUM = 16, USB_CBI_MAX_PACKET_NUM = 16,
USB_CBI_RESET_CMD_LEN = 12, USB_CBI_RESET_CMD_LEN = 12,
// //
// Usb Cbi retry C/B/I transport times, set by experience // USB CBI retry C/B/I transport times, set by experience
// //
USB_CBI_MAX_RETRY = 3, USB_CBI_MAX_RETRY = 3,
// //
// Usb Cbi wait device reset complete, set by experience // Time to wait for USB CBI reset to complete, set by experience
// //
USB_CBI_RESET_DEVICE_STALL = 50 * USB_MASS_1_MILLISECOND, USB_CBI_RESET_DEVICE_STALL = 50 * USB_MASS_1_MILLISECOND,
// //
// Usb Cbi transport timeout, set by experience // USB CBI transport timeout, set by experience
// //
USB_CBI_RESET_DEVICE_TIMEOUT = 1 * USB_MASS_1_SECOND USB_CBI_RESET_DEVICE_TIMEOUT = 1 * USB_MASS_1_SECOND
}USB_CBI_DATA; } USB_CBI_DATA;
//
// Put Interface at the first field is to make it easy to get by Context, which
// could be BOT/CBI Protocol instance
//
typedef struct { typedef struct {
//
// Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance
//
EFI_USB_INTERFACE_DESCRIPTOR Interface; EFI_USB_INTERFACE_DESCRIPTOR Interface;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint; EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint; EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
@ -55,6 +57,89 @@ typedef struct {
} USB_CBI_STATUS; } USB_CBI_STATUS;
#pragma pack() #pragma pack()
extern USB_MASS_TRANSPORT mUsbCbi0Transport; /**
extern USB_MASS_TRANSPORT mUsbCbi1Transport; Initializes USB CBI protocol.
This function initializes the USB mass storage class CBI protocol.
It will save its context which is a USB_CBI_PROTOCOL structure
in the Context if Context isn't NULL.
@param UsbIo The USB I/O Protocol instance
@param Context The buffer to save the context to
@retval EFI_SUCCESS The device is successfully initialized.
@retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
@retval Other The USB CBI initialization fails.
**/
EFI_STATUS
UsbCbiInit (
IN EFI_USB_IO_PROTOCOL *UsbIo,
OUT VOID **Context OPTIONAL
);
/**
Execute USB mass storage command through the CBI0/CBI1 transport protocol.
@param Context The USB CBI Protocol.
@param Cmd The command to transfer to device
@param CmdLen The length of the command
@param DataDir The direction of data transfer
@param Data The buffer to hold the data
@param DataLen The length of the buffer
@param Lun Should be 0, this field for bot only
@param Timeout The time to wait
@param CmdStatus The result of the command execution
@retval EFI_SUCCESS The command is executed successfully.
@retval Other Failed to execute the command
**/
EFI_STATUS
UsbCbiExecCommand (
IN VOID *Context,
IN VOID *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN VOID *Data,
IN UINT32 DataLen,
IN UINT8 Lun,
IN UINT32 Timeout,
OUT UINT32 *CmdStatus
);
/**
Reset the USB mass storage device by CBI protocol.
This function resets the USB mass storage device by CBI protocol.
The reset is defined as a non-data command. Don't use UsbCbiExecCommand
to send the command to device because that may introduce recursive loop.
@param Context The USB CBI protocol
@param ExtendedVerification The flag controlling the rule of reset.
Not used here.
@retval EFI_SUCCESS The device is reset.
@retval Others Failed to reset the device.
**/
EFI_STATUS
UsbCbiResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
);
/**
Clean up the CBI protocol's resource.
@param Context The instance of CBI protocol.
@retval EFI_SUCCESS The resource is cleaned up.
**/
EFI_STATUS
UsbCbiCleanUp (
IN VOID *Context
);
#endif #endif

View File

@ -1,8 +1,5 @@
/** @file /** @file
USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol.
The implementation of USB mass storage class device driver.
The command set supported is "USB Mass Storage Specification
for Bootability".
Copyright (c) 2007 - 2008, Intel Corporation Copyright (c) 2007 - 2008, Intel Corporation
All rights reserved. This program and the accompanying materials All rights reserved. This program and the accompanying materials
@ -17,6 +14,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "UsbMassImpl.h" #include "UsbMassImpl.h"
//
// Array of USB transport interfaces.
//
USB_MASS_TRANSPORT *mUsbMassTransport[] = { USB_MASS_TRANSPORT *mUsbMassTransport[] = {
&mUsbCbi0Transport, &mUsbCbi0Transport,
&mUsbCbi1Transport, &mUsbCbi1Transport,
@ -24,14 +24,28 @@ USB_MASS_TRANSPORT *mUsbMassTransport[] = {
NULL NULL
}; };
EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
USBMassDriverBindingSupported,
USBMassDriverBindingStart,
USBMassDriverBindingStop,
0x11,
NULL,
NULL
};
/** /**
Reset the block device. ExtendedVerification is ignored for this. Reset the block device.
@param This The BLOCK IO protocol This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
@param ExtendedVerification Whether to execute extended verification. It resets the block device hardware.
ExtendedVerification is ignored in this implementation.
@retval EFI_SUCCESS The device is successfully reseted. @param This Indicates a pointer to the calling context.
@retval Others Failed to reset the device. @param ExtendedVerification Indicates that the driver may perform a more exhaustive
verification operation of the device during reset.
@retval EFI_SUCCESS The block device was reset.
@retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
**/ **/
EFI_STATUS EFI_STATUS
@ -45,9 +59,13 @@ UsbMassReset (
EFI_TPL OldTpl; EFI_TPL OldTpl;
EFI_STATUS Status; EFI_STATUS Status;
OldTpl = gBS->RaiseTPL (USB_MASS_TPL); //
// Raise TPL to TPL_NOTIFY to serialize all its operations
// to protect shared data structures.
//
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This); UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification); Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
gBS->RestoreTPL (OldTpl); gBS->RestoreTPL (OldTpl);
@ -56,22 +74,27 @@ UsbMassReset (
} }
/** /**
Read some blocks of data from the block device. Reads the requested number of blocks from the device.
@param This The Block IO protocol This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
@param MediaId The media's ID of the device for current request It reads the requested number of blocks from the device.
@param Lba The start block number All the blocks are read, or an error is returned.
@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 @param This Indicates a pointer to the calling context.
@retval EFI_NO_MEDIA Media isn't present @param MediaId The media ID that the read request is for.
@retval EFI_MEDIA_CHANGED The device media has been changed, that is, @param Lba The starting logical block address to read from on the device.
MediaId changed @param BufferSize The size of the Buffer in bytes.
@retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is This must be a multiple of the intrinsic block size of the device.
NULL. @param Buffer A pointer to the destination buffer for the data. The caller is
@retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block responsible for either having implicit or explicit ownership of the buffer.
size, or overflow the last block number.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/ **/
EFI_STATUS EFI_STATUS
@ -90,34 +113,35 @@ UsbMassReadBlocks (
EFI_TPL OldTpl; EFI_TPL OldTpl;
UINTN TotalBlock; UINTN TotalBlock;
OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
Media = &UsbMass->BlockIoMedia;
// //
// First, validate the parameters // First, validate the parameters
// //
if ((Buffer == NULL) || (BufferSize == 0)) { if ((Buffer == NULL) || (BufferSize == 0)) {
Status = EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
goto ON_EXIT;
} }
//
// Raise TPL to TPL_NOTIFY to serialize all its operations
// to protect shared data structures.
//
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
Media = &UsbMass->BlockIoMedia;
// //
// If it is a removable media, such as CD-Rom or Usb-Floppy, // If it is a removable media, such as CD-Rom or Usb-Floppy,
// need to detect the media before each rw. While some of // need to detect the media before each read/write. While some of
// Usb-Flash is marked as removable media. // Usb-Flash is marked as removable media.
// //
// if (Media->RemovableMedia) {
if (Media->RemovableMedia == TRUE) {
Status = UsbBootDetectMedia (UsbMass); Status = UsbBootDetectMedia (UsbMass);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));
goto ON_EXIT; goto ON_EXIT;
} }
} }
// //
// Make sure BlockSize and LBA is consistent with BufferSize // BufferSize must be a multiple of the intrinsic block size of the device.
// //
if ((BufferSize % Media->BlockSize) != 0) { if ((BufferSize % Media->BlockSize) != 0) {
Status = EFI_BAD_BUFFER_SIZE; Status = EFI_BAD_BUFFER_SIZE;
@ -126,6 +150,9 @@ UsbMassReadBlocks (
TotalBlock = BufferSize / Media->BlockSize; TotalBlock = BufferSize / Media->BlockSize;
//
// Make sure the range to read is valid.
//
if (Lba + TotalBlock - 1 > Media->LastBlock) { if (Lba + TotalBlock - 1 > Media->LastBlock) {
Status = EFI_INVALID_PARAMETER; Status = EFI_INVALID_PARAMETER;
goto ON_EXIT; goto ON_EXIT;
@ -154,22 +181,28 @@ ON_EXIT:
/** /**
Write some blocks of data to the block device. Writes a specified number of blocks to the device.
@param This The Block IO protocol This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
@param MediaId The media's ID of the device for current request It writes a specified number of blocks to the device.
@param Lba The start block number All blocks are written, or an error is returned.
@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 @param This Indicates a pointer to the calling context.
@retval EFI_NO_MEDIA Media isn't present @param MediaId The media ID that the write request is for.
@retval EFI_MEDIA_CHANGED The device media has been changed, that is, @param Lba The starting logical block address to be written.
MediaId changed @param BufferSize The size of the Buffer in bytes.
@retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is This must be a multiple of the intrinsic block size of the device.
NULL. @param Buffer Pointer to the source buffer for the data.
@retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
size, @retval EFI_SUCCESS The data were written correctly to the device.
@retval EFI_WRITE_PROTECTED The device cannot be written to.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/ **/
EFI_STATUS EFI_STATUS
@ -188,34 +221,35 @@ UsbMassWriteBlocks (
EFI_TPL OldTpl; EFI_TPL OldTpl;
UINTN TotalBlock; UINTN TotalBlock;
OldTpl = gBS->RaiseTPL (USB_MASS_TPL);
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
Media = &UsbMass->BlockIoMedia;
// //
// First, validate the parameters // First, validate the parameters
// //
if ((Buffer == NULL) || (BufferSize == 0)) { if ((Buffer == NULL) || (BufferSize == 0)) {
Status = EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
goto ON_EXIT;
} }
//
// Raise TPL to TPL_NOTIFY to serialize all its operations
// to protect shared data structures.
//
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This);
Media = &UsbMass->BlockIoMedia;
// //
// If it is a removable media, such as CD-Rom or Usb-Floppy, // If it is a removable media, such as CD-Rom or Usb-Floppy,
// need to detect the media before each rw. While some of // need to detect the media before each read/write. Some of
// Usb-Flash is marked as removable media. // USB Flash is marked as removable media.
// //
// if (Media->RemovableMedia) {
if (Media->RemovableMedia == TRUE) {
Status = UsbBootDetectMedia (UsbMass); Status = UsbBootDetectMedia (UsbMass);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));
goto ON_EXIT; goto ON_EXIT;
} }
} }
// //
// Make sure BlockSize and LBA is consistent with BufferSize // BufferSize must be a multiple of the intrinsic block size of the device.
// //
if ((BufferSize % Media->BlockSize) != 0) { if ((BufferSize % Media->BlockSize) != 0) {
Status = EFI_BAD_BUFFER_SIZE; Status = EFI_BAD_BUFFER_SIZE;
@ -224,6 +258,9 @@ UsbMassWriteBlocks (
TotalBlock = BufferSize / Media->BlockSize; TotalBlock = BufferSize / Media->BlockSize;
//
// Make sure the range to write is valid.
//
if (Lba + TotalBlock - 1 > Media->LastBlock) { if (Lba + TotalBlock - 1 > Media->LastBlock) {
Status = EFI_INVALID_PARAMETER; Status = EFI_INVALID_PARAMETER;
goto ON_EXIT; goto ON_EXIT;
@ -255,12 +292,17 @@ ON_EXIT:
} }
/** /**
Flush the cached writes to disks. USB mass storage device doesn't Flushes all modified data to a physical block device.
support write cache, so return EFI_SUCCESS directly.
@param This The BLOCK IO protocol This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
USB mass storage device doesn't support write cache,
so return EFI_SUCCESS directly.
@retval EFI_SUCCESS Always returns success @param This Indicates a pointer to the calling context.
@retval EFI_SUCCESS All outstanding data were written correctly to the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
@retval EFI_NO_MEDIA There is no media in the device.
**/ **/
EFI_STATUS EFI_STATUS
@ -273,12 +315,11 @@ UsbMassFlushBlocks (
} }
/** /**
Retrieve the media parameters such as disk geometric for the Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol.
device's BLOCK IO protocol.
@param UsbMass The USB mass storage device @param UsbMass The USB mass storage device
@retval EFI_SUCCESS The media parameters is updated successfully. @retval EFI_SUCCESS The media parameters are updated successfully.
@retval Others Failed to get the media parameters. @retval Others Failed to get the media parameters.
**/ **/
@ -294,18 +335,8 @@ UsbMassInitMedia (
Media = &UsbMass->BlockIoMedia; Media = &UsbMass->BlockIoMedia;
// //
// Initialize the MediaPrsent/ReadOnly and others to the default. // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec,
// We are not forced to get it right at this time, check UEFI2.0 // section for Block I/O Protocol.
// 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->MediaPresent = FALSE;
Media->LogicalPartition = FALSE; Media->LogicalPartition = FALSE;
@ -323,9 +354,7 @@ UsbMassInitMedia (
for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) { for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) {
Status = UsbBootGetParams (UsbMass); Status = UsbBootGetParams (UsbMass);
if ((Status != EFI_MEDIA_CHANGED) if ((Status != EFI_MEDIA_CHANGED) && (Status != EFI_NOT_READY) && (Status != EFI_TIMEOUT)) {
&& (Status != EFI_NOT_READY)
&& (Status != EFI_TIMEOUT)) {
break; break;
} }
@ -333,14 +362,16 @@ UsbMassInitMedia (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1)); gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1));
} }
} }
return Status; return Status;
} }
/** /**
Initilize the transport. Initilize the USB Mass Storage transport.
This function tries to find the matching USB Mass Storage transport
protocol for USB device. If found, initializes the matching transport.
@param This The USB mass driver's driver binding. @param This The USB mass driver's driver binding.
@param Controller The device to test. @param Controller The device to test.
@ -349,6 +380,7 @@ UsbMassInitMedia (
@param MaxLun Get the MaxLun if is BOT dev. @param MaxLun Get the MaxLun if is BOT dev.
@retval EFI_SUCCESS The initialization is successful. @retval EFI_SUCCESS The initialization is successful.
@retval EFI_UNSUPPORTED No matching transport protocol is found.
@retval Others Failed to initialize dev. @retval Others Failed to initialize dev.
**/ **/
@ -376,18 +408,22 @@ UsbMassInitTransport (
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: OpenUsbIoProtocol By Driver (%r)\n", Status));
return Status; return Status;
} }
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));
goto ON_EXIT; goto ON_EXIT;
} }
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;
//
// Traverse the USB_MASS_TRANSPORT arrary and try to find the
// matching transport protocol.
// If not found, return EFI_UNSUPPORTED.
// If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
//
for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) { for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
*Transport = mUsbMassTransport[Index]; *Transport = mUsbMassTransport[Index];
@ -398,17 +434,16 @@ UsbMassInitTransport (
} }
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: Transport->Init (%r)\n", Status));
goto ON_EXIT; goto ON_EXIT;
} }
// //
// For bot device, try to get max lun. // For BOT device, try to get its max LUN.
// If maxlun=0, then non-lun device, else multi-lun device. // If max LUN is 0, then it is a non-lun device.
// Otherwise, it is a multi-lun device.
// //
if ((*Transport)->Protocol == USB_MASS_STORE_BOT) { if ((*Transport)->Protocol == USB_MASS_STORE_BOT) {
(*Transport)->GetMaxLun (*Context, MaxLun); (*Transport)->GetMaxLun (*Context, MaxLun);
DEBUG ((EFI_D_INFO, "UsbMassInitTransport: GetMaxLun = %d\n", *MaxLun));
} }
ON_EXIT: ON_EXIT:
@ -687,13 +722,12 @@ ON_ERROR:
/** /**
Check whether the controller is a supported USB mass storage. Check whether the controller is a supported USB mass storage.
@param This The USB mass driver's driver binding. @param This The USB mass storage driver binding protocol.
@param Controller The device to test against. @param Controller The controller handle to check.
@param RemainingDevicePath The remaining device path @param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS This device is a supported USB mass storage. @retval EFI_SUCCESS The driver supports this controller.
@retval EFI_UNSUPPORTED The device isn't supported @retval other This device isn't supported.
@retval Others Some error happened.
**/ **/
EFI_STATUS EFI_STATUS
@ -708,11 +742,8 @@ USBMassDriverBindingSupported (
EFI_USB_INTERFACE_DESCRIPTOR Interface; EFI_USB_INTERFACE_DESCRIPTOR Interface;
USB_MASS_TRANSPORT *Transport; USB_MASS_TRANSPORT *Transport;
EFI_STATUS Status; EFI_STATUS Status;
INTN Index; UINTN Index;
//
// Check whether the controller support USB_IO
//
Status = gBS->OpenProtocol ( Status = gBS->OpenProtocol (
Controller, Controller,
&gEfiUsbIoProtocolGuid, &gEfiUsbIoProtocolGuid,
@ -726,7 +757,7 @@ USBMassDriverBindingSupported (
} }
// //
// Get the interface to check the USB class and find a transport // Get the interface descriptor to check the USB class and find a transport
// protocol handler. // protocol handler.
// //
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
@ -740,6 +771,12 @@ USBMassDriverBindingSupported (
goto ON_EXIT; goto ON_EXIT;
} }
//
// Traverse the USB_MASS_TRANSPORT arrary and try to find the
// matching transport method.
// If not found, return EFI_UNSUPPORTED.
// If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context.
//
for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) { for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
Transport = mUsbMassTransport[Index]; Transport = mUsbMassTransport[Index];
if (Interface.InterfaceProtocol == Transport->Protocol) { if (Interface.InterfaceProtocol == Transport->Protocol) {
@ -748,31 +785,34 @@ USBMassDriverBindingSupported (
} }
} }
DEBUG ((EFI_D_INFO, "Found a USB mass store device %r\n", Status));
ON_EXIT: ON_EXIT:
gBS->CloseProtocol ( gBS->CloseProtocol (
Controller, Controller,
&gEfiUsbIoProtocolGuid, &gEfiUsbIoProtocolGuid,
This->DriverBindingHandle, This->DriverBindingHandle,
Controller Controller
); );
return Status; return Status;
} }
/** /**
Start the USB mass storage device on the controller. It will Starts the USB mass storage device with this driver.
install a BLOCK_IO protocol on the device if everything is OK.
@param This The USB mass storage driver binding. This function consumes USB I/O Portocol, intializes USB mass storage device,
installs Block I/O Protocol, and submits Asynchronous Interrupt
Transfer to manage the USB mass storage device.
@param This The USB mass storage driver binding protocol.
@param Controller The USB mass storage device to start on @param Controller The USB mass storage device to start on
@param RemainingDevicePath The remaining device path. @param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS The driver has started on the device. @retval EFI_SUCCESS This driver supports this device.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory @retval EFI_UNSUPPORTED This driver does not support this device.
@retval Others Failed to start the driver on the device. @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
@retval EFI_ALREADY_STARTED This driver has been started.
**/ **/
EFI_STATUS EFI_STATUS
@ -831,7 +871,7 @@ USBMassDriverBindingStart (
// //
// Try best to initialize all LUNs, and return success only if one of LUNs successed to initialized. // Try best to initialize all LUNs, and return success only if one of LUNs successed to initialized.
// //
Status = UsbMassInitMultiLun(This, Controller, Transport, Context, DevicePath, MaxLun); Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
gBS->CloseProtocol ( gBS->CloseProtocol (
Controller, Controller,
@ -913,7 +953,7 @@ USBMassDriverBindingStop (
// This is a 1st type handle(non-multi-lun), which only needs uninstall // This is a 1st type handle(non-multi-lun), which only needs uninstall
// blockio protocol, close usbio protocol and free mass device. // blockio protocol, close usbio protocol and free mass device.
// //
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo); UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
// //
// Uninstall Block I/O protocol from the device handle, // Uninstall Block I/O protocol from the device handle,
@ -935,7 +975,7 @@ USBMassDriverBindingStop (
Controller Controller
); );
UsbMass->Transport->Fini (UsbMass->Context); UsbMass->Transport->CleanUp (UsbMass->Context);
gBS->FreePool (UsbMass); gBS->FreePool (UsbMass);
DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n")); DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n"));
@ -965,7 +1005,7 @@ USBMassDriverBindingStop (
continue; continue;
} }
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo); UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo);
gBS->CloseProtocol ( gBS->CloseProtocol (
Controller, Controller,
@ -1003,7 +1043,7 @@ USBMassDriverBindingStop (
// Success to stop this multi-lun handle, so go on next child. // Success to stop this multi-lun handle, so go on next child.
// //
if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) { if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) {
UsbMass->Transport->Fini (UsbMass->Context); UsbMass->Transport->CleanUp (UsbMass->Context);
} }
gBS->FreePool (UsbMass); gBS->FreePool (UsbMass);
} }
@ -1017,15 +1057,6 @@ USBMassDriverBindingStop (
return EFI_SUCCESS; return EFI_SUCCESS;
} }
EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
USBMassDriverBindingSupported,
USBMassDriverBindingStart,
USBMassDriverBindingStop,
0x11,
NULL,
NULL
};
/** /**
The entry point for the driver, which will install the driver binding and The entry point for the driver, which will install the driver binding and
component name protocol. component name protocol.
@ -1057,6 +1088,7 @@ USBMassStorageEntryPoint (
&gUsbMassStorageComponentName, &gUsbMassStorageComponentName,
&gUsbMassStorageComponentName2 &gUsbMassStorageComponentName2
); );
ASSERT_EFI_ERROR (Status);
return Status; return EFI_SUCCESS;
} }

View File

@ -23,16 +23,8 @@ typedef struct _USB_MASS_DEVICE USB_MASS_DEVICE;
#include "UsbMassCbi.h" #include "UsbMassCbi.h"
#include "UsbMassBoot.h" #include "UsbMassBoot.h"
//
// MassStorage raises TPL to TPL_NOTIFY to serialize all its operations
// to protect shared data structures.
//
#define USB_MASS_TPL TPL_NOTIFY
#define USB_MASS_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'M') #define USB_MASS_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'M')
struct _USB_MASS_DEVICE { struct _USB_MASS_DEVICE {
UINT32 Signature; UINT32 Signature;
EFI_HANDLE Controller; EFI_HANDLE Controller;
@ -47,10 +39,196 @@ struct _USB_MASS_DEVICE {
VOID *Context; // Opaque storage for mass transport VOID *Context; // Opaque storage for mass transport
}; };
#define USB_MASS_DEVICE_FROM_BLOCKIO(a) \ #define USB_MASS_DEVICE_FROM_BLOCK_IO(a) \
CR (a, USB_MASS_DEVICE, BlockIo, USB_MASS_SIGNATURE) CR (a, USB_MASS_DEVICE, BlockIo, USB_MASS_SIGNATURE)
extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName; extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMassStorageComponentName2; extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMassStorageComponentName2;
//
// Functions for Driver Binding Protocol
//
/**
Check whether the controller is a supported USB mass storage.
@param This The USB mass storage driver binding protocol.
@param Controller The controller handle to check.
@param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS The driver supports this controller.
@retval other This device isn't supported.
**/
EFI_STATUS
EFIAPI
USBMassDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Starts the USB mass storage device with this driver.
This function consumes USB I/O Portocol, intializes USB mass storage device,
installs Block I/O Protocol, and submits Asynchronous Interrupt
Transfer to manage the USB mass storage device.
@param This The USB mass storage driver binding protocol.
@param Controller The USB mass storage device to start on
@param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS This driver supports this device.
@retval EFI_UNSUPPORTED This driver does not support this device.
@retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
@retval EFI_ALREADY_STARTED This driver has been started.
**/
EFI_STATUS
EFIAPI
USBMassDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
);
/**
Stop controlling the device.
@param This The USB mass storage driver binding
@param Controller The device controller controlled by the driver.
@param NumberOfChildren The number of children of this device
@param ChildHandleBuffer The buffer of children handle.
@retval EFI_SUCCESS The driver stopped from controlling the device.
@retval Others Failed to stop the driver
**/
EFI_STATUS
EFIAPI
USBMassDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
//
// Functions for Block I/O Protocol
//
/**
Reset the block device.
This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
It resets the block device hardware.
ExtendedVerification is ignored in this implementation.
@param This Indicates a pointer to the calling context.
@param ExtendedVerification Indicates that the driver may perform a more exhaustive
verification operation of the device during reset.
@retval EFI_SUCCESS The block device was reset.
@retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset.
**/
EFI_STATUS
EFIAPI
UsbMassReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
);
/**
Reads the requested number of blocks from the device.
This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
It reads the requested number of blocks from the device.
All the blocks are read, or an error is returned.
@param This Indicates a pointer to the calling context.
@param MediaId The media ID that the read request is for.
@param Lba The starting logical block address to read from on the device.
@param BufferSize The size of the Buffer in bytes.
This must be a multiple of the intrinsic block size of the device.
@param Buffer A pointer to the destination buffer for the data. The caller is
responsible for either having implicit or explicit ownership of the buffer.
@retval EFI_SUCCESS The data was read correctly from the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
UsbMassReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Writes a specified number of blocks to the device.
This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
It writes a specified number of blocks to the device.
All blocks are written, or an error is returned.
@param This Indicates a pointer to the calling context.
@param MediaId The media ID that the write request is for.
@param Lba The starting logical block address to be written.
@param BufferSize The size of the Buffer in bytes.
This must be a multiple of the intrinsic block size of the device.
@param Buffer Pointer to the source buffer for the data.
@retval EFI_SUCCESS The data were written correctly to the device.
@retval EFI_WRITE_PROTECTED The device cannot be written to.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic
block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
**/
EFI_STATUS
EFIAPI
UsbMassWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
);
/**
Flushes all modified data to a physical block device.
This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks().
USB mass storage device doesn't support write cache,
so return EFI_SUCCESS directly.
@param This Indicates a pointer to the calling context.
@retval EFI_SUCCESS All outstanding data were written correctly to the device.
@retval EFI_DEVICE_ERROR The device reported an error while attempting to write data.
@retval EFI_NO_MEDIA There is no media in the device.
**/
EFI_STATUS
EFIAPI
UsbMassFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
);
#endif #endif