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,164 @@
/** @file
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
UsbBusComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
EFI_STATUS
EFIAPI
UsbBusComponentNameGetControllerName (
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 mUsbBusComponentName = {
UsbBusComponentNameGetDriverName,
UsbBusComponentNameGetControllerName,
"eng"
};
STATIC EFI_UNICODE_STRING_TABLE mUsbBusDriverNameTable[] = {
{ "eng", L"Usb Bus Driver" },
{ NULL , NULL }
};
EFI_STATUS
EFIAPI
UsbBusComponentNameGetDriverName (
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_NAME2_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,
mUsbBusComponentName.SupportedLanguages,
mUsbBusDriverNameTable,
DriverName
);
}
EFI_STATUS
EFIAPI
UsbBusComponentNameGetControllerName (
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_NAME2_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_SUCCESS - The Unicode string for the user readable name in the
language specified by Language for the driver
specified by This was returned in DriverName.
EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.
EFI_INVALID_PARAMETER - Language is NULL.
EFI_INVALID_PARAMETER - ControllerName is NULL.
EFI_UNSUPPORTED - The driver specified by This is not currently managing
the controller specified by ControllerHandle and
ChildHandle.
EFI_UNSUPPORTED - The driver specified by This does not support the
language specified by Language.
--*/
{
return EFI_UNSUPPORTED;
}

View File

@ -0,0 +1,99 @@
#/** @file
# Component name for module UsbBus
#
# 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 = UsbBusDxe
FILE_GUID = 240612B7-A063-11d4-9A3A-0090273FC14D
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = UsbBusDriverEntryPoint
#
# 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]
UsbDesc.c
UsbEnumer.c
UsbEnumer.h
usbbus.c
UsbHub.c
ComponentName.c
UsbUtility.h
UsbHub.h
UsbUtility.c
UsbDesc.h
usbbus.h
################################################################################
#
# 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
DevicePathLib
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
gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiUsb2HcProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiUsbHcProtocolGuid # PROTOCOL ALWAYS_CONSUMED

View File

@ -0,0 +1,85 @@
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>UsbBusDxe</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>240612B7-A063-11d4-9A3A-0090273FC14D</GuidValue>
<Version>1.0</Version>
<Abstract>Component name for module UsbBus</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>UsbBusDxe</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>DevicePathLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>MemoryAllocationLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>usbbus.h</Filename>
<Filename>UsbDesc.h</Filename>
<Filename>UsbUtility.c</Filename>
<Filename>UsbHub.h</Filename>
<Filename>UsbUtility.h</Filename>
<Filename>ComponentName.c</Filename>
<Filename>UsbHub.c</Filename>
<Filename>usbbus.c</Filename>
<Filename>UsbEnumer.h</Filename>
<Filename>UsbEnumer.c</Filename>
<Filename>UsbDesc.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
<Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUsbHcProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiUsb2HcProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiDevicePathProtocolGuid</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>UsbBusDriverEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@ -0,0 +1,991 @@
/** @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:
UsbDesc.c
Abstract:
Manage Usb Descriptor List
Revision History
**/
#include "UsbBus.h"
/**
Free the interface setting descriptor
@param Setting The descriptor to free
@return None
**/
STATIC
VOID
UsbFreeInterfaceDesc (
IN USB_INTERFACE_SETTING *Setting
)
{
USB_ENDPOINT_DESC *Ep;
UINTN Index;
if (Setting->Endpoints != NULL) {
//
// Each interface setting may have several endpoints, free them first.
//
for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
Ep = Setting->Endpoints[Index];
if (Ep != NULL) {
gBS->FreePool (Ep);
}
}
gBS->FreePool (Setting->Endpoints);
}
gBS->FreePool (Setting);
}
/**
Free a configuration descriptor with its interface
descriptors. It may be initialized partially
@param Config The configuration descriptor to free
@return None
**/
STATIC
VOID
UsbFreeConfigDesc (
IN USB_CONFIG_DESC *Config
)
{
USB_INTERFACE_DESC *Interface;
UINTN Index;
UINTN SetIndex;
if (Config->Interfaces != NULL) {
//
// A configuration may have several interfaces, free the interface
//
for (Index = 0; Index < Config->Desc.NumInterfaces; Index++) {
Interface = Config->Interfaces[Index];
if (Interface == NULL) {
continue;
}
//
// Each interface may have several settings, free the settings
//
for (SetIndex = 0; SetIndex < Interface->NumOfSetting; SetIndex++) {
if (Interface->Settings[SetIndex] != NULL) {
UsbFreeInterfaceDesc (Interface->Settings[SetIndex]);
}
}
gBS->FreePool (Interface);
}
gBS->FreePool (Config->Interfaces);
}
gBS->FreePool (Config);
}
/**
Free a device descriptor with its configurations
@param DevDesc The device descriptor
@return None
**/
VOID
UsbFreeDevDesc (
IN USB_DEVICE_DESC *DevDesc
)
{
UINTN Index;
if (DevDesc->Configs != NULL) {
for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
if (DevDesc->Configs[Index] != NULL) {
UsbFreeConfigDesc (DevDesc->Configs[Index]);
}
}
gBS->FreePool (DevDesc->Configs);
}
gBS->FreePool (DevDesc);
}
/**
Create a descriptor
@param DescBuf The buffer of raw descriptor
@param Len The lenght of the raw descriptor buffer
@param Type The type of descriptor to create
@param Consumed Number of bytes consumed
@return Created descriptor or NULL
**/
STATIC
VOID *
UsbCreateDesc (
IN UINT8 *DescBuf,
IN INTN Len,
IN UINT8 Type,
OUT INTN *Consumed
)
{
USB_DESC_HEAD *Head;
INTN DescLen;
INTN CtrlLen;
INTN Offset;
VOID *Desc;
DescLen = 0;
CtrlLen = 0;
*Consumed = 0;
switch (Type) {
case USB_DESC_TYPE_DEVICE:
DescLen = sizeof (EFI_USB_DEVICE_DESCRIPTOR);
CtrlLen = sizeof (USB_DEVICE_DESC);
break;
case USB_DESC_TYPE_CONFIG:
DescLen = sizeof (EFI_USB_CONFIG_DESCRIPTOR);
CtrlLen = sizeof (USB_CONFIG_DESC);
break;
case USB_DESC_TYPE_INTERFACE:
DescLen = sizeof (EFI_USB_INTERFACE_DESCRIPTOR);
CtrlLen = sizeof (USB_INTERFACE_SETTING);
break;
case USB_DESC_TYPE_ENDPOINT:
DescLen = sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);
CtrlLen = sizeof (USB_ENDPOINT_DESC);
break;
}
//
// All the descriptor has a common LTV (Length, Type, Value)
// format. Skip the descriptor that isn't of this Type
//
Offset = 0;
Head = (USB_DESC_HEAD*)DescBuf;
while ((Offset < Len) && (Head->Type != Type)) {
Offset += Head->Len;
Head = (USB_DESC_HEAD*)(DescBuf + Offset);
}
if ((Len <= Offset) || (Len < Offset + DescLen) ||
(Head->Type != Type) || (Head->Len != DescLen)) {
USB_ERROR (("UsbCreateDesc: met mal-format descriptor\n"));
return NULL;
}
Desc = AllocateZeroPool (CtrlLen);
if (Desc == NULL) {
return NULL;
}
CopyMem (Desc, Head, DescLen);
*Consumed = Offset + Head->Len;
return Desc;
}
/**
Parse an interface desciptor and its endpoints
@param DescBuf The buffer of raw descriptor
@param Len The lenght of the raw descriptor buffer
@param Consumed The number of raw descriptor consumed
@return The create interface setting or NULL if failed
**/
STATIC
USB_INTERFACE_SETTING *
UsbParseInterfaceDesc (
IN UINT8 *DescBuf,
IN INTN Len,
OUT INTN *Consumed
)
{
USB_INTERFACE_SETTING *Setting;
USB_ENDPOINT_DESC *Ep;
UINTN Index;
UINTN NumEp;
INTN Used;
INTN Offset;
*Consumed = 0;
Setting = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used);
if (Setting == NULL) {
USB_ERROR (("UsbParseInterfaceDesc: failed to create interface descriptor\n"));
return NULL;
}
Offset = Used;
//
// Create an arry to hold the interface's endpoints
//
NumEp = Setting->Desc.NumEndpoints;
USB_DEBUG (("UsbParseInterfaceDesc: interface %d(setting %d) has %d endpoints\n",
Setting->Desc.InterfaceNumber, Setting->Desc.AlternateSetting, NumEp));
if (NumEp == 0) {
goto ON_EXIT;
}
Setting->Endpoints = AllocateZeroPool (sizeof (USB_ENDPOINT_DESC *) * NumEp);
if (Setting->Endpoints == NULL) {
goto ON_ERROR;
}
//
// Create the endpoints for this interface
//
for (Index = 0; Index < NumEp; Index++) {
Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used);
if (Ep == NULL) {
USB_ERROR (("UsbParseInterfaceDesc: failed to create endpoint(index %d)\n", Index));
goto ON_ERROR;
}
Setting->Endpoints[Index] = Ep;
Offset += Used;
}
ON_EXIT:
*Consumed = Offset;
return Setting;
ON_ERROR:
UsbFreeInterfaceDesc (Setting);
return NULL;
}
/**
Parse the configuration descriptor and its interfaces.
@param DescBuf The buffer of raw descriptor
@param Len The lenght of the raw descriptor buffer
@return The created configuration descriptor
**/
STATIC
USB_CONFIG_DESC *
UsbParseConfigDesc (
IN UINT8 *DescBuf,
IN INTN Len
)
{
USB_CONFIG_DESC *Config;
USB_INTERFACE_SETTING *Setting;
USB_INTERFACE_DESC *Interface;
UINTN Index;
UINTN NumIf;
INTN Consumed;
ASSERT (DescBuf != NULL);
Config = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_CONFIG, &Consumed);
if (Config == NULL) {
return NULL;
}
//
// Initialize an array of setting for the configuration's interfaces.
//
NumIf = Config->Desc.NumInterfaces;
Config->Interfaces = AllocateZeroPool (sizeof (USB_INTERFACE_DESC *) * NumIf);
if (Config->Interfaces == NULL) {
goto ON_ERROR;
}
USB_DEBUG (("UsbParseConfigDesc: config %d has %d interfaces\n",
Config->Desc.ConfigurationValue, NumIf));
for (Index = 0; Index < NumIf; Index++) {
Interface = AllocateZeroPool (sizeof (USB_INTERFACE_DESC));
if (Interface == NULL) {
goto ON_ERROR;
}
Config->Interfaces[Index] = Interface;
}
//
// If a configuration has several interfaces, these interfaces are
// numbered from zero to n. If a interface has several settings,
// these settings are also number from zero to m. The interface
// setting must be organized as |interface 0, setting 0|interface 0
// setting 1|interface 1, setting 0|interface 2, setting 0|. Check
// USB2.0 spec, page 267.
//
DescBuf += Consumed;
Len -= Consumed;
while (Len > 0) {
Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed);
if ((Setting == NULL)) {
USB_ERROR (("UsbParseConfigDesc: failed to parse interface setting\n"));
goto ON_ERROR;
} else if (Setting->Desc.InterfaceNumber >= NumIf) {
USB_ERROR (("UsbParseConfigDesc: mal-formated interface descriptor\n"));
UsbFreeInterfaceDesc (Setting);
goto ON_ERROR;
}
//
// Insert the descriptor to the corresponding set.
//
Interface = Config->Interfaces[Setting->Desc.InterfaceNumber];
if (Interface->NumOfSetting >= USB_MAX_INTERFACE_SETTING) {
goto ON_ERROR;
}
Interface->Settings[Interface->NumOfSetting] = Setting;
Interface->NumOfSetting++;
DescBuf += Consumed;
Len -= Consumed;
}
return Config;
ON_ERROR:
UsbFreeConfigDesc (Config);
return NULL;
}
/**
USB standard control transfer support routine. This
function is used by USB device. It is possible that
the device's interfaces are still waiting to be
enumerated.
@param UsbDev The usb device
@param Direction The direction of data transfer
@param Type Standard / class specific / vendor specific
@param Target The receiving target
@param Request Which request
@param Value The wValue parameter of the request
@param Index The wIndex parameter of the request
@param Buf The buffer to receive data into / transmit from
@param Length The length of the buffer
@retval EFI_SUCCESS The control request is executed
@retval EFI_DEVICE_ERROR Failed to execute the control transfer
**/
EFI_STATUS
UsbCtrlRequest (
IN USB_DEVICE *UsbDev,
IN EFI_USB_DATA_DIRECTION Direction,
IN UINTN Type,
IN UINTN Target,
IN UINTN Request,
IN UINT16 Value,
IN UINT16 Index,
IN OUT VOID *Buf,
IN UINTN Length
)
{
EFI_USB_DEVICE_REQUEST DevReq;
EFI_STATUS Status;
UINT32 Result;
UINTN Len;
ASSERT ((UsbDev != NULL) && (UsbDev->Bus != NULL));
DevReq.RequestType = USB_REQUEST_TYPE (Direction, Type, Target);
DevReq.Request = (UINT8) Request;
DevReq.Value = Value;
DevReq.Index = Index;
DevReq.Length = (UINT16) Length;
Len = Length;
Status = UsbHcControlTransfer (
UsbDev->Bus,
UsbDev->Address,
UsbDev->Speed,
UsbDev->MaxPacket0,
&DevReq,
Direction,
Buf,
&Len,
50 * USB_STALL_1_MS,
&UsbDev->Translator,
&Result
);
return Status;
}
/**
Get the standard descriptors.
@param UsbDev The USB device to read descriptor from
@param DescType The type of descriptor to read
@param DescIndex The index of descriptor to read
@param LangId Language ID, only used to get string, otherwise set
it to 0
@param Buf The buffer to hold the descriptor read
@param Length The length of the buffer
@retval EFI_SUCCESS The descriptor is read OK
@retval Others Failed to retrieve the descriptor
**/
STATIC
EFI_STATUS
UsbCtrlGetDesc (
IN USB_DEVICE *UsbDev,
IN UINTN DescType,
IN UINTN DescIndex,
IN UINT16 LangId,
OUT VOID *Buf,
IN UINTN Length
)
{
EFI_STATUS Status;
Status = UsbCtrlRequest (
UsbDev,
EfiUsbDataIn,
USB_REQ_TYPE_STANDARD,
USB_TARGET_DEVICE,
USB_REQ_GET_DESCRIPTOR,
(UINT16) ((DescType << 8) | DescIndex),
LangId,
Buf,
Length
);
return Status;
}
/**
Return the max packet size for endpoint zero. This function
is the first function called to get descriptors during bus
enumeration.
@param UsbDev The usb device
@retval EFI_SUCCESS The max packet size of endpoint zero is retrieved
@retval EFI_DEVICE_ERROR Failed to retrieve it
**/
EFI_STATUS
UsbGetMaxPacketSize0 (
IN USB_DEVICE *UsbDev
)
{
EFI_USB_DEVICE_DESCRIPTOR DevDesc;
EFI_STATUS Status;
UINTN Index;
//
// Get the first 8 bytes of the device descriptor which contains
// max packet size for endpoint 0, which is at least 8.
//
UsbDev->MaxPacket0 = 8;
for (Index = 0; Index < 3; Index++) {
Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8);
if (!EFI_ERROR (Status)) {
UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0;
return EFI_SUCCESS;
}
gBS->Stall (100 * USB_STALL_1_MS);
}
return EFI_DEVICE_ERROR;
}
/**
Get the device descriptor for the device.
@param UsbDev The Usb device to retrieve descriptor from
@retval EFI_SUCCESS The device descriptor is returned
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
**/
STATIC
EFI_STATUS
UsbGetDevDesc (
IN USB_DEVICE *UsbDev
)
{
USB_DEVICE_DESC *DevDesc;
EFI_STATUS Status;
DevDesc = AllocateZeroPool (sizeof (USB_DEVICE_DESC));
if (DevDesc == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = UsbCtrlGetDesc (
UsbDev,
USB_DESC_TYPE_DEVICE,
0,
0,
DevDesc,
sizeof (EFI_USB_DEVICE_DESCRIPTOR)
);
if (EFI_ERROR (Status)) {
gBS->FreePool (DevDesc);
} else {
UsbDev->DevDesc = DevDesc;
}
return Status;
}
/**
Retrieve the indexed string for the language. It requires two
steps to get a string, first to get the string's length. Then
the string itself.
@param UsbDev The usb device
@param Index The index the string to retrieve
@param LangId Language ID
@return The created string descriptor or NULL
**/
EFI_USB_STRING_DESCRIPTOR *
UsbGetOneString (
IN USB_DEVICE *UsbDev,
IN UINT8 Index,
IN UINT16 LangId
)
{
EFI_USB_STRING_DESCRIPTOR Desc;
EFI_STATUS Status;
UINT8 *Buf;
//
// First get two bytes which contains the string length.
//
Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2);
if (EFI_ERROR (Status)) {
return NULL;
}
Buf = AllocateZeroPool (Desc.Length);
if (Buf == NULL) {
return NULL;
}
Status = UsbCtrlGetDesc (
UsbDev,
USB_DESC_TYPE_STRING,
Index,
LangId,
Buf,
Desc.Length
);
if (EFI_ERROR (Status)) {
gBS->FreePool (Buf);
return NULL;
}
return (EFI_USB_STRING_DESCRIPTOR *) Buf;
}
/**
Build the language ID table for string descriptors
@param UsbDev The Usb device
@retval EFI_UNSUPPORTED This device doesn't support string table
**/
STATIC
EFI_STATUS
UsbBuildLangTable (
IN USB_DEVICE *UsbDev
)
{
EFI_USB_STRING_DESCRIPTOR *Desc;
EFI_STATUS Status;
UINTN Index;
UINTN Max;
UINT16 *Point;
//
// The string of language ID zero returns the supported languages
//
Desc = UsbGetOneString (UsbDev, 0, 0);
if (Desc == NULL) {
return EFI_UNSUPPORTED;
}
if (Desc->Length < 4) {
Status = EFI_UNSUPPORTED;
goto ON_EXIT;
}
Status = EFI_SUCCESS;
Max = (Desc->Length - 2) / 2;
Max = (Max < USB_MAX_LANG_ID ? Max : USB_MAX_LANG_ID);
Point = Desc->String;
for (Index = 0; Index < Max; Index++) {
UsbDev->LangId[Index] = *Point;
Point++;
}
UsbDev->TotalLangId = (UINT16)Max;
ON_EXIT:
gBS->FreePool (Desc);
return Status;
}
/**
Retrieve the indexed configure for the device. USB device
returns the configuration togetther with the interfaces for
this configuration. Configuration descriptor is also of
variable length
@param UsbDev The Usb interface
@param Index The index of the configuration
@return The created configuration descriptor
**/
STATIC
EFI_USB_CONFIG_DESCRIPTOR *
UsbGetOneConfig (
IN USB_DEVICE *UsbDev,
IN UINT8 Index
)
{
EFI_USB_CONFIG_DESCRIPTOR Desc;
EFI_STATUS Status;
VOID *Buf;
//
// First get four bytes which contains the total length
// for this configuration.
//
Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, &Desc, 8);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbGetOneConfig: failed to get descript length(%d) %r\n",
Status, Desc.TotalLength));
return NULL;
}
USB_DEBUG (("UsbGetOneConfig: total length is %d\n", Desc.TotalLength));
Buf = AllocateZeroPool (Desc.TotalLength);
if (Buf == NULL) {
return NULL;
}
Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, Buf, Desc.TotalLength);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbGetOneConfig: failed to get full descript %r\n", Status));
gBS->FreePool (Buf);
return NULL;
}
return Buf;
}
/**
Build the whole array of descriptors. This function must
be called after UsbGetMaxPacketSize0 returns the max packet
size correctly for endpoint 0.
@param UsbDev The Usb device
@retval EFI_SUCCESS The descriptor table is build
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the descriptor
**/
EFI_STATUS
UsbBuildDescTable (
IN USB_DEVICE *UsbDev
)
{
EFI_USB_CONFIG_DESCRIPTOR *Config;
USB_DEVICE_DESC *DevDesc;
USB_CONFIG_DESC *ConfigDesc;
UINT8 NumConfig;
EFI_STATUS Status;
UINT8 Index;
//
// Get the device descriptor, then allocate the configure
// descriptor pointer array to hold configurations.
//
Status = UsbGetDevDesc (UsbDev);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbBuildDescTable: failed to get device descriptor - %r\n", Status));
return Status;
}
DevDesc = UsbDev->DevDesc;
NumConfig = DevDesc->Desc.NumConfigurations;
DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *));
if (DevDesc->Configs == NULL) {
return EFI_OUT_OF_RESOURCES;
}
USB_DEBUG (("UsbBuildDescTable: device has %d configures\n", NumConfig));
//
// Read each configurations, then parse them
//
for (Index = 0; Index < NumConfig; Index++) {
Config = UsbGetOneConfig (UsbDev, Index);
if (Config == NULL) {
USB_ERROR (("UsbBuildDescTable: failed to get configure (index %d)\n", Index));
//
// If we can get the default descriptor, it is likely that the
// device is still operational.
//
if (Index == 0) {
return EFI_DEVICE_ERROR;
}
break;
}
ConfigDesc = UsbParseConfigDesc ((UINT8 *) Config, Config->TotalLength);
gBS->FreePool (Config);
if (ConfigDesc == NULL) {
USB_ERROR (("UsbBuildDescTable: failed to parse configure (index %d)\n", Index));
//
// If we can get the default descriptor, it is likely that the
// device is still operational.
//
if (Index == 0) {
return EFI_DEVICE_ERROR;
}
break;
}
DevDesc->Configs[Index] = ConfigDesc;
}
//
// Don't return error even this function failed because
// it is possible for the device to not support strings.
//
Status = UsbBuildLangTable (UsbDev);
if (EFI_ERROR (Status)) {
USB_DEBUG (("UsbBuildDescTable: get language ID table %r\n", Status));
}
return EFI_SUCCESS;
}
/**
Set the device's address.
@param UsbDev The device to set address to
@param Address The address to set
@retval EFI_SUCCESS The device is set to the address
@retval Others Failed to set the device address
**/
EFI_STATUS
UsbSetAddress (
IN USB_DEVICE *UsbDev,
IN UINT8 Address
)
{
EFI_STATUS Status;
Status = UsbCtrlRequest (
UsbDev,
EfiUsbNoData,
USB_REQ_TYPE_STANDARD,
USB_TARGET_DEVICE,
USB_REQ_SET_ADDRESS,
Address,
0,
NULL,
0
);
return Status;
}
/**
Set the device's configuration. This function changes
the device's internal state. UsbSelectConfig changes
the Usb bus's internal state.
@param UsbDev The USB device to set configure to
@param ConfigIndex The configure index to set
@retval EFI_SUCCESS The device is configured now
@retval Others Failed to set the device configure
**/
EFI_STATUS
UsbSetConfig (
IN USB_DEVICE *UsbDev,
IN UINT8 ConfigIndex
)
{
EFI_STATUS Status;
Status = UsbCtrlRequest (
UsbDev,
EfiUsbNoData,
USB_REQ_TYPE_STANDARD,
USB_TARGET_DEVICE,
USB_REQ_SET_CONFIG,
ConfigIndex,
0,
NULL,
0
);
return Status;
}
/**
Usb UsbIo interface to clear the feature. This is should
only be used by HUB which is considered a device driver
on top of the UsbIo interface.
@param UsbIo The UsbIo interface
@param Target The target of the transfer: endpoint/device
@param Feature The feature to clear
@param Index The wIndex parameter
@retval EFI_SUCCESS The device feature is cleared
@retval Others Failed to clear the feature
**/
EFI_STATUS
UsbIoClearFeature (
IN EFI_USB_IO_PROTOCOL *UsbIo,
IN UINTN Target,
IN UINT16 Feature,
IN UINT16 Index
)
{
EFI_USB_DEVICE_REQUEST DevReq;
UINT32 UsbResult;
EFI_STATUS Status;
DevReq.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, Target);
DevReq.Request = USB_REQ_CLEAR_FEATURE;
DevReq.Value = Feature;
DevReq.Index = Index;
DevReq.Length = 0;
Status = UsbIo->UsbControlTransfer (
UsbIo,
&DevReq,
EfiUsbNoData,
10 * USB_STALL_1_MS,
NULL,
0,
&UsbResult
);
return Status;
}

