Import Usb/UsbBusDxe and Usb/UsbMassStorageDxe into MdeModulePkg.
authorvanjeff <vanjeff@de2fecce-e211-0410-80a6-f3fac2684e05>
Wed, 11 Jul 2007 08:47:37 +0000 (08:47 +0000)
committervanjeff <vanjeff@de2fecce-e211-0410-80a6-f3fac2684e05>
Wed, 11 Jul 2007 08:47:37 +0000 (08:47 +0000)
git-svn-id: https://edk2.tianocore.org/svn/edk2/trunk@3193 de2fecce-e211-0410-80a6-f3fac2684e05

25 files changed:
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.msa [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf [new file with mode: 0644]
edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.msa [new file with mode: 0644]

diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..da97372
--- /dev/null
@@ -0,0 +1,164 @@
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+\r
+**/\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/UefiLib.h>\r
+\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL      mUsbBusComponentName = {\r
+  UsbBusComponentNameGetDriverName,\r
+  UsbBusComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mUsbBusDriverNameTable[] = {\r
+  { "eng", L"Usb Bus Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  Arguments:\r
+    This       - A pointer to the EFI_COMPONENT_NAME2_PROTOCOL instance.\r
+    Language   - A pointer to a three character ISO 639-2 language identifier.\r
+                 This is the language of the driver name that that the caller\r
+                 is requesting, and it must match one of the languages specified\r
+                 in SupportedLanguages.  The number of languages supported by a\r
+                 driver is up to the driver writer.\r
+    DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+                 is the name of the driver specified by This in the language\r
+                 specified by Language.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the Driver specified by This\r
+                            and the language specified by Language was returned\r
+                            in DriverName.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - DriverName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+          Language,\r
+          mUsbBusComponentName.SupportedLanguages,\r
+          mUsbBusDriverNameTable,\r
+          DriverName\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the controller\r
+    that is being managed by an EFI Driver.\r
+\r
+  Arguments:\r
+    This             - A pointer to the EFI_COMPONENT_NAME2_PROTOCOL instance.\r
+    ControllerHandle - The handle of a controller that the driver specified by\r
+                       This is managing.  This handle specifies the controller\r
+                       whose name is to be returned.\r
+    ChildHandle      - The handle of the child controller to retrieve the name\r
+                       of.  This is an optional parameter that may be NULL.  It\r
+                       will be NULL for device drivers.  It will also be NULL\r
+                       for a bus drivers that wish to retrieve the name of the\r
+                       bus controller.  It will not be NULL for a bus driver\r
+                       that wishes to retrieve the name of a child controller.\r
+    Language         - A pointer to a three character ISO 639-2 language\r
+                       identifier.  This is the language of the controller name\r
+                       that that the caller is requesting, and it must match one\r
+                       of the languages specified in SupportedLanguages.  The\r
+                       number of languages supported by a driver is up to the\r
+                       driver writer.\r
+    ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                       string is the name of the controller specified by\r
+                       ControllerHandle and ChildHandle in the language specified\r
+                       by Language from the point of view of the driver specified\r
+                       by This.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the user readable name in the\r
+                            language specified by Language for the driver\r
+                            specified by This was returned in DriverName.\r
+    EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This is not currently managing\r
+                            the controller specified by ControllerHandle and\r
+                            ChildHandle.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
new file mode 100644 (file)
index 0000000..423d9fb
--- /dev/null
@@ -0,0 +1,99 @@
+#/** @file\r
+# Component name for module UsbBus\r
+#\r
+# Copyright (c) 2006, Intel Corporation. All right reserved.\r
+#\r
+#  All rights reserved. This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UsbBusDxe\r
+  FILE_GUID                      = 240612B7-A063-11d4-9A3A-0090273FC14D\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = UsbBusDriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+################################################################################\r
+#\r
+# Sources Section - list of files that are required for the build to succeed.\r
+#\r
+################################################################################\r
+\r
+[Sources.common]\r
+  UsbDesc.c\r
+  UsbEnumer.c\r
+  UsbEnumer.h\r
+  usbbus.c\r
+  UsbHub.c\r
+  ComponentName.c\r
+  UsbUtility.h\r
+  UsbHub.h\r
+  UsbUtility.c\r
+  UsbDesc.h\r
+  usbbus.h\r
+\r
+################################################################################\r
+#\r
+# Package Dependency Section - list of Package files that are required for\r
+#                              this module.\r
+#\r
+################################################################################\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+################################################################################\r
+#\r
+# Library Class Section - list of Library Classes that are required for\r
+#                         this module.\r
+#\r
+################################################################################\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  DevicePathLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  DebugLib\r
+\r
+\r
+################################################################################\r
+#\r
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names\r
+#                           that this module uses or produces.\r
+#\r
+################################################################################\r
+\r
+[Protocols]\r
+  gEfiUsbIoProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUsb2HcProtocolGuid                        # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUsbHcProtocolGuid                         # PROTOCOL ALWAYS_CONSUMED\r
+\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.msa b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.msa
new file mode 100644 (file)
index 0000000..deaecc6
--- /dev/null
@@ -0,0 +1,85 @@
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+  <MsaHeader>\r
+    <ModuleName>UsbBusDxe</ModuleName>\r
+    <ModuleType>DXE_DRIVER</ModuleType>\r
+    <GuidValue>240612B7-A063-11d4-9A3A-0090273FC14D</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component name for module UsbBus</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2006, Intel Corporation. All right reserved.</Copyright>\r
+    <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>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>UsbBusDxe</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseMemoryLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DevicePathLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>MemoryAllocationLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>usbbus.h</Filename>\r
+    <Filename>UsbDesc.h</Filename>\r
+    <Filename>UsbUtility.c</Filename>\r
+    <Filename>UsbHub.h</Filename>\r
+    <Filename>UsbUtility.h</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>UsbHub.c</Filename>\r
+    <Filename>usbbus.c</Filename>\r
+    <Filename>UsbEnumer.h</Filename>\r
+    <Filename>UsbEnumer.c</Filename>\r
+    <Filename>UsbDesc.c</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+    <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUsbHcProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUsb2HcProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUsbIoProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleEntryPoint>UsbBusDriverEntryPoint</ModuleEntryPoint>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
new file mode 100644 (file)
index 0000000..ffed149
--- /dev/null
@@ -0,0 +1,991 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbDesc.c\r
+\r
+  Abstract:\r
+\r
+    Manage Usb Descriptor List\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#include "UsbBus.h"\r
+\r
+\r
+/**\r
+  Free the interface setting descriptor\r
+\r
+  @param  Setting               The descriptor to free\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbFreeInterfaceDesc (\r
+  IN USB_INTERFACE_SETTING  *Setting\r
+  )\r
+{\r
+  USB_ENDPOINT_DESC       *Ep;\r
+  UINTN                   Index;\r
+\r
+  if (Setting->Endpoints != NULL) {\r
+    //\r
+    // Each interface setting may have several endpoints, free them first.\r
+    //\r
+    for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {\r
+      Ep = Setting->Endpoints[Index];\r
+\r
+      if (Ep != NULL) {\r
+        gBS->FreePool (Ep);\r
+      }\r
+    }\r
+\r
+    gBS->FreePool (Setting->Endpoints);\r
+  }\r
+\r
+  gBS->FreePool (Setting);\r
+}\r
+\r
+\r
+\r
+/**\r
+  Free a configuration descriptor with its interface\r
+  descriptors. It may be initialized partially\r
+\r
+  @param  Config                The configuration descriptor to free\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbFreeConfigDesc (\r
+  IN USB_CONFIG_DESC      *Config\r
+  )\r
+{\r
+  USB_INTERFACE_DESC      *Interface;\r
+  UINTN                   Index;\r
+  UINTN                   SetIndex;\r
+\r
+  if (Config->Interfaces != NULL) {\r
+    //\r
+    // A configuration may have several interfaces, free the interface\r
+    //\r
+    for (Index = 0; Index < Config->Desc.NumInterfaces; Index++) {\r
+      Interface = Config->Interfaces[Index];\r
+\r
+      if (Interface == NULL) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Each interface may have several settings, free the settings\r
+      //\r
+      for (SetIndex = 0; SetIndex < Interface->NumOfSetting; SetIndex++) {\r
+        if (Interface->Settings[SetIndex] != NULL) {\r
+          UsbFreeInterfaceDesc (Interface->Settings[SetIndex]);\r
+        }\r
+      }\r
+\r
+      gBS->FreePool (Interface);\r
+    }\r
+\r
+    gBS->FreePool (Config->Interfaces);\r
+  }\r
+\r
+  gBS->FreePool (Config);\r
+\r
+}\r
+\r
+\r
+\r
+/**\r
+  Free a device descriptor with its configurations\r
+\r
+  @param  DevDesc               The device descriptor\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UsbFreeDevDesc (\r
+  IN USB_DEVICE_DESC      *DevDesc\r
+  )\r
+{\r
+  UINTN                   Index;\r
+\r
+  if (DevDesc->Configs != NULL) {\r
+    for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {\r
+      if (DevDesc->Configs[Index] != NULL) {\r
+        UsbFreeConfigDesc (DevDesc->Configs[Index]);\r
+      }\r
+    }\r
+\r
+    gBS->FreePool (DevDesc->Configs);\r
+  }\r
+\r
+  gBS->FreePool (DevDesc);\r
+}\r
+\r
+\r
+/**\r
+  Create a descriptor\r
+\r
+  @param  DescBuf               The buffer of raw descriptor\r
+  @param  Len                   The lenght of the raw descriptor buffer\r
+  @param  Type                  The type of descriptor to create\r
+  @param  Consumed              Number of bytes consumed\r
+\r
+  @return Created descriptor or NULL\r
+\r
+**/\r
+STATIC\r
+VOID *\r
+UsbCreateDesc (\r
+  IN  UINT8               *DescBuf,\r
+  IN  INTN                Len,\r
+  IN  UINT8               Type,\r
+  OUT INTN                *Consumed\r
+  )\r
+{\r
+  USB_DESC_HEAD           *Head;\r
+  INTN                    DescLen;\r
+  INTN                    CtrlLen;\r
+  INTN                    Offset;\r
+  VOID                    *Desc;\r
+\r
+  DescLen   = 0;\r
+  CtrlLen   = 0;\r
+  *Consumed = 0;\r
+\r
+  switch (Type) {\r
+  case USB_DESC_TYPE_DEVICE:\r
+    DescLen = sizeof (EFI_USB_DEVICE_DESCRIPTOR);\r
+    CtrlLen = sizeof (USB_DEVICE_DESC);\r
+    break;\r
+\r
+  case USB_DESC_TYPE_CONFIG:\r
+    DescLen = sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
+    CtrlLen = sizeof (USB_CONFIG_DESC);\r
+    break;\r
+\r
+  case USB_DESC_TYPE_INTERFACE:\r
+    DescLen = sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
+    CtrlLen = sizeof (USB_INTERFACE_SETTING);\r
+    break;\r
+\r
+  case USB_DESC_TYPE_ENDPOINT:\r
+    DescLen = sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+    CtrlLen = sizeof (USB_ENDPOINT_DESC);\r
+    break;\r
+  }\r
+\r
+  //\r
+  // All the descriptor has a common LTV (Length, Type, Value)\r
+  // format. Skip the descriptor that isn't of this Type\r
+  //\r
+  Offset = 0;\r
+  Head   = (USB_DESC_HEAD*)DescBuf;\r
+\r
+  while ((Offset < Len) && (Head->Type != Type)) {\r
+    Offset += Head->Len;\r
+    Head    = (USB_DESC_HEAD*)(DescBuf + Offset);\r
+  }\r
+\r
+  if ((Len <= Offset)      || (Len < Offset + DescLen) ||\r
+      (Head->Type != Type) || (Head->Len != DescLen)) {\r
+    USB_ERROR (("UsbCreateDesc: met mal-format descriptor\n"));\r
+    return NULL;\r
+  }\r
+\r
+  Desc = AllocateZeroPool (CtrlLen);\r
+\r
+  if (Desc == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  CopyMem (Desc, Head, DescLen);\r
+  *Consumed = Offset + Head->Len;\r
+\r
+  return Desc;\r
+}\r
+\r
+\r
+/**\r
+  Parse an interface desciptor and its endpoints\r
+\r
+  @param  DescBuf               The buffer of raw descriptor\r
+  @param  Len                   The lenght of the raw descriptor buffer\r
+  @param  Consumed              The number of raw descriptor consumed\r
+\r
+  @return The create interface setting or NULL if failed\r
+\r
+**/\r
+STATIC\r
+USB_INTERFACE_SETTING *\r
+UsbParseInterfaceDesc (\r
+  IN  UINT8               *DescBuf,\r
+  IN  INTN                Len,\r
+  OUT INTN                *Consumed\r
+  )\r
+{\r
+  USB_INTERFACE_SETTING   *Setting;\r
+  USB_ENDPOINT_DESC       *Ep;\r
+  UINTN                   Index;\r
+  UINTN                   NumEp;\r
+  INTN                    Used;\r
+  INTN                    Offset;\r
+\r
+  *Consumed = 0;\r
+  Setting   = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used);\r
+\r
+  if (Setting == NULL) {\r
+    USB_ERROR (("UsbParseInterfaceDesc: failed to create interface descriptor\n"));\r
+    return NULL;\r
+  }\r
+\r
+  Offset = Used;\r
+\r
+  //\r
+  // Create an arry to hold the interface's endpoints\r
+  //\r
+  NumEp  = Setting->Desc.NumEndpoints;\r
+\r
+  USB_DEBUG (("UsbParseInterfaceDesc: interface %d(setting %d) has %d endpoints\n",\r
+              Setting->Desc.InterfaceNumber, Setting->Desc.AlternateSetting, NumEp));\r
+\r
+  if (NumEp == 0) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Setting->Endpoints  = AllocateZeroPool (sizeof (USB_ENDPOINT_DESC *) * NumEp);\r
+\r
+  if (Setting->Endpoints == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Create the endpoints for this interface\r
+  //\r
+  for (Index = 0; Index < NumEp; Index++) {\r
+    Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used);\r
+\r
+    if (Ep == NULL) {\r
+      USB_ERROR (("UsbParseInterfaceDesc: failed to create endpoint(index %d)\n", Index));\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Setting->Endpoints[Index]  = Ep;\r
+    Offset                    += Used;\r
+  }\r
+\r
+\r
+ON_EXIT:\r
+  *Consumed = Offset;\r
+  return Setting;\r
+\r
+ON_ERROR:\r
+  UsbFreeInterfaceDesc (Setting);\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Parse the configuration descriptor and its interfaces.\r
+\r
+  @param  DescBuf               The buffer of raw descriptor\r
+  @param  Len                   The lenght of the raw descriptor buffer\r
+\r
+  @return The created configuration descriptor\r
+\r
+**/\r
+STATIC\r
+USB_CONFIG_DESC *\r
+UsbParseConfigDesc (\r
+  IN UINT8                *DescBuf,\r
+  IN INTN                 Len\r
+  )\r
+{\r
+  USB_CONFIG_DESC         *Config;\r
+  USB_INTERFACE_SETTING   *Setting;\r
+  USB_INTERFACE_DESC      *Interface;\r
+  UINTN                   Index;\r
+  UINTN                   NumIf;\r
+  INTN                    Consumed;\r
+\r
+  ASSERT (DescBuf != NULL);\r
+\r
+  Config = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_CONFIG, &Consumed);\r
+\r
+  if (Config == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Initialize an array of setting for the configuration's interfaces.\r
+  //\r
+  NumIf               = Config->Desc.NumInterfaces;\r
+  Config->Interfaces  = AllocateZeroPool (sizeof (USB_INTERFACE_DESC *) * NumIf);\r
+\r
+  if (Config->Interfaces == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  USB_DEBUG (("UsbParseConfigDesc: config %d has %d interfaces\n",\r
+                Config->Desc.ConfigurationValue, NumIf));\r
+\r
+  for (Index = 0; Index < NumIf; Index++) {\r
+    Interface = AllocateZeroPool (sizeof (USB_INTERFACE_DESC));\r
+\r
+    if (Interface == NULL) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Config->Interfaces[Index] = Interface;\r
+  }\r
+\r
+  //\r
+  // If a configuration has several interfaces, these interfaces are\r
+  // numbered from zero to n. If a interface has several settings,\r
+  // these settings are also number from zero to m. The interface\r
+  // setting must be organized as |interface 0, setting 0|interface 0\r
+  // setting 1|interface 1, setting 0|interface 2, setting 0|. Check\r
+  // USB2.0 spec, page 267.\r
+  //\r
+  DescBuf += Consumed;\r
+  Len     -= Consumed;\r
+\r
+  while (Len > 0) {\r
+    Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed);\r
+\r
+    if ((Setting == NULL)) {\r
+      USB_ERROR (("UsbParseConfigDesc: failed to parse interface setting\n"));\r
+      goto ON_ERROR;\r
+\r
+    } else if (Setting->Desc.InterfaceNumber >= NumIf) {\r
+      USB_ERROR (("UsbParseConfigDesc: mal-formated interface descriptor\n"));\r
+\r
+      UsbFreeInterfaceDesc (Setting);\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    //\r
+    // Insert the descriptor to the corresponding set.\r
+    //\r
+    Interface = Config->Interfaces[Setting->Desc.InterfaceNumber];\r
+\r
+    if (Interface->NumOfSetting >= USB_MAX_INTERFACE_SETTING) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Interface->Settings[Interface->NumOfSetting] = Setting;\r
+    Interface->NumOfSetting++;\r
+\r
+    DescBuf += Consumed;\r
+    Len     -= Consumed;\r
+  }\r
+\r
+  return Config;\r
+\r
+ON_ERROR:\r
+  UsbFreeConfigDesc (Config);\r
+  return NULL;\r
+}\r
+\r
+\r
+\r
+/**\r
+  USB standard control transfer support routine. This\r
+  function is used by USB device. It is possible that\r
+  the device's interfaces are still waiting to be\r
+  enumerated.\r
+\r
+  @param  UsbDev                The usb device\r
+  @param  Direction             The direction of data transfer\r
+  @param  Type                  Standard / class specific / vendor specific\r
+  @param  Target                The receiving target\r
+  @param  Request               Which request\r
+  @param  Value                 The wValue parameter of the request\r
+  @param  Index                 The wIndex parameter of the request\r
+  @param  Buf                   The buffer to receive data into / transmit from\r
+  @param  Length                The length of the buffer\r
+\r
+  @retval EFI_SUCCESS           The control request is executed\r
+  @retval EFI_DEVICE_ERROR      Failed to execute the control transfer\r
+\r
+**/\r
+EFI_STATUS\r
+UsbCtrlRequest (\r
+  IN USB_DEVICE             *UsbDev,\r
+  IN EFI_USB_DATA_DIRECTION Direction,\r
+  IN UINTN                  Type,\r
+  IN UINTN                  Target,\r
+  IN UINTN                  Request,\r
+  IN UINT16                 Value,\r
+  IN UINT16                 Index,\r
+  IN OUT VOID               *Buf,\r
+  IN UINTN                  Length\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+  EFI_STATUS              Status;\r
+  UINT32                  Result;\r
+  UINTN                   Len;\r
+\r
+  ASSERT ((UsbDev != NULL) && (UsbDev->Bus != NULL));\r
+\r
+  DevReq.RequestType  = USB_REQUEST_TYPE (Direction, Type, Target);\r
+  DevReq.Request      = (UINT8) Request;\r
+  DevReq.Value        = Value;\r
+  DevReq.Index        = Index;\r
+  DevReq.Length       = (UINT16) Length;\r
+\r
+  Len                 = Length;\r
+  Status = UsbHcControlTransfer (\r
+             UsbDev->Bus,\r
+             UsbDev->Address,\r
+             UsbDev->Speed,\r
+             UsbDev->MaxPacket0,\r
+             &DevReq,\r
+             Direction,\r
+             Buf,\r
+             &Len,\r
+             50 * USB_STALL_1_MS,\r
+             &UsbDev->Translator,\r
+             &Result\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Get the standard descriptors.\r
+\r
+  @param  UsbDev                The USB device to read descriptor from\r
+  @param  DescType              The type of descriptor to read\r
+  @param  DescIndex             The index of descriptor to read\r
+  @param  LangId                Language ID, only used to get string, otherwise set\r
+                                it to 0\r
+  @param  Buf                   The buffer to hold the descriptor read\r
+  @param  Length                The length of the buffer\r
+\r
+  @retval EFI_SUCCESS           The descriptor is read OK\r
+  @retval Others                Failed to retrieve the descriptor\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbCtrlGetDesc (\r
+  IN  USB_DEVICE          *UsbDev,\r
+  IN  UINTN               DescType,\r
+  IN  UINTN               DescIndex,\r
+  IN  UINT16              LangId,\r
+  OUT VOID                *Buf,\r
+  IN  UINTN               Length\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             UsbDev,\r
+             EfiUsbDataIn,\r
+             USB_REQ_TYPE_STANDARD,\r
+             USB_TARGET_DEVICE,\r
+             USB_REQ_GET_DESCRIPTOR,\r
+             (UINT16) ((DescType << 8) | DescIndex),\r
+             LangId,\r
+             Buf,\r
+             Length\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Return the max packet size for endpoint zero. This function\r
+  is the first function called to get descriptors during bus\r
+  enumeration.\r
+\r
+  @param  UsbDev                The usb device\r
+\r
+  @retval EFI_SUCCESS           The max packet size of endpoint zero is retrieved\r
+  @retval EFI_DEVICE_ERROR      Failed to retrieve it\r
+\r
+**/\r
+EFI_STATUS\r
+UsbGetMaxPacketSize0 (\r
+  IN USB_DEVICE           *UsbDev\r
+  )\r
+{\r
+  EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
+  EFI_STATUS                Status;\r
+  UINTN                     Index;\r
+\r
+\r
+  //\r
+  // Get the first 8 bytes of the device descriptor which contains\r
+  // max packet size for endpoint 0, which is at least 8.\r
+  //\r
+  UsbDev->MaxPacket0 = 8;\r
+\r
+  for (Index = 0; Index < 3; Index++) {\r
+    Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_DEVICE, 0, 0, &DevDesc, 8);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      UsbDev->MaxPacket0 = DevDesc.MaxPacketSize0;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    gBS->Stall (100 * USB_STALL_1_MS);\r
+  }\r
+\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Get the device descriptor for the device.\r
+\r
+  @param  UsbDev                The Usb device to retrieve descriptor from\r
+\r
+  @retval EFI_SUCCESS           The device descriptor is returned\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbGetDevDesc (\r
+  IN USB_DEVICE           *UsbDev\r
+  )\r
+{\r
+  USB_DEVICE_DESC         *DevDesc;\r
+  EFI_STATUS              Status;\r
+\r
+  DevDesc = AllocateZeroPool (sizeof (USB_DEVICE_DESC));\r
+\r
+  if (DevDesc == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status  = UsbCtrlGetDesc (\r
+              UsbDev,\r
+              USB_DESC_TYPE_DEVICE,\r
+              0,\r
+              0,\r
+              DevDesc,\r
+              sizeof (EFI_USB_DEVICE_DESCRIPTOR)\r
+              );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (DevDesc);\r
+  } else {\r
+    UsbDev->DevDesc = DevDesc;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Retrieve the indexed string for the language. It requires two\r
+  steps to get a string, first to get the string's length. Then\r
+  the string itself.\r
+\r
+  @param  UsbDev                The usb device\r
+  @param  Index                 The index the string to retrieve\r
+  @param  LangId                Language ID\r
+\r
+  @return The created string descriptor or NULL\r
+\r
+**/\r
+EFI_USB_STRING_DESCRIPTOR *\r
+UsbGetOneString (\r
+  IN     USB_DEVICE       *UsbDev,\r
+  IN     UINT8            Index,\r
+  IN     UINT16           LangId\r
+  )\r
+{\r
+  EFI_USB_STRING_DESCRIPTOR Desc;\r
+  EFI_STATUS                Status;\r
+  UINT8                     *Buf;\r
+\r
+  //\r
+  // First get two bytes which contains the string length.\r
+  //\r
+  Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Buf = AllocateZeroPool (Desc.Length);\r
+\r
+  if (Buf == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = UsbCtrlGetDesc (\r
+             UsbDev,\r
+             USB_DESC_TYPE_STRING,\r
+             Index,\r
+             LangId,\r
+             Buf,\r
+             Desc.Length\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePool (Buf);\r
+    return NULL;\r
+  }\r
+\r
+  return (EFI_USB_STRING_DESCRIPTOR *) Buf;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Build the language ID table for string descriptors\r
+\r
+  @param  UsbDev                The Usb device\r
+\r
+  @retval EFI_UNSUPPORTED       This device doesn't support string table\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbBuildLangTable (\r
+  IN USB_DEVICE           *UsbDev\r
+  )\r
+{\r
+  EFI_USB_STRING_DESCRIPTOR *Desc;\r
+  EFI_STATUS                Status;\r
+  UINTN                     Index;\r
+  UINTN                     Max;\r
+  UINT16                    *Point;\r
+\r
+  //\r
+  // The string of language ID zero returns the supported languages\r
+  //\r
+  Desc = UsbGetOneString (UsbDev, 0, 0);\r
+\r
+  if (Desc == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (Desc->Length < 4) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  Max   = (Desc->Length - 2) / 2;\r
+  Max   = (Max < USB_MAX_LANG_ID ? Max : USB_MAX_LANG_ID);\r
+\r
+  Point = Desc->String;\r
+  for (Index = 0; Index < Max; Index++) {\r
+    UsbDev->LangId[Index] = *Point;\r
+    Point++;\r
+  }\r
+\r
+  UsbDev->TotalLangId = (UINT16)Max;\r
+\r
+ON_EXIT:\r
+  gBS->FreePool (Desc);\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Retrieve the indexed configure for the device. USB device\r
+  returns the configuration togetther with the interfaces for\r
+  this configuration. Configuration descriptor is also of\r
+  variable length\r
+\r
+  @param  UsbDev                The Usb interface\r
+  @param  Index                 The index of the configuration\r
+\r
+  @return The created configuration descriptor\r
+\r
+**/\r
+STATIC\r
+EFI_USB_CONFIG_DESCRIPTOR *\r
+UsbGetOneConfig (\r
+  IN USB_DEVICE           *UsbDev,\r
+  IN UINT8                Index\r
+  )\r
+{\r
+  EFI_USB_CONFIG_DESCRIPTOR Desc;\r
+  EFI_STATUS                Status;\r
+  VOID                      *Buf;\r
+\r
+  //\r
+  // First get four bytes which contains the total length\r
+  // for this configuration.\r
+  //\r
+  Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, &Desc, 8);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbGetOneConfig: failed to get descript length(%d) %r\n",\r
+                Status, Desc.TotalLength));\r
+\r
+    return NULL;\r
+  }\r
+\r
+  USB_DEBUG (("UsbGetOneConfig: total length is %d\n", Desc.TotalLength));\r
+\r
+  Buf = AllocateZeroPool (Desc.TotalLength);\r
+\r
+  if (Buf == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_CONFIG, Index, 0, Buf, Desc.TotalLength);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbGetOneConfig: failed to get full descript %r\n", Status));\r
+\r
+    gBS->FreePool (Buf);\r
+    return NULL;\r
+  }\r
+\r
+  return Buf;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Build the whole array of descriptors. This function must\r
+  be called after UsbGetMaxPacketSize0 returns the max packet\r
+  size correctly for endpoint 0.\r
+\r
+  @param  UsbDev                The Usb device\r
+\r
+  @retval EFI_SUCCESS           The descriptor table is build\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the descriptor\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBuildDescTable (\r
+  IN USB_DEVICE           *UsbDev\r
+  )\r
+{\r
+  EFI_USB_CONFIG_DESCRIPTOR *Config;\r
+  USB_DEVICE_DESC           *DevDesc;\r
+  USB_CONFIG_DESC           *ConfigDesc;\r
+  UINT8                     NumConfig;\r
+  EFI_STATUS                Status;\r
+  UINT8                     Index;\r
+\r
+  //\r
+  // Get the device descriptor, then allocate the configure\r
+  // descriptor pointer array to hold configurations.\r
+  //\r
+  Status = UsbGetDevDesc (UsbDev);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbBuildDescTable: failed to get device descriptor - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  DevDesc          = UsbDev->DevDesc;\r
+  NumConfig        = DevDesc->Desc.NumConfigurations;\r
+  DevDesc->Configs = AllocateZeroPool (NumConfig * sizeof (USB_CONFIG_DESC *));\r
+\r
+  if (DevDesc->Configs == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  USB_DEBUG (("UsbBuildDescTable: device has %d configures\n", NumConfig));\r
+\r
+  //\r
+  // Read each configurations, then parse them\r
+  //\r
+  for (Index = 0; Index < NumConfig; Index++) {\r
+    Config = UsbGetOneConfig (UsbDev, Index);\r
+\r
+    if (Config == NULL) {\r
+      USB_ERROR (("UsbBuildDescTable: failed to get configure (index %d)\n", Index));\r
+\r
+      //\r
+      // If we can get the default descriptor, it is likely that the\r
+      // device is still operational.\r
+      //\r
+      if (Index == 0) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+\r
+      break;\r
+    }\r
+\r
+    ConfigDesc = UsbParseConfigDesc ((UINT8 *) Config, Config->TotalLength);\r
+\r
+    gBS->FreePool (Config);\r
+\r
+    if (ConfigDesc == NULL) {\r
+      USB_ERROR (("UsbBuildDescTable: failed to parse configure (index %d)\n", Index));\r
+\r
+      //\r
+      // If we can get the default descriptor, it is likely that the\r
+      // device is still operational.\r
+      //\r
+      if (Index == 0) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+\r
+      break;\r
+    }\r
+\r
+    DevDesc->Configs[Index] = ConfigDesc;\r
+  }\r
+\r
+  //\r
+  // Don't return error even this function failed because\r
+  // it is possible for the device to not support strings.\r
+  //\r
+  Status = UsbBuildLangTable (UsbDev);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_DEBUG (("UsbBuildDescTable: get language ID table %r\n", Status));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Set the device's address.\r
+\r
+  @param  UsbDev                The device to set address to\r
+  @param  Address               The address to set\r
+\r
+  @retval EFI_SUCCESS           The device is set to the address\r
+  @retval Others                Failed to set the device address\r
+\r
+**/\r
+EFI_STATUS\r
+UsbSetAddress (\r
+  IN USB_DEVICE           *UsbDev,\r
+  IN UINT8                Address\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             UsbDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_STANDARD,\r
+             USB_TARGET_DEVICE,\r
+             USB_REQ_SET_ADDRESS,\r
+             Address,\r
+             0,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set the device's configuration. This function changes\r
+  the device's internal state. UsbSelectConfig changes\r
+  the Usb bus's internal state.\r
+\r
+  @param  UsbDev                The USB device to set configure to\r
+  @param  ConfigIndex           The configure index to set\r
+\r
+  @retval EFI_SUCCESS           The device is configured now\r
+  @retval Others                Failed to set the device configure\r
+\r
+**/\r
+EFI_STATUS\r
+UsbSetConfig (\r
+  IN USB_DEVICE           *UsbDev,\r
+  IN UINT8                ConfigIndex\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             UsbDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_STANDARD,\r
+             USB_TARGET_DEVICE,\r
+             USB_REQ_SET_CONFIG,\r
+             ConfigIndex,\r
+             0,\r
+             NULL,\r
+             0\r
+            );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Usb UsbIo interface to clear the feature. This is should\r
+  only be used by HUB which is considered a device driver\r
+  on top of the UsbIo interface.\r
+\r
+  @param  UsbIo                 The UsbIo interface\r
+  @param  Target                The target of the transfer: endpoint/device\r
+  @param  Feature               The feature to clear\r
+  @param  Index                 The wIndex parameter\r
+\r
+  @retval EFI_SUCCESS           The device feature is cleared\r
+  @retval Others                Failed to clear the feature\r
+\r
+**/\r
+EFI_STATUS\r
+UsbIoClearFeature (\r
+  IN  EFI_USB_IO_PROTOCOL *UsbIo,\r
+  IN  UINTN               Target,\r
+  IN  UINT16              Feature,\r
+  IN  UINT16              Index\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST  DevReq;\r
+  UINT32                  UsbResult;\r
+  EFI_STATUS              Status;\r
+\r
+  DevReq.RequestType  = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, Target);\r
+  DevReq.Request      = USB_REQ_CLEAR_FEATURE;\r
+  DevReq.Value        = Feature;\r
+  DevReq.Index        = Index;\r
+  DevReq.Length       = 0;\r
+\r
+  Status = UsbIo->UsbControlTransfer (\r
+                    UsbIo,\r
+                    &DevReq,\r
+                    EfiUsbNoData,\r
+                    10 * USB_STALL_1_MS,\r
+                    NULL,\r
+                    0,\r
+                    &UsbResult\r
+                    );\r
+\r
+  return Status;\r
+}\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h
new file mode 100644 (file)
index 0000000..bdecfcf
--- /dev/null
@@ -0,0 +1,146 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbDesc.h\r
+\r
+  Abstract:\r
+\r
+    Manage Usb Descriptor List\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _USB_DESCRIPTOR_H_\r
+#define _USB_DESCRIPTOR_H_\r
+\r
+enum {\r
+  USB_MAX_INTERFACE_SETTING  = 8,\r
+};\r
+\r
+//\r
+// The RequestType in EFI_USB_DEVICE_REQUEST is composed of\r
+// three fields: One bit direction, 2 bit type, and 5 bit\r
+// target.\r
+//\r
+#define USB_REQUEST_TYPE(Dir, Type, Target) \\r
+          ((UINT8)((((Dir) == EfiUsbDataIn ? 0x01 : 0) << 7) | (Type) | (Target)))\r
+\r
+//\r
+// A common header for usb standard descriptor.\r
+// Each stand descriptor has a length and type.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8                   Len;\r
+  UINT8                   Type;\r
+} USB_DESC_HEAD;\r
+#pragma pack()\r
+\r
+\r
+//\r
+// Each USB device has a device descriptor. Each device may\r
+// have several configures. Each configure contains several\r
+// interfaces. Each interface may have several settings. Each\r
+// setting has several endpoints.\r
+//\r
+// EFI_USB_..._DESCRIPTOR must be the first member of the\r
+// structure.\r
+//\r
+typedef struct {\r
+  EFI_USB_ENDPOINT_DESCRIPTOR   Desc;\r
+  UINT8                         Toggle;\r
+} USB_ENDPOINT_DESC;\r
+\r
+typedef struct {\r
+  EFI_USB_INTERFACE_DESCRIPTOR  Desc;\r
+  USB_ENDPOINT_DESC             **Endpoints;\r
+} USB_INTERFACE_SETTING;\r
+\r
+//\r
+// An interface may have several settings. Use a\r
+// fixed max number of settings to simplify code.\r
+// It should sufice in most environments.\r
+//\r
+typedef struct {\r
+  USB_INTERFACE_SETTING*        Settings[USB_MAX_INTERFACE_SETTING];\r
+  UINTN                         NumOfSetting;\r
+  UINT8                         ActiveIndex;  // Index of active setting\r
+} USB_INTERFACE_DESC;\r
+\r
+typedef struct {\r
+  EFI_USB_CONFIG_DESCRIPTOR     Desc;\r
+  USB_INTERFACE_DESC            **Interfaces;\r
+} USB_CONFIG_DESC;\r
+\r
+typedef struct {\r
+  EFI_USB_DEVICE_DESCRIPTOR     Desc;\r
+  USB_CONFIG_DESC               **Configs;\r
+} USB_DEVICE_DESC;\r
+\r
+EFI_STATUS\r
+UsbCtrlRequest (\r
+  IN USB_DEVICE             *UsbDev,\r
+  IN EFI_USB_DATA_DIRECTION Direction,\r
+  IN UINTN                  Type,\r
+  IN UINTN                  Target,\r
+  IN UINTN                  Request,\r
+  IN UINT16                 Value,\r
+  IN UINT16                 Index,\r
+  IN OUT VOID               *Buf,\r
+  IN UINTN                  Length\r
+  );\r
+\r
+EFI_STATUS\r
+UsbGetMaxPacketSize0 (\r
+  IN USB_DEVICE           *UsbDev\r
+  );\r
+\r
+VOID\r
+UsbFreeDevDesc (\r
+  IN USB_DEVICE_DESC      *DevDesc\r
+  );\r
+\r
+EFI_USB_STRING_DESCRIPTOR*\r
+UsbGetOneString (\r
+  IN     USB_DEVICE       *UsbDev,\r
+  IN     UINT8            StringIndex,\r
+  IN     UINT16           LangId\r
+  );\r
+\r
+EFI_STATUS\r
+UsbBuildDescTable (\r
+  IN USB_DEVICE           *UsbDev\r
+  );\r
+\r
+EFI_STATUS\r
+UsbSetAddress (\r
+  IN USB_DEVICE           *UsbDev,\r
+  IN UINT8                Address\r
+  );\r
+\r
+EFI_STATUS\r
+UsbSetConfig (\r
+  IN USB_DEVICE           *UsbDev,\r
+  IN UINT8                ConfigIndex\r
+  );\r
+\r
+EFI_STATUS\r
+UsbIoClearFeature (\r
+  IN  EFI_USB_IO_PROTOCOL *UsbIo,\r
+  IN  UINTN               Target,\r
+  IN  UINT16              Feature,\r
+  IN  UINT16              Index\r
+  );\r
+#endif\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
new file mode 100644 (file)
index 0000000..fc0007d
--- /dev/null
@@ -0,0 +1,991 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbEnumer.c\r
+\r
+  Abstract:\r
+\r
+    Usb bus enumeration support\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#include "UsbBus.h"\r
+\r
+\r
+/**\r
+  Return the endpoint descriptor in this interface\r
+\r
+  @param  UsbIf                 The interface to search in\r
+  @param  EpAddr                The address of the endpoint to return\r
+\r
+  @return The endpoint descriptor or NULL\r
+\r
+**/\r
+USB_ENDPOINT_DESC *\r
+UsbGetEndpointDesc (\r
+  IN USB_INTERFACE        *UsbIf,\r
+  IN UINT8                EpAddr\r
+  )\r
+{\r
+  USB_ENDPOINT_DESC       *EpDesc;\r
+  UINTN                   Index;\r
+\r
+  for (Index = 0; Index < UsbIf->IfSetting->Desc.NumEndpoints; Index++) {\r
+    EpDesc = UsbIf->IfSetting->Endpoints[Index];\r
+\r
+    if (EpDesc->Desc.EndpointAddress == EpAddr) {\r
+      return EpDesc;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Free the resource used by USB interface\r
+\r
+  @param  UsbIf                 The USB interface to free\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbFreeInterface (\r
+  IN USB_INTERFACE        *UsbIf\r
+  )\r
+{\r
+  UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);\r
+\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         UsbIf->Handle,\r
+         &gEfiDevicePathProtocolGuid,\r
+         UsbIf->DevicePath,\r
+         &gEfiUsbIoProtocolGuid,\r
+         &UsbIf->UsbIo,\r
+         NULL\r
+         );\r
+\r
+  if (UsbIf->DevicePath != NULL) {\r
+    gBS->FreePool (UsbIf->DevicePath);\r
+  }\r
+\r
+  gBS->FreePool (UsbIf);\r
+}\r
+\r
+\r
+/**\r
+  Create an interface for the descriptor IfDesc. Each\r
+  device's configuration can have several interfaces.\r
+\r
+  @param  Device                The device has the interface descriptor\r
+  @param  IfDesc                The interface descriptor\r
+\r
+  @return The created USB interface for the descriptor, or NULL.\r
+\r
+**/\r
+STATIC\r
+USB_INTERFACE *\r
+UsbCreateInterface (\r
+  IN USB_DEVICE           *Device,\r
+  IN USB_INTERFACE_DESC   *IfDesc\r
+  )\r
+{\r
+  USB_DEVICE_PATH         UsbNode;\r
+  USB_INTERFACE           *UsbIf;\r
+  USB_INTERFACE           *HubIf;\r
+  EFI_STATUS              Status;\r
+\r
+  UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
+\r
+  if (UsbIf == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  UsbIf->Signature  = USB_INTERFACE_SIGNATURE;\r
+  UsbIf->Device     = Device;\r
+  UsbIf->IfDesc     = IfDesc;\r
+  UsbIf->IfSetting  = IfDesc->Settings[IfDesc->ActiveIndex];\r
+  UsbIf->UsbIo      = mUsbIoProtocol;\r
+\r
+  //\r
+  // Install protocols for USBIO and device path\r
+  //\r
+  UsbNode.Header.Type       = MESSAGING_DEVICE_PATH;\r
+  UsbNode.Header.SubType    = MSG_USB_DP;\r
+  UsbNode.ParentPortNumber  = Device->ParentPort;\r
+  UsbNode.InterfaceNumber   = UsbIf->IfSetting->Desc.InterfaceNumber;\r
+\r
+  SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));\r
+\r
+  HubIf = Device->ParentIf;\r
+  ASSERT (HubIf != NULL);\r
+\r
+  UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);\r
+\r
+  if (UsbIf->DevicePath == NULL) {\r
+    USB_ERROR (("UsbCreateInterface: failed to create device path\n"));\r
+\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &UsbIf->Handle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  UsbIf->DevicePath,\r
+                  &gEfiUsbIoProtocolGuid,\r
+                  &UsbIf->UsbIo,\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbCreateInterface: failed to install UsbIo - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Open USB Host Controller Protocol by Child\r
+  //\r
+  Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           &UsbIf->Handle,\r
+           &gEfiDevicePathProtocolGuid,\r
+           UsbIf->DevicePath,\r
+           &gEfiUsbIoProtocolGuid,\r
+           &UsbIf->UsbIo,\r
+           NULL\r
+           );\r
+\r
+    USB_ERROR (("UsbCreateInterface: failed to open host for child - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return UsbIf;\r
+\r
+ON_ERROR:\r
+  if (UsbIf->DevicePath) {\r
+    gBS->FreePool (UsbIf->DevicePath);\r
+  }\r
+\r
+  gBS->FreePool (UsbIf);\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Free the resource used by this USB device\r
+\r
+  @param  Device                The USB device to free\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbFreeDevice (\r
+  IN USB_DEVICE           *Device\r
+  )\r
+{\r
+  if (Device->DevDesc != NULL) {\r
+    UsbFreeDevDesc (Device->DevDesc);\r
+  }\r
+\r
+  gBS->FreePool (Device);\r
+}\r
+\r
+\r
+/**\r
+  Create a device which is on the parent's ParentPort port.\r
+\r
+  @param  ParentIf              The parent HUB interface\r
+  @param  ParentPort            The port on the HUB this device is connected to\r
+\r
+  @return Created USB device\r
+\r
+**/\r
+STATIC\r
+USB_DEVICE *\r
+UsbCreateDevice (\r
+  IN USB_INTERFACE        *ParentIf,\r
+  IN UINT8                ParentPort\r
+  )\r
+{\r
+  USB_DEVICE              *Device;\r
+\r
+  ASSERT (ParentIf != NULL);\r
+\r
+  Device = AllocateZeroPool (sizeof (USB_DEVICE));\r
+\r
+  if (Device == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Device->Bus         = ParentIf->Device->Bus;\r
+  Device->MaxPacket0  = 8;\r
+  Device->ParentAddr  = ParentIf->Device->Address;\r
+  Device->ParentIf    = ParentIf;\r
+  Device->ParentPort  = ParentPort;\r
+  return Device;\r
+}\r
+\r
+\r
+/**\r
+  Connect the USB interface with its driver. EFI USB bus will\r
+  create a USB interface for each seperate interface descriptor.\r
+\r
+  @param  UsbIf                 The interface to connect driver to\r
+\r
+  @return EFI_SUCCESS : Interface is managed by some driver\r
+  @return Others      : Failed to locate a driver for this interface\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbConnectDriver (\r
+  IN USB_INTERFACE        *UsbIf\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Hub is maintained by the USB bus driver. Otherwise try to\r
+  // connect drivers with this interface\r
+  //\r
+  if (UsbIsHubInterface (UsbIf)) {\r
+    USB_DEBUG (("UsbConnectDriver: found a hub device\n"));\r
+    Status = mUsbHubApi.Init (UsbIf);\r
+\r
+  } else {\r
+    //\r
+    // This function is called in both UsbIoControlTransfer and\r
+    // the timer callback in hub enumeration. So, at least it is\r
+    // called at TPL_CALLBACK. Some driver sitting on USB has\r
+    // twisted TPL used. It should be no problem for us to connect\r
+    // or disconnect at CALLBACK.\r
+    //\r
+    OldTpl            = UsbGetCurrentTpl ();\r
+    USB_DEBUG (("UsbConnectDriver: TPL before connect is %d\n", OldTpl));\r
+\r
+    gBS->RestoreTPL (TPL_CALLBACK);\r
+\r
+    Status            = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);\r
+    UsbIf->IsManaged  = (BOOLEAN)!EFI_ERROR (Status);\r
+\r
+    USB_DEBUG (("UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl()));\r
+    ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
+\r
+    gBS->RaiseTPL (OldTpl);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Select an alternate setting for the interface.\r
+  Each interface can have several mutually exclusive\r
+  settings. Only one setting is active. It will\r
+  also reset its endpoints' toggle to zero.\r
+\r
+  @param  IfDesc                The interface descriptor to set\r
+  @param  Alternate             The alternate setting number to locate\r
+\r
+  @retval EFI_NOT_FOUND         There is no setting with this alternate index\r
+  @retval EFI_SUCCESS           The interface is set to Alternate setting.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbSelectSetting (\r
+  IN USB_INTERFACE_DESC   *IfDesc,\r
+  IN UINT8                Alternate\r
+  )\r
+{\r
+  USB_INTERFACE_SETTING   *Setting;\r
+  UINT8                   Index;\r
+\r
+  //\r
+  // Locate the active alternate setting\r
+  //\r
+  Setting = NULL;\r
+\r
+  for (Index = 0; Index < IfDesc->NumOfSetting; Index++) {\r
+    Setting = IfDesc->Settings[Index];\r
+\r
+    if (Setting->Desc.AlternateSetting == Alternate) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == IfDesc->NumOfSetting) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  IfDesc->ActiveIndex = Index;\r
+\r
+  USB_DEBUG (("UsbSelectSetting: setting %d selected for interface %d\n",\r
+              Alternate, Setting->Desc.InterfaceNumber));\r
+\r
+  //\r
+  // Reset the endpoint toggle to zero\r
+  //\r
+  for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {\r
+    Setting->Endpoints[Index]->Toggle = 0;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Select a new configuration for the device. Each\r
+  device may support several configurations.\r
+\r
+  @param  Device                The device to select configuration\r
+  @param  ConfigValue           The index of the configuration ( != 0)\r
+\r
+  @retval EFI_NOT_FOUND         There is no configuration with the index\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource\r
+  @retval EFI_SUCCESS           The configuration is selected.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbSelectConfig (\r
+  IN USB_DEVICE           *Device,\r
+  IN UINT8                ConfigValue\r
+  )\r
+{\r
+  USB_DEVICE_DESC         *DevDesc;\r
+  USB_CONFIG_DESC         *ConfigDesc;\r
+  USB_INTERFACE_DESC      *IfDesc;\r
+  USB_INTERFACE           *UsbIf;\r
+  EFI_STATUS              Status;\r
+  UINT8                   Index;\r
+\r
+  //\r
+  // Locate the active config, then set the device's pointer\r
+  //\r
+  DevDesc     = Device->DevDesc;\r
+  ConfigDesc  = NULL;\r
+\r
+  for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) {\r
+    ConfigDesc = DevDesc->Configs[Index];\r
+\r
+    if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == DevDesc->Desc.NumConfigurations) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Device->ActiveConfig = ConfigDesc;\r
+\r
+  USB_DEBUG (("UsbSelectConfig: config %d selected for device %d\n",\r
+              ConfigValue, Device->Address));\r
+\r
+  //\r
+  // Create interfaces for each USB interface descriptor.\r
+  //\r
+  for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) {\r
+    //\r
+    // First select the default interface setting, and reset\r
+    // the endpoint toggles to zero for its endpoints.\r
+    //\r
+    IfDesc = ConfigDesc->Interfaces[Index];\r
+    UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting);\r
+\r
+    //\r
+    // Create a USB_INTERFACE and install USB_IO and other protocols\r
+    //\r
+    UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]);\r
+\r
+    if (UsbIf == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Device->Interfaces[Index] = UsbIf;\r
+\r
+    //\r
+    // Connect the device to drivers, if it failed, ignore\r
+    // the error. Don't let the unsupported interfaces to block\r
+    // the supported interfaces.\r
+    //\r
+    Status = UsbConnectDriver (UsbIf);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      USB_ERROR (("UsbSelectConfig: failed to connect driver %r, ignored\n", Status));\r
+    }\r
+  }\r
+\r
+  Device->NumOfInterface = Index;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Disconnect the USB interface with its driver.\r
+\r
+  @param  UsbIf                 The interface to disconnect driver from\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbDisconnectDriver (\r
+  IN USB_INTERFACE        *UsbIf\r
+  )\r
+{\r
+  EFI_TPL                 OldTpl;\r
+\r
+  //\r
+  // Release the hub if it's a hub controller, otherwise\r
+  // disconnect the driver if it is managed by other drivers.\r
+  //\r
+  if (UsbIf->IsHub) {\r
+    UsbIf->HubApi->Release (UsbIf);\r
+\r
+  } else if (UsbIf->IsManaged) {\r
+    //\r
+    // This function is called in both UsbIoControlTransfer and\r
+    // the timer callback in hub enumeration. So, at least it is\r
+    // called at TPL_CALLBACK. Some driver sitting on USB has\r
+    // twisted TPL used. It should be no problem for us to connect\r
+    // or disconnect at CALLBACK.\r
+    //\r
+    OldTpl           = UsbGetCurrentTpl ();\r
+    USB_DEBUG (("UsbDisconnectDriver: old TPL is %d\n", OldTpl));\r
+\r
+    gBS->RestoreTPL (TPL_CALLBACK);\r
+\r
+    gBS->DisconnectController (UsbIf->Handle, NULL, NULL);\r
+    UsbIf->IsManaged = FALSE;\r
+\r
+    USB_DEBUG (("UsbDisconnectDriver: TPL after disconnect is %d\n", UsbGetCurrentTpl()));\r
+    ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);\r
+\r
+    gBS->RaiseTPL (OldTpl);\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Remove the current device configuration\r
+\r
+  @param  Device                The USB device to remove configuration from\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UsbRemoveConfig (\r
+  IN USB_DEVICE           *Device\r
+  )\r
+{\r
+  USB_INTERFACE           *UsbIf;\r
+  UINTN                   Index;\r
+\r
+  //\r
+  // Remove each interface of the device\r
+  //\r
+  for (Index = 0; Index < Device->NumOfInterface; Index++) {\r
+    UsbIf = Device->Interfaces[Index];\r
+\r
+    if (UsbIf == NULL) {\r
+      continue;\r
+    }\r
+\r
+    UsbDisconnectDriver (UsbIf);\r
+    UsbFreeInterface (UsbIf);\r
+    Device->Interfaces[Index] = NULL;\r
+  }\r
+\r
+  Device->ActiveConfig    = NULL;\r
+  Device->NumOfInterface  = 0;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Remove the device and all its children from the bus.\r
+\r
+  @param  Device                The device to remove\r
+\r
+  @retval EFI_SUCCESS           The device is removed\r
+\r
+**/\r
+EFI_STATUS\r
+UsbRemoveDevice (\r
+  IN USB_DEVICE           *Device\r
+  )\r
+{\r
+  USB_BUS                 *Bus;\r
+  USB_DEVICE              *Child;\r
+  EFI_STATUS              Status;\r
+  UINT8                   Index;\r
+\r
+  Bus = Device->Bus;\r
+\r
+  //\r
+  // Remove all the devices on its downstream ports. Search from devices[1].\r
+  // Devices[0] is the root hub.\r
+  //\r
+  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+    Child = Bus->Devices[Index];\r
+\r
+    if ((Child == NULL) || (Child->ParentAddr != Device->Address)) {\r
+      continue;\r
+    }\r
+\r
+    Status = UsbRemoveDevice (Child);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      USB_ERROR (("UsbRemoveDevice: failed to remove child, ignore error\n"));\r
+      Bus->Devices[Index] = NULL;\r
+    }\r
+  }\r
+\r
+  UsbRemoveConfig (Device);\r
+\r
+  USB_DEBUG (("UsbRemoveDevice: device %d removed\n", Device->Address));\r
+\r
+  Bus->Devices[Device->Address] = NULL;\r
+  UsbFreeDevice (Device);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Find the child device on the hub's port\r
+\r
+  @param  HubIf                 The hub interface\r
+  @param  Port                  The port of the hub this child is connected to\r
+\r
+  @return The device on the hub's port, or NULL if there is none\r
+\r
+**/\r
+STATIC\r
+USB_DEVICE *\r
+UsbFindChild (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port\r
+  )\r
+{\r
+  USB_DEVICE              *Device;\r
+  USB_BUS                 *Bus;\r
+  UINTN                   Index;\r
+\r
+  Bus = HubIf->Device->Bus;\r
+\r
+  //\r
+  // Start checking from device 1, device 0 is the root hub\r
+  //\r
+  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+    Device = Bus->Devices[Index];\r
+\r
+    if ((Device != NULL) && (Device->ParentAddr == HubIf->Device->Address) &&\r
+        (Device->ParentPort == Port)) {\r
+\r
+      return Device;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Enumerate and configure the new device on the port of this HUB interface.\r
+\r
+  @param  HubIf                 The HUB that has the device connected\r
+  @param  Port                  The port index of the hub (started with zero)\r
+\r
+  @retval EFI_SUCCESS           The device is enumerated (added or removed)\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device\r
+  @retval Others                Failed to enumerate the device\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbEnumerateNewDev (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port\r
+  )\r
+{\r
+  USB_BUS                 *Bus;\r
+  USB_HUB_API             *HubApi;\r
+  USB_DEVICE              *Child;\r
+  USB_DEVICE              *Parent;\r
+  EFI_USB_PORT_STATUS     PortState;\r
+  UINT8                   Address;\r
+  UINT8                   Config;\r
+  EFI_STATUS              Status;\r
+\r
+  Address = USB_MAX_DEVICES;\r
+  Parent  = HubIf->Device;\r
+  Bus     = Parent->Bus;\r
+  HubApi  = HubIf->HubApi;\r
+\r
+\r
+  //\r
+  // Wait at least 100 ms for the power on port to stable\r
+  //\r
+  gBS->Stall (100 * USB_STALL_1_MS);\r
+\r
+  //\r
+  // Hub resets the device for at least 10 milliseconds.\r
+  // Host learns device speed. If device is of low/full speed\r
+  // and the hub is a EHCI root hub, ResetPort will release\r
+  // the device to its companion UHCI and return an error.\r
+  //\r
+  Status = HubApi->ResetPort (HubIf, Port);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status));\r
+\r
+    return Status;\r
+  }\r
+\r
+  USB_DEBUG (("UsbEnumerateNewDev: hub port %d is reset\n", Port));\r
+\r
+  Child = UsbCreateDevice (HubIf, Port);\r
+\r
+  if (Child == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // OK, now identify the device speed. After reset, hub\r
+  // fully knows the actual device speed.\r
+  //\r
+  Status = HubApi->GetPortStatus (HubIf, Port, &PortState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumerateNewDev: failed to get speed of port %d\n", Port));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) {\r
+    Child->Speed = EFI_USB_SPEED_LOW;\r
+\r
+  } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {\r
+    Child->Speed = EFI_USB_SPEED_HIGH;\r
+\r
+  } else {\r
+    Child->Speed = EFI_USB_SPEED_FULL;\r
+  }\r
+\r
+  USB_DEBUG (("UsbEnumerateNewDev: device is of %d speed\n", Child->Speed));\r
+\r
+  if (Child->Speed != EFI_USB_SPEED_HIGH) {\r
+    //\r
+    // If the child isn't a high speed device, it is necessary to\r
+    // set the transaction translator. This is quite simple:\r
+    //  1. if parent is of high speed, then parent is our translator\r
+    //  2. otherwise use parent's translator.\r
+    //\r
+    if (Parent->Speed == EFI_USB_SPEED_HIGH) {\r
+      Child->Translator.TranslatorHubAddress  = Parent->Address;\r
+      Child->Translator.TranslatorPortNumber  = Port;\r
+\r
+    } else {\r
+      Child->Translator = Parent->Translator;\r
+    }\r
+\r
+    USB_DEBUG (("UsbEnumerateNewDev: device uses translator (%d, %d)\n",\r
+                Child->Translator.TranslatorHubAddress,\r
+                Child->Translator.TranslatorPortNumber));\r
+  }\r
+\r
+  //\r
+  // After port is reset, hub establishes a signal path between\r
+  // the device and host (DEFALUT state). Device¡¯s registers are\r
+  // reset, use default address 0 (host enumerates one device at\r
+  // a time) , and ready to respond to control transfer at EP 0.\r
+  //\r
+\r
+  //\r
+  // Host sends a Get_Descriptor request to learn the max packet\r
+  // size of default pipe (only part of the device¡¯s descriptor).\r
+  //\r
+  Status = UsbGetMaxPacketSize0 (Child);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  USB_DEBUG (("UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0));\r
+\r
+  //\r
+  // Host assigns an address to the device. Device completes the\r
+  // status stage with default address, then switches to new address.\r
+  // ADDRESS state. Address zero is reserved for root hub.\r
+  //\r
+  for (Address = 1; Address < USB_MAX_DEVICES; Address++) {\r
+    if (Bus->Devices[Address] == NULL) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Address == USB_MAX_DEVICES) {\r
+    USB_ERROR (("UsbEnumerateNewDev: address pool is full for port %d\n", Port));\r
+\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Bus->Devices[Address] = Child;\r
+  Status                = UsbSetAddress (Child, Address);\r
+  Child->Address        = Address;\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumerateNewDev: failed to set device address - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Wait 20ms for set address to complete\r
+  //\r
+  gBS->Stall (20 * USB_STALL_1_MS);\r
+\r
+  USB_DEBUG (("UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address));\r
+\r
+  //\r
+  // Host learns about the device¡¯s abilities by requesting device's\r
+  // entire descriptions.\r
+  //\r
+  Status = UsbBuildDescTable (Child);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Select a default configuration: UEFI must set the configuration\r
+  // before the driver can connect to the device.\r
+  //\r
+  Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue;\r
+  Status = UsbSetConfig (Child, Config);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  USB_DEBUG (("UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address));\r
+\r
+  //\r
+  // Host assigns and loads a device driver.\r
+  //\r
+  Status = UsbSelectConfig (Child, Config);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumerateNewDev: failed to create interfaces - %r\n", Status));\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  if (Address != USB_MAX_DEVICES) {\r
+    Bus->Devices[Address] = NULL;\r
+  }\r
+\r
+  if (Child != NULL) {\r
+    UsbFreeDevice (Child);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Process the events on the port.\r
+\r
+  @param  HubIf                 The HUB that has the device connected\r
+  @param  Port                  The port index of the hub (started with zero)\r
+\r
+  @retval EFI_SUCCESS           The device is enumerated (added or removed)\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource for the device\r
+  @retval Others                Failed to enumerate the device\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbEnumeratePort (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port\r
+  )\r
+{\r
+  USB_HUB_API             *HubApi;\r
+  USB_DEVICE              *Child;\r
+  EFI_USB_PORT_STATUS     PortState;\r
+  EFI_STATUS              Status;\r
+\r
+  Child   = NULL;\r
+  HubApi  = HubIf->HubApi;\r
+\r
+  //\r
+  // Host learns of the new device by polling the hub for port changes.\r
+  //\r
+  Status = HubApi->GetPortStatus (HubIf, Port, &PortState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbEnumeratePort: failed to get state of port %d\n", Port));\r
+    return Status;\r
+  }\r
+\r
+  if (PortState.PortChangeStatus == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  USB_DEBUG (("UsbEnumeratePort: port %d state - %x, change - %x\n",\r
+              Port, PortState.PortStatus, PortState.PortChangeStatus));\r
+\r
+  //\r
+  // This driver only process two kinds of events now: over current and\r
+  // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET.\r
+  // ENABLE/RESET is used to reset port. SUSPEND isn't supported.\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) {\r
+    //\r
+    // If overcurrent condition is cleared, enable the port again\r
+    //\r
+    if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) {\r
+      HubApi->SetPortFeature (HubIf, Port, USB_HUB_PORT_POWER);\r
+    }\r
+\r
+  } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) {\r
+    //\r
+    // Device connected or disconnected. Either way, if there is\r
+    // already a device present in the bus, need to remove it.\r
+    //\r
+    Child = UsbFindChild (HubIf, Port);\r
+\r
+    if (Child != NULL) {\r
+      USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port));\r
+      UsbRemoveDevice (Child);\r
+    }\r
+\r
+    if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) {\r
+      //\r
+      // Now, new device connected, enumerate and configure the device\r
+      //\r
+      USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port));\r
+      Status = UsbEnumerateNewDev (HubIf, Port);\r
+\r
+    } else {\r
+      USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port));\r
+    }\r
+  }\r
+\r
+  HubApi->ClearPortChange (HubIf, Port);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Enumerate all the changed hub ports\r
+\r
+  @param  Event                 The event that is triggered\r
+  @param  Context               The context to the event\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UsbHubEnumeration (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  USB_INTERFACE           *HubIf;\r
+  UINT8                   Byte;\r
+  UINT8                   Bit;\r
+  UINT8                   Index;\r
+\r
+  ASSERT (Context);\r
+\r
+  HubIf = (USB_INTERFACE *) Context;\r
+\r
+  if (HubIf->ChangeMap == NULL) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // HUB starts its port index with 1.\r
+  //\r
+  Byte  = 0;\r
+  Bit   = 1;\r
+\r
+  for (Index = 0; Index < HubIf->NumOfPort; Index++) {\r
+    if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) {\r
+      UsbEnumeratePort (HubIf, Index);\r
+    }\r
+\r
+    USB_NEXT_BIT (Byte, Bit);\r
+  }\r
+\r
+  UsbHubAckHubStatus (HubIf->Device);\r
+\r
+  gBS->FreePool (HubIf->ChangeMap);\r
+  HubIf->ChangeMap = NULL;\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Enumerate all the changed hub ports\r
+\r
+  @param  Event                 The event that is triggered\r
+  @param  Context               The context to the event\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UsbRootHubEnumeration (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  USB_INTERFACE           *RootHub;\r
+  UINT8                   Index;\r
+\r
+  RootHub = (USB_INTERFACE *) Context;\r
+\r
+  for (Index = 0; Index < RootHub->NumOfPort; Index++) {\r
+    UsbEnumeratePort (RootHub, Index);\r
+  }\r
+}\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h
new file mode 100644 (file)
index 0000000..e14b2d7
--- /dev/null
@@ -0,0 +1,153 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbEnumer.h\r
+\r
+  Abstract:\r
+\r
+    USB bus enumeration interface\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _USB_ENUMERATION_H_\r
+#define _USB_ENUMERATION_H_\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define USB_NEXT_BIT(Byte, Bit)   \\r
+          do {                \\r
+            (Bit)++;          \\r
+            if ((Bit) > 7) {  \\r
+              (Byte)++;       \\r
+              (Bit) = 0;      \\r
+            }                 \\r
+          } while (0)\r
+\r
+\r
+//\r
+// Common interface used by usb bus enumeration process.\r
+// This interface is defined to mask the difference between\r
+// the root hub and normal hub. So, bus enumeration code\r
+// can be shared by both root hub and normal hub\r
+//\r
+typedef\r
+EFI_STATUS\r
+(*USB_HUB_INIT) (\r
+  IN USB_INTERFACE        *UsbIf\r
+  );\r
+\r
+//\r
+// Get the port status. This function is required to\r
+// ACK the port change bits although it will return\r
+// the port changes in PortState. Bus enumeration code\r
+// doesn't need to ACK the port change bits.\r
+//\r
+typedef\r
+EFI_STATUS\r
+(*USB_HUB_GET_PORT_STATUS) (\r
+  IN  USB_INTERFACE       *UsbIf,\r
+  IN  UINT8               Port,\r
+  OUT EFI_USB_PORT_STATUS *PortState\r
+  );\r
+\r
+typedef\r
+VOID\r
+(*USB_HUB_CLEAR_PORT_CHANGE) (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_HUB_SET_PORT_FEATURE) (\r
+  IN USB_INTERFACE        *UsbIf,\r
+  IN UINT8                Port,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_HUB_CLEAR_PORT_FEATURE) (\r
+  IN USB_INTERFACE        *UsbIf,\r
+  IN UINT8                Port,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_HUB_RESET_PORT) (\r
+  IN USB_INTERFACE        *UsbIf,\r
+  IN UINT8                Port\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_HUB_RELEASE) (\r
+  IN USB_INTERFACE        *UsbIf\r
+  );\r
+\r
+typedef struct _USB_HUB_API{\r
+  USB_HUB_INIT                Init;\r
+  USB_HUB_GET_PORT_STATUS     GetPortStatus;\r
+  USB_HUB_CLEAR_PORT_CHANGE   ClearPortChange;\r
+  USB_HUB_SET_PORT_FEATURE    SetPortFeature;\r
+  USB_HUB_CLEAR_PORT_FEATURE  ClearPortFeature;\r
+  USB_HUB_RESET_PORT          ResetPort;\r
+  USB_HUB_RELEASE             Release;\r
+} USB_HUB_API;\r
+\r
+USB_ENDPOINT_DESC*\r
+UsbGetEndpointDesc (\r
+  IN USB_INTERFACE        *UsbIf,\r
+  IN UINT8                EpAddr\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbSelectSetting (\r
+  IN USB_INTERFACE_DESC   *IfDesc,\r
+  IN UINT8                Alternate\r
+  );\r
+\r
+EFI_STATUS\r
+UsbSelectConfig (\r
+  IN USB_DEVICE           *Device,\r
+  IN UINT8                ConfigIndex\r
+  );\r
+\r
+VOID\r
+UsbRemoveConfig (\r
+  IN USB_DEVICE           *Device\r
+  );\r
+\r
+EFI_STATUS\r
+UsbRemoveDevice (\r
+  IN USB_DEVICE           *Device\r
+  );\r
+\r
+VOID\r
+UsbHubEnumeration (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  );\r
+\r
+VOID\r
+UsbRootHubEnumeration (\r
+  IN EFI_EVENT            Event,\r
+  IN VOID                 *Context\r
+  );\r
+#endif\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
new file mode 100644 (file)
index 0000000..25332f4
--- /dev/null
@@ -0,0 +1,1334 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbHub.c\r
+\r
+  Abstract:\r
+\r
+    Unified interface for RootHub and Hub\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#include "UsbBus.h"\r
+\r
+//\r
+// USB hub class specific requests. Although USB hub\r
+// is related to an interface, these requests are sent\r
+// to the control endpoint of the device.\r
+//\r
+\r
+\r
+/**\r
+  USB hub control transfer to clear the hub feature\r
+\r
+  @param  HubDev                The device of the hub\r
+  @param  Feature               The feature to clear\r
+\r
+  @retval EFI_SUCCESS           Feature of the hub is cleared\r
+  @retval Others                Failed to clear the feature\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlClearHubFeature (\r
+  IN USB_DEVICE           *HubDev,\r
+  IN UINT16               Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_CLEAR_FEATURE,\r
+             Feature,\r
+             0,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear the feature of the device's port\r
+\r
+  @param  HubDev                The hub device\r
+  @param  Port                  The port to clear feature\r
+  @param  Feature               The feature to clear\r
+\r
+  @retval EFI_SUCCESS           The feature of the port is cleared.\r
+  @retval Others                Failed to clear the feature.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlClearPortFeature (\r
+  IN USB_DEVICE           *HubDev,\r
+  IN UINT8                Port,\r
+  IN UINT16               Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // In USB bus, all the port index starts from 0. But HUB\r
+  // indexes its port from 1. So, port number is added one.\r
+  //\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_PORT,\r
+             USB_HUB_REQ_CLEAR_FEATURE,\r
+             Feature,\r
+             Port + 1,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Clear the transaction translate buffer if full/low\r
+  speed control/bulk transfer failed and the transfer\r
+  uses this hub as translator.Remember to clear the TT\r
+  buffer of transaction translator, not that of the\r
+  parent.\r
+\r
+  @param  HubDev                The hub device\r
+  @param  Port                  The port of the hub\r
+  @param  DevAddr               Address of the failed transaction\r
+  @param  EpNum                 The endpoint number of the failed transaction\r
+  @param  EpType                The type of failed transaction\r
+\r
+  @retval EFI_SUCCESS           The TT buffer is cleared\r
+  @retval Others                Failed to clear the TT buffer\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHubCtrlClearTTBuffer (\r
+  IN USB_DEVICE           *HubDev,\r
+  IN UINT8                Port,\r
+  IN UINT16               DevAddr,\r
+  IN UINT16               EpNum,\r
+  IN UINT16               EpType\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT16                  Value;\r
+\r
+  //\r
+  // Check USB2.0 spec page 424 for wValue's encoding\r
+  //\r
+  Value = (EpNum & 0x0F) | (DevAddr << 4) |\r
+          ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15);\r
+\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_PORT,\r
+             USB_HUB_REQ_CLEAR_TT,\r
+             Value,\r
+             Port + 1,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Usb hub control transfer to get the hub descriptor\r
+\r
+  @param  HubDev                The hub device\r
+  @param  Buf                   The buffer to hold the descriptor\r
+  @param  Len                   The length to retrieve\r
+\r
+  @retval EFI_SUCCESS           The hub descriptor is retrieved\r
+  @retval Others                Failed to retrieve the hub descriptor\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlGetHubDesc (\r
+  IN  USB_DEVICE          *HubDev,\r
+  OUT VOID                *Buf,\r
+  IN  UINTN               Len\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbDataIn,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_GET_DESC,\r
+             (UINT16) (USB_DESC_TYPE_HUB << 8),\r
+             0,\r
+             Buf,\r
+             Len\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Usb hub control transfer to get the hub status\r
+\r
+  @param  HubDev                The hub device\r
+  @param  State                 The variable to return the status\r
+\r
+  @retval EFI_SUCCESS           The hub status is returned in State\r
+  @retval Others                Failed to get the hub status\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlGetHubStatus (\r
+  IN  USB_DEVICE          *HubDev,\r
+  OUT UINT32              *State\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbDataIn,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_GET_STATUS,\r
+             0,\r
+             0,\r
+             State,\r
+             4\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Usb hub control transfer to get the port status\r
+\r
+  @param  HubDev                The hub device\r
+  @param  Port                  The port of the hub\r
+  @param  State                 Variable to return the hub port state\r
+\r
+  @retval EFI_SUCCESS           The port state is returned in State\r
+  @retval Others                Failed to retrive the port state\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlGetPortStatus (\r
+  IN  USB_DEVICE          *HubDev,\r
+  IN  UINT8               Port,\r
+  OUT VOID                *State\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // In USB bus, all the port index starts from 0. But HUB\r
+  // indexes its port from 1. So, port number is added one.\r
+  // No need to convert the hub bit to UEFI definition, they\r
+  // are the same\r
+  //\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbDataIn,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_PORT,\r
+             USB_HUB_REQ_GET_STATUS,\r
+             0,\r
+             Port + 1,\r
+             State,\r
+             4\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Usb hub control transfer to reset the TT (Transaction Transaltor)\r
+\r
+  @param  HubDev                The hub device\r
+  @param  Port                  The port of the hub\r
+\r
+  @retval EFI_SUCCESS           The TT of the hub is reset\r
+  @retval Others                Failed to reset the port\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlResetTT (\r
+  IN  USB_DEVICE          *HubDev,\r
+  IN  UINT8               Port\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_RESET_TT,\r
+             0,\r
+             Port + 1,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Usb hub control transfer to set the hub feature\r
+\r
+  @param  HubDev                The hub device\r
+  @param  Feature               The feature to set\r
+\r
+  @retval EFI_SUCESS            The feature is set for the hub\r
+  @retval Others                Failed to set the feature\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlSetHubFeature (\r
+  IN  USB_DEVICE          *HubDev,\r
+  IN  UINT8               Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_HUB,\r
+             USB_HUB_REQ_SET_FEATURE,\r
+             Feature,\r
+             0,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Usb hub control transfer to set the port feature\r
+\r
+  @param  HubDev                The Usb hub device\r
+  @param  Port                  The Usb port to set feature for\r
+  @param  Feature               The feature to set\r
+\r
+  @retval EFI_SUCCESS           The feature is set for the port\r
+  @retval Others                Failed to set the feature\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubCtrlSetPortFeature (\r
+  IN USB_DEVICE           *HubDev,\r
+  IN UINT8                Port,\r
+  IN UINT8                Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // In USB bus, all the port index starts from 0. But HUB\r
+  // indexes its port from 1. So, port number is added one.\r
+  //\r
+  Status = UsbCtrlRequest (\r
+             HubDev,\r
+             EfiUsbNoData,\r
+             USB_REQ_TYPE_CLASS,\r
+             USB_HUB_TARGET_PORT,\r
+             USB_HUB_REQ_SET_FEATURE,\r
+             Feature,\r
+             Port + 1,\r
+             NULL,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Read the whole usb hub descriptor. It is necessary\r
+  to do it in two steps because hub descriptor is of\r
+  variable length\r
+\r
+  @param  HubDev                The hub device\r
+  @param  HubDesc               The variable to return the descriptor\r
+\r
+  @retval EFI_SUCCESS           The hub descriptor is read\r
+  @retval Others                Failed to read the hub descriptor\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubReadDesc (\r
+  IN  USB_DEVICE              *HubDev,\r
+  OUT EFI_USB_HUB_DESCRIPTOR  *HubDesc\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // First get the hub descriptor length\r
+  //\r
+  Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get the whole hub descriptor\r
+  //\r
+  Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Ack the hub change bits. If these bits are not ACKed, Hub will\r
+  always return changed bit map from its interrupt endpoint.\r
+\r
+  @param  HubDev                The hub device\r
+\r
+  @retval EFI_SUCCESS           The hub change status is ACKed\r
+  @retval Others                Failed to ACK the hub status\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHubAckHubStatus (\r
+  IN  USB_DEVICE         *HubDev\r
+  )\r
+{\r
+  EFI_USB_PORT_STATUS     HubState;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {\r
+    UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);\r
+  }\r
+\r
+  if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {\r
+    UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Test whether the interface is a hub interface.\r
+\r
+  @param  UsbIf                 The interface to test\r
+\r
+  @retval TRUE                  The interface is a hub interface\r
+  @retval FALSE                 The interface isn't a hub interface\r
+\r
+**/\r
+BOOLEAN\r
+UsbIsHubInterface (\r
+  IN USB_INTERFACE        *UsbIf\r
+  )\r
+{\r
+  EFI_USB_INTERFACE_DESCRIPTOR  *Setting;\r
+\r
+  //\r
+  // If the hub is a high-speed hub with multiple TT,\r
+  // the hub will has a default setting of single TT.\r
+  //\r
+  Setting = &UsbIf->IfSetting->Desc;\r
+\r
+  if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&\r
+      (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {\r
+\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  The callback function to the USB hub status change\r
+  interrupt endpoint. It is called periodically by\r
+  the underlying host controller.\r
+\r
+  @param  Data                  The data read\r
+  @param  DataLength            The length of the data read\r
+  @param  Context               The context\r
+  @param  Result                The result of the last interrupt transfer\r
+\r
+  @retval EFI_SUCCESS           The process is OK\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbOnHubInterrupt (\r
+  IN  VOID                *Data,\r
+  IN  UINTN               DataLength,\r
+  IN  VOID                *Context,\r
+  IN  UINT32              Result\r
+  )\r
+{\r
+  USB_INTERFACE               *HubIf;\r
+  EFI_USB_IO_PROTOCOL         *UsbIo;\r
+  EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
+  EFI_STATUS                  Status;\r
+\r
+  HubIf   = (USB_INTERFACE *) Context;\r
+  UsbIo   = &(HubIf->UsbIo);\r
+  EpDesc  = &(HubIf->HubEp->Desc);\r
+\r
+  if (Result != EFI_USB_NOERROR) {\r
+    //\r
+    // If endpoint is stalled, clear the stall. Use UsbIo to access\r
+    // the control transfer so internal status are maintained.\r
+    //\r
+    if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {\r
+      UsbIoClearFeature (\r
+        UsbIo,\r
+        USB_TARGET_ENDPOINT,\r
+        USB_FEATURE_ENDPOINT_HALT,\r
+        EpDesc->EndpointAddress\r
+        );\r
+    }\r
+\r
+    //\r
+    // Delete and submit a new async interrupt\r
+    //\r
+    Status = UsbIo->UsbAsyncInterruptTransfer (\r
+                      UsbIo,\r
+                      EpDesc->EndpointAddress,\r
+                      FALSE,\r
+                      0,\r
+                      0,\r
+                      NULL,\r
+                      NULL\r
+                      );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      USB_ERROR (("UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));\r
+      return Status;\r
+    }\r
+\r
+    Status = UsbIo->UsbAsyncInterruptTransfer (\r
+                      UsbIo,\r
+                      EpDesc->EndpointAddress,\r
+                      TRUE,\r
+                      USB_HUB_POLL_INTERVAL,\r
+                      HubIf->NumOfPort / 8 + 1,\r
+                      UsbOnHubInterrupt,\r
+                      HubIf\r
+                      );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      USB_ERROR (("UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  if ((DataLength == 0) || (Data == NULL)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // OK, actually something is changed, save the change map\r
+  // then signal the HUB to do enumeration. This is a good\r
+  // practise since UsbOnHubInterrupt is called in the context\r
+  // of host contrller's AsyncInterrupt monitor.\r
+  //\r
+  HubIf->ChangeMap = AllocateZeroPool (DataLength);\r
+\r
+  if (HubIf->ChangeMap == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CopyMem (HubIf->ChangeMap, Data, DataLength);\r
+  gBS->SignalEvent (HubIf->HubNotify);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// Array that maps the change bit to feature value which is\r
+// used to clear these change bit. USB HUB API will clear\r
+// these change bit automatically. For non-root hub, these\r
+// bits determine whether hub will report the port in changed\r
+// bit maps.\r
+//\r
+#define USB_HUB_MAP_SIZE  5\r
+\r
+USB_CHANGE_FEATURE_MAP  mHubFeatureMap[USB_HUB_MAP_SIZE] = {\r
+  {USB_PORT_STAT_C_CONNECTION,  USB_HUB_C_PORT_CONNECT},\r
+  {USB_PORT_STAT_C_ENABLE,      USB_HUB_C_PORT_ENABLE},\r
+  {USB_PORT_STAT_C_SUSPEND,     USB_HUB_C_PORT_SUSPEND},\r
+  {USB_PORT_STAT_C_OVERCURRENT, USB_HUB_C_PORT_OVER_CURRENT},\r
+  {USB_PORT_STAT_C_RESET,       USB_HUB_C_PORT_RESET},\r
+};\r
+\r
+#define USB_ROOT_HUB_MAP_SIZE 5\r
+\r
+USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[USB_ROOT_HUB_MAP_SIZE] = {\r
+  {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},\r
+  {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},\r
+  {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},\r
+  {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},\r
+  {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange},\r
+};\r
+\r
+\r
+\r
+/**\r
+  Initialize the device for a non-root hub\r
+\r
+  @param  HubIf                 The USB hub interface\r
+\r
+  @retval EFI_SUCCESS           The hub is initialized\r
+  @retval EFI_DEVICE_ERROR      Failed to initialize the hub\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubInit (\r
+  IN USB_INTERFACE        *HubIf\r
+  )\r
+{\r
+  EFI_USB_HUB_DESCRIPTOR  HubDesc;\r
+  USB_ENDPOINT_DESC       *EpDesc;\r
+  USB_INTERFACE_SETTING   *Setting;\r
+  EFI_USB_IO_PROTOCOL     *UsbIo;\r
+  USB_DEVICE              *HubDev;\r
+  EFI_STATUS              Status;\r
+  UINT8                   Index;\r
+\r
+  //\r
+  // Locate the interrupt endpoint for port change map\r
+  //\r
+  HubIf->IsHub  = FALSE;\r
+  Setting       = HubIf->IfSetting;\r
+  HubDev        = HubIf->Device;\r
+  EpDesc        = NULL;\r
+\r
+  for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) {\r
+    ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));\r
+\r
+    EpDesc = Setting->Endpoints[Index];\r
+\r
+    if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&\r
+       (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == Setting->Desc.NumEndpoints) {\r
+    USB_ERROR (("UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = UsbHubReadDesc (HubDev, &HubDesc);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbHubInit: failed to read HUB descriptor %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  HubIf->NumOfPort = HubDesc.NumPorts;\r
+\r
+  USB_DEBUG (("UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));\r
+\r
+  //\r
+  // Create an event to enumerate the hub's port. On\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  UsbHubEnumeration,\r
+                  HubIf,\r
+                  &HubIf->HubNotify\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbHubInit: failed to create signal for hub %d - %r\n",\r
+                HubDev->Address, Status));\r
+\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Create AsyncInterrupt to query hub port change endpoint\r
+  // periodically. If the hub ports are changed, hub will return\r
+  // changed port map from the interrupt endpoint. The port map\r
+  // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for\r
+  // host change status).\r
+  //\r
+  UsbIo  = &HubIf->UsbIo;\r
+  Status = UsbIo->UsbAsyncInterruptTransfer (\r
+                    UsbIo,\r
+                    EpDesc->Desc.EndpointAddress,\r
+                    TRUE,\r
+                    USB_HUB_POLL_INTERVAL,\r
+                    HubIf->NumOfPort / 8 + 1,\r
+                    UsbOnHubInterrupt,\r
+                    HubIf\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",\r
+                HubDev->Address, Status));\r
+\r
+    gBS->CloseEvent (HubIf->HubNotify);\r
+    HubIf->HubNotify = NULL;\r
+\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // OK, set IsHub to TRUE. Now usb bus can handle this device\r
+  // as a working HUB. If failed eariler, bus driver will not\r
+  // recognize it as a hub. Other parts of the bus should be able\r
+  // to work.\r
+  //\r
+  HubIf->IsHub  = TRUE;\r
+  HubIf->HubApi = &mUsbHubApi;\r
+  HubIf->HubEp  = EpDesc;\r
+\r
+  //\r
+  // Feed power to all the hub ports. It should be ok\r
+  // for both gang/individual powered hubs.\r
+  //\r
+  for (Index = 0; Index < HubDesc.NumPorts; Index++) {\r
+    UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_POWER);\r
+  }\r
+\r
+  gBS->Stall (HubDesc.PwrOn2PwrGood * 2 * USB_STALL_1_MS);\r
+  UsbHubAckHubStatus (HubIf->Device);\r
+\r
+  USB_DEBUG (("UsbHubInit: hub %d initialized\n", HubDev->Address));\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Get the port status. This function is required to\r
+  ACK the port change bits although it will return\r
+  the port changes in PortState. Bus enumeration code\r
+  doesn't need to ACK the port change bits.\r
+\r
+  @param  HubIf                 The hub interface\r
+  @param  Port                  The port of the hub to get state\r
+  @param  PortState             Variable to return the port state\r
+\r
+  @retval EFI_SUCCESS           The port status is successfully returned\r
+  @retval Others                Failed to return the status\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubGetPortStatus (\r
+  IN  USB_INTERFACE       *HubIf,\r
+  IN  UINT8               Port,\r
+  OUT EFI_USB_PORT_STATUS *PortState\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status  = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Clear the port change status.\r
+\r
+  @param  HubIf                 The hub interface\r
+  @param  Port                  The hub port\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbHubClearPortChange (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port\r
+  )\r
+{\r
+  EFI_USB_PORT_STATUS     PortState;\r
+  USB_CHANGE_FEATURE_MAP  *Map;\r
+  UINTN                   Index;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // OK, get the usb port status, now ACK the change bits.\r
+  // Don't return error when failed to clear the change bits.\r
+  // It may lead to extra port state report. USB bus should\r
+  // be able to handle this.\r
+  //\r
+  for (Index = 0; Index < USB_HUB_MAP_SIZE; Index++) {\r
+    Map = &mHubFeatureMap[Index];\r
+\r
+    if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
+      UsbHubCtrlClearPortFeature (HubIf->Device, Port, Map->Feature);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Function to set the port feature for non-root hub\r
+\r
+  @param  HubIf                 The hub interface\r
+  @param  Port                  The port of the hub\r
+  @param  Feature               The feature of the port to set\r
+\r
+  @retval EFI_SUCCESS           The hub port feature is set\r
+  @retval Others                Failed to set the port feature\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubSetPortFeature (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, Feature);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Interface function to clear the port feature for non-root hub\r
+\r
+  @param  HubIf                 The hub interface\r
+  @param  Port                  The port of the hub to clear feature for\r
+  @param  Feature               The feature to clear\r
+\r
+  @retval EFI_SUCCESS           The port feature is cleared\r
+  @retval Others                Failed to clear the port feature\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubClearPortFeature (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, Feature);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Interface funtion to reset the port\r
+\r
+  @param  HubIf                 The hub interface\r
+  @param  Port                  The port to reset\r
+\r
+  @retval EFI_SUCCESS           The hub port is reset\r
+  @retval EFI_TIMEOUT           Failed to reset the port in time\r
+  @retval Others                Failed to reset the port\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubResetPort (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port\r
+  )\r
+{\r
+  EFI_USB_PORT_STATUS     PortState;\r
+  UINTN                   Index;\r
+  EFI_STATUS              Status;\r
+\r
+  Status  = UsbHubSetPortFeature (HubIf, Port, USB_HUB_PORT_RESET);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Drive the reset signal for at least 10ms. Check USB 2.0 Spec\r
+  // section 7.1.7.5 for timing requirements.\r
+  //\r
+  gBS->Stall (20 * USB_STALL_1_MS);\r
+\r
+  //\r
+  // USB hub will clear RESET bit if reset is actually finished.\r
+  //\r
+  ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+  for (Index = 0; Index < 20; Index++) {\r
+    Status = UsbHubGetPortStatus (HubIf, Port, &PortState);\r
+\r
+    if (!EFI_ERROR (Status) &&\r
+        !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    gBS->Stall (5 * USB_STALL_1_MS);\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+\r
+/**\r
+  Release the hub's control of the interface\r
+\r
+  @param  HubIf                 The hub interface\r
+\r
+  @retval EFI_SUCCESS           The interface is release of hub control\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbHubRelease (\r
+  IN USB_INTERFACE        *HubIf\r
+  )\r
+{\r
+  EFI_USB_IO_PROTOCOL     *UsbIo;\r
+  EFI_STATUS              Status;\r
+\r
+  UsbIo  = &HubIf->UsbIo;\r
+  Status = UsbIo->UsbAsyncInterruptTransfer (\r
+                    UsbIo,\r
+                    HubIf->HubEp->Desc.EndpointAddress,\r
+                    FALSE,\r
+                    USB_HUB_POLL_INTERVAL,\r
+                    0,\r
+                    NULL,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  gBS->CloseEvent (HubIf->HubNotify);\r
+\r
+  HubIf->IsHub      = FALSE;\r
+  HubIf->HubApi     = NULL;\r
+  HubIf->HubEp      = NULL;\r
+  HubIf->HubNotify  = NULL;\r
+\r
+  USB_DEBUG (("UsbHubRelease: hub device %d released\n", HubIf->Device->Address));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Initialize the interface for root hub\r
+\r
+  @param  HubIf                 The root hub interface\r
+\r
+  @retval EFI_SUCCESS           The interface is initialied for root hub\r
+  @retval Others                Failed to initialize the hub\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbRootHubInit (\r
+  IN USB_INTERFACE        *HubIf\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT8                   MaxSpeed;\r
+  UINT8                   NumOfPort;\r
+  UINT8                   Support64;\r
+\r
+  Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  USB_DEBUG (("UsbRootHubInit: root hub %x - max speed %d, %d ports\n",\r
+              HubIf, MaxSpeed, NumOfPort));\r
+\r
+  HubIf->IsHub      = TRUE;\r
+  HubIf->HubApi     = &mUsbRootHubApi;\r
+  HubIf->HubEp      = NULL;\r
+  HubIf->MaxSpeed   = MaxSpeed;\r
+  HubIf->NumOfPort  = NumOfPort;\r
+  HubIf->HubNotify  = NULL;\r
+\r
+  //\r
+  // Create a timer to poll root hub ports periodically\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  UsbRootHubEnumeration,\r
+                  HubIf,\r
+                  &HubIf->HubNotify\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->SetTimer (\r
+                  HubIf->HubNotify,\r
+                  TimerPeriodic,\r
+                  USB_ROOTHUB_POLL_INTERVAL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseEvent (HubIf->HubNotify);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Get the port status. This function is required to\r
+  ACK the port change bits although it will return\r
+  the port changes in PortState. Bus enumeration code\r
+  doesn't need to ACK the port change bits.\r
+\r
+  @param  HubIf                 The root hub interface\r
+  @param  Port                  The root hub port to get the state\r
+  @param  PortState             Variable to return the port state\r
+\r
+  @retval EFI_SUCCESS           The port state is returned\r
+  @retval Others                Failed to retrieve the port state\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbRootHubGetPortStatus (\r
+  IN  USB_INTERFACE       *HubIf,\r
+  IN  UINT8               Port,\r
+  OUT EFI_USB_PORT_STATUS *PortState\r
+  )\r
+{\r
+  USB_BUS                 *Bus;\r
+  EFI_STATUS              Status;\r
+\r
+  Bus     = HubIf->Device->Bus;\r
+  Status  = UsbHcGetRootHubPortStatus (Bus, Port, PortState);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear the port change status.\r
+\r
+  @param  HubIf                 The root hub interface\r
+  @param  Port                  The root hub port\r
+\r
+  @retval EFI_SUCCESS           The port state is returned\r
+  @retval Others                Failed to retrieve the port state\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbRootHubClearPortChange (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port\r
+  )\r
+{\r
+  EFI_USB_PORT_STATUS     PortState;\r
+  USB_CHANGE_FEATURE_MAP  *Map;\r
+  UINTN                   Index;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // OK, get the usb port status, now ACK the change bits.\r
+  // Don't return error when failed to clear the change bits.\r
+  // It may lead to extra port state report. USB bus should\r
+  // be able to handle this.\r
+  //\r
+  for (Index = 0; Index < USB_ROOT_HUB_MAP_SIZE; Index++) {\r
+    Map = &mRootHubFeatureMap[Index];\r
+\r
+    if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {\r
+      UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Map->Feature);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Set the root hub port feature\r
+\r
+  @param  HubIf                 The Usb hub interface\r
+  @param  Port                  The hub port\r
+  @param  Feature               The feature to set\r
+\r
+  @retval EFI_SUCCESS           The root hub port is set with the feature\r
+  @retval Others                Failed to set the feature\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbRootHubSetPortFeature (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status  = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear the root hub port feature\r
+\r
+  @param  HubIf                 The root hub interface\r
+  @param  Port                  The root hub port\r
+  @param  Feature               The feature to clear\r
+\r
+  @retval EFI_SUCCESS           The root hub port is cleared of the feature\r
+  @retval Others                Failed to clear the feature\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbRootHubClearPortFeature (\r
+  IN USB_INTERFACE        *HubIf,\r
+  IN UINT8                Port,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  Status  = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Interface funtion to reset the root hub port\r
+\r
+  @param  RootIf                The root hub interface\r
+  @param  Port                  The port to reset\r
+\r
+  @retval EFI_SUCCESS           The hub port is reset\r
+  @retval EFI_TIMEOUT           Failed to reset the port in time\r
+  @retval EFI_NOT_FOUND         The low/full speed device connected to high  speed\r
+                                root hub is released to the companion UHCI\r
+  @retval Others                Failed to reset the port\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbRootHubResetPort (\r
+  IN USB_INTERFACE        *RootIf,\r
+  IN UINT8                Port\r
+  )\r
+{\r
+  USB_BUS                 *Bus;\r
+  EFI_STATUS              Status;\r
+  EFI_USB_PORT_STATUS     PortState;\r
+  UINTN                   Index;\r
+\r
+  //\r
+  // Notice: although EHCI requires that ENABLED bit be cleared\r
+  // when reset the port, we don't need to care that here. It\r
+  // should be handled in the EHCI driver.\r
+  //\r
+  Bus     = RootIf->Device->Bus;\r
+  Status  = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbRootHubResetPort: failed to start reset on port %d\n", Port));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Drive the reset signal for at least 50ms. Check USB 2.0 Spec\r
+  // section 7.1.7.5 for timing requirements.\r
+  //\r
+  gBS->Stall (50 * USB_STALL_1_MS);\r
+\r
+  Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbRootHubResetPort: failed to clear reset on port %d\n", Port));\r
+    return Status;\r
+  }\r
+\r
+  gBS->Stall (USB_STALL_1_MS);\r
+\r
+  //\r
+  // USB host controller won't clear the RESET bit until\r
+  // reset is actually finished.\r
+  //\r
+  ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));\r
+\r
+  for (Index = 0; Index < USB_HUB_LOOP; Index++) {\r
+    Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {\r
+      break;\r
+    }\r
+\r
+    gBS->Stall (10 * USB_STALL_1_MS);\r
+  }\r
+\r
+  if (Index == USB_HUB_LOOP) {\r
+    USB_ERROR (("UsbRootHubResetPort: reset not finished in time on port %d\n", Port));\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {\r
+    //\r
+    // OK, the port is reset. If root hub is of high speed and\r
+    // the device is of low/full speed, release the ownership to\r
+    // companion UHCI. If root hub is of full speed, it won't\r
+    // automatically enable the port, we need to enable it manually.\r
+    //\r
+    if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {\r
+      USB_ERROR (("UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));\r
+\r
+      UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);\r
+      return EFI_NOT_FOUND;\r
+\r
+    } else {\r
+\r
+      Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        USB_ERROR (("UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));\r
+        return Status;\r
+      }\r
+\r
+      gBS->Stall (20 * USB_STALL_1_MS);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Release the root hub's control of the interface\r
+\r
+  @param  HubIf                 The root hub interface\r
+\r
+  @retval EFI_SUCCESS           The root hub's control of the interface is\r
+                                released.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbRootHubRelease (\r
+  IN USB_INTERFACE        *HubIf\r
+  )\r
+{\r
+  USB_DEBUG (("UsbRootHubRelease: root hub released for hub %x\n", HubIf));\r
+\r
+  gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);\r
+  gBS->CloseEvent (HubIf->HubNotify);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+USB_HUB_API mUsbHubApi = {\r
+  UsbHubInit,\r
+  UsbHubGetPortStatus,\r
+  UsbHubClearPortChange,\r
+  UsbHubSetPortFeature,\r
+  UsbHubClearPortFeature,\r
+  UsbHubResetPort,\r
+  UsbHubRelease\r
+};\r
+\r
+USB_HUB_API mUsbRootHubApi = {\r
+  UsbRootHubInit,\r
+  UsbRootHubGetPortStatus,\r
+  UsbRootHubClearPortChange,\r
+  UsbRootHubSetPortFeature,\r
+  UsbRootHubClearPortFeature,\r
+  UsbRootHubResetPort,\r
+  UsbRootHubRelease\r
+};\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.h
new file mode 100644 (file)
index 0000000..0238ea0
--- /dev/null
@@ -0,0 +1,140 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbHub.h\r
+\r
+  Abstract:\r
+\r
+    The definition for USB hub\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _USB_HUB_H_\r
+#define _USB_HUB_H_\r
+\r
+#define USB_ENDPOINT_ADDR(EpAddr) ((EpAddr) & 0x7F)\r
+#define USB_ENDPOINT_TYPE(Desc)   ((Desc)->Attributes & USB_ENDPOINT_TYPE_MASK)\r
+\r
+enum {\r
+  USB_DESC_TYPE_HUB           = 0x29,\r
+\r
+  //\r
+  // Hub class control transfer target\r
+  //\r
+  USB_HUB_TARGET_HUB          = 0,\r
+  USB_HUB_TARGET_PORT         = 3,\r
+\r
+  //\r
+  // HUB class specific contrl transfer request type\r
+  //\r
+  USB_HUB_REQ_GET_STATUS      = 0,\r
+  USB_HUB_REQ_CLEAR_FEATURE   = 1,\r
+  USB_HUB_REQ_SET_FEATURE     = 3,\r
+  USB_HUB_REQ_GET_DESC        = 6,\r
+  USB_HUB_REQ_SET_DESC        = 7,\r
+  USB_HUB_REQ_CLEAR_TT        = 8,\r
+  USB_HUB_REQ_RESET_TT        = 9,\r
+  USB_HUB_REQ_GET_TT_STATE    = 10,\r
+  USB_HUB_REQ_STOP_TT         = 11,\r
+\r
+\r
+  //\r
+  // USB hub class feature selector\r
+  //\r
+  USB_HUB_C_HUB_LOCAL_POWER   = 0,\r
+  USB_HUB_C_HUB_OVER_CURRENT  = 1,\r
+  USB_HUB_PORT_CONNECTION     = 0,\r
+  USB_HUB_PORT_ENABLE         = 1,\r
+  USB_HUB_PORT_SUSPEND        = 2,\r
+  USB_HUB_PORT_OVER_CURRENT   = 3,\r
+  USB_HUB_PORT_RESET          = 4,\r
+  USB_HUB_PORT_POWER          = 8,\r
+  USB_HUB_PORT_LOW_SPEED      = 9,\r
+  USB_HUB_C_PORT_CONNECT      = 16,\r
+  USB_HUB_C_PORT_ENABLE       = 17,\r
+  USB_HUB_C_PORT_SUSPEND      = 18,\r
+  USB_HUB_C_PORT_OVER_CURRENT = 19,\r
+  USB_HUB_C_PORT_RESET        = 20,\r
+  USB_HUB_PORT_TEST           = 21,\r
+  USB_HUB_PORT_INDICATOR      = 22,\r
+\r
+  //\r
+  // USB hub power control method. In gang power control\r
+  //\r
+  USB_HUB_GANG_POWER_CTRL     = 0,\r
+  USB_HUB_PORT_POWER_CTRL     = 0x01,\r
+\r
+  //\r
+  // USB hub status bits\r
+  //\r
+  USB_HUB_STAT_LOCAL_POWER    = 0x01,\r
+  USB_HUB_STAT_OVER_CURRENT   = 0x02,\r
+  USB_HUB_STAT_C_LOCAL_POWER  = 0x01,\r
+  USB_HUB_STAT_C_OVER_CURRENT = 0x02,\r
+\r
+  USB_HUB_CLASS_CODE          = 0x09,\r
+  USB_HUB_SUBCLASS_CODE       = 0x00,\r
+\r
+\r
+  USB_HUB_LOOP                = 50,\r
+};\r
+\r
+#pragma pack(1)\r
+//\r
+// Hub descriptor, the last two fields are of variable lenght.\r
+//\r
+typedef struct {\r
+  UINT8           Length;\r
+  UINT8           DescType;\r
+  UINT8           NumPorts;\r
+  UINT16          HubCharacter;\r
+  UINT8           PwrOn2PwrGood;\r
+  UINT8           HubContrCurrent;\r
+  UINT8           Filler[16];\r
+} EFI_USB_HUB_DESCRIPTOR;\r
+#pragma pack()\r
+\r
+\r
+typedef struct {\r
+  UINT16                ChangedBit;\r
+  EFI_USB_PORT_FEATURE  Feature;\r
+} USB_CHANGE_FEATURE_MAP;\r
+\r
+\r
+EFI_STATUS\r
+UsbHubCtrlClearTTBuffer (\r
+  IN USB_DEVICE           *UsbDev,\r
+  IN UINT8                Port,\r
+  IN UINT16               DevAddr,\r
+  IN UINT16               EpNum,\r
+  IN UINT16               EpType\r
+  );\r
+\r
+\r
+BOOLEAN\r
+UsbIsHubInterface (\r
+  IN USB_INTERFACE        *UsbIf\r
+  );\r
+\r
+EFI_STATUS\r
+UsbHubAckHubStatus (\r
+  IN  USB_DEVICE         *UsbDev\r
+  );\r
+\r
+extern USB_HUB_API        mUsbHubApi;\r
+extern USB_HUB_API        mUsbRootHubApi;\r
+#endif\r
+\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c
new file mode 100644 (file)
index 0000000..216f948
--- /dev/null
@@ -0,0 +1,769 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbUtility.c\r
+\r
+  Abstract:\r
+\r
+    Wrapper function for usb host controller interface\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+\r
+#include "UsbBus.h"\r
+\r
+\r
+/**\r
+  Get the capability of the host controller\r
+\r
+  @param  UsbBus           The usb driver\r
+  @param  MaxSpeed         The maximum speed this host controller supports\r
+  @param  NumOfPort        The number of the root hub port\r
+  @param  Is64BitCapable   Whether this controller support 64 bit addressing\r
+\r
+  @retval EFI_SUCCESS      The host controller capability is returned\r
+  @retval Others           Failed to retrieve the host controller capability.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcGetCapability (\r
+  IN  USB_BUS             *UsbBus,\r
+  OUT UINT8               *MaxSpeed,\r
+  OUT UINT8               *NumOfPort,\r
+  OUT UINT8               *Is64BitCapable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->GetCapability (\r
+                              UsbBus->Usb2Hc,\r
+                              MaxSpeed,\r
+                              NumOfPort,\r
+                              Is64BitCapable\r
+                              );\r
+\r
+  } else {\r
+    Status = UsbBus->UsbHc->GetRootHubPortNumber (UsbBus->UsbHc, NumOfPort);\r
+\r
+    *MaxSpeed       = EFI_USB_SPEED_FULL;\r
+    *Is64BitCapable = (UINT8) FALSE;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reset the host controller\r
+\r
+  @param  UsbBus           The usb bus driver\r
+  @param  Attributes       The reset type, only global reset is used by this driver\r
+\r
+  @return GC_TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcReset (\r
+  IN USB_BUS              *UsbBus,\r
+  IN UINT16               Attributes\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->Reset (UsbBus->Usb2Hc, Attributes);\r
+  } else {\r
+    Status = UsbBus->UsbHc->Reset (UsbBus->UsbHc, Attributes);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the current operation state of the host controller\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  State            The host controller operation state\r
+\r
+  @retval EFI_SUCCESS      The operation state is returned in State\r
+  @retval Others           Failed to get the host controller state\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcGetState (\r
+  IN  USB_BUS             *UsbBus,\r
+  OUT EFI_USB_HC_STATE    *State\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->GetState (UsbBus->Usb2Hc, State);\r
+  } else {\r
+    Status = UsbBus->UsbHc->GetState (UsbBus->UsbHc, State);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set the host controller operation state\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  State            The state to set\r
+\r
+  @retval EFI_SUCCESS      The host controller is now working at State\r
+  @retval Others           Failed to set operation state\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcSetState (\r
+  IN USB_BUS              *UsbBus,\r
+  IN EFI_USB_HC_STATE     State\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->SetState (UsbBus->Usb2Hc, State);\r
+  } else {\r
+    Status = UsbBus->UsbHc->SetState (UsbBus->UsbHc, State);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the root hub port state\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  PortIndex        The index of port\r
+  @param  PortStatus       The variable to save port state\r
+\r
+  @retval EFI_SUCCESS      The root port state is returned in\r
+  @retval Others           Failed to get the root hub port state\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcGetRootHubPortStatus (\r
+  IN  USB_BUS             *UsbBus,\r
+  IN  UINT8               PortIndex,\r
+  OUT EFI_USB_PORT_STATUS *PortStatus\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->GetRootHubPortStatus (UsbBus->Usb2Hc, PortIndex, PortStatus);\r
+  } else {\r
+    Status = UsbBus->UsbHc->GetRootHubPortStatus (UsbBus->UsbHc, PortIndex, PortStatus);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set the root hub port feature\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  PortIndex        The port index\r
+  @param  Feature          The port feature to set\r
+\r
+  @retval EFI_SUCCESS      The port feature is set\r
+  @retval Others           Failed to set port feature\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcSetRootHubPortFeature (\r
+  IN USB_BUS              *UsbBus,\r
+  IN UINT8                PortIndex,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->SetRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);\r
+  } else {\r
+    Status = UsbBus->UsbHc->SetRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear the root hub port feature\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  PortIndex        The port index\r
+  @param  Feature          The port feature to clear\r
+\r
+  @retval EFI_SUCCESS      The port feature is clear\r
+  @retval Others           Failed to clear port feature\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcClearRootHubPortFeature (\r
+  IN USB_BUS              *UsbBus,\r
+  IN UINT8                PortIndex,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->ClearRootHubPortFeature (UsbBus->Usb2Hc, PortIndex, Feature);\r
+  } else {\r
+    Status = UsbBus->UsbHc->ClearRootHubPortFeature (UsbBus->UsbHc, PortIndex, Feature);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute a control transfer to the device\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  DevAddr          The device address\r
+  @param  DevSpeed         The device speed\r
+  @param  MaxPacket        Maximum packet size of endpoint 0\r
+  @param  Request          The control transfer request\r
+  @param  Direction        The direction of data stage\r
+  @param  Data             The buffer holding data\r
+  @param  DataLength       The length of the data\r
+  @param  TimeOut          Timeout (in ms) to wait until timeout\r
+  @param  Translator       The transaction translator for low/full speed device\r
+  @param  UsbResult        The result of transfer\r
+\r
+  @retval EFI_SUCCESS      The control transfer finished without error\r
+  @retval Others           The control transfer failed, reason returned in UsbReslt\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcControlTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  EFI_USB_DEVICE_REQUEST              *Request,\r
+  IN  EFI_USB_DATA_DIRECTION              Direction,\r
+  IN  OUT VOID                            *Data,\r
+  IN  OUT UINTN                           *DataLength,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 IsSlowDevice;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->ControlTransfer (\r
+                               UsbBus->Usb2Hc,\r
+                               DevAddr,\r
+                               DevSpeed,\r
+                               MaxPacket,\r
+                               Request,\r
+                               Direction,\r
+                               Data,\r
+                               DataLength,\r
+                               TimeOut,\r
+                               Translator,\r
+                               UsbResult\r
+                               );\r
+\r
+  } else {\r
+    IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);\r
+    Status = UsbBus->UsbHc->ControlTransfer (\r
+                              UsbBus->UsbHc,\r
+                              DevAddr,\r
+                              IsSlowDevice,\r
+                              (UINT8) MaxPacket,\r
+                              Request,\r
+                              Direction,\r
+                              Data,\r
+                              DataLength,\r
+                              TimeOut,\r
+                              UsbResult\r
+                              );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute a bulk transfer to the device's endpoint\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  DevAddr          The target device address\r
+  @param  EpAddr           The target endpoint address, with direction encoded in\r
+                           bit 7\r
+  @param  DevSpeed         The device's speed\r
+  @param  MaxPacket        The endpoint's max packet size\r
+  @param  BufferNum        The number of data buffer\r
+  @param  Data             Array of pointers to data buffer\r
+  @param  DataLength       The length of data buffer\r
+  @param  DataToggle       On input, the initial data toggle to use, also  return\r
+                           the next toggle on output.\r
+  @param  TimeOut          The time to wait until timeout\r
+  @param  Translator       The transaction translator for low/full speed device\r
+  @param  UsbResult        The result of USB execution\r
+\r
+  @retval EFI_SUCCESS      The bulk transfer is finished without error\r
+  @retval Others           Failed to execute bulk transfer, result in UsbResult\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcBulkTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  UINT8                               BufferNum,\r
+  IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+  IN  OUT UINTN                           *DataLength,\r
+  IN  OUT UINT8                           *DataToggle,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->BulkTransfer (\r
+                               UsbBus->Usb2Hc,\r
+                               DevAddr,\r
+                               EpAddr,\r
+                               DevSpeed,\r
+                               MaxPacket,\r
+                               BufferNum,\r
+                               Data,\r
+                               DataLength,\r
+                               DataToggle,\r
+                               TimeOut,\r
+                               Translator,\r
+                               UsbResult\r
+                               );\r
+  } else {\r
+    Status = UsbBus->UsbHc->BulkTransfer (\r
+                              UsbBus->UsbHc,\r
+                              DevAddr,\r
+                              EpAddr,\r
+                              (UINT8) MaxPacket,\r
+                              *Data,\r
+                              DataLength,\r
+                              DataToggle,\r
+                              TimeOut,\r
+                              UsbResult\r
+                              );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Queue or cancel an asynchronous interrupt transfer\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  DevAddr          The target device address\r
+  @param  EpAddr           The target endpoint address, with direction encoded in\r
+                           bit 7\r
+  @param  DevSpeed         The device's speed\r
+  @param  MaxPacket        The endpoint's max packet size\r
+  @param  IsNewTransfer    Whether this is a new request. If not, cancel the old\r
+                           request\r
+  @param  DataToggle       Data toggle to use on input, next toggle on output\r
+  @param  PollingInterval  The interval to poll the interrupt transfer (in ms)\r
+  @param  DataLength       The length of periodical data receive\r
+  @param  Translator       The transaction translator for low/full speed device\r
+  @param  Callback         Function to call when data is received\r
+  @param  Context          The context to the callback\r
+\r
+  @retval EFI_SUCCESS      The asynchronous transfer is queued\r
+  @retval Others           Failed to queue the transfer\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcAsyncInterruptTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  BOOLEAN                             IsNewTransfer,\r
+  IN OUT UINT8                            *DataToggle,\r
+  IN  UINTN                               PollingInterval,\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     Callback,\r
+  IN  VOID                                *Context OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 IsSlowDevice;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->AsyncInterruptTransfer (\r
+                               UsbBus->Usb2Hc,\r
+                               DevAddr,\r
+                               EpAddr,\r
+                               DevSpeed,\r
+                               MaxPacket,\r
+                               IsNewTransfer,\r
+                               DataToggle,\r
+                               PollingInterval,\r
+                               DataLength,\r
+                               Translator,\r
+                               Callback,\r
+                               Context\r
+                               );\r
+  } else {\r
+    IsSlowDevice = (BOOLEAN)(EFI_USB_SPEED_LOW == DevSpeed);\r
+\r
+    Status = UsbBus->UsbHc->AsyncInterruptTransfer (\r
+                              UsbBus->UsbHc,\r
+                              DevAddr,\r
+                              EpAddr,\r
+                              IsSlowDevice,\r
+                              (UINT8) MaxPacket,\r
+                              IsNewTransfer,\r
+                              DataToggle,\r
+                              PollingInterval,\r
+                              DataLength,\r
+                              Callback,\r
+                              Context\r
+                              );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute a synchronous interrupt transfer to the target endpoint\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  DevAddr          The target device address\r
+  @param  EpAddr           The target endpoint address, with direction encoded in\r
+                           bit 7\r
+  @param  DevSpeed         The device's speed\r
+  @param  MaxPacket        The endpoint's max packet size\r
+  @param  Data             Pointer to data buffer\r
+  @param  DataLength       The length of data buffer\r
+  @param  DataToggle       On input, the initial data toggle to use, also  return\r
+                           the next toggle on output.\r
+  @param  TimeOut          The time to wait until timeout\r
+  @param  Translator       The transaction translator for low/full speed device\r
+  @param  UsbResult        The result of USB execution\r
+\r
+  @retval EFI_SUCCESS      The synchronous interrupt transfer is OK\r
+  @retval Others           Failed to execute the synchronous interrupt transfer\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcSyncInterruptTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN OUT VOID                             *Data,\r
+  IN OUT UINTN                            *DataLength,\r
+  IN OUT UINT8                            *DataToggle,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 IsSlowDevice;\r
+\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    Status = UsbBus->Usb2Hc->SyncInterruptTransfer (\r
+                               UsbBus->Usb2Hc,\r
+                               DevAddr,\r
+                               EpAddr,\r
+                               DevSpeed,\r
+                               MaxPacket,\r
+                               Data,\r
+                               DataLength,\r
+                               DataToggle,\r
+                               TimeOut,\r
+                               Translator,\r
+                               UsbResult\r
+                               );\r
+  } else {\r
+    IsSlowDevice = (EFI_USB_SPEED_LOW == DevSpeed) ? TRUE : FALSE;\r
+    Status = UsbBus->UsbHc->SyncInterruptTransfer (\r
+                              UsbBus->UsbHc,\r
+                              DevAddr,\r
+                              EpAddr,\r
+                              IsSlowDevice,\r
+                              (UINT8) MaxPacket,\r
+                              Data,\r
+                              DataLength,\r
+                              DataToggle,\r
+                              TimeOut,\r
+                              UsbResult\r
+                              );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute a synchronous Isochronous USB transfer\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  DevAddr          The target device address\r
+  @param  EpAddr           The target endpoint address, with direction encoded in\r
+                           bit 7\r
+  @param  DevSpeed         The device's speed\r
+  @param  MaxPacket        The endpoint's max packet size\r
+  @param  BufferNum        The number of data buffer\r
+  @param  Data             Array of pointers to data buffer\r
+  @param  DataLength       The length of data buffer\r
+  @param  Translator       The transaction translator for low/full speed device\r
+  @param  UsbResult        The result of USB execution\r
+\r
+  @retval EFI_UNSUPPORTED  The isochronous transfer isn't supported now\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcIsochronousTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  UINT8                               BufferNum,\r
+  IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Queue an asynchronous isochronous transfer\r
+\r
+  @param  UsbBus           The USB bus driver\r
+  @param  DevAddr          The target device address\r
+  @param  EpAddr           The target endpoint address, with direction encoded in\r
+                           bit 7\r
+  @param  DevSpeed         The device's speed\r
+  @param  MaxPacket        The endpoint's max packet size\r
+  @param  BufferNum        The number of data buffer\r
+  @param  Data             Array of pointers to data buffer\r
+  @param  DataLength       The length of data buffer\r
+  @param  Translator       The transaction translator for low/full speed device\r
+  @param  Callback         The function to call when data is transferred\r
+  @param  Context          The context to the callback function\r
+\r
+  @retval EFI_UNSUPPORTED  The asynchronous isochronous transfer isn't supported\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcAsyncIsochronousTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  UINT8                               BufferNum,\r
+  IN OUT VOID                             *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     Callback,\r
+  IN  VOID                                *Context\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Open the USB host controller protocol BY_CHILD\r
+\r
+  @param  Bus              The USB bus driver\r
+  @param  Child            The child handle\r
+\r
+  @return The open protocol return\r
+\r
+**/\r
+EFI_STATUS\r
+UsbOpenHostProtoByChild (\r
+  IN USB_BUS              *Bus,\r
+  IN EFI_HANDLE           Child\r
+  )\r
+{\r
+  EFI_USB_HC_PROTOCOL     *UsbHc;\r
+  EFI_USB2_HC_PROTOCOL    *Usb2Hc;\r
+  EFI_STATUS              Status;\r
+\r
+  if (Bus->Usb2Hc != NULL) {\r
+    Status = gBS->OpenProtocol (\r
+                    Bus->HostHandle,\r
+                    &gEfiUsb2HcProtocolGuid,\r
+                    &Usb2Hc,\r
+                    mUsbBusDriverBinding.DriverBindingHandle,\r
+                    Child,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+\r
+  } else {\r
+    Status = gBS->OpenProtocol (\r
+                    Bus->HostHandle,\r
+                    &gEfiUsbHcProtocolGuid,\r
+                    &UsbHc,\r
+                    mUsbBusDriverBinding.DriverBindingHandle,\r
+                    Child,\r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                    );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Close the USB host controller protocol BY_CHILD\r
+\r
+  @param  Bus              The USB bus driver\r
+  @param  Child            The child handle\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UsbCloseHostProtoByChild (\r
+  IN USB_BUS              *Bus,\r
+  IN EFI_HANDLE           Child\r
+  )\r
+{\r
+  if (Bus->Usb2Hc != NULL) {\r
+    gBS->CloseProtocol (\r
+           Bus->HostHandle,\r
+           &gEfiUsb2HcProtocolGuid,\r
+           mUsbBusDriverBinding.DriverBindingHandle,\r
+           Child\r
+           );\r
+\r
+  } else {\r
+    gBS->CloseProtocol (\r
+           Bus->HostHandle,\r
+           &gEfiUsbHcProtocolGuid,\r
+           mUsbBusDriverBinding.DriverBindingHandle,\r
+           Child\r
+           );\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  return the current TPL, copied from the EDKII glue lib.\r
+\r
+  VOID\r
+\r
+  @return Current TPL\r
+\r
+**/\r
+EFI_TPL\r
+UsbGetCurrentTpl (\r
+  VOID\r
+  )\r
+{\r
+  EFI_TPL                 Tpl;\r
+\r
+  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+  gBS->RestoreTPL (Tpl);\r
+\r
+  return Tpl;\r
+}\r
+\r
+\r
+#ifdef EFI_DEBUG\r
+VOID\r
+UsbDebug (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  USB's debug output function.\r
+\r
+Arguments:\r
+\r
+  Format  - The format parameters to the print\r
+  ...     - The variable length parameters after format\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+  DebugVPrint (DEBUG_INFO, Format, Marker);\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+\r
+/**\r
+  USB's error output function.\r
+\r
+  @param  Format           The format parameters to the print\r
+  @param  ...              The variable length parameters after format\r
+\r
+  @return None\r
+\r
+**/\r
+VOID\r
+UsbError (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST                 Marker;\r
+\r
+  VA_START (Marker, Format);\r
+  DebugVPrint (DEBUG_ERROR, Format, Marker);\r
+  VA_END (Marker);\r
+}\r
+\r
+#endif\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.h
new file mode 100644 (file)
index 0000000..2dafd1c
--- /dev/null
@@ -0,0 +1,220 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbUtility.h\r
+\r
+  Abstract:\r
+\r
+    Manage Usb Port/Hc/Etc\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _USB_UTILITY_H\r
+#define _USB_UTILITY_H\r
+\r
+EFI_STATUS\r
+UsbHcGetCapability (\r
+  IN  USB_BUS             *UsbBus,\r
+  OUT UINT8               *MaxSpeed,\r
+  OUT UINT8               *NumOfPort,\r
+  OUT UINT8               *Is64BitCapable\r
+  );\r
+\r
+EFI_STATUS\r
+UsbHcReset (\r
+  IN USB_BUS              *UsbBus,\r
+  IN UINT16               Attributes\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcGetState (\r
+  IN  USB_BUS             *UsbBus,\r
+  OUT EFI_USB_HC_STATE    *State\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcSetState (\r
+  IN  USB_BUS             *UsbBus,\r
+  IN EFI_USB_HC_STATE     State\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcGetRootHubPortStatus (\r
+  IN  USB_BUS             *UsbBus,\r
+  IN  UINT8               PortIndex,\r
+  OUT EFI_USB_PORT_STATUS *PortStatus\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcSetRootHubPortFeature (\r
+  IN USB_BUS              *UsbBus,\r
+  IN UINT8                PortIndex,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcClearRootHubPortFeature (\r
+  IN USB_BUS              *UsbBus,\r
+  IN UINT8                PortIndex,\r
+  IN EFI_USB_PORT_FEATURE Feature\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcControlTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  EFI_USB_DEVICE_REQUEST              *Request,\r
+  IN  EFI_USB_DATA_DIRECTION              Direction,\r
+  IN  OUT VOID                            *Data,\r
+  IN  OUT UINTN                           *DataLength,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcBulkTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  UINT8                               BufferNum,\r
+  IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
+  IN  OUT UINTN                           *DataLength,\r
+  IN  OUT UINT8                           *DataToggle,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcAsyncInterruptTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  BOOLEAN                             IsNewTransfer,\r
+  IN OUT UINT8                            *DataToggle,\r
+  IN  UINTN                               PollingInterval,\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     Callback,\r
+  IN  VOID                                *Context OPTIONAL\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcSyncInterruptTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN OUT VOID                             *Data,\r
+  IN OUT UINTN                            *DataLength,\r
+  IN OUT UINT8                            *DataToggle,\r
+  IN  UINTN                               TimeOut,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcIsochronousTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  UINT8                               BufferNum,\r
+  IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  OUT UINT32                              *UsbResult\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbHcAsyncIsochronousTransfer (\r
+  IN  USB_BUS                             *UsbBus,\r
+  IN  UINT8                               DevAddr,\r
+  IN  UINT8                               EpAddr,\r
+  IN  UINT8                               DevSpeed,\r
+  IN  UINTN                               MaxPacket,\r
+  IN  UINT8                               BufferNum,\r
+  IN OUT VOID                             *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
+  IN  UINTN                               DataLength,\r
+  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
+  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     Callback,\r
+  IN  VOID                                *Context\r
+  );\r
+\r
+\r
+EFI_STATUS\r
+UsbOpenHostProtoByChild (\r
+  IN USB_BUS              *Bus,\r
+  IN EFI_HANDLE           Child\r
+  );\r
+\r
+\r
+VOID\r
+UsbCloseHostProtoByChild (\r
+  IN USB_BUS              *Bus,\r
+  IN EFI_HANDLE           Child\r
+  );\r
+\r
+\r
+EFI_TPL\r
+UsbGetCurrentTpl (\r
+  VOID\r
+  );\r
+\r
+//\r
+// USB debug support routines\r
+//\r
+#ifdef EFI_DEBUG\r
+  #define USB_DEBUG(arg)            UsbDebug arg\r
+  #define USB_ERROR(arg)            UsbError arg\r
+#else\r
+  #define USB_DEBUG(arg)\r
+  #define USB_ERROR(arg)\r
+#endif\r
+\r
+VOID\r
+UsbDebug (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  );\r
+\r
+\r
+VOID\r
+UsbError (\r
+  IN  CHAR8               *Format,\r
+  ...\r
+  );\r
+#endif\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c
new file mode 100644 (file)
index 0000000..c5a0604
--- /dev/null
@@ -0,0 +1,1384 @@
+/** @file\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbBus.c\r
+\r
+  Abstract:\r
+\r
+    Usb Bus Driver Binding and Bus IO Protocol\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#include "UsbBus.h"\r
+\r
+//\r
+// USB_BUS_PROTOCOL is only used to locate USB_BUS\r
+//\r
+EFI_GUID  mUsbBusProtocolGuid = EFI_USB_BUS_PROTOCOL_GUID;\r
+\r
+\r
+/**\r
+  USB_IO function to execute a control transfer. This\r
+  function will execute the USB transfer. If transfer\r
+  successes, it will sync the internal state of USB bus\r
+  with device state.\r
+\r
+  @param  This                   The USB_IO instance\r
+  @param  Request                The control transfer request\r
+  @param  Direction              Direction for data stage\r
+  @param  Timeout                The time to wait before timeout\r
+  @param  Data                   The buffer holding the data\r
+  @param  DataLength             Then length of the data\r
+  @param  UsbStatus              USB result\r
+\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid\r
+  @retval EFI_SUCCESS            The control transfer succeded.\r
+  @retval Others                 Failed to execute the transfer\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoControlTransfer (\r
+  IN  EFI_USB_IO_PROTOCOL     *This,\r
+  IN  EFI_USB_DEVICE_REQUEST  *Request,\r
+  IN  EFI_USB_DATA_DIRECTION  Direction,\r
+  IN  UINT32                  Timeout,\r
+  IN  OUT VOID                *Data,      OPTIONAL\r
+  IN  UINTN                   DataLength, OPTIONAL\r
+  OUT UINT32                  *UsbStatus\r
+  )\r
+{\r
+  USB_DEVICE              *Dev;\r
+  USB_INTERFACE           *UsbIf;\r
+  USB_ENDPOINT_DESC       *EpDesc;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+\r
+  if (UsbStatus == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev    = UsbIf->Device;\r
+\r
+  Status = UsbHcControlTransfer (\r
+             Dev->Bus,\r
+             Dev->Address,\r
+             Dev->Speed,\r
+             Dev->MaxPacket0,\r
+             Request,\r
+             Direction,\r
+             Data,\r
+             &DataLength,\r
+             (UINTN) Timeout,\r
+             &Dev->Translator,\r
+             UsbStatus\r
+             );\r
+\r
+  if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
+    //\r
+    // Clear TT buffer when CTRL/BULK split transaction failes\r
+    // Clear the TRANSLATOR TT buffer, not parent's buffer\r
+    //\r
+    if (Dev->Translator.TranslatorHubAddress != 0) {\r
+      UsbHubCtrlClearTTBuffer (\r
+        Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
+        Dev->Translator.TranslatorPortNumber,\r
+        Dev->Address,\r
+        0,\r
+        USB_ENDPOINT_CONTROL\r
+        );\r
+    }\r
+\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Some control transfer will change the device's internal\r
+  // status, such as Set_Configuration and Set_Interface.\r
+  // We must synchronize the bus driver's status with that in\r
+  // device. We ignore the Set_Descriptor request because it's\r
+  // hardly used by any device, especially in pre-boot environment\r
+  //\r
+\r
+  //\r
+  // Reset the endpoint toggle when endpoint stall is cleared\r
+  //\r
+  if ((Request->Request     == USB_REQ_CLEAR_FEATURE) &&\r
+      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r
+                                                 USB_TARGET_ENDPOINT)) &&\r
+      (Request->Value       == USB_FEATURE_ENDPOINT_HALT)) {\r
+\r
+    EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index);\r
+\r
+    if (EpDesc != NULL) {\r
+      EpDesc->Toggle = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Select a new configuration. This is a dangerous action. Upper driver\r
+  // should stop use its current UsbIo after calling this driver. The old\r
+  // UsbIo will be uninstalled and new UsbIo be installed. We can't use\r
+  // ReinstallProtocol since interfaces in different configuration may be\r
+  // completely irrellvant.\r
+  //\r
+  if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
+      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r
+                                                 USB_TARGET_DEVICE))) {\r
+    //\r
+    // Don't re-create the USB interfaces if configuration isn't changed.\r
+    //\r
+    if ((Dev->ActiveConfig != NULL) &&\r
+        (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) {\r
+\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    USB_DEBUG (("UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r
+\r
+    if (Dev->ActiveConfig != NULL) {\r
+      UsbRemoveConfig (Dev);\r
+    }\r
+\r
+    if (Request->Value != 0) {\r
+      Status = UsbSelectConfig (Dev, (UINT8) Request->Value);\r
+    }\r
+\r
+    //\r
+    // Exit now, Old USB_IO is invalid now\r
+    //\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // A new alternative setting is selected for the interface.\r
+  // No need to reinstall UsbIo in this case because only\r
+  // underlying communication endpoints are changed. Functionality\r
+  // should remains the same.\r
+  //\r
+  if ((Request->Request     == USB_REQ_SET_INTERFACE) &&\r
+      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,\r
+                                                 USB_TARGET_INTERFACE)) &&\r
+      (Request->Index       == UsbIf->IfSetting->Desc.InterfaceNumber)) {\r
+\r
+    Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute a bulk transfer to the device endpoint\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  Endpoint               The device endpoint\r
+  @param  Data                   The data to transfer\r
+  @param  DataLength             The length of the data to transfer\r
+  @param  Timeout                Time to wait before timeout\r
+  @param  UsbStatus              The result of USB transfer\r
+\r
+  @retval EFI_SUCCESS            The bulk transfer is OK\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
+  @retval Others                 Failed to execute transfer, reason returned in\r
+                                 UsbStatus\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoBulkTransfer (\r
+  IN  EFI_USB_IO_PROTOCOL *This,\r
+  IN  UINT8               Endpoint,\r
+  IN  OUT VOID            *Data,\r
+  IN  OUT UINTN           *DataLength,\r
+  IN  UINTN               Timeout,\r
+  OUT UINT32              *UsbStatus\r
+  )\r
+{\r
+  USB_DEVICE              *Dev;\r
+  USB_INTERFACE           *UsbIf;\r
+  USB_ENDPOINT_DESC       *EpDesc;\r
+  UINT8                   BufNum;\r
+  UINT8                   Toggle;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+\r
+  if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||\r
+      (UsbStatus == NULL)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf   = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev     = UsbIf->Device;\r
+\r
+  EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);\r
+\r
+  if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  BufNum  = 1;\r
+  Toggle  = EpDesc->Toggle;\r
+  Status  = UsbHcBulkTransfer (\r
+              Dev->Bus,\r
+              Dev->Address,\r
+              Endpoint,\r
+              Dev->Speed,\r
+              EpDesc->Desc.MaxPacketSize,\r
+              BufNum,\r
+              &Data,\r
+              DataLength,\r
+              &Toggle,\r
+              Timeout,\r
+              &Dev->Translator,\r
+              UsbStatus\r
+              );\r
+\r
+  EpDesc->Toggle = Toggle;\r
+\r
+  if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {\r
+    //\r
+    // Clear TT buffer when CTRL/BULK split transaction failes.\r
+    // Clear the TRANSLATOR TT buffer, not parent's buffer\r
+    //\r
+    if (Dev->Translator.TranslatorHubAddress != 0) {\r
+      UsbHubCtrlClearTTBuffer (\r
+        Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],\r
+        Dev->Translator.TranslatorPortNumber,\r
+        Dev->Address,\r
+        0,\r
+        USB_ENDPOINT_BULK\r
+        );\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute a synchronous interrupt transfer\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  Endpoint               The device endpoint\r
+  @param  Data                   The data to transfer\r
+  @param  DataLength             The length of the data to transfer\r
+  @param  Timeout                Time to wait before timeout\r
+  @param  UsbStatus              The result of USB transfer\r
+\r
+  @retval EFI_SUCCESS            The synchronous interrupt transfer is OK\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
+  @retval Others                 Failed to execute transfer, reason returned in\r
+                                 UsbStatus\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoSyncInterruptTransfer (\r
+  IN  EFI_USB_IO_PROTOCOL *This,\r
+  IN  UINT8               Endpoint,\r
+  IN  OUT VOID            *Data,\r
+  IN  OUT UINTN           *DataLength,\r
+  IN  UINTN               Timeout,\r
+  OUT UINT32              *UsbStatus\r
+  )\r
+{\r
+  USB_DEVICE              *Dev;\r
+  USB_INTERFACE           *UsbIf;\r
+  USB_ENDPOINT_DESC       *EpDesc;\r
+  EFI_TPL                 OldTpl;\r
+  UINT8                   Toggle;\r
+  EFI_STATUS              Status;\r
+\r
+  if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||\r
+      (UsbStatus == NULL)) {\r
+\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf   = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev     = UsbIf->Device;\r
+\r
+  EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);\r
+\r
+  if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Toggle = EpDesc->Toggle;\r
+  Status = UsbHcSyncInterruptTransfer (\r
+             Dev->Bus,\r
+             Dev->Address,\r
+             Endpoint,\r
+             Dev->Speed,\r
+             EpDesc->Desc.MaxPacketSize,\r
+             Data,\r
+             DataLength,\r
+             &Toggle,\r
+             Timeout,\r
+             &Dev->Translator,\r
+             UsbStatus\r
+             );\r
+\r
+  EpDesc->Toggle = Toggle;\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Queue a new asynchronous interrupt transfer, or remove the old\r
+  request if (IsNewTransfer == FALSE)\r
+\r
+  @param  This                   The USB_IO instance\r
+  @param  Endpoint               The device endpoint\r
+  @param  IsNewTransfer          Whether this is a new request, if it's old, remove\r
+                                 the request\r
+  @param  PollInterval           The interval to poll the transfer result, (in ms)\r
+  @param  DataLength             The length of perodic data transfer\r
+  @param  Callback               The function to call periodicaly when transfer is\r
+                                 ready\r
+  @param  Context                The context to the callback\r
+\r
+  @retval EFI_SUCCESS            New transfer is queued or old request is removed\r
+  @retval EFI_INVALID_PARAMETER  Some parameters are invalid\r
+  @retval Others                 Failed to queue the new request or remove the old\r
+                                 request\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoAsyncInterruptTransfer (\r
+  IN EFI_USB_IO_PROTOCOL              *This,\r
+  IN UINT8                            Endpoint,\r
+  IN BOOLEAN                          IsNewTransfer,\r
+  IN UINTN                            PollInterval,       OPTIONAL\r
+  IN UINTN                            DataLength,         OPTIONAL\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK  Callback,           OPTIONAL\r
+  IN VOID                             *Context            OPTIONAL\r
+  )\r
+{\r
+  USB_DEVICE              *Dev;\r
+  USB_INTERFACE           *UsbIf;\r
+  USB_ENDPOINT_DESC       *EpDesc;\r
+  EFI_TPL                 OldTpl;\r
+  UINT8                   Toggle;\r
+  EFI_STATUS              Status;\r
+\r
+  if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
+  UsbIf   = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev     = UsbIf->Device;\r
+\r
+  EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);\r
+\r
+  if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Toggle  = EpDesc->Toggle;\r
+  Status  = UsbHcAsyncInterruptTransfer (\r
+              Dev->Bus,\r
+              Dev->Address,\r
+              Endpoint,\r
+              Dev->Speed,\r
+              EpDesc->Desc.MaxPacketSize,\r
+              IsNewTransfer,\r
+              &Toggle,\r
+              PollInterval,\r
+              DataLength,\r
+              &Dev->Translator,\r
+              Callback,\r
+              Context\r
+              );\r
+\r
+  EpDesc->Toggle = Toggle;\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute a synchronous isochronous transfer\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  DeviceEndpoint         The device endpoint\r
+  @param  Data                   The data to transfer\r
+  @param  DataLength             The length of the data to transfer\r
+  @param  UsbStatus              The result of USB transfer\r
+\r
+  @retval EFI_UNSUPPORTED        Currently isochronous transfer isn't supported\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoIsochronousTransfer (\r
+  IN  EFI_USB_IO_PROTOCOL *This,\r
+  IN  UINT8               DeviceEndpoint,\r
+  IN  OUT VOID            *Data,\r
+  IN  UINTN               DataLength,\r
+  OUT UINT32              *Status\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Queue an asynchronous isochronous transfer\r
+\r
+  @param  This                   The USB_IO instance\r
+  @param  DeviceEndpoint         The device endpoint\r
+  @param  DataLength             The length of perodic data transfer\r
+  @param  IsochronousCallBack    The function to call periodicaly when transfer is\r
+                                 ready\r
+  @param  Context                The context to the callback\r
+\r
+  @retval EFI_UNSUPPORTED        Currently isochronous transfer isn't supported\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoAsyncIsochronousTransfer (\r
+  IN EFI_USB_IO_PROTOCOL              *This,\r
+  IN UINT8                            DeviceEndpoint,\r
+  IN OUT VOID                         *Data,\r
+  IN UINTN                            DataLength,\r
+  IN EFI_ASYNC_USB_TRANSFER_CALLBACK  IsochronousCallBack,\r
+  IN VOID                             *Context              OPTIONAL\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  Retrieve the device descriptor of the device\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  Descriptor             The variable to receive the device descriptor\r
+\r
+  @retval EFI_SUCCESS            The device descriptor is returned\r
+  @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoGetDeviceDescriptor (\r
+  IN  EFI_USB_IO_PROTOCOL       *This,\r
+  OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor\r
+  )\r
+{\r
+  USB_DEVICE              *Dev;\r
+  USB_INTERFACE           *UsbIf;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  if (Descriptor == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev    = UsbIf->Device;\r
+\r
+  CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the configuration descriptor of the current active configuration\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  Descriptor             The USB configuration descriptor\r
+\r
+  @retval EFI_SUCCESS            The active configuration descriptor is returned\r
+  @retval EFI_INVALID_PARAMETER  Some parameter is invalid\r
+  @retval EFI_NOT_FOUND          Currently no active configuration is selected.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoGetActiveConfigDescriptor (\r
+  IN  EFI_USB_IO_PROTOCOL       *This,\r
+  OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor\r
+  )\r
+{\r
+  USB_DEVICE              *Dev;\r
+  USB_INTERFACE           *UsbIf;\r
+  EFI_STATUS              Status;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  if (Descriptor == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev    = UsbIf->Device;\r
+\r
+  if (Dev->ActiveConfig == NULL) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Retrieve the active interface setting descriptor for this USB IO instance\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  Descriptor             The variable to receive active interface setting\r
+\r
+  @retval EFI_SUCCESS            The active interface setting is returned\r
+  @retval EFI_INVALID_PARAMETER  Some parameter is invalid\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoGetInterfaceDescriptor (\r
+  IN  EFI_USB_IO_PROTOCOL           *This,\r
+  OUT EFI_USB_INTERFACE_DESCRIPTOR  *Descriptor\r
+  )\r
+{\r
+  USB_INTERFACE           *UsbIf;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  if (Descriptor == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
+  CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Retrieve the endpoint descriptor from this interface setting\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  Index                  The index (start from zero) of the endpoint to\r
+                                 retrieve\r
+  @param  Descriptor             The variable to receive the descriptor\r
+\r
+  @retval EFI_SUCCESS            The endpoint descriptor is returned\r
+  @retval EFI_INVALID_PARAMETER  Some parameter is invalid\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoGetEndpointDescriptor (\r
+  IN  EFI_USB_IO_PROTOCOL         *This,\r
+  IN  UINT8                       Index,\r
+  OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor\r
+  )\r
+{\r
+  USB_INTERFACE           *UsbIf;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
+\r
+  if ((Descriptor == NULL) || (Index >= UsbIf->IfSetting->Desc.NumEndpoints)) {\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CopyMem (\r
+    Descriptor,\r
+    &(UsbIf->IfSetting->Endpoints[Index]->Desc),\r
+    sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r
+    );\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Retrieve the supported language ID table from the device\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  LangIDTable            The table to return the language IDs\r
+  @param  TableSize              The number of supported languanges\r
+\r
+  @retval EFI_SUCCESS            The language ID is return\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoGetSupportedLanguages (\r
+  IN  EFI_USB_IO_PROTOCOL *This,\r
+  OUT UINT16              **LangIDTable,\r
+  OUT UINT16              *TableSize\r
+  )\r
+{\r
+  USB_DEVICE              *Dev;\r
+  USB_INTERFACE           *UsbIf;\r
+  EFI_TPL                 OldTpl;\r
+\r
+  OldTpl        = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf         = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev           = UsbIf->Device;\r
+\r
+  *LangIDTable  = Dev->LangId;\r
+  *TableSize    = Dev->TotalLangId;\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Retrieve an indexed string in the language of LangID\r
+\r
+  @param  This                   The USB IO instance\r
+  @param  LangID                 The language ID of the string to retrieve\r
+  @param  StringIndex            The index of the string\r
+  @param  String                 The variable to receive the string\r
+\r
+  @retval EFI_SUCCESS            The string is returned\r
+  @retval EFI_NOT_FOUND          No such string existed\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoGetStringDescriptor (\r
+  IN  EFI_USB_IO_PROTOCOL   *This,\r
+  IN  UINT16                LangID,\r
+  IN  UINT8                 StringIndex,\r
+  OUT CHAR16                **String\r
+  )\r
+{\r
+  USB_DEVICE                *Dev;\r
+  USB_INTERFACE             *UsbIf;\r
+  EFI_USB_STRING_DESCRIPTOR *StrDesc;\r
+  EFI_TPL                   OldTpl;\r
+  UINT8                     *Buf;\r
+  UINT8                     Index;\r
+  EFI_STATUS                Status;\r
+\r
+  if ((StringIndex == 0) || (LangID == 0)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev    = UsbIf->Device;\r
+\r
+  //\r
+  // Check whether language ID is supported\r
+  //\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  for (Index = 0; Index < Dev->TotalLangId; Index++) {\r
+    if (Dev->LangId[Index] == LangID) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == Dev->TotalLangId) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Retrieve the string descriptor then allocate a buffer\r
+  // to hold the string itself.\r
+  //\r
+  StrDesc = UsbGetOneString (Dev, StringIndex, LangID);\r
+\r
+  if (StrDesc == NULL) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (StrDesc->Length <= 2) {\r
+    goto FREE_STR;\r
+  }\r
+\r
+  Buf = AllocateZeroPool (StrDesc->Length);\r
+\r
+  if (Buf == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FREE_STR;\r
+  }\r
+\r
+  CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);\r
+  *String = (CHAR16 *) Buf;\r
+  Status  = EFI_SUCCESS;\r
+\r
+FREE_STR:\r
+  gBS->FreePool (StrDesc);\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reset the device, then if that succeeds, reconfigure the\r
+  device with its address and current active configuration.\r
+\r
+  @param  This                   The USB IO instance\r
+\r
+  @retval EFI_SUCCESS            The device is reset and configured\r
+  @retval Others                 Failed to reset the device\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UsbIoPortReset (\r
+  IN EFI_USB_IO_PROTOCOL  *This\r
+  )\r
+{\r
+  USB_INTERFACE           *UsbIf;\r
+  USB_INTERFACE           *HubIf;\r
+  USB_DEVICE              *Dev;\r
+  UINT8                   Address;\r
+  EFI_TPL                 OldTpl;\r
+  EFI_STATUS              Status;\r
+\r
+  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+  UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
+  Dev    = UsbIf->Device;\r
+\r
+  HubIf  = Dev->ParentIf;\r
+  Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbIoPortReset: failed to reset hub port %d@hub  %d, %r \n",\r
+                Dev->ParentPort, Dev->ParentAddr, Status));\r
+\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Reset the device to its current address. The device now has a\r
+  // address of ZERO, so need to set Dev->Address to zero first for\r
+  // host to communicate with the device\r
+  //\r
+  Address       = Dev->Address;\r
+  Dev->Address  = 0;\r
+  Status        = UsbSetAddress (Dev, Address);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbIoPortReset: failed to set address for device %d - %r\n",\r
+                Address, Status));\r
+\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Dev->Address  = Address;\r
+\r
+  //\r
+  // Reset the current active configure, after this device\r
+  // is in CONFIGURED state.\r
+  //\r
+  if (Dev->ActiveConfig != NULL) {\r
+    Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      USB_ERROR (("UsbIoPortReset: failed to set configure for device %d - %r\n",\r
+                  Address, Status));\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+  return Status;\r
+}\r
+\r
+EFI_USB_IO_PROTOCOL mUsbIoProtocol = {\r
+  UsbIoControlTransfer,\r
+  UsbIoBulkTransfer,\r
+  UsbIoAsyncInterruptTransfer,\r
+  UsbIoSyncInterruptTransfer,\r
+  UsbIoIsochronousTransfer,\r
+  UsbIoAsyncIsochronousTransfer,\r
+  UsbIoGetDeviceDescriptor,\r
+  UsbIoGetActiveConfigDescriptor,\r
+  UsbIoGetInterfaceDescriptor,\r
+  UsbIoGetEndpointDescriptor,\r
+  UsbIoGetStringDescriptor,\r
+  UsbIoGetSupportedLanguages,\r
+  UsbIoPortReset\r
+};\r
+\r
+//@MT: EFI_DRIVER_ENTRY_POINT (UsbBusDriverEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusDriverEntryPoint (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The USB bus driver entry pointer\r
+\r
+Arguments:\r
+\r
+  ImageHandle - The driver image handle\r
+  SystemTable - The system table\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - The component name protocol is installed\r
+  Others      - Failed to init the usb driver\r
+\r
+--*/\r
+{\r
+  return EfiLibInstallAllDriverProtocols (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &mUsbBusDriverBinding,\r
+           ImageHandle,\r
+           &mUsbBusComponentName,\r
+           NULL,\r
+           NULL\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Check whether USB bus driver support this device\r
+\r
+  @param  This                   The USB bus driver binding protocol\r
+  @param  Controller             The controller handle to test againist\r
+  @param  RemainingDevicePath    The remaining device path\r
+\r
+  @retval EFI_SUCCESS            The bus supports this controller.\r
+  @retval EFI_UNSUPPORTED        This device isn't supported\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusControllerDriverSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_DEV_PATH_PTR          DevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
+  EFI_USB2_HC_PROTOCOL      *Usb2Hc;\r
+  EFI_USB_HC_PROTOCOL       *UsbHc;\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // Check whether device path is valid\r
+  //\r
+  if (RemainingDevicePath != NULL) {\r
+    DevicePathNode.DevPath = RemainingDevicePath;\r
+\r
+    if ((DevicePathNode.DevPath->Type    != MESSAGING_DEVICE_PATH) ||\r
+        (DevicePathNode.DevPath->SubType != MSG_USB_DP) ||\r
+        (DevicePathNodeLength (DevicePathNode.DevPath) != sizeof (USB_DEVICE_PATH))) {\r
+\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiDevicePathProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  //\r
+  // Check whether USB_HC2 protocol is installed\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  (VOID **) &Usb2Hc,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiUsb2HcProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If failed to open USB_HC2, fall back to USB_HC\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsbHcProtocolGuid,\r
+                  (VOID **) &UsbHc,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiUsbHcProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start to process the controller\r
+\r
+  @param  This                   The USB bus driver binding instance\r
+  @param  Controller             The controller to check\r
+  @param  RemainingDevicePath    The remaining device patch\r
+\r
+  @retval EFI_SUCCESS            The controller is controlled by the usb bus\r
+  @retval EFI_ALREADY_STARTED    The controller is already controlled by the usb\r
+                                 bus\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusControllerDriverStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  USB_BUS                 *UsbBus;\r
+  USB_DEVICE              *RootHub;\r
+  USB_INTERFACE           *RootIf;\r
+  EFI_USB_BUS_PROTOCOL    *UsbBusId;\r
+  EFI_STATUS              Status;\r
+  EFI_STATUS              Status2;\r
+\r
+  //\r
+  // Locate the USB bus protocol, if it is found, USB bus\r
+  // is already started on this controller.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &mUsbBusProtocolGuid,\r
+                  (VOID **) &UsbBusId,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r
+\r
+  if (UsbBus == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  UsbBus->Signature   = USB_BUS_SIGNATURE;\r
+  UsbBus->HostHandle  = Controller;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &UsbBus->DevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbBusStart: Failed to open device path %r\n", Status));\r
+\r
+    gBS->FreePool (UsbBus);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
+  // This is for backward compatbility with EFI 1.x. In UEFI\r
+  // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r
+  // and USB_HC because EHCI driver will install both protocols\r
+  // (for the same reason). If we don't consume both of them,\r
+  // the unconsumed one may be opened by others.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  (VOID **) &(UsbBus->Usb2Hc),\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  Status2 = gBS->OpenProtocol (\r
+                   Controller,\r
+                   &gEfiUsbHcProtocolGuid,\r
+                   (VOID **) &(UsbBus->UsbHc),\r
+                   This->DriverBindingHandle,\r
+                   Controller,\r
+                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                   );\r
+\r
+  if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r
+    USB_ERROR (("UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto CLOSE_HC;\r
+  }\r
+\r
+  //\r
+  // Create a fake usb device for root hub\r
+  //\r
+  RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r
+\r
+  if (RootHub == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CLOSE_HC;\r
+  }\r
+\r
+  RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
+\r
+  if (RootIf == NULL) {\r
+    gBS->FreePool (RootHub);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto CLOSE_HC;\r
+  }\r
+\r
+  RootHub->Bus            = UsbBus;\r
+  RootHub->NumOfInterface = 1;\r
+  RootHub->Interfaces[0]  = RootIf;\r
+  RootIf->Signature       = USB_INTERFACE_SIGNATURE;\r
+  RootIf->Device          = RootHub;\r
+  RootIf->DevicePath      = UsbBus->DevicePath;\r
+\r
+  Status                  = mUsbRootHubApi.Init (RootIf);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbBusStart: Failed to init root hub %r\n", Status));\r
+    goto FREE_ROOTHUB;\r
+  }\r
+\r
+  UsbBus->Devices[0] = RootHub;\r
+\r
+  //\r
+  // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &mUsbBusProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &UsbBus->BusId\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    USB_ERROR (("UsbBusStart: Failed to install bus protocol %r\n", Status));\r
+\r
+    mUsbRootHubApi.Release (RootIf);\r
+    goto FREE_ROOTHUB;\r
+  }\r
+\r
+  UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
+  UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
+\r
+  USB_DEBUG (("UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf));\r
+  return EFI_SUCCESS;\r
+\r
+FREE_ROOTHUB:\r
+  gBS->FreePool (RootIf);\r
+  gBS->FreePool (RootHub);\r
+\r
+CLOSE_HC:\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiUsb2HcProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  }\r
+\r
+  if (UsbBus->UsbHc != NULL) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiUsbHcProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiDevicePathProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  gBS->FreePool (UsbBus);\r
+\r
+  USB_ERROR (("UsbBusStart: Failed to start bus driver %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop handle the controller by this USB bus driver\r
+\r
+  @param  This                   The USB bus driver binding protocol\r
+  @param  Controller             The controller to release\r
+  @param  NumberOfChildren       The child of USB bus that opened controller\r
+                                 BY_CHILD\r
+  @param  ChildHandleBuffer      The array of child handle\r
+\r
+  @retval EFI_SUCCESS            The controller or children are stopped\r
+  @retval EFI_DEVICE_ERROR       Failed to stop the driver\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusControllerDriverStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+{\r
+  USB_BUS               *Bus;\r
+  USB_DEVICE            *RootHub;\r
+  USB_DEVICE            *UsbDev;\r
+  USB_INTERFACE         *RootIf;\r
+  USB_INTERFACE         *UsbIf;\r
+  EFI_USB_BUS_PROTOCOL  *BusId;\r
+  EFI_USB_IO_PROTOCOL   *UsbIo;\r
+  EFI_TPL               OldTpl;\r
+  UINTN                 Index;\r
+  EFI_STATUS            Status;\r
+\r
+  Status  = EFI_SUCCESS;\r
+\r
+  if (NumberOfChildren > 0) {\r
+    OldTpl   = gBS->RaiseTPL (USB_BUS_TPL);\r
+\r
+    for (Index = 0; Index < NumberOfChildren; Index++) {\r
+      Status = gBS->OpenProtocol (\r
+                      ChildHandleBuffer[Index],\r
+                      &gEfiUsbIoProtocolGuid,\r
+                      (VOID **) &UsbIo,\r
+                      This->DriverBindingHandle,\r
+                      Controller,\r
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                      );\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // It is possible that the child has already been released:\r
+        // 1. For combo device, free one device will release others.\r
+        // 2. If a hub is released, all devices on its down facing\r
+        //    ports are released also.\r
+        //\r
+        continue;\r
+      }\r
+\r
+      UsbIf   = USB_INTERFACE_FROM_USBIO (UsbIo);\r
+      UsbDev  = UsbIf->Device;\r
+\r
+      UsbRemoveDevice (UsbDev);\r
+    }\r
+\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  USB_DEBUG (("UsbBusStop: usb bus stopped on %x\n", Controller));\r
+\r
+  //\r
+  // Locate USB_BUS for the current host controller\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &mUsbBusProtocolGuid,\r
+                  (VOID **) &BusId,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Bus = USB_BUS_FROM_THIS (BusId);\r
+\r
+  //\r
+  // Stop the root hub, then free all the devices\r
+  //\r
+  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
+  UsbHcSetState (Bus, EfiUsbHcStateHalt);\r
+\r
+  RootHub = Bus->Devices[0];\r
+  RootIf  = RootHub->Interfaces[0];\r
+\r
+  mUsbRootHubApi.Release (RootIf);\r
+\r
+  for (Index = 1; Index < USB_MAX_DEVICES; Index++) {\r
+    if (Bus->Devices[Index] != NULL) {\r
+      UsbRemoveDevice (Bus->Devices[Index]);\r
+    }\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  gBS->FreePool   (RootIf);\r
+  gBS->FreePool   (RootHub);\r
+\r
+  //\r
+  // Uninstall the bus identifier and close USB_HC/USB2_HC protocols\r
+  //\r
+  gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &Bus->BusId);\r
+\r
+  if (Bus->Usb2Hc != NULL) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiUsb2HcProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  if (Bus->UsbHc != NULL) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiUsbHcProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiDevicePathProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  gBS->FreePool (Bus);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {\r
+  UsbBusControllerDriverSupported,\r
+  UsbBusControllerDriverStart,\r
+  UsbBusControllerDriverStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h b/edk2/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h
new file mode 100644 (file)
index 0000000..2ecc2c8
--- /dev/null
@@ -0,0 +1,210 @@
+/** @file\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:\r
+\r
+    UsbBus.h\r
+\r
+  Abstract:\r
+\r
+    Usb Bus Driver Binding and Bus IO Protocol\r
+\r
+  Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _EFI_USB_BUS_H_\r
+#define _EFI_USB_BUS_H_\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/Usb2HostController.h>\r
+#include <Protocol/UsbHostController.h>\r
+#include <Protocol/UsbIo.h>\r
+#include <Protocol/DevicePath.h>\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+\r
+#include <IndustryStandard/Usb.h>\r
+\r
+typedef struct _USB_DEVICE     USB_DEVICE;\r
+typedef struct _USB_INTERFACE  USB_INTERFACE;\r
+typedef struct _USB_BUS        USB_BUS;\r
+typedef struct _USB_HUB_API    USB_HUB_API;\r
+\r
+\r
+#include "UsbUtility.h"\r
+#include "UsbDesc.h"\r
+#include "UsbHub.h"\r
+#include "UsbEnumer.h"\r
+\r
+enum {\r
+  //\r
+  // Time definition\r
+  //\r
+  USB_STALL_1_MS            = 1000,\r
+  TICKS_PER_MS              = 10000U,\r
+  USB_ROOTHUB_POLL_INTERVAL = 1000 * TICKS_PER_MS,\r
+  USB_HUB_POLL_INTERVAL     = 64,\r
+\r
+  //\r
+  // Maximum definition\r
+  //\r
+  USB_MAX_LANG_ID           = 16,\r
+  USB_MAX_INTERFACE         = 16,\r
+  USB_MAX_DEVICES           = 128,\r
+\r
+  //\r
+  // Bus raises TPL to TPL_NOTIFY to serialize all its operations\r
+  // to protect shared data structures.\r
+  //\r
+  USB_BUS_TPL               = TPL_NOTIFY,\r
+\r
+  USB_INTERFACE_SIGNATURE   = EFI_SIGNATURE_32 ('U', 'S', 'B', 'I'),\r
+  USB_BUS_SIGNATURE         = EFI_SIGNATURE_32 ('U', 'S', 'B', 'B'),\r
+};\r
+\r
+#define USB_BIT(a)                  ((UINTN)(1 << (a)))\r
+#define USB_BIT_IS_SET(Data, Bit)   ((BOOLEAN)(((Data) & (Bit)) == (Bit)))\r
+\r
+#define EFI_USB_BUS_PROTOCOL_GUID \\r
+          {0x2B2F68CC, 0x0CD2, 0x44cf, 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75}\r
+\r
+#define USB_INTERFACE_FROM_USBIO(a) \\r
+          CR(a, USB_INTERFACE, UsbIo, USB_INTERFACE_SIGNATURE)\r
+\r
+#define USB_BUS_FROM_THIS(a) \\r
+          CR(a, USB_BUS, BusId, USB_BUS_SIGNATURE)\r
+\r
+//\r
+// Used to locate USB_BUS\r
+//\r
+typedef struct _EFI_USB_BUS_PROTOCOL {\r
+  UINT64                    Reserved;\r
+} EFI_USB_BUS_PROTOCOL;\r
+\r
+\r
+//\r
+// Stands for the real USB device. Each device may\r
+// has several seperately working interfaces.\r
+//\r
+typedef struct _USB_DEVICE {\r
+  USB_BUS                   *Bus;\r
+\r
+  //\r
+  // Configuration information\r
+  //\r
+  UINT8                     Speed;\r
+  UINT8                     Address;\r
+  UINT8                     MaxPacket0;\r
+\r
+  //\r
+  // The device's descriptors and its configuration\r
+  //\r
+  USB_DEVICE_DESC           *DevDesc;\r
+  USB_CONFIG_DESC           *ActiveConfig;\r
+\r
+  UINT16                    LangId [USB_MAX_LANG_ID];\r
+  UINT16                    TotalLangId;\r
+\r
+  UINT8                     NumOfInterface;\r
+  USB_INTERFACE             *Interfaces [USB_MAX_INTERFACE];\r
+\r
+  //\r
+  // Parent child relationship\r
+  //\r
+  EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator;\r
+\r
+  UINT8                     ParentAddr;\r
+  USB_INTERFACE             *ParentIf;\r
+  UINT8                     ParentPort;       // Start at 0\r
+} USB_DEVICE;\r
+\r
+//\r
+// Stands for different functions of USB device\r
+//\r
+typedef struct _USB_INTERFACE {\r
+  UINTN                     Signature;\r
+  USB_DEVICE                *Device;\r
+  USB_INTERFACE_DESC        *IfDesc;\r
+  USB_INTERFACE_SETTING     *IfSetting;\r
+\r
+  //\r
+  // Handles and protocols\r
+  //\r
+  EFI_HANDLE                Handle;\r
+  EFI_USB_IO_PROTOCOL       UsbIo;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  BOOLEAN                   IsManaged;\r
+\r
+  //\r
+  // Hub device special data\r
+  //\r
+  BOOLEAN                   IsHub;\r
+  USB_HUB_API               *HubApi;\r
+  UINT8                     NumOfPort;\r
+  EFI_EVENT                 HubNotify;\r
+\r
+  //\r
+  // Data used only by normal hub devices\r
+  //\r
+  USB_ENDPOINT_DESC         *HubEp;\r
+  UINT8                     *ChangeMap;\r
+\r
+  //\r
+  // Data used only by root hub to hand over device to\r
+  // companion UHCI driver if low/full speed devices are\r
+  // connected to EHCI.\r
+  //\r
+  UINT8                     MaxSpeed;\r
+} USB_INTERFACE;\r
+\r
+//\r
+// Stands for the current USB Bus\r
+//\r
+typedef struct _USB_BUS {\r
+  UINTN                     Signature;\r
+  EFI_USB_BUS_PROTOCOL      BusId;\r
+\r
+  //\r
+  // Managed USB host controller\r
+  //\r
+  EFI_HANDLE                HostHandle;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_USB2_HC_PROTOCOL      *Usb2Hc;\r
+  EFI_USB_HC_PROTOCOL       *UsbHc;\r
+\r
+  //\r
+  // An array of device that is on the bus. Devices[0] is\r
+  // for root hub. Device with address i is at Devices[i].\r
+  //\r
+  USB_DEVICE                *Devices[USB_MAX_DEVICES];\r
+} USB_BUS;\r
+\r
+extern EFI_USB_IO_PROTOCOL           mUsbIoProtocol;\r
+extern EFI_DRIVER_BINDING_PROTOCOL   mUsbBusDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL   mUsbBusComponentName;\r
+\r
+#endif\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c b/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..bd0f939
--- /dev/null
@@ -0,0 +1,153 @@
+ /*++\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/UefiLib.h>\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+UsbMassStorageGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UsbMassStorageGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ChildHandle        OPTIONAL,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName = {\r
+  UsbMassStorageGetDriverName,\r
+  UsbMassStorageGetControllerName,\r
+  "eng"\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE\r
+mUsbMassStorageDriverNameTable[] = {\r
+  {"eng", L"Usb Mass Storage Driver"},\r
+  {NULL,  NULL}\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UsbMassStorageGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  Arguments:\r
+    This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    Language   - A pointer to a three character ISO 639-2 language identifier.\r
+                 This is the language of the driver name that that the caller\r
+                 is requesting, and it must match one of the languages specified\r
+                 in SupportedLanguages.  The number of languages supported by a\r
+                 driver is up to the driver writer.\r
+    DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+                 is the name of the driver specified by This in the language\r
+                 specified by Language.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the Driver specified by This\r
+                            and the language specified by Language was returned\r
+                            in DriverName.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - DriverName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the\r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString (\r
+           Language,\r
+           gUsbMassStorageComponentName.SupportedLanguages,\r
+           mUsbMassStorageDriverNameTable,\r
+           DriverName\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UsbMassStorageGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                  ControllerHandle,\r
+  IN  EFI_HANDLE                  ChildHandle        OPTIONAL,\r
+  IN  CHAR8                       *Language,\r
+  OUT CHAR16                      **ControllerName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the controller\r
+    that is being managed by an EFI Driver.\r
+\r
+  Arguments:\r
+    This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    ControllerHandle - The handle of a controller that the driver specified by\r
+                       This is managing.  This handle specifies the controller\r
+                       whose name is to be returned.\r
+    ChildHandle      - The handle of the child controller to retrieve the name\r
+                       of.  This is an optional parameter that may be NULL.  It\r
+                      will be NULL for device drivers.  It will also be NULL\r
+                       for a bus drivers that wish to retrieve the name of the\r
+                       bus controller.  It will not be NULL for a bus driver\r
+                       that wishes to retrieve the name of a child controller.\r
+    Language         - A pointer to a three character ISO 639-2 language\r
+                       identifier.  This is the language of the controller name\r
+                       that that the caller is requesting, and it must match one\r
+                       of the languages specified in SupportedLanguages.  The\r
+                       number of languages supported by a driver is up to the\r
+                       driver writer.\r
+    ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                       string is the name of the controller specified by\r
+                       ControllerHandle and ChildHandle in the language specified\r
+                       by Language from the point of view of the driver specified\r
+                       by This.\r
+\r
+  Returns:\r
+    EFI_UNSUPPORTED  - The driver specified by This does not support the\r
+                       language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h b/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h
new file mode 100644 (file)
index 0000000..c48dee5
--- /dev/null
@@ -0,0 +1,149 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UsbMass.h\r
+\r
+Abstract:\r
+\r
+  Defination for the USB mass storage class driver. The USB mass storage\r
+  class is specified in two layers: the bottom layer is the transportation\r
+  protocol. The top layer is the command set. The transportation layer\r
+  provides the transportation of the command, data and result. The command\r
+  set defines what the command, data and result. The Bulk-Only-Transport and\r
+  Control/Bulk/Interrupt transport are two transportation protocol. USB mass\r
+  storage class adopts various industrial standard as its command set.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _EFI_USBMASS_H_\r
+#define _EFI_USBMASS_H_\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/UsbIo.h>\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#define USB_IS_IN_ENDPOINT(EndPointAddr)      (((EndPointAddr) & 0x80) == 0x80)\r
+#define USB_IS_OUT_ENDPOINT(EndPointAddr)     (((EndPointAddr) & 0x80) == 0)\r
+#define USB_IS_BULK_ENDPOINT(Attribute)       (((Attribute) & 0x03) == 0x02)\r
+#define USB_IS_INTERRUPT_ENDPOINT(Attribute)  (((Attribute) & 0x03) == 0x03)\r
+#define USB_IS_ERROR(Result, Error)           (((Result) & (Error)) != 0)\r
+\r
+enum {\r
+  //\r
+  // Usb mass storage class code\r
+  //\r
+  USB_MASS_STORE_CLASS    = 0x08,\r
+\r
+  //\r
+  // Usb mass storage subclass code, specify the command set used.\r
+  //\r
+  USB_MASS_STORE_RBC      = 0x01, // Reduced Block Commands\r
+  USB_MASS_STORE_8020I    = 0x02, // SFF-8020i, typically a CD/DVD device\r
+  USB_MASS_STORE_QIC      = 0x03, // Typically a tape device\r
+  USB_MASS_STORE_UFI      = 0x04, // Typically a floopy disk driver device\r
+  USB_MASS_STORE_8070I    = 0x05, // SFF-8070i, typically a floppy disk driver device.\r
+  USB_MASS_STORE_SCSI     = 0x06, // SCSI transparent command set\r
+\r
+  //\r
+  // Usb mass storage protocol code, specify the transport protocol\r
+  //\r
+  USB_MASS_STORE_CBI0     = 0x00, // CBI protocol with command completion interrupt\r
+  USB_MASS_STORE_CBI1     = 0x01, // CBI protocol without command completion interrupt\r
+  USB_MASS_STORE_BOT      = 0x50, // Bulk-Only Transport\r
+\r
+  USB_MASS_STALL_1_MS     = 1000,\r
+  USB_MASS_STALL_1_S      = 1000 * USB_MASS_STALL_1_MS,\r
+\r
+  USB_MASS_CMD_SUCCESS    = 0,\r
+  USB_MASS_CMD_FAIL,\r
+  USB_MASS_CMD_PERSISTENT,\r
+};\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_MASS_INIT_TRANSPORT) (\r
+  IN  EFI_USB_IO_PROTOCOL     *Usb,\r
+  IN  EFI_HANDLE              Controller,\r
+  OUT VOID                    **Context    OPTIONAL\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_MASS_EXEC_COMMAND) (\r
+  IN  VOID                    *Context,\r
+  IN  VOID                    *Cmd,\r
+  IN  UINT8                   CmdLen,\r
+  IN  EFI_USB_DATA_DIRECTION  DataDir,\r
+  IN  VOID                    *Data,\r
+  IN  UINT32                  DataLen,\r
+  IN  UINT32                  Timeout,\r
+  OUT UINT32                  *CmdStatus\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_MASS_RESET) (\r
+  IN  VOID                    *Context,\r
+  IN  BOOLEAN                 ExtendedVerification\r
+  );\r
+\r
+typedef\r
+EFI_STATUS\r
+(*USB_MASS_FINI) (\r
+  IN  VOID                    *Context\r
+  );\r
+\r
+//\r
+// This structure contains information necessary to select the\r
+// proper transport protocol. The mass storage class defines\r
+// two transport protocols. One is the CBI, and the other is BOT.\r
+// CBI is being obseleted. The design is made modular by this\r
+// structure so that the CBI protocol can be easily removed when\r
+// it is no longer necessary.\r
+//\r
+typedef struct {\r
+  UINT8                   Protocol;\r
+  USB_MASS_INIT_TRANSPORT Init;        // Initialize the mass storage transport protocol\r
+  USB_MASS_EXEC_COMMAND   ExecCommand; // Transport command to the device then get result\r
+  USB_MASS_RESET          Reset;       // Reset the device\r
+  USB_MASS_FINI           Fini;        // Clean up the resources.\r
+} USB_MASS_TRANSPORT;\r
+\r
+\r
+EFI_STATUS\r
+UsbClearEndpointStall (\r
+  IN EFI_USB_IO_PROTOCOL      *UsbIo,\r
+  IN UINT8                    EndpointAddress\r
+  );\r
+\r
+extern UINTN mUsbMscInfo;\r
+extern UINTN mUsbMscError;\r
+#endif\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c b/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c
new file mode 100644 (file)
index 0000000..980f8b2
--- /dev/null
@@ -0,0 +1,886 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UsbMassBoot.c\r
+\r
+Abstract:\r
+\r
+  This file implement the command set of "USB Mass Storage Specification\r
+  for Bootability".\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#include "UsbMassImpl.h"\r
+\r
+\r
+/**\r
+  Read an UINT32 from the buffer to avoid byte alignment problems, then\r
+  convert that to the little endia. The USB mass storage bootability spec\r
+  use big endia\r
+\r
+  @param  Buf                    The buffer contains the first byte of the UINT32\r
+                                 in big endia.\r
+\r
+  @return The UINT32 value read from the buffer in little endia.\r
+\r
+**/\r
+STATIC\r
+UINT32\r
+UsbBootGetUint32 (\r
+  IN UINT8                  *Buf\r
+  )\r
+{\r
+  UINT32                    Value;\r
+\r
+  CopyMem (&Value, Buf, sizeof (UINT32));\r
+  return USB_BOOT_SWAP32 (Value);\r
+}\r
+\r
+\r
+/**\r
+  Put an UINT32 in little endia to the buffer. The data is converted to\r
+  big endia before writing.\r
+\r
+  @param  Buf                    The buffer to write data to\r
+  @param  Data32                 The data to write.\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbBootPutUint32 (\r
+  IN UINT8                  *Buf,\r
+  IN UINT32                 Data32\r
+  )\r
+{\r
+  Data32 = USB_BOOT_SWAP32 (Data32);\r
+  CopyMem (Buf, &Data32, sizeof (UINT32));\r
+}\r
+\r
+\r
+/**\r
+  Put an UINT16 in little endia to the buffer. The data is converted to\r
+  big endia before writing.\r
+\r
+  @param  Buf                    The buffer to write data to\r
+  @param  Data16                 The data to write\r
+\r
+  @return None\r
+\r
+**/\r
+STATIC\r
+VOID\r
+UsbBootPutUint16 (\r
+  IN UINT8                   *Buf,\r
+  IN UINT16                  Data16\r
+  )\r
+{\r
+  Data16 = USB_BOOT_SWAP16 (Data16);\r
+  CopyMem (Buf, &Data16, sizeof (UINT16));\r
+}\r
+\r
+\r
+/**\r
+  Request sense information via sending Request Sense\r
+  Packet Command.\r
+\r
+  @param  UsbMass                The device to be requested sense data\r
+\r
+  @retval EFI_DEVICE_ERROR       Hardware error\r
+  @retval EFI_SUCCESS            Success\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootRequestSense (\r
+  IN USB_MASS_DEVICE          *UsbMass\r
+  )\r
+{\r
+  USB_BOOT_REQUEST_SENSE_CMD  SenseCmd;\r
+  USB_BOOT_REQUEST_SENSE_DATA SenseData;\r
+  EFI_BLOCK_IO_MEDIA          *Media;\r
+  USB_MASS_TRANSPORT          *Transport;\r
+  EFI_STATUS                  Status;\r
+  UINT32                      CmdResult;\r
+\r
+  Transport = UsbMass->Transport;\r
+\r
+  //\r
+  // Request the sense data from the device if command failed\r
+  //\r
+  ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD));\r
+  ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA));\r
+\r
+  SenseCmd.OpCode   = USB_BOOT_REQUEST_SENSE_OPCODE;\r
+  SenseCmd.Lun      = USB_BOOT_LUN (UsbMass->Lun);\r
+  SenseCmd.AllocLen = sizeof (USB_BOOT_REQUEST_SENSE_DATA);\r
+\r
+  Status = Transport->ExecCommand (\r
+                        UsbMass->Context,\r
+                        &SenseCmd,\r
+                        sizeof (USB_BOOT_REQUEST_SENSE_CMD),\r
+                        EfiUsbDataIn,\r
+                        &SenseData,\r
+                        sizeof (USB_BOOT_REQUEST_SENSE_DATA),\r
+                        USB_BOOT_GENERAL_CMD_TIMEOUT,\r
+                        &CmdResult\r
+                        );\r
+  if (EFI_ERROR (Status) || CmdResult != USB_MASS_CMD_SUCCESS) {\r
+    DEBUG ((mUsbMscError, "UsbBootRequestSense: (%r) CmdResult=0x%x\n", Status, CmdResult));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Interpret the sense data and update the media status if necessary.\r
+  //\r
+  Media = &UsbMass->BlockIoMedia;\r
+\r
+  switch (USB_BOOT_SENSE_KEY (SenseData.SenseKey)) {\r
+\r
+  case USB_BOOT_SENSE_NO_SENSE:\r
+  case USB_BOOT_SENSE_RECOVERED:\r
+    //\r
+    // Suppose hardware can handle this case, and recover later by itself\r
+    //\r
+    Status = EFI_NOT_READY;\r
+    break;\r
+\r
+  case USB_BOOT_SENSE_NOT_READY:\r
+    switch (SenseData.ASC) {\r
+    case USB_BOOT_ASC_NO_MEDIA:\r
+      Status              = EFI_NO_MEDIA;\r
+      Media->MediaPresent = FALSE;\r
+      break;\r
+\r
+    case USB_BOOT_ASC_MEDIA_UPSIDE_DOWN:\r
+      Status              = EFI_DEVICE_ERROR;\r
+      Media->MediaPresent = FALSE;\r
+      break;\r
+\r
+    case USB_BOOT_ASC_NOT_READY:\r
+      if (SenseData.ASCQ == USB_BOOT_ASCQ_IN_PROGRESS ||\r
+          SenseData.ASCQ == USB_BOOT_ASCQ_DEVICE_BUSY) {\r
+        //\r
+        // Regular timeout, and need retry once more\r
+        //\r
+        DEBUG ((mUsbMscInfo, "UsbBootRequestSense: Not ready and need retry once more\n"));\r
+        Status = EFI_NOT_READY;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case USB_BOOT_SENSE_ILLEGAL_REQUEST:\r
+    Status = EFI_INVALID_PARAMETER;\r
+    break;\r
+\r
+  case USB_BOOT_SENSE_UNIT_ATTENTION:\r
+    Status = EFI_DEVICE_ERROR;\r
+    if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) {\r
+      Status = EFI_MEDIA_CHANGED;\r
+      UsbMass->BlockIoMedia.MediaId++;\r
+    }\r
+    break;\r
+\r
+  case USB_BOOT_SNESE_DATA_PROTECT:\r
+    Status                          = EFI_WRITE_PROTECTED;\r
+    UsbMass->BlockIoMedia.ReadOnly  = TRUE;\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_DEVICE_ERROR;\r
+    break;\r
+  }\r
+\r
+  DEBUG ((mUsbMscInfo, "UsbBootRequestSense: (%r) with sense key %x/%x/%x\n",\r
+          Status,\r
+          USB_BOOT_SENSE_KEY (SenseData.SenseKey),\r
+          SenseData.ASC,\r
+          SenseData.ASCQ\r
+          ));\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Execute the USB mass storage bootability commands. If execution\r
+  failed, retrieve the error by REQUEST_SENSE then update the device's\r
+  status, such as ReadyOnly.\r
+\r
+  @param  UsbMass                The device to issue commands to\r
+  @param  Cmd                    The command to execute\r
+  @param  CmdLen                 The length of the command\r
+  @param  DataDir                The direction of data transfer\r
+  @param  Data                   The buffer to hold the data\r
+  @param  DataLen                The length of expected data\r
+  @param  Timeout                The timeout used to transfer\r
+\r
+  @retval EFI_SUCCESS            The command is excuted OK\r
+  @retval EFI_DEVICE_ERROR       Failed to request sense\r
+  @retval EFI_INVALID_PARAMETER  The command has some invalid parameters\r
+  @retval EFI_WRITE_PROTECTED    The device is write protected\r
+  @retval EFI_MEDIA_CHANGED      The device media has been changed\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbBootExecCmd (\r
+  IN USB_MASS_DEVICE            *UsbMass,\r
+  IN VOID                       *Cmd,\r
+  IN UINT8                      CmdLen,\r
+  IN EFI_USB_DATA_DIRECTION     DataDir,\r
+  IN VOID                       *Data,\r
+  IN UINT32                     DataLen,\r
+  IN UINT32                     Timeout\r
+  )\r
+{\r
+  USB_MASS_TRANSPORT          *Transport;\r
+  EFI_STATUS                  Status;\r
+  UINT32                      CmdResult;\r
+\r
+  Transport = UsbMass->Transport;\r
+  Status    = Transport->ExecCommand (\r
+                           UsbMass->Context,\r
+                           Cmd,\r
+                           CmdLen,\r
+                           DataDir,\r
+                           Data,\r
+                           DataLen,\r
+                           Timeout,\r
+                           &CmdResult\r
+                           );\r
+  //\r
+  // ExecCommand return success and get the right CmdResult means\r
+  // the commnad transfer is OK.\r
+  //\r
+  if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR(Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return UsbBootRequestSense (UsbMass);\r
+}\r
+\r
+\r
+/**\r
+  Execute the USB mass storage bootability commands. If execution\r
+  failed, retrieve the error by REQUEST_SENSE then update the device's\r
+  status, such as ReadyOnly.\r
+\r
+  @param  UsbMass                The device to issue commands to\r
+  @param  Cmd                    The command to execute\r
+  @param  CmdLen                 The length of the command\r
+  @param  DataDir                The direction of data transfer\r
+  @param  Data                   The buffer to hold the data\r
+  @param  DataLen                The length of expected data\r
+\r
+  @retval EFI_SUCCESS            The command is excuted OK\r
+  @retval EFI_DEVICE_ERROR       Failed to request sense\r
+  @retval EFI_INVALID_PARAMETER  The command has some invalid parameters\r
+  @retval EFI_WRITE_PROTECTED    The device is write protected\r
+  @retval EFI_MEDIA_CHANGED      The device media has been changed\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UsbBootExecCmdWithRetry (\r
+  IN USB_MASS_DEVICE          *UsbMass,\r
+  IN VOID                     *Cmd,\r
+  IN UINT8                    CmdLen,\r
+  IN EFI_USB_DATA_DIRECTION   DataDir,\r
+  IN VOID                     *Data,\r
+  IN UINT32                   DataLen,\r
+  IN UINT32                   Timeout\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  INT16                       Index;\r
+\r
+  //\r
+  // If the device isn't ready, wait some time. If the device is ready,\r
+  // retry the command again.\r
+  //\r
+  Status  = EFI_SUCCESS;\r
+\r
+  for (Index = 0; Index < USB_BOOT_COMMAND_RETRY; Index++) {\r
+    //\r
+    // Execute the command with an increasingly larger timeout value.\r
+    //\r
+    Status = UsbBootExecCmd (\r
+               UsbMass,\r
+               Cmd,\r
+               CmdLen,\r
+               DataDir,\r
+               Data,\r
+               DataLen,\r
+               Timeout * (Index + 1)\r
+               );\r
+    if (Status == EFI_SUCCESS ||\r
+        Status == EFI_MEDIA_CHANGED) {\r
+      break;\r
+    }\r
+    //\r
+    // Need retry once more, so reset index\r
+    //\r
+    if (Status == EFI_NOT_READY) {\r
+      Index = 0;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Use the TEST UNIT READY command to check whether it is ready.\r
+  If it is ready, update the parameters.\r
+\r
+  @param  UsbMass                The device to test\r
+\r
+  @retval EFI_SUCCESS            The device is ready and parameters are updated.\r
+  @retval Others                 Device not ready.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootIsUnitReady (\r
+  IN USB_MASS_DEVICE            *UsbMass\r
+  )\r
+{\r
+  USB_BOOT_TEST_UNIT_READY_CMD  TestCmd;\r
+\r
+  ZeroMem (&TestCmd, sizeof (USB_BOOT_TEST_UNIT_READY_CMD));\r
+\r
+  TestCmd.OpCode  = USB_BOOT_TEST_UNIT_READY_OPCODE;\r
+  TestCmd.Lun     = USB_BOOT_LUN (UsbMass->Lun);\r
+\r
+  return UsbBootExecCmdWithRetry (\r
+           UsbMass,\r
+           &TestCmd,\r
+           sizeof (USB_BOOT_TEST_UNIT_READY_CMD),\r
+           EfiUsbNoData,\r
+           NULL,\r
+           0,\r
+           USB_BOOT_GENERAL_CMD_TIMEOUT\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Inquiry Command requests that information regrarding parameters of\r
+  the Device be sent to the Host.\r
+\r
+  @param  UsbMass                The device to inquiry.\r
+\r
+  @retval EFI_SUCCESS            The device is ready and parameters are updated.\r
+  @retval Others                 Device not ready.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootInquiry (\r
+  IN USB_MASS_DEVICE            *UsbMass\r
+  )\r
+{\r
+  USB_BOOT_INQUIRY_CMD        InquiryCmd;\r
+  USB_BOOT_INQUIRY_DATA       InquiryData;\r
+  EFI_BLOCK_IO_MEDIA          *Media;\r
+  EFI_STATUS                  Status;\r
+\r
+  Media = &(UsbMass->BlockIoMedia);\r
+\r
+  //\r
+  // Use the Inquiry command to get the RemovableMedia setting.\r
+  //\r
+  ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD));\r
+  ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA));\r
+\r
+  InquiryCmd.OpCode   = USB_BOOT_INQUIRY_OPCODE;\r
+  InquiryCmd.Lun      = USB_BOOT_LUN (UsbMass->Lun);\r
+  InquiryCmd.AllocLen = sizeof (InquiryData);\r
+\r
+  Status = UsbBootExecCmdWithRetry (\r
+             UsbMass,\r
+             &InquiryCmd,\r
+             sizeof (USB_BOOT_INQUIRY_CMD),\r
+             EfiUsbDataIn,\r
+             &InquiryData,\r
+             sizeof (USB_BOOT_INQUIRY_DATA),\r
+             USB_BOOT_INQUIRY_CMD_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  UsbMass->Pdt          = USB_BOOT_PDT (InquiryData.Pdt);\r
+  Media->RemovableMedia = USB_BOOT_REMOVABLE (InquiryData.Removable);\r
+  //\r
+  // Default value 512 Bytes, in case no media present at first time\r
+  //\r
+  Media->BlockSize      = 0x0200;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the capacity of the USB mass storage media, including\r
+  the presentation, block size, and last block number. This\r
+  function is used to get the disk parameters at the start if\r
+  it is a non-removable media or to detect the media if it is\r
+  removable.\r
+\r
+  @param  UsbMass                The device to retireve disk gemotric.\r
+\r
+  @retval EFI_SUCCESS            The disk gemotric is successfully retrieved.\r
+  @retval EFI_DEVICE_ERROR       Something is inconsistent with the disk gemotric.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootReadCapacity (\r
+  IN USB_MASS_DEVICE          *UsbMass\r
+  )\r
+{\r
+  USB_BOOT_READ_CAPACITY_CMD  CapacityCmd;\r
+  USB_BOOT_READ_CAPACITY_DATA CapacityData;\r
+  EFI_BLOCK_IO_MEDIA          *Media;\r
+  EFI_STATUS                  Status;\r
+\r
+  Media   = &UsbMass->BlockIoMedia;\r
+\r
+  //\r
+  // Use the READ CAPACITY command to get the block length and last blockno\r
+  //\r
+  ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD));\r
+  ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA));\r
+\r
+  CapacityCmd.OpCode = USB_BOOT_READ_CAPACITY_OPCODE;\r
+  CapacityCmd.Lun    = USB_BOOT_LUN (UsbMass->Lun);\r
+\r
+  Status = UsbBootExecCmdWithRetry (\r
+             UsbMass,\r
+             &CapacityCmd,\r
+             sizeof (USB_BOOT_READ_CAPACITY_CMD),\r
+             EfiUsbDataIn,\r
+             &CapacityData,\r
+             sizeof (USB_BOOT_READ_CAPACITY_DATA),\r
+             USB_BOOT_GENERAL_CMD_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Media->MediaPresent = TRUE;\r
+  Media->LastBlock    = UsbBootGetUint32 (CapacityData.LastLba);\r
+  Media->BlockSize    = UsbBootGetUint32 (CapacityData.BlockLen);\r
+\r
+  DEBUG ((mUsbMscInfo, "UsbBootReadCapacity Success LBA=%d BlockSize=%d\n",\r
+    Media->LastBlock, Media->BlockSize));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Retrieves mode sense information via sending Mode Sense\r
+  Packet Command.\r
+\r
+  @param  UsbMass                The USB_FLOPPY_DEV instance.\r
+\r
+  @retval EFI_DEVICE_ERROR       Hardware error\r
+  @retval EFI_SUCCESS            Success\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootModeSense (\r
+  IN USB_MASS_DEVICE          *UsbMass\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  USB_BOOT_MODE_SENSE_CMD   ModeSenseCmd;\r
+  USB_BOOT_MODE_PARA_HEADER ModeParaHeader;\r
+  UINT8                     CommandSet;\r
+\r
+  ZeroMem (&ModeSenseCmd, sizeof (USB_BOOT_MODE_SENSE_CMD));\r
+  ZeroMem (&ModeParaHeader, sizeof (USB_BOOT_MODE_PARA_HEADER));\r
+\r
+  //\r
+  // overuse Context Pointer, the first field of Bot or Cbi is EFI_USB_INTERFACE_DESCRIPTOR\r
+  //\r
+  CommandSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass;\r
+\r
+  if (CommandSet == USB_MASS_STORE_SCSI) {\r
+    //\r
+    // Not UFI Command Set, no ModeSense Command\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ModeSenseCmd.OpCode         = USB_BOOT_MODE_SENSE10_OPCODE;\r
+  ModeSenseCmd.PageCode       = 0x3f;\r
+  ModeSenseCmd.ParaListLenLsb = (UINT8) sizeof (USB_BOOT_MODE_PARA_HEADER);\r
+\r
+  Status = UsbBootExecCmdWithRetry (\r
+             UsbMass,\r
+             &ModeSenseCmd,\r
+             sizeof (USB_BOOT_MODE_SENSE_CMD),\r
+             EfiUsbDataIn,\r
+             &ModeParaHeader,\r
+             sizeof (USB_BOOT_MODE_PARA_HEADER),\r
+             USB_BOOT_GENERAL_CMD_TIMEOUT\r
+             );\r
+  //\r
+  // Did nothing with the Header here\r
+  // But probably should\r
+  //\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the parameters for the USB mass storage media, including\r
+  the RemovableMedia, block size, and last block number. This\r
+  function is used both to initialize the media during the\r
+  DriverBindingStart and to re-initialize it when the media is\r
+  changed. Althought the RemoveableMedia is unlikely to change,\r
+  I include it here.\r
+\r
+  @param  UsbMass                The device to retireve disk gemotric.\r
+\r
+  @retval EFI_SUCCESS            The disk gemotric is successfully retrieved.\r
+  @retval EFI_DEVICE_ERROR       Something is inconsistent with the disk gemotric.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootGetParams (\r
+  IN USB_MASS_DEVICE          *UsbMass\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA          *Media;\r
+  EFI_STATUS                  Status;\r
+\r
+  Status = UsbBootInquiry (UsbMass);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((mUsbMscError, "UsbBootGetParams: UsbBootInquiry (%r)\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Media = &(UsbMass->BlockIoMedia);\r
+  //\r
+  // Don't use the Removable bit in inquirydata to test whether the media\r
+  // is removable because many flash disks wrongly set this bit.\r
+  //\r
+  if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) {\r
+    //\r
+    // CD-Rom or Optical device\r
+    //\r
+    UsbMass->OpticalStorage = TRUE;\r
+    //\r
+    // Default value 2048 Bytes, in case no media present at first time\r
+    //\r
+    Media->BlockSize        = 0x0800;\r
+  } else {\r
+    //\r
+    // Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd\r
+    //\r
+    Status = UsbBootModeSense (UsbMass);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((mUsbMscError, "UsbBootGetParams: UsbBootModeSense (%r)\n", Status));\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return UsbBootReadCapacity (UsbMass);\r
+}\r
+\r
+\r
+/**\r
+  Detect whether the removable media is present and whether it has changed.\r
+  The Non-removable media doesn't need it.\r
+\r
+  @param  UsbMass                The device to retireve disk gemotric.\r
+\r
+  @retval EFI_SUCCESS            The disk gemotric is successfully retrieved.\r
+  @retval EFI_DEVICE_ERROR       Something is inconsistent with the disk gemotric.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootDetectMedia (\r
+  IN  USB_MASS_DEVICE       *UsbMass\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA        OldMedia;\r
+  EFI_BLOCK_IO_MEDIA        *Media;\r
+  EFI_STATUS                Status;\r
+\r
+  Media    = &UsbMass->BlockIoMedia;\r
+  OldMedia = UsbMass->BlockIoMedia;\r
+\r
+  //\r
+  // First test whether the device is ready and get status\r
+  // If media changed or ready, need read the device's capacity\r
+  //\r
+  Status = UsbBootIsUnitReady (UsbMass);\r
+  if ((Status == EFI_SUCCESS && Media->MediaPresent) ||\r
+      (Status == EFI_MEDIA_CHANGED)) {\r
+    if ((UsbMass->Pdt != USB_PDT_CDROM) &&\r
+        (UsbMass->Pdt != USB_PDT_OPTICAL)) {\r
+      //\r
+      // Non CD-Rom device need ModeSenseCmd between InquiryCmd and ReadCapacityCmd\r
+      //\r
+      UsbBootModeSense (UsbMass);\r
+    }\r
+    DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need Read Capacity\n"));\r
+    Status = UsbBootReadCapacity (UsbMass);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Detect whether it is necessary to reinstall the BlockIO\r
+  //\r
+  if ((Media->MediaId != OldMedia.MediaId) ||\r
+      (Media->MediaPresent != OldMedia.MediaPresent) ||\r
+      (Media->ReadOnly != OldMedia.ReadOnly) ||\r
+      (Media->BlockSize != OldMedia.BlockSize) ||\r
+      (Media->LastBlock != OldMedia.LastBlock)) {\r
+    DEBUG ((mUsbMscInfo, "UsbBootDetectMedia: Need reinstall BlockIoProtocol\n"));\r
+    Media->MediaId++;\r
+    gBS->ReinstallProtocolInterface (\r
+           UsbMass->Controller,\r
+           &gEfiBlockIoProtocolGuid,\r
+           &UsbMass->BlockIo,\r
+           &UsbMass->BlockIo\r
+           );\r
+    //\r
+    // Check whether media present or media changed or write protected\r
+    //\r
+    if (Media->MediaPresent == FALSE) {\r
+      Status = EFI_NO_MEDIA;\r
+    }\r
+    if (Media->MediaId != OldMedia.MediaId) {\r
+      Status = EFI_MEDIA_CHANGED;\r
+    }\r
+    if (Media->ReadOnly != OldMedia.ReadOnly) {\r
+      Status = EFI_WRITE_PROTECTED;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Read some blocks from the device.\r
+\r
+  @param  UsbMass                The USB mass storage device to read from\r
+  @param  Lba                    The start block number\r
+  @param  TotalBlock             Total block number to read\r
+  @param  Buffer                 The buffer to read to\r
+\r
+  @retval EFI_SUCCESS            Data are read into the buffer\r
+  @retval Others                 Failed to read all the data\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootReadBlocks (\r
+  IN  USB_MASS_DEVICE       *UsbMass,\r
+  IN  UINT32                Lba,\r
+  IN  UINTN                 TotalBlock,\r
+  OUT UINT8                 *Buffer\r
+  )\r
+{\r
+  USB_BOOT_READ10_CMD       ReadCmd;\r
+  EFI_STATUS                Status;\r
+  UINT16                    Count;\r
+  UINT32                    BlockSize;\r
+  UINT32                    ByteSize;\r
+  UINT32                    Timeout;\r
+\r
+  BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
+  Status    = EFI_SUCCESS;\r
+\r
+  while (TotalBlock > 0) {\r
+    //\r
+    // Split the total blocks into smaller pieces to ease the pressure\r
+    // on the device. We must split the total block because the READ10\r
+    // command only has 16 bit transfer length (in the unit of block).\r
+    //\r
+    Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
+    ByteSize  = (UINT32)Count * BlockSize;\r
+\r
+    //\r
+    // Optical device need longer timeout than other device\r
+    //\r
+    if (UsbMass->OpticalStorage == TRUE) {\r
+      Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;\r
+    } else {\r
+      Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;\r
+    }\r
+\r
+    //\r
+    // Fill in the command then execute\r
+    //\r
+    ZeroMem (&ReadCmd, sizeof (USB_BOOT_READ10_CMD));\r
+\r
+    ReadCmd.OpCode  = USB_BOOT_READ10_OPCODE;\r
+    ReadCmd.Lun     = USB_BOOT_LUN (UsbMass->Lun);\r
+    UsbBootPutUint32 (ReadCmd.Lba, Lba);\r
+    UsbBootPutUint16 (ReadCmd.TransferLen, Count);\r
+\r
+    Status = UsbBootExecCmdWithRetry (\r
+               UsbMass,\r
+               &ReadCmd,\r
+               sizeof (USB_BOOT_READ10_CMD),\r
+               EfiUsbDataIn,\r
+               Buffer,\r
+               ByteSize,\r
+               Timeout\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba        += Count;\r
+    Buffer     += Count * BlockSize;\r
+    TotalBlock -= Count;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Write some blocks to the device.\r
+\r
+  @param  UsbMass                The USB mass storage device to write to\r
+  @param  Lba                    The start block number\r
+  @param  TotalBlock             Total block number to write\r
+  @param  Buffer                 The buffer to write to\r
+\r
+  @retval EFI_SUCCESS            Data are written into the buffer\r
+  @retval Others                 Failed to write all the data\r
+\r
+**/\r
+EFI_STATUS\r
+UsbBootWriteBlocks (\r
+  IN  USB_MASS_DEVICE         *UsbMass,\r
+  IN  UINT32                  Lba,\r
+  IN  UINTN                   TotalBlock,\r
+  OUT UINT8                   *Buffer\r
+  )\r
+{\r
+  USB_BOOT_WRITE10_CMD  WriteCmd;\r
+  EFI_STATUS            Status;\r
+  UINT16                Count;\r
+  UINT32                BlockSize;\r
+  UINT32                ByteSize;\r
+  UINT32                Timeout;\r
+\r
+  BlockSize = UsbMass->BlockIoMedia.BlockSize;\r
+  Status    = EFI_SUCCESS;\r
+\r
+  while (TotalBlock > 0) {\r
+    //\r
+    // Split the total blocks into smaller pieces to ease the pressure\r
+    // on the device. We must split the total block because the WRITE10\r
+    // command only has 16 bit transfer length (in the unit of block).\r
+    //\r
+    Count     = (UINT16)((TotalBlock < USB_BOOT_IO_BLOCKS) ? TotalBlock : USB_BOOT_IO_BLOCKS);\r
+    ByteSize  = (UINT32)Count * BlockSize;\r
+\r
+    //\r
+    // Optical device need longer timeout than other device\r
+    //\r
+    if (UsbMass->OpticalStorage == TRUE) {\r
+      Timeout = (UINT32)Count * USB_BOOT_OPTICAL_BLOCK_TIMEOUT;\r
+    } else {\r
+      Timeout = (UINT32)Count * USB_BOOT_GENERAL_BLOCK_TIMEOUT;\r
+    }\r
+\r
+    //\r
+    // Fill in the write10 command block\r
+    //\r
+    ZeroMem (&WriteCmd, sizeof (USB_BOOT_WRITE10_CMD));\r
+\r
+    WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE;\r
+    WriteCmd.Lun    = USB_BOOT_LUN (UsbMass->Lun);\r
+    UsbBootPutUint32 (WriteCmd.Lba, Lba);\r
+    UsbBootPutUint16 (WriteCmd.TransferLen, Count);\r
+\r
+    Status = UsbBootExecCmdWithRetry (\r
+               UsbMass,\r
+               &WriteCmd,\r
+               sizeof (USB_BOOT_WRITE10_CMD),\r
+               EfiUsbDataOut,\r
+               Buffer,\r
+               ByteSize,\r
+               Timeout\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba        += Count;\r
+    Buffer     += Count * BlockSize;\r
+    TotalBlock -= Count;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Use the USB clear feature control transfer to clear the endpoint\r
+  stall condition.\r
+\r
+  @param  UsbIo                  The USB IO protocol to use\r
+  @param  EndpointAddr           The endpoint to clear stall for\r
+\r
+  @retval EFI_SUCCESS            The endpoint stall condtion is clear\r
+  @retval Others                 Failed to clear the endpoint stall condtion\r
+\r
+**/\r
+EFI_STATUS\r
+UsbClearEndpointStall (\r
+  IN EFI_USB_IO_PROTOCOL    *UsbIo,\r
+  IN UINT8                  EndpointAddr\r
+  )\r
+{\r
+  EFI_USB_DEVICE_REQUEST    Request;\r
+  EFI_STATUS                Status;\r
+  UINT32                    CmdResult;\r
+  UINT32                    Timeout;\r
+\r
+  Request.RequestType = 0x02;\r
+  Request.Request     = USB_REQ_CLEAR_FEATURE;\r
+  Request.Value       = USB_FEATURE_ENDPOINT_HALT;\r
+  Request.Index       = EndpointAddr;\r
+  Request.Length      = 0;\r
+  Timeout             = USB_BOOT_GENERAL_CMD_TIMEOUT / USB_MASS_STALL_1_MS;\r
+\r
+  Status = UsbIo->UsbControlTransfer (\r
+                    UsbIo,\r
+                    &Request,\r
+                    EfiUsbNoData,\r
+                    Timeout,\r
+                    NULL,\r
+                    0,\r
+                    &CmdResult\r
+                    );\r
+\r
+  return Status;\r
+}\r
diff --git a/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h b/edk2/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h
new file mode 100644 (file)
index 0000000..cee70be
--- /dev/null
@@ -0,0 +1,268 @@
+/** @file\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  UsbMassBoot.h\r
+\r
+Abstract:\r
+\r
+  The definition of command and data of the USB mass storage for\r
+  bootability command set.\r
+\r
+Revision History\r
+\r
+\r
+**/\r
+\r
+#ifndef _EFI_USB_MASS_BOOT_H_\r
+#define _EFI_USB_MASS_BOOT_H_\r
+\r
+enum {\r
+  //\r
+  // The opcodes of various usb boot commands:\r
+  // INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified\r
+  // by MMC command set. Others are "Group 1 Timeout Commands". That\r
+  // is they should be retried if driver is ready.\r
+  // We can't use the Peripheral Device Type in Inquiry data to\r
+  // determine the timeout used. For example, both floppy and flash\r
+  // are likely set their PDT to 0, or Direct Access Device.\r
+  //\r
+  USB_BOOT_INQUIRY_OPCODE         = 0x12,\r
+  USB_BOOT_REQUEST_SENSE_OPCODE   = 0x03,\r
+\r
+  USB_BOOT_MODE_SENSE10_OPCODE    = 0x5a,\r
+  USB_BOOT_READ_CAPACITY_OPCODE   = 0x25,\r
+  USB_BOOT_TEST_UNIT_READY_OPCODE = 0x00,\r
+  USB_BOOT_READ10_OPCODE          = 0x28,\r
+  USB_BOOT_WRITE10_OPCODE         = 0x2a,\r
+\r
+  //\r
+  // The Sense Key part of the sense data. Sense data has three levels:\r
+  // Sense key, Additional Sense Code and Additional Sense Code Qualifier\r
+  //\r
+  USB_BOOT_SENSE_NO_SENSE         = 0x00, // No sense key\r
+  USB_BOOT_SENSE_RECOVERED        = 0x01, // Last command succeed with recovery actions\r
+  USB_BOOT_SENSE_NOT_READY        = 0x02, // Device not ready\r
+  USB_BOOT_SNESE_MEDIUM_ERROR     = 0X03, // Failed probably because flaw in the media\r
+  USB_BOOT_SENSE_HARDWARE_ERROR   = 0X04, // Non-recoverable hardware failure\r
+  USB_BOOT_SENSE_ILLEGAL_REQUEST  = 0X05, // Illegal parameters in the request\r
+  USB_BOOT_SENSE_UNIT_ATTENTION   = 0X06, // Removable medium may have been changed\r
+  USB_BOOT_SNESE_DATA_PROTECT     = 0X07, // Write protected\r
+  USB_BOOT_SENSE_BLANK_CHECK      = 0X08, // Blank/non-blank medium while reading/writing\r
+  USB_BOOT_SENSE_VENDOR           = 0X09, // Vendor specific sense key\r
+  USB_BOOT_SENSE_ABORTED          = 0X0B, // Command aborted by the device\r
+  USB_BOOT_SENSE_VOLUME_OVERFLOW  = 0x0D, // Partition overflow\r
+  USB_BOOT_SENSE_MISCOMPARE       = 0x0E, // Source data mis-match while verfying.\r
+\r
+  USB_BOOT_ASC_NOT_READY          = 0x04,\r
+  USB_BOOT_ASC_MEDIA_UPSIDE_DOWN  = 0x06,\r
+  USB_BOOT_ASC_NO_MEDIA           = 0x3A,\r
+  USB_BOOT_ASC_MEDIA_CHANGE       = 0x28,\r
+\r
+  USB_BOOT_ASCQ_IN_PROGRESS       = 0x01,\r
+  USB_BOOT_ASCQ_DEVICE_BUSY       = 0xFF,\r
+\r
+  //\r
+  // Other parameters\r
+  //\r
+  USB_BOOT_IO_BLOCKS              = 64,\r
+\r
+  //\r
+  // Boot Retry times\r
+  //\r
+  USB_BOOT_COMMAND_RETRY          = 5,\r
+  USB_BOOT_WAIT_RETRY             = 5,\r
+\r
+  //\r
+  // Boot Stall time\r
+  //\r
+  USB_BOOT_UNIT_READY_STALL       = 50 * USB_MASS_STALL_1_MS,\r
+\r
+  //\r
+  // Boot Transfer timeout\r
+  //\r
+  USB_BOOT_GENERAL_BLOCK_TIMEOUT  = 200 * USB_MASS_STALL_1_MS,\r
+  USB_BOOT_OPTICAL_BLOCK_TIMEOUT  = 1 * USB_MASS_STALL_1_S,\r
+  USB_BOOT_GENERAL_CMD_TIMEOUT    = 1 * USB_MASS_STALL_1_S,\r
+  USB_BOOT_INQUIRY_CMD_TIMEOUT    = 3 * USB_MASS_STALL_1_S,\r
+\r
+  //\r
+  // Supported PDT codes, or Peripheral Device Type\r
+  //\r
+  USB_PDT_DIRECT_ACCESS           = 0x00,       // Direct access device\r
+  USB_PDT_CDROM                   = 0x05,       // CDROM\r
+  USB_PDT_OPTICAL                 = 0x07,       // Non-CD optical disks\r
+  USB_PDT_SIMPLE_DIRECT           = 0x0E,       // Simplified direct access device\r
+};\r
+\r
+//\r
+// The required commands are INQUIRY, READ CAPACITY, TEST UNIT READY,\r
+// READ10, WRITE10, and REQUEST SENSE. The BLOCK_IO protocol uses LBA\r
+// so it isn't necessary to issue MODE SENSE / READ FORMAT CAPACITY\r
+// command to retrieve the disk gemotrics.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;            // Lun (high 3 bits)\r
+  UINT8             Reserved0[2];\r
+  UINT8             AllocLen;\r
+  UINT8             Reserved1;\r
+  UINT8             Pad[6];\r
+} USB_BOOT_INQUIRY_CMD;\r
+\r
+typedef struct {\r
+  UINT8             Pdt;            // Peripheral Device Type (low 5 bits)\r
+  UINT8             Removable;      // Removable Media (highest bit)\r
+  UINT8             Reserved0[2];\r
+  UINT8             AddLen;         // Additional length\r
+  UINT8             Reserved1[3];\r
+  UINT8             VendorID[8];\r
+  UINT8             ProductID[16];\r
+  UINT8             ProductRevision[4];\r
+} USB_BOOT_INQUIRY_DATA;\r
+\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;\r
+  UINT8             Reserved0[8];\r
+  UINT8             Pad[2];\r
+} USB_BOOT_READ_CAPACITY_CMD;\r
+\r
+typedef struct {\r
+  UINT8             LastLba[4];\r
+  UINT8             BlockLen[4];\r
+} USB_BOOT_READ_CAPACITY_DATA;\r
+\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;\r
+  UINT8             Reserved[4];\r
+  UINT8             Pad[6];\r
+} USB_BOOT_TEST_UNIT_READY_CMD;\r
+\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;\r
+  UINT8             PageCode;\r
+  UINT8             Reserved0[4];\r
+  UINT8             ParaListLenMsb;\r
+  UINT8             ParaListLenLsb;\r
+  UINT8             Reserved1;\r
+  UINT8             Pad[2];\r
+} USB_BOOT_MODE_SENSE_CMD;\r
+\r
+typedef struct {\r
+  UINT8             ModeDataLenMsb;\r
+  UINT8             ModeDataLenLsb;\r
+  UINT8             Reserved0[4];\r
+  UINT8             BlkDesLenMsb;\r
+  UINT8             BlkDesLenLsb;\r
+} USB_BOOT_MODE_PARA_HEADER;\r
+\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;            // Lun (High 3 bits)\r
+  UINT8             Lba[4];         // Logical block address\r
+  UINT8             Reserved0;\r
+  UINT8             TransferLen[2]; // Transfer length\r
+  UINT8             Reserverd1;\r
+  UINT8             Pad[2];\r
+} USB_BOOT_READ10_CMD;\r
+\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;\r
+  UINT8             Lba[4];\r
+  UINT8             Reserved0;\r
+  UINT8             TransferLen[2];\r
+  UINT8             Reserverd1;\r
+  UINT8             Pad[2];\r
+} USB_BOOT_WRITE10_CMD;\r
+\r
+typedef struct {\r
+  UINT8             OpCode;\r
+  UINT8             Lun;            // Lun (High 3 bits)\r
+  UINT8             Reserved0[2];\r
+  UINT8             AllocLen;       // Allocation length\r
+  UINT8             Reserved1;\r
+  UINT8             Pad[6];\r
+} USB_BOOT_REQUEST_SENSE_CMD;\r
+\r
+typedef struct {\r
+  UINT8             ErrorCode;\r
+  UINT8             Reserved0;\r
+  UINT8             SenseKey;       // Sense key (low 4 bits)\r
+  UINT8             Infor[4];\r
+  UINT8             AddLen;         // Additional Sense length, 10\r
+  UINT8             Reserved1[4];\r
+  UINT8             ASC;            // Additional Sense Code\r
+  UINT8             ASCQ;           // Additional Sense Code Qualifier\r
+  UINT8             Reserverd2[4];\r
+} USB_BOOT_REQUEST_SENSE_DATA;\r
+#pragma pack()\r
+\r
+//\r
+// Convert a LUN number to that in the command\r
+//\r
+#define USB_BOOT_LUN(Lun) ((Lun) << 5)\r
+\r
+//\r
+// Get the removable, PDT, and sense key bits from the command data\r
+//\r
+#define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & 0x80) != 0)\r
+#define USB_BOOT_PDT(Pdt)           ((Pdt) & 0x1f)\r
+#define USB_BOOT_SENSE_KEY(Key)     ((Key) & 0x0f)\r
+\r
+//\r
+// Swap the byte sequence of a UINT32. Intel CPU uses little endian\r
+// in UEFI environment, but USB boot uses big endian.\r
+//\r
+#define USB_BOOT_SWAP32(Data32) \\r
+                ((((Data32) & 0x000000ff) << 24) | (((Data32) & 0xff000000) >> 24) | \\r
+                 (((Data32) & 0x0000ff00) << 8)  | (((Data32) & 0x00ff0000) >> 8))\r
+\r
+#define USB_BOOT_SWAP16(Data16) \\r
+                ((((Data16) & 0x00ff) << 8) | (((Data16) & 0xff00) >> 8))\r
+\r
+EFI_STATUS\r
+UsbBootGetParams (\r
+  IN USB_MASS_DEVICE          *UsbMass\r
+  );\r
+\r
+EFI_STATUS\r
+UsbBootIsUnitReady (\r
+  IN USB_MASS_DEVICE          *UsbMass\r
+  );\r
+\r
+EFI_STATUS\r
+UsbBootDetectMedia (\r
+  IN  USB_MASS_DEVICE       *UsbMass\r
+  );\r
+\r
+EFI_STATUS\r
+UsbBootReadBlocks (\r
+  IN  USB_MASS_DEVICE         *UsbMass,\r
+  IN  UINT32                  Lba,\r
+  IN  UINTN                   TotalBlock,\r
+  OUT UINT8                   *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+UsbBootWriteBlocks (\r
+  IN&n