From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c | 586 +++++++++ roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h | 258 ++++ .../MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c | 185 +++ .../MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h | 189 +++ .../MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf | 60 + .../MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni | 16 + .../Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni | 14 + .../MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c | 365 ++++++ roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c | 1243 ++++++++++++++++++++ roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h | 257 ++++ 10 files changed, 3173 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c create mode 100644 roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h (limited to 'roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei') diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c new file mode 100644 index 000000000..c44c40389 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.c @@ -0,0 +1,586 @@ +/** @file +Usb Hub Request Support In PEI Phase + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbPeim.h" +#include "HubPeim.h" +#include "PeiUsbLib.h" + +/** + Get a given hub port status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param PortStatus Current Hub port status and change status. + + @retval EFI_SUCCESS Port status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + OUT UINT32 *PortStatus + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_GET_PORT_STATUS_REQ_TYPE; + DeviceRequest.Request = USB_HUB_GET_PORT_STATUS; + DeviceRequest.Index = Port; + DeviceRequest.Length = (UINT16) sizeof (UINT32); + + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + PortStatus, + sizeof (UINT32) + ); + +} + +/** + Set specified feature to a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value New feature value. + + @retval EFI_SUCCESS Port feature is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubSetPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_SET_PORT_FEATURE_REQ_TYPE; + DeviceRequest.Request = USB_HUB_SET_PORT_FEATURE; + DeviceRequest.Value = Value; + DeviceRequest.Index = Port; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Clear specified feature on a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Port feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE; + DeviceRequest.Request = USB_HUB_CLEAR_FEATURE_PORT; + DeviceRequest.Value = Value; + DeviceRequest.Index = Port; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Get a given hub status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param HubStatus Current Hub status and change status. + + @retval EFI_SUCCESS Hub status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetHubStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + OUT UINT32 *HubStatus + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_GET_HUB_STATUS_REQ_TYPE; + DeviceRequest.Request = USB_HUB_GET_HUB_STATUS; + DeviceRequest.Length = (UINT16) sizeof (UINT32); + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + HubStatus, + sizeof (UINT32) + ); +} + + + +/** + Clear specified feature on a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Hub feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearHubFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Value + ) +{ + EFI_USB_DEVICE_REQUEST DeviceRequest; + + ZeroMem (&DeviceRequest, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DeviceRequest.RequestType = USB_HUB_CLEAR_FEATURE_REQ_TYPE; + DeviceRequest.Request = USB_HUB_CLEAR_FEATURE; + DeviceRequest.Value = Value; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DeviceRequest, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Get a given (SuperSpeed) hub descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicates the hub controller device. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param DescriptorSize The length of Hub Descriptor buffer. + @param HubDescriptor Caller allocated buffer to store the hub descriptor if + successfully returned. + + @retval EFI_SUCCESS Hub descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiGetHubDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + UINT8 DescType; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DescType = (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) ? + USB_DT_SUPERSPEED_HUB : + USB_DT_HUB; + + // + // Fill Device request packet + // + DevReq.RequestType = USB_RT_HUB | 0x80; + DevReq.Request = USB_HUB_GET_DESCRIPTOR; + DevReq.Value = (UINT16) (DescType << 8); + DevReq.Length = (UINT16) DescriptorSize; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + HubDescriptor, + (UINT16)DescriptorSize + ); +} + +/** + Read the whole usb hub descriptor. It is necessary + to do it in two steps because hub descriptor is of + variable length. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicates the hub controller device. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param HubDescriptor Caller allocated buffer to store the hub descriptor if + successfully returned. + + @retval EFI_SUCCESS Hub descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbHubReadDesc ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN PEI_USB_IO_PPI *UsbIoPpi, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ) +{ + EFI_STATUS Status; + + // + // First get the hub descriptor length + // + Status = PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, 2, HubDescriptor); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the whole hub descriptor + // + return PeiGetHubDescriptor (PeiServices, PeiUsbDevice, UsbIoPpi, HubDescriptor->Length, HubDescriptor); +} + +/** + USB hub control transfer to set the hub depth. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicates the hub controller device. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Depth of the hub is set. + @retval Others Failed to set the depth. + +**/ +EFI_STATUS +PeiUsbHubCtrlSetHubDepth ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN PEI_USB_IO_PPI *UsbIoPpi + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = USB_RT_HUB; + DevReq.Request = USB_HUB_REQ_SET_DEPTH; + DevReq.Value = PeiUsbDevice->Tier; + DevReq.Length = 0; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Configure a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicating the hub controller device that will be configured + + @retval EFI_SUCCESS Hub configuration is done successfully. + @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error. + +**/ +EFI_STATUS +PeiDoHubConfig ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ) +{ + UINT8 HubDescBuffer[256]; + EFI_USB_HUB_DESCRIPTOR *HubDescriptor; + EFI_STATUS Status; + EFI_USB_HUB_STATUS HubStatus; + UINTN Index; + PEI_USB_IO_PPI *UsbIoPpi; + + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + + // + // The length field of descriptor is UINT8 type, so the buffer + // with 256 bytes is enough to hold the descriptor data. + // + HubDescriptor = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer; + + // + // Get the hub descriptor + // + Status = PeiUsbHubReadDesc ( + PeiServices, + PeiUsbDevice, + UsbIoPpi, + HubDescriptor + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + PeiUsbDevice->DownStreamPortNo = HubDescriptor->NbrPorts; + + if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_SUPER) { + DEBUG ((EFI_D_INFO, "PeiDoHubConfig: Set Hub Depth as 0x%x\n", PeiUsbDevice->Tier)); + PeiUsbHubCtrlSetHubDepth ( + PeiServices, + PeiUsbDevice, + UsbIoPpi + ); + } else { + // + // Power all the hub ports + // + for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { + Status = PeiHubSetPortFeature ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + EfiUsbPortPower + ); + if (EFI_ERROR (Status)) { + DEBUG (( EFI_D_ERROR, "PeiDoHubConfig: PeiHubSetPortFeature EfiUsbPortPower failed %x\n", Index)); + continue; + } + } + + DEBUG (( EFI_D_INFO, "PeiDoHubConfig: HubDescriptor.PwrOn2PwrGood: 0x%x\n", HubDescriptor->PwrOn2PwrGood)); + if (HubDescriptor->PwrOn2PwrGood > 0) { + MicroSecondDelay (HubDescriptor->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL); + } + + // + // Clear Hub Status Change + // + Status = PeiHubGetHubStatus ( + PeiServices, + UsbIoPpi, + (UINT32 *) &HubStatus + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } else { + // + // Hub power supply change happens + // + if ((HubStatus.HubChangeStatus & HUB_CHANGE_LOCAL_POWER) != 0) { + PeiHubClearHubFeature ( + PeiServices, + UsbIoPpi, + C_HUB_LOCAL_POWER + ); + } + // + // Hub change overcurrent happens + // + if ((HubStatus.HubChangeStatus & HUB_CHANGE_OVERCURRENT) != 0) { + PeiHubClearHubFeature ( + PeiServices, + UsbIoPpi, + C_HUB_OVER_CURRENT + ); + } + } + } + + return EFI_SUCCESS; +} + +/** + Send reset signal over the given root hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param PortNum Usb hub port number (starting from 1). + +**/ +VOID +PeiResetHubPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 PortNum + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_USB_PORT_STATUS HubPortStatus; + + MicroSecondDelay (100 * 1000); + + // + // reset root port + // + PeiHubSetPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortReset + ); + + // + // Drive the reset signal for worst 20ms. Check USB 2.0 Spec + // section 7.1.7.5 for timing requirements. + // + MicroSecondDelay (USB_SET_PORT_RESET_STALL); + + // + // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done. + // + ZeroMem (&HubPortStatus, sizeof (EFI_USB_PORT_STATUS)); + + for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) { + Status = PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + PortNum, + (UINT32 *) &HubPortStatus + ); + + if (EFI_ERROR (Status)) { + return; + } + + if (USB_BIT_IS_SET (HubPortStatus.PortChangeStatus, USB_PORT_STAT_C_RESET)) { + break; + } + + MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL); + } + + if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) { + DEBUG ((EFI_D_ERROR, "PeiResetHubPort: reset not finished in time on port %d\n", PortNum)); + return; + } + + // + // clear reset change root port + // + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortResetChange + ); + + MicroSecondDelay (1 * 1000); + + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortConnectChange + ); + + // + // Set port enable + // + PeiHubSetPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortEnable + ); + + // + // Clear any change status + // + + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + PortNum, + EfiUsbPortEnableChange + ); + + MicroSecondDelay (10 * 1000); + + return; +} diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h new file mode 100644 index 000000000..2a6d911a0 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/HubPeim.h @@ -0,0 +1,258 @@ +/** @file +Constants definitions for Usb Hub Peim + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PEI_HUB_PEIM_H_ +#define _PEI_HUB_PEIM_H_ + + +// +// Hub feature numbers +// +#define C_HUB_LOCAL_POWER 0 +#define C_HUB_OVER_CURRENT 1 + +// +// Hub class code & sub class code +// +#define CLASS_CODE_HUB 0x09 +#define SUB_CLASS_CODE_HUB 0 + +// +// Hub Status & Hub Change bit masks +// +#define HUB_STATUS_LOCAL_POWER 0x0001 +#define HUB_STATUS_OVERCURRENT 0x0002 + +#define HUB_CHANGE_LOCAL_POWER 0x0001 +#define HUB_CHANGE_OVERCURRENT 0x0002 + +// +// Hub Characteristics +// +#define HUB_CHAR_LPSM 0x0003 +#define HUB_CHAR_COMPOUND 0x0004 +#define HUB_CHAR_OCPM 0x0018 + +// +// Standard hub request and request type +// By [Spec-USB20/Chapter-11.24] +// +#define USB_HUB_CLEAR_FEATURE 0x01 +#define USB_HUB_CLEAR_FEATURE_REQ_TYPE 0x20 + +#define USB_HUB_CLEAR_FEATURE_PORT 0x01 +#define USB_HUB_CLEAR_FEATURE_PORT_REQ_TYPE 0x23 + +#define USB_HUB_GET_BUS_STATE 0x02 +#define USB_HUB_GET_BUS_STATE_REQ_TYPE 0xA3 + +#define USB_HUB_GET_DESCRIPTOR 0x06 +#define USB_HUB_GET_DESCRIPTOR_REQ_TYPE 0xA0 + +#define USB_HUB_GET_HUB_STATUS 0x00 +#define USB_HUB_GET_HUB_STATUS_REQ_TYPE 0xA0 + +#define USB_HUB_GET_PORT_STATUS 0x00 +#define USB_HUB_GET_PORT_STATUS_REQ_TYPE 0xA3 + +#define USB_HUB_SET_DESCRIPTOR 0x07 +#define USB_HUB_SET_DESCRIPTOR_REQ_TYPE 0x20 + +#define USB_HUB_SET_HUB_FEATURE 0x03 +#define USB_HUB_SET_HUB_FEATURE_REQ_TYPE 0x20 + +#define USB_HUB_SET_PORT_FEATURE 0x03 +#define USB_HUB_SET_PORT_FEATURE_REQ_TYPE 0x23 + +#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) +#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) + +#define USB_HUB_REQ_SET_DEPTH 12 + +#define MAXBYTES 8 +#pragma pack(1) +// +// Hub descriptor, the last two fields are of variable length. +// +typedef struct { + UINT8 Length; + UINT8 DescriptorType; + UINT8 NbrPorts; + UINT8 HubCharacteristics[2]; + UINT8 PwrOn2PwrGood; + UINT8 HubContrCurrent; + UINT8 Filler[MAXBYTES]; +} EFI_USB_HUB_DESCRIPTOR; + +typedef struct { + UINT16 HubStatus; + UINT16 HubChangeStatus; +} EFI_USB_HUB_STATUS; + +#pragma pack() +/** + Get a given hub port status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param PortStatus Current Hub port status and change status. + + @retval EFI_SUCCESS Port status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the port status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetPortStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + OUT UINT32 *PortStatus + ); + +/** + Set specified feature to a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value New feature value. + + @retval EFI_SUCCESS Port feature is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubSetPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ); + + +/** + Get a given hub status. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param HubStatus Current Hub status and change status. + + @retval EFI_SUCCESS Hub status is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub status due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubGetHubStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + OUT UINT32 *HubStatus + ); + +/** + Clear specified feature on a given hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Port Usb hub port number (starting from 1). + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Port feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the port feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearPortFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Port, + IN UINT8 Value + ); + +/** + Clear specified feature on a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Feature value that will be cleared from the hub port. + + @retval EFI_SUCCESS Hub feature is cleared successfully. + @retval EFI_DEVICE_ERROR Cannot clear the hub feature due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubClearHubFeature ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 Value + ); + +/** + Get a given hub descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicates the hub controller device. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param DescriptorSize The length of Hub Descriptor buffer. + @param HubDescriptor Caller allocated buffer to store the hub descriptor if + successfully returned. + + @retval EFI_SUCCESS Hub descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the hub descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiGetHubDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ); + +/** + Configure a given hub. + + @param PeiServices General-purpose services that are available to every PEIM. + @param PeiUsbDevice Indicating the hub controller device that will be configured + + @retval EFI_SUCCESS Hub configuration is done successfully. + @retval EFI_DEVICE_ERROR Cannot configure the hub due to a hardware error. + +**/ +EFI_STATUS +PeiDoHubConfig ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ); + +/** + Send reset signal over the given root hub port. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param PortNum Usb hub port number (starting from 1). + +**/ +VOID +PeiResetHubPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT8 PortNum + ); + +#endif + + diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c new file mode 100644 index 000000000..1385b0ab5 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.c @@ -0,0 +1,185 @@ +/** @file +Common Library for PEI USB + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbPeim.h" +#include "PeiUsbLib.h" + +/** + Get a given usb descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Request Value. + @param Index Request Index. + @param DescriptorLength Request descriptor Length. + @param Descriptor Request descriptor. + + + @retval EFI_SUCCESS Usb descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + OUT VOID *Descriptor + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + + ASSERT (UsbIoPpi != NULL); + + DevReq.RequestType = USB_DEV_GET_DESCRIPTOR_REQ_TYPE; + DevReq.Request = USB_DEV_GET_DESCRIPTOR; + DevReq.Value = Value; + DevReq.Index = Index; + DevReq.Length = DescriptorLength; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbDataIn, + PcdGet32 (PcdUsbTransferTimeoutValue), + Descriptor, + DescriptorLength + ); +} + +/** + Set a usb device with a specified address. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param AddressValue The address to assign. + + @retval EFI_SUCCESS Usb device address is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetDeviceAddress ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 AddressValue + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + + ASSERT (UsbIoPpi != NULL); + + DevReq.RequestType = USB_DEV_SET_ADDRESS_REQ_TYPE; + DevReq.Request = USB_DEV_SET_ADDRESS; + DevReq.Value = AddressValue; + DevReq.Index = 0; + DevReq.Length = 0; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + + + +/** + Configure a usb device to Configuration 1. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi + ) +{ + EFI_USB_DEVICE_REQUEST DevReq; + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_SET_CONFIGURATION_REQ_TYPE; + DevReq.Request = USB_DEV_SET_CONFIGURATION; + DevReq.Value = 1; + + return UsbIoPpi->UsbControlTransfer ( + PeiServices, + UsbIoPpi, + &DevReq, + EfiUsbNoData, + PcdGet32 (PcdUsbTransferTimeoutValue), + NULL, + 0 + ); +} + +/** + Judge if the port is connected with a usb device or not. + + @param PortStatus The usb port status gotten. + + @retval TRUE A usb device is connected with the port. + @retval FALSE No usb device is connected with the port. + +**/ +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ) +{ + // + // return the bit 0 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Get device speed according to port status. + + @param PortStatus The usb port status gotten. + + @return Device speed value. + +**/ +UINTN +PeiUsbGetDeviceSpeed ( + IN UINT16 PortStatus + ) +{ + if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) { + return EFI_USB_SPEED_LOW; + } else if ((PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0){ + return EFI_USB_SPEED_HIGH; + } else if ((PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) { + return EFI_USB_SPEED_SUPER; + } else { + return EFI_USB_SPEED_FULL; + } +} + + diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h new file mode 100644 index 000000000..48b8e594b --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/PeiUsbLib.h @@ -0,0 +1,189 @@ +/** @file +Common Library for PEI USB + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PEI_USB_LIB_H_ +#define _PEI_USB_LIB_H_ + + +// +// Standard device request and request type +// By [Spec-USB20/Chapter-9.4] +// +#define USB_DEV_GET_STATUS 0x00 +#define USB_DEV_GET_STATUS_REQ_TYPE_D 0x80 // Receiver : Device +#define USB_DEV_GET_STATUS_REQ_TYPE_I 0x81 // Receiver : Interface +#define USB_DEV_GET_STATUS_REQ_TYPE_E 0x82 // Receiver : Endpoint + +#define USB_DEV_CLEAR_FEATURE 0x01 +#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device +#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface +#define USB_DEV_CLEAR_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint + +#define USB_DEV_SET_FEATURE 0x03 +#define USB_DEV_SET_FEATURE_REQ_TYPE_D 0x00 // Receiver : Device +#define USB_DEV_SET_FEATURE_REQ_TYPE_I 0x01 // Receiver : Interface +#define USB_DEV_SET_FEATURE_REQ_TYPE_E 0x02 // Receiver : Endpoint + +#define USB_DEV_SET_ADDRESS 0x05 +#define USB_DEV_SET_ADDRESS_REQ_TYPE 0x00 + +#define USB_DEV_GET_DESCRIPTOR 0x06 +#define USB_DEV_GET_DESCRIPTOR_REQ_TYPE 0x80 + +#define USB_DEV_SET_DESCRIPTOR 0x07 +#define USB_DEV_SET_DESCRIPTOR_REQ_TYPE 0x00 + +#define USB_DEV_GET_CONFIGURATION 0x08 +#define USB_DEV_GET_CONFIGURATION_REQ_TYPE 0x80 + +#define USB_DEV_SET_CONFIGURATION 0x09 +#define USB_DEV_SET_CONFIGURATION_REQ_TYPE 0x00 + +#define USB_DEV_GET_INTERFACE 0x0A +#define USB_DEV_GET_INTERFACE_REQ_TYPE 0x81 + +#define USB_DEV_SET_INTERFACE 0x0B +#define USB_DEV_SET_INTERFACE_REQ_TYPE 0x01 + +#define USB_DEV_SYNCH_FRAME 0x0C +#define USB_DEV_SYNCH_FRAME_REQ_TYPE 0x82 + +// +// USB Descriptor types +// +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_HUB 0x29 +#define USB_DT_SUPERSPEED_HUB 0x2A +#define USB_DT_HID 0x21 + +// +// USB request type +// +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +// +// USB request targer device +// +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +typedef enum { + EfiUsbEndpointHalt, + EfiUsbDeviceRemoteWakeup +} EFI_USB_STANDARD_FEATURE_SELECTOR; + +// +// Usb Data recipient type +// +typedef enum { + EfiUsbDevice, + EfiUsbInterface, + EfiUsbEndpoint +} EFI_USB_RECIPIENT; + +/** + Get a given usb descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param Value Request Value. + @param Index Request Index. + @param DescriptorLength Request descriptor Length. + @param Descriptor Request descriptor. + + + @retval EFI_SUCCESS Usb descriptor is obtained successfully. + @retval EFI_DEVICE_ERROR Cannot get the usb descriptor due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 Value, + IN UINT16 Index, + IN UINT16 DescriptorLength, + OUT VOID *Descriptor + ); + +/** + Set a usb device with a specified address. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + @param AddressValue The address to assign. + + @retval EFI_SUCCESS Usb device address is set successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb address due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetDeviceAddress ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi, + IN UINT16 AddressValue + ); + + +/** + Configure a usb device to Configuration 1. + + @param PeiServices General-purpose services that are available to every PEIM. + @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Usb device is set to use Configuration 1 successfully. + @retval EFI_DEVICE_ERROR Cannot set the usb device due to a hardware error. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbSetConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *UsbIoPpi + ); + +/** + Judge if the port is connected with a usb device or not. + + @param PortStatus The usb port status gotten. + + @retval TRUE A usb device is connected with the port. + @retval FALSE No usb device is connected with the port. + +**/ +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ); + +/** + Get device speed according to port status. + + @param PortStatus The usb port status gotten. + + @return Device speed value. + +**/ +UINTN +PeiUsbGetDeviceSpeed ( + IN UINT16 PortStatus + ); + +#endif diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf new file mode 100644 index 000000000..31d7c2e2f --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.inf @@ -0,0 +1,60 @@ +## @file +# The Usb Bus Peim driver is used to support recovery from usb device. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UsbBusPei + MODULE_UNI_FILE = UsbBusPei.uni + FILE_GUID = 8401A045-6F70-4505-8471-7015B40355E3 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimInitializeUsb + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + PeiUsbLib.c + HubPeim.c + UsbIoPeim.c + UsbPeim.c + UsbPeim.h + PeiUsbLib.h + HubPeim.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + TimerLib + BaseMemoryLib + PeiServicesLib + PeimEntryPoint + DebugLib + PcdLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue ## CONSUMES + +[Ppis] + gPeiUsbIoPpiGuid ## PRODUCES + gPeiUsbHostControllerPpiGuid ## SOMETIMES_CONSUMES + gPeiUsb2HostControllerPpiGuid ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsb2HostControllerPpiGuid OR gPeiUsbHostControllerPpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + UsbBusPeiExtra.uni diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni new file mode 100644 index 000000000..92f8af732 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPei.uni @@ -0,0 +1,16 @@ +// /** @file +// The Usb Bus Peim driver is used to support recovery from usb device. +// +// The USB Bus PEIM driver is used to support recovery from USB devices. +// +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Support recovery from USB devices" + +#string STR_MODULE_DESCRIPTION #language en-US "The USB Bus PEIM driver is used to support recovery from USB devices." + diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni new file mode 100644 index 000000000..8bd6c65e7 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbBusPeiExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// UsbBusPei Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"USB Bus PEI Module for Recovery" + + diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c new file mode 100644 index 000000000..fc04f834a --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbIoPeim.c @@ -0,0 +1,365 @@ +/** @file +The module is used to implement Usb Io PPI interfaces. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbPeim.h" +#include "PeiUsbLib.h" + +/** + Submits control transfer to a target USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_IO_PPI. + @param Request USB device request to send. + @param Direction Specifies the data direction for the data stage. + @param Timeout Indicates the maximum timeout, in millisecond. If Timeout + is 0, then the caller must wait for the function to be + completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned. + @param Data Data buffer to be transmitted or received from USB device. + @param DataLength The size (in bytes) of the data buffer. + + @retval EFI_SUCCESS Transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT Transfer failed due to timeout. + @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +PeiUsbControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT32 Timeout, + IN OUT VOID *Data, OPTIONAL + IN UINTN DataLength OPTIONAL + ) +{ + EFI_STATUS Status; + PEI_USB_DEVICE *PeiUsbDev; + UINT32 TransferResult; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; + UINT8 EndpointIndex; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + EndpointDescriptor = NULL; + EndpointIndex = 0; + + if ((Request->Request == USB_REQ_CLEAR_FEATURE) && + (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) && + (Request->Value == USB_FEATURE_ENDPOINT_HALT)) { + // + // Request->Index is the Endpoint Address, use it to get the Endpoint Index. + // + while (EndpointIndex < MAX_ENDPOINT) { + Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + if (EndpointDescriptor->EndpointAddress == Request->Index) { + break; + } + + EndpointIndex++; + } + + if (EndpointIndex == MAX_ENDPOINT) { + return EFI_INVALID_PARAMETER; + } + } + + if (PeiUsbDev->Usb2HcPpi != NULL) { + Status = PeiUsbDev->Usb2HcPpi->ControlTransfer ( + PeiServices, + PeiUsbDev->Usb2HcPpi, + PeiUsbDev->DeviceAddress, + PeiUsbDev->DeviceSpeed, + PeiUsbDev->MaxPacketSize0, + Request, + Direction, + Data, + &DataLength, + Timeout, + &(PeiUsbDev->Translator), + &TransferResult + ); + } else { + Status = PeiUsbDev->UsbHcPpi->ControlTransfer ( + PeiServices, + PeiUsbDev->UsbHcPpi, + PeiUsbDev->DeviceAddress, + PeiUsbDev->DeviceSpeed, + (UINT8) PeiUsbDev->MaxPacketSize0, + Request, + Direction, + Data, + &DataLength, + Timeout, + &TransferResult + ); + } + + // + // Reset the endpoint toggle when endpoint stall is cleared + // + if ((Request->Request == USB_REQ_CLEAR_FEATURE) && + (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) && + (Request->Value == USB_FEATURE_ENDPOINT_HALT)) { + if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) { + PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex)); + } + } + + DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status)); + return Status; +} + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_IO_PPI. + @param DeviceEndpoint Endpoint number and its direction in bit 7. + @param Data A pointer to the buffer of data to transmit + from or receive into. + @param DataLength The length of the data buffer. + @param Timeout Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. If Timeout is 0, then + the caller must wait for the function to be completed + until EFI_SUCCESS or EFI_DEVICE_ERROR is returned. + + @retval EFI_SUCCESS The transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. + @retval EFI_INVALID_PARAMETER Parameters are invalid. + @retval EFI_TIMEOUT The transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. + +**/ +EFI_STATUS +EFIAPI +PeiUsbBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout + ) +{ + EFI_STATUS Status; + PEI_USB_DEVICE *PeiUsbDev; + UINT32 TransferResult; + UINTN MaxPacketLength; + UINT8 DataToggle; + UINT8 OldToggle; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; + UINT8 EndpointIndex; + VOID *Data2[EFI_USB_MAX_BULK_BUFFER_NUM]; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + EndpointDescriptor = NULL; + EndpointIndex = 0; + Data2[0] = Data; + Data2[1] = NULL; + + while (EndpointIndex < MAX_ENDPOINT) { + Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) { + break; + } + + EndpointIndex++; + } + + if (EndpointIndex == MAX_ENDPOINT) { + return EFI_INVALID_PARAMETER; + } + + MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize; + if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) { + DataToggle = 1; + } else { + DataToggle = 0; + } + + OldToggle = DataToggle; + + if (PeiUsbDev->Usb2HcPpi != NULL) { + Status = PeiUsbDev->Usb2HcPpi->BulkTransfer ( + PeiServices, + PeiUsbDev->Usb2HcPpi, + PeiUsbDev->DeviceAddress, + DeviceEndpoint, + PeiUsbDev->DeviceSpeed, + MaxPacketLength, + Data2, + DataLength, + &DataToggle, + Timeout, + &(PeiUsbDev->Translator), + &TransferResult + ); + } else { + Status = PeiUsbDev->UsbHcPpi->BulkTransfer ( + PeiServices, + PeiUsbDev->UsbHcPpi, + PeiUsbDev->DeviceAddress, + DeviceEndpoint, + (UINT8) MaxPacketLength, + Data, + DataLength, + &DataToggle, + Timeout, + &TransferResult + ); + } + + if (OldToggle != DataToggle) { + PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex)); + } + + DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status)); + return Status; +} + +/** + Get the usb interface descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + @param InterfaceDescriptor Request interface descriptor. + + + @retval EFI_SUCCESS Usb interface descriptor is obtained successfully. + +**/ +EFI_STATUS +EFIAPI +PeiUsbGetInterfaceDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor + ) +{ + PEI_USB_DEVICE *PeiUsbDev; + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + *InterfaceDescriptor = PeiUsbDev->InterfaceDesc; + return EFI_SUCCESS; +} + +/** + Get the usb endpoint descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + @param EndpointIndex The valid index of the specified endpoint. + @param EndpointDescriptor Request endpoint descriptor. + + @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully. + @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found. + +**/ +EFI_STATUS +EFIAPI +PeiUsbGetEndpointDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN UINT8 EndpointIndex, + OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor + ) +{ + PEI_USB_DEVICE *PeiUsbDev; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + ASSERT (EndpointDescriptor != NULL); + + // + // The valid range of EndpointIndex is 0..15 + // If EndpointIndex is lesser than 15 but larger than the number of interfaces, + // a EFI_NOT_FOUND should be returned + // + ASSERT (EndpointIndex <= 15); + + if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) { + return EFI_NOT_FOUND; + } + + *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex]; + + return EFI_SUCCESS; +} + +/** + Reset the port and re-configure the usb device. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Usb device is reset and configured successfully. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +EFIAPI +PeiUsbPortReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This + ) +{ + PEI_USB_DEVICE *PeiUsbDev; + EFI_STATUS Status; + UINT8 Address; + + PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); + + ResetRootPort ( + PeiServices, + PeiUsbDev->UsbHcPpi, + PeiUsbDev->Usb2HcPpi, + PeiUsbDev->DeviceAddress, + 0 + ); + + // + // Set address + // + Address = PeiUsbDev->DeviceAddress; + PeiUsbDev->DeviceAddress = 0; + + Status = PeiUsbSetDeviceAddress ( + PeiServices, + This, + Address + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + PeiUsbDev->DeviceAddress = Address; + + // + // Set default configuration + // + Status = PeiUsbSetConfiguration ( + PeiServices, + This + ); + + return Status; +} diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c new file mode 100644 index 000000000..45e48f472 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c @@ -0,0 +1,1243 @@ +/** @file +The module to produce Usb Bus PPI. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "UsbPeim.h" +#include "HubPeim.h" +#include "PeiUsbLib.h" + +// +// UsbIo PPI interface function +// +PEI_USB_IO_PPI mUsbIoPpi = { + PeiUsbControlTransfer, + PeiUsbBulkTransfer, + PeiUsbGetInterfaceDescriptor, + PeiUsbGetEndpointDescriptor, + PeiUsbPortReset +}; + +EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gPeiUsbIoPpiGuid, + NULL +}; + +/** + The enumeration routine to detect device change. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + + @retval EFI_SUCCESS The usb is enumerated successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbEnumeration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi + ); + +/** + Configure new detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + @param Port The port to be configured. + @param DeviceAddress The device address to be configured. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiConfigureUsbDevice ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN UINT8 Port, + IN OUT UINT8 *DeviceAddress + ); + +/** + Get all configurations from a detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetAllConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ); + +/** + Get the start position of next wanted descriptor. + + @param Buffer Buffer containing data to parse. + @param Length Buffer length. + @param DescType Descriptor type. + @param DescLength Descriptor length. + @param ParsedBytes Bytes has been parsed. + + @retval EFI_SUCCESS Get wanted descriptor successfully. + @retval EFI_DEVICE_ERROR Error occurred. + +**/ +EFI_STATUS +GetExpectedDescriptor ( + IN UINT8 *Buffer, + IN UINTN Length, + IN UINT8 DescType, + IN UINT8 DescLength, + OUT UINTN *ParsedBytes + ); + +/** + The entrypoint of the module, it will enumerate all HCs. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Usb initialization is done successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval EFI_UNSUPPORTED Can't find required PPI. + +**/ +EFI_STATUS +EFIAPI +PeimInitializeUsb ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINTN Index; + PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi; + PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi; + + if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) { + return EFI_SUCCESS; + } + + // + // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not + // be produced at the same time + // + Index = 0; + while (TRUE) { + // + // Get UsbHcPpi at first. + // + Status = PeiServicesLocatePpi ( + &gPeiUsbHostControllerPpiGuid, + Index, + NULL, + (VOID **) &UsbHcPpi + ); + if (EFI_ERROR (Status)) { + // + // No more host controller, break out + // + break; + } + PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL); + Index++; + } + + if (Index == 0) { + // + // Then try to get Usb2HcPpi. + // + while (TRUE) { + Status = PeiServicesLocatePpi ( + &gPeiUsb2HostControllerPpiGuid, + Index, + NULL, + (VOID **) &Usb2HcPpi + ); + if (EFI_ERROR (Status)) { + // + // No more host controller, break out + // + break; + } + PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi); + Index++; + } + } + + if (Index == 0) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + The Hub Enumeration just scans the hub ports one time. It also + doesn't support hot-plug. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + @param CurrentAddress The DeviceAddress of usb device. + + @retval EFI_SUCCESS The usb hub is enumerated successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiHubEnumeration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN UINT8 *CurrentAddress + ) +{ + UINTN Index; + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + EFI_USB_PORT_STATUS PortStatus; + UINTN MemPages; + EFI_PHYSICAL_ADDRESS AllocateAddress; + PEI_USB_DEVICE *NewPeiUsbDevice; + UINTN InterfaceIndex; + UINTN EndpointIndex; + + + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + + DEBUG ((EFI_D_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo)); + + for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { + + Status = PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + (UINT32 *) &PortStatus + ); + + if (EFI_ERROR (Status)) { + continue; + } + + DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus)); + // + // Only handle connection/enable/overcurrent/reset change. + // + if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) { + continue; + } else { + if (IsPortConnect (PortStatus.PortStatus)) { + // + // Begin to deal with the new device + // + MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + ZeroMem (NewPeiUsbDevice, sizeof (PEI_USB_DEVICE)); + + NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; + NewPeiUsbDevice->DeviceAddress = 0; + NewPeiUsbDevice->MaxPacketSize0 = 8; + NewPeiUsbDevice->DataToggle = 0; + CopyMem ( + &(NewPeiUsbDevice->UsbIoPpi), + &mUsbIoPpi, + sizeof (PEI_USB_IO_PPI) + ); + CopyMem ( + &(NewPeiUsbDevice->UsbIoPpiList), + &mUsbIoPpiList, + sizeof (EFI_PEI_PPI_DESCRIPTOR) + ); + NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi; + NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress; + NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi; + NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi; + NewPeiUsbDevice->Tier = (UINT8) (PeiUsbDevice->Tier + 1); + NewPeiUsbDevice->IsHub = 0x0; + NewPeiUsbDevice->DownStreamPortNo = 0x0; + + if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) || + ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) { + // + // If the port already has reset change flag and is connected and enabled, skip the port reset logic. + // + PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1)); + + PeiHubGetPortStatus ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + (UINT32 *) &PortStatus + ); + } else { + PeiHubClearPortFeature ( + PeiServices, + UsbIoPpi, + (UINT8) (Index + 1), + EfiUsbPortResetChange + ); + } + + NewPeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus); + DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed)); + + if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){ + NewPeiUsbDevice->MaxPacketSize0 = 512; + } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) { + NewPeiUsbDevice->MaxPacketSize0 = 64; + } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) { + NewPeiUsbDevice->MaxPacketSize0 = 8; + } else { + NewPeiUsbDevice->MaxPacketSize0 = 8; + } + + if(NewPeiUsbDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) { + if (PeiUsbDevice->DeviceSpeed == EFI_USB_SPEED_HIGH) { + NewPeiUsbDevice->Translator.TranslatorPortNumber = (UINT8)Index; + NewPeiUsbDevice->Translator.TranslatorHubAddress = *CurrentAddress; + } else { + CopyMem(&(NewPeiUsbDevice->Translator), &(PeiUsbDevice->Translator), sizeof(EFI_USB2_HC_TRANSACTION_TRANSLATOR)); + } + } + + // + // Configure that Usb Device + // + Status = PeiConfigureUsbDevice ( + PeiServices, + NewPeiUsbDevice, + (UINT8) (Index + 1), + CurrentAddress + ); + + if (EFI_ERROR (Status)) { + continue; + } + DEBUG ((EFI_D_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n")); + + Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList); + + if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { + NewPeiUsbDevice->IsHub = 0x1; + + Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress); + } + + for (InterfaceIndex = 1; InterfaceIndex < NewPeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { + // + // Begin to deal with the new device + // + MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem ((VOID *)(UINTN)AllocateAddress, NewPeiUsbDevice, sizeof (PEI_USB_DEVICE)); + NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress; + NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi; + NewPeiUsbDevice->InterfaceDesc = NewPeiUsbDevice->InterfaceDescList[InterfaceIndex]; + for (EndpointIndex = 0; EndpointIndex < NewPeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) { + NewPeiUsbDevice->EndpointDesc[EndpointIndex] = NewPeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex]; + } + + Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList); + + if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { + NewPeiUsbDevice->IsHub = 0x1; + + Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiHubEnumeration (PeiServices, NewPeiUsbDevice, CurrentAddress); + } + } + } + } + } + + + return EFI_SUCCESS; +} + +/** + The enumeration routine to detect device change. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + + @retval EFI_SUCCESS The usb is enumerated successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbEnumeration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi + ) +{ + UINT8 NumOfRootPort; + EFI_STATUS Status; + UINT8 Index; + EFI_USB_PORT_STATUS PortStatus; + PEI_USB_DEVICE *PeiUsbDevice; + UINTN MemPages; + EFI_PHYSICAL_ADDRESS AllocateAddress; + UINT8 CurrentAddress; + UINTN InterfaceIndex; + UINTN EndpointIndex; + + CurrentAddress = 0; + if (Usb2HcPpi != NULL) { + Usb2HcPpi->GetRootHubPortNumber ( + PeiServices, + Usb2HcPpi, + (UINT8 *) &NumOfRootPort + ); + } else if (UsbHcPpi != NULL) { + UsbHcPpi->GetRootHubPortNumber ( + PeiServices, + UsbHcPpi, + (UINT8 *) &NumOfRootPort + ); + } else { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort)); + + for (Index = 0; Index < NumOfRootPort; Index++) { + // + // First get root port status to detect changes happen + // + if (Usb2HcPpi != NULL) { + Usb2HcPpi->GetRootHubPortStatus ( + PeiServices, + Usb2HcPpi, + (UINT8) Index, + &PortStatus + ); + } else { + UsbHcPpi->GetRootHubPortStatus ( + PeiServices, + UsbHcPpi, + (UINT8) Index, + &PortStatus + ); + } + DEBUG ((EFI_D_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus)); + // + // Only handle connection/enable/overcurrent/reset change. + // + if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) { + continue; + } else { + if (IsPortConnect (PortStatus.PortStatus)) { + MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE)); + + PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; + PeiUsbDevice->DeviceAddress = 0; + PeiUsbDevice->MaxPacketSize0 = 8; + PeiUsbDevice->DataToggle = 0; + CopyMem ( + &(PeiUsbDevice->UsbIoPpi), + &mUsbIoPpi, + sizeof (PEI_USB_IO_PPI) + ); + CopyMem ( + &(PeiUsbDevice->UsbIoPpiList), + &mUsbIoPpiList, + sizeof (EFI_PEI_PPI_DESCRIPTOR) + ); + PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi; + PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress; + PeiUsbDevice->UsbHcPpi = UsbHcPpi; + PeiUsbDevice->Usb2HcPpi = Usb2HcPpi; + PeiUsbDevice->IsHub = 0x0; + PeiUsbDevice->DownStreamPortNo = 0x0; + + if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) || + ((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0)) { + // + // If the port already has reset change flag and is connected and enabled, skip the port reset logic. + // + ResetRootPort ( + PeiServices, + PeiUsbDevice->UsbHcPpi, + PeiUsbDevice->Usb2HcPpi, + Index, + 0 + ); + + if (Usb2HcPpi != NULL) { + Usb2HcPpi->GetRootHubPortStatus ( + PeiServices, + Usb2HcPpi, + (UINT8) Index, + &PortStatus + ); + } else { + UsbHcPpi->GetRootHubPortStatus ( + PeiServices, + UsbHcPpi, + (UINT8) Index, + &PortStatus + ); + } + } else { + if (Usb2HcPpi != NULL) { + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + (UINT8) Index, + EfiUsbPortResetChange + ); + } else { + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + (UINT8) Index, + EfiUsbPortResetChange + ); + } + } + + PeiUsbDevice->DeviceSpeed = (UINT8) PeiUsbGetDeviceSpeed (PortStatus.PortStatus); + DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed)); + + if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)){ + PeiUsbDevice->MaxPacketSize0 = 512; + } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) { + PeiUsbDevice->MaxPacketSize0 = 64; + } else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) { + PeiUsbDevice->MaxPacketSize0 = 8; + } else { + PeiUsbDevice->MaxPacketSize0 = 8; + } + + // + // Configure that Usb Device + // + Status = PeiConfigureUsbDevice ( + PeiServices, + PeiUsbDevice, + Index, + &CurrentAddress + ); + + if (EFI_ERROR (Status)) { + continue; + } + DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n")); + + Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); + + if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { + PeiUsbDevice->IsHub = 0x1; + + Status = PeiDoHubConfig (PeiServices, PeiUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress); + } + + for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { + // + // Begin to deal with the new device + // + MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE)); + PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + PeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress; + PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi; + PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex]; + for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) { + PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex]; + } + + Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); + + if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { + PeiUsbDevice->IsHub = 0x1; + + Status = PeiDoHubConfig (PeiServices, PeiUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress); + } + } + } else { + // + // Disconnect change happen, currently we don't support + // + } + } + } + + return EFI_SUCCESS; +} + +/** + Configure new detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + @param Port The port to be configured. + @param DeviceAddress The device address to be configured. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiConfigureUsbDevice ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN UINT8 Port, + IN OUT UINT8 *DeviceAddress + ) +{ + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + UINT8 Retry; + + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + Status = EFI_SUCCESS; + ZeroMem (&DeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR)); + // + // Get USB device descriptor + // + + for (Retry = 0; Retry < 3; Retry ++) { + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_DEVICE << 8), + 0, + 8, + &DeviceDescriptor + ); + + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry)); + break; + } + } + + if (Retry == 3) { + DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status)); + return Status; + } + + if ((DeviceDescriptor.BcdUSB >= 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) { + PeiUsbDevice->MaxPacketSize0 = 1 << 9; + } else { + PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0; + } + + (*DeviceAddress) ++; + + Status = PeiUsbSetDeviceAddress ( + PeiServices, + UsbIoPpi, + *DeviceAddress + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status)); + return Status; + } + MicroSecondDelay (USB_SET_DEVICE_ADDRESS_STALL); + + PeiUsbDevice->DeviceAddress = *DeviceAddress; + + // + // Get whole USB device descriptor + // + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_DEVICE << 8), + 0, + (UINT16) sizeof (EFI_USB_DEVICE_DESCRIPTOR), + &DeviceDescriptor + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n")); + return Status; + } + + // + // Get its default configuration and its first interface + // + Status = PeiUsbGetAllConfiguration ( + PeiServices, + PeiUsbDevice + ); + if (EFI_ERROR (Status)) { + return Status; + } + MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL); + + Status = PeiUsbSetConfiguration ( + PeiServices, + UsbIoPpi + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Get all configurations from a detected usb device. + + @param PeiServices Describes the list of possible PEI Services. + @param PeiUsbDevice The pointer of PEI_USB_DEVICE instance. + + @retval EFI_SUCCESS The new detected usb device is configured successfully. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +PeiUsbGetAllConfiguration ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice + ) +{ + EFI_STATUS Status; + EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc; + PEI_USB_IO_PPI *UsbIoPpi; + UINT16 ConfigDescLength; + UINT8 *Ptr; + UINTN SkipBytes; + UINTN LengthLeft; + UINTN InterfaceIndex; + UINTN Index; + UINTN NumOfEndpoint; + + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + + // + // First get its 4-byte configuration descriptor + // + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_CONFIG << 8), // Value + 0, // Index + 4, // Length + PeiUsbDevice->ConfigurationData + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor First Failed\n")); + return Status; + } + MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL); + + ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData; + ConfigDescLength = ConfigDesc->TotalLength; + + // + // Reject if TotalLength even cannot cover itself. + // + if (ConfigDescLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (ConfigDesc->TotalLength)) { + return EFI_DEVICE_ERROR; + } + + // + // Reject if TotalLength exceeds the PeiUsbDevice->ConfigurationData. + // + if (ConfigDescLength > sizeof (PeiUsbDevice->ConfigurationData)) { + return EFI_DEVICE_ERROR; + } + + // + // Then we get the total descriptors for this configuration + // + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_CONFIG << 8), + 0, + ConfigDescLength, + PeiUsbDevice->ConfigurationData + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n")); + return Status; + } + // + // Parse this configuration descriptor + // First get the current config descriptor; + // + Status = GetExpectedDescriptor ( + PeiUsbDevice->ConfigurationData, + ConfigDescLength, + USB_DT_CONFIG, + (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr = PeiUsbDevice->ConfigurationData + SkipBytes; + PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) Ptr; + + Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR); + LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR); + + for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { + + // + // Get the interface descriptor + // + Status = GetExpectedDescriptor ( + Ptr, + LengthLeft, + USB_DT_INTERFACE, + (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr += SkipBytes; + if (InterfaceIndex == 0) { + PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr; + } + PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr; + + Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + LengthLeft -= SkipBytes; + LengthLeft -= sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + + // + // Parse all the endpoint descriptor within this interface + // + NumOfEndpoint = PeiUsbDevice->InterfaceDescList[InterfaceIndex]->NumEndpoints; + ASSERT (NumOfEndpoint <= MAX_ENDPOINT); + + for (Index = 0; Index < NumOfEndpoint; Index++) { + // + // Get the endpoint descriptor + // + Status = GetExpectedDescriptor ( + Ptr, + LengthLeft, + USB_DT_ENDPOINT, + (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Ptr += SkipBytes; + if (InterfaceIndex == 0) { + PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr; + } + PeiUsbDevice->EndpointDescList[InterfaceIndex][Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr; + + Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + LengthLeft -= SkipBytes; + LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + } + } + + return EFI_SUCCESS; +} + +/** + Get the start position of next wanted descriptor. + + @param Buffer Buffer containing data to parse. + @param Length Buffer length. + @param DescType Descriptor type. + @param DescLength Descriptor length. + @param ParsedBytes Bytes has been parsed. + + @retval EFI_SUCCESS Get wanted descriptor successfully. + @retval EFI_DEVICE_ERROR Error occurred. + +**/ +EFI_STATUS +GetExpectedDescriptor ( + IN UINT8 *Buffer, + IN UINTN Length, + IN UINT8 DescType, + IN UINT8 DescLength, + OUT UINTN *ParsedBytes + ) +{ + USB_DESC_HEAD *Head; + UINTN Offset; + + // + // Total length is too small that cannot hold the single descriptor header plus data. + // + if (Length <= sizeof (USB_DESC_HEAD)) { + DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, total length = %d!\n", Length)); + return EFI_DEVICE_ERROR; + } + + // + // All the descriptor has a common LTV (Length, Type, Value) + // format. Skip the descriptor that isn't of this Type + // + Offset = 0; + Head = (USB_DESC_HEAD *)Buffer; + while (Offset < Length - sizeof (USB_DESC_HEAD)) { + // + // Above condition make sure Head->Len and Head->Type are safe to access + // + Head = (USB_DESC_HEAD *)&Buffer[Offset]; + + if (Head->Len == 0) { + DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = 0!\n")); + return EFI_DEVICE_ERROR; + } + + // + // Make sure no overflow when adding Head->Len to Offset. + // + if (Head->Len > MAX_UINTN - Offset) { + DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = %d!\n", Head->Len)); + return EFI_DEVICE_ERROR; + } + + if (Head->Type == DescType) { + break; + } + + Offset += Head->Len; + } + + // + // Head->Len is invalid resulting data beyond boundary, or + // Descriptor cannot be found: No such type. + // + if (Length < Offset) { + DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Offset/Len = %d/%d!\n", Offset, Length)); + return EFI_DEVICE_ERROR; + } + + if ((Head->Type != DescType) || (Head->Len < DescLength)) { + DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: descriptor cannot be found, Header(T/L) = %d/%d!\n", Head->Type, Head->Len)); + return EFI_DEVICE_ERROR; + } + + *ParsedBytes = Offset; + return EFI_SUCCESS; +} + +/** + Send reset signal over the given root hub port. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + @param PortNum The port to be reset. + @param RetryIndex The retry times. + +**/ +VOID +ResetRootPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi, + IN UINT8 PortNum, + IN UINT8 RetryIndex + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_USB_PORT_STATUS PortStatus; + + + if (Usb2HcPpi != NULL) { + MicroSecondDelay (200 * 1000); + + // + // reset root port + // + Status = Usb2HcPpi->SetRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + // + // Drive the reset signal for at least 50ms. Check USB 2.0 Spec + // section 7.1.7.5 for timing requirements. + // + MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL); + + // + // clear reset root port + // + Status = Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL); + + // + // USB host controller won't clear the RESET bit until + // reset is actually finished. + // + ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS)); + + for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) { + Status = Usb2HcPpi->GetRootHubPortStatus ( + PeiServices, + Usb2HcPpi, + PortNum, + &PortStatus + ); + if (EFI_ERROR (Status)) { + return; + } + + if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) { + break; + } + + MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL); + } + + if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) { + DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum)); + return; + } + + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortResetChange + ); + + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortConnectChange + ); + + // + // Set port enable + // + Usb2HcPpi->SetRootHubPortFeature( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortEnable + ); + + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortEnableChange + ); + + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); + } else { + MicroSecondDelay (200 * 1000); + + // + // reset root port + // + Status = UsbHcPpi->SetRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + // + // Drive the reset signal for at least 50ms. Check USB 2.0 Spec + // section 7.1.7.5 for timing requirements. + // + MicroSecondDelay (USB_SET_ROOT_PORT_RESET_STALL); + + // + // clear reset root port + // + Status = UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); + return; + } + + MicroSecondDelay (USB_CLR_ROOT_PORT_RESET_STALL); + + // + // USB host controller won't clear the RESET bit until + // reset is actually finished. + // + ZeroMem (&PortStatus, sizeof (EFI_USB_PORT_STATUS)); + + for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) { + Status = UsbHcPpi->GetRootHubPortStatus ( + PeiServices, + UsbHcPpi, + PortNum, + &PortStatus + ); + if (EFI_ERROR (Status)) { + return; + } + + if (!USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_RESET)) { + break; + } + + MicroSecondDelay (USB_WAIT_PORT_STS_CHANGE_STALL); + } + + if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) { + DEBUG ((EFI_D_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum)); + return; + } + + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortResetChange + ); + + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortConnectChange + ); + + // + // Set port enable + // + UsbHcPpi->SetRootHubPortFeature( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortEnable + ); + + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortEnableChange + ); + + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); + } + return; +} + + diff --git a/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h new file mode 100644 index 000000000..b55b97d87 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.h @@ -0,0 +1,257 @@ +/** @file +Usb Peim definition. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved. <BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PEI_USB_PEIM_H_ +#define _PEI_USB_PEIM_H_ + + +#include <PiPei.h> + +#include <Ppi/UsbHostController.h> +#include <Ppi/Usb2HostController.h> +#include <Ppi/UsbIo.h> + +#include <Library/DebugLib.h> +#include <Library/PeimEntryPoint.h> +#include <Library/PeiServicesLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/TimerLib.h> +#include <Library/PcdLib.h> + +#include <IndustryStandard/Usb.h> + +// +// A common header for usb standard descriptor. +// Each stand descriptor has a length and type. +// +#pragma pack(1) +typedef struct { + UINT8 Len; + UINT8 Type; +} USB_DESC_HEAD; +#pragma pack() + +#define MAX_INTERFACE 8 +#define MAX_ENDPOINT 16 + +#define PEI_USB_DEVICE_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'D') +typedef struct { + UINTN Signature; + PEI_USB_IO_PPI UsbIoPpi; + EFI_PEI_PPI_DESCRIPTOR UsbIoPpiList; + UINT16 MaxPacketSize0; + UINT16 DataToggle; + UINT8 DeviceAddress; + UINT8 DeviceSpeed; + UINT8 IsHub; + UINT8 DownStreamPortNo; + UINTN AllocateAddress; + PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi; + PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi; + UINT8 ConfigurationData[1024]; + EFI_USB_CONFIG_DESCRIPTOR *ConfigDesc; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDesc; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescList[MAX_INTERFACE]; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc[MAX_ENDPOINT]; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescList[MAX_INTERFACE][MAX_ENDPOINT]; + EFI_USB2_HC_TRANSACTION_TRANSLATOR Translator; + UINT8 Tier; +} PEI_USB_DEVICE; + +#define PEI_USB_DEVICE_FROM_THIS(a) CR (a, PEI_USB_DEVICE, UsbIoPpi, PEI_USB_DEVICE_SIGNATURE) + +#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit))) + +#define USB_BUS_1_MILLISECOND 1000 + +// +// Wait for port reset, refers to specification +// [USB20-7.1.7.5, it says 10ms for hub and 50ms for +// root hub] +// +// According to USB2.0, Chapter 11.5.1.5 Resetting, +// the worst case for TDRST is 20ms +// +#define USB_SET_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND) +#define USB_SET_ROOT_PORT_RESET_STALL (50 * USB_BUS_1_MILLISECOND) + +// +// Wait for clear roothub port reset, set by experience +// +#define USB_CLR_ROOT_PORT_RESET_STALL (20 * USB_BUS_1_MILLISECOND) + +// +// Wait for port statue reg change, set by experience +// +#define USB_WAIT_PORT_STS_CHANGE_STALL (100) + +// +// Host software return timeout if port status doesn't change +// after 500ms(LOOP * STALL = 5000 * 0.1ms), set by experience +// +#define USB_WAIT_PORT_STS_CHANGE_LOOP 5000 + +// +// Wait for hub port power-on, refers to specification +// [USB20-11.23.2] +// +#define USB_SET_PORT_POWER_STALL (2 * USB_BUS_1_MILLISECOND) + +// +// Wait for set device address, refers to specification +// [USB20-9.2.6.3, it says 2ms] +// +#define USB_SET_DEVICE_ADDRESS_STALL (2 * USB_BUS_1_MILLISECOND) + +// +// Wait for get configuration descriptor, set by experience +// +#define USB_GET_CONFIG_DESCRIPTOR_STALL (1 * USB_BUS_1_MILLISECOND) + +/** + Submits control transfer to a target USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_IO_PPI. + @param Request USB device request to send. + @param Direction Specifies the data direction for the data stage. + @param Timeout Indicates the maximum timeout, in millisecond. If Timeout + is 0, then the caller must wait for the function to be + completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned. + @param Data Data buffer to be transmitted or received from USB device. + @param DataLength The size (in bytes) of the data buffer. + + @retval EFI_SUCCESS Transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. + @retval EFI_INVALID_PARAMETER Some parameters are invalid. + @retval EFI_TIMEOUT Transfer failed due to timeout. + @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. + +**/ +EFI_STATUS +EFIAPI +PeiUsbControlTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT32 Timeout, + IN OUT VOID *Data, OPTIONAL + IN UINTN DataLength OPTIONAL + ); + +/** + Submits bulk transfer to a bulk endpoint of a USB device. + + @param PeiServices The pointer of EFI_PEI_SERVICES. + @param This The pointer of PEI_USB_IO_PPI. + @param DeviceEndpoint Endpoint number and its direction in bit 7. + @param Data A pointer to the buffer of data to transmit + from or receive into. + @param DataLength The length of the data buffer. + @param Timeout Indicates the maximum time, in millisecond, which the + transfer is allowed to complete. If Timeout is 0, then + the caller must wait for the function to be completed + until EFI_SUCCESS or EFI_DEVICE_ERROR is returned. + + @retval EFI_SUCCESS The transfer was completed successfully. + @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. + @retval EFI_INVALID_PARAMETER Parameters are invalid. + @retval EFI_TIMEOUT The transfer failed due to timeout. + @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. + +**/ +EFI_STATUS +EFIAPI +PeiUsbBulkTransfer ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout + ); + +/** + Get the usb interface descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + @param InterfaceDescriptor Request interface descriptor. + + + @retval EFI_SUCCESS Usb interface descriptor is obtained successfully. + +**/ +EFI_STATUS +EFIAPI +PeiUsbGetInterfaceDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor + ); + +/** + Get the usb endpoint descriptor. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + @param EndpointIndex The valid index of the specified endpoint. + @param EndpointDescriptor Request endpoint descriptor. + + @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully. + @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found. + +**/ +EFI_STATUS +EFIAPI +PeiUsbGetEndpointDescriptor ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This, + IN UINT8 EndpointIndex, + OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor + ); + +/** + Reset the port and re-configure the usb device. + + @param PeiServices General-purpose services that are available to every PEIM. + @param This Indicates the PEI_USB_IO_PPI instance. + + @retval EFI_SUCCESS Usb device is reset and configured successfully. + @retval Others Other failure occurs. + +**/ +EFI_STATUS +EFIAPI +PeiUsbPortReset ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_IO_PPI *This + ); + +/** + Send reset signal over the given root hub port. + + @param PeiServices Describes the list of possible PEI Services. + @param UsbHcPpi The pointer of PEI_USB_HOST_CONTROLLER_PPI instance. + @param Usb2HcPpi The pointer of PEI_USB2_HOST_CONTROLLER_PPI instance. + @param PortNum The port to be reset. + @param RetryIndex The retry times. + +**/ +VOID +ResetRootPort ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi, + IN UINT8 PortNum, + IN UINT8 RetryIndex + ); + +#endif -- cgit