diff options
author | vanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524> | 2007-07-11 08:47:37 +0000 |
---|---|---|
committer | vanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524> | 2007-07-11 08:47:37 +0000 |
commit | e237e7ae9fc23f32a25040d49cc9a16f2a7f3b4c (patch) | |
tree | f7c7ea55cac3b9816f5f6f2a39fbc09406e7a134 /MdeModulePkg/Bus/Usb/UsbBusDxe | |
parent | f183b4f349e207768bfbf3287b9d37ac7b16d101 (diff) | |
download | edk2-e237e7ae9fc23f32a25040d49cc9a16f2a7f3b4c.zip edk2-e237e7ae9fc23f32a25040d49cc9a16f2a7f3b4c.tar.gz edk2-e237e7ae9fc23f32a25040d49cc9a16f2a7f3b4c.tar.bz2 |
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
Diffstat (limited to 'MdeModulePkg/Bus/Usb/UsbBusDxe')
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c | 164 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf | 99 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.msa | 85 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c | 991 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h | 146 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c | 991 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h | 153 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c | 1334 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h | 140 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c | 769 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h | 220 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c | 1384 | ||||
-rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h | 210 |
13 files changed, 6686 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c new file mode 100644 index 0000000..da97372 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c @@ -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;
+}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf new file mode 100644 index 0000000..423d9fb --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf @@ -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
+
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.msa b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.msa new file mode 100644 index 0000000..deaecc6 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.msa @@ -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>
\ No newline at end of file diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c new file mode 100644 index 0000000..ffed149 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c @@ -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;
+}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h new file mode 100644 index 0000000..bdecfcf --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h @@ -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
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c new file mode 100644 index 0000000..fc0007d --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c @@ -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);
+ }
+}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h new file mode 100644 index 0000000..e14b2d7 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h @@ -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
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c new file mode 100644 index 0000000..25332f4 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c @@ -0,0 +1,1334 @@ +/** @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.c
+
+ Abstract:
+
+ Unified interface for RootHub and Hub
+
+ Revision History
+
+
+**/
+
+#include "UsbBus.h"
+
+//
+// USB hub class specific requests. Although USB hub
+// is related to an interface, these requests are sent
+// to the control endpoint of the device.
+//
+
+
+/**
+ USB hub control transfer to clear the hub feature
+
+ @param HubDev The device of the hub
+ @param Feature The feature to clear
+
+ @retval EFI_SUCCESS Feature of the hub is cleared
+ @retval Others Failed to clear the feature
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlClearHubFeature (
+ IN USB_DEVICE *HubDev,
+ IN UINT16 Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_CLEAR_FEATURE,
+ Feature,
+ 0,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Clear the feature of the device's port
+
+ @param HubDev The hub device
+ @param Port The port to clear feature
+ @param Feature The feature to clear
+
+ @retval EFI_SUCCESS The feature of the port is cleared.
+ @retval Others Failed to clear the feature.
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlClearPortFeature (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ IN UINT16 Feature
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // In USB bus, all the port index starts from 0. But HUB
+ // indexes its port from 1. So, port number is added one.
+ //
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_CLEAR_FEATURE,
+ Feature,
+ Port + 1,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+
+/**
+ Clear the transaction translate buffer if full/low
+ speed control/bulk transfer failed and the transfer
+ uses this hub as translator.Remember to clear the TT
+ buffer of transaction translator, not that of the
+ parent.
+
+ @param HubDev The hub device
+ @param Port The port of the hub
+ @param DevAddr Address of the failed transaction
+ @param EpNum The endpoint number of the failed transaction
+ @param EpType The type of failed transaction
+
+ @retval EFI_SUCCESS The TT buffer is cleared
+ @retval Others Failed to clear the TT buffer
+
+**/
+EFI_STATUS
+UsbHubCtrlClearTTBuffer (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ IN UINT16 DevAddr,
+ IN UINT16 EpNum,
+ IN UINT16 EpType
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Value;
+
+ //
+ // Check USB2.0 spec page 424 for wValue's encoding
+ //
+ Value = (EpNum & 0x0F) | (DevAddr << 4) |
+ ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15);
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_CLEAR_TT,
+ Value,
+ Port + 1,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to get the hub descriptor
+
+ @param HubDev The hub device
+ @param Buf The buffer to hold the descriptor
+ @param Len The length to retrieve
+
+ @retval EFI_SUCCESS The hub descriptor is retrieved
+ @retval Others Failed to retrieve the hub descriptor
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlGetHubDesc (
+ IN USB_DEVICE *HubDev,
+ OUT VOID *Buf,
+ IN UINTN Len
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbDataIn,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_GET_DESC,
+ (UINT16) (USB_DESC_TYPE_HUB << 8),
+ 0,
+ Buf,
+ Len
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to get the hub status
+
+ @param HubDev The hub device
+ @param State The variable to return the status
+
+ @retval EFI_SUCCESS The hub status is returned in State
+ @retval Others Failed to get the hub status
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlGetHubStatus (
+ IN USB_DEVICE *HubDev,
+ OUT UINT32 *State
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbDataIn,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_GET_STATUS,
+ 0,
+ 0,
+ State,
+ 4
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to get the port status
+
+ @param HubDev The hub device
+ @param Port The port of the hub
+ @param State Variable to return the hub port state
+
+ @retval EFI_SUCCESS The port state is returned in State
+ @retval Others Failed to retrive the port state
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlGetPortStatus (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ OUT VOID *State
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // In USB bus, all the port index starts from 0. But HUB
+ // indexes its port from 1. So, port number is added one.
+ // No need to convert the hub bit to UEFI definition, they
+ // are the same
+ //
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbDataIn,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_GET_STATUS,
+ 0,
+ Port + 1,
+ State,
+ 4
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to reset the TT (Transaction Transaltor)
+
+ @param HubDev The hub device
+ @param Port The port of the hub
+
+ @retval EFI_SUCCESS The TT of the hub is reset
+ @retval Others Failed to reset the port
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlResetTT (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_RESET_TT,
+ 0,
+ Port + 1,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to set the hub feature
+
+ @param HubDev The hub device
+ @param Feature The feature to set
+
+ @retval EFI_SUCESS The feature is set for the hub
+ @retval Others Failed to set the feature
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlSetHubFeature (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_HUB,
+ USB_HUB_REQ_SET_FEATURE,
+ Feature,
+ 0,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Usb hub control transfer to set the port feature
+
+ @param HubDev The Usb hub device
+ @param Port The Usb port to set feature for
+ @param Feature The feature to set
+
+ @retval EFI_SUCCESS The feature is set for the port
+ @retval Others Failed to set the feature
+
+**/
+STATIC
+EFI_STATUS
+UsbHubCtrlSetPortFeature (
+ IN USB_DEVICE *HubDev,
+ IN UINT8 Port,
+ IN UINT8 Feature
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // In USB bus, all the port index starts from 0. But HUB
+ // indexes its port from 1. So, port number is added one.
+ //
+ Status = UsbCtrlRequest (
+ HubDev,
+ EfiUsbNoData,
+ USB_REQ_TYPE_CLASS,
+ USB_HUB_TARGET_PORT,
+ USB_HUB_REQ_SET_FEATURE,
+ Feature,
+ Port + 1,
+ NULL,
+ 0
+ );
+
+ return Status;
+}
+
+
+/**
+ Read the whole usb hub descriptor. It is necessary
+ to do it in two steps because hub descriptor is of
+ variable length
+
+ @param HubDev The hub device
+ @param HubDesc The variable to return the descriptor
+
+ @retval EFI_SUCCESS The hub descriptor is read
+ @retval Others Failed to read the hub descriptor
+
+**/
+STATIC
+EFI_STATUS
+UsbHubReadDesc (
+ IN USB_DEVICE *HubDev,
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDesc
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // First get the hub descriptor length
+ //
+ Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the whole hub descriptor
+ //
+ Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
+
+ return Status;
+}
+
+
+
+/**
+ Ack the hub change bits. If these bits are not ACKed, Hub will
+ always return changed bit map from its interrupt endpoint.
+
+ @param HubDev The hub device
+
+ @retval EFI_SUCCESS The hub change status is ACKed
+ @retval Others Failed to ACK the hub status
+
+**/
+EFI_STATUS
+UsbHubAckHubStatus (
+ IN USB_DEVICE *HubDev
+ )
+{
+ EFI_USB_PORT_STATUS HubState;
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
+ UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
+ }
+
+ if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
+ UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test whether the interface is a hub interface.
+
+ @param UsbIf The interface to test
+
+ @retval TRUE The interface is a hub interface
+ @retval FALSE The interface isn't a hub interface
+
+**/
+BOOLEAN
+UsbIsHubInterface (
+ IN USB_INTERFACE *UsbIf
+ )
+{
+ EFI_USB_INTERFACE_DESCRIPTOR *Setting;
+
+ //
+ // If the hub is a high-speed hub with multiple TT,
+ // the hub will has a default setting of single TT.
+ //
+ Setting = &UsbIf->IfSetting->Desc;
+
+ if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
+ (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ The callback function to the USB hub status change
+ interrupt endpoint. It is called periodically by
+ the underlying host controller.
+
+ @param Data The data read
+ @param DataLength The length of the data read
+ @param Context The context
+ @param Result The result of the last interrupt transfer
+
+ @retval EFI_SUCCESS The process is OK
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource
+
+**/
+STATIC
+EFI_STATUS
+UsbOnHubInterrupt (
+ IN VOID *Data,
+ IN UINTN DataLength,
+ IN VOID *Context,
+ IN UINT32 Result
+ )
+{
+ USB_INTERFACE *HubIf;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
+ EFI_STATUS Status;
+
+ HubIf = (USB_INTERFACE *) Context;
+ UsbIo = &(HubIf->UsbIo);
+ EpDesc = &(HubIf->HubEp->Desc);
+
+ if (Result != EFI_USB_NOERROR) {
+ //
+ // If endpoint is stalled, clear the stall. Use UsbIo to access
+ // the control transfer so internal status are maintained.
+ //
+ if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
+ UsbIoClearFeature (
+ UsbIo,
+ USB_TARGET_ENDPOINT,
+ USB_FEATURE_ENDPOINT_HALT,
+ EpDesc->EndpointAddress
+ );
+ }
+
+ //
+ // Delete and submit a new async interrupt
+ //
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EpDesc->EndpointAddress,
+ FALSE,
+ 0,
+ 0,
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
+ return Status;
+ }
+
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EpDesc->EndpointAddress,
+ TRUE,
+ USB_HUB_POLL_INTERVAL,
+ HubIf->NumOfPort / 8 + 1,
+ UsbOnHubInterrupt,
+ HubIf
+ );
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
+ }
+
+ return Status;
+ }
+
+ if ((DataLength == 0) || (Data == NULL)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // OK, actually something is changed, save the change map
+ // then signal the HUB to do enumeration. This is a good
+ // practise since UsbOnHubInterrupt is called in the context
+ // of host contrller's AsyncInterrupt monitor.
+ //
+ HubIf->ChangeMap = AllocateZeroPool (DataLength);
+
+ if (HubIf->ChangeMap == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (HubIf->ChangeMap, Data, DataLength);
+ gBS->SignalEvent (HubIf->HubNotify);
+
+ return EFI_SUCCESS;
+}
+
+//
+// Array that maps the change bit to feature value which is
+// used to clear these change bit. USB HUB API will clear
+// these change bit automatically. For non-root hub, these
+// bits determine whether hub will report the port in changed
+// bit maps.
+//
+#define USB_HUB_MAP_SIZE 5
+
+USB_CHANGE_FEATURE_MAP mHubFeatureMap[USB_HUB_MAP_SIZE] = {
+ {USB_PORT_STAT_C_CONNECTION, USB_HUB_C_PORT_CONNECT},
+ {USB_PORT_STAT_C_ENABLE, USB_HUB_C_PORT_ENABLE},
+ {USB_PORT_STAT_C_SUSPEND, USB_HUB_C_PORT_SUSPEND},
+ {USB_PORT_STAT_C_OVERCURRENT, USB_HUB_C_PORT_OVER_CURRENT},
+ {USB_PORT_STAT_C_RESET, USB_HUB_C_PORT_RESET},
+};
+
+#define USB_ROOT_HUB_MAP_SIZE 5
+
+USB_CHANGE_FEATURE_MAP mRootHubFeatureMap[USB_ROOT_HUB_MAP_SIZE] = {
+ {USB_PORT_STAT_C_CONNECTION, EfiUsbPortConnectChange},
+ {USB_PORT_STAT_C_ENABLE, EfiUsbPortEnableChange},
+ {USB_PORT_STAT_C_SUSPEND, EfiUsbPortSuspendChange},
+ {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
+ {USB_PORT_STAT_C_RESET, EfiUsbPortResetChange},
+};
+
+
+
+/**
+ Initialize the device for a non-root hub
+
+ @param HubIf The USB hub interface
+
+ @retval EFI_SUCCESS The hub is initialized
+ @retval EFI_DEVICE_ERROR Failed to initialize the hub
+
+**/
+STATIC
+EFI_STATUS
+UsbHubInit (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ EFI_USB_HUB_DESCRIPTOR HubDesc;
+ USB_ENDPOINT_DESC *EpDesc;
+ USB_INTERFACE_SETTING *Setting;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ USB_DEVICE *HubDev;
+ EFI_STATUS Status;
+ UINT8 Index;
+
+ //
+ // Locate the interrupt endpoint for port change map
+ //
+ HubIf->IsHub = FALSE;
+ Setting = HubIf->IfSetting;
+ HubDev = HubIf->Device;
+ EpDesc = NULL;
+
+ for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {
+ ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
+
+ EpDesc = Setting->Endpoints[Index];
+
+ if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
+ (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {
+ break;
+ }
+ }
+
+ if (Index == Setting->Desc.NumEndpoints) {
+ USB_ERROR (("UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = UsbHubReadDesc (HubDev, &HubDesc);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbHubInit: failed to read HUB descriptor %r\n", Status));
+ return Status;
+ }
+
+ HubIf->NumOfPort = HubDesc.NumPorts;
+
+ USB_DEBUG (("UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));
+
+ //
+ // Create an event to enumerate the hub's port. On
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ UsbHubEnumeration,
+ HubIf,
+ &HubIf->HubNotify
+ );
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbHubInit: failed to create signal for hub %d - %r\n",
+ HubDev->Address, Status));
+
+ return Status;
+ }
+
+ //
+ // Create AsyncInterrupt to query hub port change endpoint
+ // periodically. If the hub ports are changed, hub will return
+ // changed port map from the interrupt endpoint. The port map
+ // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
+ // host change status).
+ //
+ UsbIo = &HubIf->UsbIo;
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ EpDesc->Desc.EndpointAddress,
+ TRUE,
+ USB_HUB_POLL_INTERVAL,
+ HubIf->NumOfPort / 8 + 1,
+ UsbOnHubInterrupt,
+ HubIf
+ );
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
+ HubDev->Address, Status));
+
+ gBS->CloseEvent (HubIf->HubNotify);
+ HubIf->HubNotify = NULL;
+
+ return Status;
+ }
+
+ //
+ // OK, set IsHub to TRUE. Now usb bus can handle this device
+ // as a working HUB. If failed eariler, bus driver will not
+ // recognize it as a hub. Other parts of the bus should be able
+ // to work.
+ //
+ HubIf->IsHub = TRUE;
+ HubIf->HubApi = &mUsbHubApi;
+ HubIf->HubEp = EpDesc;
+
+ //
+ // Feed power to all the hub ports. It should be ok
+ // for both gang/individual powered hubs.
+ //
+ for (Index = 0; Index < HubDesc.NumPorts; Index++) {
+ UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_POWER);
+ }
+
+ gBS->Stall (HubDesc.PwrOn2PwrGood * 2 * USB_STALL_1_MS);
+ UsbHubAckHubStatus (HubIf->Device);
+
+ USB_DEBUG (("UsbHubInit: hub %d initialized\n", HubDev->Address));
+ return Status;
+}
+
+
+
+/**
+ 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.
+
+ @param HubIf The hub interface
+ @param Port The port of the hub to get state
+ @param PortState Variable to return the port state
+
+ @retval EFI_SUCCESS The port status is successfully returned
+ @retval Others Failed to return the status
+
+**/
+STATIC
+EFI_STATUS
+UsbHubGetPortStatus (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ OUT EFI_USB_PORT_STATUS *PortState
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
+
+ return Status;
+}
+
+
+
+/**
+ Clear the port change status.
+
+ @param HubIf The hub interface
+ @param Port The hub port
+
+ @return None
+
+**/
+STATIC
+VOID
+UsbHubClearPortChange (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ EFI_USB_PORT_STATUS PortState;
+ USB_CHANGE_FEATURE_MAP *Map;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // OK, get the usb port status, now ACK the change bits.
+ // Don't return error when failed to clear the change bits.
+ // It may lead to extra port state report. USB bus should
+ // be able to handle this.
+ //
+ for (Index = 0; Index < USB_HUB_MAP_SIZE; Index++) {
+ Map = &mHubFeatureMap[Index];
+
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
+ UsbHubCtrlClearPortFeature (HubIf->Device, Port, Map->Feature);
+ }
+ }
+}
+
+
+
+/**
+ Function to set the port feature for non-root hub
+
+ @param HubIf The hub interface
+ @param Port The port of the hub
+ @param Feature The feature of the port to set
+
+ @retval EFI_SUCCESS The hub port feature is set
+ @retval Others Failed to set the port feature
+
+**/
+STATIC
+EFI_STATUS
+UsbHubSetPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, Feature);
+
+ return Status;
+}
+
+
+/**
+ Interface function to clear the port feature for non-root hub
+
+ @param HubIf The hub interface
+ @param Port The port of the hub to clear feature for
+ @param Feature The feature to clear
+
+ @retval EFI_SUCCESS The port feature is cleared
+ @retval Others Failed to clear the port feature
+
+**/
+STATIC
+EFI_STATUS
+UsbHubClearPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, Feature);
+
+ return Status;
+}
+
+
+/**
+ Interface funtion to reset the port
+
+ @param HubIf The hub interface
+ @param Port The port to reset
+
+ @retval EFI_SUCCESS The hub port is reset
+ @retval EFI_TIMEOUT Failed to reset the port in time
+ @retval Others Failed to reset the port
+
+**/
+STATIC
+EFI_STATUS
+UsbHubResetPort (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ EFI_USB_PORT_STATUS PortState;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = UsbHubSetPortFeature (HubIf, Port, USB_HUB_PORT_RESET);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Drive the reset signal for at least 10ms. Check USB 2.0 Spec
+ // section 7.1.7.5 for timing requirements.
+ //
+ gBS->Stall (20 * USB_STALL_1_MS);
+
+ //
+ // USB hub will clear RESET bit if reset is actually finished.
+ //
+ ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
+
+ for (Index = 0; Index < 20; Index++) {
+ Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
+
+ if (!EFI_ERROR (Status) &&
+ !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
+
+ return EFI_SUCCESS;
+ }
+
+ gBS->Stall (5 * USB_STALL_1_MS);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ Release the hub's control of the interface
+
+ @param HubIf The hub interface
+
+ @retval EFI_SUCCESS The interface is release of hub control
+
+**/
+STATIC
+EFI_STATUS
+UsbHubRelease (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_STATUS Status;
+
+ UsbIo = &HubIf->UsbIo;
+ Status = UsbIo->UsbAsyncInterruptTransfer (
+ UsbIo,
+ HubIf->HubEp->Desc.EndpointAddress,
+ FALSE,
+ USB_HUB_POLL_INTERVAL,
+ 0,
+ NULL,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseEvent (HubIf->HubNotify);
+
+ HubIf->IsHub = FALSE;
+ HubIf->HubApi = NULL;
+ HubIf->HubEp = NULL;
+ HubIf->HubNotify = NULL;
+
+ USB_DEBUG (("UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Initialize the interface for root hub
+
+ @param HubIf The root hub interface
+
+ @retval EFI_SUCCESS The interface is initialied for root hub
+ @retval Others Failed to initialize the hub
+
+**/
+STATIC
+EFI_STATUS
+UsbRootHubInit (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ EFI_STATUS Status;
+ UINT8 MaxSpeed;
+ UINT8 NumOfPort;
+ UINT8 Support64;
+
+ Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ USB_DEBUG (("UsbRootHubInit: root hub %x - max speed %d, %d ports\n",
+ HubIf, MaxSpeed, NumOfPort));
+
+ HubIf->IsHub = TRUE;
+ HubIf->HubApi = &mUsbRootHubApi;
+ HubIf->HubEp = NULL;
+ HubIf->MaxSpeed = MaxSpeed;
+ HubIf->NumOfPort = NumOfPort;
+ HubIf->HubNotify = NULL;
+
+ //
+ // Create a timer to poll root hub ports periodically
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ UsbRootHubEnumeration,
+ HubIf,
+ &HubIf->HubNotify
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (
+ HubIf->HubNotify,
+ TimerPeriodic,
+ USB_ROOTHUB_POLL_INTERVAL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (HubIf->HubNotify);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ 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.
+
+ @param HubIf The root hub interface
+ @param Port The root hub port to get the state
+ @param PortState Variable to return the port state
+
+ @retval EFI_SUCCESS The port state is returned
+ @retval Others Failed to retrieve the port state
+
+**/
+STATIC
+EFI_STATUS
+UsbRootHubGetPortStatus (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ OUT EFI_USB_PORT_STATUS *PortState
+ )
+{
+ USB_BUS *Bus;
+ EFI_STATUS Status;
+
+ Bus = HubIf->Device->Bus;
+ Status = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
+
+ return Status;
+}
+
+
+/**
+ Clear the port change status.
+
+ @param HubIf The root hub interface
+ @param Port The root hub port
+
+ @retval EFI_SUCCESS The port state is returned
+ @retval Others Failed to retrieve the port state
+
+**/
+STATIC
+VOID
+UsbRootHubClearPortChange (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port
+ )
+{
+ EFI_USB_PORT_STATUS PortState;
+ USB_CHANGE_FEATURE_MAP *Map;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // OK, get the usb port status, now ACK the change bits.
+ // Don't return error when failed to clear the change bits.
+ // It may lead to extra port state report. USB bus should
+ // be able to handle this.
+ //
+ for (Index = 0; Index < USB_ROOT_HUB_MAP_SIZE; Index++) {
+ Map = &mRootHubFeatureMap[Index];
+
+ if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
+ UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Map->Feature);
+ }
+ }
+}
+
+
+
+/**
+ Set the root hub port feature
+
+ @param HubIf The Usb hub interface
+ @param Port The hub port
+ @param Feature The feature to set
+
+ @retval EFI_SUCCESS The root hub port is set with the feature
+ @retval Others Failed to set the feature
+
+**/
+STATIC
+EFI_STATUS
+UsbRootHubSetPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
+
+ return Status;
+}
+
+
+/**
+ Clear the root hub port feature
+
+ @param HubIf The root hub interface
+ @param Port The root hub port
+ @param Feature The feature to clear
+
+ @retval EFI_SUCCESS The root hub port is cleared of the feature
+ @retval Others Failed to clear the feature
+
+**/
+STATIC
+EFI_STATUS
+UsbRootHubClearPortFeature (
+ IN USB_INTERFACE *HubIf,
+ IN UINT8 Port,
+ IN EFI_USB_PORT_FEATURE Feature
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
+
+ return Status;
+}
+
+
+/**
+ Interface funtion to reset the root hub port
+
+ @param RootIf The root hub interface
+ @param Port The port to reset
+
+ @retval EFI_SUCCESS The hub port is reset
+ @retval EFI_TIMEOUT Failed to reset the port in time
+ @retval EFI_NOT_FOUND The low/full speed device connected to high speed
+ root hub is released to the companion UHCI
+ @retval Others Failed to reset the port
+
+**/
+STATIC
+EFI_STATUS
+UsbRootHubResetPort (
+ IN USB_INTERFACE *RootIf,
+ IN UINT8 Port
+ )
+{
+ USB_BUS *Bus;
+ EFI_STATUS Status;
+ EFI_USB_PORT_STATUS PortState;
+ UINTN Index;
+
+ //
+ // Notice: although EHCI requires that ENABLED bit be cleared
+ // when reset the port, we don't need to care that here. It
+ // should be handled in the EHCI driver.
+ //
+ Bus = RootIf->Device->Bus;
+ Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbRootHubResetPort: failed to start reset on port %d\n", Port));
+ return Status;
+ }
+
+ //
+ // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
+ // section 7.1.7.5 for timing requirements.
+ //
+ gBS->Stall (50 * USB_STALL_1_MS);
+
+ Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
+ return Status;
+ }
+
+ gBS->Stall (USB_STALL_1_MS);
+
+ //
+ // USB host controller won't clear the RESET bit until
+ // reset is actually finished.
+ //
+ ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
+
+ for (Index = 0; Index < USB_HUB_LOOP; Index++) {
+ Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
+ break;
+ }
+
+ gBS->Stall (10 * USB_STALL_1_MS);
+ }
+
+ if (Index == USB_HUB_LOOP) {
+ USB_ERROR (("UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
+ return EFI_TIMEOUT;
+ }
+
+ if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
+ //
+ // OK, the port is reset. If root hub is of high speed and
+ // the device is of low/full speed, release the ownership to
+ // companion UHCI. If root hub is of full speed, it won't
+ // automatically enable the port, we need to enable it manually.
+ //
+ if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
+ USB_ERROR (("UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
+
+ UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
+ return EFI_NOT_FOUND;
+
+ } else {
+
+ Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
+ return Status;
+ }
+
+ gBS->Stall (20 * USB_STALL_1_MS);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Release the root hub's control of the interface
+
+ @param HubIf The root hub interface
+
+ @retval EFI_SUCCESS The root hub's control of the interface is
+ released.
+
+**/
+STATIC
+EFI_STATUS
+UsbRootHubRelease (
+ IN USB_INTERFACE *HubIf
+ )
+{
+ USB_DEBUG (("UsbRootHubRelease: root hub released for hub %x\n", HubIf));
+
+ gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
+ gBS->CloseEvent (HubIf->HubNotify);
+
+ return EFI_SUCCESS;
+}
+
+USB_HUB_API mUsbHubApi = {
+ UsbHubInit,
+ UsbHubGetPortStatus,
+ UsbHubClearPortChange,
+ UsbHubSetPortFeature,
+ UsbHubClearPortFeature,
+ UsbHubResetPort,
+ UsbHubRelease
+};
+
+USB_HUB_API mUsbRootHubApi = {
+ UsbRootHubInit,
+ UsbRootHubGetPortStatus,
+ UsbRootHubClearPortChange,
+ UsbRootHubSetPortFeature,
+ UsbRootHubClearPortFeature,
+ UsbRootHubResetPort,
+ UsbRootHubRelease
+};
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h new file mode 100644 index 0000000..0238ea0 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h @@ -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
+
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c new file mode 100644 index 0000000..216f948 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c @@ -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
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h new file mode 100644 index 0000000..2dafd1c --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h @@ -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
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c new file mode 100644 index 0000000..c5a0604 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c @@ -0,0 +1,1384 @@ +/** @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.c
+
+ Abstract:
+
+ Usb Bus Driver Binding and Bus IO Protocol
+
+ Revision History
+
+
+**/
+
+#include "UsbBus.h"
+
+//
+// USB_BUS_PROTOCOL is only used to locate USB_BUS
+//
+EFI_GUID mUsbBusProtocolGuid = EFI_USB_BUS_PROTOCOL_GUID;
+
+
+/**
+ USB_IO function to execute a control transfer. This
+ function will execute the USB transfer. If transfer
+ successes, it will sync the internal state of USB bus
+ with device state.
+
+ @param This The USB_IO instance
+ @param Request The control transfer request
+ @param Direction Direction for data stage
+ @param Timeout The time to wait before timeout
+ @param Data The buffer holding the data
+ @param DataLength Then length of the data
+ @param UsbStatus USB result
+
+ @retval EFI_INVALID_PARAMETER The parameters are invalid
+ @retval EFI_SUCCESS The control transfer succeded.
+ @retval Others Failed to execute the transfer
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoControlTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN EFI_USB_DEVICE_REQUEST *Request,
+ IN EFI_USB_DATA_DIRECTION Direction,
+ IN UINT32 Timeout,
+ IN OUT VOID *Data, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ OUT UINT32 *UsbStatus
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (UsbStatus == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ Status = UsbHcControlTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Dev->Speed,
+ Dev->MaxPacket0,
+ Request,
+ Direction,
+ Data,
+ &DataLength,
+ (UINTN) Timeout,
+ &Dev->Translator,
+ UsbStatus
+ );
+
+ if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {
+ //
+ // Clear TT buffer when CTRL/BULK split transaction failes
+ // Clear the TRANSLATOR TT buffer, not parent's buffer
+ //
+ if (Dev->Translator.TranslatorHubAddress != 0) {
+ UsbHubCtrlClearTTBuffer (
+ Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],
+ Dev->Translator.TranslatorPortNumber,
+ Dev->Address,
+ 0,
+ USB_ENDPOINT_CONTROL
+ );
+ }
+
+ goto ON_EXIT;
+ }
+
+ //
+ // Some control transfer will change the device's internal
+ // status, such as Set_Configuration and Set_Interface.
+ // We must synchronize the bus driver's status with that in
+ // device. We ignore the Set_Descriptor request because it's
+ // hardly used by any device, especially in pre-boot environment
+ //
+
+ //
+ // Reset the endpoint toggle when endpoint stall is cleared
+ //
+ if ((Request->Request == USB_REQ_CLEAR_FEATURE) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
+ USB_TARGET_ENDPOINT)) &&
+ (Request->Value == USB_FEATURE_ENDPOINT_HALT)) {
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index);
+
+ if (EpDesc != NULL) {
+ EpDesc->Toggle = 0;
+ }
+ }
+
+ //
+ // Select a new configuration. This is a dangerous action. Upper driver
+ // should stop use its current UsbIo after calling this driver. The old
+ // UsbIo will be uninstalled and new UsbIo be installed. We can't use
+ // ReinstallProtocol since interfaces in different configuration may be
+ // completely irrellvant.
+ //
+ if ((Request->Request == USB_REQ_SET_CONFIG) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
+ USB_TARGET_DEVICE))) {
+ //
+ // Don't re-create the USB interfaces if configuration isn't changed.
+ //
+ if ((Dev->ActiveConfig != NULL) &&
+ (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) {
+
+ goto ON_EXIT;
+ }
+
+ USB_DEBUG (("UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));
+
+ if (Dev->ActiveConfig != NULL) {
+ UsbRemoveConfig (Dev);
+ }
+
+ if (Request->Value != 0) {
+ Status = UsbSelectConfig (Dev, (UINT8) Request->Value);
+ }
+
+ //
+ // Exit now, Old USB_IO is invalid now
+ //
+ goto ON_EXIT;
+ }
+
+ //
+ // A new alternative setting is selected for the interface.
+ // No need to reinstall UsbIo in this case because only
+ // underlying communication endpoints are changed. Functionality
+ // should remains the same.
+ //
+ if ((Request->Request == USB_REQ_SET_INTERFACE) &&
+ (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
+ USB_TARGET_INTERFACE)) &&
+ (Request->Index == UsbIf->IfSetting->Desc.InterfaceNumber)) {
+
+ Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value);
+
+ if (!EFI_ERROR (Status)) {
+ UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Execute a bulk transfer to the device endpoint
+
+ @param This The USB IO instance
+ @param Endpoint The device endpoint
+ @param Data The data to transfer
+ @param DataLength The length of the data to transfer
+ @param Timeout Time to wait before timeout
+ @param UsbStatus The result of USB transfer
+
+ @retval EFI_SUCCESS The bulk transfer is OK
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid
+ @retval Others Failed to execute transfer, reason returned in
+ UsbStatus
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoBulkTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *UsbStatus
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ UINT8 BufNum;
+ UINT8 Toggle;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||
+ (UsbStatus == NULL)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);
+
+ if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ BufNum = 1;
+ Toggle = EpDesc->Toggle;
+ Status = UsbHcBulkTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Endpoint,
+ Dev->Speed,
+ EpDesc->Desc.MaxPacketSize,
+ BufNum,
+ &Data,
+ DataLength,
+ &Toggle,
+ Timeout,
+ &Dev->Translator,
+ UsbStatus
+ );
+
+ EpDesc->Toggle = Toggle;
+
+ if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {
+ //
+ // Clear TT buffer when CTRL/BULK split transaction failes.
+ // Clear the TRANSLATOR TT buffer, not parent's buffer
+ //
+ if (Dev->Translator.TranslatorHubAddress != 0) {
+ UsbHubCtrlClearTTBuffer (
+ Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],
+ Dev->Translator.TranslatorPortNumber,
+ Dev->Address,
+ 0,
+ USB_ENDPOINT_BULK
+ );
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Execute a synchronous interrupt transfer
+
+ @param This The USB IO instance
+ @param Endpoint The device endpoint
+ @param Data The data to transfer
+ @param DataLength The length of the data to transfer
+ @param Timeout Time to wait before timeout
+ @param UsbStatus The result of USB transfer
+
+ @retval EFI_SUCCESS The synchronous interrupt transfer is OK
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid
+ @retval Others Failed to execute transfer, reason returned in
+ UsbStatus
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoSyncInterruptTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN OUT VOID *Data,
+ IN OUT UINTN *DataLength,
+ IN UINTN Timeout,
+ OUT UINT32 *UsbStatus
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ EFI_TPL OldTpl;
+ UINT8 Toggle;
+ EFI_STATUS Status;
+
+ if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||
+ (UsbStatus == NULL)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);
+
+ if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Toggle = EpDesc->Toggle;
+ Status = UsbHcSyncInterruptTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Endpoint,
+ Dev->Speed,
+ EpDesc->Desc.MaxPacketSize,
+ Data,
+ DataLength,
+ &Toggle,
+ Timeout,
+ &Dev->Translator,
+ UsbStatus
+ );
+
+ EpDesc->Toggle = Toggle;
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Queue a new asynchronous interrupt transfer, or remove the old
+ request if (IsNewTransfer == FALSE)
+
+ @param This The USB_IO instance
+ @param Endpoint The device endpoint
+ @param IsNewTransfer Whether this is a new request, if it's old, remove
+ the request
+ @param PollInterval The interval to poll the transfer result, (in ms)
+ @param DataLength The length of perodic data transfer
+ @param Callback The function to call periodicaly when transfer is
+ ready
+ @param Context The context to the callback
+
+ @retval EFI_SUCCESS New transfer is queued or old request is removed
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid
+ @retval Others Failed to queue the new request or remove the old
+ request
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoAsyncInterruptTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Endpoint,
+ IN BOOLEAN IsNewTransfer,
+ IN UINTN PollInterval, OPTIONAL
+ IN UINTN DataLength, OPTIONAL
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, OPTIONAL
+ IN VOID *Context OPTIONAL
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ USB_ENDPOINT_DESC *EpDesc;
+ EFI_TPL OldTpl;
+ UINT8 Toggle;
+ EFI_STATUS Status;
+
+ if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint);
+
+ if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Toggle = EpDesc->Toggle;
+ Status = UsbHcAsyncInterruptTransfer (
+ Dev->Bus,
+ Dev->Address,
+ Endpoint,
+ Dev->Speed,
+ EpDesc->Desc.MaxPacketSize,
+ IsNewTransfer,
+ &Toggle,
+ PollInterval,
+ DataLength,
+ &Dev->Translator,
+ Callback,
+ Context
+ );
+
+ EpDesc->Toggle = Toggle;
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Execute a synchronous isochronous transfer
+
+ @param This The USB IO instance
+ @param DeviceEndpoint The device endpoint
+ @param Data The data to transfer
+ @param DataLength The length of the data to transfer
+ @param UsbStatus The result of USB transfer
+
+ @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoIsochronousTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ OUT UINT32 *Status
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Queue an asynchronous isochronous transfer
+
+ @param This The USB_IO instance
+ @param DeviceEndpoint The device endpoint
+ @param DataLength The length of perodic data transfer
+ @param IsochronousCallBack The function to call periodicaly when transfer is
+ ready
+ @param Context The context to the callback
+
+ @retval EFI_UNSUPPORTED Currently isochronous transfer isn't supported
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoAsyncIsochronousTransfer (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 DeviceEndpoint,
+ IN OUT VOID *Data,
+ IN UINTN DataLength,
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
+ IN VOID *Context OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Retrieve the device descriptor of the device
+
+ @param This The USB IO instance
+ @param Descriptor The variable to receive the device descriptor
+
+ @retval EFI_SUCCESS The device descriptor is returned
+ @retval EFI_INVALID_PARAMETER The parameter is invalid
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoGetDeviceDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the configuration descriptor of the current active configuration
+
+ @param This The USB IO instance
+ @param Descriptor The USB configuration descriptor
+
+ @retval EFI_SUCCESS The active configuration descriptor is returned
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid
+ @retval EFI_NOT_FOUND Currently no active configuration is selected.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoGetActiveConfigDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ if (Dev->ActiveConfig == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto ON_EXIT;
+ }
+
+ CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Retrieve the active interface setting descriptor for this USB IO instance
+
+ @param This The USB IO instance
+ @param Descriptor The variable to receive active interface setting
+
+ @retval EFI_SUCCESS The active interface setting is returned
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoGetInterfaceDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor
+ )
+{
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ if (Descriptor == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve the endpoint descriptor from this interface setting
+
+ @param This The USB IO instance
+ @param Index The index (start from zero) of the endpoint to
+ retrieve
+ @param Descriptor The variable to receive the descriptor
+
+ @retval EFI_SUCCESS The endpoint descriptor is returned
+ @retval EFI_INVALID_PARAMETER Some parameter is invalid
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoGetEndpointDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT8 Index,
+ OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor
+ )
+{
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+
+ if ((Descriptor == NULL) || (Index >= UsbIf->IfSetting->Desc.NumEndpoints)) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (
+ Descriptor,
+ &(UsbIf->IfSetting->Endpoints[Index]->Desc),
+ sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
+ );
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve the supported language ID table from the device
+
+ @param This The USB IO instance
+ @param LangIDTable The table to return the language IDs
+ @param TableSize The number of supported languanges
+
+ @retval EFI_SUCCESS The language ID is return
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoGetSupportedLanguages (
+ IN EFI_USB_IO_PROTOCOL *This,
+ OUT UINT16 **LangIDTable,
+ OUT UINT16 *TableSize
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ *LangIDTable = Dev->LangId;
+ *TableSize = Dev->TotalLangId;
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Retrieve an indexed string in the language of LangID
+
+ @param This The USB IO instance
+ @param LangID The language ID of the string to retrieve
+ @param StringIndex The index of the string
+ @param String The variable to receive the string
+
+ @retval EFI_SUCCESS The string is returned
+ @retval EFI_NOT_FOUND No such string existed
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UsbIoGetStringDescriptor (
+ IN EFI_USB_IO_PROTOCOL *This,
+ IN UINT16 LangID,
+ IN UINT8 StringIndex,
+ OUT CHAR16 **String
+ )
+{
+ USB_DEVICE *Dev;
+ USB_INTERFACE *UsbIf;
+ EFI_USB_STRING_DESCRIPTOR *StrDesc;
+ EFI_TPL OldTpl;
+ UINT8 *Buf;
+ UINT8 Index;
+ EFI_STATUS Status;
+
+ if ((StringIndex == 0) || (LangID == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ //
+ // Check whether language ID is supported
+ //
+ Status = EFI_NOT_FOUND;
+
+ for (Index = 0; Index < Dev->TotalLangId; Index++) {
+ if (Dev->LangId[Index] == LangID) {
+ break;
+ }
+ }
+
+ if (Index == Dev->TotalLangId) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Retrieve the string descriptor then allocate a buffer
+ // to hold the string itself.
+ //
+ StrDesc = UsbGetOneString (Dev, StringIndex, LangID);
+
+ if (StrDesc == NULL) {
+ goto ON_EXIT;
+ }
+
+ if (StrDesc->Length <= 2) {
+ goto FREE_STR;
+ }
+
+ Buf = AllocateZeroPool (StrDesc->Length);
+
+ if (Buf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FREE_STR;
+ }
+
+ CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);
+ *String = (CHAR16 *) Buf;
+ Status = EFI_SUCCESS;
+
+FREE_STR:
+ gBS->FreePool (StrDesc);
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Reset the device, then if that succeeds, reconfigure the
+ device with its address and current active configuration.
+
+ @param This The USB IO instance
+
+ @retval EFI_SUCCESS The device is reset and configured
+ @retval Others Failed to reset the device
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIoPortReset (
+ IN EFI_USB_IO_PROTOCOL *This
+ )
+{
+ USB_INTERFACE *UsbIf;
+ USB_INTERFACE *HubIf;
+ USB_DEVICE *Dev;
+ UINT8 Address;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (This);
+ Dev = UsbIf->Device;
+
+ HubIf = Dev->ParentIf;
+ Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbIoPortReset: failed to reset hub port %d@hub %d, %r \n",
+ Dev->ParentPort, Dev->ParentAddr, Status));
+
+ goto ON_EXIT;
+ }
+
+ //
+ // Reset the device to its current address. The device now has a
+ // address of ZERO, so need to set Dev->Address to zero first for
+ // host to communicate with the device
+ //
+ Address = Dev->Address;
+ Dev->Address = 0;
+ Status = UsbSetAddress (Dev, Address);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbIoPortReset: failed to set address for device %d - %r\n",
+ Address, Status));
+
+ goto ON_EXIT;
+ }
+
+ Dev->Address = Address;
+
+ //
+ // Reset the current active configure, after this device
+ // is in CONFIGURED state.
+ //
+ if (Dev->ActiveConfig != NULL) {
+ Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbIoPortReset: failed to set configure for device %d - %r\n",
+ Address, Status));
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+EFI_USB_IO_PROTOCOL mUsbIoProtocol = {
+ UsbIoControlTransfer,
+ UsbIoBulkTransfer,
+ UsbIoAsyncInterruptTransfer,
+ UsbIoSyncInterruptTransfer,
+ UsbIoIsochronousTransfer,
+ UsbIoAsyncIsochronousTransfer,
+ UsbIoGetDeviceDescriptor,
+ UsbIoGetActiveConfigDescriptor,
+ UsbIoGetInterfaceDescriptor,
+ UsbIoGetEndpointDescriptor,
+ UsbIoGetStringDescriptor,
+ UsbIoGetSupportedLanguages,
+ UsbIoPortReset
+};
+
+//@MT: EFI_DRIVER_ENTRY_POINT (UsbBusDriverEntryPoint)
+
+EFI_STATUS
+EFIAPI
+UsbBusDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ The USB bus driver entry pointer
+
+Arguments:
+
+ ImageHandle - The driver image handle
+ SystemTable - The system table
+
+Returns:
+
+ EFI_SUCCESS - The component name protocol is installed
+ Others - Failed to init the usb driver
+
+--*/
+{
+ return EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &mUsbBusDriverBinding,
+ ImageHandle,
+ &mUsbBusComponentName,
+ NULL,
+ NULL
+ );
+}
+
+
+/**
+ Check whether USB bus driver support this device
+
+ @param This The USB bus driver binding protocol
+ @param Controller The controller handle to test againist
+ @param RemainingDevicePath The remaining device path
+
+ @retval EFI_SUCCESS The bus supports this controller.
+ @retval EFI_UNSUPPORTED This device isn't supported
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_DEV_PATH_PTR DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_USB2_HC_PROTOCOL *Usb2Hc;
+ EFI_USB_HC_PROTOCOL *UsbHc;
+ EFI_STATUS Status;
+
+ //
+ // Check whether device path is valid
+ //
+ if (RemainingDevicePath != NULL) {
+ DevicePathNode.DevPath = RemainingDevicePath;
+
+ if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||
+ (DevicePathNode.DevPath->SubType != MSG_USB_DP) ||
+ (DevicePathNodeLength (DevicePathNode.DevPath) != sizeof (USB_DEVICE_PATH))) {
+
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Check whether USB_HC2 protocol is installed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &Usb2Hc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If failed to open USB_HC2, fall back to USB_HC
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **) &UsbHc,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Start to process the controller
+
+ @param This The USB bus driver binding instance
+ @param Controller The controller to check
+ @param RemainingDevicePath The remaining device patch
+
+ @retval EFI_SUCCESS The controller is controlled by the usb bus
+ @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
+ bus
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ USB_BUS *UsbBus;
+ USB_DEVICE *RootHub;
+ USB_INTERFACE *RootIf;
+ EFI_USB_BUS_PROTOCOL *UsbBusId;
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+
+ //
+ // Locate the USB bus protocol, if it is found, USB bus
+ // is already started on this controller.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &mUsbBusProtocolGuid,
+ (VOID **) &UsbBusId,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ UsbBus = AllocateZeroPool (sizeof (USB_BUS));
+
+ if (UsbBus == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UsbBus->Signature = USB_BUS_SIGNATURE;
+ UsbBus->HostHandle = Controller;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UsbBus->DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbBusStart: Failed to open device path %r\n", Status));
+
+ gBS->FreePool (UsbBus);
+ return Status;
+ }
+
+ //
+ // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).
+ // This is for backward compatbility with EFI 1.x. In UEFI
+ // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2
+ // and USB_HC because EHCI driver will install both protocols
+ // (for the same reason). If we don't consume both of them,
+ // the unconsumed one may be opened by others.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ (VOID **) &(UsbBus->Usb2Hc),
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ Status2 = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ (VOID **) &(UsbBus->UsbHc),
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {
+ USB_ERROR (("UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));
+
+ Status = EFI_DEVICE_ERROR;
+ goto CLOSE_HC;
+ }
+
+ //
+ // Create a fake usb device for root hub
+ //
+ RootHub = AllocateZeroPool (sizeof (USB_DEVICE));
+
+ if (RootHub == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CLOSE_HC;
+ }
+
+ RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));
+
+ if (RootIf == NULL) {
+ gBS->FreePool (RootHub);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CLOSE_HC;
+ }
+
+ RootHub->Bus = UsbBus;
+ RootHub->NumOfInterface = 1;
+ RootHub->Interfaces[0] = RootIf;
+ RootIf->Signature = USB_INTERFACE_SIGNATURE;
+ RootIf->Device = RootHub;
+ RootIf->DevicePath = UsbBus->DevicePath;
+
+ Status = mUsbRootHubApi.Init (RootIf);
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbBusStart: Failed to init root hub %r\n", Status));
+ goto FREE_ROOTHUB;
+ }
+
+ UsbBus->Devices[0] = RootHub;
+
+ //
+ // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &mUsbBusProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &UsbBus->BusId
+ );
+
+ if (EFI_ERROR (Status)) {
+ USB_ERROR (("UsbBusStart: Failed to install bus protocol %r\n", Status));
+
+ mUsbRootHubApi.Release (RootIf);
+ goto FREE_ROOTHUB;
+ }
+
+ UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);
+ UsbHcSetState (UsbBus, EfiUsbHcStateOperational);
+
+ USB_DEBUG (("UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf));
+ return EFI_SUCCESS;
+
+FREE_ROOTHUB:
+ gBS->FreePool (RootIf);
+ gBS->FreePool (RootHub);
+
+CLOSE_HC:
+ if (UsbBus->Usb2Hc != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (UsbBus->UsbHc != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->FreePool (UsbBus);
+
+ USB_ERROR (("UsbBusStart: Failed to start bus driver %r\n", Status));
+ return Status;
+}
+
+
+/**
+ Stop handle the controller by this USB bus driver
+
+ @param This The USB bus driver binding protocol
+ @param Controller The controller to release
+ @param NumberOfChildren The child of USB bus that opened controller
+ BY_CHILD
+ @param ChildHandleBuffer The array of child handle
+
+ @retval EFI_SUCCESS The controller or children are stopped
+ @retval EFI_DEVICE_ERROR Failed to stop the driver
+
+**/
+EFI_STATUS
+EFIAPI
+UsbBusControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ USB_BUS *Bus;
+ USB_DEVICE *RootHub;
+ USB_DEVICE *UsbDev;
+ USB_INTERFACE *RootIf;
+ USB_INTERFACE *UsbIf;
+ EFI_USB_BUS_PROTOCOL *BusId;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ EFI_TPL OldTpl;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (NumberOfChildren > 0) {
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ //
+ // It is possible that the child has already been released:
+ // 1. For combo device, free one device will release others.
+ // 2. If a hub is released, all devices on its down facing
+ // ports are released also.
+ //
+ continue;
+ }
+
+ UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo);
+ UsbDev = UsbIf->Device;
+
+ UsbRemoveDevice (UsbDev);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+ }
+
+ USB_DEBUG (("UsbBusStop: usb bus stopped on %x\n", Controller));
+
+ //
+ // Locate USB_BUS for the current host controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &mUsbBusProtocolGuid,
+ (VOID **) &BusId,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Bus = USB_BUS_FROM_THIS (BusId);
+
+ //
+ // Stop the root hub, then free all the devices
+ //
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+ UsbHcSetState (Bus, EfiUsbHcStateHalt);
+
+ RootHub = Bus->Devices[0];
+ RootIf = RootHub->Interfaces[0];
+
+ mUsbRootHubApi.Release (RootIf);
+
+ for (Index = 1; Index < USB_MAX_DEVICES; Index++) {
+ if (Bus->Devices[Index] != NULL) {
+ UsbRemoveDevice (Bus->Devices[Index]);
+ }
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ gBS->FreePool (RootIf);
+ gBS->FreePool (RootHub);
+
+ //
+ // Uninstall the bus identifier and close USB_HC/USB2_HC protocols
+ //
+ gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &Bus->BusId);
+
+ if (Bus->Usb2Hc != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsb2HcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ if (Bus->UsbHc != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbHcProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->FreePool (Bus);
+
+ return Status;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {
+ UsbBusControllerDriverSupported,
+ UsbBusControllerDriverStart,
+ UsbBusControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h new file mode 100644 index 0000000..2ecc2c8 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h @@ -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
|