--- /dev/null
+/** @file\r
+The module to produce Usb Bus PPI.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ \r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+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
+#include "UsbPeim.h"\r
+#include "HubPeim.h"\r
+#include "PeiUsbLib.h"\r
+\r
+//\r
+// UsbIo PPI interface function\r
+//\r
+PEI_USB_IO_PPI mUsbIoPpi = {\r
+ PeiUsbControlTransfer,\r
+ PeiUsbBulkTransfer,\r
+ PeiUsbGetInterfaceDescriptor,\r
+ PeiUsbGetEndpointDescriptor,\r
+ PeiUsbPortReset\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gPeiUsbIoPpiGuid,\r
+ NULL\r
+};\r
+\r
+/**\r
+ The enumeration routine to detect device change.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
+\r
+ @retval EFI_SUCCESS The usb is enumerated successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbEnumeration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi\r
+ );\r
+\r
+/**\r
+ Configure new detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+ @param Port The port to be configured.\r
+ @param DeviceAddress The device address to be configured.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiConfigureUsbDevice (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN UINT8 Port,\r
+ IN OUT UINT8 *DeviceAddress\r
+ );\r
+\r
+/**\r
+ Get all configurations from a detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetAllConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice\r
+ );\r
+\r
+/**\r
+ Get the start position of next wanted descriptor.\r
+ \r
+ @param Buffer Buffer containing data to parse.\r
+ @param Length Buffer length.\r
+ @param DescType Descriptor type.\r
+ @param DescLength Descriptor length.\r
+ @param ParsedBytes Bytes has been parsed.\r
+\r
+ @retval EFI_SUCCESS Get wanted descriptor successfully.\r
+ @retval EFI_DEVICE_ERROR Error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExpectedDescriptor (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN Length,\r
+ IN UINT8 DescType,\r
+ IN UINT8 DescLength,\r
+ OUT UINTN *ParsedBytes\r
+ );\r
+\r
+/**\r
+ The entrypoint of the module, it will enumerate all HCs.\r
+ \r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS Usb initialization is done successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval EFI_UNSUPPORTED Can't find required PPI.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeUsb (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi;\r
+ PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi;\r
+\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not \r
+ // be produced at the same time\r
+ //\r
+ Index = 0;\r
+ while (TRUE) {\r
+ //\r
+ // Get UsbHcPpi at first.\r
+ //\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsbHostControllerPpiGuid,\r
+ Index,\r
+ NULL,\r
+ (VOID **) &UsbHcPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No more host controller, break out\r
+ //\r
+ break;\r
+ }\r
+ PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL);\r
+ Index++;\r
+ }\r
+\r
+ if (Index == 0) {\r
+ //\r
+ // Then try to get Usb2HcPpi.\r
+ //\r
+ while (TRUE) {\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsb2HostControllerPpiGuid,\r
+ Index,\r
+ NULL,\r
+ (VOID **) &Usb2HcPpi\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No more host controller, break out\r
+ //\r
+ break;\r
+ } \r
+ PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi); \r
+ Index++;\r
+ }\r
+ }\r
+ \r
+ if (Index == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The Hub Enumeration just scans the hub ports one time. It also\r
+ doesn't support hot-plug.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+ @param CurrentAddress The DeviceAddress of usb device.\r
+\r
+ @retval EFI_SUCCESS The usb hub is enumerated successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubEnumeration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN UINT8 *CurrentAddress\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ EFI_USB_PORT_STATUS PortStatus;\r
+ UINTN MemPages;\r
+ EFI_PHYSICAL_ADDRESS AllocateAddress;\r
+ PEI_USB_DEVICE *NewPeiUsbDevice;\r
+\r
+\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+\r
+ Status = PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ (UINT32 *) &PortStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ EfiUsbPortConnectChange\r
+ );\r
+\r
+ MicroSecondDelay (100 * 1000);\r
+\r
+ if (IsPortConnect (PortStatus.PortStatus)) {\r
+\r
+ PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ (UINT32 *) &PortStatus\r
+ );\r
+\r
+ //\r
+ // Begin to deal with the new device\r
+ //\r
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ MemPages,\r
+ &AllocateAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);\r
+ ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
+\r
+ NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;\r
+ NewPeiUsbDevice->DeviceAddress = 0;\r
+ NewPeiUsbDevice->MaxPacketSize0 = 8;\r
+ NewPeiUsbDevice->DataToggle = 0;\r
+ CopyMem (\r
+ &(NewPeiUsbDevice->UsbIoPpi),\r
+ &mUsbIoPpi,\r
+ sizeof (PEI_USB_IO_PPI)\r
+ );\r
+ CopyMem (\r
+ &(NewPeiUsbDevice->UsbIoPpiList),\r
+ &mUsbIoPpiList,\r
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+ );\r
+ NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi;\r
+ NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;\r
+ NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi;\r
+ NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi;\r
+ NewPeiUsbDevice->IsHub = 0x0;\r
+ NewPeiUsbDevice->DownStreamPortNo = 0x0;\r
+\r
+ PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1));\r
+\r
+ PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ (UINT32 *) &PortStatus\r
+ );\r
+\r
+ NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+\r
+ if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {\r
+ if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
+ NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index;\r
+ NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress;\r
+ } else {\r
+ CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR));\r
+ }\r
+ }\r
+\r
+ //\r
+ // Configure that Usb Device\r
+ //\r
+ Status = PeiConfigureUsbDevice (\r
+ PeiServices,\r
+ NewPeiUsbDevice,\r
+ (UINT8) (Index + 1),\r
+ CurrentAddress\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList);\r
+\r
+ if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {\r
+ NewPeiUsbDevice->IsHub = 0x1;\r
+\r
+ Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress);\r
+ }\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The enumeration routine to detect device change.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
+\r
+ @retval EFI_SUCCESS The usb is enumerated successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbEnumeration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi\r
+ )\r
+{\r
+ UINT8 NumOfRootPort;\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ EFI_USB_PORT_STATUS PortStatus;\r
+ PEI_USB_DEVICE *PeiUsbDevice;\r
+ UINTN MemPages;\r
+ EFI_PHYSICAL_ADDRESS AllocateAddress;\r
+ UINT8 CurrentAddress;\r
+\r
+\r
+ CurrentAddress = 0;\r
+ if (Usb2HcPpi != NULL){\r
+ Usb2HcPpi->GetRootHubPortNumber (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8 *) &NumOfRootPort\r
+ ); \r
+ } else {\r
+ UsbHcPpi->GetRootHubPortNumber (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8 *) &NumOfRootPort\r
+ );\r
+ }\r
+\r
+ for (Index = 0; Index < NumOfRootPort; Index++) {\r
+ //\r
+ // First get root port status to detect changes happen\r
+ //\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ ); \r
+ } else {\r
+ UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ }\r
+ DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus));\r
+ if (IsPortConnectChange (PortStatus.PortChangeStatus)) {\r
+ //\r
+ // Changes happen, first clear this change status\r
+ //\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ EfiUsbPortConnectChange\r
+ ); \r
+ } else {\r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ EfiUsbPortConnectChange\r
+ );\r
+ }\r
+ MicroSecondDelay (100 * 1000);\r
+\r
+ if (IsPortConnect (PortStatus.PortStatus)) {\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ } else {\r
+ UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ }\r
+\r
+ //\r
+ // Connect change happen\r
+ //\r
+ MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ MemPages,\r
+ &AllocateAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress);\r
+ ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));\r
+\r
+ PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;\r
+ PeiUsbDevice->DeviceAddress = 0;\r
+ PeiUsbDevice->MaxPacketSize0 = 8;\r
+ PeiUsbDevice->DataToggle = 0;\r
+ CopyMem (\r
+ &(PeiUsbDevice->UsbIoPpi),\r
+ &mUsbIoPpi,\r
+ sizeof (PEI_USB_IO_PPI)\r
+ );\r
+ CopyMem (\r
+ &(PeiUsbDevice->UsbIoPpiList),\r
+ &mUsbIoPpiList,\r
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
+ );\r
+ PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;\r
+ PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress;\r
+ PeiUsbDevice->UsbHcPpi = UsbHcPpi;\r
+ PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;\r
+ PeiUsbDevice->IsHub = 0x0;\r
+ PeiUsbDevice->DownStreamPortNo = 0x0;\r
+\r
+ ResetRootPort (\r
+ PeiServices,\r
+ PeiUsbDevice->UsbHcPpi,\r
+ PeiUsbDevice->Usb2HcPpi,\r
+ Index,\r
+ 0\r
+ );\r
+\r
+ if (Usb2HcPpi != NULL) {\r
+ Usb2HcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ } else {\r
+ UsbHcPpi->GetRootHubPortStatus (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ (UINT8) Index,\r
+ &PortStatus\r
+ );\r
+ }\r
+\r
+ PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus);\r
+ DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));\r
+\r
+ //\r
+ // Configure that Usb Device\r
+ //\r
+ Status = PeiConfigureUsbDevice (\r
+ PeiServices,\r
+ PeiUsbDevice,\r
+ Index,\r
+ &CurrentAddress\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n"));\r
+\r
+ Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);\r
+\r
+ if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {\r
+ PeiUsbDevice->IsHub = 0x1;\r
+\r
+ Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);\r
+ }\r
+ } else {\r
+ //\r
+ // Disconnect change happen, currently we don't support\r
+ //\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Configure new detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+ @param Port The port to be configured.\r
+ @param DeviceAddress The device address to be configured.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiConfigureUsbDevice (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice,\r
+ IN UINT8 Port,\r
+ IN OUT UINT8 *DeviceAddress\r
+ )\r
+{\r
+ EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;\r
+ EFI_STATUS Status;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINT8 Retry;\r
+\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+ Status = EFI_SUCCESS;\r
+ ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR));\r
+ //\r
+ // Get USB device descriptor\r
+ //\r
+\r
+ for (Retry = 0; Retry < 3; Retry ++) {\r
+\r
+ PeiUsbDevice->MaxPacketSize0 = 8;\r
+\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_DEVICE << 8),\r
+ 0,\r
+ 8,\r
+ &DeviceDescriptor\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry));\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Retry == 3) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry));\r
+ return Status;\r
+ }\r
+\r
+ PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0;\r
+\r
+ (*DeviceAddress) ++;\r
+\r
+ Status = PeiUsbSetDeviceAddress (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ *DeviceAddress\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n"));\r
+ return Status;\r
+ }\r
+\r
+ PeiUsbDevice->DeviceAddress = *DeviceAddress;\r
+\r
+ //\r
+ // Get whole USB device descriptor\r
+ //\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_DEVICE << 8),\r
+ 0,\r
+ (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR),\r
+ &DeviceDescriptor\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n"));\r
+ return Status;\r
+ }\r
+ //\r
+ // Get its default configuration and its first interface\r
+ //\r
+ Status = PeiUsbGetAllConfiguration (\r
+ PeiServices,\r
+ PeiUsbDevice\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PeiUsbSetConfiguration (\r
+ PeiServices,\r
+ UsbIoPpi\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get all configurations from a detected usb device.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance.\r
+\r
+ @retval EFI_SUCCESS The new detected usb device is configured successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiUsbGetAllConfiguration (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+ UINT16 ConfigDescLength;\r
+ UINT8 *Ptr;\r
+ UINTN SkipBytes;\r
+ UINTN LengthLeft;\r
+ UINTN Index;\r
+ UINTN NumOfEndpoint;\r
+\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+ //\r
+ // First get its 4-byte configuration descriptor\r
+ //\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_CONFIG << 8), // Value\r
+ 0, // Index\r
+ 4, // Length\r
+ PeiUsbDevice->ConfigurationData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n"));\r
+ return Status;\r
+ }\r
+\r
+ ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;\r
+ ConfigDescLength = ConfigDesc->TotalLength;\r
+\r
+ //\r
+ // Then we get the total descriptors for this configuration\r
+ //\r
+ Status = PeiUsbGetDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (USB_DT_CONFIG << 8),\r
+ 0,\r
+ ConfigDescLength,\r
+ PeiUsbDevice->ConfigurationData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n"));\r
+ return Status;\r
+ }\r
+ //\r
+ // Parse this configuration descriptor\r
+ // First get the current config descriptor;\r
+ //\r
+ Status = GetExpectedDescriptor (\r
+ PeiUsbDevice->ConfigurationData,\r
+ ConfigDescLength,\r
+ USB_DT_CONFIG,\r
+ (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR),\r
+ &SkipBytes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ptr = PeiUsbDevice->ConfigurationData + SkipBytes;\r
+ PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr;\r
+\r
+ Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
+ LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR);\r
+\r
+ //\r
+ // Get the first interface descriptor\r
+ //\r
+ Status = GetExpectedDescriptor (\r
+ Ptr,\r
+ LengthLeft,\r
+ USB_DT_INTERFACE,\r
+ (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR),\r
+ &SkipBytes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ptr += SkipBytes;\r
+ PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr;\r
+\r
+ Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
+ LengthLeft -= SkipBytes;\r
+ LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR);\r
+\r
+ //\r
+ // Parse all the endpoint descriptor within this interface\r
+ //\r
+ NumOfEndpoint = PeiUsbDevice->InterfaceDesc->NumEndpoints;\r
+ ASSERT (NumOfEndpoint <= MAX_ENDPOINT);\r
+\r
+ for (Index = 0; Index < NumOfEndpoint; Index++) {\r
+ //\r
+ // Get the endpoint descriptor\r
+ //\r
+ Status = GetExpectedDescriptor (\r
+ Ptr,\r
+ LengthLeft,\r
+ USB_DT_ENDPOINT,\r
+ (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR),\r
+ &SkipBytes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Ptr += SkipBytes;\r
+ PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr;\r
+\r
+ Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+ LengthLeft -= SkipBytes;\r
+ LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get the start position of next wanted descriptor.\r
+ \r
+ @param Buffer Buffer containing data to parse.\r
+ @param Length Buffer length.\r
+ @param DescType Descriptor type.\r
+ @param DescLength Descriptor length.\r
+ @param ParsedBytes Bytes has been parsed.\r
+\r
+ @retval EFI_SUCCESS Get wanted descriptor successfully.\r
+ @retval EFI_DEVICE_ERROR Error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+GetExpectedDescriptor (\r
+ IN UINT8 *Buffer,\r
+ IN UINTN Length,\r
+ IN UINT8 DescType,\r
+ IN UINT8 DescLength,\r
+ OUT UINTN *ParsedBytes\r
+ )\r
+{\r
+ UINT16 DescriptorHeader;\r
+ UINT8 Len;\r
+ UINT8 *Ptr;\r
+ UINTN Parsed;\r
+\r
+ Parsed = 0;\r
+ Ptr = Buffer;\r
+\r
+ while (TRUE) {\r
+ //\r
+ // Buffer length should not less than Desc length\r
+ //\r
+ if (Length < DescLength) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ DescriptorHeader = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8));\r
+\r
+ Len = Buffer[0];\r
+\r
+ //\r
+ // Check to see if it is a start of expected descriptor\r
+ //\r
+ if (DescriptorHeader == ((DescType << 8) | DescLength)) {\r
+ break;\r
+ }\r
+\r
+ if ((UINT8) (DescriptorHeader >> 8) == DescType) {\r
+ if (Len > DescLength) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // Descriptor length should be at least 2\r
+ // and should not exceed the buffer length\r
+ //\r
+ if (Len < 2) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (Len > Length) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Skip this mismatch descriptor\r
+ //\r
+ Length -= Len;\r
+ Ptr += Len;\r
+ Parsed += Len;\r
+ }\r
+\r
+ *ParsedBytes = Parsed;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send reset signal over the given root hub port.\r
+ \r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance.\r
+ @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance.\r
+ @param PortNum The port to be reset.\r
+ @param RetryIndex The retry times.\r
+\r
+**/\r
+VOID\r
+ResetRootPort (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi,\r
+ IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi,\r
+ IN UINT8 PortNum,\r
+ IN UINT8 RetryIndex\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ if (Usb2HcPpi != NULL) {\r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // reset root port\r
+ //\r
+ Status = Usb2HcPpi->SetRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // clear reset root port\r
+ //\r
+ Status = Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (1 * 1000);\r
+ \r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortConnectChange\r
+ );\r
+ \r
+ //\r
+ // Set port enable\r
+ //\r
+ Usb2HcPpi->SetRootHubPortFeature(\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnable\r
+ );\r
+ \r
+ Usb2HcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ Usb2HcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnableChange\r
+ );\r
+ \r
+ MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);\r
+ } else {\r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // reset root port\r
+ //\r
+ Status = UsbHcPpi->SetRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (200 * 1000);\r
+ \r
+ //\r
+ // clear reset root port\r
+ //\r
+ Status = UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n"));\r
+ return;\r
+ }\r
+ \r
+ MicroSecondDelay (1 * 1000);\r
+ \r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortConnectChange\r
+ );\r
+ \r
+ //\r
+ // Set port enable\r
+ //\r
+ UsbHcPpi->SetRootHubPortFeature(\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnable\r
+ );\r
+ \r
+ UsbHcPpi->ClearRootHubPortFeature (\r
+ PeiServices,\r
+ UsbHcPpi,\r
+ PortNum,\r
+ EfiUsbPortEnableChange\r
+ );\r
+ \r
+ MicroSecondDelay ((RetryIndex + 1) * 50 * 1000);\r
+ }\r
+ return;\r
+}\r
+\r
+\r