--- /dev/null
+/** @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
--- /dev/null
+#/** @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
--- /dev/null
+<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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+ /*++\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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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 &n