X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FPci%2FEhciDxe%2FEhci.c;h=0b7270f4e9305136b17425e05581a0f5a9be7f22;hb=1436aea4d5707e672672a11bda72be2c63c936c3;hp=3161ede9498ff0340105f003c4664c7619f7b22d;hpb=e172ea16a7002f736a0c3d39c127a890f120d374;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c index 3161ede949..0b7270f4e9 100644 --- a/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c +++ b/MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c @@ -1,27 +1,21 @@ -/** @file +/** @file The Ehci controller driver. - EhciDxe driver is responsible for managing the behavior of EHCI controller. - It implements the interfaces of monitoring the status of all ports and transferring + 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. + to the EHCI controller before a UHCI or OHCI driver attaches to the companion UHCI or + OHCI controller. This way avoids the control transfer on a shared port between EHCI + and companion host controller when UHCI or OHCI 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 -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. +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent **/ - #include "Ehci.h" // @@ -29,23 +23,23 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // to the UEFI protocol's port state (change). // USB_PORT_STATE_MAP mUsbPortStateMap[] = { - {PORTSC_CONN, USB_PORT_STAT_CONNECTION}, - {PORTSC_ENABLED, USB_PORT_STAT_ENABLE}, - {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND}, - {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT}, - {PORTSC_RESET, USB_PORT_STAT_RESET}, - {PORTSC_POWER, USB_PORT_STAT_POWER}, - {PORTSC_OWNER, USB_PORT_STAT_OWNER} + { PORTSC_CONN, USB_PORT_STAT_CONNECTION }, + { PORTSC_ENABLED, USB_PORT_STAT_ENABLE }, + { PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND }, + { PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT }, + { PORTSC_RESET, USB_PORT_STAT_RESET }, + { PORTSC_POWER, USB_PORT_STAT_POWER }, + { PORTSC_OWNER, USB_PORT_STAT_OWNER } }; USB_PORT_STATE_MAP mUsbPortChangeMap[] = { - {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION}, - {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE}, - {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT} + { PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION }, + { PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE }, + { PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT } }; EFI_DRIVER_BINDING_PROTOCOL -gEhciDriverBinding = { + gEhciDriverBinding = { EhcDriverBindingSupported, EhcDriverBindingStart, EhcDriverBindingStop, @@ -76,27 +70,26 @@ EhcGetCapability ( OUT UINT8 *Is64BitCapable ) { - USB2_HC_DEV *Ehc; - EFI_TPL OldTpl; + USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) { return EFI_INVALID_PARAMETER; } - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); *MaxSpeed = EFI_USB_SPEED_HIGH; - *PortNumber = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS); - *Is64BitCapable = (UINT8) (Ehc->HcCapParams & HCCP_64BIT); + *PortNumber = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS); + *Is64BitCapable = (UINT8)Ehc->Support64BitDma; - DEBUG ((EFI_D_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable)); + DEBUG ((DEBUG_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable)); gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; } - /** Provides software reset for the USB host controller. @@ -113,68 +106,84 @@ EhcGetCapability ( EFI_STATUS EFIAPI EhcReset ( - IN EFI_USB2_HC_PROTOCOL *This, - IN UINT16 Attributes + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT16 Attributes ) { - USB2_HC_DEV *Ehc; - EFI_TPL OldTpl; - EFI_STATUS Status; + USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; + EFI_STATUS Status; - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + Ehc = EHC_FROM_THIS (This); - switch (Attributes) { - case EFI_USB_HC_RESET_GLOBAL: - // - // Flow through, same behavior as Host Controller Reset - // - case EFI_USB_HC_RESET_HOST_CONTROLLER: + if (Ehc->DevicePath != NULL) { // - // Host Controller must be Halt when Reset it + // Report Status Code to indicate reset happens // - if (!EhcIsHalt (Ehc)) { - Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_USB | EFI_IOB_PC_RESET), + Ehc->DevicePath + ); + } - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto ON_EXIT; - } - } + OldTpl = gBS->RaiseTPL (EHC_TPL); + switch (Attributes) { + case EFI_USB_HC_RESET_GLOBAL: // - // Clean up the asynchronous transfers, currently only - // interrupt supports asynchronous operation. + // Flow through, same behavior as Host Controller Reset // - EhciDelAllAsyncIntTransfers (Ehc); - EhcAckAllInterrupt (Ehc); - EhcFreeSched (Ehc); + case EFI_USB_HC_RESET_HOST_CONTROLLER: + // + // Host Controller must be Halt when Reset it + // + if (EhcIsDebugPortInUse (Ehc, NULL)) { + Status = EFI_SUCCESS; + goto ON_EXIT; + } - Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT); + if (!EhcIsHalt (Ehc)) { + Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + } - Status = EhcInitHC (Ehc); - break; + // + // Clean up the asynchronous transfers, currently only + // interrupt supports asynchronous operation. + // + EhciDelAllAsyncIntTransfers (Ehc); + EhcAckAllInterrupt (Ehc); + EhcFreeSched (Ehc); - case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG: - case EFI_USB_HC_RESET_HOST_WITH_DEBUG: - Status = EFI_UNSUPPORTED; - break; + Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT); - default: - Status = EFI_INVALID_PARAMETER; + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = EhcInitHC (Ehc); + break; + + case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG: + case EFI_USB_HC_RESET_HOST_WITH_DEBUG: + Status = EFI_UNSUPPORTED; + break; + + default: + Status = EFI_INVALID_PARAMETER; } ON_EXIT: - DEBUG ((EFI_D_INFO, "EhcReset: exit status %r\n", Status)); + DEBUG ((DEBUG_INFO, "EhcReset: exit status %r\n", Status)); gBS->RestoreTPL (OldTpl); return Status; } - /** Retrieve the current state of the USB host controller. @@ -191,19 +200,19 @@ ON_EXIT: EFI_STATUS EFIAPI EhcGetState ( - IN CONST EFI_USB2_HC_PROTOCOL *This, - OUT EFI_USB_HC_STATE *State + IN EFI_USB2_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State ) { - EFI_TPL OldTpl; - USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; + USB2_HC_DEV *Ehc; if (State == NULL) { return EFI_INVALID_PARAMETER; } - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) { *State = EfiUsbHcStateHalt; @@ -213,11 +222,10 @@ EhcGetState ( gBS->RestoreTPL (OldTpl); - DEBUG ((EFI_D_INFO, "EhcGetState: current state %d\n", *State)); + DEBUG ((DEBUG_INFO, "EhcGetState: current state %d\n", *State)); return EFI_SUCCESS; } - /** Sets the USB host controller to a specific state. @@ -233,14 +241,14 @@ EhcGetState ( EFI_STATUS EFIAPI EhcSetState ( - IN EFI_USB2_HC_PROTOCOL *This, - IN EFI_USB_HC_STATE State + IN EFI_USB2_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State ) { - USB2_HC_DEV *Ehc; - EFI_TPL OldTpl; - EFI_STATUS Status; - EFI_USB_HC_STATE CurState; + USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; + EFI_STATUS Status; + EFI_USB_HC_STATE CurState; Status = EhcGetState (This, &CurState); @@ -252,47 +260,46 @@ EhcSetState ( return EFI_SUCCESS; } - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); switch (State) { - case EfiUsbHcStateHalt: - Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); - break; - - case EfiUsbHcStateOperational: - if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) { - Status = EFI_DEVICE_ERROR; + case EfiUsbHcStateHalt: + Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); break; - } - // - // Software must not write a one to this field unless the host controller - // is in the Halted state. Doing so will yield undefined results. - // refers to Spec[EHCI1.0-2.3.1] - // - if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) { - Status = EFI_DEVICE_ERROR; - break; - } + case EfiUsbHcStateOperational: + if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) { + Status = EFI_DEVICE_ERROR; + break; + } - Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT); - break; + // + // Software must not write a one to this field unless the host controller + // is in the Halted state. Doing so will yield undefined results. + // refers to Spec[EHCI1.0-2.3.1] + // + if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) { + Status = EFI_DEVICE_ERROR; + break; + } - case EfiUsbHcStateSuspend: - Status = EFI_UNSUPPORTED; - break; + Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT); + break; - default: - Status = EFI_INVALID_PARAMETER; + case EfiUsbHcStateSuspend: + Status = EFI_UNSUPPORTED; + break; + + default: + Status = EFI_INVALID_PARAMETER; } - DEBUG ((EFI_D_INFO, "EhcSetState: exit status %r\n", Status)); + DEBUG ((DEBUG_INFO, "EhcSetState: exit status %r\n", Status)); gBS->RestoreTPL (OldTpl); return Status; } - /** Retrieves the current status of a USB root hub port. @@ -310,28 +317,28 @@ EhcSetState ( EFI_STATUS EFIAPI EhcGetRootHubPortStatus ( - IN CONST EFI_USB2_HC_PROTOCOL *This, - IN CONST UINT8 PortNumber, - OUT EFI_USB_PORT_STATUS *PortStatus + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 PortNumber, + OUT EFI_USB_PORT_STATUS *PortStatus ) { - USB2_HC_DEV *Ehc; - EFI_TPL OldTpl; - UINT32 Offset; - UINT32 State; - UINT32 TotalPort; - UINTN Index; - UINTN MapSize; - EFI_STATUS Status; + USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; + UINT32 Offset; + UINT32 State; + UINT32 TotalPort; + UINTN Index; + UINTN MapSize; + EFI_STATUS Status; if (PortStatus == NULL) { return EFI_INVALID_PARAMETER; } - OldTpl = gBS->RaiseTPL (EHC_TPL); + OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); - Status = EFI_SUCCESS; + Ehc = EHC_FROM_THIS (This); + Status = EFI_SUCCESS; TotalPort = (Ehc->HcStructParams & HCSP_NPORTS); @@ -340,11 +347,15 @@ EhcGetRootHubPortStatus ( goto ON_EXIT; } - Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber)); - PortStatus->PortStatus = 0; - PortStatus->PortChangeStatus = 0; + Offset = (UINT32)(EHC_PORT_STAT_OFFSET + (4 * PortNumber)); + PortStatus->PortStatus = 0; + PortStatus->PortChangeStatus = 0; + + if (EhcIsDebugPortInUse (Ehc, &PortNumber)) { + goto ON_EXIT; + } - State = EhcReadOpReg (Ehc, Offset); + State = EhcReadOpReg (Ehc, Offset); // // Identify device speed. If in K state, it is low speed. @@ -354,7 +365,6 @@ EhcGetRootHubPortStatus ( // if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) { PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED; - } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) { PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; } @@ -366,7 +376,7 @@ EhcGetRootHubPortStatus ( for (Index = 0; Index < MapSize; Index++) { if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) { - PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState); + PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState); } } @@ -374,7 +384,7 @@ EhcGetRootHubPortStatus ( for (Index = 0; Index < MapSize; Index++) { if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) { - PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState); + PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState); } } @@ -383,7 +393,6 @@ ON_EXIT: return Status; } - /** Sets a feature for the specified root hub port. @@ -404,16 +413,16 @@ EhcSetRootHubPortFeature ( IN EFI_USB_PORT_FEATURE PortFeature ) { - USB2_HC_DEV *Ehc; - EFI_TPL OldTpl; - UINT32 Offset; - UINT32 State; - UINT32 TotalPort; - EFI_STATUS Status; - - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); - Status = EFI_SUCCESS; + USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; + UINT32 Offset; + UINT32 State; + UINT32 TotalPort; + EFI_STATUS Status; + + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); + Status = EFI_SUCCESS; TotalPort = (Ehc->HcStructParams & HCSP_NPORTS); @@ -422,8 +431,8 @@ EhcSetRootHubPortFeature ( goto ON_EXIT; } - Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber)); - State = EhcReadOpReg (Ehc, Offset); + Offset = (UINT32)(EHC_PORT_STAT_OFFSET + (4 * PortNumber)); + State = EhcReadOpReg (Ehc, Offset); // // Mask off the port status change bits, these bits are @@ -432,65 +441,68 @@ EhcSetRootHubPortFeature ( State &= ~PORTSC_CHANGE_MASK; switch (PortFeature) { - case EfiUsbPortEnable: - // - // Sofeware can't set this bit, Port can only be enable by - // EHCI as a part of the reset and enable - // - State |= PORTSC_ENABLED; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortEnable: + // + // Sofeware can't set this bit, Port can only be enable by + // EHCI as a part of the reset and enable + // + State |= PORTSC_ENABLED; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortSuspend: - State |= PORTSC_SUSPEND; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortSuspend: + State |= PORTSC_SUSPEND; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortReset: - // - // Make sure Host Controller not halt before reset it - // - if (EhcIsHalt (Ehc)) { - Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT); + case EfiUsbPortReset: + // + // Make sure Host Controller not halt before reset it + // + if (EhcIsHalt (Ehc)) { + Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status)); - break; + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status)); + break; + } } - } - // - // Set one to PortReset bit must also set zero to PortEnable bit - // - State |= PORTSC_RESET; - State &= ~PORTSC_ENABLED; - EhcWriteOpReg (Ehc, Offset, State); - break; + // + // Set one to PortReset bit must also set zero to PortEnable bit + // + State |= PORTSC_RESET; + State &= ~PORTSC_ENABLED; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortPower: - // - // Not supported, ignore the operation - // - Status = EFI_SUCCESS; - break; + case EfiUsbPortPower: + // + // Set port power bit when PPC is 1 + // + if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) { + State |= PORTSC_POWER; + EhcWriteOpReg (Ehc, Offset, State); + } - case EfiUsbPortOwner: - State |= PORTSC_OWNER; - EhcWriteOpReg (Ehc, Offset, State); - break; + break; - default: - Status = EFI_INVALID_PARAMETER; + case EfiUsbPortOwner: + State |= PORTSC_OWNER; + EhcWriteOpReg (Ehc, Offset, State); + break; + + default: + Status = EFI_INVALID_PARAMETER; } ON_EXIT: - DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status)); + DEBUG ((DEBUG_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status)); gBS->RestoreTPL (OldTpl); return Status; } - /** Clears a feature for the specified root hub port. @@ -514,16 +526,16 @@ EhcClearRootHubPortFeature ( IN EFI_USB_PORT_FEATURE PortFeature ) { - USB2_HC_DEV *Ehc; - EFI_TPL OldTpl; - UINT32 Offset; - UINT32 State; - UINT32 TotalPort; - EFI_STATUS Status; - - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); - Status = EFI_SUCCESS; + USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; + UINT32 Offset; + UINT32 State; + UINT32 TotalPort; + EFI_STATUS Status; + + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); + Status = EFI_SUCCESS; TotalPort = (Ehc->HcStructParams & HCSP_NPORTS); @@ -532,91 +544,99 @@ EhcClearRootHubPortFeature ( goto ON_EXIT; } - Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber); - State = EhcReadOpReg (Ehc, Offset); + Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber); + State = EhcReadOpReg (Ehc, Offset); State &= ~PORTSC_CHANGE_MASK; switch (PortFeature) { - case EfiUsbPortEnable: - // - // Clear PORT_ENABLE feature means disable port. - // - State &= ~PORTSC_ENABLED; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortEnable: + // + // Clear PORT_ENABLE feature means disable port. + // + State &= ~PORTSC_ENABLED; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortSuspend: - // - // A write of zero to this bit is ignored by the host - // controller. The host controller will unconditionally - // set this bit to a zero when: - // 1. software sets the Forct Port Resume bit to a zero from a one. - // 2. software sets the Port Reset bit to a one frome a zero. - // - State &= ~PORSTSC_RESUME; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortSuspend: + // + // A write of zero to this bit is ignored by the host + // controller. The host controller will unconditionally + // set this bit to a zero when: + // 1. software sets the Forct Port Resume bit to a zero from a one. + // 2. software sets the Port Reset bit to a one frome a zero. + // + State &= ~PORSTSC_RESUME; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortReset: - // - // Clear PORT_RESET means clear the reset signal. - // - State &= ~PORTSC_RESET; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortReset: + // + // Clear PORT_RESET means clear the reset signal. + // + State &= ~PORTSC_RESET; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortOwner: - // - // Clear port owner means this port owned by EHC - // - State &= ~PORTSC_OWNER; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortOwner: + // + // Clear port owner means this port owned by EHC + // + State &= ~PORTSC_OWNER; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortConnectChange: - // - // Clear connect status change - // - State |= PORTSC_CONN_CHANGE; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortConnectChange: + // + // Clear connect status change + // + State |= PORTSC_CONN_CHANGE; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortEnableChange: - // - // Clear enable status change - // - State |= PORTSC_ENABLE_CHANGE; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortEnableChange: + // + // Clear enable status change + // + State |= PORTSC_ENABLE_CHANGE; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortOverCurrentChange: - // - // Clear PortOverCurrent change - // - State |= PORTSC_OVERCUR_CHANGE; - EhcWriteOpReg (Ehc, Offset, State); - break; + case EfiUsbPortOverCurrentChange: + // + // Clear PortOverCurrent change + // + State |= PORTSC_OVERCUR_CHANGE; + EhcWriteOpReg (Ehc, Offset, State); + break; - case EfiUsbPortPower: - case EfiUsbPortSuspendChange: - case EfiUsbPortResetChange: - // - // Not supported or not related operation - // - break; + case EfiUsbPortPower: + // + // Clear port power bit when PPC is 1 + // + if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) { + State &= ~PORTSC_POWER; + EhcWriteOpReg (Ehc, Offset, State); + } - default: - Status = EFI_INVALID_PARAMETER; - break; + break; + case EfiUsbPortSuspendChange: + case EfiUsbPortResetChange: + // + // Not supported or not related operation + // + break; + + default: + Status = EFI_INVALID_PARAMETER; + break; } ON_EXIT: - DEBUG ((EFI_D_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status)); + DEBUG ((DEBUG_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status)); gBS->RestoreTPL (OldTpl); return Status; } - /** Submits control transfer to a target USB device. @@ -657,11 +677,11 @@ EhcControlTransfer ( OUT UINT32 *TransferResult ) { - USB2_HC_DEV *Ehc; - URB *Urb; - EFI_TPL OldTpl; - UINT8 Endpoint; - EFI_STATUS Status; + USB2_HC_DEV *Ehc; + URB *Urb; + EFI_TPL OldTpl; + UINT8 Endpoint; + EFI_STATUS Status; // // Validate parameters @@ -672,22 +692,26 @@ EhcControlTransfer ( if ((TransferDirection != EfiUsbDataIn) && (TransferDirection != EfiUsbDataOut) && - (TransferDirection != EfiUsbNoData)) { + (TransferDirection != EfiUsbNoData)) + { return EFI_INVALID_PARAMETER; } if ((TransferDirection == EfiUsbNoData) && - ((Data != NULL) || (*DataLength != 0))) { + ((Data != NULL) || (*DataLength != 0))) + { return EFI_INVALID_PARAMETER; } if ((TransferDirection != EfiUsbNoData) && - ((Data == NULL) || (*DataLength == 0))) { + ((Data == NULL) || (*DataLength == 0))) + { return EFI_INVALID_PARAMETER; } if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) && - (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) { + (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) + { return EFI_INVALID_PARAMETER; } @@ -695,14 +719,14 @@ EhcControlTransfer ( return EFI_INVALID_PARAMETER; } - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); Status = EFI_DEVICE_ERROR; *TransferResult = EFI_USB_ERR_SYSTEM; if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) { - DEBUG ((EFI_D_ERROR, "EhcControlTransfer: HC halted at entrance\n")); + DEBUG ((DEBUG_ERROR, "EhcControlTransfer: HC halted at entrance\n")); EhcAckAllInterrupt (Ehc); goto ON_EXIT; @@ -719,26 +743,26 @@ EhcControlTransfer ( // endpoint is bidirectional. EhcCreateUrb expects this // combination of Ep addr and its direction. // - Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0)); - Urb = EhcCreateUrb ( - Ehc, - DeviceAddress, - Endpoint, - DeviceSpeed, - 0, - MaximumPacketLength, - Translator, - EHC_CTRL_TRANSFER, - Request, - Data, - *DataLength, - NULL, - NULL, - 1 - ); + Endpoint = (UINT8)(0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0)); + Urb = EhcCreateUrb ( + Ehc, + DeviceAddress, + Endpoint, + DeviceSpeed, + 0, + MaximumPacketLength, + Translator, + EHC_CTRL_TRANSFER, + Request, + Data, + *DataLength, + NULL, + NULL, + 1 + ); if (Urb == NULL) { - DEBUG ((EFI_D_ERROR, "EhcControlTransfer: failed to create URB")); + DEBUG ((DEBUG_ERROR, "EhcControlTransfer: failed to create URB")); Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; @@ -767,13 +791,12 @@ ON_EXIT: gBS->RestoreTPL (OldTpl); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); + DEBUG ((DEBUG_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); } return Status; } - /** Submits bulk transfer to a bulk endpoint of a USB device. @@ -821,16 +844,17 @@ EhcBulkTransfer ( OUT UINT32 *TransferResult ) { - USB2_HC_DEV *Ehc; - URB *Urb; - EFI_TPL OldTpl; - EFI_STATUS Status; + USB2_HC_DEV *Ehc; + URB *Urb; + EFI_TPL OldTpl; + EFI_STATUS Status; // // Validate the parameters // if ((DataLength == NULL) || (*DataLength == 0) || - (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) { + (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) + { return EFI_INVALID_PARAMETER; } @@ -840,18 +864,19 @@ EhcBulkTransfer ( if ((DeviceSpeed == EFI_USB_SPEED_LOW) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) || - ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) { + ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) + { return EFI_INVALID_PARAMETER; } - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); *TransferResult = EFI_USB_ERR_SYSTEM; Status = EFI_DEVICE_ERROR; if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) { - DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: HC is halted\n")); + DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: HC is halted\n")); EhcAckAllInterrupt (Ehc); goto ON_EXIT; @@ -881,7 +906,7 @@ EhcBulkTransfer ( ); if (Urb == NULL) { - DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: failed to create URB\n")); + DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: failed to create URB\n")); Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; @@ -907,13 +932,12 @@ ON_EXIT: gBS->RestoreTPL (OldTpl); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); + DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); } return Status; } - /** Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. @@ -946,25 +970,24 @@ ON_EXIT: EFI_STATUS EFIAPI EhcAsyncInterruptTransfer ( - IN EFI_USB2_HC_PROTOCOL * This, - IN UINT8 DeviceAddress, - IN UINT8 EndPointAddress, - IN UINT8 DeviceSpeed, - IN UINTN MaximumPacketLength, - IN BOOLEAN IsNewTransfer, - IN OUT UINT8 *DataToggle, - IN UINTN PollingInterval, - IN UINTN DataLength, - IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator, - IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, - IN VOID *Context OPTIONAL + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle, + IN UINTN PollingInterval, + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, + IN VOID *Context OPTIONAL ) { - USB2_HC_DEV *Ehc; - URB *Urb; - EFI_TPL OldTpl; - EFI_STATUS Status; - UINT8 *Data; + USB2_HC_DEV *Ehc; + URB *Urb; + EFI_TPL OldTpl; + EFI_STATUS Status; // // Validate parameters @@ -987,8 +1010,8 @@ EhcAsyncInterruptTransfer ( } } - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); // // Delete Async interrupt transfer request. DataToggle will return @@ -997,14 +1020,14 @@ EhcAsyncInterruptTransfer ( if (!IsNewTransfer) { Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle); - DEBUG ((EFI_D_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status)); + DEBUG ((DEBUG_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status)); goto ON_EXIT; } Status = EFI_SUCCESS; if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) { - DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n")); + DEBUG ((DEBUG_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n")); EhcAckAllInterrupt (Ehc); Status = EFI_DEVICE_ERROR; @@ -1013,16 +1036,7 @@ EhcAsyncInterruptTransfer ( EhcAckAllInterrupt (Ehc); - Data = AllocatePool (DataLength); - - if (Data == NULL) { - DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to allocate buffer\n")); - - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - - Urb = EhcCreateUrb ( + Urb = EhciInsertAsyncIntTransfer ( Ehc, DeviceAddress, EndPointAddress, @@ -1030,9 +1044,6 @@ EhcAsyncInterruptTransfer ( *DataToggle, MaximumPacketLength, Translator, - EHC_INT_TRANSFER_ASYNC, - NULL, - Data, DataLength, CallBackFunction, Context, @@ -1040,20 +1051,10 @@ EhcAsyncInterruptTransfer ( ); if (Urb == NULL) { - DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to create URB\n")); - - gBS->FreePool (Data); Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } - // - // New asynchronous transfer must inserted to the head. - // Check the comments in EhcMoniteAsyncRequests - // - EhcLinkQhToPeriod (Ehc, Urb->Qh); - InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList); - ON_EXIT: Ehc->PciIo->Flush (Ehc->PciIo); gBS->RestoreTPL (OldTpl); @@ -1061,7 +1062,6 @@ ON_EXIT: return Status; } - /** Submits synchronous interrupt transfer to an interrupt endpoint of a USB device. @@ -1105,20 +1105,17 @@ EhcSyncInterruptTransfer ( OUT UINT32 *TransferResult ) { - USB2_HC_DEV *Ehc; - EFI_TPL OldTpl; - URB *Urb; - EFI_STATUS Status; + USB2_HC_DEV *Ehc; + EFI_TPL OldTpl; + URB *Urb; + EFI_STATUS Status; // // Validates parameters // if ((DataLength == NULL) || (*DataLength == 0) || - (Data == NULL) || (TransferResult == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (!EHCI_IS_DATAIN (EndPointAddress)) { + (Data == NULL) || (TransferResult == NULL)) + { return EFI_INVALID_PARAMETER; } @@ -1128,18 +1125,19 @@ EhcSyncInterruptTransfer ( if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) || - ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) { + ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) + { return EFI_INVALID_PARAMETER; } - OldTpl = gBS->RaiseTPL (EHC_TPL); - Ehc = EHC_FROM_THIS (This); + OldTpl = gBS->RaiseTPL (EHC_TPL); + Ehc = EHC_FROM_THIS (This); *TransferResult = EFI_USB_ERR_SYSTEM; Status = EFI_DEVICE_ERROR; if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) { - DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n")); + DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n")); EhcAckAllInterrupt (Ehc); goto ON_EXIT; @@ -1165,7 +1163,7 @@ EhcSyncInterruptTransfer ( ); if (Urb == NULL) { - DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n")); + DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n")); Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; @@ -1183,18 +1181,18 @@ EhcSyncInterruptTransfer ( Status = EFI_SUCCESS; } + EhcFreeUrb (Ehc, Urb); ON_EXIT: Ehc->PciIo->Flush (Ehc->PciIo); gBS->RestoreTPL (OldTpl); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); + DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult)); } return Status; } - /** Submits isochronous transfer to a target USB device. @@ -1234,7 +1232,6 @@ EhcIsochronousTransfer ( return EFI_UNSUPPORTED; } - /** Submits Async isochronous transfer to a target USB device. @@ -1290,8 +1287,8 @@ EhcAsyncIsochronousTransfer ( EFI_STATUS EFIAPI EhcDriverEntryPoint ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable ) { return EfiLibInstallDriverBindingComponentName2 ( @@ -1304,7 +1301,6 @@ EhcDriverEntryPoint ( ); } - /** Test to see if this driver supports ControllerHandle. Any ControllerHandle that has Usb2HcProtocol installed will @@ -1321,14 +1317,14 @@ EhcDriverEntryPoint ( EFI_STATUS EFIAPI EhcDriverBindingSupported ( - IN EFI_DRIVER_BINDING_PROTOCOL *This, - IN EFI_HANDLE Controller, - IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { - EFI_STATUS Status; - EFI_PCI_IO_PROTOCOL *PciIo; - USB_CLASSC UsbClassCReg; + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + USB_CLASSC UsbClassCReg; // // Test whether there is PCI IO Protocol attached on the controller handle. @@ -1336,7 +1332,7 @@ EhcDriverBindingSupported ( Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, - (VOID **) &PciIo, + (VOID **)&PciIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER @@ -1362,9 +1358,9 @@ EhcDriverBindingSupported ( // // Test whether the controller belongs to Ehci type // - if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) - || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface !=PCI_IF_UHCI))) { - + if ( (UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) + || ((UsbClassCReg.ProgInterface != PCI_IF_EHCI) && (UsbClassCReg.ProgInterface != PCI_IF_UHCI) && (UsbClassCReg.ProgInterface != PCI_IF_OHCI))) + { Status = EFI_UNSUPPORTED; } @@ -1379,11 +1375,134 @@ ON_EXIT: return Status; } +/** + Get the usb debug port related information. + + @param Ehc The EHCI device. + + @retval RETURN_SUCCESS Get debug port number, bar and offset successfully. + @retval Others The usb host controller does not supported usb debug port capability. + +**/ +EFI_STATUS +EhcGetUsbDebugPortInfo ( + IN USB2_HC_DEV *Ehc + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT16 PciStatus; + UINT8 CapabilityPtr; + UINT8 CapabilityId; + UINT16 DebugPort; + EFI_STATUS Status; + + ASSERT (Ehc->PciIo != NULL); + PciIo = Ehc->PciIo; + + // + // Detect if the EHCI host controller support Capaility Pointer. + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_PRIMARY_STATUS_OFFSET, + sizeof (UINT16), + &PciStatus + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) { + // + // The Pci Device Doesn't Support Capability Pointer. + // + return EFI_UNSUPPORTED; + } + + // + // Get Pointer To Capability List + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CAPBILITY_POINTER_OFFSET, + 1, + &CapabilityPtr + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find Capability ID 0xA, Which Is For Debug Port + // + while (CapabilityPtr != 0) { + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + CapabilityPtr, + 1, + &CapabilityId + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (CapabilityId == EHC_DEBUG_PORT_CAP_ID) { + break; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + CapabilityPtr + 1, + 1, + &CapabilityPtr + ); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // No Debug Port Capability Found + // + if (CapabilityPtr == 0) { + return EFI_UNSUPPORTED; + } + + // + // Get The Base Address Of Debug Port Register In Debug Port Capability Register + // + Status = PciIo->Pci.Read ( + Ehc->PciIo, + EfiPciIoWidthUint8, + CapabilityPtr + 2, + sizeof (UINT16), + &DebugPort + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Ehc->DebugPortOffset = DebugPort & 0x1FFF; + Ehc->DebugPortBarNum = (UINT8)((DebugPort >> 13) - 1); + Ehc->DebugPortNum = (UINT8)((Ehc->HcStructParams & 0x00F00000) >> 20); + + return EFI_SUCCESS; +} /** Create and initialize a USB2_HC_DEV. @param PciIo The PciIo on this device. + @param DevicePath The device path of host controller. @param OriginalPciAttributes Original PCI attributes. @return The allocated and initialized USB2_HC_DEV structure if created, @@ -1392,12 +1511,13 @@ ON_EXIT: **/ USB2_HC_DEV * EhcCreateUsb2Hc ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN UINT64 OriginalPciAttributes + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT64 OriginalPciAttributes ) { - USB2_HC_DEV *Ehc; - EFI_STATUS Status; + USB2_HC_DEV *Ehc; + EFI_STATUS Status; Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV)); @@ -1408,25 +1528,26 @@ EhcCreateUsb2Hc ( // // Init EFI_USB2_HC_PROTOCOL interface and private data structure // - Ehc->Signature = USB2_HC_DEV_SIGNATURE; - - Ehc->Usb2Hc.GetCapability = EhcGetCapability; - Ehc->Usb2Hc.Reset = EhcReset; - Ehc->Usb2Hc.GetState = EhcGetState; - Ehc->Usb2Hc.SetState = EhcSetState; - Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer; - Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer; - Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer; - Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer; - Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer; - Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer; - Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus; - Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature; - Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature; - Ehc->Usb2Hc.MajorRevision = 0x2; - Ehc->Usb2Hc.MinorRevision = 0x0; + Ehc->Signature = USB2_HC_DEV_SIGNATURE; + + Ehc->Usb2Hc.GetCapability = EhcGetCapability; + Ehc->Usb2Hc.Reset = EhcReset; + Ehc->Usb2Hc.GetState = EhcGetState; + Ehc->Usb2Hc.SetState = EhcSetState; + Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer; + Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer; + Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer; + Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer; + Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer; + Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer; + Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus; + Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature; + Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature; + Ehc->Usb2Hc.MajorRevision = 0x2; + Ehc->Usb2Hc.MinorRevision = 0x0; Ehc->PciIo = PciIo; + Ehc->DevicePath = DevicePath; Ehc->OriginalPciAttributes = OriginalPciAttributes; InitializeListHead (&Ehc->AsyncIntTransfers); @@ -1435,14 +1556,24 @@ EhcCreateUsb2Hc ( Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET); Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF; - DEBUG ((EFI_D_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen)); + DEBUG ((DEBUG_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen)); + + // + // EHCI Controllers with a CapLen of 0 are ignored. + // + if (Ehc->CapLen == 0) { + gBS->FreePool (Ehc); + return NULL; + } + + EhcGetUsbDebugPortInfo (Ehc); // // Create AsyncRequest Polling Timer // Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, + TPL_NOTIFY, EhcMonitorAsyncRequests, Ehc, &Ehc->PollTimer @@ -1460,30 +1591,27 @@ EhcCreateUsb2Hc ( One notified function to stop the Host Controller when gBS->ExitBootServices() called. @param Event Pointer to this event - @param Context Event hanlder private data + @param Context Event handler private data **/ VOID EFIAPI EhcExitBootService ( - EFI_EVENT Event, - VOID *Context + EFI_EVENT Event, + VOID *Context ) { - USB2_HC_DEV *Ehc; + USB2_HC_DEV *Ehc; - Ehc = (USB2_HC_DEV *) Context; + Ehc = (USB2_HC_DEV *)Context; // - // Stop the Host Controller + // Reset the Host Controller // - EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); - - return; + EhcResetHC (Ehc, EHC_RESET_TIMEOUT); } - /** Starting the Usb EHCI Driver. @@ -1500,30 +1628,31 @@ EhcExitBootService ( EFI_STATUS EFIAPI EhcDriverBindingStart ( - IN EFI_DRIVER_BINDING_PROTOCOL *This, - IN EFI_HANDLE Controller, - IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { - 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; + 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 CompanionSegmentNumber; + UINTN CompanionBusNumber; + UINTN CompanionDeviceNumber; + UINTN CompanionFunctionNumber; + UINTN EhciSegmentNumber; + UINTN EhciBusNumber; + UINTN EhciDeviceNumber; + UINTN EhciFunctionNumber; + EFI_DEVICE_PATH_PROTOCOL *HcDevicePath; // // Open the PciIo Protocol, then enable the USB host controller @@ -1531,7 +1660,7 @@ EhcDriverBindingStart ( Status = gBS->OpenProtocol ( Controller, &gEfiPciIoProtocolGuid, - (VOID **) &PciIo, + (VOID **)&PciIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER @@ -1541,6 +1670,19 @@ EhcDriverBindingStart ( return Status; } + // + // Open Device Path Protocol for on USB host controller + // + HcDevicePath = NULL; + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **)&HcDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + PciAttributesSaved = FALSE; // // Save original PCI attributes @@ -1555,6 +1697,7 @@ EhcDriverBindingStart ( if (EFI_ERROR (Status)) { goto CLOSE_PCIIO; } + PciAttributesSaved = TRUE; Status = PciIo->Attributes ( @@ -1564,17 +1707,17 @@ EhcDriverBindingStart ( &Supports ); if (!EFI_ERROR (Status)) { - Supports &= EFI_PCI_DEVICE_ENABLE; - Status = PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationEnable, - Supports, - NULL - ); + Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); } if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to enable controller\n")); + DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to enable controller\n")); goto CLOSE_PCIIO; } @@ -1593,21 +1736,23 @@ EhcDriverBindingStart ( Status = EFI_UNSUPPORTED; goto CLOSE_PCIIO; } + // - // determine if the device is UHCI host controller or not. If yes, then find out the + // Determine if the device is UHCI or OHCI 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. + // UHCI or OHCI driver attaches to UHCI or OHCI host controller. // - if ((UsbClassCReg.ProgInterface == PCI_IF_UHCI) && - (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && - (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) { + if (((UsbClassCReg.ProgInterface == PCI_IF_UHCI) || (UsbClassCReg.ProgInterface == PCI_IF_OHCI)) && + (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && + (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) + { Status = PciIo->GetLocation ( - PciIo, - &UhciSegmentNumber, - &UhciBusNumber, - &UhciDeviceNumber, - &UhciFunctionNumber - ); + PciIo, + &CompanionSegmentNumber, + &CompanionBusNumber, + &CompanionDeviceNumber, + &CompanionFunctionNumber + ); if (EFI_ERROR (Status)) { goto CLOSE_PCIIO; } @@ -1628,19 +1773,19 @@ EhcDriverBindingStart ( // Get the device path on this handle // Status = gBS->HandleProtocol ( - HandleBuffer[Index], - &gEfiPciIoProtocolGuid, - (VOID **)&Instance - ); + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **)&Instance + ); ASSERT_EFI_ERROR (Status); Status = Instance->Pci.Read ( - Instance, - EfiPciIoWidthUint8, - PCI_CLASSCODE_OFFSET, - sizeof (USB_CLASSC) / sizeof (UINT8), - &UsbClassCReg - ); + Instance, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (USB_CLASSC) / sizeof (UINT8), + &UsbClassCReg + ); if (EFI_ERROR (Status)) { Status = EFI_UNSUPPORTED; @@ -1648,33 +1793,36 @@ EhcDriverBindingStart ( } if ((UsbClassCReg.ProgInterface == PCI_IF_EHCI) && - (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && - (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) { + (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) && + (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) + { Status = Instance->GetLocation ( - Instance, - &EhciSegmentNumber, - &EhciBusNumber, - &EhciDeviceNumber, - &EhciFunctionNumber - ); + 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) { + if (EhciBusNumber == CompanionBusNumber) { gBS->CloseProtocol ( - Controller, - &gEfiPciIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); - EhcDriverBindingStart(This, HandleBuffer[Index], NULL); + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + EhcDriverBindingStart (This, HandleBuffer[Index], NULL); } } } + Status = EFI_NOT_FOUND; goto CLOSE_PCIIO; } @@ -1682,15 +1830,39 @@ EhcDriverBindingStart ( // // Create then install USB2_HC_PROTOCOL // - Ehc = EhcCreateUsb2Hc (PciIo, OriginalPciAttributes); + Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes); if (Ehc == NULL) { - DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n")); + DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n")); Status = EFI_OUT_OF_RESOURCES; goto CLOSE_PCIIO; } + // + // Enable 64-bit DMA support in the PCI layer if this controller + // supports it. + // + if (EHC_BIT_IS_SET (Ehc->HcCapParams, HCCP_64BIT)) { + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE, + NULL + ); + if (!EFI_ERROR (Status)) { + Ehc->Support64BitDma = TRUE; + } else { + DEBUG (( + DEBUG_WARN, + "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n", + __FUNCTION__, + Controller, + Status + )); + } + } + Status = gBS->InstallProtocolInterface ( &Controller, &gEfiUsb2HcProtocolGuid, @@ -1699,7 +1871,7 @@ EhcDriverBindingStart ( ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n")); + DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n")); goto FREE_POOL; } @@ -1710,12 +1882,15 @@ EhcDriverBindingStart ( if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) { EhcClearLegacySupport (Ehc); } - EhcResetHC (Ehc, EHC_RESET_TIMEOUT); + + if (!EhcIsDebugPortInUse (Ehc, NULL)) { + EhcResetHC (Ehc, EHC_RESET_TIMEOUT); + } Status = EhcInitHC (Ehc); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to init host controller\n")); + DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to init host controller\n")); goto UNINSTALL_USBHC; } @@ -1725,7 +1900,7 @@ EhcDriverBindingStart ( Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n")); + DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n")); EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); goto UNINSTALL_USBHC; @@ -1765,8 +1940,7 @@ EhcDriverBindingStart ( FALSE ); - - DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller)); + DEBUG ((DEBUG_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller)); return EFI_SUCCESS; UNINSTALL_USBHC: @@ -1787,11 +1961,11 @@ CLOSE_PCIIO: // Restore original PCI attributes // PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationSet, - OriginalPciAttributes, - NULL - ); + PciIo, + EfiPciIoAttributeOperationSet, + OriginalPciAttributes, + NULL + ); } gBS->CloseProtocol ( @@ -1804,9 +1978,8 @@ CLOSE_PCIIO: return Status; } - /** - Stop this driver on ControllerHandle. Support stoping any child handles + Stop this driver on ControllerHandle. Support stopping any child handles created by this driver. @param This Protocol instance pointer. @@ -1821,10 +1994,10 @@ CLOSE_PCIIO: EFI_STATUS EFIAPI EhcDriverBindingStop ( - IN EFI_DRIVER_BINDING_PROTOCOL *This, - IN EFI_HANDLE Controller, - IN UINTN NumberOfChildren, - IN EFI_HANDLE *ChildHandleBuffer + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; @@ -1840,7 +2013,7 @@ EhcDriverBindingStop ( Status = gBS->OpenProtocol ( Controller, &gEfiUsb2HcProtocolGuid, - (VOID **) &Usb2Hc, + (VOID **)&Usb2Hc, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL @@ -1853,13 +2026,6 @@ EhcDriverBindingStop ( Ehc = EHC_FROM_THIS (Usb2Hc); PciIo = Ehc->PciIo; - // - // Stop AsyncRequest Polling timer then stop the EHCI driver - // and uninstall the EHCI protocl. - // - gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL); - EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); - Status = gBS->UninstallProtocolInterface ( Controller, &gEfiUsb2HcProtocolGuid, @@ -1870,6 +2036,13 @@ EhcDriverBindingStop ( return Status; } + // + // Stop AsyncRequest Polling timer then stop the EHCI driver + // and uninstall the EHCI protocl. + // + gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL); + EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT); + if (Ehc->PollTimer != NULL) { gBS->CloseEvent (Ehc->PollTimer); } @@ -1885,8 +2058,8 @@ EhcDriverBindingStop ( } // - // Disable routing of all ports to EHCI controller, so all ports are - // routed back to the UHCI controller. + // Disable routing of all ports to EHCI controller, so all ports are + // routed back to the UHCI or OHCI controller. // EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC); @@ -1894,11 +2067,11 @@ EhcDriverBindingStop ( // Restore original PCI attributes // PciIo->Attributes ( - PciIo, - EfiPciIoAttributeOperationSet, - Ehc->OriginalPciAttributes, - NULL - ); + PciIo, + EfiPciIoAttributeOperationSet, + Ehc->OriginalPciAttributes, + NULL + ); gBS->CloseProtocol ( Controller, @@ -1911,4 +2084,3 @@ EhcDriverBindingStop ( return EFI_SUCCESS; } -