Import Usb/UsbBusDxe and Usb/UsbMassStorageDxe into MdeModulePkg.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3193 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
vanjeff
2007-07-11 08:47:37 +00:00
parent f183b4f349
commit e237e7ae9f
25 changed files with 10355 additions and 0 deletions

View File

@@ -0,0 +1,153 @@
/*++
Copyright (c) 2004 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
ComponentName.c
Abstract:
--*/
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The Library classes this module consumes
//
#include <Library/UefiLib.h>
//
// EFI Component Name Functions
//
EFI_STATUS
EFIAPI
UsbMassStorageGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
UsbMassStorageGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName = {
UsbMassStorageGetDriverName,
UsbMassStorageGetControllerName,
"eng"
};
STATIC EFI_UNICODE_STRING_TABLE
mUsbMassStorageDriverNameTable[] = {
{"eng", L"Usb Mass Storage Driver"},
{NULL, NULL}
};
EFI_STATUS
EFIAPI
UsbMassStorageGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
Language - A pointer to a three character ISO 639-2 language identifier.
This is the language of the driver name that that the caller
is requesting, and it must match one of the languages specified
in SupportedLanguages. The number of languages supported by a
driver is up to the driver writer.
DriverName - A pointer to the Unicode string to return. This Unicode string
is the name of the driver specified by This in the language
specified by Language.
Returns:
EFI_SUCCESS - The Unicode string for the Driver specified by This
and the language specified by Language was returned
in DriverName.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - DriverName is NULL.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return LookupUnicodeString (
Language,
gUsbMassStorageComponentName.SupportedLanguages,
mUsbMassStorageDriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
UsbMassStorageGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
/*++
Routine Description:
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by an EFI Driver.
Arguments:
This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
ControllerHandle - The handle of a controller that the driver specified by
This is managing. This handle specifies the controller
whose name is to be returned.
ChildHandle - The handle of the child controller to retrieve the name
of. This is an optional parameter that may be NULL. It
will be NULL for device drivers. It will also be NULL
for a bus drivers that wish to retrieve the name of the
bus controller. It will not be NULL for a bus driver
that wishes to retrieve the name of a child controller.
Language - A pointer to a three character ISO 639-2 language
identifier. This is the language of the controller name
that that the caller is requesting, and it must match one
of the languages specified in SupportedLanguages. The
number of languages supported by a driver is up to the
driver writer.
ControllerName - A pointer to the Unicode string to return. This Unicode
string is the name of the controller specified by
ControllerHandle and ChildHandle in the language specified
by Language from the point of view of the driver specified
by This.
Returns:
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@@ -0,0 +1,149 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMass.h
Abstract:
Defination for the USB mass storage class driver. The USB mass storage
class is specified in two layers: the bottom layer is the transportation
protocol. The top layer is the command set. The transportation layer
provides the transportation of the command, data and result. The command
set defines what the command, data and result. The Bulk-Only-Transport and
Control/Bulk/Interrupt transport are two transportation protocol. USB mass
storage class adopts various industrial standard as its command set.
Revision History
**/
#ifndef _EFI_USBMASS_H_
#define _EFI_USBMASS_H_
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Protocol/BlockIo.h>
#include <Protocol/UsbIo.h>
//
// The Library classes this module consumes
//
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/MemoryAllocationLib.h>
#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0x80)
#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0)
#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x02)
#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x03)
#define USB_IS_ERROR(Result, Error) (((Result) & (Error)) != 0)
enum {
//
// Usb mass storage class code
//
USB_MASS_STORE_CLASS = 0x08,
//
// Usb mass storage subclass code, specify the command set used.
//
USB_MASS_STORE_RBC = 0x01, // Reduced Block Commands
USB_MASS_STORE_8020I = 0x02, // SFF-8020i, typically a CD/DVD device
USB_MASS_STORE_QIC = 0x03, // Typically a tape device
USB_MASS_STORE_UFI = 0x04, // Typically a floopy disk driver device
USB_MASS_STORE_8070I = 0x05, // SFF-8070i, typically a floppy disk driver device.
USB_MASS_STORE_SCSI = 0x06, // SCSI transparent command set
//
// Usb mass storage protocol code, specify the transport protocol
//
USB_MASS_STORE_CBI0 = 0x00, // CBI protocol with command completion interrupt
USB_MASS_STORE_CBI1 = 0x01, // CBI protocol without command completion interrupt
USB_MASS_STORE_BOT = 0x50, // Bulk-Only Transport
USB_MASS_STALL_1_MS = 1000,
USB_MASS_STALL_1_S = 1000 * USB_MASS_STALL_1_MS,
USB_MASS_CMD_SUCCESS = 0,
USB_MASS_CMD_FAIL,
USB_MASS_CMD_PERSISTENT,
};
typedef
EFI_STATUS
(*USB_MASS_INIT_TRANSPORT) (
IN EFI_USB_IO_PROTOCOL *Usb,
IN EFI_HANDLE Controller,
OUT VOID **Context OPTIONAL
);
typedef
EFI_STATUS
(*USB_MASS_EXEC_COMMAND) (
IN VOID *Context,
IN VOID *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN VOID *Data,
IN UINT32 DataLen,
IN UINT32 Timeout,
OUT UINT32 *CmdStatus
);
typedef
EFI_STATUS
(*USB_MASS_RESET) (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
);
typedef
EFI_STATUS
(*USB_MASS_FINI) (
IN VOID *Context
);
//
// This structure contains information necessary to select the
// proper transport protocol. The mass storage class defines
// two transport protocols. One is the CBI, and the other is BOT.
// CBI is being obseleted. The design is made modular by this
// structure so that the CBI protocol can be easily removed when
// it is no longer necessary.
//
typedef struct {
UINT8 Protocol;
USB_MASS_INIT_TRANSPORT Init; // Initialize the mass storage transport protocol
USB_MASS_EXEC_COMMAND ExecCommand; // Transport command to the device then get result
USB_MASS_RESET Reset; // Reset the device
USB_MASS_FINI Fini; // Clean up the resources.
} USB_MASS_TRANSPORT;
EFI_STATUS
UsbClearEndpointStall (
IN EFI_USB_IO_PROTOCOL *UsbIo,
IN UINT8 EndpointAddress
);
extern UINTN mUsbMscInfo;
extern UINTN mUsbMscError;
#endif

View File

@@ -0,0 +1,886 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassBoot.c
Abstract:
This file implement the command set of "USB Mass Storage Specification
for Bootability".
Revision History
**/
#include "UsbMassImpl.h"
/**
Read an UINT32 from the buffer to avoid byte alignment problems, then
convert that to the little endia. The USB mass storage bootability spec
use big endia
@param Buf The buffer contains the first byte of the UINT32
in big endia.
@return The UINT32 value read from the buffer in little endia.
**/
STATIC
UINT32
UsbBootGetUint32 (
IN UINT8 *Buf
)
{
UINT32 Value;
CopyMem (&Value, Buf, sizeof (UINT32));
return USB_BOOT_SWAP32 (Value);
}
/**
Put an UINT32 in little endia to the buffer. The data is converted to
big endia before writing.
@param Buf The buffer to write data to
@param Data32 The data to write.
@return None
**/
STATIC
VOID
UsbBootPutUint32 (
IN UINT8 *Buf,
IN UINT32 Data32
)
{
Data32 = USB_BOOT_SWAP32 (Data32);
CopyMem (Buf, &Data32, sizeof (UINT32));
}
/**
Put an UINT16 in little endia to the buffer. The data is converted to
big endia before writing.
@param Buf The buffer to write data to
@param Data16 The data to write
@return None
**/
STATIC
VOID
UsbBootPutUint16 (
IN UINT8 *Buf,
IN UINT16 Data16
)
{
Data16 = USB_BOOT_SWAP16 (Data16);
CopyMem (Buf, &Data16, sizeof (UINT16));
}
/**
Request sense information via sending Request Sense
Packet Command.
@param UsbMass The device to be requested sense data
@retval EFI_DEVICE_ERROR Hardware error
@retval EFI_SUCCESS Success
**/
EFI_STATUS
UsbBootRequestSense (
IN USB_MASS_DEVICE *UsbMass
)
{
USB_BOOT_REQUEST_SENSE_CMD SenseCmd;
USB_BOOT_REQUEST_SENSE_DATA SenseData;
EFI_BLOCK_IO_MEDIA *Media;
USB_MASS_TRANSPORT *Transport;
EFI_STATUS Status;
UINT32 CmdResult;
Transport = UsbMass->Transport;
//
// Request the sense data from the device if command failed
//
ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));
ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));
SenseCmd.OpCode = USB_BOOT_REQUEST_SENSE_OPCODE;
SenseCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
SenseCmd.AllocLen = sizeof (USB_BOOT_REQUEST_SENSE_DATA);
Status = Transport->ExecCommand (
UsbMass->Context,
&SenseCmd,
sizeof (USB_BOOT_REQUEST_SENSE_CMD),
EfiUsbDataIn,
&SenseData,
sizeof (USB_BOOT_REQUEST_SENSE_DATA),
USB_BOOT_GENERAL_CMD_TIMEOUT,
&CmdResult
);
if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {
DEBUG ((mUsbMscError, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));
return EFI_DEVICE_ERROR;
}
//
// Interpret the sense data and update the media status if necessary.
//
Media = &UsbMass->BlockIoMedia;
switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {
case USB_BOOT_SENSE_NO_SENSE:
case USB_BOOT_SENSE_RECOVERED:
//
// Suppose hardware can handle this case, and recover later by itself
//
Status = EFI_NOT_READY;
break;
case USB_BOOT_SENSE_NOT_READY:
switch (SenseData.ASC) {
case USB_BOOT_ASC_NO_MEDIA:
Status = EFI_NO_MEDIA;
Media->MediaPresent = FALSE;
break;
case USB_BOOT_ASC_MEDIA_UPSIDE_DOWN:
Status = EFI_DEVICE_ERROR;
Media->MediaPresent = FALSE;
break;
case USB_BOOT_ASC_NOT_READY:
if (SenseData.ASCQ == USB_BOOT_ASCQ_IN_PROGRESS ||
SenseData.ASCQ == USB_BOOT_ASCQ_DEVICE_BUSY) {
//
// Regular timeout, and need retry once more
//
DEBUG ((mUsbMscInfo, "UsbBootRequestSense: Not ready and need retry once more\n"));
Status = EFI_NOT_READY;
}
}
break;
case USB_BOOT_SENSE_ILLEGAL_REQUEST:
Status = EFI_INVALID_PARAMETER;
break;
case USB_BOOT_SENSE_UNIT_ATTENTION:
Status = EFI_DEVICE_ERROR;
if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) {
Status = EFI_MEDIA_CHANGED;
UsbMass->BlockIoMedia.MediaId++;
}
break;
case USB_BOOT_SNESE_DATA_PROTECT:
Status = EFI_WRITE_PROTECTED;
UsbMass->BlockIoMedia.ReadOnly = TRUE;
break;
default:
Status = EFI_DEVICE_ERROR;
break;
}
DEBUG ((mUsbMscInfo, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",
Status,
USB_BOOT_SENSE_KEY (SenseData.SenseKey),
SenseData.ASC,
SenseData.ASCQ
));
return Status;
}
/**
Execute the USB mass storage bootability commands. If execution
failed, retrieve the error by REQUEST_SENSE then update the device's
status, such as ReadyOnly.
@param UsbMass The device to issue commands to
@param Cmd The command to execute
@param CmdLen The length of the command
@param DataDir The direction of data transfer
@param Data The buffer to hold the data
@param DataLen The length of expected data
@param Timeout The timeout used to transfer
@retval EFI_SUCCESS The command is excuted OK
@retval EFI_DEVICE_ERROR Failed to request sense
@retval EFI_INVALID_PARAMETER The command has some invalid parameters
@retval EFI_WRITE_PROTECTED The device is write protected
@retval EFI_MEDIA_CHANGED The device media has been changed
**/
STATIC
EFI_STATUS
UsbBootExecCmd (
IN USB_MASS_DEVICE *UsbMass,
IN VOID *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN VOID *Data,
IN UINT32 DataLen,
IN UINT32 Timeout
)
{
USB_MASS_TRANSPORT *Transport;
EFI_STATUS Status;
UINT32 CmdResult;
Transport = UsbMass->Transport;
Status = Transport->ExecCommand (
UsbMass->Context,
Cmd,
CmdLen,
DataDir,
Data,
DataLen,
Timeout,
&CmdResult
);
//
// ExecCommand return success and get the right CmdResult means
// the commnad transfer is OK.
//
if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR(Status)) {
return EFI_SUCCESS;
}
return UsbBootRequestSense (UsbMass);
}
/**
Execute the USB mass storage bootability commands. If execution
failed, retrieve the error by REQUEST_SENSE then update the device's
status, such as ReadyOnly.
@param UsbMass The device to issue commands to
@param Cmd The command to execute
@param CmdLen The length of the command
@param DataDir The direction of data transfer
@param Data The buffer to hold the data
@param DataLen The length of expected data
@retval EFI_SUCCESS The command is excuted OK
@retval EFI_DEVICE_ERROR Failed to request sense
@retval EFI_INVALID_PARAMETER The command has some invalid parameters
@retval EFI_WRITE_PROTECTED The device is write protected
@retval EFI_MEDIA_CHANGED The device media has been changed
**/
STATIC
EFI_STATUS
UsbBootExecCmdWithRetry (
IN USB_MASS_DEVICE *UsbMass,
IN VOID *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN VOID *Data,
IN UINT32 DataLen,
IN UINT32 Timeout
)
{
EFI_STATUS Status;
INT16 Index;
//
// If the device isn't ready, wait some time. If the device is ready,
// retry the command again.
//
Status = EFI_SUCCESS;
for (Index = 0; Index < USB_BOOT_COMMAND_RETRY; Index++) {
//
// Execute the command with an increasingly larger timeout value.
//
Status = UsbBootExecCmd (
UsbMass,
Cmd,
CmdLen,
DataDir,
Data,
DataLen,
Timeout * (Index + 1)
);
if (Status == EFI_SUCCESS ||
Status == EFI_MEDIA_CHANGED) {
break;
}
//
// Need retry once more, so reset index
//
if (Status == EFI_NOT_READY) {
Index = 0;
}
}
return Status;
}
/**
Use the TEST UNIT READY command to check whether it is ready.
If it is ready, update the parameters.
@param UsbMass The device to test
@retval EFI_SUCCESS The device is ready and parameters are updated.
@retval Others Device not ready.
**/
EFI_STATUS
UsbBootIsUnitReady (
IN USB_MASS_DEVICE *UsbMass
)
{
USB_BOOT_TEST_UNIT_READY_CMD TestCmd;
ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));
TestCmd.OpCode = USB_BOOT_TEST_UNIT_READY_OPCODE;
TestCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
return UsbBootExecCmdWithRetry (
UsbMass,
&TestCmd,
sizeof (USB_BOOT_TEST_UNIT_READY_CMD),
EfiUsbNoData,
NULL,
0,
USB_BOOT_GENERAL_CMD_TIMEOUT
);
}
/**
Inquiry Command requests that information regrarding parameters of
the Device be sent to the Host.
@param UsbMass The device to inquiry.
@retval EFI_SUCCESS The device is ready and parameters are updated.
@retval Others Device not ready.
**/
EFI_STATUS
UsbBootInquiry (
IN USB_MASS_DEVICE *UsbMass
)
{
USB_BOOT_INQUIRY_CMD InquiryCmd;
USB_BOOT_INQUIRY_DATA InquiryData;
EFI_BLOCK_IO_MEDIA *Media;
EFI_STATUS Status;
Media = &(UsbMass->BlockIoMedia);
//
// Use the Inquiry command to get the RemovableMedia setting.
//
ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));
ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));
InquiryCmd.OpCode = USB_BOOT_INQUIRY_OPCODE;
InquiryCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
InquiryCmd.AllocLen = sizeof (InquiryData);
Status = UsbBootExecCmdWithRetry (
UsbMass,
&InquiryCmd,
sizeof (USB_BOOT_INQUIRY_CMD),
EfiUsbDataIn,
&InquiryData,
sizeof (USB_BOOT_INQUIRY_DATA),
USB_BOOT_INQUIRY_CMD_TIMEOUT
);
if (EFI_ERROR (Status)) {
return Status;
}
UsbMass->Pdt = USB_BOOT_PDT (InquiryData.Pdt);
Media->RemovableMedia = USB_BOOT_REMOVABLE (InquiryData.Removable);
//
// Default value 512 Bytes, in case no media present at first time
//
Media->BlockSize = 0x0200;
return Status;
}
/**
Get the capacity of the USB mass storage media, including
the presentation, block size, and last block number. This
function is used to get the disk parameters at the start if
it is a non-removable media or to detect the media if it is
removable.
@param UsbMass The device to retireve disk gemotric.
@retval EFI_SUCCESS The disk gemotric is successfully retrieved.
@retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.
**/
EFI_STATUS
UsbBootReadCapacity (
IN USB_MASS_DEVICE *UsbMass
)
{
USB_BOOT_READ_CAPACITY_CMD CapacityCmd;
USB_BOOT_READ_CAPACITY_DATA CapacityData;
EFI_BLOCK_IO_MEDIA *Media;
EFI_STATUS Status;
Media = &UsbMass->BlockIoMedia;
//
// Use the READ CAPACITY command to get the block length and last blockno
//
ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));
ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));
CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;
CapacityCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
Status = UsbBootExecCmdWithRetry (
UsbMass,
&CapacityCmd,
sizeof (USB_BOOT_READ_CAPACITY_CMD),
EfiUsbDataIn,
&CapacityData,
sizeof (USB_BOOT_READ_CAPACITY_DATA),
USB_BOOT_GENERAL_CMD_TIMEOUT
);
if (EFI_ERROR (Status)) {
return Status;
}
Media->MediaPresent = TRUE;
Media->LastBlock = UsbBootGetUint32 (CapacityData.LastLba);
Media->BlockSize = UsbBootGetUint32 (CapacityData.BlockLen);
DEBUG ((mUsbMscInfo, "UsbBootReadCapacity Success LBA=%d BlockSize=%d\n",
Media->LastBlock, Media->BlockSize));
return EFI_SUCCESS;
}
/**
Retrieves mode sense information via sending Mode Sense
Packet Command.
@param UsbMass The USB_FLOPPY_DEV instance.
@retval EFI_DEVICE_ERROR Hardware error
@retval EFI_SUCCESS Success
**/
EFI_STATUS
UsbBootModeSense (
IN USB_MASS_DEVICE *UsbMass
)
{
EFI_STATUS Status;
USB_BOOT_MODE_SENSE_CMD ModeSenseCmd;
USB_BOOT_MODE_PARA_HEADER ModeParaHeader;
UINT8 CommandSet;
ZeroMem (&ModeSenseCmd, sizeof (USB_BOOT_MODE_SENSE_CMD));
ZeroMem (&ModeParaHeader, sizeof (USB_BOOT_MODE_PARA_HEADER));
//
// overuse Context Pointer, the first field of Bot or Cbi is EFI_USB_INTERFACE_DESCRIPTOR
//
CommandSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;
if (CommandSet == USB_MASS_STORE_SCSI) {
//
// Not UFI Command Set, no ModeSense Command
//
return EFI_SUCCESS;
}
ModeSenseCmd.OpCode = USB_BOOT_MODE_SENSE10_OPCODE;
ModeSenseCmd.PageCode = 0x3f;
ModeSenseCmd.ParaListLenLsb = (UINT8) sizeof (USB_BOOT_MODE_PARA_HEADER);
Status = UsbBootExecCmdWithRetry (
UsbMass,
&ModeSenseCmd,
sizeof (USB_BOOT_MODE_SENSE_CMD),
EfiUsbDataIn,
&ModeParaHeader,
sizeof (USB_BOOT_MODE_PARA_HEADER),
USB_BOOT_GENERAL_CMD_TIMEOUT
);
//
// Did nothing with the Header here
// But probably should
//
return Status;
}
/**
Get the parameters for the USB mass storage media, including
the RemovableMedia, block size, and last block number. This
function is used both to initialize the media during the
DriverBindingStart and to re-initialize it when the media is
changed. Althought the RemoveableMedia is unlikely to change,
I include it here.
@param UsbMass The device to retireve disk gemotric.
@retval EFI_SUCCESS The disk gemotric is successfully retrieved.
@retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.
**/
EFI_STATUS
UsbBootGetParams (
IN USB_MASS_DEVICE *UsbMass
)
{
EFI_BLOCK_IO_MEDIA *Media;
EFI_STATUS Status;
Status = UsbBootInquiry (UsbMass);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));
return Status;
}
Media = &(UsbMass->BlockIoMedia);
//
// Don't use the Removable bit in inquirydata to test whether the media
// is removable because many flash disks wrongly set this bit.
//
if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {
//
// CD-Rom or Optical device
//
UsbMass->OpticalStorage = TRUE;
//
// Default value 2048 Bytes, in case no media present at first time
//
Media->BlockSize = 0x0800;
} else {
//
// Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd
//
Status = UsbBootModeSense (UsbMass);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "UsbBootGetParams: UsbBootModeSense (%r)\n", Status));
return Status;
}
}
return UsbBootReadCapacity (UsbMass);
}
/**
Detect whether the removable media is present and whether it has changed.
The Non-removable media doesn't need it.
@param UsbMass The device to retireve disk gemotric.
@retval EFI_SUCCESS The disk gemotric is successfully retrieved.
@retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric.
**/
EFI_STATUS
UsbBootDetectMedia (
IN USB_MASS_DEVICE *UsbMass
)
{
EFI_BLOCK_IO_MEDIA OldMedia;
EFI_BLOCK_IO_MEDIA *Media;
EFI_STATUS Status;
Media = &UsbMass->BlockIoMedia;
OldMedia = UsbMass->BlockIoMedia;
//
// First test whether the device is ready and get status
// If media changed or ready, need read the device's capacity
//
Status = UsbBootIsUnitReady (UsbMass);
if ((Status == EFI_SUCCESS && Media->MediaPresent) ||
(Status == EFI_MEDIA_CHANGED)) {
if ((UsbMass->Pdt != USB_PDT_CDROM) &&
(UsbMass->Pdt != USB_PDT_OPTICAL)) {
//
// Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd
//
UsbBootModeSense (UsbMass);
}
DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need Read Capacity\n"));
Status = UsbBootReadCapacity (UsbMass);
}
if (EFI_ERROR (Status)) {
return Status;
}
//
// Detect whether it is necessary to reinstall the BlockIO
//
if ((Media->MediaId != OldMedia.MediaId) ||
(Media->MediaPresent != OldMedia.MediaPresent) ||
(Media->ReadOnly != OldMedia.ReadOnly) ||
(Media->BlockSize != OldMedia.BlockSize) ||
(Media->LastBlock != OldMedia.LastBlock)) {
DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need reinstall BlockIoProtocol\n"));
Media->MediaId++;
gBS->ReinstallProtocolInterface (
UsbMass->Controller,
&gEfiBlockIoProtocolGuid,
&UsbMass->BlockIo,
&UsbMass->BlockIo
);
//
// Check whether media present or media changed or write protected
//
if (Media->MediaPresent == FALSE) {
Status = EFI_NO_MEDIA;
}
if (Media->MediaId != OldMedia.MediaId) {
Status = EFI_MEDIA_CHANGED;
}
if (Media->ReadOnly != OldMedia.ReadOnly) {
Status = EFI_WRITE_PROTECTED;
}
}
return Status;
}
/**
Read some blocks from the device.
@param UsbMass The USB mass storage device to read from
@param Lba The start block number
@param TotalBlock Total block number to read
@param Buffer The buffer to read to
@retval EFI_SUCCESS Data are read into the buffer
@retval Others Failed to read all the data
**/
EFI_STATUS
UsbBootReadBlocks (
IN USB_MASS_DEVICE *UsbMass,
IN UINT32 Lba,
IN UINTN TotalBlock,
OUT UINT8 *Buffer
)
{
USB_BOOT_READ10_CMD ReadCmd;
EFI_STATUS Status;
UINT16 Count;
UINT32 BlockSize;
UINT32 ByteSize;
UINT32 Timeout;
BlockSize = UsbMass->BlockIoMedia.BlockSize;
Status = EFI_SUCCESS;
while (TotalBlock > 0) {
//
// Split the total blocks into smaller pieces to ease the pressure
// on the device. We must split the total block because the READ10
// command only has 16 bit transfer length (in the unit of block).
//
Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
ByteSize = (UINT32)Count * BlockSize;
//
// Optical device need longer timeout than other device
//
if (UsbMass->OpticalStorage == TRUE) {
Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;
} else {
Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;
}
//
// Fill in the command then execute
//
ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));
ReadCmd.OpCode = USB_BOOT_READ10_OPCODE;
ReadCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
UsbBootPutUint32 (ReadCmd.Lba, Lba);
UsbBootPutUint16 (ReadCmd.TransferLen, Count);
Status = UsbBootExecCmdWithRetry (
UsbMass,
&ReadCmd,
sizeof (USB_BOOT_READ10_CMD),
EfiUsbDataIn,
Buffer,
ByteSize,
Timeout
);
if (EFI_ERROR (Status)) {
return Status;
}
Lba += Count;
Buffer += Count * BlockSize;
TotalBlock -= Count;
}
return Status;
}
/**
Write some blocks to the device.
@param UsbMass The USB mass storage device to write to
@param Lba The start block number
@param TotalBlock Total block number to write
@param Buffer The buffer to write to
@retval EFI_SUCCESS Data are written into the buffer
@retval Others Failed to write all the data
**/
EFI_STATUS
UsbBootWriteBlocks (
IN USB_MASS_DEVICE *UsbMass,
IN UINT32 Lba,
IN UINTN TotalBlock,
OUT UINT8 *Buffer
)
{
USB_BOOT_WRITE10_CMD WriteCmd;
EFI_STATUS Status;
UINT16 Count;
UINT32 BlockSize;
UINT32 ByteSize;
UINT32 Timeout;
BlockSize = UsbMass->BlockIoMedia.BlockSize;
Status = EFI_SUCCESS;
while (TotalBlock > 0) {
//
// Split the total blocks into smaller pieces to ease the pressure
// on the device. We must split the total block because the WRITE10
// command only has 16 bit transfer length (in the unit of block).
//
Count = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);
ByteSize = (UINT32)Count * BlockSize;
//
// Optical device need longer timeout than other device
//
if (UsbMass->OpticalStorage == TRUE) {
Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;
} else {
Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;
}
//
// Fill in the write10 command block
//
ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));
WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;
WriteCmd.Lun = USB_BOOT_LUN (UsbMass->Lun);
UsbBootPutUint32 (WriteCmd.Lba, Lba);
UsbBootPutUint16 (WriteCmd.TransferLen, Count);
Status = UsbBootExecCmdWithRetry (
UsbMass,
&WriteCmd,
sizeof (USB_BOOT_WRITE10_CMD),
EfiUsbDataOut,
Buffer,
ByteSize,
Timeout
);
if (EFI_ERROR (Status)) {
return Status;
}
Lba += Count;
Buffer += Count * BlockSize;
TotalBlock -= Count;
}
return Status;
}
/**
Use the USB clear feature control transfer to clear the endpoint
stall condition.
@param UsbIo The USB IO protocol to use
@param EndpointAddr The endpoint to clear stall for
@retval EFI_SUCCESS The endpoint stall condtion is clear
@retval Others Failed to clear the endpoint stall condtion
**/
EFI_STATUS
UsbClearEndpointStall (
IN EFI_USB_IO_PROTOCOL *UsbIo,
IN UINT8 EndpointAddr
)
{
EFI_USB_DEVICE_REQUEST Request;
EFI_STATUS Status;
UINT32 CmdResult;
UINT32 Timeout;
Request.RequestType = 0x02;
Request.Request = USB_REQ_CLEAR_FEATURE;
Request.Value = USB_FEATURE_ENDPOINT_HALT;
Request.Index = EndpointAddr;
Request.Length = 0;
Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_STALL_1_MS;
Status = UsbIo->UsbControlTransfer (
UsbIo,
&Request,
EfiUsbNoData,
Timeout,
NULL,
0,
&CmdResult
);
return Status;
}

