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

2507 lines
65 KiB
C
Raw 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) 1997 Microsoft Corporation
Module Name:
detect.c
Abstract:
This module contains the detector for the NT driver.
Author:
Stephane Plante (splante)
Environment:
NT Kernel Model Driver only
Revision History:
July 7, 1997 - Complete rewrite
--*/
#include "pch.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, ACPIDetectCouldExtensionBeInRelation)
#pragma alloc_text(PAGE, ACPIDetectFilterMatch)
#pragma alloc_text(PAGE, ACPIDetectPdoMatch)
#endif
//
// This is the root device extension
//
PDEVICE_EXTENSION RootDeviceExtension;
//
// This is the pool that controls the allocations for Device Extensions
//
NPAGED_LOOKASIDE_LIST DeviceExtensionLookAsideList;
//
// This is the list entry for all the surprise removed extensions
//
PDEVICE_EXTENSION AcpiSurpriseRemovedDeviceExtensions[ACPI_MAX_REMOVED_EXTENSIONS];
//
// This is the index into the Surprise Removed Index array
//
ULONG AcpiSurpriseRemovedIndex;
//
// This is the lock that is required when modifying the links between
// the device extension structures
//
KSPIN_LOCK AcpiDeviceTreeLock;
//
// This is the ulong that will remember which S states are supported by the
// system. The convention for using this ulong is that we 1 << SupportedState
// into it
//
ULONG AcpiSupportedSystemStates;
//
// This is where acpi will store the various overrides
//
ULONG AcpiOverrideAttributes;
//
// This is where acpi will store its registry path
//
UNICODE_STRING AcpiRegistryPath;
//
// This is the processor revision string...
//
ANSI_STRING AcpiProcessorString;
NTSTATUS
ACPIDetectCouldExtensionBeInRelation(
IN PDEVICE_EXTENSION DeviceExtension,
IN PDEVICE_RELATIONS DeviceRelations,
IN BOOLEAN RequireADR,
IN BOOLEAN RequireHID,
OUT PDEVICE_OBJECT *PdoObject
)
/*++
Routine Description:
This routine takes a given extension and a set of relations and decides
whether a the given extension *could* be represented in the relation
list. This is done by seeing if any of the passed in relations match
the hardware described by the extension. If the extension's object is
already a member of the list, the corrosponding Pdo will be written
into the PdoObject parameter. If success is returned without a PdoObject,
a filter or Pdo should probably be created (note that this routine does
not check to see if the devices are present).
Arguments:
DeviceExtension - Extension we wish to match in the relation
DeviceRelations - Relations we should examine
RequireADR - If set, nodes must have _ADR's
RequireHID - If set, nodes must have _HID's
PdoObject - Where to store the match if found
Return Value:
NTSTATUS - STATUS_SUCCESS if extension might be or is in list.
PdoObject - Non-Null means that this PDO corrosponds to the passed in
extension.
--*/
{
BOOLEAN match = FALSE;
BOOLEAN testADR = FALSE;
BOOLEAN testHID = FALSE;
NTSTATUS status;
UNICODE_STRING acpiUnicodeID;
ULONG address;
ULONG i;
PAGED_CODE();
ASSERT( PdoObject != NULL);
if (PdoObject == NULL) {
return STATUS_INVALID_PARAMETER_1;
}
*PdoObject = NULL;
//
// Make sure to initialize the UNICODE_STRING
//
RtlZeroMemory( &acpiUnicodeID, sizeof(UNICODE_STRING) );
//
// Check to see if there is an _ADR present
//
if (RequireADR) {
//
// Filters must have _ADR's
//
if ( !(DeviceExtension->Flags & DEV_PROP_ADDRESS) ) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
}
//
// Check to see if there is an _HID present
//
if (RequireHID) {
//
// Non-Filters require _HID's
//
if (DeviceExtension->DeviceID == NULL ||
!(DeviceExtension->Flags & DEV_PROP_HID) ) {
return STATUS_OBJECT_NAME_NOT_FOUND;
}
}
//
// Check to see if the relation is non-empty. If it isn't, there isn't
// any work to do. This device obviously could be a Pdo child (as opposed
// to a filter) but it sure isn't at the moment.
//
if (DeviceRelations == NULL || DeviceRelations->Count == 0) {
//
// No match
//
return STATUS_SUCCESS;
}
//
// If we get to this point, and there is an _ADR present, we will test with
// it. We also obtain the address at this time
//
if ( (DeviceExtension->Flags & DEV_MASK_ADDRESS) ) {
testADR = TRUE;
status = ACPIGetAddressSync(
DeviceExtension,
&address,
NULL
);
}
//
// If we get to this point, and there is an _HID present, then we will
// test with it. We will build the unicode address at this time
//
if ( (DeviceExtension->Flags & DEV_MASK_HID) ) {
status = ACPIGetPnpIDSyncWide(
DeviceExtension,
&(acpiUnicodeID.Buffer),
&(acpiUnicodeID.Length)
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Make sure that we have the maximum length of the string
//
acpiUnicodeID.MaximumLength = acpiUnicodeID.Length;
//
// Remember to test fora _HID
//
testHID = TRUE;
}
//
// Loop for all the object in the extension
//
for (i = 0; i < DeviceRelations->Count; i++) {
//
// Assume we don't have a match
//
match = FALSE;
//
// Check to see if we match the address
//
if (testHID) {
status = ACPIMatchHardwareId(
DeviceRelations->Objects[i],
&acpiUnicodeID,
&match
);
if (!NT_SUCCESS(status)) {
//
// If we failed, then I guess we can just ignore it and
// proceed
//
continue;
}
}
//
// Did we match?
//
// NB: the test for AddrObject is a hack specially reserved for
// PCI. The issue is this. Some buses, have no concept of PnP ids
// so the above test will never succeed. However, those buses are
// expected to have ADR, so we can use ADR's to determine if we
// we have a match. So if we don't have a match and we don't have
// an ADR, then we just continue. But if we have ADR and don't have
// a match, we might just have a match, so we will try again
//
if (match == FALSE && testADR == FALSE) {
//
// Then just continue
//
continue;
}
//
// If there is an ADR, then we must check for that as well
//
if (testADR) {
match = FALSE;
status = ACPIMatchHardwareAddress(
DeviceRelations->Objects[i],
address,
&match
);
if (!NT_SUCCESS(status)) {
//
// If we failed, then I guess we
continue;
}
//
// Did we match?
//
if (match == FALSE) {
//
// Then just continue
//
continue;
}
} // if (addrObject ... )
//
// At this point, there is no doubt, there is a match
//
*PdoObject = DeviceRelations->Objects[i];
break ;
} // for
//
// We have exhausted all options --- thus there is no match
//
return STATUS_SUCCESS ;
}
NTSTATUS
ACPIDetectDockDevices(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PDEVICE_RELATIONS *DeviceRelations
)
/*++
Routine Description
Arguments:
deviceExtension - The device extension of the object whose
relations we care to know about
DeviceRelations - Pointer to Pointer to the array of device
relations
Return Value:
NTSTATUS
--*/
{
BOOLEAN matchFound;
EXTENSIONLIST_ENUMDATA eled ;
LONG oldReferenceCount;
KIRQL oldIrql;
PDEVICE_OBJECT tempPdo ;
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION providerExtension = NULL;
PDEVICE_EXTENSION targetExtension = NULL;
PDEVICE_RELATIONS currentRelations = NULL;
PDEVICE_RELATIONS newRelations = NULL;
PLIST_ENTRY listEntry = NULL;
ULONG i = 0;
ULONG j = 0;
ULONG index = 0;
ULONG newRelationSize = 0;
ULONG deviceStatus;
//
// Determine the current size of the device relation (if any exists)
//
if (DeviceRelations != NULL && *DeviceRelations != NULL) {
//
// We need this value to help us build an MDL. After that is done,
// we will refetch it
//
currentRelations = (*DeviceRelations);
newRelationSize = currentRelations->Count;
}
ACPIExtListSetupEnum(
&eled,
&(DeviceExtension->ChildDeviceList),
&AcpiDeviceTreeLock,
SiblingDeviceList,
WALKSCHEME_REFERENCE_ENTRIES
) ;
for(providerExtension = ACPIExtListStartEnum(&eled);
ACPIExtListTestElement(&eled, (BOOLEAN) NT_SUCCESS(status));
providerExtension = ACPIExtListEnumNext(&eled)) {
if (providerExtension == NULL) {
ACPIExtListExitEnumEarly( &eled );
break;
}
//
// Only profile providers for this walk...
//
if (!(providerExtension->Flags & DEV_PROP_DOCK)) {
continue;
}
//
// Is it physically present?
//
status = ACPIGetDevicePresenceSync(
providerExtension,
(PVOID *) &deviceStatus,
NULL
);
if (!(providerExtension->Flags & DEV_MASK_NOT_PRESENT)) {
//
// This profile provider should be in the list
//
if (providerExtension->DeviceObject == NULL) {
//
// Build it
//
status = ACPIBuildPdo(
DeviceExtension->DeviceObject->DriverObject,
providerExtension,
DeviceExtension->DeviceObject,
FALSE
);
if (!NT_SUCCESS(status)) {
ASSERT(providerExtension->DeviceObject == NULL) ;
}
}
if (providerExtension->DeviceObject != NULL) {
if (!ACPIExtListIsMemberOfRelation(
providerExtension->DeviceObject,
currentRelations
)) {
newRelationSize++;
}
}
} // if (providerExtension ... )
}
if (!NT_SUCCESS(status)) {
//
// Hmm... Let the world know that this happened
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
providerExtension,
"ACPIDetectDockDevices: ACPIBuildPdo = %08lx\n",
status
) );
return status;
}
//
// At this point, we can see if we need to change the size of the
// device relations
//
if ( (currentRelations != NULL && newRelationSize == currentRelations->Count) ||
(currentRelations == NULL && newRelationSize == 0) ) {
//
// Done
//
return STATUS_SUCCESS;
}
//
// Determine the size of the new relations. Use index as a
// scratch buffer
//
index = sizeof(DEVICE_RELATIONS) +
( sizeof(PDEVICE_OBJECT) * (newRelationSize - 1) );
//
// Allocate the new device relation buffer. Use nonpaged pool since we
// are at dispatch
//
newRelations = ExAllocatePoolWithTag(
NonPagedPool,
index,
ACPI_DEVICE_POOLTAG
);
if (newRelations == NULL) {
//
// Return failure
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize DeviceRelations data structure
//
RtlZeroMemory( newRelations, index );
//
// If there are existing relations, we must determine
if (currentRelations) {
//
// Copy old relations, and determine the starting index for the
// first of the PDOs created by this driver. We will put off freeing
// the old relations till we are no longer holding the lock
//
RtlCopyMemory(
newRelations->Objects,
currentRelations->Objects,
currentRelations->Count * sizeof(PDEVICE_OBJECT)
);
index = currentRelations->Count;
j = currentRelations->Count;
} else {
//
// There will not be a lot of work to do in this case
//
index = j = 0;
}
ACPIExtListSetupEnum(
&eled,
&(DeviceExtension->ChildDeviceList),
&AcpiDeviceTreeLock,
SiblingDeviceList,
WALKSCHEME_HOLD_SPINLOCK
) ;
//
// We need the spin lock so that we can walk the tree again. This time
// we don't need to let it go until we are done since we don't need
// to call anything that will at PASSIVE_LEVEL
//
for(providerExtension = ACPIExtListStartEnum(&eled);
ACPIExtListTestElement(&eled, (BOOLEAN) (newRelationSize!=index));
providerExtension = ACPIExtListEnumNext(&eled)) {
//
// The only objects that we care about are those that are marked as
// PDOs and have a physical object associated with them
//
if (!(providerExtension->Flags & DEV_MASK_NOT_PRESENT) &&
(providerExtension->Flags & DEV_PROP_DOCK) &&
providerExtension->DeviceObject != NULL ) {
//
// We don't ObReferenceO here because we are still at
// dispatch level (and for efficiency's sake, we don't
// want to drop down)
//
newRelations->Objects[index] =
providerExtension->PhysicalDeviceObject;
//
// Update the location for the next object in the
// relation
//
index++ ;
} // if (providerExtension->Flags ... )
} // for
//
// Update the size of the relations by the number of matches that we
// successfully made
//
newRelations->Count = index;
newRelationSize = index;
//
// We have to reference all of the objects that we added
//
index = (currentRelations != NULL ? currentRelations->Count : 0);
for (; index < newRelationSize; index++) {
//
// Attempt to reference the object
//
status = ObReferenceObjectByPointer(
newRelations->Objects[index],
0,
NULL,
KernelMode
);
if (!NT_SUCCESS(status) ) {
PDEVICE_OBJECT tempDeviceObject;
//
// Hmm... Let the world know that this happened
//
ACPIPrint( (
ACPI_PRINT_FAILURE,
"ACPIDetectDockDevices: ObjReferenceObject(0x%08lx) "
"= 0x%08lx\n",
newRelations->Objects[index],
status
) );
//
// Swap the bad element for the last one in the chain
//
newRelations->Count--;
tempDeviceObject = newRelations->Objects[newRelations->Count];
newRelations->Objects[newRelations->Count] =
newRelations->Objects[index];
newRelations->Objects[index] = tempDeviceObject;
}
}
//
// Free the old device relations (if it is present)
//
if (currentRelations) {
ExFreePool( *DeviceRelations );
}
//
// Update the device relation pointer
//
*DeviceRelations = newRelations;
//
// Done
//
return STATUS_SUCCESS;
}
VOID
ACPIDetectDuplicateADR(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine looks at all the sibling devices of the specified
device and determines if there are devices with duplicate _ADRs
Arguments:
DeviceExtension - The DeviceExtension that we are trying to detect
duplicate's on
Return Value:
VOID
--*/
{
BOOLEAN resetDeviceAddress = FALSE;
EXTENSIONLIST_ENUMDATA eled;
PDEVICE_EXTENSION childExtension;
PDEVICE_EXTENSION parentExtension = DeviceExtension->ParentExtension;
//
// Is this the root of the device tree?
//
if (parentExtension == NULL) {
return;
}
//
// Do we fail to eject a PDO for this device? Or does this device not have
// an _ADR?
//
if ( (DeviceExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
(DeviceExtension->Flags & DEV_TYPE_NOT_PRESENT) ||
!(DeviceExtension->Flags & DEV_MASK_ADDRESS) ) {
return;
}
//
// Walk the children --- spinlock is taken
//
ACPIExtListSetupEnum(
&eled,
&(parentExtension->ChildDeviceList),
&AcpiDeviceTreeLock,
SiblingDeviceList,
WALKSCHEME_HOLD_SPINLOCK
);
for (childExtension = ACPIExtListStartEnum( &eled );
ACPIExtListTestElement( &eled, TRUE );
childExtension = ACPIExtListEnumNext( &eled ) ) {
if (childExtension == NULL) {
ACPIExtListExitEnumEarly( &eled );
break;
}
//
// If the child and target extension matches, then we are looking
// at ourselves. This is not a very interesting comparison
//
if (childExtension == DeviceExtension) {
continue;
}
//
// Does the child have an _ADR? If not, then its boring to compare
//
if ( (childExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
(childExtension->Flags & DEV_MASK_NOT_PRESENT) ||
(childExtension->Flags & DEV_PROP_UNLOADING) ||
!(childExtension->Flags & DEV_PROP_ADDRESS) ) {
continue;
}
//
// If we don't have matching ADRs, this is a boring comparison to make
// also
//
if (childExtension->Address != DeviceExtension->Address) {
continue;
}
//
// At this point, we are hosed. We have two different devices with the
// same ADR. Very Bad. We need to remember that we have a match so that
// we can reset the current device extension address as well, once
// we have scanned all the siblings
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIDetectDuplicateADR - matches with %08lx\n",
childExtension
) );
resetDeviceAddress = TRUE;
//
// Reset the child's Address. We do this by OR'ing in 0xFFFF which
// effectively resets the Function Number to -1.
//
childExtension->Address |= 0xFFFF;
ACPIInternalUpdateFlags(
&(childExtension->Flags),
DEV_PROP_FIXED_ADDRESS,
FALSE
);
}
//
// Do we reset the DeviceExtension's address?
//
if (resetDeviceAddress) {
DeviceExtension->Address |= 0xFFFF;
ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_PROP_FIXED_ADDRESS,
FALSE
);
}
}
VOID
ACPIDetectDuplicateHID(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine looks at all the sibling devices of the specified
device and determines if there are devices with duplicate HIDs and
UIDs
Arguments:
DeviceExtension - The DeviceExtension that we are trying to detect
duplicate's on
Return Value:
VOID -or- Bugcheck
--*/
{
EXTENSIONLIST_ENUMDATA eled;
PDEVICE_EXTENSION childExtension;
PDEVICE_EXTENSION parentExtension = DeviceExtension->ParentExtension;
//
// Is this the root of the device tree?
//
if (parentExtension == NULL) {
return;
}
//
// Do we fail to eject a PDO for this device? Or does this device not have
// an _HID?
//
if ( (DeviceExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
(DeviceExtension->Flags & DEV_MASK_NOT_PRESENT) ||
!(DeviceExtension->Flags & DEV_MASK_HID) ) {
return;
}
//
// Walk the children --- spinlock is taken
//
ACPIExtListSetupEnum(
&eled,
&(parentExtension->ChildDeviceList),
&AcpiDeviceTreeLock,
SiblingDeviceList,
WALKSCHEME_HOLD_SPINLOCK
);
for (childExtension = ACPIExtListStartEnum( &eled );
ACPIExtListTestElement( &eled, TRUE );
childExtension = ACPIExtListEnumNext( &eled ) ) {
if (childExtension == NULL) {
ACPIExtListExitEnumEarly( &eled );
break;
}
//
// If the child and target extension matches, then we are looking
// at ourselves. This is not a very interesting comparison
//
if (childExtension == DeviceExtension) {
continue;
}
//
// Does the child have an _HID? If not, then its boring to compare
//
if ( (childExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
(childExtension->Flags & DEV_MASK_NOT_PRESENT) ||
(childExtension->Flags & DEV_PROP_UNLOADING) ||
!(childExtension->Flags & DEV_MASK_HID) ) {
continue;
}
//
// If we don't have matching HIDs, this is a boring comparison to make
// also
//
if (!strstr(childExtension->DeviceID, DeviceExtension->DeviceID) ) {
continue;
}
//
// Work around OSCeola bugs
//
if ( (childExtension->Flags & DEV_MASK_UID) &&
(DeviceExtension->Flags & DEV_MASK_UID) ) {
//
// Check to see if their UIDs match
//
if (strcmp(childExtension->InstanceID, DeviceExtension->InstanceID) ) {
continue;
}
//
// At this point, we are hosed. We have two different devices with the
// same PNP id, but no UIDs. Very bad
//
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
DeviceExtension,
"ACPIDetectDuplicateHID - has _UID match with %08lx\n"
"\t\tContact the Machine Vendor to get this problem fixed\n",
childExtension
) );
KeBugCheckEx(
ACPI_BIOS_ERROR,
ACPI_REQUIRED_METHOD_NOT_PRESENT,
(ULONG_PTR) DeviceExtension,
PACKED_UID,
1
);
}
//
// At this point, we are hosed. We have two different devices with the
// same PNP id, but no UIDs. Very bad
//
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
DeviceExtension,
"ACPIDetectDuplicateHID - matches with %08lx\n",
childExtension
) );
KeBugCheckEx(
ACPI_BIOS_ERROR,
ACPI_REQUIRED_METHOD_NOT_PRESENT,
(ULONG_PTR) DeviceExtension,
PACKED_UID,
0
);
//
// Make sure to only muck with the DeviceExtension UID if it doesn't
// already have one
//
if (!(DeviceExtension->Flags & DEV_MASK_UID) ) {
//
// Build a fake instance ID for the device
//
DeviceExtension->InstanceID = ExAllocatePoolWithTag(
NonPagedPool,
9 * sizeof(UCHAR),
ACPI_STRING_POOLTAG
);
if (DeviceExtension->InstanceID == NULL) {
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
DeviceExtension,
"ACPIDetectDuplicateHID - no memory!\n"
) );
ACPIInternalError( ACPI_DETECT );
}
RtlZeroMemory( DeviceExtension->InstanceID, 9 * sizeof(UCHAR) );
sprintf( DeviceExtension->InstanceID, "%lx", DeviceExtension->AcpiObject->dwNameSeg );
//
// Remember that we have a fixed uid
//
ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_PROP_FIXED_UID,
FALSE
);
}
//
// Make sure to only muck with the ChildExtension UID if it doesn't
// already have one
//
if (!(childExtension->Flags & DEV_MASK_UID) ) {
//
// Build a fake instance ID for the duplicate
//
childExtension->InstanceID = ExAllocatePoolWithTag(
NonPagedPool,
9 * sizeof(UCHAR),
ACPI_STRING_POOLTAG
);
if (childExtension->InstanceID == NULL) {
ACPIDevPrint( (
ACPI_PRINT_CRITICAL,
DeviceExtension,
"ACPIDetectDuplicateHID - no memory!\n"
) );
ACPIInternalError( ACPI_DETECT );
}
RtlZeroMemory( childExtension->InstanceID, 9 * sizeof(UCHAR) );
sprintf( childExtension->InstanceID, "%lx", childExtension->AcpiObject->dwNameSeg );
//
// Update the flags for both devices to indicate the fixed UID
//
ACPIInternalUpdateFlags(
&(childExtension->Flags),
DEV_PROP_FIXED_UID,
FALSE
);
}
}
}
NTSTATUS
ACPIDetectEjectDevices(
IN PDEVICE_EXTENSION DeviceExtension,
IN OUT PDEVICE_RELATIONS *DeviceRelations,
IN PDEVICE_EXTENSION AdditionalExtension OPTIONAL
)
/*++
Routine Description
Arguments:
DeviceExtension - The device extension of the object whose
relations we care to know about
DeviceRelations - Pointer to Pointer to the array of device
relations
AdditionalExtension - If set, non-NULL AdditionalExtension's
DeviceObject will be added to the list (this
is for the profile providers)
ADRIAO N.B 07/14/1999 -
A more clever way to solve the profile provider issue is listed here.
1) Add a new phase in buildsrc after the _EJD phase, call it PhaseDock
2) When PhaseDock finds a _DCK node, it creates a seperate extension,
RemoveEntryList's the EjectHead and Inserts the list on the new extension
(ie, new extension hijacks old extensions _EJD's)
3) New extension adds old as an ejection relation
4) Old extension adds new as it's *only* ejection relation
(We're not taking this design due to the ship schedule, it's safer to hack
the existing one).
Return Value:
NTSTATUS
--*/
{
BOOLEAN inRelation;
EXTENSIONLIST_ENUMDATA eled ;
LONG oldReferenceCount;
KIRQL oldIrql;
NTSTATUS status;
PDEVICE_OBJECT tempPdo ;
PDEVICE_EXTENSION ejecteeExtension = NULL;
PDEVICE_EXTENSION targetExtension = NULL;
PDEVICE_RELATIONS currentRelations = NULL;
PDEVICE_RELATIONS newRelations = NULL;
PLIST_ENTRY listEntry = NULL;
ULONG i = 0;
ULONG index = 0;
ULONG newRelationSize = 0;
//
// We might not have resolved all our ejection dependencies, so lets do
// that now...
//
ACPIBuildMissingEjectionRelations();
//
// Determine the current size of the device relation (if any exists)
//
if (DeviceRelations != NULL && *DeviceRelations != NULL) {
//
// We need this value to help us build an MDL. After that is done,
// we will refetch it
//
currentRelations = (*DeviceRelations);
newRelationSize = currentRelations->Count;
}
ACPIExtListSetupEnum(
&eled,
&(DeviceExtension->EjectDeviceHead),
&AcpiDeviceTreeLock,
EjectDeviceList,
WALKSCHEME_REFERENCE_ENTRIES
) ;
for(ejecteeExtension = ACPIExtListStartEnum(&eled);
ACPIExtListTestElement(&eled, TRUE);
ejecteeExtension = ACPIExtListEnumNext(&eled)) {
//
// Is it physically present?
//
if (!(ejecteeExtension->Flags & DEV_MASK_NOT_PRESENT) &&
!(ejecteeExtension->Flags & DEV_PROP_FAILED_INIT) &&
(ejecteeExtension->PhysicalDeviceObject != NULL) ) {
//
// Is there a match between the device relations and the current
// device extension?
//
status = ACPIDetectCouldExtensionBeInRelation(
ejecteeExtension,
currentRelations,
FALSE,
FALSE,
&tempPdo
) ;
if ( tempPdo == NULL && NT_SUCCESS(status) ) {
//
// We are here if we an extension that does not match any
// of the hardware represented by the current contents of
// the relation.
//
if (ejecteeExtension->PhysicalDeviceObject != NULL) {
inRelation = ACPIExtListIsMemberOfRelation(
ejecteeExtension->PhysicalDeviceObject,
currentRelations
);
if (inRelation == FALSE) {
newRelationSize++;
}
}
}
} // if (ejecteeExtension ... )
}
//
// Do we have an extra device to include in the list?
//
if (ARGUMENT_PRESENT(AdditionalExtension) &&
!(AdditionalExtension->Flags & DEV_MASK_NOT_PRESENT) &&
(AdditionalExtension->PhysicalDeviceObject != NULL)) {
inRelation = ACPIExtListIsMemberOfRelation(
AdditionalExtension->PhysicalDeviceObject,
currentRelations);
if (inRelation == FALSE) {
newRelationSize++;
}
}
//
// At this point, we can see if we need to change the size of the
// device relations
//
if ( (currentRelations != NULL && newRelationSize == currentRelations->Count) ||
(currentRelations == NULL && newRelationSize == 0) ) {
//
// Done
//
return STATUS_SUCCESS;
}
//
// Determine the size of the new relations. Use index as a
// scratch buffer
//
index = sizeof(DEVICE_RELATIONS) +
( sizeof(PDEVICE_OBJECT) * (newRelationSize - 1) );
//
// Allocate the new device relation buffer. Use nonpaged pool since we
// are at dispatch
//
newRelations = ExAllocatePoolWithTag(
PagedPool,
index,
ACPI_DEVICE_POOLTAG
);
if (newRelations == NULL) {
//
// Return failure
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize DeviceRelations data structure
//
RtlZeroMemory( newRelations, index );
//
// If there are existing relations, we must determine
if (currentRelations) {
//
// Copy old relations, and determine the starting index for the
// first of the PDOs created by this driver. We will put off freeing
// the old relations till we are no longer holding the lock
//
RtlCopyMemory(
newRelations->Objects,
currentRelations->Objects,
currentRelations->Count * sizeof(PDEVICE_OBJECT)
);
index = currentRelations->Count;
} else {
//
// There will not be a lot of work to do in this case
//
index = 0;
}
ACPIExtListSetupEnum(
&eled,
&(DeviceExtension->EjectDeviceHead),
&AcpiDeviceTreeLock,
EjectDeviceList,
WALKSCHEME_REFERENCE_ENTRIES
) ;
//
// We need the spin lock so that we can walk the tree again. This time
// we don't need to let it go until we are done since we don't need
// to call anything that will at PASSIVE_LEVEL
//
for(ejecteeExtension = ACPIExtListStartEnum(&eled);
ACPIExtListTestElement(&eled, (BOOLEAN) (newRelationSize!=index));
ejecteeExtension = ACPIExtListEnumNext(&eled)) {
if (ejecteeExtension == NULL) {
ACPIExtListExitEnumEarly( &eled );
break;
}
//
// The only objects that we care about are those that are marked as
// PDOs and have a phsyical object associated with them
//
if (!(ejecteeExtension->Flags & DEV_MASK_NOT_PRESENT) &&
!(ejecteeExtension->Flags & DEV_PROP_DOCK) &&
(ejecteeExtension->PhysicalDeviceObject != NULL) ) {
//
// See if the object is already in the relations. Note that it
// actually correct to use currentRelations for the test instead
// of newRelations. This is because we only want to compare
// against those object which were handed to us, not the ones
// that we added.
//
inRelation = ACPIExtListIsMemberOfRelation(
ejecteeExtension->PhysicalDeviceObject,
currentRelations
);
if (inRelation == FALSE) {
//
// We don't ObReferenceO here because we are still at
// dispatch level (and for efficiency's sake, we don't
// want to drop down). We also update the location for
// the next object in the relation
//
newRelations->Objects[index++] =
ejecteeExtension->PhysicalDeviceObject;
}
} // if (ejecteeExtension->Flags ... )
} // for
//
// Do we have an extra device to include in the list? If so, add it now
//
if (ARGUMENT_PRESENT(AdditionalExtension) &&
!(AdditionalExtension->Flags & DEV_MASK_NOT_PRESENT) &&
(AdditionalExtension->PhysicalDeviceObject != NULL)) {
inRelation = ACPIExtListIsMemberOfRelation(
AdditionalExtension->PhysicalDeviceObject,
currentRelations);
if (inRelation == FALSE) {
newRelations->Objects[index++] =
AdditionalExtension->PhysicalDeviceObject;
}
}
//
// Update the size of the relations by the number of matches that we
// successfully made
//
newRelations->Count = index;
newRelationSize = index;
//
// We have to reference all of the objects that we added
//
index = (currentRelations != NULL ? currentRelations->Count : 0);
for (; index < newRelationSize; index++) {
//
// Attempt to reference the object
//
status = ObReferenceObjectByPointer(
newRelations->Objects[index],
0,
NULL,
KernelMode
);
if (!NT_SUCCESS(status) ) {
PDEVICE_OBJECT tempDeviceObject;
//
// Hmm... Let the world know that this happened
//
ACPIPrint( (
ACPI_PRINT_FAILURE,
"ACPIDetectEjectDevices: ObjReferenceObject(0x%08lx) "
"= 0x%08lx\n",
newRelations->Objects[index],
status
) );
//
// Swap the bad element for the last one in the chain
//
newRelations->Count--;
tempDeviceObject = newRelations->Objects[newRelations->Count];
newRelations->Objects[newRelations->Count] =
newRelations->Objects[index];
newRelations->Objects[index] = tempDeviceObject;
}
}
//
// Free the old device relations (if it is present)
//
if (currentRelations) {
ExFreePool( *DeviceRelations );
}
//
// Update the device relation pointer
//
*DeviceRelations = newRelations;
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ACPIDetectFilterDevices(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_RELATIONS DeviceRelations
)
/*++
Routine Description:
This is one of the two routines that is used for QueryDeviceRelations.
This routine is called on the IRPs way *up* the stack. Its purpose is
to create FILTERS for device which are in the relation and are known
to ACPI
Arguments:
DeviceObject - The object whose relations we care to know about
DeviceRelations - Pointer to array of device relations
Return Value:
NTSTATUS
--*/
{
LONG oldReferenceCount = 0;
KIRQL oldIrql;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = NULL;
PDEVICE_EXTENSION parentExtension = ACPIInternalGetDeviceExtension(DeviceObject);
PDEVICE_EXTENSION targetExtension = NULL;
PDEVICE_OBJECT pdoObject = NULL;
PLIST_ENTRY listEntry = NULL;
ULONG deviceStatus;
//
// Sync with the build surprise removal code...
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Do we have missing children?
//
if (parentExtension->Flags & DEV_PROP_REBUILD_CHILDREN) {
ACPIInternalUpdateFlags(
&(parentExtension->Flags),
DEV_PROP_REBUILD_CHILDREN,
TRUE
);
ACPIBuildMissingChildren( parentExtension );
}
//
// Done with the sync part
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// No matter what, we must make sure that we are synchronized with the
// build engine.
//
status = ACPIBuildFlushQueue( parentExtension );
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
parentExtension,
"ACPIBuildFlushQueue = %08lx\n",
status
) );
return status;
}
//
// We must walk the tree at dispatch level <sigh>
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Sanity check
//
if (IsListEmpty( &(parentExtension->ChildDeviceList) ) ) {
//
// We have nothing to do here
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
return STATUS_SUCCESS;
}
//
// Grab the first child
//
deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
parentExtension->ChildDeviceList.Flink,
DEVICE_EXTENSION,
SiblingDeviceList
);
//
// Always update the reference count to make sure that no one will
// ever delete the node without our knowing it
//
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
//
// Relinquish the spin lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Loop until we get back to the parent
//
while (deviceExtension != NULL) {
//
// Note: Do *NOT* set the NOT_ENUMERATED bit here. We have already
// set the bit in ACPIDetectPdoDevices()
//
//
// Update the device status. Make sure that we call at PASSIVE
// level, since we will be calling synchronously
//
status = ACPIGetDevicePresenceSync(
deviceExtension,
(PVOID *) &deviceStatus,
NULL
);
if ( NT_SUCCESS(status) &&
!(deviceExtension->Flags & DEV_MASK_NOT_PRESENT) ) {
//
// Is there a match between the device relations and the current
// device extension?
//
status = ACPIDetectFilterMatch(
deviceExtension,
DeviceRelations,
&pdoObject
);
if (NT_SUCCESS(status) ) {
if (pdoObject != NULL) {
//
// We have to build a filter object here
//
status = ACPIBuildFilter(
DeviceObject->DriverObject,
deviceExtension,
pdoObject
);
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
deviceExtension,
"ACPIDetectFilterDevices = %08lx\n",
status
) );
}
}
} else {
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
deviceExtension,
"ACPIDetectFilterMatch = 0x%08lx\n",
status
) );
}
}
//
// Reacquire the spin lock
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Decrement the reference count on the node
//
oldReferenceCount = InterlockedDecrement(
&(deviceExtension->ReferenceCount)
);
//
// Check to see if we have gone all the way around the list
// list
if (deviceExtension->SiblingDeviceList.Flink ==
&(parentExtension->ChildDeviceList) ) {
//
// Remove the node, if necessary
//
if (oldReferenceCount == 0) {
//
// Free the memory allocated by the extension
//
ACPIInitDeleteDeviceExtension( deviceExtension );
}
//
// Release the spin lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Stop the loop
//
break;
} // if
//
// Next element
//
deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
deviceExtension->SiblingDeviceList.Flink,
DEVICE_EXTENSION,
SiblingDeviceList
);
//
// Remove the old node, if necessary
//
if (oldReferenceCount == 0) {
//
// Unlink the extension from the tree
//
listEntry = RemoveTailList(
&(deviceExtension->SiblingDeviceList)
);
//
// It is not possible for this to point to the parent without
// having succeeded the previous test
//
targetExtension = CONTAINING_RECORD(
listEntry,
DEVICE_EXTENSION,
SiblingDeviceList
);
//
// Free the memory allocated for the extension
//
ACPIInitDeleteDeviceExtension( targetExtension );
}
//
// Increment the reference count on this node so that it too
// cannot be deleted
//
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
//
// Now, we release the spin lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
} // while
//
// We succeeded
//
return STATUS_SUCCESS;
}
NTSTATUS
ACPIDetectFilterMatch(
IN PDEVICE_EXTENSION DeviceExtension,
IN PDEVICE_RELATIONS DeviceRelations,
OUT PDEVICE_OBJECT *PdoObject
)
/*++
Routine Description:
This routine takes a given extension and a set of relations and decides
whether a new filter should be attached to one of the PDO's listed in
the relation list.
Arguments:
DeviceExtension - Extension we wish to match in the relation
DeviceRelations - Relations we should examine
PdoObject - Where to store the match
Return Value:
NTSTATUS
PdoObject - Non-Null means that PdoObject needs a filter attached to it.
--*/
{
NTSTATUS status;
PAGED_CODE();
ASSERT( PdoObject != NULL);
if (PdoObject == NULL) {
return STATUS_INVALID_PARAMETER_1;
}
*PdoObject = NULL;
//
// For this to work, we must set the DEV_TYPE_NOT_FOUND flag when we
// first create the device and at any time when there is no device object
// associated with the extension
//
if ( !(DeviceExtension->Flags & DEV_TYPE_NOT_FOUND) ||
(DeviceExtension->Flags & DEV_PROP_DOCK) ||
DeviceExtension->DeviceObject != NULL) {
ULONG count;
//
// If we don't have any relations, then we can't match anything
//
if (DeviceRelations == NULL || DeviceRelations->Count == 0) {
return STATUS_SUCCESS;
}
//
// Look at all the PDOs in the relation and see if they match what
// a device object that we are attached to
//
for (count = 0; count < DeviceRelations->Count; count++) {
if (DeviceExtension->PhysicalDeviceObject == DeviceRelations->Objects[count]) {
//
// Clear the flag that says that we haven't enumerated
// this
//
ACPIInternalUpdateFlags(
&(DeviceExtension->Flags),
DEV_TYPE_NOT_ENUMERATED,
TRUE
);
}
}
return STATUS_SUCCESS;
}
status = ACPIDetectCouldExtensionBeInRelation(
DeviceExtension,
DeviceRelations,
TRUE,
FALSE,
PdoObject
) ;
if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
//
// Harmless cleanup, we just checked a node on a non-ACPI bus that
// doesn't have an _ADR (likely it has a _HID, and will make it's
// own PDO)
//
status = STATUS_SUCCESS;
}
return status ;
}
NTSTATUS
ACPIDetectPdoDevices(
IN PDEVICE_OBJECT DeviceObject,
IN PDEVICE_RELATIONS *DeviceRelations
)
/*++
Routine Description
This is one of the two functions that is used for QueryDeviceRelations.
This routine is called on the IRPs way *down* the stack. Its purpose is
to create PDOs for device which are not in the relation
Arguments:
DeviceObject - The object whose relations we care to know about
DeviceRelations - Pointer to Pointer to the array of device relations
Return Value:
NTSTATUS
--*/
{
BOOLEAN matchFound;
LONG oldReferenceCount;
KIRQL oldIrql;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = NULL;
PDEVICE_EXTENSION parentExtension = ACPIInternalGetDeviceExtension(DeviceObject);
PDEVICE_EXTENSION targetExtension = NULL;
PDEVICE_RELATIONS currentRelations = NULL;
PDEVICE_RELATIONS newRelations = NULL;
PLIST_ENTRY listEntry = NULL;
ULONG i = 0;
ULONG j = 0;
ULONG index = 0;
ULONG newRelationSize = 0;
ULONG deviceStatus;
//
// Determine the current size of the device relation (if any exists)
//
if (DeviceRelations != NULL && *DeviceRelations != NULL) {
//
// We need this value to help us build an MDL. After that is done,
// we will refetch it
//
currentRelations = (*DeviceRelations);
newRelationSize = currentRelations->Count;
}
//
// Sync with the build surprise removal code...
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Do we have missing children?
//
if (parentExtension->Flags & DEV_PROP_REBUILD_CHILDREN) {
ACPIInternalUpdateFlags(
&(parentExtension->Flags),
DEV_PROP_REBUILD_CHILDREN,
TRUE
);
ACPIBuildMissingChildren( parentExtension );
}
//
// Done with the sync part
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// The first step is to actually try to make sure that we are currently
// synchronized with the build engine
//
status = ACPIBuildFlushQueue( parentExtension );
if (!NT_SUCCESS(status)) {
ACPIDevPrint( (
ACPI_PRINT_FAILURE,
parentExtension,
"ACPIBuildFlushQueue = %08lx\n",
status
) );
return status;
}
//
// We must walk the tree at dispatch level <sigh>
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Sanity check
//
if (IsListEmpty( &(parentExtension->ChildDeviceList) ) ) {
//
// We have nothing to do here
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Do we currently have some relations? If so, then we just return
// those and don't need to add anything to them
//
if (currentRelations) {
return STATUS_SUCCESS;
}
//
// We still need to return an information context with a count of 0
//
newRelations = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(DEVICE_RELATIONS),
ACPI_DEVICE_POOLTAG
);
if (newRelations == NULL) {
//
// Return failure
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize DeviceRelations data structure
//
RtlZeroMemory( newRelations, sizeof(DEVICE_RELATIONS) );
//
// We don't need to this, but its better to be explicit
//
newRelations->Count = 0;
//
// Remember the new relations and return
//
*DeviceRelations = newRelations;
return STATUS_SUCCESS;
}
//
// Grab the first child
//
deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
parentExtension->ChildDeviceList.Flink,
DEVICE_EXTENSION,
SiblingDeviceList
);
//
// Always update the reference count to make sure that no one will
// ever delete the node without our knowing it
//
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
//
// Relinquish the spin lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Loop until we get back to the parent
//
while (deviceExtension != NULL) {
//
// Always consider the device as never having been enumerated.
//
// NOTE:
// The reason that we do this here (and only here) is because
// ACPIDetectFilterMatch() is called later on and we need to know
// which device objects were detected as PDOs and which ones were
// also detected as Filters. Setting this flag twice would defeat that
// purpose.
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
DEV_TYPE_NOT_ENUMERATED,
FALSE
);
//
// Update the current device status
//
status = ACPIGetDevicePresenceSync(
deviceExtension,
(PVOID *) &deviceStatus,
NULL
);
//
// If the device exists
//
if ( NT_SUCCESS(status) &&
!(deviceExtension->Flags & DEV_MASK_NOT_PRESENT) ) {
//
// Is there a match between the device relations and the current
// device extension?
//
matchFound = ACPIDetectPdoMatch(
deviceExtension,
currentRelations
);
if (matchFound == FALSE) {
//
// NOTE: we use this here to prevent having to typecase later
// on
//
matchFound =
(parentExtension->Flags & DEV_TYPE_FDO) ? FALSE : TRUE;
//
// Build a new PDO
//
status = ACPIBuildPdo(
DeviceObject->DriverObject,
deviceExtension,
parentExtension->PhysicalDeviceObject,
matchFound
);
if (NT_SUCCESS(status)) {
//
// We have created a device object that we will have to
// add into the device relations
//
newRelationSize += 1;
}
} else if (deviceExtension->Flags & DEV_TYPE_PDO &&
deviceExtension->DeviceObject != NULL) {
//
// Just we because the device_extension matched doesn't mean
// that it is included in the device relations. What we will
// do here is look to see if
// a) the extension is a PDO
// b) there is a device object associated with the
// extension
// c) the device object is *not* in the device relation
//
matchFound = FALSE;
if (currentRelations != NULL) {
for (index = 0; index < currentRelations->Count; index++) {
if (currentRelations->Objects[index] ==
deviceExtension->DeviceObject) {
//
// Match found
//
matchFound = TRUE;
break;
}
} // for
}
//
// Did we not find a match?
//
if (!matchFound) {
//
// We need to make sure that its in the relation
//
newRelationSize += 1;
//
// And at the same time, clear the flag that says that
// we haven't enumerated this
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
DEV_TYPE_NOT_ENUMERATED,
TRUE
);
}
} // if (ACPIDetectPDOMatch ... )
} // if (deviceExtension ... )
//
// Reacquire the spin lock
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Decrement the reference count on the node
//
oldReferenceCount = InterlockedDecrement(
&(deviceExtension->ReferenceCount)
);
//
// Check to see if we have gone all the way around the list
// list
if (deviceExtension->SiblingDeviceList.Flink ==
&(parentExtension->ChildDeviceList) ) {
//
// Remove the node, if necessary
//
if (oldReferenceCount == 0) {
//
// Free the memory allocated by the extension
//
ACPIInitDeleteDeviceExtension( deviceExtension );
}
//
// Now, we release the spin lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// Stop the loop
//
break;
} // if
//
// Next element
//
deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
deviceExtension->SiblingDeviceList.Flink,
DEVICE_EXTENSION,
SiblingDeviceList
);
//
// Remove the old node, if necessary
//
if (oldReferenceCount == 0) {
//
// Unlink the obsolete extension
//
listEntry = RemoveTailList(
&(deviceExtension->SiblingDeviceList)
);
//
// It is not possible for this to point to the parent without
// having succeeded the previous test
//
targetExtension = CONTAINING_RECORD(
listEntry,
DEVICE_EXTENSION,
SiblingDeviceList
);
//
// Deleted the old extension
//
ACPIInitDeleteDeviceExtension( targetExtension );
}
//
// Increment the reference count on this node so that it too
// cannot be deleted
//
InterlockedIncrement( &(deviceExtension->ReferenceCount) );
//
// Now, we release the spin lock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
} // while
//
// At this point, we can see if we need to change the size of the
// device relations
//
if ( (currentRelations && newRelationSize == currentRelations->Count) ||
(currentRelations == NULL && newRelationSize == 0) ) {
//
// Done
//
return STATUS_SUCCESS;
}
//
// Determine the size of the new relations. Use index as a
// scratch buffer
//
index = sizeof(DEVICE_RELATIONS) +
( sizeof(PDEVICE_OBJECT) * (newRelationSize - 1) );
//
// Allocate the new device relation buffer. Use nonpaged pool since we
// are at dispatch
//
newRelations = ExAllocatePoolWithTag(
NonPagedPool,
index,
ACPI_DEVICE_POOLTAG
);
if (newRelations == NULL) {
//
// Return failure
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize DeviceRelations data structure
//
RtlZeroMemory( newRelations, index );
//
// If there are existing relations, we must determine
if (currentRelations) {
//
// Copy old relations, and determine the starting index for the
// first of the PDOs created by this driver. We will put off freeing
// the old relations till we are no longer holding the lock
//
RtlCopyMemory(
newRelations->Objects,
currentRelations->Objects,
currentRelations->Count * sizeof(PDEVICE_OBJECT)
);
index = currentRelations->Count;
j = currentRelations->Count;
} else {
//
// There will not be a lot of work to do in this case
//
index = j = 0;
}
//
// We need the spin lock so that we can walk the tree again. This time
// we don't need to let it go until we are done since we don't need
// to call anything that will at PASSIVE_LEVEL
//
KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
//
// Sanity check
//
if (IsListEmpty( &(parentExtension->ChildDeviceList) ) ) {
//
// We have nothing to do here
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
ExFreePool( newRelations );
return STATUS_SUCCESS;
}
//
// Walk the tree one more time and add all PDOs that aren't present in
// the device relations
//
deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
parentExtension->ChildDeviceList.Flink,
DEVICE_EXTENSION,
SiblingDeviceList
);
//
// Loop until we get back to the parent
//
while (deviceExtension != NULL) {
//
// The only objects that we care about are those that are marked as
// PDOs and have a phsyical object associated with them
//
if (deviceExtension->Flags & DEV_TYPE_PDO &&
deviceExtension->DeviceObject != NULL &&
!(deviceExtension->Flags & DEV_MASK_NOT_PRESENT) ) {
//
// We don't ObReferenceO here because we are still at
// dispatch level (and for efficiency's sake, we don't
// want to drop down)
//
newRelations->Objects[index] =
deviceExtension->DeviceObject;
//
// Update the location for the next object in the
// relation
//
index += 1;
//
// And at the same time, clear the flag that says that
// we haven't enumerated this
//
ACPIInternalUpdateFlags(
&(deviceExtension->Flags),
DEV_TYPE_NOT_ENUMERATED,
TRUE
);
} // if (deviceExtension->Flags ... )
//
// Check to see if we have found all the objects that we care
// about. As in, don't mess the system by walking past the end
// of the device relations
//
if (newRelationSize == index) {
//
// Done
//
break;
}
//
// Check to see if we have gone all the way around the list
// list
if (deviceExtension->SiblingDeviceList.Flink ==
&(parentExtension->ChildDeviceList) ) {
break;
} // if
//
// Next element
//
deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
deviceExtension->SiblingDeviceList.Flink,
DEVICE_EXTENSION,
SiblingDeviceList
);
} // while (deviceExtension ... )
//
// Update the size of the relations by the number of matches that we
// successfully made
//
newRelations->Count = index;
newRelationSize = index;
//
// At this point, we are well and truely done with the spinlock
//
KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
//
// We have to reference all of the objects that we added
//
index = (currentRelations != NULL ? currentRelations->Count : 0);
for (; index < newRelationSize; index++) {
//
// Attempt to reference the object
//
status = ObReferenceObjectByPointer(
newRelations->Objects[index],
0,
NULL,
KernelMode
);
if (!NT_SUCCESS(status) ) {
PDEVICE_OBJECT tempDeviceObject;
//
// Hmm... Let the world know that this happened
//
ACPIPrint( (
ACPI_PRINT_FAILURE,
"ACPIDetectPdoDevices: ObjReferenceObject(0x%08lx) "
"= 0x%08lx\n",
newRelations->Objects[index],
status
) );
//
// Swap the bad element for the last one in the chain
//
newRelations->Count--;
tempDeviceObject = newRelations->Objects[newRelations->Count];
newRelations->Objects[newRelations->Count] =
newRelations->Objects[index];
newRelations->Objects[index] = tempDeviceObject;
}
}
//
// Free the old device relations (if it is present)
//
if (currentRelations) {
ExFreePool( *DeviceRelations );
}
//
// Update the device relation pointer
//
*DeviceRelations = newRelations;
//
// Done
//
return STATUS_SUCCESS;
}
BOOLEAN
ACPIDetectPdoMatch(
IN PDEVICE_EXTENSION DeviceExtension,
IN PDEVICE_RELATIONS DeviceRelations
)
/*++
Routine Description:
This routine takes a given extension and a set of relations and decides
whether a new PDO should be created for the extension. Return result
is *FALSE* if one should be created, *TRUE* if one was already created.
NB: This routine is called by a parent who owns the AcpiDeviceTreeLock...
NNB: This means that this routine is always called at DISPATCH_LEVEL
Arguments:
DeviceExtension - What we are trying to match too
DeviceRelations - What we are trying to match with
Return Value:
TRUE - The DeviceExtension can be ignored
FALSE - A device object needs to be created for the extension
--*/
{
NTSTATUS status;
PDEVICE_OBJECT devicePdoObject = NULL ;
PAGED_CODE();
//
// For this to work, we must set the DEV_TYPE_NOT_FOUND flag when we
// first create the device and at any time when there is no device object
// associated with the extension
//
if (!(DeviceExtension->Flags & DEV_TYPE_NOT_FOUND) ||
(DeviceExtension->Flags & DEV_PROP_DOCK) ||
DeviceExtension->DeviceObject != NULL) {
return TRUE;
}
//
// deviceObject will be filled in if the extension in question is
// already in the relation. The status will not be successful if the
// extension could not be in the relation.
//
status = ACPIDetectCouldExtensionBeInRelation(
DeviceExtension,
DeviceRelations,
FALSE,
TRUE,
&devicePdoObject
) ;
return (devicePdoObject||(!NT_SUCCESS(status))) ? TRUE : FALSE ;
}