X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FBus%2FPci%2FEhciDxe%2FEhci.c;h=3161ede9498ff0340105f003c4664c7619f7b22d;hp=c8de7052bb9f1b90778e188004e1bb3dd5b0cbfa;hb=8776881fe8fc4d810be60a3bb76674cb43a1d402;hpb=597f4ee21c004a25d77d0417e9de7f6d5f9aace5 diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c index c8de7052bb..3161ede949 100644 --- a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c +++ b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c @@ -1,8 +1,16 @@ -/** @file - +/** @file The Ehci controller driver. -Copyright (c) 2006 - 2009, Intel Corporation + EhciDxe driver is responsible for managing the behavior of EHCI controller. + It implements the interfaces of monitoring the status of all ports and transferring + Control, Bulk, Interrupt and Isochronous requests to Usb2.0 device. + + Note that EhciDxe driver is enhanced to guarantee that the EHCI controller get attached + to the EHCI controller before the UHCI driver attaches to the companion UHCI controller. + This way avoids the control transfer on a shared port between EHCI and companion host + controller when UHCI gets attached earlier than EHCI and a USB 2.0 device inserts. + +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 @@ -41,7 +49,7 @@ gEhciDriverBinding = { EhcDriverBindingSupported, EhcDriverBindingStart, EhcDriverBindingStop, - 0x10, + 0x30, NULL, NULL }; @@ -1341,7 +1349,7 @@ EhcDriverBindingSupported ( Status = PciIo->Pci.Read ( PciIo, EfiPciIoWidthUint8, - EHC_PCI_CLASSC, + PCI_CLASSCODE_OFFSET, sizeof (USB_CLASSC) / sizeof (UINT8), &UsbClassCReg ); @@ -1354,9 +1362,8 @@ EhcDriverBindingSupported ( // // Test whether the controller belongs to Ehci type // - if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || - (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) || - (UsbClassCReg.PI != EHC_PCI_CLASSC_PI)) { + if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) + || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface !=PCI_IF_UHCI))) { Status = EFI_UNSUPPORTED; } @@ -1449,6 +1456,33 @@ EhcCreateUsb2Hc ( return Ehc; } +/** + One notified function to stop the Host Controller when gBS->ExitBootServices() called. + + @param Event Pointer to this event + @param Context Event hanlder private data + +**/ +VOID +EFIAPI +EhcExitBootService ( + EFI_EVENT Event, + VOID *Context + ) + +{ + USB2_HC_DEV *Ehc; + + Ehc = (USB2_HC_DEV *) Context; + + // + // Stop the Host Controller + // + EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); + + return; +} + /** Starting the Usb EHCI Driver. @@ -1474,9 +1508,22 @@ EhcDriverBindingStart ( EFI_STATUS Status; USB2_HC_DEV *Ehc; EFI_PCI_IO_PROTOCOL *PciIo; + EFI_PCI_IO_PROTOCOL *Instance; UINT64 Supports; UINT64 OriginalPciAttributes; BOOLEAN PciAttributesSaved; + USB_CLASSC UsbClassCReg; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + UINTN Index; + UINTN UhciSegmentNumber; + UINTN UhciBusNumber; + UINTN UhciDeviceNumber; + UINTN UhciFunctionNumber; + UINTN EhciSegmentNumber; + UINTN EhciBusNumber; + UINTN EhciDeviceNumber; + UINTN EhciFunctionNumber; // // Open the PciIo Protocol, then enable the USB host controller @@ -1491,8 +1538,7 @@ EhcDriverBindingStart ( ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to open PCI_IO\n")); - return EFI_DEVICE_ERROR; + return Status; } PciAttributesSaved = FALSE; @@ -1532,6 +1578,107 @@ EhcDriverBindingStart ( goto CLOSE_PCIIO; } + // + // Get the Pci device class code. + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto CLOSE_PCIIO; + } + // + // determine if the device is UHCI host controller or not. If yes, then find out the + // companion usb ehci host controller and force EHCI driver get attached to it before + // UHCI driver attaches to UHCI host controller. + // + if ((UsbClassCReg.ProgInterface == PCI_IF_UHCI) && + (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && + (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) { + Status = PciIo->GetLocation ( + PciIo, + &UhciSegmentNumber, + &UhciBusNumber, + &UhciDeviceNumber, + &UhciFunctionNumber + ); + if (EFI_ERROR (Status)) { + goto CLOSE_PCIIO; + } + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + goto CLOSE_PCIIO; + } + + for (Index = 0; Index < NumberOfHandles; Index++) { + // + // Get the device path on this handle + // + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **)&Instance + ); + ASSERT_EFI_ERROR (Status); + + Status = Instance->Pci.Read ( + Instance, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); + + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto CLOSE_PCIIO; + } + + if ((UsbClassCReg.ProgInterface == PCI_IF_EHCI) && + (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && + (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) { + Status = Instance->GetLocation ( + Instance, + &EhciSegmentNumber, + &EhciBusNumber, + &EhciDeviceNumber, + &EhciFunctionNumber + ); + if (EFI_ERROR (Status)) { + goto CLOSE_PCIIO; + } + // + // Currently, the judgment on the companion usb host controller is through the + // same bus number, which may vary on different platform. + // + if (EhciBusNumber == UhciBusNumber) { + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + EhcDriverBindingStart(This, HandleBuffer[Index], NULL); + } + } + } + Status = EFI_NOT_FOUND; + goto CLOSE_PCIIO; + } + // // Create then install USB2_HC_PROTOCOL // @@ -1557,7 +1704,7 @@ EhcDriverBindingStart ( } // - // Robustnesss improvement such as for UoL + // Robustnesss improvement such as for Duet platform // Default is not required. // if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) { @@ -1584,6 +1731,21 @@ EhcDriverBindingStart ( goto UNINSTALL_USBHC; } + // + // Create event to stop the HC when exit boot service. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + EhcExitBootService, + Ehc, + &gEfiEventExitBootServicesGuid, + &Ehc->ExitBootServiceEvent + ); + if (EFI_ERROR (Status)) { + goto UNINSTALL_USBHC; + } + // // Install the component name protocol, don't fail the start // because of something for display. @@ -1712,12 +1874,22 @@ EhcDriverBindingStop ( gBS->CloseEvent (Ehc->PollTimer); } + if (Ehc->ExitBootServiceEvent != NULL) { + gBS->CloseEvent (Ehc->ExitBootServiceEvent); + } + EhcFreeSched (Ehc); if (Ehc->ControllerNameTable != NULL) { FreeUnicodeStringTable (Ehc->ControllerNameTable); } + // + // Disable routing of all ports to EHCI controller, so all ports are + // routed back to the UHCI controller. + // + EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC); + // // Restore original PCI attributes //