View File

@ -0,0 +1,146 @@
/** @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:
UsbDesc.h
Abstract:
Manage Usb Descriptor List
Revision History
**/
#ifndef _USB_DESCRIPTOR_H_
#define _USB_DESCRIPTOR_H_
enum {
USB_MAX_INTERFACE_SETTING = 8,
};
//
// The RequestType in EFI_USB_DEVICE_REQUEST is composed of
// three fields: One bit direction, 2 bit type, and 5 bit
// target.
//
#define USB_REQUEST_TYPE(Dir, Type, Target) \
((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))
//
// A common header for usb standard descriptor.
// Each stand descriptor has a length and type.
//
#pragma pack(1)
typedef struct {
UINT8 Len;
UINT8 Type;
} USB_DESC_HEAD;
#pragma pack()
//
// Each USB device has a device descriptor. Each device may
// have several configures. Each configure contains several
// interfaces. Each interface may have several settings. Each
// setting has several endpoints.
//
// EFI_USB_..._DESCRIPTOR must be the first member of the
// structure.
//
typedef struct {
EFI_USB_ENDPOINT_DESCRIPTOR Desc;
UINT8 Toggle;
} USB_ENDPOINT_DESC;
typedef struct {
EFI_USB_INTERFACE_DESCRIPTOR Desc;
USB_ENDPOINT_DESC **Endpoints;
} USB_INTERFACE_SETTING;
//
// An interface may have several settings. Use a
// fixed max number of settings to simplify code.
// It should sufice in most environments.
//
typedef struct {
USB_INTERFACE_SETTING* Settings[USB_MAX_INTERFACE_SETTING];
UINTN NumOfSetting;
UINT8 ActiveIndex; // Index of active setting
} USB_INTERFACE_DESC;
typedef struct {
EFI_USB_CONFIG_DESCRIPTOR Desc;
USB_INTERFACE_DESC **Interfaces;
} USB_CONFIG_DESC;
typedef struct {
EFI_USB_DEVICE_DESCRIPTOR Desc;
USB_CONFIG_DESC **Configs;
} USB_DEVICE_DESC;
EFI_STATUS
UsbCtrlRequest (
IN USB_DEVICE *UsbDev,
IN EFI_USB_DATA_DIRECTION Direction,
IN UINTN Type,
IN UINTN Target,
IN UINTN Request,
IN UINT16 Value,
IN UINT16 Index,
IN OUT VOID *Buf,
IN UINTN Length
);
EFI_STATUS
UsbGetMaxPacketSize0 (
IN USB_DEVICE *UsbDev
);
VOID
UsbFreeDevDesc (
IN USB_DEVICE_DESC *DevDesc
);
EFI_USB_STRING_DESCRIPTOR*
UsbGetOneString (
IN USB_DEVICE *UsbDev,
IN UINT8 StringIndex,
IN UINT16 LangId
);
EFI_STATUS
UsbBuildDescTable (
IN USB_DEVICE *UsbDev
);
EFI_STATUS
UsbSetAddress (
IN USB_DEVICE *UsbDev,
IN UINT8 Address
);
EFI_STATUS
UsbSetConfig (
IN USB_DEVICE *UsbDev,
IN UINT8 ConfigIndex
);
EFI_STATUS
UsbIoClearFeature (
IN EFI_USB_IO_PROTOCOL *UsbIo,
IN UINTN Target,
IN UINT16 Feature,
IN UINT16 Index
);
#endif

View File

