|
|
/*++
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 ; }
|