--- /dev/null
+/** @file\r
+Usb Hub Request Support In PEI Phase\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
+ Get a given hub port status.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param PortStatus Current Hub port status and change status.\r
+\r
+ @retval EFI_SUCCESS Port status is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ OUT UINT32 *PortStatus\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_GET_PORT_STATUS;\r
+ DeviceRequest.Index = Port;\r
+ DeviceRequest.Length = (UINT16) sizeof (UINT32);\r
+\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ PortStatus,\r
+ sizeof (UINT32)\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Set specified feature to a given hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param Value New feature value.\r
+\r
+ @retval EFI_SUCCESS Port feature is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE;\r
+ DeviceRequest.Value = Value;\r
+ DeviceRequest.Index = Port;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear specified feature on a given hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Port Usb hub port number (starting from 1).\r
+ @param Value Feature value that will be cleared from the hub port.\r
+\r
+ @retval EFI_SUCCESS Port feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Port,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT;\r
+ DeviceRequest.Value = Value;\r
+ DeviceRequest.Index = Port;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Get a given hub status.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param HubStatus Current Hub status and change status.\r
+\r
+ @retval EFI_SUCCESS Hub status is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubGetHubStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ OUT UINT32 *HubStatus\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_GET_HUB_STATUS;\r
+ DeviceRequest.Length = (UINT16) sizeof (UINT32);\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ HubStatus,\r
+ sizeof (UINT32)\r
+ );\r
+}\r
+\r
+/**\r
+ Set specified feature to a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value New feature value.\r
+\r
+ @retval EFI_SUCCESS Port feature is set successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubSetHubFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_SET_HUB_FEATURE_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_SET_HUB_FEATURE;\r
+ DeviceRequest.Value = Value;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Clear specified feature on a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param Value Feature value that will be cleared from the hub port.\r
+\r
+ @retval EFI_SUCCESS Hub feature is cleared successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiHubClearHubFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DeviceRequest;\r
+\r
+ ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE;\r
+ DeviceRequest.Request = USB_HUB_CLEAR_FEATURE;\r
+ DeviceRequest.Value = Value;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DeviceRequest,\r
+ EfiUsbNoData,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ NULL,\r
+ 0\r
+ );\r
+}\r
+\r
+/**\r
+ Get a given hub descriptor.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param DescriptorSize The length of Hub Descriptor buffer.\r
+ @param HubDescriptor Caller allocated buffer to store the hub descriptor if\r
+ successfully returned.\r
+\r
+ @retval EFI_SUCCESS Hub descriptor is obtained successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiGetHubDescriptor (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINTN DescriptorSize,\r
+ OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor\r
+ )\r
+{\r
+ EFI_USB_DEVICE_REQUEST DevReq;\r
+ ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));\r
+\r
+ //\r
+ // Fill Device request packet\r
+ //\r
+ DevReq.RequestType = USB_RT_HUB | 0x80;\r
+ DevReq.Request = USB_HUB_GET_DESCRIPTOR;\r
+ DevReq.Value = USB_DT_HUB << 8;\r
+ DevReq.Length = (UINT16)DescriptorSize;\r
+\r
+ return UsbIoPpi->UsbControlTransfer (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ &DevReq,\r
+ EfiUsbDataIn,\r
+ PcdGet32 (PcdUsbTransferTimeoutValue),\r
+ HubDescriptor,\r
+ (UINT16)DescriptorSize\r
+ );\r
+}\r
+\r
+/**\r
+ Configure a given hub.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param PeiUsbDevice Indicating the hub controller device that will be configured\r
+\r
+ @retval EFI_SUCCESS Hub configuration is done successfully.\r
+ @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+PeiDoHubConfig (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_DEVICE *PeiUsbDevice\r
+ )\r
+{\r
+ EFI_USB_HUB_DESCRIPTOR HubDescriptor;\r
+ EFI_STATUS Status;\r
+ EFI_USB_HUB_STATUS HubStatus;\r
+ UINTN Index;\r
+ UINT32 PortStatus;\r
+ PEI_USB_IO_PPI *UsbIoPpi;\r
+\r
+ ZeroMem (&HubDescriptor, sizeof (HubDescriptor));\r
+ UsbIoPpi = &PeiUsbDevice->UsbIoPpi;\r
+\r
+ //\r
+ // First get the hub descriptor length\r
+ //\r
+ Status = PeiGetHubDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ 2,\r
+ &HubDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // First get the whole descriptor, then\r
+ // get the number of hub ports\r
+ //\r
+ Status = PeiGetHubDescriptor (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ HubDescriptor.Length,\r
+ &HubDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ PeiUsbDevice->DownStreamPortNo = HubDescriptor.NbrPorts;\r
+\r
+ Status = PeiHubGetHubStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT32 *) &HubStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Get all hub ports status\r
+ //\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+\r
+ Status = PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ &PortStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // Power all the hub ports\r
+ //\r
+ for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) {\r
+ Status = PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT8) (Index + 1),\r
+ EfiUsbPortPower\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // Clear Hub Status Change\r
+ //\r
+ Status = PeiHubGetHubStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ (UINT32 *) &HubStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // Hub power supply change happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_LOCAL_POWER\r
+ );\r
+ }\r
+ //\r
+ // Hub change overcurrent happens\r
+ //\r
+ if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) {\r
+ PeiHubClearHubFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ C_HUB_OVER_CURRENT\r
+ );\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send reset signal over the given root hub port.\r
+\r
+ @param PeiServices General-purpose services that are available to every PEIM.\r
+ @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance.\r
+ @param PortNum Usb hub port number (starting from 1).\r
+\r
+**/\r
+VOID\r
+PeiResetHubPort (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_IO_PPI *UsbIoPpi,\r
+ IN UINT8 PortNum\r
+ )\r
+{\r
+ UINT8 Try;\r
+ EFI_USB_PORT_STATUS HubPortStatus;\r
+\r
+\r
+ MicroSecondDelay (100 * 1000);\r
+\r
+ //\r
+ // reset root port\r
+ //\r
+ PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+\r
+ Try = 10;\r
+ do {\r
+ PeiHubGetPortStatus (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ (UINT32 *) &HubPortStatus\r
+ );\r
+\r
+ MicroSecondDelay (2 * 1000);\r
+ Try -= 1;\r
+ } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Try > 0);\r
+\r
+ //\r
+ // clear reset root port\r
+ //\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortReset\r
+ );\r
+\r
+ MicroSecondDelay (1 * 1000);\r
+\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortConnectChange\r
+ );\r
+\r
+ //\r
+ // Set port enable\r
+ //\r
+ PeiHubSetPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortEnable\r
+ );\r
+\r
+ //\r
+ // Clear any change status\r
+ //\r
+\r
+ PeiHubClearPortFeature (\r
+ PeiServices,\r
+ UsbIoPpi,\r
+ PortNum,\r
+ EfiUsbPortEnableChange\r
+ );\r
+\r
+ MicroSecondDelay (10 * 1000);\r
+\r
+ return;\r
+}\r