2507 lines
65 KiB
C
2507 lines
65 KiB
C
/*++
|
||
|
||
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 ;
|
||
}
|
||
|