View File

@@ -0,0 +1,268 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassBoot.h
Abstract:
The definition of command and data of the USB mass storage for
bootability command set.
Revision History
**/
#ifndef _EFI_USB_MASS_BOOT_H_
#define _EFI_USB_MASS_BOOT_H_
enum {
//
// The opcodes of various usb boot commands:
// INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified
// by MMC command set. Others are "Group 1 Timeout Commands". That
// is they should be retried if driver is ready.
// We can't use the Peripheral Device Type in Inquiry data to
// determine the timeout used. For example, both floppy and flash
// are likely set their PDT to 0, or Direct Access Device.
//
USB_BOOT_INQUIRY_OPCODE = 0x12,
USB_BOOT_REQUEST_SENSE_OPCODE = 0x03,
USB_BOOT_MODE_SENSE10_OPCODE = 0x5a,
USB_BOOT_READ_CAPACITY_OPCODE = 0x25,
USB_BOOT_TEST_UNIT_READY_OPCODE = 0x00,
USB_BOOT_READ10_OPCODE = 0x28,
USB_BOOT_WRITE10_OPCODE = 0x2a,
//
// The Sense Key part of the sense data. Sense data has three levels:
// Sense key, Additional Sense Code and Additional Sense Code Qualifier
//
USB_BOOT_SENSE_NO_SENSE = 0x00, // No sense key
USB_BOOT_SENSE_RECOVERED = 0x01, // Last command succeed with recovery actions
USB_BOOT_SENSE_NOT_READY = 0x02, // Device not ready
USB_BOOT_SNESE_MEDIUM_ERROR = 0X03, // Failed probably because flaw in the media
USB_BOOT_SENSE_HARDWARE_ERROR = 0X04, // Non-recoverable hardware failure
USB_BOOT_SENSE_ILLEGAL_REQUEST = 0X05, // Illegal parameters in the request
USB_BOOT_SENSE_UNIT_ATTENTION = 0X06, // Removable medium may have been changed
USB_BOOT_SNESE_DATA_PROTECT = 0X07, // Write protected
USB_BOOT_SENSE_BLANK_CHECK = 0X08, // Blank/non-blank medium while reading/writing
USB_BOOT_SENSE_VENDOR = 0X09, // Vendor specific sense key
USB_BOOT_SENSE_ABORTED = 0X0B, // Command aborted by the device
USB_BOOT_SENSE_VOLUME_OVERFLOW = 0x0D, // Partition overflow
USB_BOOT_SENSE_MISCOMPARE = 0x0E, // Source data mis-match while verfying.
USB_BOOT_ASC_NOT_READY = 0x04,
USB_BOOT_ASC_MEDIA_UPSIDE_DOWN = 0x06,
USB_BOOT_ASC_NO_MEDIA = 0x3A,
USB_BOOT_ASC_MEDIA_CHANGE = 0x28,
USB_BOOT_ASCQ_IN_PROGRESS = 0x01,
USB_BOOT_ASCQ_DEVICE_BUSY = 0xFF,
//
// Other parameters
//
USB_BOOT_IO_BLOCKS = 64,
//
// Boot Retry times
//
USB_BOOT_COMMAND_RETRY = 5,
USB_BOOT_WAIT_RETRY = 5,
//
// Boot Stall time
//
USB_BOOT_UNIT_READY_STALL = 50 * USB_MASS_STALL_1_MS,
//
// Boot Transfer timeout
//
USB_BOOT_GENERAL_BLOCK_TIMEOUT = 200 * USB_MASS_STALL_1_MS,
USB_BOOT_OPTICAL_BLOCK_TIMEOUT = 1 * USB_MASS_STALL_1_S,
USB_BOOT_GENERAL_CMD_TIMEOUT = 1 * USB_MASS_STALL_1_S,
USB_BOOT_INQUIRY_CMD_TIMEOUT = 3 * USB_MASS_STALL_1_S,
//
// Supported PDT codes, or Peripheral Device Type
//
USB_PDT_DIRECT_ACCESS = 0x00, // Direct access device
USB_PDT_CDROM = 0x05, // CDROM
USB_PDT_OPTICAL = 0x07, // Non-CD optical disks
USB_PDT_SIMPLE_DIRECT = 0x0E, // Simplified direct access device
};
//
// The required commands are INQUIRY, READ CAPACITY, TEST UNIT READY,
// READ10, WRITE10, and REQUEST SENSE. The BLOCK_IO protocol uses LBA
// so it isn't necessary to issue MODE SENSE / READ FORMAT CAPACITY
// command to retrieve the disk gemotrics.
//
#pragma pack(1)
typedef struct {
UINT8 OpCode;
UINT8 Lun; // Lun (high 3 bits)
UINT8 Reserved0[2];
UINT8 AllocLen;
UINT8 Reserved1;
UINT8 Pad[6];
} USB_BOOT_INQUIRY_CMD;
typedef struct {
UINT8 Pdt; // Peripheral Device Type (low 5 bits)
UINT8 Removable; // Removable Media (highest bit)
UINT8 Reserved0[2];
UINT8 AddLen; // Additional length
UINT8 Reserved1[3];
UINT8 VendorID[8];
UINT8 ProductID[16];
UINT8 ProductRevision[4];
} USB_BOOT_INQUIRY_DATA;
typedef struct {
UINT8 OpCode;
UINT8 Lun;
UINT8 Reserved0[8];
UINT8 Pad[2];
} USB_BOOT_READ_CAPACITY_CMD;
typedef struct {
UINT8 LastLba[4];
UINT8 BlockLen[4];
} USB_BOOT_READ_CAPACITY_DATA;
typedef struct {
UINT8 OpCode;
UINT8 Lun;
UINT8 Reserved[4];
UINT8 Pad[6];
} USB_BOOT_TEST_UNIT_READY_CMD;
typedef struct {
UINT8 OpCode;
UINT8 Lun;
UINT8 PageCode;
UINT8 Reserved0[4];
UINT8 ParaListLenMsb;
UINT8 ParaListLenLsb;
UINT8 Reserved1;
UINT8 Pad[2];
} USB_BOOT_MODE_SENSE_CMD;
typedef struct {
UINT8 ModeDataLenMsb;
UINT8 ModeDataLenLsb;
UINT8 Reserved0[4];
UINT8 BlkDesLenMsb;
UINT8 BlkDesLenLsb;
} USB_BOOT_MODE_PARA_HEADER;
typedef struct {
UINT8 OpCode;
UINT8 Lun; // Lun (High 3 bits)
UINT8 Lba[4]; // Logical block address
UINT8 Reserved0;
UINT8 TransferLen[2]; // Transfer length
UINT8 Reserverd1;
UINT8 Pad[2];
} USB_BOOT_READ10_CMD;
typedef struct {
UINT8 OpCode;
UINT8 Lun;
UINT8 Lba[4];
UINT8 Reserved0;
UINT8 TransferLen[2];
UINT8 Reserverd1;
UINT8 Pad[2];
} USB_BOOT_WRITE10_CMD;
typedef struct {
UINT8 OpCode;
UINT8 Lun; // Lun (High 3 bits)
UINT8 Reserved0[2];
UINT8 AllocLen; // Allocation length
UINT8 Reserved1;
UINT8 Pad[6];
} USB_BOOT_REQUEST_SENSE_CMD;
typedef struct {
UINT8 ErrorCode;
UINT8 Reserved0;
UINT8 SenseKey; // Sense key (low 4 bits)
UINT8 Infor[4];
UINT8 AddLen; // Additional Sense length, 10
UINT8 Reserved1[4];
UINT8 ASC; // Additional Sense Code
UINT8 ASCQ; // Additional Sense Code Qualifier
UINT8 Reserverd2[4];
} USB_BOOT_REQUEST_SENSE_DATA;
#pragma pack()
//
// Convert a LUN number to that in the command
//
#define USB_BOOT_LUN(Lun) ((Lun) << 5)
//
// Get the removable, PDT, and sense key bits from the command data
//
#define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & 0x80) != 0)
#define USB_BOOT_PDT(Pdt) ((Pdt) & 0x1f)
#define USB_BOOT_SENSE_KEY(Key) ((Key) & 0x0f)
//
// Swap the byte sequence of a UINT32. Intel CPU uses little endian
// in UEFI environment, but USB boot uses big endian.
//
#define USB_BOOT_SWAP32(Data32) \
((((Data32) & 0x000000ff) << 24) | (((Data32) & 0xff000000) >> 24) | \
(((Data32) & 0x0000ff00) << 8) | (((Data32) & 0x00ff0000) >> 8))
#define USB_BOOT_SWAP16(Data16) \
((((Data16) & 0x00ff) << 8) | (((Data16) & 0xff00) >> 8))
EFI_STATUS
UsbBootGetParams (
IN USB_MASS_DEVICE *UsbMass
);
EFI_STATUS
UsbBootIsUnitReady (
IN USB_MASS_DEVICE *UsbMass
);
EFI_STATUS
UsbBootDetectMedia (
IN USB_MASS_DEVICE *UsbMass
);
EFI_STATUS
UsbBootReadBlocks (
IN USB_MASS_DEVICE *UsbMass,
IN UINT32 Lba,
IN UINTN TotalBlock,
OUT UINT8 *Buffer
);
EFI_STATUS
UsbBootWriteBlocks (
IN USB_MASS_DEVICE *UsbMass,
IN UINT32 Lba,
IN UINTN TotalBlock,
OUT UINT8 *Buffer
);
#endif

