522 lines
14 KiB
C
522 lines
14 KiB
C
/** @file
|
|
Implementation of USBFN protocol driver.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2015 - 2020 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains a 'Sample Driver' and is licensed as such under the terms
|
|
of your license agreement with Intel or your vendor. This file may be modified
|
|
by the user, subject to the additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
|
|
|
|
#include "UsbDeviceDxe.h"
|
|
#include <Library/PchPciBdfLib.h>
|
|
|
|
EFI_DRIVER_BINDING_PROTOCOL mUsbDeviceDxeDriverBinding = {
|
|
UsbDeviceDxeDriverSupported,
|
|
UsbDeviceDxeDriverStart,
|
|
UsbDeviceDxeDriverStop,
|
|
0x1,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
#define DEVICE_CONNECT_TIMEOUT_IN_SECS 5 * 60 //Wait for 5 Mins for cable detection
|
|
/**
|
|
This function can be called to poll for certain value within a time given.
|
|
|
|
@param[in] MmioAddress The Mmio Address.
|
|
@param[in] BitMask Bits to be masked.
|
|
@param[in] BitValue Value to be polled.
|
|
#param[in] DelayTime Delay time in terms of 100 micro seconds.
|
|
|
|
@retval EFI_SUCCESS Successfully polled the value.
|
|
@retval EFI_TIMEOUT Timeout while polling the value.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PchMmioPoll32 (
|
|
IN UINTN MmioAddress,
|
|
IN UINT32 BitMask,
|
|
IN UINT32 BitValue,
|
|
IN UINT16 DelayTime
|
|
)
|
|
{
|
|
UINT32 LoopTime;
|
|
UINT8 PollSuccess;
|
|
|
|
LoopTime = 0;
|
|
PollSuccess = 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "PchMmioPoll32, BitMask: %x, BitValue: %x\n", BitMask, BitValue));
|
|
for (LoopTime = 0; LoopTime < DelayTime; LoopTime++) {
|
|
if ((MmioRead32 (MmioAddress) & BitMask) == (BitValue & BitMask)) {
|
|
PollSuccess = 1;
|
|
break;
|
|
} else {
|
|
gBS->Stall (100);
|
|
}
|
|
}
|
|
|
|
if (PollSuccess) {
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Platform specific initialization.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
PlatformSpecificInit (
|
|
VOID
|
|
)
|
|
{
|
|
UINT64 OtgPciMmBase;
|
|
EFI_STATUS Status;
|
|
WDT_PROTOCOL *WdtProtocol;
|
|
UINT8 WdtState;
|
|
|
|
WdtState = 1;
|
|
|
|
Status = EFI_SUCCESS;
|
|
Status = gBS->LocateProtocol (&gWdtProtocolGuid, NULL, (VOID **)&WdtProtocol);
|
|
if (!EFI_ERROR(Status)) {
|
|
WdtState = WdtProtocol->IsWdtEnabled ();
|
|
DEBUG ((DEBUG_INFO, "WdtState %d\n", WdtState));
|
|
}
|
|
|
|
//
|
|
// Configure Controllers.
|
|
//
|
|
OtgPciMmBase = PchXdciPciCfgBase ();
|
|
DEBUG ((DEBUG_INFO, "OtgPciMmBase: %x\n", OtgPciMmBase));
|
|
|
|
PciSegmentWrite8 ((OtgPciMmBase + 0x04), 0x06); // enable MSE to access xDCI MMIO
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
EFIAPI
|
|
UsbDeviceDxeExitBootService (
|
|
EFI_EVENT Event,
|
|
VOID *Context
|
|
)
|
|
{
|
|
USB_XDCI_DEV_CONTEXT *UsbXdciDevContext;
|
|
|
|
UsbXdciDevContext = (USB_XDCI_DEV_CONTEXT *) Context;
|
|
DEBUG ((EFI_D_INFO, "UsbDeviceDxeExitBootService enter\n"));
|
|
|
|
if (UsbXdciDevContext->XdciPollTimer != NULL) {
|
|
gBS->SetTimer (UsbXdciDevContext->XdciPollTimer, TimerCancel, 0);
|
|
gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer);
|
|
UsbXdciDevContext->XdciPollTimer = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
The USB bus driver entry pointer.
|
|
|
|
@param ImageHandle The driver image handle.
|
|
@param SystemTable The system table.
|
|
|
|
@return EFI_SUCCESS The component name protocol is installed.
|
|
@return Others Failed to init the usb driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceDxeEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN UsbFnEnable;
|
|
SETUP_DATA SystemConfiguration;
|
|
UINTN VarSize;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceDxeEntryPoint entry\n"));
|
|
UsbFnEnable = FALSE;
|
|
|
|
VarSize = sizeof (SETUP_DATA);
|
|
Status = gRT->GetVariable (
|
|
L"Setup",
|
|
&gSetupVariableGuid,
|
|
NULL,
|
|
&VarSize,
|
|
&SystemConfiguration
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
UsbFnEnable = SystemConfiguration.UsbFnEnable;
|
|
}
|
|
DEBUG ((DEBUG_INFO, "UsbFnEnable: %x\n", UsbFnEnable));
|
|
|
|
if (UsbFnEnable == TRUE) {
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&mUsbDeviceDxeDriverBinding,
|
|
ImageHandle,
|
|
&mUsbDeviceDxeComponentName,
|
|
&mUsbDeviceDxeComponentName2
|
|
);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceDxeEntryPoint exit, Status: %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Check whether USB bus driver support this device.
|
|
|
|
@param This The USB bus driver binding protocol.
|
|
@param Controller The controller handle to check.
|
|
@param RemainingDevicePath The remaining device path.
|
|
|
|
@retval EFI_SUCCESS The bus supports this controller.
|
|
@retval EFI_UNSUPPORTED This device isn't supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceDxeDriverSupported (
|
|
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;
|
|
|
|
|
|
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 USB device type
|
|
//
|
|
// 0x0C03FE / 0x0C0380
|
|
if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
|
|
(UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
|
|
((UsbClassCReg.ProgInterface != PCI_IF_USBDEV) && (UsbClassCReg.ProgInterface != 0x80))) {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
|
|
ON_EXIT:
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Start to process the controller.
|
|
|
|
@param This The USB bus driver binding instance.
|
|
@param Controller The controller to check.
|
|
@param RemainingDevicePath The remaining device patch.
|
|
|
|
@retval EFI_SUCCESS The controller is controlled by the usb bus.
|
|
@retval EFI_ALREADY_STARTED The controller is already controlled by the usb
|
|
bus.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceDxeDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_XDCI_DEV_CONTEXT *UsbXdciDevContext;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT32 XdciMmioBarHigh;
|
|
EFI_EVENT ExitBootServicesEvent;
|
|
|
|
DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFunIoEntryPoint - Entry\n"));
|
|
|
|
UsbXdciDevContext = NULL;
|
|
XdciMmioBarHigh = 0;
|
|
|
|
//
|
|
// Provide protocol interface
|
|
//
|
|
//
|
|
// Get the PCI I/O Protocol on PciHandle
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto ErrorExit;
|
|
}
|
|
|
|
UsbXdciDevContext = AllocateZeroPool (sizeof (USB_XDCI_DEV_CONTEXT));
|
|
if (UsbXdciDevContext == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Initialize the driver context
|
|
//
|
|
UsbXdciDevContext->StartUpController = FALSE;
|
|
UsbXdciDevContext->XdciHandle = Controller;
|
|
UsbXdciDevContext->FirstNodePtr = NULL;
|
|
UsbXdciDevContext->Signature = EFI_USB_DEV_SIGNATURE;
|
|
|
|
PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
R_PCH_OTG_BAR0,
|
|
1,
|
|
&UsbXdciDevContext->XdciMmioBarAddr
|
|
);
|
|
|
|
if ((UsbXdciDevContext->XdciMmioBarAddr & B_PCH_OTG_BAR0_TYPE) == B_PCH_OTG_BAR0_64_BIT) {
|
|
PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
R_PCH_OTG_BAR_HIGH,
|
|
1,
|
|
&XdciMmioBarHigh
|
|
);
|
|
}
|
|
|
|
UsbXdciDevContext->XdciMmioBarAddr = ((UINT64) XdciMmioBarHigh << 32) | (UsbXdciDevContext->XdciMmioBarAddr & B_PCH_OTG_BAR0_BA);
|
|
DEBUG ((USB_FUIO_DEBUG_INFO, "USB DEV mode IO addr 0x%016lx\n", UsbXdciDevContext->XdciMmioBarAddr));
|
|
|
|
if (UsbXdciDevContext->XdciMmioBarAddr == 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
CopyMem (
|
|
&(UsbXdciDevContext->UsbFunIoProtocol),
|
|
&mUsbFunIoProtocol,
|
|
sizeof (EFI_USBFN_IO_PROTOCOL)
|
|
);
|
|
|
|
CopyMem (
|
|
&(UsbXdciDevContext->UsbDevModeProtocol),
|
|
&mUsbDeviceModeProtocol,
|
|
sizeof (EFI_USB_DEVICE_MODE_PROTOCOL)
|
|
);
|
|
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
UsbDeviceDxeExitBootService,
|
|
UsbXdciDevContext,
|
|
&gEfiEventExitBootServicesGuid,
|
|
&ExitBootServicesEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ErrorExit;
|
|
}
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&UsbXdciDevContext->XdciHandle,
|
|
&gUsbFnIoProtocolGuid,
|
|
&UsbXdciDevContext->UsbFunIoProtocol,
|
|
&gUsbDeviceModeProtocolGuid,
|
|
&UsbXdciDevContext->UsbDevModeProtocol,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((USB_FUIO_DEBUG_ERROR, "ERROR - Failed to install upper protocol, Status: %r\n", Status));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
DEBUG ((USB_FUIO_DEBUG_LOAD, "Done - install upper protocol complete\n"));
|
|
DEBUG ((USB_FUIO_DEBUG_LOAD, "UsbFunIoEntryPoint - Exit\n"));
|
|
return Status;
|
|
|
|
ErrorExit:
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
if (UsbXdciDevContext != NULL) {
|
|
if (UsbXdciDevContext->XdciPollTimer != NULL) {
|
|
gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer);
|
|
UsbXdciDevContext->XdciPollTimer = NULL;
|
|
}
|
|
FreePool (UsbXdciDevContext);
|
|
}
|
|
|
|
DEBUG ((USB_FUIO_DEBUG_ERROR, "ERROR - UsbFunIoEntryPoint - Exit\n"));
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceDxeDriverStart, Status: %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Stop handle the controller by this USB bus driver.
|
|
|
|
@param This The USB bus driver binding protocol.
|
|
@param Controller The controller to release.
|
|
@param NumberOfChildren The child of USB bus that opened controller
|
|
BY_CHILD.
|
|
@param ChildHandleBuffer The array of child handle.
|
|
|
|
@retval EFI_SUCCESS The controller or children are stopped.
|
|
@retval EFI_DEVICE_ERROR Failed to stop the driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceDxeDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_USBFN_IO_PROTOCOL *UsbFunIoProtocol;
|
|
EFI_STATUS Status;
|
|
USB_XDCI_DEV_CONTEXT *UsbXdciDevContext;
|
|
|
|
|
|
//
|
|
// Locate USB_BUS for the current host controller
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gUsbFnIoProtocolGuid,
|
|
(VOID**) &UsbFunIoProtocol,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
UsbXdciDevContext = USBFUIO_CONTEXT_FROM_PROTOCOL (UsbFunIoProtocol);
|
|
|
|
//
|
|
// free pool
|
|
//
|
|
while (UsbXdciDevContext->FirstNodePtr != NULL) {
|
|
RemoveNode (UsbFunIoProtocol, UsbXdciDevContext->FirstNodePtr);
|
|
}
|
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
UsbXdciDevContext->XdciHandle,
|
|
&gUsbFnIoProtocolGuid,
|
|
&UsbXdciDevContext->UsbFunIoProtocol,
|
|
&gUsbDeviceModeProtocolGuid,
|
|
&UsbXdciDevContext->UsbDevModeProtocol,
|
|
NULL
|
|
);
|
|
|
|
|
|
//
|
|
// Deinit??
|
|
//
|
|
if (UsbXdciDevContext->StartUpController == TRUE) {
|
|
Status = StopController (UsbFunIoProtocol);
|
|
DEBUG ((USB_FUIO_DEBUG_INFO, "USB DEV mode STOP UsbFnDeInitDevice %r\n", Status));
|
|
}
|
|
|
|
if (UsbXdciDevContext->XdciPollTimer != NULL) {
|
|
gBS->SetTimer (UsbXdciDevContext->XdciPollTimer, TimerCancel, 0);
|
|
gBS->CloseEvent (UsbXdciDevContext->XdciPollTimer);
|
|
UsbXdciDevContext->XdciPollTimer = NULL;
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
if (UsbXdciDevContext->DevInfoPtr != NULL) {
|
|
FreeDeviceInfo(UsbXdciDevContext->DevInfoPtr);
|
|
FreePool(UsbXdciDevContext->DevInfoPtr);
|
|
}
|
|
|
|
FreePool (UsbXdciDevContext);
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceDxeDriverStop, Status: %r\n", Status));
|
|
return EFI_SUCCESS;
|
|
}
|