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

1813 lines
41 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:
init.c
Abstract:
This modules contains the init code
Author:
Stephane Plante (splante)
Environment:
NT Kernel Model Driver only
--*/
#include "pch.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,ACPIInitMultiString)
#pragma alloc_text(PAGE,ACPIInitStopDevice)
#pragma alloc_text(PAGE,ACPIInitUnicodeString)
#endif
VOID
ACPIInitDeleteChildDeviceList(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine looks at all of the children of the current devnode and
deletes their device objects, basically resetting them to the unenumerated
state
Arguments:
DeviceExtension - The extension whose children should go away
Return Value:
None
--*/
{
EXTENSIONLIST_ENUMDATA eled;
PDEVICE_EXTENSION childExtension;
//
// Setup the list so that we can walk it
//
ACPIExtListSetupEnum(
&eled,
&(DeviceExtension->ChildDeviceList),
&AcpiDeviceTreeLock,
SiblingDeviceList,
WALKSCHEME_REFERENCE_ENTRIES
);
for (childExtension = ACPIExtListStartEnum( &eled );
ACPIExtListTestElement( &eled, (BOOLEAN) TRUE );
childExtension = ACPIExtListEnumNext( &eled) ) {
//
// Reset the device
//
ACPIInitResetDeviceExtension( childExtension );
}
}
VOID
ACPIInitDeleteDeviceExtension(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine does the cleanup associated with removing a device object
Arguments:
DeviceExtension
ReturnValue:
None
--*/
{
PDEVICE_EXTENSION currentExtension, parentExtension ;
//
// We must be under the tree lock.
//
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL) ; // Close enough...
//
// Nobody should care about this node.
//
ASSERT(!DeviceExtension->ReferenceCount) ;
for(currentExtension = DeviceExtension ;
currentExtension;
currentExtension = parentExtension) {
//
// And there should be no children.
//
ASSERT( IsListEmpty( &currentExtension->ChildDeviceList ) );
//
// Unlink the dead extension (does nothing if alreeady unlinked)
//
RemoveEntryList(&currentExtension->SiblingDeviceList);
//
// We also don't want to be part of anyone's ejection list either
// This also removes the extension from the unresolved list as well
//
RemoveEntryList(&currentExtension->EjectDeviceList);
//
// If this device had any ejection relations, most all of those
// unto the unresolved list
//
if (!IsListEmpty( &(currentExtension->EjectDeviceHead) ) ) {
ACPIInternalMoveList(
&(currentExtension->EjectDeviceHead),
&AcpiUnresolvedEjectList
);
}
//
// At this point, we need to check if the ACPI namespace
// object associated with it is also going away
//
if (currentExtension->Flags & DEV_PROP_UNLOADING) {
//
// Let the world know
//
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
currentExtension,
"- tell Interperter to unload %x\n",
currentExtension->AcpiObject
) );
AMLIDestroyFreedObjs( currentExtension->AcpiObject );
}
//
// Free the common resources
//
if ( (currentExtension->Flags & DEV_PROP_HID) &&
currentExtension->DeviceID != NULL) {
ExFreePool( currentExtension->DeviceID );
}
if ( (currentExtension->Flags & DEV_PROP_UID) &&
currentExtension->InstanceID != NULL) {
ExFreePool( currentExtension->InstanceID );
}
if (currentExtension->ResourceList != NULL) {
ExFreePool( currentExtension->ResourceList );
}
if (currentExtension->PnpResourceList != NULL) {
ExFreePool( currentExtension->PnpResourceList );
}
if (currentExtension->Flags & DEV_PROP_FIXED_CID &&
currentExtension->Processor.CompatibleID != NULL) {
ExFreePool( currentExtension->Processor.CompatibleID );
}
//
// Free any device-specific allocations we might have made
//
if (currentExtension->Flags & DEV_CAP_THERMAL_ZONE &&
currentExtension->Thermal.Info != NULL) {
ExFreePool( currentExtension->Thermal.Info );
}
//
// Remember the parent's device extension
//
parentExtension = currentExtension->ParentExtension;
//
// Free the extension back to the proper place
//
ExFreeToNPagedLookasideList(
&DeviceExtensionLookAsideList,
currentExtension
);
//
// Sanity check
//
if (parentExtension == NULL) {
break;
}
if (InterlockedDecrement(&parentExtension->ReferenceCount)) {
//
// Parent still has a reference count, bail out.
//
break;
}
}
return;
}
NTSTATUS
ACPIInitDosDeviceName(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
If this device has a _DDN method, it is evaluated and the result is
stored within the Device Registry Key
N.B. This routine must be called at Passive level
Arguments:
DeviceExtension - The extension that we wish to find a _DDN for
Return Value:
NTSTATUS
--*/
{
ANSI_STRING ansiString;
HANDLE devHandle;
NTSTATUS status;
OBJDATA objData;
PNSOBJ ddnObject;
PWSTR fixString = L"FirmwareIdentified";
PWSTR pathString = L"DosDeviceName";
ULONG fixValue = 1;
UNICODE_STRING unicodeString;
UNICODE_STRING ddnString;
//
// Initialize the unicode string
//
RtlInitUnicodeString( &unicodeString, fixString);
//
// Open the handle that we need
//
status = IoOpenDeviceRegistryKey(
DeviceExtension->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DEVICE,
STANDARD_RIGHTS_WRITE,
&devHandle
);
if (!NT_SUCCESS(status)) {
//
// Let the world know. But return success anyways
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIInitDosDeviceName - open failed %08lx\n",
status
) );
return STATUS_SUCCESS;
}
//
// Try to set the value
//
status = ZwSetValueKey(
devHandle,
&unicodeString,
0,
REG_DWORD,
&fixValue,
sizeof(fixValue)
);
//
// Initialize the unicode string
//
RtlInitUnicodeString( &unicodeString, pathString);
//
// Lets look for the _DDN
//
ddnObject = ACPIAmliGetNamedChild(
DeviceExtension->AcpiObject,
PACKED_DDN
);
if (ddnObject == NULL) {
ZwClose( devHandle );
return STATUS_SUCCESS;
}
//
// Evaluate the method
//
status = AMLIEvalNameSpaceObject(
ddnObject,
&objData,
0,
NULL
);
if (!NT_SUCCESS(status)) {
//
// Let the world know. But return success anyways
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIInitDosDeviceName - eval returns %08lx\n",
status
) );
ZwClose( devHandle );
return STATUS_SUCCESS;
}
if (objData.dwDataType != OBJTYPE_STRDATA) {
//
// Let the world know. But return success anyways
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIInitDosDeviceName - eval returns wrong type %d\n",
objData.dwDataType
) );
AMLIFreeDataBuffs( &objData, 1 );
ZwClose( devHandle );
return STATUS_SUCCESS;
}
//
// Convert the string to an ansi string
//
RtlInitAnsiString( &ansiString, objData.pbDataBuff );
status = RtlAnsiStringToUnicodeString(
&ddnString,
&ansiString,
TRUE
);
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIInitDosDeviceName - cannot convert to unicode string %x\n",
status
) );
AMLIFreeDataBuffs( &objData, 1 );
ZwClose( devHandle );
return status;
}
//
// Try to set the value
//
status = ZwSetValueKey(
devHandle,
&unicodeString,
0,
REG_SZ,
ddnString.Buffer,
ddnString.Length
);
//
// No longer need the object data and the handle
//
AMLIFreeDataBuffs( &objData, 1 );
ZwClose( devHandle );
//
// What happened
//
if (!NT_SUCCESS(status)) {
//
// Let the world know. But return success anyways
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIInitDosDeviceName - set failed %08lx\n",
status
) );
}
return STATUS_SUCCESS;
}
NTSTATUS
ACPIInitMultiString(
PUNICODE_STRING MultiString,
...
)
/*++
Routine Description:
This routine will take a null terminated list of ascii strings and combine
them together to generate a unicode multi-string block
Arguments:
MultiString - a unicode structure in which a multi-string will be built
... - a null terminated list of narrow strings which will be combined
together. This list must contain at least a trailing NULL
Return Value:
NTSTATUS
--*/
{
ANSI_STRING ansiString;
NTSTATUS status;
PCSTR rawString;
PWSTR unicodeLocation;
ULONG multiLength = 0;
UNICODE_STRING unicodeString;
va_list ap;
PAGED_CODE();
va_start(ap,MultiString);
//
// Make sure that we won't memory leak
//
ASSERT(MultiString->Buffer == NULL);
rawString = va_arg(ap, PCSTR);
while (rawString != NULL) {
RtlInitAnsiString(&ansiString, rawString);
multiLength += RtlAnsiStringToUnicodeSize(&(ansiString));
rawString = va_arg(ap, PCSTR);
} // while
va_end( ap );
if (multiLength == 0) {
//
// Done
//
RtlInitUnicodeString( MultiString, NULL );
return STATUS_SUCCESS;
}
//
// We need an extra null
//
multiLength += sizeof(WCHAR);
MultiString->MaximumLength = (USHORT) multiLength;
MultiString->Buffer = ExAllocatePoolWithTag(
PagedPool,
multiLength,
ACPI_STRING_POOLTAG
);
if (MultiString->Buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(MultiString->Buffer, multiLength);
unicodeString.Buffer = MultiString->Buffer;
unicodeString.MaximumLength = (USHORT) multiLength;
va_start( ap, MultiString);
rawString = va_arg(ap, PCSTR);
while (rawString != NULL) {
RtlInitAnsiString(&ansiString,rawString);
status = RtlAnsiStringToUnicodeString(
&unicodeString,
&ansiString,
FALSE
);
//
// We don't allocate memory, so if something goes wrong here,
// its the function thats at fault
//
ASSERT( NT_SUCCESS(status) );
//
// Move the buffers along
//
unicodeString.Buffer += ( (unicodeString.Length/sizeof(WCHAR)) + 1);
unicodeString.MaximumLength -= (unicodeString.Length + sizeof(WCHAR));
unicodeString.Length = 0;
//
// Next
//
rawString = va_arg(ap, PCSTR);
} // while
va_end(ap);
ASSERT(unicodeString.MaximumLength == sizeof(WCHAR));
//
// Stick the final null there
//
unicodeString.Buffer[0] = L'\0';
MultiString->Length = MultiString->MaximumLength;
return STATUS_SUCCESS;
}
VOID
ACPIInitPowerRequestCompletion(
IN PDEVICE_EXTENSION DeviceExtension,
IN PVOID Context,
IN NTSTATUS Status
)
/*++
Routine Description:
This function is called when the PowerRequest from a StartDevice
or a StopDevice has completed
Arguments:
DeviceExtension - The DeviceExtension of the completed device
Context - KEVENT
Status - The result of the operation
Return Value:
VOID
--*/
{
PKEVENT event = (PKEVENT) Context;
//
// Set the event
//
KeSetEvent( event, IO_NO_INCREMENT, FALSE );
}
VOID
ACPIInitReadRegistryKeys(
)
/*++
Routine Description:
This routine is called by DriverEntry to read all the information
from the registry that is global to the life of the driver
Arguments:
None
Return Value:
None
--*/
{
HANDLE processorKey = NULL;
NTSTATUS status;
PUCHAR identifierString = NULL;
PUCHAR processorString = NULL;
PUCHAR steppingString = NULL;
PUCHAR idString = NULL;
ULONG argSize;
ULONG baseSize;
ULONG identifierStringSize;
ULONG processorStringSize;
//
// Read the Override Attribute from the registry
//
argSize = sizeof(AcpiOverrideAttributes);
status = OSReadRegValue(
"Attributes",
(HANDLE) NULL,
&AcpiOverrideAttributes,
&argSize
);
if (!NT_SUCCESS(status)) {
AcpiOverrideAttributes = 0;
}
//
// Make sure that we initialize the Processor String...
//
RtlZeroMemory( &AcpiProcessorString, sizeof(ANSI_STRING) );
//
// Open the Processor Handle
//
status = OSOpenHandle(
ACPI_PROCESSOR_INFORMATION_KEY,
NULL,
&processorKey
);
if ( !NT_SUCCESS(status) ) {
ACPIPrint ((
ACPI_PRINT_FAILURE,
"ACPIInitReadRegistryKeys: failed to open Processor Key (rc=%x)\n",
status));
return;
}
//
// Default guess as to how many bytes we need for the processor string
//
baseSize = 40;
//
// Try to read the processor ID string
//
do {
//
// If we had allocated memory, then free it
//
if (processorString != NULL) {
ExFreePool( processorString );
}
//
// Allocate the amount of memory we think we need
//
processorString = ExAllocatePoolWithTag(
PagedPool,
baseSize * sizeof(UCHAR),
ACPI_STRING_POOLTAG
);
if (!processorString) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ACPIInitReadRegistryKeysExit;
}
RtlZeroMemory( processorString, baseSize * sizeof(UCHAR) );
//
// Update the amount we think we would need for next time
//
argSize = baseSize * sizeof(UCHAR);
baseSize += 10;
//
// Try to read the key
//
status = OSReadRegValue(
"Identifier",
processorKey,
processorString,
&argSize
);
} while ( status == STATUS_BUFFER_OVERFLOW );
//
// Did we get the identifier?
//
if (!NT_SUCCESS( status )) {
ACPIPrint( (
ACPI_PRINT_FAILURE,
"ACPIInitReadRegistryKeys: failed to read Identifier Value (rc=%x)\n",
status
) );
goto ACPIInitReadRegistryKeysExit;
}
//
// Remove Stepping information from the identifier string.
//
steppingString = strstr(processorString, ACPI_PROCESSOR_STEPPING_IDENTIFIER);
if (steppingString) {
steppingString[-1] = 0;
}
//
// Remember how many bytes are in the processorString
//
processorStringSize = strlen(processorString) + 1;
//
// Reset our guess for how many bytes we will need for the identifier
//
baseSize = 10;
//
// Try to read the vendor processor ID string
//
do {
//
// If we had allocated memory, then free it
//
if (identifierString != NULL) {
ExFreePool( identifierString );
}
//
// Allocate the amount of memory we think we need
//
identifierString = ExAllocatePoolWithTag(
PagedPool,
baseSize * sizeof(UCHAR),
ACPI_STRING_POOLTAG
);
if (!identifierString) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ACPIInitReadRegistryKeysExit;
}
RtlZeroMemory( identifierString, baseSize * sizeof(UCHAR) );
//
// Update the amount we think we would need for next time
//
argSize = baseSize * sizeof(UCHAR);
baseSize += 10;
//
// Try to read the key
//
status = OSReadRegValue(
"VendorIdentifier",
processorKey,
identifierString,
&argSize
);
} while ( status == STATUS_BUFFER_OVERFLOW );
//
// Did we get the identifier?
//
if (!NT_SUCCESS( status )) {
ACPIPrint( (
ACPI_PRINT_FAILURE,
"ACPIInitReadRegistryKeys: failed to read Vendor Value (rc=%x)\n",
status
) );
goto ACPIInitReadRegistryKeysExit;
}
//
// Remember how many bytes are in the processorString
//
identifierStringSize = argSize;
//
// At this point, we can calculate how many bytes we will need for the
// total string. Since the total string is the concatenatation of
// identifierString + " - " + processorString, we just add 2 to the
// sum of the both string sizes (since both sizes include the NULL
// terminator at the end...
//
baseSize = 2 + identifierStringSize + processorStringSize;
//
// Allocate this memory. In the future, we will (probably) need to
// touch this string at DPC level, so it must be fron Non-Paged-Pool
//
idString = ExAllocatePoolWithTag(
NonPagedPool,
baseSize * sizeof(UCHAR),
ACPI_STRING_POOLTAG
);
if (!idString) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ACPIInitReadRegistryKeysExit;
}
//
// Generate the string
//
sprintf( idString, "%s - %s", identifierString, processorString );
//
// Remember the string for the future
//
AcpiProcessorString.Buffer = idString,
AcpiProcessorString.Length = AcpiProcessorString.MaximumLength = (USHORT) baseSize;
//
// Clean up time
//
ACPIInitReadRegistryKeysExit:
if (processorKey) {
OSCloseHandle(processorKey);
}
if (identifierString) {
ExFreePool(identifierString);
}
if (processorString) {
ExFreePool(processorString);
}
}
VOID
ACPIInitRemoveDeviceExtension(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine removes the device extension the ACPI namespace tree add
adds it to the list of surprised removed extensions (which is kept for
debugging purposes only)
This routine is called with the ACPI device tree lock owned
Arguments:
DeviceExtension - the device to remove from the tree
Return Value:
None
--*/
{
PDEVICE_EXTENSION currentExtension, parentExtension;
//
// We must be under the tree lock.
//
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL) ; // Close enough...
//
// Unlink the dead extension (does nothing if alreeady unlinked)
//
RemoveEntryList(&DeviceExtension->SiblingDeviceList);
//
// We also don't want to be part of anyone's ejection list either.
// This removes the device extension from the unresolved list as well...
//
RemoveEntryList(&DeviceExtension->EjectDeviceList);
//
// If this device has ejection relations, then move all of them
// to the unresolved list
//
if (!IsListEmpty( &(DeviceExtension->EjectDeviceHead) ) ) {
ACPIInternalMoveList(
&(DeviceExtension->EjectDeviceHead),
&AcpiUnresolvedEjectList
);
}
//
// We no longer have any parents
//
parentExtension = DeviceExtension->ParentExtension ;
DeviceExtension->ParentExtension = NULL;
//
// Remember that we removed this extension...
//
AcpiSurpriseRemovedDeviceExtensions[AcpiSurpriseRemovedIndex] =
DeviceExtension;
AcpiSurpriseRemovedIndex = (AcpiSurpriseRemovedIndex + 1) %
ACPI_MAX_REMOVED_EXTENSIONS;
//
// Now, we have to look at the parent and decrement its ref count
// as is appropriate --- crawling up the tree and decrementing ref
// counts as we go
//
for(currentExtension = parentExtension;
currentExtension;
currentExtension = parentExtension) {
//
// Decrement the reference on the current extension...
// We have to do this because we previously unlinked one of its
// children
//
if (InterlockedDecrement(&currentExtension->ReferenceCount)) {
//
// Parent still has a reference count, bail out.
//
break;
}
//
// Get the parent
//
parentExtension = currentExtension->ParentExtension ;
//
// Remember that we removed this extension...
//
AcpiSurpriseRemovedDeviceExtensions[AcpiSurpriseRemovedIndex] =
currentExtension;
AcpiSurpriseRemovedIndex = (AcpiSurpriseRemovedIndex + 1) %
ACPI_MAX_REMOVED_EXTENSIONS;
//
// We don't actually expect the device's ref count to drop to
// zero, but if it does, then we must delete the extension
//
ACPIInitDeleteDeviceExtension( currentExtension );
}
}
VOID
ACPIInitResetDeviceExtension(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Clear up a device extension
Arguments:
DeviceExtension - The extension we wish to reset
Return Value:
None
--*/
{
KIRQL oldIrql;
LONG oldReferenceCount;
PCM_RESOURCE_LIST cmResourceList;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_OBJECT targetObject = NULL;
//
// We require the spinlock for parts of this
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Clean up those parts that are associated with us being a filter
//
if (DeviceExtension->Flags & DEV_TYPE_FILTER) {
if (DeviceExtension->Flags & DEV_TYPE_PDO) {
//
// If we are a PDO, then we need to release the reference we took on
// TargetDeviceObject in Buildsrc.c
//
if (DeviceExtension->TargetDeviceObject) {
ObDereferenceObject(DeviceExtension->TargetDeviceObject) ;
}
} else {
//
// If we are a Filter, then we need to remember to detach ourselves
// from the device
//
targetObject = DeviceExtension->TargetDeviceObject;
}
}
//
// Step one is to zero out the things that we no longer care about
//
if (DeviceExtension->PnpResourceList != NULL) {
ExFreePool( DeviceExtension->PnpResourceList );
DeviceExtension->PnpResourceList = NULL;
}
cmResourceList = DeviceExtension->ResourceList;
if (DeviceExtension->ResourceList != NULL) {
DeviceExtension->ResourceList = NULL;
}
deviceObject = DeviceExtension->DeviceObject;
if (deviceObject != NULL) {
deviceObject->DeviceExtension = NULL;
DeviceExtension->DeviceObject = NULL;
//
// The reference count should have value > 0
//
oldReferenceCount = InterlockedDecrement(
&(DeviceExtension->ReferenceCount)
);
ASSERT(oldReferenceCount >= 0) ;
if ( oldReferenceCount == 0) {
//
// Delete the extension
//
ACPIInitDeleteDeviceExtension( DeviceExtension );
goto ACPIInitResetDeviceExtensionExit;
}
}
//
// If we got to this point, we aren't deleting the device extension
//
DeviceExtension->TargetDeviceObject = NULL;
DeviceExtension->PhysicalDeviceObject = NULL;
//
// Mark the node as being fresh and untouched. Only do this if the device
// isn't marked as NEVER_PRESENT. If its never present, we will just trust
// the device to contain the correct information.
//
if (!(DeviceExtension->Flags & DEV_TYPE_NEVER_PRESENT)) {
ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_MASK_TYPE, TRUE );
ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_TYPE_NOT_FOUND, FALSE );
ACPIInternalUpdateFlags( &(DeviceExtension->Flags), DEV_TYPE_REMOVED, FALSE );
}
ACPIInitResetDeviceExtensionExit:
//
// Done with the spinlock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Now we can do the things we need to do at passive level
//
if (cmResourceList != NULL) {
ExFreePool( cmResourceList );
}
if (targetObject != NULL) {
IoDetachDevice( targetObject );
}
if (deviceObject != NULL) {
IoDeleteDevice( deviceObject );
}
}
NTSTATUS
ACPIInitStartACPI(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This function is called as soon as we think that the
START_DEVICE Irp for the ACPI driver FDO is going to
complete successfully
Arguments:
DeviceObject - DeviceObject that is being started
Return Value:
NTSTATUS
--*/
{
KEVENT event;
KIRQL oldIrql;
NTSTATUS status;
OBJDATA objData;
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
PNSOBJ acpiObject = NULL;
PNSOBJ sleepObject = NULL;
PNSOBJ childObject = NULL;
POWER_STATE state;
//
// This will prevent the system from processing power irps
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
AcpiSystemInitialized = FALSE;
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Initialize the event
//
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
//
// Setup the synchronization request
//
status = ACPIBuildSynchronizationRequest(
deviceExtension,
ACPIBuildNotifyEvent,
&event,
&AcpiBuildDeviceList,
FALSE
);
//
// What happened?
//
if (!NT_SUCCESS(status)) {
return status;
}
//
// Start the initilization
//
// NOTE: This routine causes many things to happens. Namely, it starts
// the process of loading ACPI tables. This (eventually) causes the
// Driver to start building device extensions. For this function to
// work properly, after we call this function, we need to wait until
// we have finished building device extensions. That means that we
// must wait for the event to be signaled
//
if (ACPIInitialize( (PVOID) DeviceObject ) == FALSE) {
return STATUS_DEVICE_DOES_NOT_EXIST;
}
//
// At this point, we have to wait. The check for STATUS_PENDING is
// just good programming practice sicne BuildSynchronizationRequest can
// only return Failure or STATUS_PENDING
//
if (status == STATUS_PENDING) {
//
// We had better wait for the above to complete
//
KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE,
NULL
);
}
//
// Hand all the machine state stuff to the HAL
//
NotifyHalWithMachineStates();
//
// Register the Power Callback
//
ACPIInternalRegisterPowerCallBack(
deviceExtension,
(PCALLBACK_FUNCTION) ACPIRootPowerCallBack
);
//
// Cause the Power DPC to be fired for the first time
//
KeAcquireSpinLock( &AcpiPowerQueueLock, &oldIrql );
if (!AcpiPowerDpcRunning) {
KeInsertQueueDpc( &AcpiPowerDpc, NULL, NULL );
}
KeReleaseSpinLock( &AcpiPowerQueueLock, oldIrql );
//
// This will allow the system to get power irps again
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
AcpiSystemInitialized = TRUE;
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Start the IRQ arbiter so that we can handle children's resources.
//
AcpiInitIrqArbiter(DeviceObject);
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ACPIInitStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PCM_RESOURCE_LIST SuppliedList,
IN PACPI_POWER_CALLBACK CallBack,
IN PVOID CallBackContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine is tasked with starting the device by programming in the
supplied resources
Arguments:
DeviceObject - The object that we care about
SuppliedList - The resources associated with the device
CallBack - The function to call when done
Irp - The argument to pass to the callback
Return Value:
NTSTATUS
--*/
{
KIRQL oldIrql;
NTSTATUS status = STATUS_SUCCESS;
OBJDATA crsData;
PCM_RESOURCE_LIST resList;
PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
PNSOBJ acpiObject = deviceExtension->AcpiObject;
PNSOBJ crsObject;
PNSOBJ srsObject;
POBJDATA srsData;
ULONG resSize;
ULONG srsSize;
ULONG deviceStatus;
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
//
// Do we have resources? Or a valid list?
//
if (SuppliedList == NULL || SuppliedList->Count != 1) {
//
// Ignore this resource list
//
goto ACPIInitStartDeviceSendD0;
}
//
// Can we program this device? That is there a _CRS and an _SRS child?
//
crsObject = ACPIAmliGetNamedChild( acpiObject, PACKED_CRS );
srsObject = ACPIAmliGetNamedChild( acpiObject, PACKED_SRS );
if (crsObject == NULL || srsObject == NULL) {
ACPIDevPrint( (
ACPI_PRINT_WARNING,
deviceExtension,
"ACPIInitStartDevice - No SRS or CRS\n"
) );
goto ACPIInitStartDeviceSendD0;
}
//
// Run the _CRS method
//
status = AMLIEvalNameSpaceObject(
crsObject,
&crsData,
0,
NULL
);
if (!NT_SUCCESS(status)) {
//
// Failed
//
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
deviceExtension,
"ACPIInitStartDevice - _CRS failed %08lx\n",
status
) );
goto ACPIInitStartDeviceError;
}
if (crsData.dwDataType != OBJTYPE_BUFFDATA ||
crsData.dwDataLen == 0 ||
crsData.pbDataBuff == NULL) {
//
// Failed
//
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
deviceExtension,
"ACPIInitStartDevice - _CRS return invalid data\n",
crsData.dwDataType
) );
AMLIFreeDataBuffs( &crsData, 1 );
status = STATUS_UNSUCCESSFUL;
goto ACPIInitStartDeviceError;
}
//
// Dump the list
//
#if DBG
if (NT_SUCCESS(status)) {
ACPIDebugCmResourceList( SuppliedList, deviceExtension );
}
#endif
//
// Allocate memory and copy the list...
//
resSize = sizeof(CM_RESOURCE_LIST) +
(SuppliedList->List[0].PartialResourceList.Count - 1) *
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
resList = ExAllocatePoolWithTag(
PagedPool,
resSize,
ACPI_STRING_POOLTAG
);
if (resList == NULL) {
//
// Not enough resources
//
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
deviceExtension,
"ACPIInitStartDevice - Could not allocate %08lx bytes\n",
resSize
) );
AMLIFreeDataBuffs( &crsData, 1 );
status = STATUS_INSUFFICIENT_RESOURCES;
goto ACPIInitStartDeviceError;
}
RtlCopyMemory( resList, SuppliedList, resSize );
//
// Now, make a copy of the crs object, but store it in non paged pool
// because it will be used at DPC level
//
srsSize = sizeof(OBJDATA) + crsData.dwDataLen;
srsData = ExAllocatePoolWithTag(
NonPagedPool,
srsSize,
ACPI_OBJECT_POOLTAG
);
if (srsData == NULL) {
//
// Not enough resources
//
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
deviceExtension,
"ACPIInitStartDevice - Could not allocate %08lx bytes\n",
srsSize
) );
AMLIFreeDataBuffs( &crsData, 1 );
ExFreePool( resList );
status = STATUS_INSUFFICIENT_RESOURCES;
goto ACPIInitStartDeviceError;
}
RtlCopyMemory( srsData, &crsData, sizeof(OBJDATA) );
srsData->pbDataBuff = ( (PUCHAR) srsData ) + sizeof(OBJDATA);
RtlCopyMemory( srsData->pbDataBuff, crsData.pbDataBuff, crsData.dwDataLen );
//
// At this point, we no longer care about the _CRS data
//
AMLIFreeDataBuffs( &crsData, 1 );
//
// Make the new _srs
//
status = PnpCmResourcesToBiosResources( resList, srsData->pbDataBuff );
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
deviceExtension,
"ACPIInitStartDevice - PnpCmResourceToBiosResources = %08lx\n",
status
) );
ExFreePool( resList );
ExFreePool( srsData );
goto ACPIInitStartDeviceError;
}
//
// The call to make the _SRS is destructive --- recopy the original list
//
RtlCopyMemory( resList, SuppliedList, resSize );
//
// We need to hold this lock to set this resource
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
if (deviceExtension->PnpResourceList != NULL) {
ExFreePool( deviceExtension->PnpResourceList );
}
deviceExtension->PnpResourceList = srsData;
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// We keep this around for debug information
//
if (deviceExtension->ResourceList != NULL) {
//
// If we already have a resource list, make sure that we free it
//
ExFreePool( deviceExtension->ResourceList );
}
deviceExtension->ResourceList = resList;
ACPIInitStartDeviceSendD0:
//
// Mark the irp as pending... We need to this because InternalDevice will
// return STATUS_PENDING if it behaves in the correct manner
//
IoMarkIrpPending( Irp );
//
// I don't want to block in this driver if I can help it. Since there
// is already a mechanism for me to execute a D0 and execute a completion
// routine, I will choose to exercise that option
//
status = ACPIDeviceInternalDeviceRequest(
deviceExtension,
PowerDeviceD0,
CallBack,
CallBackContext,
DEVICE_REQUEST_LOCK_DEVICE
);
if (status == STATUS_MORE_PROCESSING_REQUIRED) {
//
// We do this to make sure that we don't also call the completion
// routine
//
status = STATUS_PENDING;
}
//
// Done
//
return status;
//
// This label is the the point where we should jump to if any device
// cannot program its resources, but we are going to return success
//
ACPIInitStartDeviceError:
ASSERT(!NT_SUCCESS(status));
//
// We have a failure here. As the completion routine was *not* called, we
// must do that ourselves.
//
CallBack(
deviceExtension,
CallBackContext,
status
);
//
// Done
//
return status;
}
NTSTATUS
ACPIInitStopACPI(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine stops the ACPI FDO
Arguments:
DeviceObject - The pointer to the ACPI FDO
Return Value:
NTSTATUS
--*/
{
//
// We will *never* stop ACPI
//
return STATUS_SUCCESS;
}
NTSTATUS
ACPIInitStopDevice(
IN PDEVICE_EXTENSION DeviceExtension,
IN BOOLEAN UnlockDevice
)
/*++
Routine Description:
This routine stops a device
Arguments:
DeviceExtension - The extension of the device to stop. An extension
is passed in as the device object may have already
been deleted by the PDO below our device object.
UnlockDevice - True if the device should be unlocked after being
stopped.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PNSOBJ acpiObject = DeviceExtension->AcpiObject;
PNSOBJ workObject;
POWER_STATE state;
ULONG deviceStatus;
PAGED_CODE();
//
// First step is try to turn off the device. We should only do this
// if the device is in an *known* state
//
if (DeviceExtension->PowerInfo.PowerState != PowerDeviceUnspecified) {
KEVENT event;
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
status = ACPIDeviceInternalDeviceRequest(
DeviceExtension,
PowerDeviceD3,
ACPIInitPowerRequestCompletion,
&event,
UnlockDevice ? DEVICE_REQUEST_UNLOCK_DEVICE : 0
);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE,
NULL
);
status = STATUS_SUCCESS;
}
}
//
// Nothing to stop...
//
if (acpiObject == NULL) {
goto ACPIInitStopDeviceExit;
}
//
// Second step is try to disable the device...
//
if ( (workObject = ACPIAmliGetNamedChild( acpiObject, PACKED_DIS ) ) != NULL ) {
//
// There is a method to do this
//
status = AMLIEvalNameSpaceObject( workObject, NULL, 0, NULL );
if (!NT_SUCCESS(status) ) {
goto ACPIInitStopDeviceExit;
}
//
// See if the device is disabled
//
status = ACPIGetDevicePresenceSync(
DeviceExtension,
&deviceStatus,
NULL
);
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
DeviceExtension,
"ACPIInitStopDevice - GetDevicePresenceSync = 0x%08lx\n",
status
) );
goto ACPIInitStopDeviceExit;
}
if (deviceStatus & STA_STATUS_ENABLED) {
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
DeviceExtension,
"ACPIInitStopDevice - STA_STATUS_ENABLED - 0x%08lx\n",
deviceStatus
) );
goto ACPIInitStopDeviceExit;
}
}
ACPIInitStopDeviceExit:
if (DeviceExtension->ResourceList != NULL) {
ExFreePool( DeviceExtension->ResourceList );
DeviceExtension->ResourceList = NULL;
}
return STATUS_SUCCESS;
}
NTSTATUS
ACPIInitUnicodeString(
IN PUNICODE_STRING UnicodeString,
IN PCHAR Buffer
)
/*++
Routine Description:
This routine takes an ASCII string and converts it to a Unicode string. The
Caller is responsible for call RtlFreeUnicodeString() on the returned string
Arguments:
UnicodeString - Where to store the new unicode string
Buffer - What we will convert to unicode
Return Value:
NTSTATUS
--*/
{
ANSI_STRING ansiString;
NTSTATUS status;
ULONG maxLength;
PAGED_CODE();
//
// Make sure that we won't memory leak
//
ASSERT(UnicodeString->Buffer == NULL);
//
// We need to do this first before we run the convertion code. Buidling a
// counted Ansi String is important
//
RtlInitAnsiString(&ansiString, Buffer);
//
// How long is the ansi string
//
maxLength = RtlAnsiStringToUnicodeSize(&(ansiString));
if (maxLength > MAXUSHORT) {
return STATUS_INVALID_PARAMETER_2;
}
UnicodeString->MaximumLength = (USHORT) maxLength;
//
// Allocate a buffer for the string
//
UnicodeString->Buffer = ExAllocatePoolWithTag(
PagedPool,
maxLength,
ACPI_STRING_POOLTAG
);
if (UnicodeString->Buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Convert the counted ANSI string to a counted Unicode string
//
status = RtlAnsiStringToUnicodeString(
UnicodeString,
&ansiString,
FALSE
);
//
// Done
//
return status;
}