View File

@@ -0,0 +1,561 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassBot.c
Abstract:
Implementation of the USB mass storage Bulk-Only Transport protocol.
Revision History
**/
#include "UsbMass.h"
#include "UsbMassBot.h"
UINTN mUsbBotInfo = DEBUG_INFO;
UINTN mUsbBotError = DEBUG_ERROR;
STATIC
EFI_STATUS
UsbBotResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
);
/**
Initialize the USB mass storage class BOT transport protocol.
It will save its context which is a USB_BOT_PROTOCOL structure
in the Context if Context isn't NULL.
@param UsbIo The USB IO protocol to use
@param Controller The controller to init
@param Context The variable to save the context to
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
@retval EFI_UNSUPPORTED The transport protocol doesn't support the device.
@retval EFI_SUCCESS The device is supported and protocol initialized.
**/
STATIC
EFI_STATUS
UsbBotInit (
IN EFI_USB_IO_PROTOCOL * UsbIo,
IN EFI_HANDLE Controller,
OUT VOID **Context OPTIONAL
)
{
USB_BOT_PROTOCOL *UsbBot;
EFI_USB_INTERFACE_DESCRIPTOR *Interface;
EFI_USB_ENDPOINT_DESCRIPTOR EndPoint;
EFI_STATUS Status;
UINT8 Index;
//
// Allocate the BOT context, append two endpoint descriptors to it
//
UsbBot = AllocateZeroPool (
sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
);
if (UsbBot == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UsbBot->UsbIo = UsbIo;
//
// Get the interface descriptor and validate that it
// is a USB MSC BOT interface.
//
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbBotError, "UsbBotInit: Get invalid BOT interface (%r)\n", Status));
goto ON_ERROR;
}
Interface = &UsbBot->Interface;
if (Interface->InterfaceProtocol != USB_MASS_STORE_BOT) {
Status = EFI_UNSUPPORTED;
goto ON_ERROR;
}
//
// Locate and save the first bulk-in and bulk-out endpoint
//
for (Index = 0; Index < Interface->NumEndpoints; Index++) {
Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);
if (EFI_ERROR (Status) || !USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {
continue;
}
if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&
(UsbBot->BulkInEndpoint == NULL)) {
UsbBot->BulkInEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1);
*UsbBot->BulkInEndpoint = EndPoint;
}
if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
(UsbBot->BulkOutEndpoint == NULL)) {
UsbBot->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1) + 1;
*UsbBot->BulkOutEndpoint = EndPoint;
}
}
if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) {
DEBUG ((mUsbBotError, "UsbBotInit: In/Out Endpoint invalid\n"));
Status = EFI_UNSUPPORTED;
goto ON_ERROR;
}
//
// The USB BOT protocol uses dCBWTag to match the CBW and CSW.
//
UsbBot->CbwTag = 0x01;
if (Context != NULL) {
*Context = UsbBot;
} else {
gBS->FreePool (UsbBot);
}
return EFI_SUCCESS;
ON_ERROR:
gBS->FreePool (UsbBot);
return Status;
}
/**
Send the command to the device using Bulk-Out endpoint
@param UsbBot The USB BOT device
@param Cmd The command to transfer to device
@param CmdLen the length of the command
@param DataDir The direction of the data
@param TransLen The expected length of the data
@retval EFI_NOT_READY The device return NAK to the transfer
@retval EFI_SUCCESS The command is sent to the device.
@retval Others Failed to send the command to device
**/
STATIC
EFI_STATUS
UsbBotSendCommand (
IN USB_BOT_PROTOCOL *UsbBot,
IN UINT8 *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN UINT32 TransLen
)
{
USB_BOT_CBW Cbw;
EFI_STATUS Status;
UINT32 Result;
UINTN DataLen;
UINTN Timeout;
ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN));
//
// Fill in the CSW. Only the first LUN is supported now.
//
Cbw.Signature = USB_BOT_CBW_SIGNATURE;
Cbw.Tag = UsbBot->CbwTag;
Cbw.DataLen = TransLen;
Cbw.Flag = ((DataDir == EfiUsbDataIn) ? 0x80 : 0);
Cbw.Lun = 0;
Cbw.CmdLen = CmdLen;
ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN);
CopyMem (Cbw.CmdBlock, Cmd, CmdLen);
Result = 0;
DataLen = sizeof (USB_BOT_CBW);
Timeout = USB_BOT_CBW_TIMEOUT / USB_MASS_STALL_1_MS;
//
// Use the UsbIo to send the command to the device. The default
// time out is enough.
//
Status = UsbBot->UsbIo->UsbBulkTransfer (
UsbBot->UsbIo,
UsbBot->BulkOutEndpoint->EndpointAddress,
&Cbw,
&DataLen,
Timeout,
&Result
);
//
// Respond to Bulk-Out endpoint stall with a Reset Recovery,
// see the spec section 5.3.1
//
if (EFI_ERROR (Status)) {
if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) {
UsbBotResetDevice (UsbBot, FALSE);
} else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
Status = EFI_NOT_READY;
}
}
return Status;
}
/**
Transfer the data between the device and host. BOT transfer
is composed of three phase, command, data, and status.
@param UsbBot The USB BOT device
@param DataDir The direction of the data
@param Data The buffer to hold data
@param TransLen The expected length of the data
@param Timeout The time to wait the command to complete
@retval EFI_SUCCESS The data is transferred
@retval Others Failed to transfer data
**/
STATIC
EFI_STATUS
UsbBotDataTransfer (
IN USB_BOT_PROTOCOL *UsbBot,
IN EFI_USB_DATA_DIRECTION DataDir,
IN OUT UINT8 *Data,
IN OUT UINTN *TransLen,
IN UINT32 Timeout
)
{
EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
EFI_STATUS Status;
UINT32 Result;
//
// It's OK if no data to transfer
//
if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
return EFI_SUCCESS;
}
//
// Select the endpoint then issue the transfer
//
if (DataDir == EfiUsbDataIn) {
Endpoint = UsbBot->BulkInEndpoint;
} else {
Endpoint = UsbBot->BulkOutEndpoint;
}
Result = 0;
Timeout = Timeout / USB_MASS_STALL_1_MS;
Status = UsbBot->UsbIo->UsbBulkTransfer (
UsbBot->UsbIo,
Endpoint->EndpointAddress,
Data,
TransLen,
Timeout,
&Result
);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbBotError, "UsbBotDataTransfer: (%r)\n", Status));
if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
DEBUG ((mUsbBotError, "UsbBotDataTransfer: DataIn Stall\n"));
UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress);
} else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {
Status = EFI_NOT_READY;
}
}
return Status;
}
/**
Get the command execution status from device. BOT transfer is
composed of three phase, command, data, and status.
This function return the transfer status of the BOT's CSW status,
and return the high level command execution result in Result. So
even it returns EFI_SUCCESS, the command may still have failed.
@param UsbBot The USB BOT device
@param TransLen The expected length of the data
@param Timeout The time to wait the command to complete
@param CmdStatus The result of the command execution.
@retval EFI_DEVICE_ERROR Failed to retrieve the command execute result
@retval EFI_SUCCESS Command execute result is retrieved and in the
Result.
**/
STATIC
EFI_STATUS
UsbBotGetStatus (
IN USB_BOT_PROTOCOL *UsbBot,
IN UINT32 TransLen,
OUT UINT8 *CmdStatus
)
{
USB_BOT_CSW Csw;
UINTN Len;
UINT8 Endpoint;
EFI_STATUS Status;
UINT32 Result;
EFI_USB_IO_PROTOCOL *UsbIo;
UINT32 Index;
UINTN Timeout;
*CmdStatus = USB_BOT_COMMAND_ERROR;
Status = EFI_DEVICE_ERROR;
Endpoint = UsbBot->BulkInEndpoint->EndpointAddress;
UsbIo = UsbBot->UsbIo;
Timeout = USB_BOT_CSW_TIMEOUT / USB_MASS_STALL_1_MS;
for (Index = 0; Index < USB_BOT_GET_STATUS_RETRY; Index++) {
//
// Attemp to the read CSW from bulk in endpoint
//
ZeroMem (&Csw, sizeof (USB_BOT_CSW));
Result = 0;
Len = sizeof (USB_BOT_CSW);
Status = UsbIo->UsbBulkTransfer (
UsbIo,
Endpoint,
&Csw,
&Len,
Timeout,
&Result
);
if (EFI_ERROR(Status)) {
DEBUG ((mUsbBotError, "UsbBotGetStatus (%r)\n", Status));
if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {
DEBUG ((mUsbBotError, "UsbBotGetStatus: DataIn Stall\n"));
UsbClearEndpointStall (UsbIo, Endpoint);
}
continue;
}
if (Csw.Signature != USB_BOT_CSW_SIGNATURE) {
//
// Invalid Csw need perform reset recovery
//
DEBUG ((mUsbBotError, "UsbBotGetStatus: Device return a invalid signature\n"));
Status = UsbBotResetDevice (UsbBot, FALSE);
} else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) {
//
// Respond phase error need perform reset recovery
//
DEBUG ((mUsbBotError, "UsbBotGetStatus: Device return a phase error\n"));
Status = UsbBotResetDevice (UsbBot, FALSE);
} else {
*CmdStatus = Csw.CmdStatus;
break;
}
}
//
//The tag is increased even there is an error.
//
UsbBot->CbwTag++;
return Status;
}
/**
Call the Usb mass storage class transport protocol to issue
the command/data/status circle to execute the commands
@param Context The context of the BOT protocol, that is,
USB_BOT_PROTOCOL
@param Cmd The high level command
@param CmdLen The command length
@param DataDir The direction of the data transfer
@param Data The buffer to hold data
@param DataLen The length of the data
@param Timeout The time to wait command
@param CmdStatus The result of high level command execution
@retval EFI_DEVICE_ERROR Failed to excute command
@retval EFI_SUCCESS The command is executed OK, and result in CmdStatus
**/
STATIC
EFI_STATUS
UsbBotExecCommand (
IN VOID *Context,
IN VOID *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN VOID *Data,
IN UINT32 DataLen,
IN UINT32 Timeout,
OUT UINT32 *CmdStatus
)
{
USB_BOT_PROTOCOL *UsbBot;
EFI_STATUS Status;
UINTN TransLen;
UINT8 Result;
*CmdStatus = USB_MASS_CMD_FAIL;
UsbBot = (USB_BOT_PROTOCOL *) Context;
//
// Send the command to the device. Return immediately if device
// rejects the command.
//
Status = UsbBotSendCommand (UsbBot, Cmd, CmdLen, DataDir, DataLen);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbBotError, "UsbBotExecCommand: UsbBotSendCommand (%r)\n", Status));
return Status;
}
//
// Transfer the data. Don't return immediately even data transfer
// failed. The host should attempt to receive the CSW no matter
// whether it succeeds or failed.
//
TransLen = (UINTN) DataLen;
UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout);
//
// Get the status, if that succeeds, interpret the result
//
Status = UsbBotGetStatus (UsbBot, DataLen, &Result);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbBotError, "UsbBotExecCommand: UsbBotGetStatus (%r)\n", Status));
return Status;
}
if (Result == 0) {
*CmdStatus = USB_MASS_CMD_SUCCESS;
}
return EFI_SUCCESS;
}
/**
Reset the mass storage device by BOT protocol
@param Context The context of the BOT protocol, that is,
USB_BOT_PROTOCOL
@retval EFI_SUCCESS The device is reset
@retval Others Failed to reset the device.
**/
STATIC
EFI_STATUS
UsbBotResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
)
{
USB_BOT_PROTOCOL *UsbBot;
EFI_USB_DEVICE_REQUEST Request;
EFI_STATUS Status;
UINT32 Result;
UINT32 Timeout;
UsbBot = (USB_BOT_PROTOCOL *) Context;
if (ExtendedVerification) {
//
// If we need to do strictly reset, reset its parent hub port
//
Status = UsbBot->UsbIo->UsbPortReset (UsbBot->UsbIo);
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Issue a class specific "Bulk-Only Mass Storage Reset reqest.
// See the spec section 3.1
//
Request.RequestType = 0x21;
Request.Request = USB_BOT_RESET_REQUEST;
Request.Value = 0;
Request.Index = UsbBot->Interface.InterfaceNumber;
Request.Length = 0;
Timeout = USB_BOT_RESET_TIMEOUT / USB_MASS_STALL_1_MS;
Status = UsbBot->UsbIo->UsbControlTransfer (
UsbBot->UsbIo,
&Request,
EfiUsbNoData,
Timeout,
NULL,
0,
&Result
);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbBotError, "UsbBotResetDevice: (%r)\n", Status));
return Status;
}
//
// The device shall NAK the host's request until the reset is
// complete. We can use this to sync the device and host. For
// now just stall 100ms to wait the device.
//
gBS->Stall (USB_BOT_RESET_STALL);
//
// Clear the Bulk-In and Bulk-Out stall condition.
//
UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress);
UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress);
return Status;
}
/**
Clean up the resource used by this BOT protocol
@param Context The context of the BOT protocol, that is,
USB_BOT_PROTOCOL
@retval EFI_SUCCESS The resource is cleaned up.
**/
STATIC
EFI_STATUS
UsbBotFini (
IN VOID *Context
)
{
gBS->FreePool (Context);
return EFI_SUCCESS;
}
USB_MASS_TRANSPORT
mUsbBotTransport = {
USB_MASS_STORE_BOT,
UsbBotInit,
UsbBotExecCommand,
UsbBotResetDevice,
UsbBotFini
};

