]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
MdeModulePkg: Add PEI USB drivers and related PPIs
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusPei / HubPeim.c
diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c
new file mode 100644 (file)
index 0000000..5b7ebfa
--- /dev/null
@@ -0,0 +1,537 @@
+/** @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