1813 lines
41 KiB
C
1813 lines
41 KiB
C
|
/*++
|
|||
|
|
|||
|
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( ¤tExtension->ChildDeviceList ) );
|
|||
|
|
|||
|
//
|
|||
|
// Unlink the dead extension (does nothing if alreeady unlinked)
|
|||
|
//
|
|||
|
RemoveEntryList(¤tExtension->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(¤tExtension->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(¤tExtension->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;
|
|||
|
}
|
|||
|
|