__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout MdeModulePkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
		
			
				
	
	
		
			2094 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2094 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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
 | 
						|
  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 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 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Ehci.h"
 | 
						|
 | 
						|
//
 | 
						|
// Two arrays used to translate the EHCI port state (change)
 | 
						|
// 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       }
 | 
						|
};
 | 
						|
 | 
						|
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 }
 | 
						|
};
 | 
						|
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL
 | 
						|
  gEhciDriverBinding = {
 | 
						|
  EhcDriverBindingSupported,
 | 
						|
  EhcDriverBindingStart,
 | 
						|
  EhcDriverBindingStop,
 | 
						|
  0x30,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieves the capability of root hub ports.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB_HC_PROTOCOL instance.
 | 
						|
  @param  MaxSpeed              Max speed supported by the controller.
 | 
						|
  @param  PortNumber            Number of the root hub ports.
 | 
						|
  @param  Is64BitCapable        Whether the controller supports 64-bit memory
 | 
						|
                                addressing.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Host controller capability were retrieved successfully.
 | 
						|
  @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcGetCapability (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL  *This,
 | 
						|
  OUT UINT8                 *MaxSpeed,
 | 
						|
  OUT UINT8                 *PortNumber,
 | 
						|
  OUT UINT8                 *Is64BitCapable
 | 
						|
  )
 | 
						|
{
 | 
						|
  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);
 | 
						|
 | 
						|
  *MaxSpeed       = EFI_USB_SPEED_HIGH;
 | 
						|
  *PortNumber     = (UINT8)(Ehc->HcStructParams & HCSP_NPORTS);
 | 
						|
  *Is64BitCapable = (UINT8)Ehc->Support64BitDma;
 | 
						|
 | 
						|
  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.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  Attributes            A bit mask of the reset operation to perform.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The reset operation succeeded.
 | 
						|
  @retval EFI_INVALID_PARAMETER Attributes is not valid.
 | 
						|
  @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is
 | 
						|
                                not currently supported by the host controller.
 | 
						|
  @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcReset (
 | 
						|
  IN EFI_USB2_HC_PROTOCOL  *This,
 | 
						|
  IN UINT16                Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB2_HC_DEV  *Ehc;
 | 
						|
  EFI_TPL      OldTpl;
 | 
						|
  EFI_STATUS   Status;
 | 
						|
 | 
						|
  Ehc = EHC_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Ehc->DevicePath != NULL) {
 | 
						|
    //
 | 
						|
    // Report Status Code to indicate reset happens
 | 
						|
    //
 | 
						|
    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
      EFI_PROGRESS_CODE,
 | 
						|
      (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
 | 
						|
      Ehc->DevicePath
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (EHC_TPL);
 | 
						|
 | 
						|
  switch (Attributes) {
 | 
						|
    case EFI_USB_HC_RESET_GLOBAL:
 | 
						|
    //
 | 
						|
    // Flow through, same behavior as Host Controller Reset
 | 
						|
    //
 | 
						|
    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;
 | 
						|
      }
 | 
						|
 | 
						|
      if (!EhcIsHalt (Ehc)) {
 | 
						|
        Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
 | 
						|
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          Status = EFI_DEVICE_ERROR;
 | 
						|
          goto ON_EXIT;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Clean up the asynchronous transfers, currently only
 | 
						|
      // interrupt supports asynchronous operation.
 | 
						|
      //
 | 
						|
      EhciDelAllAsyncIntTransfers (Ehc);
 | 
						|
      EhcAckAllInterrupt (Ehc);
 | 
						|
      EhcFreeSched (Ehc);
 | 
						|
 | 
						|
      Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
 | 
						|
 | 
						|
      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 ((DEBUG_INFO, "EhcReset: exit status %r\n", Status));
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the current state of the USB host controller.
 | 
						|
 | 
						|
  @param  This                   This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  State                  Variable to return the current host controller
 | 
						|
                                 state.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Host controller state was returned in State.
 | 
						|
  @retval EFI_INVALID_PARAMETER  State is NULL.
 | 
						|
  @retval EFI_DEVICE_ERROR       An error was encountered while attempting to
 | 
						|
                                 retrieve the host controller's current state.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcGetState (
 | 
						|
  IN   EFI_USB2_HC_PROTOCOL  *This,
 | 
						|
  OUT  EFI_USB_HC_STATE      *State
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_TPL      OldTpl;
 | 
						|
  USB2_HC_DEV  *Ehc;
 | 
						|
 | 
						|
  if (State == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (EHC_TPL);
 | 
						|
  Ehc    = EHC_FROM_THIS (This);
 | 
						|
 | 
						|
  if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
 | 
						|
    *State = EfiUsbHcStateHalt;
 | 
						|
  } else {
 | 
						|
    *State = EfiUsbHcStateOperational;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "EhcGetState: current state %d\n", *State));
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sets the USB host controller to a specific state.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  State                 The state of the host controller that will be set.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The USB host controller was successfully placed
 | 
						|
                                in the state specified by State.
 | 
						|
  @retval EFI_INVALID_PARAMETER State is invalid.
 | 
						|
  @retval EFI_DEVICE_ERROR      Failed to set the state due to device error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcSetState (
 | 
						|
  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;
 | 
						|
 | 
						|
  Status = EhcGetState (This, &CurState);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CurState == State) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
        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;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
 | 
						|
      break;
 | 
						|
 | 
						|
    case EfiUsbHcStateSuspend:
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "EhcSetState: exit status %r\n", Status));
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieves the current status of a USB root hub port.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  PortNumber            The root hub port to retrieve the state from.
 | 
						|
                                This value is zero-based.
 | 
						|
  @param  PortStatus            Variable to receive the port state.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The status of the USB root hub port specified.
 | 
						|
                                by PortNumber was returned in PortStatus.
 | 
						|
  @retval EFI_INVALID_PARAMETER PortNumber is invalid.
 | 
						|
  @retval EFI_DEVICE_ERROR      Can't read register.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcGetRootHubPortStatus (
 | 
						|
  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;
 | 
						|
 | 
						|
  if (PortStatus == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (EHC_TPL);
 | 
						|
 | 
						|
  Ehc    = EHC_FROM_THIS (This);
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
 | 
						|
 | 
						|
  if (PortNumber >= TotalPort) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  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);
 | 
						|
 | 
						|
  //
 | 
						|
  // Identify device speed. If in K state, it is low speed.
 | 
						|
  // If the port is enabled after reset, the device is of
 | 
						|
  // high speed. The USB bus driver should retrieve the actual
 | 
						|
  // port speed after reset.
 | 
						|
  //
 | 
						|
  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;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Convert the EHCI port/port change state to UEFI status
 | 
						|
  //
 | 
						|
  MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
 | 
						|
 | 
						|
  for (Index = 0; Index < MapSize; Index++) {
 | 
						|
    if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
 | 
						|
      PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
 | 
						|
 | 
						|
  for (Index = 0; Index < MapSize; Index++) {
 | 
						|
    if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
 | 
						|
      PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sets a feature for the specified root hub port.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  PortNumber            Root hub port to set.
 | 
						|
  @param  PortFeature           Feature to set.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The feature specified by PortFeature was set.
 | 
						|
  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
 | 
						|
  @retval EFI_DEVICE_ERROR      Can't read register.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcSetRootHubPortFeature (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL  *This,
 | 
						|
  IN  UINT8                 PortNumber,
 | 
						|
  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;
 | 
						|
 | 
						|
  TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
 | 
						|
 | 
						|
  if (PortNumber >= TotalPort) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Offset = (UINT32)(EHC_PORT_STAT_OFFSET + (4 * PortNumber));
 | 
						|
  State  = EhcReadOpReg (Ehc, Offset);
 | 
						|
 | 
						|
  //
 | 
						|
  // Mask off the port status change bits, these bits are
 | 
						|
  // write clean bit
 | 
						|
  //
 | 
						|
  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 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);
 | 
						|
 | 
						|
        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;
 | 
						|
 | 
						|
    case EfiUsbPortPower:
 | 
						|
      //
 | 
						|
      // Set port power bit when PPC is 1
 | 
						|
      //
 | 
						|
      if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {
 | 
						|
        State |= PORTSC_POWER;
 | 
						|
        EhcWriteOpReg (Ehc, Offset, State);
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case EfiUsbPortOwner:
 | 
						|
      State |= PORTSC_OWNER;
 | 
						|
      EhcWriteOpReg (Ehc, Offset, State);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  DEBUG ((DEBUG_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status));
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clears a feature for the specified root hub port.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  PortNumber            Specifies the root hub port whose feature is
 | 
						|
                                requested to be cleared.
 | 
						|
  @param  PortFeature           Indicates the feature selector associated with the
 | 
						|
                                feature clear request.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The feature specified by PortFeature was cleared
 | 
						|
                                for the USB root hub port specified by PortNumber.
 | 
						|
  @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
 | 
						|
  @retval EFI_DEVICE_ERROR      Can't read register.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcClearRootHubPortFeature (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL  *This,
 | 
						|
  IN  UINT8                 PortNumber,
 | 
						|
  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;
 | 
						|
 | 
						|
  TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
 | 
						|
 | 
						|
  if (PortNumber >= TotalPort) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  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 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 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 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 EfiUsbPortPower:
 | 
						|
      //
 | 
						|
      // Clear port power bit when PPC is 1
 | 
						|
      //
 | 
						|
      if ((Ehc->HcCapParams & HCSP_PPC) == HCSP_PPC) {
 | 
						|
        State &= ~PORTSC_POWER;
 | 
						|
        EhcWriteOpReg (Ehc, Offset, State);
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
    case EfiUsbPortSuspendChange:
 | 
						|
    case EfiUsbPortResetChange:
 | 
						|
      //
 | 
						|
      // Not supported or not related operation
 | 
						|
      //
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      Status = EFI_INVALID_PARAMETER;
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  DEBUG ((DEBUG_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status));
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Submits control transfer to a target USB device.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  DeviceAddress         The target device address.
 | 
						|
  @param  DeviceSpeed           Target device speed.
 | 
						|
  @param  MaximumPacketLength   Maximum packet size the default control transfer
 | 
						|
                                endpoint is capable of sending or receiving.
 | 
						|
  @param  Request               USB device request to send.
 | 
						|
  @param  TransferDirection     Specifies the data direction for the data stage
 | 
						|
  @param  Data                  Data buffer to be transmitted or received from USB
 | 
						|
                                device.
 | 
						|
  @param  DataLength            The size (in bytes) of the data buffer.
 | 
						|
  @param  TimeOut               Indicates the maximum timeout, in millisecond.
 | 
						|
  @param  Translator            Transaction translator to be used by this device.
 | 
						|
  @param  TransferResult        Return the result of this control transfer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Transfer was completed successfully.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resources.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
 | 
						|
  @retval EFI_TIMEOUT           Transfer failed due to timeout.
 | 
						|
  @retval EFI_DEVICE_ERROR      Transfer failed due to host controller or device error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcControlTransfer (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL                *This,
 | 
						|
  IN  UINT8                               DeviceAddress,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaximumPacketLength,
 | 
						|
  IN  EFI_USB_DEVICE_REQUEST              *Request,
 | 
						|
  IN  EFI_USB_DATA_DIRECTION              TransferDirection,
 | 
						|
  IN  OUT VOID                            *Data,
 | 
						|
  IN  OUT UINTN                           *DataLength,
 | 
						|
  IN  UINTN                               TimeOut,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT UINT32                              *TransferResult
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB2_HC_DEV  *Ehc;
 | 
						|
  URB          *Urb;
 | 
						|
  EFI_TPL      OldTpl;
 | 
						|
  UINT8        Endpoint;
 | 
						|
  EFI_STATUS   Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate parameters
 | 
						|
  //
 | 
						|
  if ((Request == NULL) || (TransferResult == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((TransferDirection != EfiUsbDataIn) &&
 | 
						|
      (TransferDirection != EfiUsbDataOut) &&
 | 
						|
      (TransferDirection != EfiUsbNoData))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((TransferDirection == EfiUsbNoData) &&
 | 
						|
      ((Data != NULL) || (*DataLength != 0)))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((TransferDirection != EfiUsbNoData) &&
 | 
						|
      ((Data == NULL) || (*DataLength == 0)))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&
 | 
						|
      (MaximumPacketLength != 32) && (MaximumPacketLength != 64))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  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 ((DEBUG_ERROR, "EhcControlTransfer: HC halted at entrance\n"));
 | 
						|
 | 
						|
    EhcAckAllInterrupt (Ehc);
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcAckAllInterrupt (Ehc);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a new URB, insert it into the asynchronous
 | 
						|
  // schedule list, then poll the execution status.
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // Encode the direction in address, although default control
 | 
						|
  // 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
 | 
						|
               );
 | 
						|
 | 
						|
  if (Urb == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcControlTransfer: failed to create URB"));
 | 
						|
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcLinkQhToAsync (Ehc, Urb->Qh);
 | 
						|
  Status = EhcExecTransfer (Ehc, Urb, TimeOut);
 | 
						|
  EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the status from URB. The result is updated in EhcCheckUrbResult
 | 
						|
  // which is called by EhcExecTransfer
 | 
						|
  //
 | 
						|
  *TransferResult = Urb->Result;
 | 
						|
  *DataLength     = Urb->Completed;
 | 
						|
 | 
						|
  if (*TransferResult == EFI_USB_NOERROR) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcAckAllInterrupt (Ehc);
 | 
						|
  EhcFreeUrb (Ehc, Urb);
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  Ehc->PciIo->Flush (Ehc->PciIo);
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Submits bulk transfer to a bulk endpoint of a USB device.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  DeviceAddress         Target device address.
 | 
						|
  @param  EndPointAddress       Endpoint number and its direction in bit 7.
 | 
						|
  @param  DeviceSpeed           Device speed, Low speed device doesn't support bulk
 | 
						|
                                transfer.
 | 
						|
  @param  MaximumPacketLength   Maximum packet size the endpoint is capable of
 | 
						|
                                sending or receiving.
 | 
						|
  @param  DataBuffersNumber     Number of data buffers prepared for the transfer.
 | 
						|
  @param  Data                  Array of pointers to the buffers of data to transmit
 | 
						|
                                from or receive into.
 | 
						|
  @param  DataLength            The lenght of the data buffer.
 | 
						|
  @param  DataToggle            On input, the initial data toggle for the transfer;
 | 
						|
                                On output, it is updated to to next data toggle to
 | 
						|
                                use of the subsequent bulk transfer.
 | 
						|
  @param  TimeOut               Indicates the maximum time, in millisecond, which
 | 
						|
                                the transfer is allowed to complete.
 | 
						|
  @param  Translator            A pointr to the transaction translator data.
 | 
						|
  @param  TransferResult        A pointer to the detailed result information of the
 | 
						|
                                bulk transfer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The transfer was completed successfully.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
 | 
						|
  @retval EFI_TIMEOUT           The transfer failed due to timeout.
 | 
						|
  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcBulkTransfer (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL                *This,
 | 
						|
  IN  UINT8                               DeviceAddress,
 | 
						|
  IN  UINT8                               EndPointAddress,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaximumPacketLength,
 | 
						|
  IN  UINT8                               DataBuffersNumber,
 | 
						|
  IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
 | 
						|
  IN  OUT UINTN                           *DataLength,
 | 
						|
  IN  OUT UINT8                           *DataToggle,
 | 
						|
  IN  UINTN                               TimeOut,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT UINT32                              *TransferResult
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB2_HC_DEV  *Ehc;
 | 
						|
  URB          *Urb;
 | 
						|
  EFI_TPL      OldTpl;
 | 
						|
  EFI_STATUS   Status;
 | 
						|
  UINTN        DebugErrorLevel;
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the parameters
 | 
						|
  //
 | 
						|
  if ((DataLength == NULL) || (*DataLength == 0) ||
 | 
						|
      (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((*DataToggle != 0) && (*DataToggle != 1)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
 | 
						|
      ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
 | 
						|
      ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  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 ((DEBUG_ERROR, "EhcBulkTransfer: HC is halted\n"));
 | 
						|
 | 
						|
    EhcAckAllInterrupt (Ehc);
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcAckAllInterrupt (Ehc);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a new URB, insert it into the asynchronous
 | 
						|
  // schedule list, then poll the execution status.
 | 
						|
  //
 | 
						|
  Urb = EhcCreateUrb (
 | 
						|
          Ehc,
 | 
						|
          DeviceAddress,
 | 
						|
          EndPointAddress,
 | 
						|
          DeviceSpeed,
 | 
						|
          *DataToggle,
 | 
						|
          MaximumPacketLength,
 | 
						|
          Translator,
 | 
						|
          EHC_BULK_TRANSFER,
 | 
						|
          NULL,
 | 
						|
          Data[0],
 | 
						|
          *DataLength,
 | 
						|
          NULL,
 | 
						|
          NULL,
 | 
						|
          1
 | 
						|
          );
 | 
						|
 | 
						|
  if (Urb == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcBulkTransfer: failed to create URB\n"));
 | 
						|
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcLinkQhToAsync (Ehc, Urb->Qh);
 | 
						|
  Status = EhcExecTransfer (Ehc, Urb, TimeOut);
 | 
						|
  EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
 | 
						|
 | 
						|
  *TransferResult = Urb->Result;
 | 
						|
  *DataLength     = Urb->Completed;
 | 
						|
  *DataToggle     = Urb->DataToggle;
 | 
						|
 | 
						|
  if (*TransferResult == EFI_USB_NOERROR) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcAckAllInterrupt (Ehc);
 | 
						|
  EhcFreeUrb (Ehc, Urb);
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  Ehc->PciIo->Flush (Ehc->PciIo);
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    if (Status == EFI_TIMEOUT) {
 | 
						|
      DebugErrorLevel = DEBUG_VERBOSE;
 | 
						|
    } else {
 | 
						|
      DebugErrorLevel = DEBUG_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG ((DebugErrorLevel, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Submits an asynchronous interrupt transfer to an
 | 
						|
  interrupt endpoint of a USB device.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  DeviceAddress         Target device address.
 | 
						|
  @param  EndPointAddress       Endpoint number and its direction encoded in bit 7
 | 
						|
  @param  DeviceSpeed           Indicates device speed.
 | 
						|
  @param  MaximumPacketLength   Maximum packet size the target endpoint is capable
 | 
						|
  @param  IsNewTransfer         If TRUE, to submit an new asynchronous interrupt
 | 
						|
                                transfer If FALSE, to remove the specified
 | 
						|
                                asynchronous interrupt.
 | 
						|
  @param  DataToggle            On input, the initial data toggle to use; on output,
 | 
						|
                                it is updated to indicate the next data toggle.
 | 
						|
  @param  PollingInterval       The he interval, in milliseconds, that the transfer
 | 
						|
                                is polled.
 | 
						|
  @param  DataLength            The length of data to receive at the rate specified
 | 
						|
                                by  PollingInterval.
 | 
						|
  @param  Translator            Transaction translator to use.
 | 
						|
  @param  CallBackFunction      Function to call at the rate specified by
 | 
						|
                                PollingInterval.
 | 
						|
  @param  Context               Context to CallBackFunction.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The request has been successfully submitted or canceled.
 | 
						|
  @retval EFI_INVALID_PARAMETER Some parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The request failed due to a lack of resources.
 | 
						|
  @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
 | 
						|
 | 
						|
**/
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB2_HC_DEV  *Ehc;
 | 
						|
  URB          *Urb;
 | 
						|
  EFI_TPL      OldTpl;
 | 
						|
  EFI_STATUS   Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate parameters
 | 
						|
  //
 | 
						|
  if (!EHCI_IS_DATAIN (EndPointAddress)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IsNewTransfer) {
 | 
						|
    if (DataLength == 0) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((*DataToggle != 1) && (*DataToggle != 0)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((PollingInterval > 255) || (PollingInterval < 1)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (EHC_TPL);
 | 
						|
  Ehc    = EHC_FROM_THIS (This);
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete Async interrupt transfer request. DataToggle will return
 | 
						|
  // the next data toggle to use.
 | 
						|
  //
 | 
						|
  if (!IsNewTransfer) {
 | 
						|
    Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);
 | 
						|
 | 
						|
    DEBUG ((DEBUG_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));
 | 
						|
    EhcAckAllInterrupt (Ehc);
 | 
						|
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcAckAllInterrupt (Ehc);
 | 
						|
 | 
						|
  Urb = EhciInsertAsyncIntTransfer (
 | 
						|
          Ehc,
 | 
						|
          DeviceAddress,
 | 
						|
          EndPointAddress,
 | 
						|
          DeviceSpeed,
 | 
						|
          *DataToggle,
 | 
						|
          MaximumPacketLength,
 | 
						|
          Translator,
 | 
						|
          DataLength,
 | 
						|
          CallBackFunction,
 | 
						|
          Context,
 | 
						|
          PollingInterval
 | 
						|
          );
 | 
						|
 | 
						|
  if (Urb == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  Ehc->PciIo->Flush (Ehc->PciIo);
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Submits synchronous interrupt transfer to an interrupt endpoint
 | 
						|
  of a USB device.
 | 
						|
 | 
						|
  @param  This                  This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  DeviceAddress         Target device address.
 | 
						|
  @param  EndPointAddress       Endpoint number and its direction encoded in bit 7
 | 
						|
  @param  DeviceSpeed           Indicates device speed.
 | 
						|
  @param  MaximumPacketLength   Maximum packet size the target endpoint is capable
 | 
						|
                                of sending or receiving.
 | 
						|
  @param  Data                  Buffer of data that will be transmitted to  USB
 | 
						|
                                device or received from USB device.
 | 
						|
  @param  DataLength            On input, the size, in bytes, of the data buffer; On
 | 
						|
                                output, the number of bytes transferred.
 | 
						|
  @param  DataToggle            On input, the initial data toggle to use; on output,
 | 
						|
                                it is updated to indicate the next data toggle.
 | 
						|
  @param  TimeOut               Maximum time, in second, to complete.
 | 
						|
  @param  Translator            Transaction translator to use.
 | 
						|
  @param  TransferResult        Variable to receive the transfer result.
 | 
						|
 | 
						|
  @return EFI_SUCCESS           The transfer was completed successfully.
 | 
						|
  @return EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
 | 
						|
  @return EFI_INVALID_PARAMETER Some parameters are invalid.
 | 
						|
  @return EFI_TIMEOUT           The transfer failed due to timeout.
 | 
						|
  @return EFI_DEVICE_ERROR      The failed due to host controller or device error
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcSyncInterruptTransfer (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL                *This,
 | 
						|
  IN  UINT8                               DeviceAddress,
 | 
						|
  IN  UINT8                               EndPointAddress,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaximumPacketLength,
 | 
						|
  IN  OUT VOID                            *Data,
 | 
						|
  IN  OUT UINTN                           *DataLength,
 | 
						|
  IN  OUT UINT8                           *DataToggle,
 | 
						|
  IN  UINTN                               TimeOut,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT UINT32                              *TransferResult
 | 
						|
  )
 | 
						|
{
 | 
						|
  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 ((*DataToggle != 1) && (*DataToggle != 0)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8))  ||
 | 
						|
      ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
 | 
						|
      ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072)))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  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 ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
 | 
						|
 | 
						|
    EhcAckAllInterrupt (Ehc);
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcAckAllInterrupt (Ehc);
 | 
						|
 | 
						|
  Urb = EhcCreateUrb (
 | 
						|
          Ehc,
 | 
						|
          DeviceAddress,
 | 
						|
          EndPointAddress,
 | 
						|
          DeviceSpeed,
 | 
						|
          *DataToggle,
 | 
						|
          MaximumPacketLength,
 | 
						|
          Translator,
 | 
						|
          EHC_INT_TRANSFER_SYNC,
 | 
						|
          NULL,
 | 
						|
          Data,
 | 
						|
          *DataLength,
 | 
						|
          NULL,
 | 
						|
          NULL,
 | 
						|
          1
 | 
						|
          );
 | 
						|
 | 
						|
  if (Urb == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));
 | 
						|
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcLinkQhToPeriod (Ehc, Urb->Qh);
 | 
						|
  Status = EhcExecTransfer (Ehc, Urb, TimeOut);
 | 
						|
  EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
 | 
						|
 | 
						|
  *TransferResult = Urb->Result;
 | 
						|
  *DataLength     = Urb->Completed;
 | 
						|
  *DataToggle     = Urb->DataToggle;
 | 
						|
 | 
						|
  if (*TransferResult == EFI_USB_NOERROR) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  EhcFreeUrb (Ehc, Urb);
 | 
						|
ON_EXIT:
 | 
						|
  Ehc->PciIo->Flush (Ehc->PciIo);
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Submits isochronous transfer to a target USB device.
 | 
						|
 | 
						|
  @param  This                 This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  DeviceAddress        Target device address.
 | 
						|
  @param  EndPointAddress      End point address with its direction.
 | 
						|
  @param  DeviceSpeed          Device speed, Low speed device doesn't support this
 | 
						|
                               type.
 | 
						|
  @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of
 | 
						|
                               sending or receiving.
 | 
						|
  @param  DataBuffersNumber    Number of data buffers prepared for the transfer.
 | 
						|
  @param  Data                 Array of pointers to the buffers of data that will
 | 
						|
                               be transmitted to USB device or received from USB
 | 
						|
                               device.
 | 
						|
  @param  DataLength           The size, in bytes, of the data buffer.
 | 
						|
  @param  Translator           Transaction translator to use.
 | 
						|
  @param  TransferResult       Variable to receive the transfer result.
 | 
						|
 | 
						|
  @return EFI_UNSUPPORTED      Isochronous transfer is unsupported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcIsochronousTransfer (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL                *This,
 | 
						|
  IN  UINT8                               DeviceAddress,
 | 
						|
  IN  UINT8                               EndPointAddress,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaximumPacketLength,
 | 
						|
  IN  UINT8                               DataBuffersNumber,
 | 
						|
  IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | 
						|
  IN  UINTN                               DataLength,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT UINT32                              *TransferResult
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Submits Async isochronous transfer to a target USB device.
 | 
						|
 | 
						|
  @param  This                 This EFI_USB2_HC_PROTOCOL instance.
 | 
						|
  @param  DeviceAddress        Target device address.
 | 
						|
  @param  EndPointAddress      End point address with its direction.
 | 
						|
  @param  DeviceSpeed          Device speed, Low speed device doesn't support this
 | 
						|
                               type.
 | 
						|
  @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of
 | 
						|
                               sending or receiving.
 | 
						|
  @param  DataBuffersNumber    Number of data buffers prepared for the transfer.
 | 
						|
  @param  Data                 Array of pointers to the buffers of data that will
 | 
						|
                               be transmitted to USB device or received from USB
 | 
						|
                               device.
 | 
						|
  @param  DataLength           The size, in bytes, of the data buffer.
 | 
						|
  @param  Translator           Transaction translator to use.
 | 
						|
  @param  IsochronousCallBack  Function to be called when the transfer complete.
 | 
						|
  @param  Context              Context passed to the call back function as
 | 
						|
                               parameter.
 | 
						|
 | 
						|
  @return EFI_UNSUPPORTED      Isochronous transfer isn't supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcAsyncIsochronousTransfer (
 | 
						|
  IN  EFI_USB2_HC_PROTOCOL                *This,
 | 
						|
  IN  UINT8                               DeviceAddress,
 | 
						|
  IN  UINT8                               EndPointAddress,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaximumPacketLength,
 | 
						|
  IN  UINT8                               DataBuffersNumber,
 | 
						|
  IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | 
						|
  IN  UINTN                               DataLength,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,
 | 
						|
  IN  VOID                                *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Entry point for EFI drivers.
 | 
						|
 | 
						|
  @param  ImageHandle       EFI_HANDLE.
 | 
						|
  @param  SystemTable       EFI_SYSTEM_TABLE.
 | 
						|
 | 
						|
  @return EFI_SUCCESS       Success.
 | 
						|
          EFI_DEVICE_ERROR  Fail.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcDriverEntryPoint (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EfiLibInstallDriverBindingComponentName2 (
 | 
						|
           ImageHandle,
 | 
						|
           SystemTable,
 | 
						|
           &gEhciDriverBinding,
 | 
						|
           ImageHandle,
 | 
						|
           &gEhciComponentName,
 | 
						|
           &gEhciComponentName2
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Test to see if this driver supports ControllerHandle. Any
 | 
						|
  ControllerHandle that has Usb2HcProtocol installed will
 | 
						|
  be supported.
 | 
						|
 | 
						|
  @param  This                 Protocol instance pointer.
 | 
						|
  @param  Controller           Handle of device to test.
 | 
						|
  @param  RemainingDevicePath  Not used.
 | 
						|
 | 
						|
  @return EFI_SUCCESS          This driver supports this device.
 | 
						|
  @return EFI_UNSUPPORTED      This driver does not support this device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcDriverBindingSupported (
 | 
						|
  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;
 | 
						|
 | 
						|
  //
 | 
						|
  // Test whether there is PCI IO Protocol attached on the controller handle.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiPciIoProtocolGuid,
 | 
						|
                  (VOID **)&PciIo,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = PciIo->Pci.Read (
 | 
						|
                        PciIo,
 | 
						|
                        EfiPciIoWidthUint8,
 | 
						|
                        PCI_CLASSCODE_OFFSET,
 | 
						|
                        sizeof (USB_CLASSC) / sizeof (UINT8),
 | 
						|
                        &UsbClassCReg
 | 
						|
                        );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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) && (UsbClassCReg.ProgInterface != PCI_IF_OHCI)))
 | 
						|
  {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Controller,
 | 
						|
         &gEfiPciIoProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         Controller
 | 
						|
         );
 | 
						|
 | 
						|
  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,
 | 
						|
           otherwise NULL.
 | 
						|
 | 
						|
**/
 | 
						|
USB2_HC_DEV *
 | 
						|
EhcCreateUsb2Hc (
 | 
						|
  IN EFI_PCI_IO_PROTOCOL       *PciIo,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
 | 
						|
  IN UINT64                    OriginalPciAttributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB2_HC_DEV  *Ehc;
 | 
						|
  EFI_STATUS   Status;
 | 
						|
 | 
						|
  Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));
 | 
						|
 | 
						|
  if (Ehc == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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->PciIo                 = PciIo;
 | 
						|
  Ehc->DevicePath            = DevicePath;
 | 
						|
  Ehc->OriginalPciAttributes = OriginalPciAttributes;
 | 
						|
 | 
						|
  InitializeListHead (&Ehc->AsyncIntTransfers);
 | 
						|
 | 
						|
  Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);
 | 
						|
  Ehc->HcCapParams    = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);
 | 
						|
  Ehc->CapLen         = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;
 | 
						|
 | 
						|
  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_NOTIFY,
 | 
						|
                  EhcMonitorAsyncRequests,
 | 
						|
                  Ehc,
 | 
						|
                  &Ehc->PollTimer
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->FreePool (Ehc);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return Ehc;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  One notified function to stop the Host Controller when gBS->ExitBootServices() called.
 | 
						|
 | 
						|
  @param  Event                   Pointer to this event
 | 
						|
  @param  Context                 Event handler private data
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
EhcExitBootService (
 | 
						|
  EFI_EVENT  Event,
 | 
						|
  VOID       *Context
 | 
						|
  )
 | 
						|
 | 
						|
{
 | 
						|
  USB2_HC_DEV  *Ehc;
 | 
						|
 | 
						|
  Ehc = (USB2_HC_DEV *)Context;
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset the Host Controller
 | 
						|
  //
 | 
						|
  EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Starting the Usb EHCI Driver.
 | 
						|
 | 
						|
  @param  This                 Protocol instance pointer.
 | 
						|
  @param  Controller           Handle of device to test.
 | 
						|
  @param  RemainingDevicePath  Not used.
 | 
						|
 | 
						|
  @return EFI_SUCCESS          supports this device.
 | 
						|
  @return EFI_UNSUPPORTED      do not support this device.
 | 
						|
  @return EFI_DEVICE_ERROR     cannot be started due to device Error.
 | 
						|
  @return EFI_OUT_OF_RESOURCES cannot allocate resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcDriverBindingStart (
 | 
						|
  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                     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
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiPciIoProtocolGuid,
 | 
						|
                  (VOID **)&PciIo,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    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
 | 
						|
  //
 | 
						|
  Status = PciIo->Attributes (
 | 
						|
                    PciIo,
 | 
						|
                    EfiPciIoAttributeOperationGet,
 | 
						|
                    0,
 | 
						|
                    &OriginalPciAttributes
 | 
						|
                    );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto CLOSE_PCIIO;
 | 
						|
  }
 | 
						|
 | 
						|
  PciAttributesSaved = TRUE;
 | 
						|
 | 
						|
  Status = PciIo->Attributes (
 | 
						|
                    PciIo,
 | 
						|
                    EfiPciIoAttributeOperationSupported,
 | 
						|
                    0,
 | 
						|
                    &Supports
 | 
						|
                    );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
 | 
						|
    Status    = PciIo->Attributes (
 | 
						|
                         PciIo,
 | 
						|
                         EfiPciIoAttributeOperationEnable,
 | 
						|
                         Supports,
 | 
						|
                         NULL
 | 
						|
                         );
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));
 | 
						|
    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 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 or OHCI driver attaches to UHCI or OHCI host controller.
 | 
						|
  //
 | 
						|
  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,
 | 
						|
                      &CompanionSegmentNumber,
 | 
						|
                      &CompanionBusNumber,
 | 
						|
                      &CompanionDeviceNumber,
 | 
						|
                      &CompanionFunctionNumber
 | 
						|
                      );
 | 
						|
    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 == CompanionBusNumber) {
 | 
						|
          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
 | 
						|
  //
 | 
						|
  Ehc = EhcCreateUsb2Hc (PciIo, HcDevicePath, OriginalPciAttributes);
 | 
						|
 | 
						|
  if (Ehc == NULL) {
 | 
						|
    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",
 | 
						|
        __func__,
 | 
						|
        Controller,
 | 
						|
        Status
 | 
						|
        ));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->InstallProtocolInterface (
 | 
						|
                  &Controller,
 | 
						|
                  &gEfiUsb2HcProtocolGuid,
 | 
						|
                  EFI_NATIVE_INTERFACE,
 | 
						|
                  &Ehc->Usb2Hc
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
 | 
						|
    goto FREE_POOL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Robustnesss improvement such as for Duet platform
 | 
						|
  // Default is not required.
 | 
						|
  //
 | 
						|
  if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
 | 
						|
    EhcClearLegacySupport (Ehc);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EhcIsDebugPortInUse (Ehc, NULL)) {
 | 
						|
    EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EhcInitHC (Ehc);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));
 | 
						|
    goto UNINSTALL_USBHC;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Start the asynchronous interrupt monitor
 | 
						|
  //
 | 
						|
  Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
 | 
						|
 | 
						|
    EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
 | 
						|
    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.
 | 
						|
  //
 | 
						|
  AddUnicodeString2 (
 | 
						|
    "eng",
 | 
						|
    gEhciComponentName.SupportedLanguages,
 | 
						|
    &Ehc->ControllerNameTable,
 | 
						|
    L"Enhanced Host Controller (USB 2.0)",
 | 
						|
    TRUE
 | 
						|
    );
 | 
						|
  AddUnicodeString2 (
 | 
						|
    "en",
 | 
						|
    gEhciComponentName2.SupportedLanguages,
 | 
						|
    &Ehc->ControllerNameTable,
 | 
						|
    L"Enhanced Host Controller (USB 2.0)",
 | 
						|
    FALSE
 | 
						|
    );
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
UNINSTALL_USBHC:
 | 
						|
  gBS->UninstallProtocolInterface (
 | 
						|
         Controller,
 | 
						|
         &gEfiUsb2HcProtocolGuid,
 | 
						|
         &Ehc->Usb2Hc
 | 
						|
         );
 | 
						|
 | 
						|
FREE_POOL:
 | 
						|
  EhcFreeSched (Ehc);
 | 
						|
  gBS->CloseEvent (Ehc->PollTimer);
 | 
						|
  gBS->FreePool (Ehc);
 | 
						|
 | 
						|
CLOSE_PCIIO:
 | 
						|
  if (PciAttributesSaved) {
 | 
						|
    //
 | 
						|
    // Restore original PCI attributes
 | 
						|
    //
 | 
						|
    PciIo->Attributes (
 | 
						|
             PciIo,
 | 
						|
             EfiPciIoAttributeOperationSet,
 | 
						|
             OriginalPciAttributes,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Controller,
 | 
						|
         &gEfiPciIoProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         Controller
 | 
						|
         );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop this driver on ControllerHandle. Support stopping any child handles
 | 
						|
  created by this driver.
 | 
						|
 | 
						|
  @param  This                 Protocol instance pointer.
 | 
						|
  @param  Controller           Handle of device to stop driver on.
 | 
						|
  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
 | 
						|
  @param  ChildHandleBuffer    List of handles for the children we need to stop.
 | 
						|
 | 
						|
  @return EFI_SUCCESS          Success.
 | 
						|
  @return EFI_DEVICE_ERROR     Fail.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EhcDriverBindingStop (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   Controller,
 | 
						|
  IN UINTN                        NumberOfChildren,
 | 
						|
  IN EFI_HANDLE                   *ChildHandleBuffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  EFI_USB2_HC_PROTOCOL  *Usb2Hc;
 | 
						|
  EFI_PCI_IO_PROTOCOL   *PciIo;
 | 
						|
  USB2_HC_DEV           *Ehc;
 | 
						|
 | 
						|
  //
 | 
						|
  // Test whether the Controller handler passed in is a valid
 | 
						|
  // Usb controller handle that should be supported, if not,
 | 
						|
  // return the error status directly
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiUsb2HcProtocolGuid,
 | 
						|
                  (VOID **)&Usb2Hc,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Ehc   = EHC_FROM_THIS (Usb2Hc);
 | 
						|
  PciIo = Ehc->PciIo;
 | 
						|
 | 
						|
  Status = gBS->UninstallProtocolInterface (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiUsb2HcProtocolGuid,
 | 
						|
                  Usb2Hc
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    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);
 | 
						|
  }
 | 
						|
 | 
						|
  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 or OHCI controller.
 | 
						|
  //
 | 
						|
  EhcClearOpRegBit (Ehc, EHC_CONFIG_FLAG_OFFSET, CONFIGFLAG_ROUTE_EHC);
 | 
						|
 | 
						|
  //
 | 
						|
  // Restore original PCI attributes
 | 
						|
  //
 | 
						|
  PciIo->Attributes (
 | 
						|
           PciIo,
 | 
						|
           EfiPciIoAttributeOperationSet,
 | 
						|
           Ehc->OriginalPciAttributes,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Controller,
 | 
						|
         &gEfiPciIoProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         Controller
 | 
						|
         );
 | 
						|
 | 
						|
  FreePool (Ehc);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |