X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FUsb%2FUsbBusPei%2FUsbPeim.c;h=6ea44951627a6241e5553cf4a01dad985b7cd570;hb=HEAD;hp=4a5d8e8bc4265fc143794b051401de9ca05d9aa4;hpb=2256f1f7578365c7d8acadb77a1e95373faed78b;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c index 4a5d8e8bc4..6ea4495162 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c @@ -1,16 +1,9 @@ /** @file The module to produce Usb Bus PPI. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
- -This program and the accompanying materials -are licensed and made available under the terms and conditions -of the BSD License which accompanies this distribution. The -full text of the license may be found at -http://opensource.org/licenses/bsd-license.php +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -21,7 +14,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // // UsbIo PPI interface function // -PEI_USB_IO_PPI mUsbIoPpi = { +PEI_USB_IO_PPI mUsbIoPpi = { PeiUsbControlTransfer, PeiUsbBulkTransfer, PeiUsbGetInterfaceDescriptor, @@ -29,7 +22,7 @@ PEI_USB_IO_PPI mUsbIoPpi = { PeiUsbPortReset }; -EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = { +EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = { (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gPeiUsbIoPpiGuid, NULL @@ -37,7 +30,7 @@ EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = { /** 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. @@ -49,14 +42,14 @@ EFI_PEI_PPI_DESCRIPTOR mUsbIoPpiList = { **/ EFI_STATUS PeiUsbEnumeration ( - IN EFI_PEI_SERVICES **PeiServices, - IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, - IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi + 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. @@ -69,15 +62,15 @@ PeiUsbEnumeration ( **/ EFI_STATUS PeiConfigureUsbDevice ( - IN EFI_PEI_SERVICES **PeiServices, - IN PEI_USB_DEVICE *PeiUsbDevice, - IN UINT8 Port, - IN OUT UINT8 *DeviceAddress + 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. @@ -88,13 +81,13 @@ PeiConfigureUsbDevice ( **/ EFI_STATUS PeiUsbGetAllConfiguration ( - IN EFI_PEI_SERVICES **PeiServices, - IN PEI_USB_DEVICE *PeiUsbDevice + 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. @@ -107,16 +100,16 @@ PeiUsbGetAllConfiguration ( **/ EFI_STATUS GetExpectedDescriptor ( - IN UINT8 *Buffer, - IN UINTN Length, - IN UINT8 DescType, - IN UINT8 DescLength, - OUT UINTN *ParsedBytes + 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. @@ -128,21 +121,21 @@ GetExpectedDescriptor ( EFI_STATUS EFIAPI PeimInitializeUsb ( - IN EFI_PEI_FILE_HANDLE FileHandle, - IN CONST EFI_PEI_SERVICES **PeiServices + 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; + 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 + // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not // be produced at the same time // Index = 0; @@ -154,7 +147,7 @@ PeimInitializeUsb ( &gPeiUsbHostControllerPpiGuid, Index, NULL, - (VOID **) &UsbHcPpi + (VOID **)&UsbHcPpi ); if (EFI_ERROR (Status)) { // @@ -162,7 +155,8 @@ PeimInitializeUsb ( // break; } - PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, UsbHcPpi, NULL); + + PeiUsbEnumeration ((EFI_PEI_SERVICES **)PeiServices, UsbHcPpi, NULL); Index++; } @@ -175,19 +169,20 @@ PeimInitializeUsb ( &gPeiUsb2HostControllerPpiGuid, Index, NULL, - (VOID **) &Usb2HcPpi - ); + (VOID **)&Usb2HcPpi + ); if (EFI_ERROR (Status)) { // // No more host controller, break out // break; - } - PeiUsbEnumeration ((EFI_PEI_SERVICES **) PeiServices, NULL, Usb2HcPpi); + } + + PeiUsbEnumeration ((EFI_PEI_SERVICES **)PeiServices, NULL, Usb2HcPpi); Index++; } } - + if (Index == 0) { return EFI_UNSUPPORTED; } @@ -198,7 +193,7 @@ PeimInitializeUsb ( /** 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. @@ -210,9 +205,9 @@ PeimInitializeUsb ( **/ EFI_STATUS PeiHubEnumeration ( - IN EFI_PEI_SERVICES **PeiServices, - IN PEI_USB_DEVICE *PeiUsbDevice, - IN UINT8 *CurrentAddress + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_DEVICE *PeiUsbDevice, + IN UINT8 *CurrentAddress ) { UINTN Index; @@ -222,62 +217,53 @@ PeiHubEnumeration ( UINTN MemPages; EFI_PHYSICAL_ADDRESS AllocateAddress; PEI_USB_DEVICE *NewPeiUsbDevice; + UINTN InterfaceIndex; + UINTN EndpointIndex; + UsbIoPpi = &PeiUsbDevice->UsbIoPpi; - UsbIoPpi = &PeiUsbDevice->UsbIoPpi; + DEBUG ((DEBUG_INFO, "PeiHubEnumeration: DownStreamPortNo: %x\n", PeiUsbDevice->DownStreamPortNo)); for (Index = 0; Index < PeiUsbDevice->DownStreamPortNo; Index++) { - Status = PeiHubGetPortStatus ( - PeiServices, - UsbIoPpi, - (UINT8) (Index + 1), - (UINT32 *) &PortStatus - ); + PeiServices, + UsbIoPpi, + (UINT8)(Index + 1), + (UINT32 *)&PortStatus + ); if (EFI_ERROR (Status)) { continue; } - if (IsPortConnectChange (PortStatus.PortChangeStatus)) { - PeiHubClearPortFeature ( - PeiServices, - UsbIoPpi, - (UINT8) (Index + 1), - EfiUsbPortConnectChange - ); - - MicroSecondDelay (100 * 1000); - + DEBUG ((DEBUG_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)) { - - PeiHubGetPortStatus ( - PeiServices, - UsbIoPpi, - (UINT8) (Index + 1), - (UINT32 *) &PortStatus - ); - // // Begin to deal with the new device // MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; - Status = PeiServicesAllocatePages ( - EfiBootServicesCode, - MemPages, - &AllocateAddress - ); + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } - NewPeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + 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; + NewPeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; + NewPeiUsbDevice->DeviceAddress = 0; + NewPeiUsbDevice->MaxPacketSize0 = 8; + NewPeiUsbDevice->DataToggle = 0; CopyMem ( &(NewPeiUsbDevice->UsbIoPpi), &mUsbIoPpi, @@ -289,50 +275,78 @@ PeiHubEnumeration ( sizeof (EFI_PEI_PPI_DESCRIPTOR) ); NewPeiUsbDevice->UsbIoPpiList.Ppi = &NewPeiUsbDevice->UsbIoPpi; - NewPeiUsbDevice->AllocateAddress = (UINTN) AllocateAddress; + NewPeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress; NewPeiUsbDevice->UsbHcPpi = PeiUsbDevice->UsbHcPpi; NewPeiUsbDevice->Usb2HcPpi = PeiUsbDevice->Usb2HcPpi; + NewPeiUsbDevice->Tier = (UINT8)(PeiUsbDevice->Tier + 1); NewPeiUsbDevice->IsHub = 0x0; NewPeiUsbDevice->DownStreamPortNo = 0x0; - PeiResetHubPort (PeiServices, UsbIoPpi, (UINT8)(Index + 1)); + 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 + ); + } - PeiHubGetPortStatus ( - PeiServices, - UsbIoPpi, - (UINT8) (Index + 1), - (UINT32 *) &PortStatus - ); + NewPeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus); + DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed)); - NewPeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus); + 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)); + 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 - ); + PeiServices, + NewPeiUsbDevice, + (UINT8)(Index + 1), + CurrentAddress + ); if (EFI_ERROR (Status)) { continue; } + DEBUG ((DEBUG_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n")); + Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList); if (NewPeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { - NewPeiUsbDevice->IsHub = 0x1; + NewPeiUsbDevice->IsHub = 0x1; Status = PeiDoHubConfig (PeiServices, NewPeiUsbDevice); if (EFI_ERROR (Status)) { @@ -341,18 +355,53 @@ PeiHubEnumeration ( 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. @@ -364,9 +413,9 @@ PeiHubEnumeration ( **/ EFI_STATUS PeiUsbEnumeration ( - IN EFI_PEI_SERVICES **PeiServices, - IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, - IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_USB_HOST_CONTROLLER_PPI *UsbHcPpi, + IN PEI_USB2_HOST_CONTROLLER_PPI *Usb2HcPpi ) { UINT8 NumOfRootPort; @@ -377,101 +426,74 @@ PeiUsbEnumeration ( UINTN MemPages; EFI_PHYSICAL_ADDRESS AllocateAddress; UINT8 CurrentAddress; - + UINTN InterfaceIndex; + UINTN EndpointIndex; CurrentAddress = 0; - if (Usb2HcPpi != NULL){ + if (Usb2HcPpi != NULL) { Usb2HcPpi->GetRootHubPortNumber ( - PeiServices, - Usb2HcPpi, - (UINT8 *) &NumOfRootPort - ); - } else { + PeiServices, + Usb2HcPpi, + (UINT8 *)&NumOfRootPort + ); + } else if (UsbHcPpi != NULL) { UsbHcPpi->GetRootHubPortNumber ( PeiServices, UsbHcPpi, - (UINT8 *) &NumOfRootPort + (UINT8 *)&NumOfRootPort ); + } else { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; } + DEBUG ((DEBUG_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 - ); + PeiServices, + Usb2HcPpi, + (UINT8)Index, + &PortStatus + ); } else { UsbHcPpi->GetRootHubPortStatus ( PeiServices, UsbHcPpi, - (UINT8) Index, + (UINT8)Index, &PortStatus ); } - DEBUG ((EFI_D_INFO, "USB Status --- ConnectChange[%04x] Status[%04x]\n", PortStatus.PortChangeStatus, PortStatus.PortStatus)); - if (IsPortConnectChange (PortStatus.PortChangeStatus)) { - // - // Changes happen, first clear this change status - // - if (Usb2HcPpi != NULL) { - Usb2HcPpi->ClearRootHubPortFeature ( - PeiServices, - Usb2HcPpi, - (UINT8) Index, - EfiUsbPortConnectChange - ); - } else { - UsbHcPpi->ClearRootHubPortFeature ( - PeiServices, - UsbHcPpi, - (UINT8) Index, - EfiUsbPortConnectChange - ); - } - MicroSecondDelay (100 * 1000); + DEBUG ((DEBUG_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)) { - if (Usb2HcPpi != NULL) { - Usb2HcPpi->GetRootHubPortStatus ( - PeiServices, - Usb2HcPpi, - (UINT8) Index, - &PortStatus - ); - } else { - UsbHcPpi->GetRootHubPortStatus ( - PeiServices, - UsbHcPpi, - (UINT8) Index, - &PortStatus - ); - } - - // - // Connect change happen - // MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; - Status = PeiServicesAllocatePages ( - EfiBootServicesCode, - MemPages, - &AllocateAddress - ); + Status = PeiServicesAllocatePages ( + EfiBootServicesCode, + MemPages, + &AllocateAddress + ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } - PeiUsbDevice = (PEI_USB_DEVICE *) ((UINTN) AllocateAddress); + 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; + PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; + PeiUsbDevice->DeviceAddress = 0; + PeiUsbDevice->MaxPacketSize0 = 8; + PeiUsbDevice->DataToggle = 0; CopyMem ( &(PeiUsbDevice->UsbIoPpi), &mUsbIoPpi, @@ -482,54 +504,88 @@ PeiUsbEnumeration ( &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; - - ResetRootPort ( - PeiServices, - PeiUsbDevice->UsbHcPpi, - PeiUsbDevice->Usb2HcPpi, - Index, - 0 - ); + 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 - ); + if (Usb2HcPpi != NULL) { + Usb2HcPpi->GetRootHubPortStatus ( + PeiServices, + Usb2HcPpi, + (UINT8)Index, + &PortStatus + ); + } else { + UsbHcPpi->GetRootHubPortStatus ( + PeiServices, + UsbHcPpi, + (UINT8)Index, + &PortStatus + ); + } } else { - UsbHcPpi->GetRootHubPortStatus ( - PeiServices, - UsbHcPpi, - (UINT8) Index, - &PortStatus - ); + if (Usb2HcPpi != NULL) { + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + (UINT8)Index, + EfiUsbPortResetChange + ); + } else { + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + (UINT8)Index, + EfiUsbPortResetChange + ); + } } - PeiUsbDevice->DeviceSpeed = (UINT8)IsPortLowSpeedDeviceAttached (PortStatus.PortStatus); - DEBUG ((EFI_D_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed)); + PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus); + DEBUG ((DEBUG_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 - ); + PeiServices, + PeiUsbDevice, + Index, + &CurrentAddress + ); if (EFI_ERROR (Status)) { continue; } - DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n")); + + DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n")); Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); @@ -543,6 +599,43 @@ PeiUsbEnumeration ( 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 @@ -556,7 +649,7 @@ PeiUsbEnumeration ( /** 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. @@ -569,16 +662,16 @@ PeiUsbEnumeration ( **/ EFI_STATUS PeiConfigureUsbDevice ( - IN EFI_PEI_SERVICES **PeiServices, - IN PEI_USB_DEVICE *PeiUsbDevice, - IN UINT8 Port, - IN OUT UINT8 *DeviceAddress + 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; + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; + EFI_STATUS Status; + PEI_USB_IO_PPI *UsbIoPpi; + UINT8 Retry; UsbIoPpi = &PeiUsbDevice->UsbIoPpi; Status = EFI_SUCCESS; @@ -587,10 +680,7 @@ PeiConfigureUsbDevice ( // Get USB device descriptor // - for (Retry = 0; Retry < 3; Retry ++) { - - PeiUsbDevice->MaxPacketSize0 = 8; - + for (Retry = 0; Retry < 3; Retry++) { Status = PeiUsbGetDescriptor ( PeiServices, UsbIoPpi, @@ -601,65 +691,73 @@ PeiConfigureUsbDevice ( ); if (!EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry)); + DEBUG ((DEBUG_INFO, "PeiUsbGet Device Descriptor the %d time Success\n", Retry)); break; } } if (Retry == 3) { - DEBUG ((EFI_D_ERROR, "PeiUsbGet Device Descriptor fail\n", Retry)); + DEBUG ((DEBUG_ERROR, "PeiUsbGet Device Descriptor fail: %x %r\n", Retry, Status)); return Status; } - PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0; + if ((DeviceDescriptor.BcdUSB >= 0x0300) && (DeviceDescriptor.MaxPacketSize0 == 9)) { + PeiUsbDevice->MaxPacketSize0 = 1 << 9; + } else { + PeiUsbDevice->MaxPacketSize0 = DeviceDescriptor.MaxPacketSize0; + } - (*DeviceAddress) ++; + (*DeviceAddress)++; Status = PeiUsbSetDeviceAddress ( - PeiServices, - UsbIoPpi, - *DeviceAddress - ); + PeiServices, + UsbIoPpi, + *DeviceAddress + ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n")); + DEBUG ((DEBUG_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 - ); + 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")); + DEBUG ((DEBUG_ERROR, "PeiUsbGetDescriptor First Failed\n")); return Status; } + // // Get its default configuration and its first interface // Status = PeiUsbGetAllConfiguration ( - PeiServices, - PeiUsbDevice - ); - + PeiServices, + PeiUsbDevice + ); if (EFI_ERROR (Status)) { return Status; } + MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL); + Status = PeiUsbSetConfiguration ( - PeiServices, - UsbIoPpi - ); + PeiServices, + UsbIoPpi + ); if (EFI_ERROR (Status)) { return Status; @@ -670,7 +768,7 @@ PeiConfigureUsbDevice ( /** 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. @@ -681,19 +779,20 @@ PeiConfigureUsbDevice ( **/ EFI_STATUS PeiUsbGetAllConfiguration ( - IN EFI_PEI_SERVICES **PeiServices, - IN PEI_USB_DEVICE *PeiUsbDevice + 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 Index; - UINTN NumOfEndpoint; + 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; @@ -701,110 +800,137 @@ PeiUsbGetAllConfiguration ( // First get its 4-byte configuration descriptor // Status = PeiUsbGetDescriptor ( - PeiServices, - UsbIoPpi, - (USB_DT_CONFIG << 8), // Value - 0, // Index - 4, // Length - PeiUsbDevice->ConfigurationData - ); + 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")); + DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor First Failed\n")); return Status; } - ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData; - ConfigDescLength = ConfigDesc->TotalLength; + MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL); + + ConfigDesc = (EFI_USB_CONFIG_DESCRIPTOR *)PeiUsbDevice->ConfigurationData; + ConfigDescLength = ConfigDesc->TotalLength; // - // Then we get the total descriptors for this configuration + // Reject if TotalLength even cannot cover itself. // - Status = PeiUsbGetDescriptor ( - PeiServices, - UsbIoPpi, - (USB_DT_CONFIG << 8), - 0, - ConfigDescLength, - PeiUsbDevice->ConfigurationData - ); + if (ConfigDescLength < OFFSET_OF (EFI_USB_CONFIG_DESCRIPTOR, TotalLength) + sizeof (ConfigDesc->TotalLength)) { + return EFI_DEVICE_ERROR; + } - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "PeiUsbGet Config Descriptor all Failed\n")); - return Status; + // + // Reject if TotalLength exceeds the PeiUsbDevice->ConfigurationData. + // + if (ConfigDescLength > sizeof (PeiUsbDevice->ConfigurationData)) { + return EFI_DEVICE_ERROR; } + // - // Parse this configuration descriptor - // First get the current config descriptor; + // Then we get the total descriptors for this configuration // - Status = GetExpectedDescriptor ( - PeiUsbDevice->ConfigurationData, - ConfigDescLength, - USB_DT_CONFIG, - (UINT8) sizeof (EFI_USB_CONFIG_DESCRIPTOR), - &SkipBytes - ); + Status = PeiUsbGetDescriptor ( + PeiServices, + UsbIoPpi, + (USB_DT_CONFIG << 8), + 0, + ConfigDescLength, + PeiUsbDevice->ConfigurationData + ); if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "PeiUsbGet Config Descriptor all Failed\n")); 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); - // - // Get the first interface descriptor + // Parse this configuration descriptor + // First get the current config descriptor; // Status = GetExpectedDescriptor ( - Ptr, - LengthLeft, - USB_DT_INTERFACE, - (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR), - &SkipBytes - ); + PeiUsbDevice->ConfigurationData, + ConfigDescLength, + USB_DT_CONFIG, + (UINT8)sizeof (EFI_USB_CONFIG_DESCRIPTOR), + &SkipBytes + ); if (EFI_ERROR (Status)) { return Status; } - Ptr += SkipBytes; - PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr; + Ptr = PeiUsbDevice->ConfigurationData + SkipBytes; + PeiUsbDevice->ConfigDesc = (EFI_USB_CONFIG_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->InterfaceDesc->NumEndpoints; - ASSERT (NumOfEndpoint <= MAX_ENDPOINT); + Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR); + LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR); - for (Index = 0; Index < NumOfEndpoint; Index++) { + for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { // - // Get the endpoint descriptor + // Get the interface descriptor // Status = GetExpectedDescriptor ( - Ptr, - LengthLeft, - USB_DT_ENDPOINT, - (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR), - &SkipBytes - ); + Ptr, + LengthLeft, + USB_DT_INTERFACE, + (UINT8)sizeof (EFI_USB_INTERFACE_DESCRIPTOR), + &SkipBytes + ); if (EFI_ERROR (Status)) { return Status; } Ptr += SkipBytes; - PeiUsbDevice->EndpointDesc[Index] = (EFI_USB_ENDPOINT_DESCRIPTOR *) Ptr; + if (InterfaceIndex == 0) { + PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr; + } + + PeiUsbDevice->InterfaceDescList[InterfaceIndex] = (EFI_USB_INTERFACE_DESCRIPTOR *)Ptr; - Ptr += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + Ptr += sizeof (EFI_USB_INTERFACE_DESCRIPTOR); LengthLeft -= SkipBytes; - LengthLeft -= sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + 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; @@ -812,7 +938,7 @@ PeiUsbGetAllConfiguration ( /** Get the start position of next wanted descriptor. - + @param Buffer Buffer containing data to parse. @param Length Buffer length. @param DescType Descriptor type. @@ -825,72 +951,77 @@ PeiUsbGetAllConfiguration ( **/ EFI_STATUS GetExpectedDescriptor ( - IN UINT8 *Buffer, - IN UINTN Length, - IN UINT8 DescType, - IN UINT8 DescLength, - OUT UINTN *ParsedBytes + IN UINT8 *Buffer, + IN UINTN Length, + IN UINT8 DescType, + IN UINT8 DescLength, + OUT UINTN *ParsedBytes ) { - UINT16 DescriptorHeader; - UINT8 Len; - UINT8 *Ptr; - UINTN Parsed; + USB_DESC_HEAD *Head; + UINTN Offset; - Parsed = 0; - Ptr = Buffer; + // + // 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; + } - while (TRUE) { + // + // 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)) { // - // Buffer length should not less than Desc length + // Above condition make sure Head->Len and Head->Type are safe to access // - if (Length < DescLength) { - return EFI_DEVICE_ERROR; - } - - DescriptorHeader = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8)); - - Len = Buffer[0]; + Head = (USB_DESC_HEAD *)&Buffer[Offset]; - // - // Check to see if it is a start of expected descriptor - // - if (DescriptorHeader == ((DescType << 8) | DescLength)) { - break; + if (Head->Len == 0) { + DEBUG ((DEBUG_ERROR, "GetExpectedDescriptor: met mal-format descriptor, Head->Len = 0!\n")); + return EFI_DEVICE_ERROR; } - if ((UINT8) (DescriptorHeader >> 8) == DescType) { - if (Len > DescLength) { - return EFI_DEVICE_ERROR; - } - } // - // Descriptor length should be at least 2 - // and should not exceed the buffer length + // Make sure no overflow when adding Head->Len to Offset. // - if (Len < 2) { + 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 (Len > Length) { - return EFI_DEVICE_ERROR; + if (Head->Type == DescType) { + break; } - // - // Skip this mismatch descriptor - // - Length -= Len; - Ptr += Len; - Parsed += Len; + + 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; } - *ParsedBytes = Parsed; + 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. @@ -900,81 +1031,122 @@ GetExpectedDescriptor ( **/ 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 + 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; - + 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 - ); - + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortReset + ); + if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); + DEBUG ((DEBUG_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); return; } - - MicroSecondDelay (200 * 1000); - + + // + // 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 - ); - + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortReset + ); + if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); + DEBUG ((DEBUG_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 ((DEBUG_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum)); return; } - - MicroSecondDelay (1 * 1000); - + Usb2HcPpi->ClearRootHubPortFeature ( - PeiServices, - Usb2HcPpi, - PortNum, - EfiUsbPortConnectChange - ); - + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortResetChange + ); + + Usb2HcPpi->ClearRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortConnectChange + ); + // // Set port enable // - Usb2HcPpi->SetRootHubPortFeature( - PeiServices, - Usb2HcPpi, - PortNum, - EfiUsbPortEnable - ); - + Usb2HcPpi->SetRootHubPortFeature ( + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortEnable + ); + Usb2HcPpi->ClearRootHubPortFeature ( - PeiServices, - Usb2HcPpi, - PortNum, - EfiUsbPortEnableChange - ); - + PeiServices, + Usb2HcPpi, + PortNum, + EfiUsbPortEnableChange + ); + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); } else { MicroSecondDelay (200 * 1000); - + // // reset root port // @@ -984,14 +1156,18 @@ ResetRootPort ( PortNum, EfiUsbPortReset ); - + if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); + DEBUG ((DEBUG_ERROR, "SetRootHubPortFeature EfiUsbPortReset Failed\n")); return; } - - MicroSecondDelay (200 * 1000); - + + // + // 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 // @@ -1001,41 +1177,76 @@ ResetRootPort ( PortNum, EfiUsbPortReset ); - + if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); + DEBUG ((DEBUG_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 ((DEBUG_ERROR, "ResetRootPort: reset not finished in time on port %d\n", PortNum)); return; } - - MicroSecondDelay (1 * 1000); - + + UsbHcPpi->ClearRootHubPortFeature ( + PeiServices, + UsbHcPpi, + PortNum, + EfiUsbPortResetChange + ); + UsbHcPpi->ClearRootHubPortFeature ( PeiServices, UsbHcPpi, PortNum, EfiUsbPortConnectChange ); - + // // Set port enable // - UsbHcPpi->SetRootHubPortFeature( + UsbHcPpi->SetRootHubPortFeature ( PeiServices, UsbHcPpi, PortNum, EfiUsbPortEnable ); - + UsbHcPpi->ClearRootHubPortFeature ( PeiServices, UsbHcPpi, PortNum, EfiUsbPortEnableChange ); - + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); } + return; } - -