Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15611 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1229 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1229 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| The module to produce Usb Bus PPI.
 | |
| 
 | |
| Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
|   
 | |
| 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
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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;
 | |
|   }
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   ConfigDesc        = (EFI_USB_CONFIG_DESCRIPTOR *) PeiUsbDevice->ConfigurationData;
 | |
|   ConfigDescLength  = ConfigDesc->TotalLength;
 | |
| 
 | |
|   //
 | |
|   // 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
 | |
|   )
 | |
| {
 | |
|   UINT16  DescriptorHeader;
 | |
|   UINT8   Len;
 | |
|   UINT8   *Ptr;
 | |
|   UINTN   Parsed;
 | |
| 
 | |
|   Parsed  = 0;
 | |
|   Ptr     = Buffer;
 | |
| 
 | |
|   while (TRUE) {
 | |
|     //
 | |
|     // Buffer length should not less than Desc length
 | |
|     //
 | |
|     if (Length < DescLength) {
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     DescriptorHeader  = (UINT16) (*Ptr + ((*(Ptr + 1)) << 8));
 | |
| 
 | |
|     Len               = Buffer[0];
 | |
| 
 | |
|     //
 | |
|     // Check to see if it is a start of expected descriptor
 | |
|     //
 | |
|     if (DescriptorHeader == ((DescType << 8) | DescLength)) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     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
 | |
|     //
 | |
|     if (Len < 2) {
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     if (Len > Length) {
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
|     //
 | |
|     // Skip this mismatch descriptor
 | |
|     //
 | |
|     Length -= Len;
 | |
|     Ptr += Len;
 | |
|     Parsed += Len;
 | |
|   }
 | |
| 
 | |
|   *ParsedBytes = Parsed;
 | |
| 
 | |
|   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;
 | |
| }
 | |
| 
 | |
| 
 |