@ -0,0 +1,991 @@
/** @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:
UsbEnumer.c
Abstract:
Usb bus enumeration support
Revision History
**/
#include "UsbBus.h"
/**
Return the endpoint descriptor in this interface
@param UsbIf The interface to search in
@param EpAddr The address of the endpoint to return
@return The endpoint descriptor or NULL
**/
USB_ENDPOINT_DESC *
UsbGetEndpointDesc (
IN USB_INTERFACE *UsbIf,
IN UINT8 EpAddr
)
{
USB_ENDPOINT_DESC *EpDesc;
UINTN Index;
for (Index = 0; Index < UsbIf->IfSetting->Desc.NumEndpoints; Index++) {
EpDesc = UsbIf->IfSetting->Endpoints[Index];
if (EpDesc->Desc.EndpointAddress == EpAddr) {
return EpDesc;
}
}
return NULL;
}
/**
Free the resource used by USB interface
@param UsbIf The USB interface to free
@return None
**/
STATIC
VOID
UsbFreeInterface (
IN USB_INTERFACE *UsbIf
)
{
UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
gBS->UninstallMultipleProtocolInterfaces (
UsbIf->Handle,
&gEfiDevicePathProtocolGuid,
UsbIf->DevicePath,
&gEfiUsbIoProtocolGuid,
&UsbIf->UsbIo,
NULL
);
if (UsbIf->DevicePath != NULL) {
gBS->FreePool (UsbIf->DevicePath);
}
gBS->FreePool (UsbIf);
}
/**
Create an interface for the descriptor IfDesc. Each
device's configuration can have several interfaces.
@param Device The device has the interface descriptor
@param IfDesc The interface descriptor
@return The created USB interface for the descriptor, or NULL.
**/
STATIC
USB_INTERFACE *
UsbCreateInterface (
IN USB_DEVICE *Device,
IN USB_INTERFACE_DESC *IfDesc
)
{
USB_DEVICE_PATH UsbNode;
USB_INTERFACE *UsbIf;
USB_INTERFACE *HubIf;
EFI_STATUS Status;
UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));
if (UsbIf == NULL) {
return NULL;
}
UsbIf->Signature = USB_INTERFACE_SIGNATURE;
UsbIf->Device = Device;
UsbIf->IfDesc = IfDesc;
UsbIf->IfSetting = IfDesc->Settings[IfDesc->ActiveIndex];
UsbIf->UsbIo = mUsbIoProtocol;
//
// Install protocols for USBIO and device path
//
UsbNode.Header.Type = MESSAGING_DEVICE_PATH;
UsbNode.Header.SubType = MSG_USB_DP;
UsbNode.ParentPortNumber = Device->ParentPort;
UsbNode.InterfaceNumber = UsbIf->IfSetting->Desc.InterfaceNumber;
SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
HubIf = Device->ParentIf;
ASSERT (HubIf != NULL);
UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);
if (UsbIf->DevicePath == NULL) {
USB_ERROR (("UsbCreateInterface: failed to create device path\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
Status = gBS->InstallMultipleProtocolInterfaces (
&UsbIf->Handle,
&gEfiDevicePathProtocolGuid,
UsbIf->DevicePath,
&gEfiUsbIoProtocolGuid,
&UsbIf->UsbIo,
NULL
);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbCreateInterface: failed to install UsbIo - %r\n", Status));
goto ON_ERROR;
}
//
// Open USB Host Controller Protocol by Child
//
Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
&UsbIf->Handle,
&gEfiDevicePathProtocolGuid,
UsbIf->DevicePath,
&gEfiUsbIoProtocolGuid,
&UsbIf->UsbIo,
NULL
);
USB_ERROR (("UsbCreateInterface: failed to open host for child - %r\n", Status));
goto ON_ERROR;
}
return UsbIf;
ON_ERROR:
if (UsbIf->DevicePath) {
gBS->FreePool (UsbIf->DevicePath);
}
gBS->FreePool (UsbIf);
return NULL;
}
/**
Free the resource used by this USB device
@param Device The USB device to free
@return None
**/
STATIC
VOID
UsbFreeDevice (
IN USB_DEVICE *Device
)
{
if (Device->DevDesc != NULL) {
UsbFreeDevDesc (Device->DevDesc);
}
gBS->FreePool (Device);
}
/**
Create a device which is on the parent's ParentPort port.
@param ParentIf The parent HUB interface
@param ParentPort The port on the HUB this device is connected to
@return Created USB device
**/
STATIC
USB_DEVICE *
UsbCreateDevice (
IN USB_INTERFACE *ParentIf,
IN UINT8 ParentPort
)
{
USB_DEVICE *Device;
ASSERT (ParentIf != NULL);
Device = AllocateZeroPool (sizeof (USB_DEVICE));
if (Device == NULL) {
return NULL;
}
Device->Bus = ParentIf->Device->Bus;
Device->MaxPacket0 = 8;
Device->ParentAddr = ParentIf->Device->Address;
Device->ParentIf = ParentIf;
Device->ParentPort = ParentPort;
return Device;
}
/**
Connect the USB interface with its driver. EFI USB bus will
create a USB interface for each seperate interface descriptor.
@param UsbIf The interface to connect driver to
@return EFI_SUCCESS : Interface is managed by some driver
@return Others : Failed to locate a driver for this interface
**/
STATIC
EFI_STATUS
UsbConnectDriver (
IN USB_INTERFACE *UsbIf
)
{
EFI_STATUS Status;
EFI_TPL OldTpl;
Status = EFI_SUCCESS;
//
// Hub is maintained by the USB bus driver. Otherwise try to
// connect drivers with this interface
//
if (UsbIsHubInterface (UsbIf)) {
USB_DEBUG (("UsbConnectDriver: found a hub device\n"));
Status = mUsbHubApi.Init (UsbIf);
} else {
//
// This function is called in both UsbIoControlTransfer and
// the timer callback in hub enumeration. So, at least it is
// called at TPL_CALLBACK. Some driver sitting on USB has
// twisted TPL used. It should be no problem for us to connect
// or disconnect at CALLBACK.
//
OldTpl = UsbGetCurrentTpl ();
USB_DEBUG (("UsbConnectDriver: TPL before connect is %d\n", OldTpl));
gBS->RestoreTPL (TPL_CALLBACK);
Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status);
USB_DEBUG (("UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl()));
ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
gBS->RaiseTPL (OldTpl);
}
return Status;
}
/**
Select an alternate setting for the interface.
Each interface can have several mutually exclusive
settings. Only one setting is active. It will
also reset its endpoints' toggle to zero.
@param IfDesc The interface descriptor to set
@param Alternate The alternate setting number to locate
@retval EFI_NOT_FOUND There is no setting with this alternate index
@retval EFI_SUCCESS The interface is set to Alternate setting.
**/
EFI_STATUS
UsbSelectSetting (
IN USB_INTERFACE_DESC *IfDesc,
IN UINT8 Alternate
)
{
USB_INTERFACE_SETTING *Setting;
UINT8 Index;
//
// Locate the active alternate setting
//
Setting = NULL;
for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {
Setting = IfDesc->Settings[Index];
if (Setting->Desc.AlternateSetting == Alternate) {
break;
}
}
if (Index == IfDesc->NumOfSetting) {
return EFI_NOT_FOUND;
}
IfDesc->ActiveIndex = Index;
USB_DEBUG (("UsbSelectSetting: setting %d selected for interface %d\n",
Alternate, Setting->Desc.InterfaceNumber));
//
// Reset the endpoint toggle to zero
//
for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
Setting->Endpoints[Index]->Toggle = 0;
}
return EFI_SUCCESS;
}
/**
Select a new configuration for the device. Each
device may support several configurations.
@param Device The device to select configuration
@param ConfigValue The index of the configuration ( != 0)
@retval EFI_NOT_FOUND There is no configuration with the index
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource
@retval EFI_SUCCESS The configuration is selected.
**/
EFI_STATUS
UsbSelectConfig (
IN USB_DEVICE *Device,
IN UINT8 ConfigValue
)
{
USB_DEVICE_DESC *DevDesc;
USB_CONFIG_DESC *ConfigDesc;
USB_INTERFACE_DESC *IfDesc;
USB_INTERFACE *UsbIf;
EFI_STATUS Status;
UINT8 Index;
//
// Locate the active config, then set the device's pointer
//
DevDesc = Device->DevDesc;
ConfigDesc = NULL;
for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {
ConfigDesc = DevDesc->Configs[Index];
if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {
break;
}
}
if (Index == DevDesc->Desc.NumConfigurations) {
return EFI_NOT_FOUND;
}
Device->ActiveConfig = ConfigDesc;
USB_DEBUG (("UsbSelectConfig: config %d selected for device %d\n",
ConfigValue, Device->Address));
//
// Create interfaces for each USB interface descriptor.
//
for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {
//
// First select the default interface setting, and reset
// the endpoint toggles to zero for its endpoints.
//
IfDesc = ConfigDesc->Interfaces[Index];
UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);
//
// Create a USB_INTERFACE and install USB_IO and other protocols
//
UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);
if (UsbIf == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Device->Interfaces[Index] = UsbIf;
//
// Connect the device to drivers, if it failed, ignore
// the error. Don't let the unsupported interfaces to block
// the supported interfaces.
//
Status = UsbConnectDriver (UsbIf);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbSelectConfig: failed to connect driver %r, ignored\n", Status));
}
}
Device->NumOfInterface = Index;
return EFI_SUCCESS;
}
/**
Disconnect the USB interface with its driver.
@param UsbIf The interface to disconnect driver from
@return None
**/
STATIC
VOID
UsbDisconnectDriver (
IN USB_INTERFACE *UsbIf
)
{
EFI_TPL OldTpl;
//
// Release the hub if it's a hub controller, otherwise
// disconnect the driver if it is managed by other drivers.
//
if (UsbIf->IsHub) {
UsbIf->HubApi->Release (UsbIf);
} else if (UsbIf->IsManaged) {
//
// This function is called in both UsbIoControlTransfer and
// the timer callback in hub enumeration. So, at least it is
// called at TPL_CALLBACK. Some driver sitting on USB has
// twisted TPL used. It should be no problem for us to connect
// or disconnect at CALLBACK.
//
OldTpl = UsbGetCurrentTpl ();
USB_DEBUG (("UsbDisconnectDriver: old TPL is %d\n", OldTpl));
gBS->RestoreTPL (TPL_CALLBACK);
gBS->DisconnectController (UsbIf->Handle, NULL, NULL);
UsbIf->IsManaged = FALSE;
USB_DEBUG (("UsbDisconnectDriver: TPL after disconnect is %d\n", UsbGetCurrentTpl()));
ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
gBS->RaiseTPL (OldTpl);
}
}
/**
Remove the current device configuration
@param Device The USB device to remove configuration from
@return None
**/
VOID
UsbRemoveConfig (
IN USB_DEVICE *Device
)
{
USB_INTERFACE *UsbIf;
UINTN Index;
//
// Remove each interface of the device
//
for (Index = 0; Index < Device->NumOfInterface; Index++) {
UsbIf = Device->Interfaces[Index];
if (UsbIf == NULL) {
continue;
}
UsbDisconnectDriver (UsbIf);
UsbFreeInterface (UsbIf);
Device->Interfaces[Index] = NULL;
}
Device->ActiveConfig = NULL;
Device->NumOfInterface = 0;
}
/**
Remove the device and all its children from the bus.
@param Device The device to remove
@retval EFI_SUCCESS The device is removed
**/
EFI_STATUS
UsbRemoveDevice (
IN USB_DEVICE *Device
)
{
USB_BUS *Bus;
USB_DEVICE *Child;
EFI_STATUS Status;
UINT8 Index;
Bus = Device->Bus;
//
// Remove all the devices on its downstream ports. Search from devices[1].
// Devices[0] is the root hub.
//
for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
Child = Bus->Devices[Index];
if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {
continue;
}
Status = UsbRemoveDevice (Child);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbRemoveDevice: failed to remove child, ignore error\n"));
Bus->Devices[Index] = NULL;
}
}
UsbRemoveConfig (Device);
USB_DEBUG (("UsbRemoveDevice: device %d removed\n", Device->Address));
Bus->Devices[Device->Address] = NULL;
UsbFreeDevice (Device);
return EFI_SUCCESS;
}
/**
Find the child device on the hub's port
@param HubIf The hub interface
@param Port The port of the hub this child is connected to
@return The device on the hub's port, or NULL if there is none
**/
STATIC
USB_DEVICE *
UsbFindChild (
IN USB_INTERFACE *HubIf,
IN UINT8 Port
)
{
USB_DEVICE *Device;
USB_BUS *Bus;
UINTN Index;
Bus = HubIf->Device->Bus;
//
// Start checking from device 1, device 0 is the root hub
//
for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
Device = Bus->Devices[Index];
if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&
(Device->ParentPort == Port)) {
return Device;
}
}
return NULL;
}
/**
Enumerate and configure the new device on the port of this HUB interface.
@param HubIf The HUB that has the device connected
@param Port The port index of the hub (started with zero)
@retval EFI_SUCCESS The device is enumerated (added or removed)
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
@retval Others Failed to enumerate the device
**/
STATIC
EFI_STATUS
UsbEnumerateNewDev (
IN USB_INTERFACE *HubIf,
IN UINT8 Port
)
{
USB_BUS *Bus;
USB_HUB_API *HubApi;
USB_DEVICE *Child;
USB_DEVICE *Parent;
EFI_USB_PORT_STATUS PortState;
UINT8 Address;
UINT8 Config;
EFI_STATUS Status;
Address = USB_MAX_DEVICES;
Parent = HubIf->Device;
Bus = Parent->Bus;
HubApi = HubIf->HubApi;
//
// Wait at least 100 ms for the power on port to stable
//
gBS->Stall (100 * USB_STALL_1_MS);
//
// Hub resets the device for at least 10 milliseconds.
// Host learns device speed. If device is of low/full speed
// and the hub is a EHCI root hub, ResetPort will release
// the device to its companion UHCI and return an error.
//
Status = HubApi->ResetPort (HubIf, Port);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));
return Status;
}
USB_DEBUG (("UsbEnumerateNewDev: hub port %d is reset\n", Port));
Child = UsbCreateDevice (HubIf, Port);
if (Child == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// OK, now identify the device speed. After reset, hub
// fully knows the actual device speed.
//
Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumerateNewDev: failed to get speed of port %d\n", Port));
goto ON_ERROR;
}
if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
Child->Speed = EFI_USB_SPEED_LOW;
} else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
Child->Speed = EFI_USB_SPEED_HIGH;
} else {
Child->Speed = EFI_USB_SPEED_FULL;
}
USB_DEBUG (("UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));
if (Child->Speed != EFI_USB_SPEED_HIGH) {
//
// If the child isn't a high speed device, it is necessary to
// set the transaction translator. This is quite simple:
// 1. if parent is of high speed, then parent is our translator
// 2. otherwise use parent's translator.
//
if (Parent->Speed == EFI_USB_SPEED_HIGH) {
Child->Translator.TranslatorHubAddress = Parent->Address;
Child->Translator.TranslatorPortNumber = Port;
} else {
Child->Translator = Parent->Translator;
}
USB_DEBUG (("UsbEnumerateNewDev: device uses translator (%d, %d)\n",
Child->Translator.TranslatorHubAddress,
Child->Translator.TranslatorPortNumber));
}
//
// After port is reset, hub establishes a signal path between
// the device and host (DEFALUT state). Device¡¯s registers are
// reset, use default address 0 (host enumerates one device at
// a time) , and ready to respond to control transfer at EP 0.
//
//
// Host sends a Get_Descriptor request to learn the max packet
// size of default pipe (only part of the device¡¯s descriptor).
//
Status = UsbGetMaxPacketSize0 (Child);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));
goto ON_ERROR;
}
USB_DEBUG (("UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));
//
// Host assigns an address to the device. Device completes the
// status stage with default address, then switches to new address.
// ADDRESS state. Address zero is reserved for root hub.
//
for (Address = 1; Address < USB_MAX_DEVICES; Address++) {
if (Bus->Devices[Address] == NULL) {
break;
}
}
if (Address == USB_MAX_DEVICES) {
USB_ERROR (("UsbEnumerateNewDev: address pool is full for port %d\n", Port));
Status = EFI_ACCESS_DENIED;
goto ON_ERROR;
}
Bus->Devices[Address] = Child;
Status = UsbSetAddress (Child, Address);
Child->Address = Address;
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumerateNewDev: failed to set device address - %r\n", Status));
goto ON_ERROR;
}
//
// Wait 20ms for set address to complete
//
gBS->Stall (20 * USB_STALL_1_MS);
USB_DEBUG (("UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));
//
// Host learns about the device¡¯s abilities by requesting device's
// entire descriptions.
//
Status = UsbBuildDescTable (Child);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));
goto ON_ERROR;
}
//
// Select a default configuration: UEFI must set the configuration
// before the driver can connect to the device.
//
Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;
Status = UsbSetConfig (Child, Config);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));
goto ON_ERROR;
}
USB_DEBUG (("UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));
//
// Host assigns and loads a device driver.
//
Status = UsbSelectConfig (Child, Config);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));
goto ON_ERROR;
}
return EFI_SUCCESS;
ON_ERROR:
if (Address != USB_MAX_DEVICES) {
Bus->Devices[Address] = NULL;
}
if (Child != NULL) {
UsbFreeDevice (Child);
}
return Status;
}
/**
Process the events on the port.
@param HubIf The HUB that has the device connected
@param Port The port index of the hub (started with zero)
@retval EFI_SUCCESS The device is enumerated (added or removed)
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device
@retval Others Failed to enumerate the device
**/
STATIC
EFI_STATUS
UsbEnumeratePort (
IN USB_INTERFACE *HubIf,
IN UINT8 Port
)
{
USB_HUB_API *HubApi;
USB_DEVICE *Child;
EFI_USB_PORT_STATUS PortState;
EFI_STATUS Status;
Child = NULL;
HubApi = HubIf->HubApi;
//
// Host learns of the new device by polling the hub for port changes.
//
Status = HubApi->GetPortStatus (HubIf, Port, &PortState);
if (EFI_ERROR (Status)) {
USB_ERROR (("UsbEnumeratePort: failed to get state of port %d\n", Port));
return Status;
}
if (PortState.PortChangeStatus == 0) {
return EFI_SUCCESS;
}
USB_DEBUG (("UsbEnumeratePort: port %d state - %x, change - %x\n",
Port, PortState.PortStatus, PortState.PortChangeStatus));
//
// This driver only process two kinds of events now: over current and
// connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.
// ENABLE/RESET is used to reset port. SUSPEND isn't supported.
//
Status = EFI_SUCCESS;
if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {
//
// If overcurrent condition is cleared, enable the port again
//
if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {
HubApi->SetPortFeature (HubIf, Port, USB_HUB_PORT_POWER);
}
} else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {
//
// Device connected or disconnected. Either way, if there is
// already a device present in the bus, need to remove it.
//
Child = UsbFindChild (HubIf, Port);
if (Child != NULL) {
USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port));
UsbRemoveDevice (Child);
}
if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {
//
// Now, new device connected, enumerate and configure the device
//
USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port));
Status = UsbEnumerateNewDev (HubIf, Port);
} else {
USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port));
}
}
HubApi->ClearPortChange (HubIf, Port);
return Status;
}
/**
Enumerate all the changed hub ports
@param Event The event that is triggered
@param Context The context to the event
@return None
**/
VOID
UsbHubEnumeration (
IN EFI_EVENT Event,
IN VOID *Context
)
{
USB_INTERFACE *HubIf;
UINT8 Byte;
UINT8 Bit;
UINT8 Index;
ASSERT (Context);
HubIf = (USB_INTERFACE *) Context;
if (HubIf->ChangeMap == NULL) {
return ;
}
//
// HUB starts its port index with 1.
//
Byte = 0;
Bit = 1;
for (Index = 0; Index < HubIf->NumOfPort; Index++) {
if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {
UsbEnumeratePort (HubIf, Index);
}
USB_NEXT_BIT (Byte, Bit);
}
UsbHubAckHubStatus (HubIf->Device);
gBS->FreePool (HubIf->ChangeMap);
HubIf->ChangeMap = NULL;
return ;
}
/**
Enumerate all the changed hub ports
@param Event The event that is triggered
@param Context The context to the event
@return None
**/
VOID
UsbRootHubEnumeration (
IN EFI_EVENT Event,
IN VOID *Context
)
{
USB_INTERFACE *RootHub;
UINT8 Index;
RootHub = (USB_INTERFACE *) Context;
for (Index = 0; Index < RootHub->NumOfPort; Index++) {
UsbEnumeratePort (RootHub, Index);
}
}