View File

@@ -0,0 +1,102 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassBot.h
Abstract:
Defination for the USB mass storage Bulk-Only Transport protocol.
This implementation is based on the "Universal Serial Bus Mass
Storage Class Bulk-Only Transport" Revision 1.0, September 31, 1999.
Revision History
**/
#ifndef _EFI_USBMASS_BOT_H_
#define _EFI_USBMASS_BOT_H_
enum {
//
// Usb Bulk-Only class specfic request
//
USB_BOT_RESET_REQUEST = 0xFF, // Bulk-Only Mass Storage Reset
USB_BOT_GETLUN_REQUEST = 0xFE, // Get Max Lun
USB_BOT_CBW_SIGNATURE = 0x43425355, // dCBWSignature, tag the packet as CBW
USB_BOT_CSW_SIGNATURE = 0x53425355, // dCSWSignature, tag the packet as CSW
USB_BOT_MAX_LUN = 0x0F, // Lun number is from 0 to 15
USB_BOT_MAX_CMDLEN = 16, // Maxium number of command from command set
//
// Usb BOT command block status values
//
USB_BOT_COMMAND_OK = 0x00, // Command passed, good status
USB_BOT_COMMAND_FAILED = 0x01, // Command failed
USB_BOT_COMMAND_ERROR = 0x02, // Phase error, need to reset the device
//
// Usb Bot retry times
//
USB_BOT_GET_STATUS_RETRY = 3,
//
// Usb Bot stall time
//
USB_BOT_RESET_STALL = 100 * USB_MASS_STALL_1_MS,
//
// Usb Bot transfer timeout
//
USB_BOT_CBW_TIMEOUT = 1 * USB_MASS_STALL_1_S,
USB_BOT_CSW_TIMEOUT = 1 * USB_MASS_STALL_1_S,
USB_BOT_RESET_TIMEOUT = 3 * USB_MASS_STALL_1_S,
};
//
// The CBW (Command Block Wrapper) and CSW (Command Status Wrapper)
// structures used by the Usb BOT protocol.
//
#pragma pack(1)
typedef struct {
UINT32 Signature;
UINT32 Tag;
UINT32 DataLen; // Length of data between CBW and CSW
UINT8 Flag; // Bit 7, 0 ~ Data-Out, 1 ~ Data-In
UINT8 Lun; // Lun number. Bits 0~3 are used
UINT8 CmdLen; // Length of the command. Bits 0~4 are used
UINT8 CmdBlock[USB_BOT_MAX_CMDLEN];
} USB_BOT_CBW;
typedef struct {
UINT32 Signature;
UINT32 Tag;
UINT32 DataResidue;
UINT8 CmdStatus;
} USB_BOT_CSW;
#pragma pack()
//
// Put Interface at the first field is to make it easy to get by Context, which
// could be BOT/CBI Protocol instance
//
typedef struct {
EFI_USB_INTERFACE_DESCRIPTOR Interface;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
UINT32 CbwTag;
EFI_USB_IO_PROTOCOL *UsbIo;
} USB_BOT_PROTOCOL;
extern USB_MASS_TRANSPORT mUsbBotTransport;
#endif

