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