/**
*Uhcd.c - USB Host Controller Driver (xHCI) for Lenovo HR650X
*
*Source: AmiModulePkg/Usb/Uhcd.c (and related: UsbMisc.c, AmiUsbHc.c)
*
*This module implements an AMI-proprietary USB Host Controller Driver
*that manages xHCI controllers on the Lenovo HR650X platform. It handles:
*
* - Driver entry and UHCD protocol installation
* - xHCI controller enumeration, initialization, and register access
* - USB device tree management (add/remove/update devices)
* - Control, bulk, interrupt, and isochronous transfer scheduling
* - Root hub emulation (port status, feature control)
* - Timer-based polling for interrupt transfers
* - Memory pool management for RT USB data structures
*
*The driver defines a large global structure (gUsbData, ~30KB) allocated
*from runtime memory pool. It also defines a private vtable (gUsbCallbacks)
*for internal helper dispatch.
*/
#include "Uhcd.h"
/*===========================================================================
*Global variables
*===========================================================================*/
USB_DATA *gUsbData = NULL; /*Main driver context (qword_11A90) */
USB_HC_CALLBACKS *gUsbCallbacks = NULL; /*Private vtable (qword_11A38) */
EFI_CPU_IO2_PROTOCOL *gCpuIo = NULL; /*SystemTable->BootServices derived */
EFI_BOOT_SERVICES *gBootServices = NULL; /*gBS */
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL; /*gRT */
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gSystemTable = NULL;
/*===========================================================================
*Utility functions (memory, string, compare)
*===========================================================================*/
/**
*MemCopy - Overlapping-safe memory copy.
*
*Equivalent to UefiLib CopyMem with overlap handling.
*When src < dst and ranges overlap, copies from end to start.
*Otherwise, uses qmemcpy (fast 8-byte aligned copy + trailing bytes).
*
* @param dst Destination buffer
* @param src Source buffer
* @param count Number of bytes to copy
*
* @return dst
*/
void *MemCopy (
void *dst,
const void *src,
UINTN count
)
{
return memmove(dst, src, count);
}
/**
*MemSet - Fill memory with a constant byte.
*
* @param buf Buffer to fill
* @param count Number of bytes
* @param value Fill byte value
*
* @return buf
*/
void *MemSet (
void *buf,
UINTN count,
UINT8 value
)
{
return memset(buf, value, count);
}
/**
*MemCmp - Compare two memory buffers.
*
* @param a1 First buffer
* @param a2 Second buffer
* @param len Number of bytes to compare
*
* @return 0 if equal, nonzero otherwise
*/
INTN MemCmp (
const VOID *a1,
const VOID *a2,
UINTN len
)
{
return memcmp(a1, a2, len);
}
/*===========================================================================
*USB memory pool management
*===========================================================================*/
/**
*UsbRtAllocPool - Allocate from USB runtime memory pool.
*
*Uses a pre-allocated RT memory region (gBS->AllocatePages of
*EfiRuntimeServicesData) and sub-allocates entries aligned to
* @c Alignment.
*
* @param Size Requested allocation size
* @param Alignment Required alignment (must be power of 2)
*
* @return Allocated virtual address, or NULL on failure
*/
VOID *UsbRtAllocPool (
UINT32 Size,
UINT16 Alignment
)
{
/*See decompiled sub_2AB0 */
return NULL;
}
/**
*UsbRtAllocPages - Allocate aligned physical pages from system memory.
*
*Uses gBS->AllocatePages with AllocateMaxAddress to obtain physical
*pages aligned to @c Alignment.
*
* @param CpuIo EFI_CPU_IO2_PROTOCOL instance
* @param Pages Number of 4KB pages requested
* @param Alignment Required alignment in bytes (power of 2)
*
* @return Physical address of allocated memory, or 0 on failure
*/
UINT64 UsbRtAllocPages (
IN EFI_CPU_IO2_PROTOCOL *CpuIo,
IN UINTN Pages,
IN UINT64 Alignment
)
{
/*See decompiled sub_2C18 */
return 0;
}
/*===========================================================================
*xHCI controller enumeration and initialization
*===========================================================================*/
/**
*LocateAndInitXhciController - Find and initialize xHCI controllers.
*
*Scans the ACPI DSDT/SSDT for xHCI controller devices, opens PCI I/O
*protocol, reads capability registers, resets the controller, and
*prepares the operational register range.
*
* @param ImageHandle The driver's image handle
* @param AcpiTable Pointer to DSDT/SSDT table
*
* @return EFI_STATUS
*/
EFI_STATUS LocateAndInitXhciController (
EFI_HANDLE ImageHandle,
VOID *AcpiTable
)
{
/*See decompiled sub_2634 */
return EFI_UNSUPPORTED;
}
/**
*XhciCapabilityProbe - Probe xHCI controller capabilities.
*
*Reads CAPLENGTH, HCSPARAMS1/2, HCCPARAMS1, DBOFF, RTSOFF,
*and extended capabilities (USB2/USB3 support, legacy support, debug).
*
* @param MmioBase MMIO base address of the xHCI controller
* @param Regs Output: filled-in register offsets
*
* @return EFI_STATUS
*/
EFI_STATUS XhciCapabilityProbe (
UINT64 MmioBase,
VOID *Regs
)
{
/*See decompiled sub_5718, sub_5AD0 */
return EFI_UNSUPPORTED;
}
/*===========================================================================
*USB device tree management
*===========================================================================*/
/**
*UsbBusInstallDevice - Install a new USB device in the device tree.
*/
EFI_STATUS UsbBusInstallDevice (
UINT8 *DeviceData,
VOID *ParentHub
)
{
/*See decompiled sub_7E98 */
return EFI_UNSUPPORTED;
}
/**
*UsbBusUninstallDevice - Remove a USB device from the device tree.
*/
EFI_STATUS UsbBusUninstallDevice (
UINT8 *DeviceData
)
{
/*See decompiled sub_8778 */
return EFI_UNSUPPORTED;
}
/**
*UsbBusRemoveDeviceGroup - Remove all devices on a hub port.
*/
EFI_STATUS UsbBusRemoveDeviceGroup (
VOID *HubNode,
UINT8 Port
)
{
/*See decompiled sub_8A70 */
return EFI_UNSUPPORTED;
}
/**
*UsbHcNodeTimerCheck - Periodic HC timer callback.
*/
VOID UsbHcNodeTimerCheck (
VOID *HubNode
)
{
/*See decompiled sub_8C70 */
return;
}
/*===========================================================================
*USB transfer scheduling
*===========================================================================*/
/**
*UsbHcControlTransfer - Execute a USB control transfer.
*/
EFI_STATUS UsbHcControlTransfer (
IN USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndpointAddress,
IN VOID *Request,
IN UINTN RequestLen,
IN EFI_USB_DEVICE_REQUEST *UsbRequest,
IN UINT32 Timeout,
OUT VOID *Data,
IN OUT UINTN *DataLength,
OUT UINT64 *TransferStatus
)
{
/*See decompiled sub_3FF0 */
return EFI_UNSUPPORTED;
}
/**
*UsbHcBulkTransfer - Execute a USB bulk transfer.
*/
EFI_STATUS UsbHcBulkTransfer (
IN USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndPoint,
IN UINT8 Direction,
IN OUT VOID *Data,
IN OUT UINTN *DataLength,
IN UINTN Timeout,
OUT UINT64 *TransferStatus
)
{
/*See decompiled sub_4274 */
return EFI_UNSUPPORTED;
}
/**
*UsbHcAsyncInterruptTransfer - Set up or remove async interrupt xfer.
*/
EFI_STATUS UsbHcAsyncInterruptTransfer (
IN USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndPoint,
IN BOOLEAN IsNewTransfer,
IN UINTN PollingInterval,
IN UINTN DataLength,
IN VOID *CallBackFunction,
IN VOID *Context
)
{
/*See decompiled sub_4720 */
return EFI_UNSUPPORTED;
}
/**
*UsbHcSyncInterruptTransfer - Execute a synchronous interrupt xfer.
*/
EFI_STATUS UsbHcSyncInterruptTransfer (
IN USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndPoint,
IN OUT VOID *Data,
IN OUT UINTN *DataLength,
IN UINTN Timeout,
OUT UINT64 *TransferStatus
)
{
/*See decompiled sub_49A4 */
return EFI_UNSUPPORTED;
}
/**
*UsbHcIsochronousTransfer - Execute an isochronous transfer.
*/
EFI_STATUS UsbHcIsochronousTransfer (
IN USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndPoint,
IN OUT VOID *Data,
IN UINTN DataLength,
OUT UINT64 *TransferStatus
)
{
/*See decompiled sub_50BC */
return EFI_UNSUPPORTED;
}
/**
*UsbHcAsyncIsochronousTransfer - Set up or remove async isochronous.
*/
EFI_STATUS UsbHcAsyncIsochronousTransfer (
IN USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndPoint,
IN VOID *CallBackFunction,
IN VOID *Context
)
{
/*See decompiled sub_53E8 */
return EFI_UNSUPPORTED;
}
/*===========================================================================
*Root hub emulation
*===========================================================================*/
EFI_STATUS UsbHcGetRootHubPortStatus (
IN USB_HC_PROTOCOL *This,
IN UINT8 PortNumber,
OUT UINT64 *PortStatus
)
{
/*See decompiled sub_3B1C, sub_3B68 */
return EFI_UNSUPPORTED;
}
EFI_STATUS UsbHcSetRootHubPortFeature (
IN USB_HC_PROTOCOL *This,
IN UINT8 PortNumber,
IN EFI_USB_PORT_FEATURE Feature
)
{
/*See decompiled sub_3C7C */
return EFI_UNSUPPORTED;
}
EFI_STATUS UsbHcClearRootHubPortFeature (
IN USB_HC_PROTOCOL *This,
IN UINT8 PortNumber,
IN EFI_USB_PORT_FEATURE Feature
)
{
/*See decompiled sub_3CEC */
return EFI_UNSUPPORTED;
}
EFI_STATUS UsbHcSetState (
IN USB_HC_PROTOCOL *This,
IN UINT32 State
)
{
/*See decompiled sub_3908 */
return EFI_UNSUPPORTED;
}
/*===========================================================================
*Device enumeration / descriptor helpers
*===========================================================================*/
EFI_STATUS UsbBusLoadEndpointPolicy (
UINT8 *DeviceData
)
{
/*See decompiled sub_674C, sub_6A7C */
return EFI_UNSUPPORTED;
}
EFI_STATUS UsbBusConfigureEndpoints (
UINT8 *DeviceData
)
{
/*See decompiled sub_6BC0 */
return EFI_UNSUPPORTED;
}
EFI_STATUS UsbBusGetDeviceDescriptor (
UINT8 *DeviceData,
VOID *Desc
)
{
/*See decompiled sub_6384 */
return EFI_UNSUPPORTED;
}
/*===========================================================================
*Driver binding protocol
*===========================================================================*/
EFI_STATUS EFIAPI UhcdDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
/*See decompiled sub_2448 */
return EFI_UNSUPPORTED;
}
EFI_STATUS EFIAPI UhcdDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
/*See decompiled sub_1290 */
return EFI_UNSUPPORTED;
}
EFI_STATUS EFIAPI UhcdDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
/*See decompiled sub_1620 */
return EFI_UNSUPPORTED;
}
EFI_STATUS EFIAPI UhcdDriverBindingStopChild (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_HANDLE ChildHandle
)
{
/*See decompiled sub_116C */
return EFI_UNSUPPORTED;
}
/*===========================================================================
*Driver entry point
*===========================================================================*/
/**
*UhcdDriverEntryPoint - Entry point for the UHCD driver.
*
*Performs:
*1. Save ImageHandle, SystemTable, BootServices, RuntimeServices
*2. Read UsbSupport variable before initialization
*3. Allocate gUsbData (~30KB) and initialize all fields
*4. Allocate gUsbCallbacks vtable with helper function pointers
*5. Install USB_HC protocol interface (sub_52C as HC handler)
*6. Register driver binding, install components, create timer events
*7. Register USB bus, mass storage, HID, and keyboard class drivers
*
* @param ImageHandle The firmware-allocated handle for this image
* @param SystemTable The UEFI system table
*
* @return EFI_STATUS
*/
EFI_STATUS EFIAPI UhcdDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT32 VarSize;
UINT8 UsbEnabled;
//
// Save global table pointers
//
if (gSystemTable == NULL) {
gSystemTable = SystemTable;
gBootServices = SystemTable->BootServices;
gRuntimeServices = SystemTable->RuntimeServices;
}
//
// Check firmware variable: UsbSupport must be enabled (=1)
//
VarSize = sizeof (UsbEnabled);
Status = gRuntimeServices->GetVariable (
L"UsbSupport",
&gUsbSupportVarGuid,
NULL,
&VarSize,
&UsbEnabled
);
if (EFI_ERROR (Status) || !(UsbEnabled & 1)) {
return EFI_UNSUPPORTED;
}
//
// Allocate main driver context (gUsbData)
//
gUsbData = AllocateRuntimePool (sizeof (USB_DATA));
if (gUsbData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem (gUsbData, sizeof (USB_DATA));
gUsbData->Signature = USB_DATA_SIGNATURE;
gUsbData->Flags = USB_DATA_FLAG_INITIALIZED;
//
// Allocate device address map
//
gUsbData->DeviceAddressMap = ~(UINT64)0;
//
// Initialize timer list head (self-referencing)
//
InitializeListHead (&gUsbData->TimerListHead);
gUsbData->TimerInterval = 100; /*100 ms */
gUsbData->TimerMaxCount = 6;
//
// Allocate memory map via PciIo->AllocateBuffer
//
// ... see decompiled sub_678 ...
//
// Allocate gUsbCallbacks vtable and populate function pointers
//
gUsbCallbacks = AllocatePool (sizeof (USB_HC_CALLBACKS));
if (gUsbCallbacks == NULL) {
return EFI_OUT_OF_RESOURCES;
}
gUsbCallbacks->UsbData = gUsbData;
gUsbCallbacks->DriverBinding = NULL; /*set during InstallProtocolInterface */
gUsbCallbacks->GetCurrentDevice = UsbHcGetCurrentDevice;
gUsbCallbacks->SetDeviceAddress = UsbHcSetDeviceAddress;
gUsbCallbacks->ResetDevice = UsbHcResetDevice;
gUsbCallbacks->GetPollingMap = UsbHcGetNullMap;
gUsbCallbacks->GetBulkMap = UsbHcGetNullMap;
gUsbCallbacks->GetControlMap = UsbHcGetNullMap;
gUsbCallbacks->TimerCallback = UsbHcTimerCallback;
gUsbCallbacks->StopController = UsbHcStopPolling;
gUsbCallbacks->SkipDevice = UsbHcSkipDevice;
gUsbCallbacks->LegacySupport = UsbHcLegacySupport;
//
// Install USB_HC protocol interface
//
// ... see InstallProtocolInterface(&ImageHandle, &gUhcdProtocolGuid, ...) ...
//
// Install USB_BUS protocol, UHCD timer event, etc.
//
DEBUG ((DEBUG_INFO, "AmiUsb Version: %d\n", *(UINT8*)gUsbData));
DEBUG ((DEBUG_INFO,
"AMIUHCD USB Init: data located at........... %x\n",
gUsbData));
DEBUG ((DEBUG_INFO, "Log address: %x\n", (UINT64)&gUsbData + 8));
DEBUG ((DEBUG_INFO, "Memory map: %x\n", gUsbData->MemoryMapPhys));
DEBUG ((DEBUG_INFO, "Device address map: %x\n", gUsbData->DeviceAddressMap));
return Status;
}
/**
*ModuleEntryPoint - PE/COFF entry point.
*
*Standard UEFI DXE driver entry. Saves global table pointers
*and invokes UhcdDriverEntryPoint.
*
* @param ImageHandle Image handle
* @param SystemTable System table
*
* @return EFI_STATUS
*/
EFI_STATUS EFIAPI ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
gImageHandle = ImageHandle;
gSystemTable = SystemTable;
gBootServices = SystemTable->BootServices;
gRuntimeServices = SystemTable->RuntimeServices;
return UhcdDriverEntryPoint (ImageHandle, SystemTable);
}