View File

@@ -0,0 +1,619 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassCbi.c
Abstract:
Implementation of the USB mass storage Control/Bulk/Interrupt transpor.
Notice: it is being obseleted by the standard body in favor of the BOT
(Bulk-Only Transport).
Revision History
**/
#include "UsbMass.h"
#include "UsbMassCbi.h"
UINTN mUsbCbiInfo = DEBUG_INFO;
UINTN mUsbCbiError = DEBUG_ERROR;
STATIC
EFI_STATUS
UsbCbiResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
);
/**
Initialize the USB mass storage class CBI transport protocol.
If Context isn't NULL, it will save its context in it.
@param UsbIo The USB IO to use
@param Controller The device controller
@param Context The variable to save context in
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
@retval EFI_UNSUPPORTED The device isn't supported
@retval EFI_SUCCESS The CBI protocol is initialized.
**/
STATIC
EFI_STATUS
UsbCbiInit (
IN EFI_USB_IO_PROTOCOL *UsbIo,
IN EFI_HANDLE Controller,
OUT VOID **Context OPTIONAL
)
{
USB_CBI_PROTOCOL *UsbCbi;
EFI_USB_INTERFACE_DESCRIPTOR *Interface;
EFI_USB_ENDPOINT_DESCRIPTOR EndPoint;
EFI_STATUS Status;
UINT8 Index;
//
// Allocate the CBI context
//
UsbCbi = AllocateZeroPool (
sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
);
if (UsbCbi == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UsbCbi->UsbIo = UsbIo;
//
// Get the interface descriptor and validate that it is a USB mass
// storage class CBI interface.
//
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Interface = &UsbCbi->Interface;
if ((Interface->InterfaceProtocol != USB_MASS_STORE_CBI0)
&& (Interface->InterfaceProtocol != USB_MASS_STORE_CBI1)) {
Status = EFI_UNSUPPORTED;
goto ON_ERROR;
}
//
// Locate and save the bulk-in, bulk-out, and interrupt endpoint
//
for (Index = 0; Index < Interface->NumEndpoints; Index++) {
Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);
if (EFI_ERROR (Status)) {
continue;
}
if (USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {
//
// Use the first Bulk-In and Bulk-Out endpoints
//
if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&
(UsbCbi->BulkInEndpoint == NULL)) {
UsbCbi->BulkInEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1);
*UsbCbi->BulkInEndpoint = EndPoint;
}
if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
(UsbCbi->BulkOutEndpoint == NULL)) {
UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1;
*UsbCbi->BulkOutEndpoint = EndPoint;
}
} else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) {
//
// Use the first interrupt endpoint if it is CBI0
//
if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) &&
(UsbCbi->InterruptEndpoint == NULL)) {
UsbCbi->InterruptEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 2;
*UsbCbi->InterruptEndpoint = EndPoint;
}
}
}
if ((UsbCbi->BulkInEndpoint == NULL)
|| (UsbCbi->BulkOutEndpoint == NULL)
|| ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0)
&& (UsbCbi->InterruptEndpoint == NULL))) {
Status = EFI_UNSUPPORTED;
goto ON_ERROR;
}
if (Context != NULL) {
*Context = UsbCbi;
} else {
gBS->FreePool (UsbCbi);
}
return EFI_SUCCESS;
ON_ERROR:
gBS->FreePool (UsbCbi);
return Status;
}
/**
Send the command to the device using class specific control transfer.
@param UsbCbi The USB CBI protocol
@param Cmd The high level command to transfer to device
@param CmdLen The length of the command
@param Timeout The time to wait the command to finish
@retval EFI_SUCCESS The command is transferred to device
@retval Others The command failed to transfer to device
**/
STATIC
EFI_STATUS
UsbCbiSendCommand (
IN USB_CBI_PROTOCOL *UsbCbi,
IN UINT8 *Cmd,
IN UINT8 CmdLen,
IN UINT32 Timeout
)
{
EFI_USB_DEVICE_REQUEST Request;
EFI_STATUS Status;
UINT32 TransStatus;
UINTN DataLen;
INTN Retry;
//
// Fill in the device request, CBI use the "Accept Device-Specific
// Cmd" (ADSC) class specific request to send commands
//
Request.RequestType = 0x21;
Request.Request = 0;
Request.Value = 0;
Request.Index = UsbCbi->Interface.InterfaceNumber;
Request.Length = CmdLen;
Status = EFI_SUCCESS;
Timeout = Timeout / USB_MASS_STALL_1_MS;
for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
//
// Use the UsbIo to send the command to the device
//
TransStatus = 0;
DataLen = CmdLen;
Status = UsbCbi->UsbIo->UsbControlTransfer (
UsbCbi->UsbIo,
&Request,
EfiUsbDataOut,
Timeout,
Cmd,
DataLen,
&TransStatus
);
//
// The device can fail the command by STALL the control endpoint.
// It can delay the command by NAK the data or status stage, this
// is a "class-specific exemption to the USB specification". Retry
// if the command is NAKed.
//
if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
continue;
}
break;
}
return Status;
}
/**
Transfer data between the device and host. The CBI contains three phase,
command, data, and status. This is data phase.
@param UsbCbi The USB CBI device
@param DataDir The direction of the data transfer
@param Data The buffer to hold the data
@param TransLen The expected transfer length
@param Timeout The time to wait the command to execute
@retval EFI_SUCCESS The data transfer succeeded
@retval Others Failed to transfer all the data
**/
STATIC
EFI_STATUS
UsbCbiDataTransfer (
IN USB_CBI_PROTOCOL *UsbCbi,
IN EFI_USB_DATA_DIRECTION DataDir,
IN OUT UINT8 *Data,
IN OUT UINTN *TransLen,
IN UINT32 Timeout
)
{
EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
EFI_STATUS Status;
UINT32 TransStatus;
UINTN Remain;
UINTN Increment;
UINT8 *Next;
UINTN Retry;
//
// It's OK if no data to transfer
//
if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
return EFI_SUCCESS;
}
//
// Select the endpoint then issue the transfer
//
if (DataDir == EfiUsbDataIn) {
Endpoint = UsbCbi->BulkInEndpoint;
} else {
Endpoint = UsbCbi->BulkOutEndpoint;
}
Next = Data;
Remain = *TransLen;
Retry = 0;
Status = EFI_SUCCESS;
Timeout = Timeout / USB_MASS_STALL_1_MS;
//
// Transfer the data, if the device returns NAK, retry it.
//
while (Remain > 0) {
TransStatus = 0;
if (Remain > (UINTN) USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize) {
Increment = USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize;
} else {
Increment = Remain;
}
Status = UsbCbi->UsbIo->UsbBulkTransfer (
UsbCbi->UsbIo,
Endpoint->EndpointAddress,
Next,
&Increment,
Timeout,
&TransStatus
);
if (EFI_ERROR (Status)) {
if (TransStatus == EFI_USB_ERR_NAK) {
//
// The device can NAK the host if either the data/buffer isn't
// aviable or the command is in-progress. The data can be partly
// transferred. The transfer is aborted if several succssive data
// transfer commands are NAKed.
//
if (Increment == 0) {
if (++Retry > USB_CBI_MAX_RETRY) {
goto ON_EXIT;
}
} else {
Next += Increment;
Remain -= Increment;
Retry = 0;
}
continue;
}
//
// The device can fail the command by STALL the bulk endpoint.
// Clear the stall if that is the case.
//
if (TransStatus == EFI_USB_ERR_STALL) {
UsbClearEndpointStall (UsbCbi->UsbIo, Endpoint->EndpointAddress);
}
goto ON_EXIT;
}
Next += Increment;
Remain -= Increment;
}
ON_EXIT:
*TransLen -= Remain;
return Status;
}
/**
Get the result of high level command execution from interrupt
endpoint. This function returns the USB transfer status, and
put the high level command execution result in Result.
@param UsbCbi The USB CBI protocol
@param Timeout The time to wait the command to execute
@param Result GC_TODO: add argument description
@retval EFI_SUCCESS The high level command execution result is
retrieved in Result.
@retval Others Failed to retrieve the result.
**/
STATIC
EFI_STATUS
UsbCbiGetStatus (
IN USB_CBI_PROTOCOL *UsbCbi,
IN UINT32 Timeout,
OUT USB_CBI_STATUS *Result
)
{
UINTN Len;
UINT8 Endpoint;
EFI_STATUS Status;
UINT32 TransStatus;
INTN Retry;
Endpoint = UsbCbi->InterruptEndpoint->EndpointAddress;
Status = EFI_SUCCESS;
Timeout = Timeout / USB_MASS_STALL_1_MS;
//
// Attemp to the read the result from interrupt endpoint
//
for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
TransStatus = 0;
Len = sizeof (USB_CBI_STATUS);
Status = UsbCbi->UsbIo->UsbSyncInterruptTransfer (
UsbCbi->UsbIo,
Endpoint,
Result,
&Len,
Timeout,
&TransStatus
);
//
// The CBI can NAK the interrupt endpoint if the command is in-progress.
//
if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
continue;
}
break;
}
return Status;
}
/**
Execute USB mass storage command through the CBI0/CBI1 transport protocol
@param Context The USB CBI device
@param Cmd The command to transfer to device
@param CmdLen The length of the command
@param DataDir The direction of data transfer
@param Data The buffer to hold the data
@param DataLen The length of the buffer
@param Timeout The time to wait
@param CmdStatus The result of the command execution
@retval EFI_SUCCESS The command is executed OK and result in CmdStatus.
@retval EFI_DEVICE_ERROR Failed to execute the command
**/
STATIC
EFI_STATUS
UsbCbiExecCommand (
IN VOID *Context,
IN VOID *Cmd,
IN UINT8 CmdLen,
IN EFI_USB_DATA_DIRECTION DataDir,
IN VOID *Data,
IN UINT32 DataLen,
IN UINT32 Timeout,
OUT UINT32 *CmdStatus
)
{
USB_CBI_PROTOCOL *UsbCbi;
USB_CBI_STATUS Result;
EFI_STATUS Status;
UINTN TransLen;
*CmdStatus = USB_MASS_CMD_SUCCESS;
UsbCbi = (USB_CBI_PROTOCOL *) Context;
//
// Send the command to the device. Return immediately if device
// rejects the command.
//
Status = UsbCbiSendCommand (UsbCbi, Cmd, CmdLen, Timeout);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbCbiError, "UsbCbiExecCommand: UsbCbiSendCommand (%r)\n",Status));
return Status;
}
//
// Transfer the data, return this status if no interrupt endpoint
// is used to report the transfer status.
//
TransLen = (UINTN) DataLen;
Status = UsbCbiDataTransfer (UsbCbi, DataDir, Data, &TransLen, Timeout);
if (UsbCbi->InterruptEndpoint == NULL) {
DEBUG ((mUsbCbiError, "UsbCbiExecCommand: UsbCbiDataTransfer (%r)\n",Status));
return Status;
}
//
// Get the status, if that succeeds, interpret the result
//
Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbCbiError, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status));
return EFI_DEVICE_ERROR;
}
if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) {
//
// For UFI device, ASC and ASCQ are returned.
//
if (Result.Type != 0) {
*CmdStatus = USB_MASS_CMD_FAIL;
}
} else {
//
// Check page 27, CBI spec 1.1 for vaious reture status.
//
switch (Result.Value & 0x03) {
case 0x00:
//
// Pass
//
*CmdStatus = USB_MASS_CMD_SUCCESS;
break;
case 0x02:
//
// Phase Error, response with reset. Fall through to Fail.
//
UsbCbiResetDevice (UsbCbi, FALSE);
case 0x01:
//
// Fail
//
*CmdStatus = USB_MASS_CMD_FAIL;
break;
case 0x03:
//
// Persistent Fail, need to send REQUEST SENSE.
//
*CmdStatus = USB_MASS_CMD_PERSISTENT;
break;
}
}
return EFI_SUCCESS;
}
/**
Call the Usb mass storage class transport protocol to
reset the device. The reset is defined as a Non-Data
command. Don't use UsbCbiExecCommand to send the command
to device because that may introduce recursive loop.
@param Context The USB CBI device protocol
@retval EFI_SUCCESS the device is reset
@retval Others Failed to reset the device
**/
STATIC
EFI_STATUS
UsbCbiResetDevice (
IN VOID *Context,
IN BOOLEAN ExtendedVerification
)
{
UINT8 ResetCmd[USB_CBI_RESET_CMD_LEN];
USB_CBI_PROTOCOL *UsbCbi;
USB_CBI_STATUS Result;
EFI_STATUS Status;
UINT32 Timeout;
UsbCbi = (USB_CBI_PROTOCOL *) Context;
//
// Fill in the reset command.
//
SetMem (ResetCmd, USB_CBI_RESET_CMD_LEN, 0xFF);
ResetCmd[0] = 0x1D;
ResetCmd[1] = 0x04;
Timeout = USB_CBI_RESET_TIMEOUT / USB_MASS_STALL_1_MS;
//
// Send the command to the device. Don't use UsbCbiExecCommand here.
//
Status = UsbCbiSendCommand (UsbCbi, ResetCmd, USB_CBI_RESET_CMD_LEN, Timeout);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Just retrieve the status and ignore that. Then stall
// 50ms to wait it complete
//
UsbCbiGetStatus (UsbCbi, Timeout, &Result);
gBS->Stall (50 * 1000);
//
// Clear the Bulk-In and Bulk-Out stall condition and
// init data toggle.
//
UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress);
UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress);
return Status;
}
/**
Clean up the CBI protocol's resource
@param Context The CBI protocol
@retval EFI_SUCCESS The resource is cleaned up.
**/
STATIC
EFI_STATUS
UsbCbiFini (
IN VOID *Context
)
{
gBS->FreePool (Context);
return EFI_SUCCESS;
}
USB_MASS_TRANSPORT
mUsbCbi0Transport = {
USB_MASS_STORE_CBI0,
UsbCbiInit,
UsbCbiExecCommand,
UsbCbiResetDevice,
UsbCbiFini
};
USB_MASS_TRANSPORT
mUsbCbi1Transport = {
USB_MASS_STORE_CBI1,
UsbCbiInit,
UsbCbiExecCommand,
UsbCbiResetDevice,
UsbCbiFini
};

