X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FUsb%2FUsbBusPei%2FUsbPeim.c;h=86734f2f7362b4bc0c9f25705e8c9d65086bb2c8;hb=c96de1dbaedce11489974c3e977f1de4ec5cfb84;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..86734f2f73 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c +++ b/MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c @@ -1,8 +1,8 @@ /** @file The module to produce Usb Bus PPI. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
- +Copyright (c) 2006 - 2018, 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 @@ -37,7 +37,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. @@ -56,7 +56,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. @@ -77,7 +77,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. @@ -94,7 +94,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. @@ -116,7 +116,7 @@ GetExpectedDescriptor ( /** 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. @@ -142,7 +142,7 @@ PeimInitializeUsb ( } // - // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not + // gPeiUsbHostControllerPpiGuid and gPeiUsb2HostControllerPpiGuid should not // be produced at the same time // Index = 0; @@ -176,18 +176,18 @@ PeimInitializeUsb ( Index, NULL, (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 +198,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. @@ -222,10 +222,14 @@ PeiHubEnumeration ( 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 ( @@ -239,25 +243,14 @@ PeiHubEnumeration ( continue; } - if (IsPortConnectChange (PortStatus.PortChangeStatus)) { - PeiHubClearPortFeature ( - PeiServices, - UsbIoPpi, - (UINT8) (Index + 1), - EfiUsbPortConnectChange - ); - - MicroSecondDelay (100 * 1000); - + 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)) { - - PeiHubGetPortStatus ( - PeiServices, - UsbIoPpi, - (UINT8) (Index + 1), - (UINT32 *) &PortStatus - ); - // // Begin to deal with the new device // @@ -292,28 +285,53 @@ PeiHubEnumeration ( 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 ((EFI_D_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 (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 @@ -328,6 +346,7 @@ PeiHubEnumeration ( if (EFI_ERROR (Status)) { continue; } + DEBUG ((EFI_D_INFO, "PeiHubEnumeration: PeiConfigureUsbDevice Success\n")); Status = PeiServicesInstallPpi (&NewPeiUsbDevice->UsbIoPpiList); @@ -341,8 +360,43 @@ 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); + } + } + } } } @@ -352,7 +406,7 @@ PeiHubEnumeration ( /** 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. @@ -377,23 +431,29 @@ 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 { + ); + } 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 @@ -404,7 +464,7 @@ PeiUsbEnumeration ( Usb2HcPpi, (UINT8) Index, &PortStatus - ); + ); } else { UsbHcPpi->GetRootHubPortStatus ( PeiServices, @@ -413,48 +473,14 @@ PeiUsbEnumeration ( &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 ((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)) { - 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, @@ -489,33 +515,65 @@ PeiUsbEnumeration ( PeiUsbDevice->IsHub = 0x0; PeiUsbDevice->DownStreamPortNo = 0x0; - ResetRootPort ( - PeiServices, - PeiUsbDevice->UsbHcPpi, - PeiUsbDevice->Usb2HcPpi, - Index, - 0 - ); + 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); + 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 // @@ -529,7 +587,7 @@ PeiUsbEnumeration ( if (EFI_ERROR (Status)) { continue; } - DEBUG ((EFI_D_INFO, "PeiConfigureUsbDevice Success\n")); + DEBUG ((EFI_D_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n")); Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); @@ -543,6 +601,42 @@ 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 +650,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. @@ -588,9 +682,6 @@ PeiConfigureUsbDevice ( // for (Retry = 0; Retry < 3; Retry ++) { - - PeiUsbDevice->MaxPacketSize0 = 8; - Status = PeiUsbGetDescriptor ( PeiServices, UsbIoPpi, @@ -601,17 +692,21 @@ PeiConfigureUsbDevice ( ); if (!EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "PeiUsbGet Device Descriptor the %d time Sucess\n", Retry)); + 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\n", Retry)); + DEBUG ((EFI_D_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) ++; @@ -622,9 +717,10 @@ PeiConfigureUsbDevice ( ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed\n")); + DEBUG ((EFI_D_ERROR, "PeiUsbSetDeviceAddress Failed: %r\n", Status)); return Status; } + MicroSecondDelay (USB_SET_DEVICE_ADDRESS_STALL); PeiUsbDevice->DeviceAddress = *DeviceAddress; @@ -644,6 +740,7 @@ PeiConfigureUsbDevice ( DEBUG ((EFI_D_ERROR, "PeiUsbGetDescriptor First Failed\n")); return Status; } + // // Get its default configuration and its first interface // @@ -651,10 +748,10 @@ PeiConfigureUsbDevice ( PeiServices, PeiUsbDevice ); - if (EFI_ERROR (Status)) { return Status; } + MicroSecondDelay (USB_GET_CONFIG_DESCRIPTOR_STALL); Status = PeiUsbSetConfiguration ( PeiServices, @@ -670,7 +767,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. @@ -692,6 +789,7 @@ PeiUsbGetAllConfiguration ( UINT8 *Ptr; UINTN SkipBytes; UINTN LengthLeft; + UINTN InterfaceIndex; UINTN Index; UINTN NumOfEndpoint; @@ -713,6 +811,7 @@ PeiUsbGetAllConfiguration ( 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; @@ -755,43 +854,16 @@ PeiUsbGetAllConfiguration ( Ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR); LengthLeft = ConfigDescLength - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR); - // - // Get the first interface descriptor - // - Status = GetExpectedDescriptor ( - Ptr, - LengthLeft, - USB_DT_INTERFACE, - (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR), - &SkipBytes - ); - - if (EFI_ERROR (Status)) { - return Status; - } - - Ptr += SkipBytes; - PeiUsbDevice->InterfaceDesc = (EFI_USB_INTERFACE_DESCRIPTOR *) Ptr; + for (InterfaceIndex = 0; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) { - 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); - - for (Index = 0; Index < NumOfEndpoint; Index++) { // - // Get the endpoint descriptor + // Get the interface descriptor // Status = GetExpectedDescriptor ( Ptr, LengthLeft, - USB_DT_ENDPOINT, - (UINT8) sizeof (EFI_USB_ENDPOINT_DESCRIPTOR), + USB_DT_INTERFACE, + (UINT8) sizeof (EFI_USB_INTERFACE_DESCRIPTOR), &SkipBytes ); @@ -800,11 +872,47 @@ PeiUsbGetAllConfiguration ( } 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 +920,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. @@ -832,65 +940,70 @@ GetExpectedDescriptor ( 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. @@ -908,11 +1021,13 @@ ResetRootPort ( ) { EFI_STATUS Status; + UINTN Index; + EFI_USB_PORT_STATUS PortStatus; if (Usb2HcPpi != NULL) { MicroSecondDelay (200 * 1000); - + // // reset root port // @@ -922,14 +1037,18 @@ ResetRootPort ( PortNum, EfiUsbPortReset ); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_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 // @@ -939,21 +1058,57 @@ ResetRootPort ( PortNum, EfiUsbPortReset ); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); return; } - - MicroSecondDelay (1 * 1000); - + + 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 // @@ -963,18 +1118,18 @@ ResetRootPort ( PortNum, EfiUsbPortEnable ); - + Usb2HcPpi->ClearRootHubPortFeature ( PeiServices, Usb2HcPpi, PortNum, EfiUsbPortEnableChange ); - + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); } else { MicroSecondDelay (200 * 1000); - + // // reset root port // @@ -984,14 +1139,18 @@ ResetRootPort ( PortNum, EfiUsbPortReset ); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_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,21 +1160,57 @@ ResetRootPort ( PortNum, EfiUsbPortReset ); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "ClearRootHubPortFeature EfiUsbPortReset Failed\n")); return; } - - MicroSecondDelay (1 * 1000); - + + 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 // @@ -1025,14 +1220,14 @@ ResetRootPort ( PortNum, EfiUsbPortEnable ); - + UsbHcPpi->ClearRootHubPortFeature ( PeiServices, UsbHcPpi, PortNum, EfiUsbPortEnableChange ); - + MicroSecondDelay ((RetryIndex + 1) * 50 * 1000); } return;