Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

786 lines
16 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
vector.c
Abstract:
This module is how external drivers add / remove hooks to deal with
ACPI Gpe Events
Author:
Stephane Plante
Environment:
NT Kernel Mode Driver Only
--*/
#include "pch.h"
//
// Table for installed GPE handlers
//
PGPE_VECTOR_ENTRY GpeVectorTable = NULL;
UCHAR GpeVectorFree = 0;
ULONG GpeVectorTableSize = 0;
VOID
ACPIVectorBuildVectorMasks(
VOID
)
/*++
Routine Description:
This routine is called to walk the GPE Vector Table and properly
enable all the events that we think should be enabled.
This routine is typically called after we have loaded a new set
of tables or we have unloaded an existing set of tables.
We have to call this routine because at the start of the operation,
we clear out all the knowledge of these additional vectors.
This routine is called with GPEs disabled and the GPE Table locked
acquired.
Arguments:
None
Return Value:
None
--*/
{
BOOLEAN installed;
ULONG i;
ULONG mode;
//
// Walk all the elements in the table
//
for (i = 0; i < GpeVectorTableSize; i++) {
//
// Does this entry point to a vector object?
//
if (GpeVectorTable[i].GpeVectorObject == NULL) {
continue;
}
if (GpeVectorTable[i].GpeVectorObject->Mode == LevelSensitive) {
mode = ACPI_GPE_LEVEL_INSTALL;
} else {
mode = ACPI_GPE_EDGE_INSTALL;
}
//
// Install the GPE into bit-maps. This validates the GPE number.
//
installed = ACPIGpeInstallRemoveIndex(
GpeVectorTable[i].GpeVectorObject->Vector,
mode,
ACPI_GPE_HANDLER,
&(GpeVectorTable[i].GpeVectorObject->HasControlMethod)
);
if (!installed) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"ACPIVectorBuildVectorMasks: Could not reenable Vector Object %d\n",
i
) );
}
}
}
NTSTATUS
ACPIVectorClear(
PDEVICE_OBJECT AcpiDeviceObject,
PVOID GpeVectorObject
)
/*++
Routine Description:
Clear the GPE_STS (status) bit associated with a vector object
Arguments:
AcpiDeviceObject - The ACPI device object
GpeVectorObject - Pointer to the vector object returned by
ACPIGpeConnectVector
Return Value
Returns status
--*/
{
PGPE_VECTOR_OBJECT localVectorObject = GpeVectorObject;
ULONG gpeIndex;
ULONG bitOffset;
ULONG i;
ASSERT( localVectorObject );
//
// What is the GPE index for this vector?
//
gpeIndex = localVectorObject->Vector;
//
// Calculate the proper mask to use
//
bitOffset = gpeIndex % 8;
//
// Calculate the offset for the register
//
i = ACPIGpeIndexToGpeRegister (gpeIndex);
//
// Clear the register
//
ACPIWriteGpeStatusRegister (i, (UCHAR) (1 << bitOffset));
return STATUS_SUCCESS;
}
NTSTATUS
ACPIVectorConnect(
PDEVICE_OBJECT AcpiDeviceObject,
ULONG GpeVector,
KINTERRUPT_MODE GpeMode,
BOOLEAN Sharable,
PGPE_SERVICE_ROUTINE ServiceRoutine,
PVOID ServiceContext,
PVOID *GpeVectorObject
)
/*++
Routine Description:
Connects a handler to a general-purpose event.
Arguments:
AcpiDeviceObject - The ACPI object
GpeVector - The event number to connect to
GpeMode - Level or edge interrupt
Sharable - Can this level be shared?
ServiceRoutine - Address of the handler
ServiceContext - Context object to be passed to the handler
*GpeVectorObject - Pointer to where the vector object is returned
Return Value
Returns status
--*/
{
BOOLEAN installed;
KIRQL oldIrql;
NTSTATUS status;
PGPE_VECTOR_OBJECT localVectorObject;
ULONG mode;
ASSERT( GpeVectorObject );
ACPIPrint( (
ACPI_PRINT_INFO,
"ACPIVectorConnect: Attach GPE handler\n"
) );
status = STATUS_SUCCESS;
*GpeVectorObject = NULL;
//
// Do GPEs exist on this machine?
//
if (AcpiInformation->GpeSize == 0) {
return STATUS_UNSUCCESSFUL;
}
//
// Validate the vector number (GPE number)
//
if ( !ACPIGpeValidIndex(GpeVector) ) {
return STATUS_INVALID_PARAMETER_2;
}
//
// Create and initialize a vector object
//
localVectorObject = ExAllocatePoolWithTag (
NonPagedPool,
sizeof(GPE_VECTOR_OBJECT),
ACPI_SHARED_GPE_POOLTAG
);
if (localVectorObject == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( localVectorObject, sizeof(GPE_VECTOR_OBJECT) );
localVectorObject->Vector = GpeVector;
localVectorObject->Handler = ServiceRoutine;
localVectorObject->Context = ServiceContext;
localVectorObject->Mode = GpeMode;
//
// We don't implement anything other than sharable...
//
localVectorObject->Sharable = Sharable;
//
// Level/Edge mode for ACPIGpeInstallRemoveIndex()
//
if (GpeMode == LevelSensitive) {
mode = ACPI_GPE_LEVEL_INSTALL;
} else {
mode = ACPI_GPE_EDGE_INSTALL;
}
//
// Lock the global tables
//
KeAcquireSpinLock (&GpeTableLock, &oldIrql);
//
// Disable GPEs while we are installing the handler
//
ACPIGpeEnableDisableEvents(FALSE);
//
// Install the GPE into bit-maps. This validates the GPE number.
//
installed = ACPIGpeInstallRemoveIndex(
GpeVector,
mode,
ACPI_GPE_HANDLER,
&(localVectorObject->HasControlMethod)
);
if (!installed) {
status = STATUS_UNSUCCESSFUL;
} else {
//
// Install GPE handler into vector table.
//
installed = ACPIVectorInstall(
GpeVector,
localVectorObject
);
if (!installed) {
ACPIGpeInstallRemoveIndex(
GpeVector,
ACPI_GPE_REMOVE,
0,
&localVectorObject->HasControlMethod
);
status = STATUS_UNSUCCESSFUL;
}
}
if (!NT_SUCCESS(status)) {
ExFreePool (localVectorObject);
} else {
*GpeVectorObject = localVectorObject;
}
//
// Update hardware to match us
//
ACPIGpeEnableDisableEvents (TRUE);
//
// Unlock tables and return status
//
KeReleaseSpinLock (&GpeTableLock, oldIrql);
return status;
}
NTSTATUS
ACPIVectorDisable(
PDEVICE_OBJECT AcpiDeviceObject,
PVOID GpeVectorObject
)
/*++
Routine Description:
Temporarily disable a GPE that is already attached to a handler.
Arguments:
AcpiDeviceObject - The ACPI device object
GpeVectorObject - Pointer to the vector object returned by ACPIGpeConnectVector
Return Value
Returns status
--*/
{
PGPE_VECTOR_OBJECT localVectorObject = GpeVectorObject;
KIRQL oldIrql;
ULONG gpeIndex;
ULONG bit;
ULONG i;
//
// The GPE index was validated when the handler was attached
//
gpeIndex = localVectorObject->Vector;
//
// Calculate the mask and index
//
bit = (1 << (gpeIndex % 8));
i = ACPIGpeIndexToGpeRegister (gpeIndex);
//
// Lock the global tables
//
KeAcquireSpinLock (&GpeTableLock, &oldIrql);
//
// Disable GPEs while we are fussing with the enable bits
//
ACPIGpeEnableDisableEvents(FALSE);
//
// Remove the GPE from the enable bit-maps. This event will be completely disabled,
// but the handler has not been removed.
//
GpeEnable [i] &= ~bit;
GpeCurEnable [i] &= ~bit;
ASSERT(!(GpeWakeEnable[i] & bit));
//
// Update hardware to match us
//
ACPIGpeEnableDisableEvents (TRUE);
//
// Unlock tables and return status
//
KeReleaseSpinLock (&GpeTableLock, oldIrql);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"ACPIVectorDisable: GPE %x disabled\n",
gpeIndex
) );
return STATUS_SUCCESS;
}
NTSTATUS
ACPIVectorDisconnect(
PVOID GpeVectorObject
)
/*++
Routine Description:
Disconnects a handler from a general-purpose event.
Arguments:
GpeVectorObject - Pointer to the vector object returned by
ACPIGpeConnectVector
Return Value
Returns status
--*/
{
BOOLEAN removed;
KIRQL oldIrql;
NTSTATUS status = STATUS_SUCCESS;
PGPE_VECTOR_OBJECT gpeVectorObj = GpeVectorObject;
ACPIPrint( (
ACPI_PRINT_INFO,
"ACPIVectorDisconnect: Detach GPE handler\n"
) );
//
// Lock the global tables
//
KeAcquireSpinLock (&GpeTableLock, &oldIrql);
//
// Disable GPEs while we are removing the handler
//
ACPIGpeEnableDisableEvents (FALSE);
//
// Remove GPE handler From vector table.
//
ACPIVectorRemove(gpeVectorObj->Vector);
//
// Remove the GPE from the bit-maps. Fall back to using control method
// if available.
//
removed = ACPIGpeInstallRemoveIndex(
gpeVectorObj->Vector,
ACPI_GPE_REMOVE,
0,
&(gpeVectorObj->HasControlMethod)
);
if (!removed) {
status = STATUS_UNSUCCESSFUL;
}
//
// Update hardware to match us
//
ACPIGpeEnableDisableEvents(TRUE);
//
// Unlock tables and return status
//
KeReleaseSpinLock (&GpeTableLock, oldIrql);
//
// Free the vector object, it's purpose is done.
//
if (status == STATUS_SUCCESS) {
ExFreePool (GpeVectorObject);
}
return status;
}
NTSTATUS
ACPIVectorEnable(
PDEVICE_OBJECT AcpiDeviceObject,
PVOID GpeVectorObject
)
/*++
Routine Description:
Enable (a previously disabled) GPE that is already attached to a handler.
Arguments:
AcpiDeviceObject - The ACPI device object
GpeVectorObject - Pointer to the vector object returned by ACPIGpeConnectVector
Return Value
Returns status
--*/
{
KIRQL oldIrql;
PGPE_VECTOR_OBJECT localVectorObject = GpeVectorObject;
ULONG bit;
ULONG gpeIndex;
ULONG gpeRegister;
//
// The GPE index was validated when the handler was attached
//
gpeIndex = localVectorObject->Vector;
bit = (1 << (gpeIndex % 8));
gpeRegister = ACPIGpeIndexToGpeRegister (gpeIndex);
//
// Lock the global tables
//
KeAcquireSpinLock (&GpeTableLock, &oldIrql);
//
// Disable GPEs while we are fussing with the enable bits
//
ACPIGpeEnableDisableEvents (FALSE);
//
// Enable the GPE in the bit maps.
//
GpeEnable [gpeRegister] |= bit;
GpeCurEnable [gpeRegister] |= bit;
//
// Update hardware to match us
//
ACPIGpeEnableDisableEvents (TRUE);
//
// Unlock tables and return status
//
KeReleaseSpinLock (&GpeTableLock, oldIrql);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"ACPIVectorEnable: GPE %x enabled\n",
gpeIndex
) );
return STATUS_SUCCESS;
}
VOID
ACPIVectorFreeEntry (
ULONG TableIndex
)
/*++
Routine Description:
Free a GPE vector table entry.
NOTE: Should be called with the global GpeVectorTable locked.
Arguments:
TableIndex - Index into GPE vector table of entry to be freed
Return Value:
NONE
--*/
{
//
// Put onto free list
//
GpeVectorTable[TableIndex].Next = GpeVectorFree;
GpeVectorFree = (UCHAR) TableIndex;
}
BOOLEAN
ACPIVectorGetEntry (
PULONG TableIndex
)
/*++
Routine Description:
Get a new vector entry from the GPE vector table.
NOTE: Should be called with the global GpeVectorTable locked.
Arguments:
TableIndex - Pointer to where the vector table index of the entry is returned
Return Value:
TRUE - Success
FALSE - Failure
--*/
{
PGPE_VECTOR_ENTRY Vector;
ULONG i, j;
#define NEW_TABLE_ENTRIES 4
if (!GpeVectorFree) {
//
// No free entries on vector table, make some
//
i = GpeVectorTableSize;
Vector = ExAllocatePoolWithTag (
NonPagedPool,
sizeof (GPE_VECTOR_ENTRY) * (i + NEW_TABLE_ENTRIES),
ACPI_SHARED_GPE_POOLTAG
);
if (Vector == NULL) {
return FALSE;
}
//
// Make sure that its in a known state
//
RtlZeroMemory(
Vector,
(sizeof(GPE_VECTOR_ENTRY) * (i + NEW_TABLE_ENTRIES) )
);
//
// Copy old table to new
//
if (GpeVectorTable) {
RtlCopyMemory(
Vector,
GpeVectorTable,
sizeof (GPE_VECTOR_ENTRY) * i
);
ExFreePool (GpeVectorTable);
}
GpeVectorTableSize += NEW_TABLE_ENTRIES;
GpeVectorTable = Vector;
//
// Link new entries
//
for (j=0; j < NEW_TABLE_ENTRIES; j++) {
GpeVectorTable[i+j].Next = (UCHAR) (i+j+1);
}
//
// The last entry in the list gets pointed to 0, because we then
// want to grow this list again
//
GpeVectorTable[i+j-1].Next = 0;
//
// The next free vector the head of the list that we just allocated
//
GpeVectorFree = (UCHAR) i;
}
*TableIndex = GpeVectorFree;
Vector = &GpeVectorTable[GpeVectorFree];
GpeVectorFree = Vector->Next;
return TRUE;
}
BOOLEAN
ACPIVectorInstall(
ULONG GpeIndex,
PGPE_VECTOR_OBJECT GpeVectorObject
)
/*++
Routine Description:
Install a GPE handler into the Map and Vector tables
NOTE: Should be called with the global GpeVectorTable locked, and GPEs disabled
Arguments:
Return Value:
TRUE - Success
FALSE - Failure
--*/
{
ULONG byteIndex;
ULONG tableIndex;
//
// Get an entry in the global vector table
//
if (ACPIVectorGetEntry (&tableIndex)) {
//
// Install the entry into the map table
//
byteIndex = ACPIGpeIndexToByteIndex (GpeIndex);
GpeMap [byteIndex] = (UCHAR) tableIndex;
//
// Install the vector object in the vector table entry
//
GpeVectorTable [tableIndex].GpeVectorObject = GpeVectorObject;
return TRUE;
}
return FALSE;
}
BOOLEAN
ACPIVectorRemove(
ULONG GpeIndex
)
/*++
Routine Description:
Remove a GPE handler from the Map and Vector tables
NOTE: Should be called with the global GpeVectorTable locked,
and GPEs disabled
Arguments:
Return Value:
TRUE - Success
FALSE - Failure
--*/
{
ULONG byteIndex;
ULONG tableIndex;
//
// Get the table index from the map table
//
byteIndex = ACPIGpeIndexToByteIndex (GpeIndex);
tableIndex = GpeMap [byteIndex];
//
// Bounds check
//
if (tableIndex >= GpeVectorTableSize) {
return FALSE;
}
//
// Remember that we don't have this GpeVectorObject anymore
//
GpeVectorTable[tableIndex].GpeVectorObject = NULL;
//
// Free the slot in the master vector table
//
ACPIVectorFreeEntry (tableIndex);
return TRUE;
}