windows-nt/Source/XPSP1/NT/base/busdrv/acpi/driver/nt/internal.c
2020-09-26 16:20:57 +08:00

1308 lines
28 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
internal.c
Abstract:
This file contains those functions which didn't easily fit into any
of the other project files. They are typically accessory functions
used to prevent repeatitive and tedious coding.
Author:
Stephane Plante (splante)
Environment:
NT Kernel Model Driver only
--*/
#include "pch.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,ACPIInternalGetDeviceCapabilities)
#pragma alloc_text(PAGE,ACPIInternalIsPci)
#pragma alloc_text(PAGE,ACPIInternalGrowBuffer)
#pragma alloc_text(PAGE,ACPIInternalSendSynchronousIrp)
#endif
//
// For IA32 bit machines, which don't have a 64 bit compare-exchange
// instruction, we need a spinlock so that the OS can simulate it
//
KSPIN_LOCK AcpiUpdateFlagsLock;
//
// We need to have a table of HexDigits so that we can easily generate
// the proper nane for a GPE method
//
UCHAR HexDigit[] = "0123456789ABCDEF";
//
// This is a look-up table. The entry into the table corresponds to the
// first bit set (in an x86-architecture, this is the left most bit set to
// one...
//
UCHAR FirstSetLeftBit[256] = {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
BOOLEAN
ACPIInternalConvertToNumber(
IN UCHAR ValueLow,
IN UCHAR ValueHigh,
IN PULONG Output
)
/*++
Routine Description:
This routine takes the supplied values (in ASCII format) and converts
them into numerical format. The ValueLow is the the low nibble of a uchar,
and the ValueHigh is the high nibble of a uchar. The input ASCII format
is HEX
Arguments:
ValueLow - ASCII Hex representation of low nibble
ValueHigh - ASCII Hex representation of high nibble
Output - Where to write the resulting UCHAR.
Return Value:
BOOLEAN - TRUE if converstion went okay
- FALSE otherwise
--*/
{
UCHAR Number;
UCHAR Scratch;
//
// Calculate the high nibble
//
if ( (ValueHigh < '0') || (ValueHigh > '9') ) {
if ( (ValueHigh < 'A') || (ValueHigh > 'F') ) {
return FALSE;
} else {
Scratch = (ValueHigh - 'A') + 10;
}
} else {
Scratch = (ValueHigh - '0');
}
//
// We now have the high nibble
//
Number = (UCHAR)Scratch;
Number <<=4;
//
// Calculate the low nibble
//
if ( (ValueLow < '0') || (ValueLow > '9') ) {
if ( (ValueLow < 'A') || (ValueLow > 'F') ) {
return FALSE;
} else {
Scratch = (ValueLow - 'A') + 10;
}
} else {
Scratch = (ValueLow - '0' );
}
//
// We now have the low nibble
//
Number |= ((UCHAR)Scratch);
//
// Store the result
//
if ( Output ) {
*Output = Number;
return TRUE;
} else {
return FALSE;
}
}
VOID
ACPIInternalDecrementIrpReferenceCount(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine decrements the number of outstanding request count in the
device extension and does the correct thing when this goes to zero
Arguments:
DeviceExtension - The Extension to decrement the count
Return Value:
NTSTATUS
--*/
{
LONG oldReferenceCount;
//
// Decrement the reference count since we are done processing
// the irp by the time we get back here
//
oldReferenceCount = InterlockedDecrement(
&(DeviceExtension->OutstandingIrpCount)
);
if (oldReferenceCount == 0) {
KeSetEvent( DeviceExtension->RemoveEvent, 0, FALSE );
}
}
NTSTATUS
ACPIInternalGetDeviceCapabilities(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_CAPABILITIES DeviceCapabilities
)
/*++
Routine Description:
This routine sends get the capabilities of the given stack
Arguments:
DeviceObject - The object that we want to know about
DeviceCapabilities - The capabilities of that device
Return Value:
NTSTATUS
--*/
{
IO_STACK_LOCATION irpSp;
NTSTATUS status;
PUCHAR dummy;
PAGED_CODE();
ASSERT( DeviceObject != NULL );
ASSERT( DeviceCapabilities != NULL );
//
// Initialize the stack location that we will use
//
RtlZeroMemory( &irpSp, sizeof(IO_STACK_LOCATION) );
irpSp.MajorFunction = IRP_MJ_PNP;
irpSp.MinorFunction = IRP_MN_QUERY_CAPABILITIES;
irpSp.Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
//
// Initialize the capabilities that we will send down
//
RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
DeviceCapabilities->Version = 1;
DeviceCapabilities->Address = (ULONG) -1;
DeviceCapabilities->UINumber = (ULONG) -1;
//
// Make the call now...
//
status = ACPIInternalSendSynchronousIrp(
DeviceObject,
&irpSp,
(PVOID) &dummy
);
// Done
//
return status;
}
PDEVICE_EXTENSION
ACPIInternalGetDeviceExtension(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
The ACPI Driver can no longer just get the device extension by
Dereferencing DeviceObject->DeviceExtension because it allows a
race condition when dealing with the surprise remove case
This routine is called to turn the Device Object into a Device Extension
Arguments:
DeviceObject - The Device Object
Return Value:
PDEVICE_EXTENSION
--*/
{
KIRQL oldIrql;
PDEVICE_EXTENSION deviceExtension;
//
// Acquire the device tree lock
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Dereference the device extension
//
deviceExtension = DeviceObject->DeviceExtension;
#if 0
//
// Is this a surprise removed device extension?
//
if (deviceExtension != NULL &&
deviceExtension->Flags & DEV_TYPE_SURPRISE_REMOVED) {
//
// Get the "real" extension
//
deviceExtension = deviceExtension->Removed.OriginalAcpiExtension;
}
#endif
//
// Done with the lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Return the device extension
//
return deviceExtension;
}
NTSTATUS
ACPIInternalGetDispatchTable(
IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_EXTENSION *DeviceExtension,
OUT PIRP_DISPATCH_TABLE *DispatchTable
)
/*++
Routine Description:
This routine returns the deviceExtension and dispatch table that is
to be used by the target object
Arguments:
DeviceObject - The Device Object
DeviceExtension - Where to store the deviceExtension
DispatchTable - Where to store the dispatchTable
Return Value:
PDEVICE_EXTENSION
--*/
{
KIRQL oldIrql;
//
// Acquire the device tree lock
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Dereference the device extension
//
*DeviceExtension = DeviceObject->DeviceExtension;
if (DeviceObject->DeviceExtension) {
//
// Dereference the dispatch table
//
*DispatchTable = (*DeviceExtension)->DispatchTable;
} else {
//
// No dispatch table to hand back
//
*DispatchTable = NULL;
}
//
// Done with the lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Return
//
return STATUS_SUCCESS;
}
NTSTATUS
ACPIInternalGrowBuffer(
IN OUT PVOID *Buffer,
IN ULONG OriginalSize,
IN ULONG NewSize
)
/*++
Routine Description:
This function is used to grow a buffer. It allocates memory, zeroes it out,
and copies the original information over.
Note: I suppose it can *shrink* a buffer as well, but I wouldn't bet my life
on it. The caller is responsible for freeing allocated memory
Arguments
Buffer - Points to the Pointer to the Buffer that we want to change
OriginalSize - How big the buffer was originally
NewSize - How big we want to make the buffer
Return Value:
NTSTATUS
--*/
{
PUCHAR temp;
PAGED_CODE();
ASSERT( Buffer != NULL );
temp = ExAllocatePoolWithTag(
PagedPool,
NewSize,
ACPI_RESOURCE_POOLTAG
);
if (temp == NULL) {
if (*Buffer) {
ExFreePool ( *Buffer );
*Buffer = NULL;
}
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory ( temp, NewSize );
if ( *Buffer ) {
RtlCopyMemory ( temp, *Buffer, OriginalSize );
ExFreePool( *Buffer );
}
*Buffer = temp;
return STATUS_SUCCESS;
}
NTSTATUS
ACPIInternalIsPci(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine determines if the specified device object is part of a
PCI stack, either as a PCI device or as a PCI Bus.
This routine will then set the flags that if it is a PCI device, then
it will always be remembered as such
Arguments:
DeviceObject - The device object to check
--*/
{
AMLISUPP_CONTEXT_PASSIVE isPciDeviceContext;
BOOLEAN pciDevice;
KEVENT removeEvent;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
PAGED_CODE();
//
// Is this already a PCI device?
//
if ( (deviceExtension->Flags & DEV_CAP_PCI) ||
(deviceExtension->Flags & DEV_CAP_PCI_DEVICE) ) {
return STATUS_SUCCESS;
}
//
// Is this a PCI bus?
//
if (IsPciBus(deviceExtension->DeviceObject)) {
//
// Remember that we are a PCI bus
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
(DEV_CAP_PCI),
FALSE
);
return STATUS_SUCCESS;
}
//
// Are we a PCI device?
//
isPciDeviceContext.Status = STATUS_NOT_FOUND;
KeInitializeEvent(
&isPciDeviceContext.Event,
SynchronizationEvent,
FALSE
);
status = IsPciDevice(
deviceExtension->AcpiObject,
AmlisuppCompletePassive,
(PVOID) &isPciDeviceContext,
&pciDevice
);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(
&isPciDeviceContext.Event,
Executive,
KernelMode,
FALSE,
NULL
);
status = isPciDeviceContext.Status;
}
if (NT_SUCCESS(status) && pciDevice) {
//
// Remember that we are a PCI device
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
(DEV_CAP_PCI_DEVICE),
FALSE
);
}
return status;
}
BOOLEAN
ACPIInternalIsReportedMissing(
IN PDEVICE_EXTENSION DeviceExtension
)
{
KIRQL oldIrql;
PDEVICE_EXTENSION currentExtension;
BOOLEAN reportedMissing;
//
// Preinit
//
reportedMissing = FALSE;
//
// Acquire the device tree lock
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
currentExtension = DeviceExtension;
do {
if ( currentExtension->Flags & DEV_TYPE_NOT_ENUMERATED ) {
reportedMissing = TRUE;
break;
}
currentExtension = currentExtension->ParentExtension;
} while ( currentExtension );
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
return reportedMissing;
}
VOID
ACPIInternalMoveList(
IN PLIST_ENTRY FromList,
IN PLIST_ENTRY ToList
)
/*++
Routine Description:
This routine moves entire list arounds.
Arguments:
FromList - the List to move items from
ToList - the List to move items to
Return Value:
None
--*/
{
PLIST_ENTRY oldHead;
PLIST_ENTRY oldTail;
PLIST_ENTRY newTail;
//
// We have to check to see if the from list is empty, otherwise, the
// direct pointer hacking will make a mess of things
//
if (!IsListEmpty(FromList)) {
newTail = ToList->Blink;
oldTail = FromList->Blink;
oldHead = FromList->Flink;
//
// Move the pointers around some
//
oldTail->Flink = ToList;
ToList->Blink = oldTail;
oldHead->Blink = newTail;
newTail->Flink = oldHead;
InitializeListHead( FromList );
}
}
VOID
ACPIInternalMovePowerList(
IN PLIST_ENTRY FromList,
IN PLIST_ENTRY ToList
)
/*++
Routine Description:
This routine moves entire list arounds. Since this routine is only
used for Device Power Management, we also take the time to reset the
amount of work done to NULL.
Arguments:
FromList - the List to move items from
ToList - the List to move items to
Return Value:
None
--*/
{
PACPI_POWER_REQUEST powerRequest;
PLIST_ENTRY oldHead = FromList->Flink;
//
// Before we do anything, walk the From and reset the amount of work that
// was done
//
while (oldHead != FromList) {
//
// Obtain the power request that this entry contains
//
powerRequest = CONTAINING_RECORD(
oldHead,
ACPI_POWER_REQUEST,
ListEntry
);
#if DBG
if (oldHead == &AcpiPowerPhase0List ||
oldHead == &AcpiPowerPhase1List ||
oldHead == &AcpiPowerPhase2List ||
oldHead == &AcpiPowerPhase3List ||
oldHead == &AcpiPowerPhase4List ||
oldHead == &AcpiPowerPhase5List ||
oldHead == &AcpiPowerWaitWakeList) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"ACPIInternalMoveList: %08x is linked into %08lx\n",
oldHead,
FromList
) );
DbgBreakPoint();
}
#endif
//
// Grab the next entry
//
oldHead = oldHead->Flink;
//
// Reset the amount of work done. Note: This could be a CompareExchange
// with the Comparand being WORK_DONE_COMPLETED
//
InterlockedExchange(
&(powerRequest->WorkDone),
WORK_DONE_STEP_0
);
}
//
// Actually Move the list here...
//
ACPIInternalMoveList( FromList, ToList );
}
NTSTATUS
ACPIInternalRegisterPowerCallBack(
IN PDEVICE_EXTENSION DeviceExtension,
IN PCALLBACK_FUNCTION CallBackFunction
)
/*++
Routine Description:
This routine is called to register a Power Call on the appropriate
device extension.
Arguments:
DeviceExtension - This will be the context field of the CallBackFunction
CallBackFunction - The function to invoke
Return Value:
NSTATUS
--*/
{
NTSTATUS status;
OBJECT_ATTRIBUTES objAttributes;
PCALLBACK_OBJECT callBack;
PVOID callBackRegistration;
UNICODE_STRING callBackName;
//
// if there is already a callback present, this is a nop
//
if (DeviceExtension->Flags & DEV_PROP_CALLBACK) {
return STATUS_SUCCESS;
}
//
// Remember that we have a callback
//
ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_PROP_CALLBACK,
FALSE
);
//
// Register a callback that tells us when the user changes the
// system power policy
//
RtlInitUnicodeString( &callBackName, L"\\Callback\\PowerState" );
InitializeObjectAttributes(
&objAttributes,
&callBackName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
NULL
);
status = ExCreateCallback(
&callBack,
&objAttributes,
FALSE,
TRUE
);
if (NT_SUCCESS(status)) {
ExRegisterCallback(
callBack,
CallBackFunction,
DeviceExtension
);
}
if (!NT_SUCCESS(status)) {
//
// Ignored failed registrations
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIInternalRegisterPowerCallBack: Failed to register callback %x",
status
) );
status = STATUS_SUCCESS;
//
// Remember that we don't have a callback
//
ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_PROP_CALLBACK,
TRUE
);
}
return status;
}
NTSTATUS
ACPIInternalSendSynchronousIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION TopStackLocation,
OUT PVOID *Information
)
/*++
Routine Description:
Builds a PNP Irp and sends it down to DeviceObject
Arguments:
DeviceObject - Target DeviceObject
TopStackLocation - Specifies the Parameters for the Irp
Information - The returned IoStatus.Information field
Return Value:
NTSTATUS
--*/
{
IO_STATUS_BLOCK ioStatus;
KEVENT pnpEvent;
NTSTATUS status;
PDEVICE_OBJECT targetObject;
PIO_STACK_LOCATION irpStack;
PIRP pnpIrp;
PAGED_CODE();
//
// Initialize the event
//
KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE );
//
// Get the irp that we will send the request to
//
targetObject = IoGetAttachedDeviceReference( DeviceObject );
//
// Build an IRP
//
pnpIrp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP,
targetObject,
NULL, // I don't need a buffer
0, // Size is empty
NULL, // Don't have to worry about the starting location
&pnpEvent,
&ioStatus
);
if (pnpIrp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ACPIInternalSendSynchronousIrpExit;
}
//
// PNP Irps all begin life as STATUS_NOT_SUPPORTED.
//
pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
pnpIrp->IoStatus.Information = 0;
//
// Get the top of stack ...
//
irpStack = IoGetNextIrpStackLocation ( pnpIrp );
if (irpStack == NULL) {
status = STATUS_INVALID_PARAMETER;
goto ACPIInternalSendSynchronousIrpExit;
}
//
// Set the top of stack
//
*irpStack = *TopStackLocation;
//
// Make sure that there are no completion routine set
//
IoSetCompletionRoutine(
pnpIrp,
NULL,
NULL,
FALSE,
FALSE,
FALSE
);
//
// Call the driver
//
status = IoCallDriver( targetObject, pnpIrp );
if (status == STATUS_PENDING) {
//
// If the status is STATUS_PENDING, than we must block until the irp completes
// and pull the true status out
//
KeWaitForSingleObject(
&pnpEvent,
Executive,
KernelMode,
FALSE,
NULL);
status = ioStatus.Status;
}
//
// Tell the user how much information was passed (if necessary)
//
if (NT_SUCCESS(status) && (Information != NULL)) {
*Information = (PVOID)ioStatus.Information;
}
ACPIInternalSendSynchronousIrpExit:
ACPIPrint( (
ACPI_PRINT_IRP,
"ACPIInternalSendSynchronousIrp: %#08lx Status = %#08lx\n",
DeviceObject, status
) );
//
// Done with reference
//
ObDereferenceObject( targetObject );
return status;
}
NTSTATUS
ACPIInternalSetDeviceInterface (
IN PDEVICE_OBJECT DeviceObject,
IN LPGUID InterfaceGuid
)
/*++
Routine Description:
This routine does all the grunt work for registering an interface and
enabling it
Arguments:
DeviceObject - The device we wish to register the interface on
InterfaceGuid - The interface we wish to register
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
UNICODE_STRING symbolicLinkName;
//
// Register the interface
//
status = IoRegisterDeviceInterface(
DeviceObject,
InterfaceGuid,
NULL,
&symbolicLinkName
);
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
deviceExtension,
"ACPIInternalSetDeviceInterface: IoRegisterDeviceInterface = %08lx",
status
) );
return status;
}
//
// Turn on the interface
//
status = IoSetDeviceInterfaceState(&symbolicLinkName, TRUE);
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
deviceExtension,
"ACPIInternalSetDeviceInterface: IoSetDeviceInterfaceState = %08lx",
status
) );
goto ACPIInternalSetDeviceInterfaceExit;
}
ACPIInternalSetDeviceInterfaceExit:
//
// Done
//
return status;
}
VOID
ACPIInternalUpdateDeviceStatus(
IN PDEVICE_EXTENSION DeviceExtension,
IN ULONG DeviceStatus
)
/*++
Routine Description:
This routine is called to update the status of the DeviceExtension based
upon the result of the _STA, which are passed as DeviceStatus
Arguments:
DeviceExtension - The extension whose status is to be updated
DeviceState - The status of the device
Return Value:
VOID
--*/
{
KIRQL oldIrql;
ULONGLONG originalFlags;
PDEVICE_EXTENSION parentExtension = NULL;
BOOLEAN bPreviouslyPresent;
//
// Is the device working okay?
//
originalFlags = ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_PROP_DEVICE_FAILED,
(BOOLEAN) (DeviceStatus & STA_STATUS_WORKING_OK)
);
//
// Is the device meant to be shown in the UI?
//
originalFlags = ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_CAP_NO_SHOW_IN_UI,
(BOOLEAN) (DeviceStatus & STA_STATUS_USER_INTERFACE)
);
//
// Is the device decoding its resources?
//
originalFlags = ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_PROP_DEVICE_ENABLED,
(BOOLEAN) !(DeviceStatus & STA_STATUS_ENABLED)
);
//
// Update the extensions flags bassed on wether or not STA_STATUS_PRESENT is
// set
//
originalFlags = ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_TYPE_NOT_PRESENT,
(BOOLEAN) (DeviceStatus & STA_STATUS_PRESENT)
);
//
// If the original flags do not contain the set value, but we are setting
// the flags, then we must call IoInvalidDeviceRelations on the parent
//
if (!(originalFlags & DEV_TYPE_NOT_PRESENT) &&
!(DeviceStatus & STA_STATUS_PRESENT)) {
//
// Need the device tree lock
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
parentExtension = DeviceExtension->ParentExtension;
while (parentExtension && (parentExtension->Flags & DEV_TYPE_NOT_FOUND)) {
parentExtension = parentExtension->ParentExtension;
}
IoInvalidateDeviceRelations(
parentExtension->PhysicalDeviceObject,
BusRelations
);
//
// Done with the lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
}
}
ULONGLONG
ACPIInternalUpdateFlags(
IN PULONGLONG FlagLocation,
IN ULONGLONG NewFlags,
IN BOOLEAN Clear
)
/*++
Routine Description:
This routine updates flags in the specified location
Arguments:
FlagLocation - Where the flags are located
NewFlags - The bits that should be set or cleared
Clear - Wether the bits should be set or cleared
Return Value:
Original Flags
--*/
{
ULONGLONG originalFlags;
ULONGLONG tempFlags;
ULONGLONG flags;
ULONG uFlags;
ULONG uTempFlags;
ULONG uOriginalFlags;
#if 0
if (Clear) {
//
// Clear the bits
//
originalFlags = *FlagLocation;
do {
tempFlags = originalFlags;
flags = tempFlags & ~NewFlags;
//
// Calculate the low part
//
uFlags = (ULONG) flags;
uTempFlags = (ULONG) tempFlags;
originalFlags = InterlockedCompareExchange(
(PULONG) FlagLocation,
uFlags,
uTempFlags
);
//
// Calculate the high part
//
uFlags = (ULONG) (flags >> 32);
uTempFlags = (ULONG) (tempFlags >> 32);
uOriginalFlags = InterlockedCompareExchange(
(PULONG) FlagLocation+1,
uFlags,
uTempFlags
);
//
// Rebuild the original flags
//
originalFlags |= (uOriginalFlags << 32);
tempFlags |= (uTempFlags << 32);
} while ( tempFlags != originalFlags );
} else {
//
// Set the bits
//
originalFlags = *FlagLocation;
do {
tempFlags = originalFlags;
flags = tempFlags | NewFlags;
//
// Calculate the low part
//
uFlags = (ULONG) flags;
uTempFlags = (ULONG) tempFlags;
originalFlags = InterlockedCompareExchange(
(PULONG) FlagLocation,
uFlags,
uTempFlags
);
//
// Calculate the high part
//
uFlags = (ULONG) (flags >> 32);
uTempFlags = (ULONG) (tempFlags >> 32);
uOriginalFlags = InterlockedCompareExchange(
(PULONG) FlagLocation+1,
uFlags,
uTempFlags
);
//
// Rebuild the original flags
//
originalFlags |= (uOriginalFlags << 32);
tempFlags |= (uTempFlags << 32);
} while ( tempFlags != originalFlags );
}
#else
if (Clear) {
//
// Clear the bits
//
originalFlags = *FlagLocation;
do {
tempFlags = originalFlags;
flags = tempFlags & ~NewFlags;
//
// Exchange the bits
//
originalFlags = ExInterlockedCompareExchange64(
(PLONGLONG) FlagLocation,
(PLONGLONG) &flags,
(PLONGLONG) &tempFlags,
&AcpiUpdateFlagsLock
);
} while ( tempFlags != originalFlags );
} else {
//
// Set the bits
//
originalFlags = *FlagLocation;
do {
tempFlags = originalFlags;
flags = tempFlags | NewFlags;
//
// Exchange teh bits
//
originalFlags = ExInterlockedCompareExchange64(
(PLONGLONG) FlagLocation,
(PLONGLONG) &flags,
(PLONGLONG) &tempFlags,
&AcpiUpdateFlagsLock
);
} while ( tempFlags != originalFlags );
}
#endif
//
// return the original flags
//
return originalFlags;
}