View File

@ -0,0 +1,153 @@
/** @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:
UsbEnumer.h
Abstract:
USB bus enumeration interface
Revision History
**/
#ifndef _USB_ENUMERATION_H_
#define _USB_ENUMERATION_H_
//
// Advance the byte and bit to the next bit, adjust byte accordingly.
//
#define USB_NEXT_BIT(Byte, Bit) \
do { \
(Bit)++; \
if ((Bit) > 7) { \
(Byte)++; \
(Bit) = 0; \
} \
} while (0)
//
// Common interface used by usb bus enumeration process.
// This interface is defined to mask the difference between
// the root hub and normal hub. So, bus enumeration code
// can be shared by both root hub and normal hub
//
typedef
EFI_STATUS
(*USB_HUB_INIT) (
IN USB_INTERFACE *UsbIf
);
//
// Get the port status. This function is required to
// ACK the port change bits although it will return
// the port changes in PortState. Bus enumeration code
// doesn't need to ACK the port change bits.
//
typedef
EFI_STATUS
(*USB_HUB_GET_PORT_STATUS) (
IN USB_INTERFACE *UsbIf,
IN UINT8 Port,
OUT EFI_USB_PORT_STATUS *PortState
);
typedef
VOID
(*USB_HUB_CLEAR_PORT_CHANGE) (
IN USB_INTERFACE *HubIf,
IN UINT8 Port
);
typedef
EFI_STATUS
(*USB_HUB_SET_PORT_FEATURE) (
IN USB_INTERFACE *UsbIf,
IN UINT8 Port,
IN EFI_USB_PORT_FEATURE Feature
);
typedef
EFI_STATUS
(*USB_HUB_CLEAR_PORT_FEATURE) (
IN USB_INTERFACE *UsbIf,
IN UINT8 Port,
IN EFI_USB_PORT_FEATURE Feature
);
typedef
EFI_STATUS
(*USB_HUB_RESET_PORT) (
IN USB_INTERFACE *UsbIf,
IN UINT8 Port
);
typedef
EFI_STATUS
(*USB_HUB_RELEASE) (
IN USB_INTERFACE *UsbIf
);
typedef struct _USB_HUB_API{
USB_HUB_INIT Init;
USB_HUB_GET_PORT_STATUS GetPortStatus;
USB_HUB_CLEAR_PORT_CHANGE ClearPortChange;
USB_HUB_SET_PORT_FEATURE SetPortFeature;
USB_HUB_CLEAR_PORT_FEATURE ClearPortFeature;
USB_HUB_RESET_PORT ResetPort;
USB_HUB_RELEASE Release;
} USB_HUB_API;
USB_ENDPOINT_DESC*
UsbGetEndpointDesc (
IN USB_INTERFACE *UsbIf,
IN UINT8 EpAddr
);
EFI_STATUS
UsbSelectSetting (
IN USB_INTERFACE_DESC *IfDesc,
IN UINT8 Alternate
);
EFI_STATUS
UsbSelectConfig (
IN USB_DEVICE *Device,
IN UINT8 ConfigIndex
);
VOID
UsbRemoveConfig (
IN USB_DEVICE *Device
);
EFI_STATUS
UsbRemoveDevice (
IN USB_DEVICE *Device
);
VOID
UsbHubEnumeration (
IN EFI_EVENT Event,
IN VOID *Context
);
VOID
UsbRootHubEnumeration (
IN EFI_EVENT Event,
IN VOID *Context
);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,140 @@
/** @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:
UsbHub.h
Abstract:
The definition for USB hub
Revision History
**/
#ifndef _USB_HUB_H_
#define _USB_HUB_H_
#define USB_ENDPOINT_ADDR(EpAddr) ((EpAddr) & 0x7F)
#define USB_ENDPOINT_TYPE(Desc) ((Desc)->Attributes & USB_ENDPOINT_TYPE_MASK)
enum {
USB_DESC_TYPE_HUB = 0x29,
//
// Hub class control transfer target
//
USB_HUB_TARGET_HUB = 0,
USB_HUB_TARGET_PORT = 3,
//
// HUB class specific contrl transfer request type
//
USB_HUB_REQ_GET_STATUS = 0,
USB_HUB_REQ_CLEAR_FEATURE = 1,
USB_HUB_REQ_SET_FEATURE = 3,
USB_HUB_REQ_GET_DESC = 6,
USB_HUB_REQ_SET_DESC = 7,
USB_HUB_REQ_CLEAR_TT = 8,
USB_HUB_REQ_RESET_TT = 9,
USB_HUB_REQ_GET_TT_STATE = 10,
USB_HUB_REQ_STOP_TT = 11,
//
// USB hub class feature selector
//
USB_HUB_C_HUB_LOCAL_POWER = 0,
USB_HUB_C_HUB_OVER_CURRENT = 1,
USB_HUB_PORT_CONNECTION = 0,
USB_HUB_PORT_ENABLE = 1,
USB_HUB_PORT_SUSPEND = 2,
USB_HUB_PORT_OVER_CURRENT = 3,
USB_HUB_PORT_RESET = 4,
USB_HUB_PORT_POWER = 8,
USB_HUB_PORT_LOW_SPEED = 9,
USB_HUB_C_PORT_CONNECT = 16,
USB_HUB_C_PORT_ENABLE = 17,
USB_HUB_C_PORT_SUSPEND = 18,
USB_HUB_C_PORT_OVER_CURRENT = 19,
USB_HUB_C_PORT_RESET = 20,
USB_HUB_PORT_TEST = 21,
USB_HUB_PORT_INDICATOR = 22,
//
// USB hub power control method. In gang power control
//
USB_HUB_GANG_POWER_CTRL = 0,
USB_HUB_PORT_POWER_CTRL = 0x01,
//
// USB hub status bits
//
USB_HUB_STAT_LOCAL_POWER = 0x01,
USB_HUB_STAT_OVER_CURRENT = 0x02,
USB_HUB_STAT_C_LOCAL_POWER = 0x01,
USB_HUB_STAT_C_OVER_CURRENT = 0x02,
USB_HUB_CLASS_CODE = 0x09,
USB_HUB_SUBCLASS_CODE = 0x00,
USB_HUB_LOOP = 50,
};
#pragma pack(1)
//
// Hub descriptor, the last two fields are of variable lenght.
//
typedef struct {
UINT8 Length;
UINT8 DescType;
UINT8 NumPorts;
UINT16 HubCharacter;
UINT8 PwrOn2PwrGood;
UINT8 HubContrCurrent;
UINT8 Filler[16];
} EFI_USB_HUB_DESCRIPTOR;
#pragma pack()
typedef struct {
UINT16 ChangedBit;
EFI_USB_PORT_FEATURE Feature;
} USB_CHANGE_FEATURE_MAP;
EFI_STATUS
UsbHubCtrlClearTTBuffer (
IN USB_DEVICE *UsbDev,
IN UINT8 Port,
IN UINT16 DevAddr,
IN UINT16 EpNum,
IN UINT16 EpType
);
BOOLEAN
UsbIsHubInterface (
IN USB_INTERFACE *UsbIf
);
EFI_STATUS
UsbHubAckHubStatus (
IN USB_DEVICE *UsbDev
);
extern USB_HUB_API mUsbHubApi;
extern USB_HUB_API mUsbRootHubApi;
#endif