View File

@@ -0,0 +1,64 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassCbi.h
Abstract:
Defination for the USB mass storage Control/Bulk/Interrupt transpor.
Revision History
**/
#ifndef _EFI_USBMASS_CBI_H_
#define _EFI_USBMASS_CBI_H_
enum {
USB_CBI_MAX_PACKET_NUM = 16,
USB_CBI_RESET_CMD_LEN = 12,
//
// Usb CBI retry times
//
USB_CBI_MAX_RETRY = 3,
//
// Usb Cbi transfer timeout
//
USB_CBI_RESET_TIMEOUT = 1 * USB_MASS_STALL_1_S,
};
//
// Put Interface at the first field is to make it easy to get by Context, which
// could be BOT/CBI Protocol instance
//
typedef struct {
EFI_USB_INTERFACE_DESCRIPTOR Interface;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint;
EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint;
EFI_USB_ENDPOINT_DESCRIPTOR *InterruptEndpoint;
EFI_USB_IO_PROTOCOL *UsbIo;
} USB_CBI_PROTOCOL;
#pragma pack(1)
typedef struct {
UINT8 Type;
UINT8 Value;
} USB_CBI_STATUS;
#pragma pack()
extern USB_MASS_TRANSPORT mUsbCbi0Transport;
extern USB_MASS_TRANSPORT mUsbCbi1Transport;
#endif

