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 ;
|
|||
|
}
|
|||
|
|