reactos/drivers/bus/acpi/osl.c
2018-08-04 19:19:34 +02:00

950 lines
19 KiB
C

/*******************************************************************************
* *
* ACPI Component Architecture Operating System Layer (OSL) for ReactOS *
* *
*******************************************************************************/
#include "precomp.h"
#include <pseh/pseh2.h>
#define NDEBUG
#include <debug.h>
static PKINTERRUPT AcpiInterrupt;
static BOOLEAN AcpiInterruptHandlerRegistered = FALSE;
static ACPI_OSD_HANDLER AcpiIrqHandler = NULL;
static PVOID AcpiIrqContext = NULL;
static ULONG AcpiIrqNumber = 0;
ACPI_STATUS
AcpiOsInitialize (void)
{
DPRINT("AcpiOsInitialize called\n");
#ifndef NDEBUG
/* Verboseness level of the acpica core */
AcpiDbgLevel = 0x00FFFFFF;
AcpiDbgLayer = 0xFFFFFFFF;
#endif
return AE_OK;
}
ACPI_STATUS
AcpiOsTerminate(void)
{
DPRINT("AcpiOsTerminate() called\n");
return AE_OK;
}
ACPI_PHYSICAL_ADDRESS
AcpiOsGetRootPointer (
void)
{
ACPI_PHYSICAL_ADDRESS pa = 0;
DPRINT("AcpiOsGetRootPointer\n");
AcpiFindRootPointer(&pa);
return pa;
}
ACPI_STATUS
AcpiOsPredefinedOverride(
const ACPI_PREDEFINED_NAMES *PredefinedObject,
ACPI_STRING *NewValue)
{
if (!PredefinedObject || !NewValue)
{
DPRINT1("Invalid parameter\n");
return AE_BAD_PARAMETER;
}
/* No override */
*NewValue = NULL;
return AE_OK;
}
ACPI_STATUS
AcpiOsTableOverride(
ACPI_TABLE_HEADER *ExistingTable,
ACPI_TABLE_HEADER **NewTable)
{
if (!ExistingTable || !NewTable)
{
DPRINT1("Invalid parameter\n");
return AE_BAD_PARAMETER;
}
/* No override */
*NewTable = NULL;
return AE_OK;
}
ACPI_STATUS
AcpiOsPhysicalTableOverride(
ACPI_TABLE_HEADER *ExistingTable,
ACPI_PHYSICAL_ADDRESS *NewAddress,
UINT32 *NewTableLength)
{
if (!ExistingTable || !NewAddress || !NewTableLength)
{
DPRINT1("Invalid parameter\n");
return AE_BAD_PARAMETER;
}
/* No override */
*NewAddress = 0;
*NewTableLength = 0;
return AE_OK;
}
void *
AcpiOsMapMemory (
ACPI_PHYSICAL_ADDRESS phys,
ACPI_SIZE length)
{
PHYSICAL_ADDRESS Address;
PVOID Ptr;
DPRINT("AcpiOsMapMemory(phys 0x%p size 0x%X)\n", phys, length);
Address.QuadPart = (ULONG)phys;
Ptr = MmMapIoSpace(Address, length, MmNonCached);
if (!Ptr)
{
DPRINT1("Mapping failed\n");
}
return Ptr;
}
void
AcpiOsUnmapMemory (
void *virt,
ACPI_SIZE length)
{
DPRINT("AcpiOsMapMemory(phys 0x%p size 0x%X)\n", virt, length);
ASSERT(virt);
MmUnmapIoSpace(virt, length);
}
ACPI_STATUS
AcpiOsGetPhysicalAddress(
void *LogicalAddress,
ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
{
PHYSICAL_ADDRESS PhysAddr;
if (!LogicalAddress || !PhysicalAddress)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
PhysAddr = MmGetPhysicalAddress(LogicalAddress);
*PhysicalAddress = (ACPI_PHYSICAL_ADDRESS)PhysAddr.QuadPart;
return AE_OK;
}
void *
AcpiOsAllocate (ACPI_SIZE size)
{
DPRINT("AcpiOsAllocate size %d\n",size);
return ExAllocatePoolWithTag(NonPagedPool, size, 'ipcA');
}
void
AcpiOsFree(void *ptr)
{
if (!ptr)
DPRINT1("Attempt to free null pointer!!!\n");
ExFreePoolWithTag(ptr, 'ipcA');
}
BOOLEAN
AcpiOsReadable(
void *Memory,
ACPI_SIZE Length)
{
BOOLEAN Ret = FALSE;
_SEH2_TRY
{
ProbeForRead(Memory, Length, sizeof(UCHAR));
Ret = TRUE;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = FALSE;
}
_SEH2_END;
return Ret;
}
BOOLEAN
AcpiOsWritable(
void *Memory,
ACPI_SIZE Length)
{
BOOLEAN Ret = FALSE;
_SEH2_TRY
{
ProbeForWrite(Memory, Length, sizeof(UCHAR));
Ret = TRUE;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = FALSE;
}
_SEH2_END;
return Ret;
}
ACPI_THREAD_ID
AcpiOsGetThreadId (void)
{
/* Thread ID must be non-zero */
return (ULONG_PTR)PsGetCurrentThreadId() + 1;
}
ACPI_STATUS
AcpiOsExecute (
ACPI_EXECUTE_TYPE Type,
ACPI_OSD_EXEC_CALLBACK Function,
void *Context)
{
HANDLE ThreadHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
DPRINT("AcpiOsExecute\n");
InitializeObjectAttributes(&ObjectAttributes,
NULL,
OBJ_KERNEL_HANDLE,
NULL,
NULL);
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,
NULL,
NULL,
(PKSTART_ROUTINE)Function,
Context);
if (!NT_SUCCESS(Status))
return AE_ERROR;
ZwClose(ThreadHandle);
return AE_OK;
}
void
AcpiOsSleep (UINT64 milliseconds)
{
DPRINT("AcpiOsSleep %d\n", milliseconds);
KeStallExecutionProcessor(milliseconds*1000);
}
void
AcpiOsStall (UINT32 microseconds)
{
DPRINT("AcpiOsStall %d\n",microseconds);
KeStallExecutionProcessor(microseconds);
}
ACPI_STATUS
AcpiOsCreateMutex(
ACPI_MUTEX *OutHandle)
{
PFAST_MUTEX Mutex;
if (!OutHandle)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
Mutex = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), 'LpcA');
if (!Mutex) return AE_NO_MEMORY;
ExInitializeFastMutex(Mutex);
*OutHandle = (ACPI_MUTEX)Mutex;
return AE_OK;
}
void
AcpiOsDeleteMutex(
ACPI_MUTEX Handle)
{
if (!Handle)
{
DPRINT1("Bad parameter\n");
return;
}
ExFreePoolWithTag(Handle, 'LpcA');
}
ACPI_STATUS
AcpiOsAcquireMutex(
ACPI_MUTEX Handle,
UINT16 Timeout)
{
if (!Handle)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
/* Check what the caller wants us to do */
if (Timeout == ACPI_DO_NOT_WAIT)
{
/* Try to acquire without waiting */
if (!ExTryToAcquireFastMutex((PFAST_MUTEX)Handle))
return AE_TIME;
}
else
{
/* Block until we get it */
ExAcquireFastMutex((PFAST_MUTEX)Handle);
}
return AE_OK;
}
void
AcpiOsReleaseMutex(
ACPI_MUTEX Handle)
{
if (!Handle)
{
DPRINT1("Bad parameter\n");
return;
}
ExReleaseFastMutex((PFAST_MUTEX)Handle);
}
typedef struct _ACPI_SEM {
UINT32 CurrentUnits;
KEVENT Event;
KSPIN_LOCK Lock;
} ACPI_SEM, *PACPI_SEM;
ACPI_STATUS
AcpiOsCreateSemaphore(
UINT32 MaxUnits,
UINT32 InitialUnits,
ACPI_SEMAPHORE *OutHandle)
{
PACPI_SEM Sem;
if (!OutHandle)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
Sem = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_SEM), 'LpcA');
if (!Sem) return AE_NO_MEMORY;
Sem->CurrentUnits = InitialUnits;
KeInitializeEvent(&Sem->Event, SynchronizationEvent, Sem->CurrentUnits != 0);
KeInitializeSpinLock(&Sem->Lock);
*OutHandle = (ACPI_SEMAPHORE)Sem;
return AE_OK;
}
ACPI_STATUS
AcpiOsDeleteSemaphore(
ACPI_SEMAPHORE Handle)
{
if (!Handle)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
ExFreePoolWithTag(Handle, 'LpcA');
return AE_OK;
}
ACPI_STATUS
AcpiOsWaitSemaphore(
ACPI_SEMAPHORE Handle,
UINT32 Units,
UINT16 Timeout)
{
PACPI_SEM Sem = Handle;
KIRQL OldIrql;
if (!Handle)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
KeAcquireSpinLock(&Sem->Lock, &OldIrql);
/* Make sure we can wait if we have fewer units than we need */
if ((Timeout == ACPI_DO_NOT_WAIT) && (Sem->CurrentUnits < Units))
{
/* We can't so we must bail now */
KeReleaseSpinLock(&Sem->Lock, OldIrql);
return AE_TIME;
}
/* Time to block until we get enough units */
while (Sem->CurrentUnits < Units)
{
KeReleaseSpinLock(&Sem->Lock, OldIrql);
KeWaitForSingleObject(&Sem->Event,
Executive,
KernelMode,
FALSE,
NULL);
KeAcquireSpinLock(&Sem->Lock, &OldIrql);
}
Sem->CurrentUnits -= Units;
if (Sem->CurrentUnits != 0) KeSetEvent(&Sem->Event, IO_NO_INCREMENT, FALSE);
KeReleaseSpinLock(&Sem->Lock, OldIrql);
return AE_OK;
}
ACPI_STATUS
AcpiOsSignalSemaphore(
ACPI_SEMAPHORE Handle,
UINT32 Units)
{
PACPI_SEM Sem = Handle;
KIRQL OldIrql;
if (!Handle)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
KeAcquireSpinLock(&Sem->Lock, &OldIrql);
Sem->CurrentUnits += Units;
KeSetEvent(&Sem->Event, IO_NO_INCREMENT, FALSE);
KeReleaseSpinLock(&Sem->Lock, OldIrql);
return AE_OK;
}
ACPI_STATUS
AcpiOsCreateLock(
ACPI_SPINLOCK *OutHandle)
{
PKSPIN_LOCK SpinLock;
if (!OutHandle)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
SpinLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(KSPIN_LOCK), 'LpcA');
if (!SpinLock) return AE_NO_MEMORY;
KeInitializeSpinLock(SpinLock);
*OutHandle = (ACPI_SPINLOCK)SpinLock;
return AE_OK;
}
void
AcpiOsDeleteLock(
ACPI_SPINLOCK Handle)
{
if (!Handle)
{
DPRINT1("Bad parameter\n");
return;
}
ExFreePoolWithTag(Handle, 'LpcA');
}
ACPI_CPU_FLAGS
AcpiOsAcquireLock(
ACPI_SPINLOCK Handle)
{
KIRQL OldIrql;
if ((OldIrql = KeGetCurrentIrql()) >= DISPATCH_LEVEL)
{
KeAcquireSpinLockAtDpcLevel((PKSPIN_LOCK)Handle);
}
else
{
KeAcquireSpinLock((PKSPIN_LOCK)Handle, &OldIrql);
}
return (ACPI_CPU_FLAGS)OldIrql;
}
void
AcpiOsReleaseLock(
ACPI_SPINLOCK Handle,
ACPI_CPU_FLAGS Flags)
{
KIRQL OldIrql = (KIRQL)Flags;
if (OldIrql >= DISPATCH_LEVEL)
{
KeReleaseSpinLockFromDpcLevel((PKSPIN_LOCK)Handle);
}
else
{
KeReleaseSpinLock((PKSPIN_LOCK)Handle, OldIrql);
}
}
BOOLEAN NTAPI
OslIsrStub(
PKINTERRUPT Interrupt,
PVOID ServiceContext)
{
INT32 Status;
Status = (*AcpiIrqHandler)(AcpiIrqContext);
if (Status == ACPI_INTERRUPT_HANDLED)
return TRUE;
else
return FALSE;
}
UINT32
AcpiOsInstallInterruptHandler (
UINT32 InterruptNumber,
ACPI_OSD_HANDLER ServiceRoutine,
void *Context)
{
ULONG Vector;
KIRQL DIrql;
KAFFINITY Affinity;
NTSTATUS Status;
if (AcpiInterruptHandlerRegistered)
{
DPRINT1("Reregister interrupt attempt failed\n");
return AE_ALREADY_EXISTS;
}
if (!ServiceRoutine)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
DPRINT("AcpiOsInstallInterruptHandler()\n");
Vector = HalGetInterruptVector(
Internal,
0,
InterruptNumber,
InterruptNumber,
&DIrql,
&Affinity);
AcpiIrqNumber = InterruptNumber;
AcpiIrqHandler = ServiceRoutine;
AcpiIrqContext = Context;
AcpiInterruptHandlerRegistered = TRUE;
Status = IoConnectInterrupt(
&AcpiInterrupt,
OslIsrStub,
NULL,
NULL,
Vector,
DIrql,
DIrql,
LevelSensitive,
TRUE,
Affinity,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not connect to interrupt %d\n", Vector);
return AE_ERROR;
}
return AE_OK;
}
ACPI_STATUS
AcpiOsRemoveInterruptHandler (
UINT32 InterruptNumber,
ACPI_OSD_HANDLER ServiceRoutine)
{
DPRINT("AcpiOsRemoveInterruptHandler()\n");
if (!ServiceRoutine)
{
DPRINT1("Bad parameter\n");
return AE_BAD_PARAMETER;
}
if (AcpiInterruptHandlerRegistered)
{
IoDisconnectInterrupt(AcpiInterrupt);
AcpiInterrupt = NULL;
AcpiInterruptHandlerRegistered = FALSE;
}
else
{
DPRINT1("Trying to remove non-existing interrupt handler\n");
return AE_NOT_EXIST;
}
return AE_OK;
}
ACPI_STATUS
AcpiOsReadMemory (
ACPI_PHYSICAL_ADDRESS Address,
UINT64 *Value,
UINT32 Width)
{
DPRINT("AcpiOsReadMemory %p\n", Address);
switch (Width)
{
case 8:
*Value = (*(PUCHAR)(ULONG_PTR)Address);
break;
case 16:
*Value = (*(PUSHORT)(ULONG_PTR)Address);
break;
case 32:
*Value = (*(PULONG)(ULONG_PTR)Address);
break;
case 64:
*Value = (*(PULONGLONG)(ULONG_PTR)Address);
break;
default:
DPRINT1("AcpiOsReadMemory got bad width: %d\n",Width);
return (AE_BAD_PARAMETER);
break;
}
return (AE_OK);
}
ACPI_STATUS
AcpiOsWriteMemory (
ACPI_PHYSICAL_ADDRESS Address,
UINT64 Value,
UINT32 Width)
{
DPRINT("AcpiOsWriteMemory %p\n", Address);
switch (Width)
{
case 8:
*(PUCHAR)(ULONG_PTR)Address = Value;
break;
case 16:
*(PUSHORT)(ULONG_PTR)Address = Value;
break;
case 32:
*(PULONG)(ULONG_PTR)Address = Value;
break;
case 64:
*(PULONGLONG)(ULONG_PTR)Address = Value;
break;
default:
DPRINT1("AcpiOsWriteMemory got bad width: %d\n",Width);
return (AE_BAD_PARAMETER);
break;
}
return (AE_OK);
}
ACPI_STATUS
AcpiOsReadPort (
ACPI_IO_ADDRESS Address,
UINT32 *Value,
UINT32 Width)
{
DPRINT("AcpiOsReadPort %p, width %d\n",Address,Width);
switch (Width)
{
case 8:
*Value = READ_PORT_UCHAR((PUCHAR)(ULONG_PTR)Address);
break;
case 16:
*Value = READ_PORT_USHORT((PUSHORT)(ULONG_PTR)Address);
break;
case 32:
*Value = READ_PORT_ULONG((PULONG)(ULONG_PTR)Address);
break;
default:
DPRINT1("AcpiOsReadPort got bad width: %d\n",Width);
return (AE_BAD_PARAMETER);
break;
}
return (AE_OK);
}
ACPI_STATUS
AcpiOsWritePort (
ACPI_IO_ADDRESS Address,
UINT32 Value,
UINT32 Width)
{
DPRINT("AcpiOsWritePort %p, width %d\n",Address,Width);
switch (Width)
{
case 8:
WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR)Address, Value);
break;
case 16:
WRITE_PORT_USHORT((PUSHORT)(ULONG_PTR)Address, Value);
break;
case 32:
WRITE_PORT_ULONG((PULONG)(ULONG_PTR)Address, Value);
break;
default:
DPRINT1("AcpiOsWritePort got bad width: %d\n",Width);
return (AE_BAD_PARAMETER);
break;
}
return (AE_OK);
}
BOOLEAN
OslIsPciDevicePresent(ULONG BusNumber, ULONG SlotNumber)
{
UINT32 ReadLength;
PCI_COMMON_CONFIG PciConfig;
/* Detect device presence by reading the PCI configuration space */
ReadLength = HalGetBusDataByOffset(PCIConfiguration,
BusNumber,
SlotNumber,
&PciConfig,
0,
sizeof(PciConfig));
if (ReadLength == 0)
{
DPRINT("PCI device is not present\n");
return FALSE;
}
ASSERT(ReadLength >= 2);
if (PciConfig.VendorID == PCI_INVALID_VENDORID)
{
DPRINT("Invalid vendor ID in PCI configuration space\n");
return FALSE;
}
DPRINT("PCI device is present\n");
return TRUE;
}
ACPI_STATUS
AcpiOsReadPciConfiguration (
ACPI_PCI_ID *PciId,
UINT32 Reg,
UINT64 *Value,
UINT32 Width)
{
PCI_SLOT_NUMBER slot;
slot.u.AsULONG = 0;
slot.u.bits.DeviceNumber = PciId->Device;
slot.u.bits.FunctionNumber = PciId->Function;
DPRINT("AcpiOsReadPciConfiguration, slot=0x%X, func=0x%X\n", slot.u.AsULONG, Reg);
if (!OslIsPciDevicePresent(PciId->Bus, slot.u.AsULONG))
return AE_NOT_FOUND;
/* Width is in BITS */
HalGetBusDataByOffset(PCIConfiguration,
PciId->Bus,
slot.u.AsULONG,
Value,
Reg,
(Width >> 3));
return AE_OK;
}
ACPI_STATUS
AcpiOsWritePciConfiguration (
ACPI_PCI_ID *PciId,
UINT32 Reg,
UINT64 Value,
UINT32 Width)
{
ULONG buf = Value;
PCI_SLOT_NUMBER slot;
slot.u.AsULONG = 0;
slot.u.bits.DeviceNumber = PciId->Device;
slot.u.bits.FunctionNumber = PciId->Function;
DPRINT("AcpiOsWritePciConfiguration, slot=0x%x\n", slot.u.AsULONG);
if (!OslIsPciDevicePresent(PciId->Bus, slot.u.AsULONG))
return AE_NOT_FOUND;
/* Width is in BITS */
HalSetBusDataByOffset(PCIConfiguration,
PciId->Bus,
slot.u.AsULONG,
&buf,
Reg,
(Width >> 3));
return AE_OK;
}
void ACPI_INTERNAL_VAR_XFACE
AcpiOsPrintf (
const char *Fmt,
...)
{
va_list Args;
va_start (Args, Fmt);
AcpiOsVprintf (Fmt, Args);
va_end (Args);
return;
}
void
AcpiOsVprintf (
const char *Fmt,
va_list Args)
{
#ifndef NDEBUG
vDbgPrintEx (-1, DPFLTR_ERROR_LEVEL, Fmt, Args);
#endif
return;
}
void
AcpiOsRedirectOutput(
void *Destination)
{
/* No-op */
DPRINT1("Output redirection not supported\n");
}
UINT64
AcpiOsGetTimer(
void)
{
LARGE_INTEGER CurrentTime;
KeQuerySystemTime(&CurrentTime);
return CurrentTime.QuadPart;
}
void
AcpiOsWaitEventsComplete(void)
{
/*
* Wait for all asynchronous events to complete.
* This implementation does nothing.
*/
return;
}
ACPI_STATUS
AcpiOsSignal (
UINT32 Function,
void *Info)
{
ACPI_SIGNAL_FATAL_INFO *FatalInfo = Info;
switch (Function)
{
case ACPI_SIGNAL_FATAL:
if (Info)
DPRINT1 ("AcpiOsBreakpoint: %d %d %d ****\n", FatalInfo->Type, FatalInfo->Code, FatalInfo->Argument);
else
DPRINT1 ("AcpiOsBreakpoint ****\n");
break;
case ACPI_SIGNAL_BREAKPOINT:
if (Info)
DPRINT1 ("AcpiOsBreakpoint: %s ****\n", Info);
else
DPRINT1 ("AcpiOsBreakpoint ****\n");
break;
}
ASSERT(FALSE);
return (AE_OK);
}
ACPI_STATUS
AcpiOsEnterSleep(
UINT8 SleepState,
UINT32 RegaValue,
UINT32 RegbValue)
{
DPRINT1("Entering sleep state S%u.\n", SleepState);
return AE_OK;
}
ACPI_STATUS
AcpiOsGetLine(
char *Buffer,
UINT32 BufferLength,
UINT32 *BytesRead)
{
DPRINT1("File reading not supported\n");
return AE_ERROR;
}