View File

@@ -0,0 +1,640 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassImpl.c
Abstract:
The implementation of USB mass storage class device driver.
The command set supported is "USB Mass Storage Specification
for Bootability".
Revision History
**/
#include "UsbMassImpl.h"
//
// The underlying transport protocol. CBI support isn't included
// in the current build. It is being obseleted by the standard
// body. If you want to enable it, remove the if directive here,
// then add the UsbMassCbi.c/.h to the driver's inf file.
//
STATIC
USB_MASS_TRANSPORT *mUsbMassTransport[] = {
&mUsbCbi0Transport,
&mUsbCbi1Transport,
&mUsbBotTransport,
NULL
};
UINTN mUsbMscInfo = DEBUG_INFO;
UINTN mUsbMscError = DEBUG_ERROR;
/**
Retrieve the media parameters such as disk gemotric for the
device's BLOCK IO protocol.
@param UsbMass The USB mass storage device
@retval EFI_SUCCESS The media parameters is updated successfully.
@retval Others Failed to get the media parameters.
**/
EFI_STATUS
UsbMassInitMedia (
IN USB_MASS_DEVICE *UsbMass
)
{
EFI_BLOCK_IO_MEDIA *Media;
EFI_STATUS Status;
UINTN Index;
Media = &UsbMass->BlockIoMedia;
//
// Initialize the MediaPrsent/ReadOnly and others to the default.
// We are not forced to get it right at this time, check UEFI2.0
// spec for more information:
//
// MediaPresent: This field shows the media present status as
// of the most recent ReadBlocks or WriteBlocks call.
//
// ReadOnly : This field shows the read-only status as of the
// recent WriteBlocks call.
//
// but remember to update MediaId/MediaPresent/ReadOnly status
// after ReadBlocks and WriteBlocks
//
Media->MediaPresent = FALSE;
Media->LogicalPartition = FALSE;
Media->ReadOnly = FALSE;
Media->WriteCaching = FALSE;
Media->IoAlign = 0;
//
// Some device may spend several seconds before it is ready.
// Try several times before giving up. Wait 5s at most.
//
Status = EFI_SUCCESS;
for (Index = 0; Index < USB_BOOT_WAIT_RETRY; Index++) {
Status = UsbBootGetParams (UsbMass);
if ((Status != EFI_MEDIA_CHANGED)
&& (Status != EFI_NOT_READY)
&& (Status != EFI_TIMEOUT)) {
break;
}
Status = UsbBootIsUnitReady (UsbMass);
if (EFI_ERROR (Status)) {
gBS->Stall (USB_BOOT_UNIT_READY_STALL * (Index + 1));
}
}
return Status;
}
/**
Reset the block device. ExtendedVerification is ignored for this.
@param This The BLOCK IO protocol
@param ExtendedVerification Whether to execute extended verfication.
@retval EFI_SUCCESS The device is successfully resetted.
@retval Others Failed to reset the device.
**/
EFI_STATUS
UsbMassReset (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
USB_MASS_DEVICE *UsbMass;
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
return UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification);
}
/**
Read some blocks of data from the block device.
@param This The Block IO protocol
@param MediaId The media's ID of the device for current request
@param Lba The start block number
@param BufferSize The size of buffer to read data in
@param Buffer The buffer to read data to
@retval EFI_SUCCESS The data is successfully read
@retval EFI_NO_MEDIA Media isn't present
@retval EFI_MEDIA_CHANGED The device media has been changed, that is,
MediaId changed
@retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
NULL.
@retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
size, or overflow the last block number.
**/
EFI_STATUS
UsbMassReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
USB_MASS_DEVICE *UsbMass;
EFI_BLOCK_IO_MEDIA *Media;
EFI_STATUS Status;
UINTN TotalBlock;
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
Media = &UsbMass->BlockIoMedia;
//
// First, validate the parameters
//
if ((Buffer == NULL) || (BufferSize == 0)) {
return EFI_INVALID_PARAMETER;
}
//
// If it is a remoable media, such as CD-Rom or Usb-Floppy,
// if, need to detect the media before each rw, while Usb-Flash
// needn't. However, it's hard to identify Usb-Floppy between
// Usb-Flash by now, so detect media every time.
//
Status = UsbBootDetectMedia (UsbMass);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status));
return Status;
}
//
// Make sure BlockSize and LBA is consistent with BufferSize
//
if ((BufferSize % Media->BlockSize) != 0) {
return EFI_BAD_BUFFER_SIZE;
}
TotalBlock = BufferSize / Media->BlockSize;
if (Lba + TotalBlock - 1 > Media->LastBlock) {
return EFI_BAD_BUFFER_SIZE;
}
Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status));
UsbMassReset (This, TRUE);
}
return Status;
}
/**
Write some blocks of data to the block device.
@param This The Block IO protocol
@param MediaId The media's ID of the device for current request
@param Lba The start block number
@param BufferSize The size of buffer to write data to
@param Buffer The buffer to write data to
@retval EFI_SUCCESS The data is successfully written
@retval EFI_NO_MEDIA Media isn't present
@retval EFI_MEDIA_CHANGED The device media has been changed, that is,
MediaId changed
@retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is
NULL.
@retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block
size,
**/
EFI_STATUS
UsbMassWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
USB_MASS_DEVICE *UsbMass;
EFI_BLOCK_IO_MEDIA *Media;
EFI_STATUS Status;
UINTN TotalBlock;
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This);
Media = &UsbMass->BlockIoMedia;
//
// First, validate the parameters
//
if ((Buffer == NULL) || (BufferSize == 0)) {
return EFI_INVALID_PARAMETER;
}
//
// If it is a remoable media, such as CD-Rom or Usb-Floppy,
// if, need to detect the media before each rw, while Usb-Flash
// needn't. However, it's hard to identify Usb-Floppy between
// Usb-Flash by now, so detect media every time.
//
Status = UsbBootDetectMedia (UsbMass);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status));
return Status;
}
//
// Make sure BlockSize and LBA is consistent with BufferSize
//
if ((BufferSize % Media->BlockSize) != 0) {
return EFI_BAD_BUFFER_SIZE;
}
TotalBlock = BufferSize / Media->BlockSize;
if (Lba + TotalBlock - 1 > Media->LastBlock) {
return EFI_BAD_BUFFER_SIZE;
}
//
// Try to write the data even the device is marked as ReadOnly,
// and clear the status should the write succeed.
//
Status = UsbBootWriteBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "UsbMassWriteBlocks: UsbBootWriteBlocks (%r) -> Reset\n", Status));
UsbMassReset (This, TRUE);
}
return Status;
}
/**
Flush the cached writes to disks. USB mass storage device doesn't
support write cache, so return EFI_SUCCESS directly.
@param This The BLOCK IO protocol
@retval EFI_SUCCESS Always returns success
**/
EFI_STATUS
UsbMassFlushBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This
)
{
return EFI_SUCCESS;
}
/**
Check whether the controller is a supported USB mass storage.
@param This The USB mass driver's driver binding.
@param Controller The device to test against.
@param RemainingDevicePath The remaining device path
@retval EFI_SUCCESS This device is a supported USB mass storage.
@retval EFI_UNSUPPORTED The device isn't supported
@retval Others Some error happened.
**/
EFI_STATUS
EFIAPI
USBMassDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_USB_IO_PROTOCOL *UsbIo;
EFI_USB_INTERFACE_DESCRIPTOR Interface;
USB_MASS_TRANSPORT *Transport;
EFI_STATUS Status;
INTN Index;
//
// Check whether the controlelr support USB_IO
//
Status = gBS->OpenProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
&UsbIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the interface to check the USB class and find a transport
// protocol handler.
//
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
Status = EFI_UNSUPPORTED;
if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) {
goto ON_EXIT;
}
for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
Transport = mUsbMassTransport[Index];
if (Interface.InterfaceProtocol == Transport->Protocol) {
Status = Transport->Init (UsbIo, Controller, NULL);
break;
}
}
DEBUG ((mUsbMscInfo, "Found a USB mass store device %r\n", Status));
ON_EXIT:
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
/**
Start the USB mass storage device on the controller. It will
install a BLOCK_IO protocol on the device if everything is OK.
@param This The USB mass storage driver binding.
@param Controller The USB mass storage device to start on
@param RemainingDevicePath The remaining device path.
@retval EFI_SUCCESS The driver has started on the device.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
@retval Others Failed to start the driver on the device.
**/
EFI_STATUS
EFIAPI
USBMassDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_USB_IO_PROTOCOL *UsbIo;
EFI_USB_INTERFACE_DESCRIPTOR Interface;
USB_MASS_DEVICE *UsbMass;
USB_MASS_TRANSPORT *Transport;
EFI_STATUS Status;
UINTN Index;
Status = gBS->OpenProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
&UsbIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
UsbMass = AllocateZeroPool (sizeof (USB_MASS_DEVICE));
if (UsbMass == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Initialize the transport protocols
//
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status));
goto ON_ERROR;
}
Status = EFI_UNSUPPORTED;
for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) {
Transport = mUsbMassTransport[Index];
if (Interface.InterfaceProtocol == Transport->Protocol) {
UsbMass->Transport = Transport;
Status = Transport->Init (UsbIo, Controller, &UsbMass->Context);
break;
}
}
if (EFI_ERROR (Status)) {
DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Transport->Init (%r)\n", Status));
goto ON_ERROR;
}
UsbMass->Signature = USB_MASS_SIGNATURE;
UsbMass->Controller = Controller;
UsbMass->UsbIo = UsbIo;
UsbMass->BlockIo.Media = &UsbMass->BlockIoMedia;
UsbMass->BlockIo.Reset = UsbMassReset;
UsbMass->BlockIo.ReadBlocks = UsbMassReadBlocks;
UsbMass->BlockIo.WriteBlocks = UsbMassWriteBlocks;
UsbMass->BlockIo.FlushBlocks = UsbMassFlushBlocks;
UsbMass->OpticalStorage = FALSE;
//
// Get the storage's parameters, such as last block number.
// then install the BLOCK_IO
//
Status = UsbMassInitMedia (UsbMass);
if (!EFI_ERROR (Status)) {
if ((UsbMass->Pdt != USB_PDT_DIRECT_ACCESS) &&
(UsbMass->Pdt != USB_PDT_CDROM) &&
(UsbMass->Pdt != USB_PDT_OPTICAL) &&
(UsbMass->Pdt != USB_PDT_SIMPLE_DIRECT)) {
DEBUG ((mUsbMscError, "USBMassDriverBindingStart: Found an unsupported peripheral type[%d]\n", UsbMass->Pdt));
goto ON_ERROR;
}
} else if (Status != EFI_NO_MEDIA){
DEBUG ((mUsbMscError, "USBMassDriverBindingStart: UsbMassInitMedia (%r)\n", Status));
goto ON_ERROR;
}
Status = gBS->InstallProtocolInterface (
&Controller,
&gEfiBlockIoProtocolGuid,
EFI_NATIVE_INTERFACE,
&UsbMass->BlockIo
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
return EFI_SUCCESS;
ON_ERROR:
gBS->FreePool (UsbMass);
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
/**
Stop controlling the device.
@param This The USB mass storage driver binding
@param Controller The device controller controlled by the driver.
@param NumberOfChildren The number of children of this device
@param ChildHandleBuffer The buffer of children handle.
@retval EFI_SUCCESS The driver stopped from controlling the device.
@retval Others Failed to stop the driver
**/
EFI_STATUS
EFIAPI
USBMassDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
USB_MASS_DEVICE *UsbMass;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
//
// First, get our context back from the BLOCK_IO
//
Status = gBS->OpenProtocol (
Controller,
&gEfiBlockIoProtocolGuid,
&BlockIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo);
//
// Uninstall Block I/O protocol from the device handle,
// then call the transport protocol to stop itself.
//
Status = gBS->UninstallProtocolInterface (
Controller,
&gEfiBlockIoProtocolGuid,
&UsbMass->BlockIo
);
if (EFI_ERROR (Status)) {
return Status;
}
gBS->CloseProtocol (
Controller,
&gEfiUsbIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
UsbMass->Transport->Fini (UsbMass->Context);
gBS->FreePool (UsbMass);
return EFI_SUCCESS;
}
EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = {
USBMassDriverBindingSupported,
USBMassDriverBindingStart,
USBMassDriverBindingStop,
0x11,
NULL,
NULL
};
//@MT: EFI_DRIVER_ENTRY_POINT (USBMassStorageEntryPoint)
EFI_STATUS
EFIAPI
USBMassStorageEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
The entry point for the driver, which will install the driver binding and
component name protocol
Arguments:
ImageHandle - The image handle of this driver
SystemTable - The system table
Returns:
EFI_SUCCESS - the protocols are installed OK
Others - Failed to install protocols.
--*/
{
EFI_STATUS Status;
//
// Install driver binding protocol
//
Status = EfiLibInstallAllDriverProtocols (
ImageHandle,
SystemTable,
&gUSBMassDriverBinding,
ImageHandle,
&gUsbMassStorageComponentName,
NULL,
NULL
);
return Status;
}

View File

@@ -0,0 +1,57 @@
/** @file
Copyright (c) 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
UsbMassImpl.h
Abstract:
The implementation of USB mass storage class device driver.
Revision History
**/
#ifndef _EFI_USBMASS_IMPL_H_
#define _EFI_USBMASS_IMPL_H_
typedef struct _USB_MASS_DEVICE USB_MASS_DEVICE;
#include "UsbMass.h"
#include "UsbMassBot.h"
#include "UsbMassCbi.h"
#include "UsbMassBoot.h"
enum {
USB_MASS_SIGNATURE= EFI_SIGNATURE_32 ('U', 's', 'b', 'K'),
};
typedef struct _USB_MASS_DEVICE {
UINT32 Signature;
EFI_HANDLE Controller;
EFI_USB_IO_PROTOCOL *UsbIo;
EFI_BLOCK_IO_PROTOCOL BlockIo;
EFI_BLOCK_IO_MEDIA BlockIoMedia;
BOOLEAN OpticalStorage;
UINT8 Lun; // Logical Unit Number
UINT8 Pdt; // Peripheral Device Type
USB_MASS_TRANSPORT *Transport; // USB mass storage transport protocol
VOID *Context; // Opaque storage for mass transport
};
#define USB_MASS_DEVICE_FROM_BLOCKIO(a) \
CR (a, USB_MASS_DEVICE, BlockIo, USB_MASS_SIGNATURE)
extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName;
#endif

View File

@@ -0,0 +1,95 @@
#/** @file
# Component name for module UsbMassStorage
#
# Copyright (c) 2006, Intel Corporation. All right reserved.
#
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
#**/
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UsbMassStorageDxe
FILE_GUID = 9FB4B4A7-42C0-4bcd-8540-9BCC6711F83E
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = USBMassStorageEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
################################################################################
#
# Sources Section - list of files that are required for the build to succeed.
#
################################################################################
[Sources.common]
UsbMassBoot.h
UsbMassImpl.h
UsbMassBot.h
UsbMassBot.c
ComponentName.c
UsbMassImpl.c
UsbMassBoot.c
UsbMassCbi.h
UsbMass.h
UsbMassCbi.c
################################################################################
#
# Package Dependency Section - list of Package files that are required for
# this module.
#
################################################################################
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
################################################################################
#
# Library Class Section - list of Library Classes that are required for
# this module.
#
################################################################################
[LibraryClasses]
MemoryAllocationLib
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
BaseMemoryLib
DebugLib
################################################################################
#
# Protocol C Name Section - list of Protocol and Protocol Notify C Names
# that this module uses or produces.
#
################################################################################
[Protocols]
gEfiUsbIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiBlockIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@@ -0,0 +1,75 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>UsbMassStorageDxe</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>9FB4B4A7-42C0-4bcd-8540-9BCC6711F83E</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module UsbMassStorage</Abstract>
<Description>FIX ME!</Description>
<Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>
<License>All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>UsbMassStorageDxe</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseMemoryLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>MemoryAllocationLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>UsbMassCbi.c</Filename>
<Filename>UsbMass.h</Filename>
<Filename>UsbMassCbi.h</Filename>
<Filename>UsbMassBoot.c</Filename>
<Filename>UsbMassImpl.c</Filename>
<Filename>ComponentName.c</Filename>
<Filename>UsbMassBot.c</Filename>
<Filename>UsbMassBot.h</Filename>
<Filename>UsbMassImpl.h</Filename>
<Filename>UsbMassBoot.h</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiBlockIoProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUsbIoProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>USBMassStorageEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>