View File

@ -0,0 +1,769 @@
/** @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:
UsbUtility.c
Abstract:
Wrapper function for usb host controller interface
Revision History
**/
#include "UsbBus.h"
/**
Get the capability of the host controller
@param UsbBus The usb driver
@param MaxSpeed The maximum speed this host controller supports
@param NumOfPort The number of the root hub port
@param Is64BitCapable Whether this controller support 64 bit addressing
@retval EFI_SUCCESS The host controller capability is returned
@retval Others Failed to retrieve the host controller capability.
**/
EFI_STATUS
UsbHcGetCapability (
IN USB_BUS *UsbBus,
OUT UINT8 *MaxSpeed,
OUT UINT8 *NumOfPort,
OUT UINT8 *Is64BitCapable
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->GetCapability (
UsbBus->Usb2Hc,
MaxSpeed,
NumOfPort,
Is64BitCapable
);
} else {
Status = UsbBus->UsbHc->GetRootHubPortNumber (UsbBus->UsbHc, NumOfPort);
*MaxSpeed = EFI_USB_SPEED_FULL;
*Is64BitCapable = (UINT8) FALSE;
}
return Status;
}
/**
Reset the host controller
@param UsbBus The usb bus driver
@param Attributes The reset type, only global reset is used by this driver
@return GC_TODO: add return values
**/
EFI_STATUS
UsbHcReset (
IN USB_BUS *UsbBus,
IN UINT16 Attributes
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->Reset (UsbBus->Usb2Hc, Attributes);
} else {
Status = UsbBus->UsbHc->Reset (UsbBus->UsbHc, Attributes);
}
return Status;
}
/**
Get the current operation state of the host controller
@param UsbBus The USB bus driver
@param State The host controller operation state
@retval EFI_SUCCESS The operation state is returned in State
@retval Others Failed to get the host controller state
**/
EFI_STATUS
UsbHcGetState (
IN USB_BUS *UsbBus,
OUT EFI_USB_HC_STATE *State
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->GetState (UsbBus->Usb2Hc, State);
} else {
Status = UsbBus->UsbHc->GetState (UsbBus->UsbHc, State);
}
return Status;
}
/**
Set the host controller operation state
@param UsbBus The USB bus driver
@param State The state to set
@retval EFI_SUCCESS The host controller is now working at State
@retval Others Failed to set operation state
**/
EFI_STATUS
UsbHcSetState (
IN USB_BUS *UsbBus,
IN EFI_USB_HC_STATE State
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->SetState (UsbBus->Usb2Hc, State);
} else {
Status = UsbBus->UsbHc->SetState (UsbBus->UsbHc, State);
}
return Status;
}
/**
Get the root hub port state
@param UsbBus The USB bus driver
@param PortIndex The index of port
@param PortStatus The variable to save port state
@retval EFI_SUCCESS The root port state is returned in
@retval Others Failed to get the root hub port state
**/
EFI_STATUS
UsbHcGetRootHubPortStatus (
IN USB_BUS *UsbBus,
IN UINT8 PortIndex,
OUT EFI_USB_PORT_STATUS *PortStatus
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->GetRootHubPortStatus (UsbBus->Usb2Hc, PortIndex, PortStatus);
} else {
Status = UsbBus->UsbHc->GetRootHubPortStatus (UsbBus->UsbHc, PortIndex, PortStatus);
}
return Status;
}
/**
Set the root hub port feature
@param UsbBus The USB bus driver
@param PortIndex The port index
@param Feature The port feature to set
@retval EFI_SUCCESS The port feature is set
@retval Others Failed to set port feature
**/
EFI_STATUS
UsbHcSetRootHubPortFeature (
IN USB_BUS *UsbBus,
IN UINT8 PortIndex,
IN EFI_USB_PORT_FEATURE Feature
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->SetRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
} else {
Status = UsbBus->UsbHc->SetRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
}
return Status;
}
/**
Clear the root hub port feature
@param UsbBus The USB bus driver
@param PortIndex The port index
@param Feature The port feature to clear
@retval EFI_SUCCESS The port feature is clear
@retval Others Failed to clear port feature
**/
EFI_STATUS
UsbHcClearRootHubPortFeature (
IN USB_BUS *UsbBus,
IN UINT8 PortIndex,
IN EFI_USB_PORT_FEATURE Feature
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->ClearRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);
} else {
Status = UsbBus->UsbHc->ClearRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);
}
return Status;
}
/**
Execute a control transfer to the device
@param UsbBus The USB bus driver
@param DevAddr The device address
@param DevSpeed The device speed
@param MaxPacket Maximum packet size of endpoint 0
@param Request The control transfer request
@param Direction The direction of data stage
@param Data The buffer holding data
@param DataLength The length of the data
@param TimeOut Timeout (in ms) to wait until timeout
@param Translator The transaction translator for low/full speed device
@param UsbResult The result of transfer
@retval EFI_SUCCESS The control transfer finished without error
@retval Others The control transfer failed, reason returned in UsbReslt
**/
EFI_STATUS
UsbHcControlTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN EFI_USB_DEVICE_REQUEST *Request,
IN EFI_USB_DATA_DIRECTION Direction,
IN OUT VOID *Data,
IN OUT UINTN *DataLength,
IN UINTN TimeOut,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
)
{
EFI_STATUS Status;
BOOLEAN IsSlowDevice;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->ControlTransfer (
UsbBus->Usb2Hc,
DevAddr,
DevSpeed,
MaxPacket,
Request,
Direction,
Data,
DataLength,
TimeOut,
Translator,
UsbResult
);
} else {
IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
Status = UsbBus->UsbHc->ControlTransfer (
UsbBus->UsbHc,
DevAddr,
IsSlowDevice,
(UINT8) MaxPacket,
Request,
Direction,
Data,
DataLength,
TimeOut,
UsbResult
);
}
return Status;
}
/**
Execute a bulk transfer to the device's endpoint
@param UsbBus The USB bus driver
@param DevAddr The target device address
@param EpAddr The target endpoint address, with direction encoded in
bit 7
@param DevSpeed The device's speed
@param MaxPacket The endpoint's max packet size
@param BufferNum The number of data buffer
@param Data Array of pointers to data buffer
@param DataLength The length of data buffer
@param DataToggle On input, the initial data toggle to use, also return
the next toggle on output.
@param TimeOut The time to wait until timeout
@param Translator The transaction translator for low/full speed device
@param UsbResult The result of USB execution
@retval EFI_SUCCESS The bulk transfer is finished without error
@retval Others Failed to execute bulk transfer, result in UsbResult
**/
EFI_STATUS
UsbHcBulkTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN UINT8 BufferNum,
IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
IN OUT UINTN *DataLength,
IN OUT UINT8 *DataToggle,
IN UINTN TimeOut,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
)
{
EFI_STATUS Status;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->BulkTransfer (
UsbBus->Usb2Hc,
DevAddr,
EpAddr,
DevSpeed,
MaxPacket,
BufferNum,
Data,
DataLength,
DataToggle,
TimeOut,
Translator,
UsbResult
);
} else {
Status = UsbBus->UsbHc->BulkTransfer (
UsbBus->UsbHc,
DevAddr,
EpAddr,
(UINT8) MaxPacket,
*Data,
DataLength,
DataToggle,
TimeOut,
UsbResult
);
}
return Status;
}
/**
Queue or cancel an asynchronous interrupt transfer
@param UsbBus The USB bus driver
@param DevAddr The target device address
@param EpAddr The target endpoint address, with direction encoded in
bit 7
@param DevSpeed The device's speed
@param MaxPacket The endpoint's max packet size
@param IsNewTransfer Whether this is a new request. If not, cancel the old
request
@param DataToggle Data toggle to use on input, next toggle on output
@param PollingInterval The interval to poll the interrupt transfer (in ms)
@param DataLength The length of periodical data receive
@param Translator The transaction translator for low/full speed device
@param Callback Function to call when data is received
@param Context The context to the callback
@retval EFI_SUCCESS The asynchronous transfer is queued
@retval Others Failed to queue the transfer
**/
EFI_STATUS
UsbHcAsyncInterruptTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN BOOLEAN IsNewTransfer,
IN OUT UINT8 *DataToggle,
IN UINTN PollingInterval,
IN UINTN DataLength,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
IN VOID *Context OPTIONAL
)
{
EFI_STATUS Status;
BOOLEAN IsSlowDevice;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->AsyncInterruptTransfer (
UsbBus->Usb2Hc,
DevAddr,
EpAddr,
DevSpeed,
MaxPacket,
IsNewTransfer,
DataToggle,
PollingInterval,
DataLength,
Translator,
Callback,
Context
);
} else {
IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);
Status = UsbBus->UsbHc->AsyncInterruptTransfer (
UsbBus->UsbHc,
DevAddr,
EpAddr,
IsSlowDevice,
(UINT8) MaxPacket,
IsNewTransfer,
DataToggle,
PollingInterval,
DataLength,
Callback,
Context
);
}
return Status;
}
/**
Execute a synchronous interrupt transfer to the target endpoint
@param UsbBus The USB bus driver
@param DevAddr The target device address
@param EpAddr The target endpoint address, with direction encoded in
bit 7
@param DevSpeed The device's speed
@param MaxPacket The endpoint's max packet size
@param Data Pointer to data buffer
@param DataLength The length of data buffer
@param DataToggle On input, the initial data toggle to use, also return
the next toggle on output.
@param TimeOut The time to wait until timeout
@param Translator The transaction translator for low/full speed device
@param UsbResult The result of USB execution
@retval EFI_SUCCESS The synchronous interrupt transfer is OK
@retval Others Failed to execute the synchronous interrupt transfer
**/
EFI_STATUS
UsbHcSyncInterruptTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN OUT VOID *Data,
IN OUT UINTN *DataLength,
IN OUT UINT8 *DataToggle,
IN UINTN TimeOut,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
)
{
EFI_STATUS Status;
BOOLEAN IsSlowDevice;
if (UsbBus->Usb2Hc != NULL) {
Status = UsbBus->Usb2Hc->SyncInterruptTransfer (
UsbBus->Usb2Hc,
DevAddr,
EpAddr,
DevSpeed,
MaxPacket,
Data,
DataLength,
DataToggle,
TimeOut,
Translator,
UsbResult
);
} else {
IsSlowDevice = (EFI_USB_SPEED_LOW == DevSpeed) ? TRUE : FALSE;
Status = UsbBus->UsbHc->SyncInterruptTransfer (
UsbBus->UsbHc,
DevAddr,
EpAddr,
IsSlowDevice,
(UINT8) MaxPacket,
Data,
DataLength,
DataToggle,
TimeOut,
UsbResult
);
}
return Status;
}
/**
Execute a synchronous Isochronous USB transfer
@param UsbBus The USB bus driver
@param DevAddr The target device address
@param EpAddr The target endpoint address, with direction encoded in
bit 7
@param DevSpeed The device's speed
@param MaxPacket The endpoint's max packet size
@param BufferNum The number of data buffer
@param Data Array of pointers to data buffer
@param DataLength The length of data buffer
@param Translator The transaction translator for low/full speed device
@param UsbResult The result of USB execution
@retval EFI_UNSUPPORTED The isochronous transfer isn't supported now
**/
EFI_STATUS
UsbHcIsochronousTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN UINT8 BufferNum,
IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
IN UINTN DataLength,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
)
{
return EFI_UNSUPPORTED;
}
/**
Queue an asynchronous isochronous transfer
@param UsbBus The USB bus driver
@param DevAddr The target device address
@param EpAddr The target endpoint address, with direction encoded in
bit 7
@param DevSpeed The device's speed
@param MaxPacket The endpoint's max packet size
@param BufferNum The number of data buffer
@param Data Array of pointers to data buffer
@param DataLength The length of data buffer
@param Translator The transaction translator for low/full speed device
@param Callback The function to call when data is transferred
@param Context The context to the callback function
@retval EFI_UNSUPPORTED The asynchronous isochronous transfer isn't supported
**/
EFI_STATUS
UsbHcAsyncIsochronousTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN UINT8 BufferNum,
IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
IN UINTN DataLength,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
IN VOID *Context
)
{
return EFI_UNSUPPORTED;
}
/**
Open the USB host controller protocol BY_CHILD
@param Bus The USB bus driver
@param Child The child handle
@return The open protocol return
**/
EFI_STATUS
UsbOpenHostProtoByChild (
IN USB_BUS *Bus,
IN EFI_HANDLE Child
)
{
EFI_USB_HC_PROTOCOL *UsbHc;
EFI_USB2_HC_PROTOCOL *Usb2Hc;
EFI_STATUS Status;
if (Bus->Usb2Hc != NULL) {
Status = gBS->OpenProtocol (
Bus->HostHandle,
&gEfiUsb2HcProtocolGuid,
&Usb2Hc,
mUsbBusDriverBinding.DriverBindingHandle,
Child,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
} else {
Status = gBS->OpenProtocol (
Bus->HostHandle,
&gEfiUsbHcProtocolGuid,
&UsbHc,
mUsbBusDriverBinding.DriverBindingHandle,
Child,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
}
return Status;
}
/**
Close the USB host controller protocol BY_CHILD
@param Bus The USB bus driver
@param Child The child handle
@return None
**/
VOID
UsbCloseHostProtoByChild (
IN USB_BUS *Bus,
IN EFI_HANDLE Child
)
{
if (Bus->Usb2Hc != NULL) {
gBS->CloseProtocol (
Bus->HostHandle,
&gEfiUsb2HcProtocolGuid,
mUsbBusDriverBinding.DriverBindingHandle,
Child
);
} else {
gBS->CloseProtocol (
Bus->HostHandle,
&gEfiUsbHcProtocolGuid,
mUsbBusDriverBinding.DriverBindingHandle,
Child
);
}
}
/**
return the current TPL, copied from the EDKII glue lib.
VOID
@return Current TPL
**/
EFI_TPL
UsbGetCurrentTpl (
VOID
)
{
EFI_TPL Tpl;
Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
gBS->RestoreTPL (Tpl);
return Tpl;
}
#ifdef EFI_DEBUG
VOID
UsbDebug (
IN CHAR8 *Format,
...
)
/*++
Routine Description:
USB's debug output function.
Arguments:
Format - The format parameters to the print
... - The variable length parameters after format
Returns:
None
--*/
{
VA_LIST Marker;
VA_START (Marker, Format);
DebugVPrint (DEBUG_INFO, Format, Marker);
VA_END (Marker);
}
/**
USB's error output function.
@param Format The format parameters to the print
@param ... The variable length parameters after format
@return None
**/
VOID
UsbError (
IN CHAR8 *Format,
...
)
{
VA_LIST Marker;
VA_START (Marker, Format);
DebugVPrint (DEBUG_ERROR, Format, Marker);
VA_END (Marker);
}
#endif

View File

@ -0,0 +1,220 @@
/** @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:
UsbUtility.h
Abstract:
Manage Usb Port/Hc/Etc
Revision History
**/
#ifndef _USB_UTILITY_H
#define _USB_UTILITY_H
EFI_STATUS
UsbHcGetCapability (
IN USB_BUS *UsbBus,
OUT UINT8 *MaxSpeed,
OUT UINT8 *NumOfPort,
OUT UINT8 *Is64BitCapable
);
EFI_STATUS
UsbHcReset (
IN USB_BUS *UsbBus,
IN UINT16 Attributes
);
EFI_STATUS
UsbHcGetState (
IN USB_BUS *UsbBus,
OUT EFI_USB_HC_STATE *State
);
EFI_STATUS
UsbHcSetState (
IN USB_BUS *UsbBus,
IN EFI_USB_HC_STATE State
);
EFI_STATUS
UsbHcGetRootHubPortStatus (
IN USB_BUS *UsbBus,
IN UINT8 PortIndex,
OUT EFI_USB_PORT_STATUS *PortStatus
);
EFI_STATUS
UsbHcSetRootHubPortFeature (
IN USB_BUS *UsbBus,
IN UINT8 PortIndex,
IN EFI_USB_PORT_FEATURE Feature
);
EFI_STATUS
UsbHcClearRootHubPortFeature (
IN USB_BUS *UsbBus,
IN UINT8 PortIndex,
IN EFI_USB_PORT_FEATURE Feature
);
EFI_STATUS
UsbHcControlTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN EFI_USB_DEVICE_REQUEST *Request,
IN EFI_USB_DATA_DIRECTION Direction,
IN OUT VOID *Data,
IN OUT UINTN *DataLength,
IN UINTN TimeOut,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
);
EFI_STATUS
UsbHcBulkTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN UINT8 BufferNum,
IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
IN OUT UINTN *DataLength,
IN OUT UINT8 *DataToggle,
IN UINTN TimeOut,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
);
EFI_STATUS
UsbHcAsyncInterruptTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN BOOLEAN IsNewTransfer,
IN OUT UINT8 *DataToggle,
IN UINTN PollingInterval,
IN UINTN DataLength,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
IN VOID *Context OPTIONAL
);
EFI_STATUS
UsbHcSyncInterruptTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN OUT VOID *Data,
IN OUT UINTN *DataLength,
IN OUT UINT8 *DataToggle,
IN UINTN TimeOut,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
);
EFI_STATUS
UsbHcIsochronousTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN UINT8 BufferNum,
IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
IN UINTN DataLength,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT UINT32 *UsbResult
);
EFI_STATUS
UsbHcAsyncIsochronousTransfer (
IN USB_BUS *UsbBus,
IN UINT8 DevAddr,
IN UINT8 EpAddr,
IN UINT8 DevSpeed,
IN UINTN MaxPacket,
IN UINT8 BufferNum,
IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
IN UINTN DataLength,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,
IN VOID *Context
);
EFI_STATUS
UsbOpenHostProtoByChild (
IN USB_BUS *Bus,
IN EFI_HANDLE Child
);
VOID
UsbCloseHostProtoByChild (
IN USB_BUS *Bus,
IN EFI_HANDLE Child
);
EFI_TPL
UsbGetCurrentTpl (
VOID
);
//
// USB debug support routines
//
#ifdef EFI_DEBUG
#define USB_DEBUG(arg) UsbDebug arg
#define USB_ERROR(arg) UsbError arg
#else
#define USB_DEBUG(arg)
#define USB_ERROR(arg)
#endif
VOID
UsbDebug (
IN CHAR8 *Format,
...
);
VOID
UsbError (
IN CHAR8 *Format,
...
);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,210 @@
/** @file
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:
UsbBus.h
Abstract:
Usb Bus Driver Binding and Bus IO Protocol
Revision History
**/
#ifndef _EFI_USB_BUS_H_
#define _EFI_USB_BUS_H_
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Protocol/Usb2HostController.h>
#include <Protocol/UsbHostController.h>
#include <Protocol/UsbIo.h>
#include <Protocol/DevicePath.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/DevicePathLib.h>
#include <Library/MemoryAllocationLib.h>
#include <IndustryStandard/Usb.h>
typedef struct _USB_DEVICE USB_DEVICE;
typedef struct _USB_INTERFACE USB_INTERFACE;
typedef struct _USB_BUS USB_BUS;
typedef struct _USB_HUB_API USB_HUB_API;
#include "UsbUtility.h"
#include "UsbDesc.h"
#include "UsbHub.h"
#include "UsbEnumer.h"
enum {
//
// Time definition
//
USB_STALL_1_MS = 1000,
TICKS_PER_MS = 10000U,
USB_ROOTHUB_POLL_INTERVAL = 1000 * TICKS_PER_MS,
USB_HUB_POLL_INTERVAL = 64,
//
// Maximum definition
//
USB_MAX_LANG_ID = 16,
USB_MAX_INTERFACE = 16,
USB_MAX_DEVICES = 128,
//
// Bus raises TPL to TPL_NOTIFY to serialize all its operations
// to protect shared data structures.
//
USB_BUS_TPL = TPL_NOTIFY,
USB_INTERFACE_SIGNATURE = EFI_SIGNATURE_32 ('U', 'S', 'B', 'I'),
USB_BUS_SIGNATURE = EFI_SIGNATURE_32 ('U', 'S', 'B', 'B'),
};
#define USB_BIT(a) ((UINTN)(1 << (a)))
#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
#define EFI_USB_BUS_PROTOCOL_GUID \
{0x2B2F68CC, 0x0CD2, 0x44cf, 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75}
#define USB_INTERFACE_FROM_USBIO(a) \
CR(a, USB_INTERFACE, UsbIo, USB_INTERFACE_SIGNATURE)
#define USB_BUS_FROM_THIS(a) \
CR(a, USB_BUS, BusId, USB_BUS_SIGNATURE)
//
// Used to locate USB_BUS
//
typedef struct _EFI_USB_BUS_PROTOCOL {
UINT64 Reserved;
} EFI_USB_BUS_PROTOCOL;
//
// Stands for the real USB device. Each device may
// has several seperately working interfaces.
//
typedef struct _USB_DEVICE {
USB_BUS *Bus;
//
// Configuration information
//
UINT8 Speed;
UINT8 Address;
UINT8 MaxPacket0;
//
// The device's descriptors and its configuration
//
USB_DEVICE_DESC *DevDesc;
USB_CONFIG_DESC *ActiveConfig;
UINT16 LangId [USB_MAX_LANG_ID];
UINT16 TotalLangId;
UINT8 NumOfInterface;
USB_INTERFACE *Interfaces [USB_MAX_INTERFACE];
//
// Parent child relationship
//
EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;
UINT8 ParentAddr;
USB_INTERFACE *ParentIf;
UINT8 ParentPort; // Start at 0
} USB_DEVICE;
//
// Stands for different functions of USB device
//
typedef struct _USB_INTERFACE {
UINTN Signature;
USB_DEVICE *Device;
USB_INTERFACE_DESC *IfDesc;
USB_INTERFACE_SETTING *IfSetting;
//
// Handles and protocols
//
EFI_HANDLE Handle;
EFI_USB_IO_PROTOCOL UsbIo;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
BOOLEAN IsManaged;
//
// Hub device special data
//
BOOLEAN IsHub;
USB_HUB_API *HubApi;
UINT8 NumOfPort;
EFI_EVENT HubNotify;
//
// Data used only by normal hub devices
//
USB_ENDPOINT_DESC *HubEp;
UINT8 *ChangeMap;
//
// Data used only by root hub to hand over device to
// companion UHCI driver if low/full speed devices are
// connected to EHCI.
//
UINT8 MaxSpeed;
} USB_INTERFACE;
//
// Stands for the current USB Bus
//
typedef struct _USB_BUS {
UINTN Signature;
EFI_USB_BUS_PROTOCOL BusId;
//
// Managed USB host controller
//
EFI_HANDLE HostHandle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_USB2_HC_PROTOCOL *Usb2Hc;
EFI_USB_HC_PROTOCOL *UsbHc;
//
// An array of device that is on the bus. Devices[0] is
// for root hub. Device with address i is at Devices[i].
//
USB_DEVICE *Devices[USB_MAX_DEVICES];
} USB_BUS;
extern EFI_USB_IO_PROTOCOL mUsbIoProtocol;
extern EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL mUsbBusComponentName;
#endif

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>