/*++ Copyright (c) 1997 Microsoft Corporation Module Name: extlist.c Abstract: This module contains routines for managing ACPI extension lists Author: Adrian J. Oney (AdriaO) Environment: NT Kernel Model Driver only These routines are meant to be used as a for loop, ie: Iterate over the list using: ACPIExtListSetupEnum(...); for( ACPIExtListStartEnum(...); ACPIExtListTestElement(...); ACPIExtListEnumNext(...) ) { if (GoingToBreak) { ACPIExtListExitEnumEarly(...); break ; } } Revision History: Feb 11, 1998 - Authored --*/ #include "pch.h" BOOLEAN ACPIExtListIsFinished( IN PEXTENSIONLIST_ENUMDATA PExtList_EnumData ) /*++ Routine Description: Arguments: Return Value: --*/ { ACPIDebugEnter( "ACPIExtListIsFinished" ); if (CONTAINING_LIST(PExtList_EnumData->pDevExtCurrent, PExtList_EnumData->ExtOffset) == PExtList_EnumData->pListHead) { return TRUE ; } return FALSE ; ACPIDebugExit( "ACPIExtListIsFinished" ); } PDEVICE_EXTENSION EXPORT ACPIExtListStartEnum( IN OUT PEXTENSIONLIST_ENUMDATA PExtList_EnumData ) /*++ Routine Description: Arguments: Return Value: --*/ { ACPIDebugEnter( "ACPIExtListStartEnum" ); // // We must walk the tree at dispatch level // if (PExtList_EnumData->WalkScheme != WALKSCHEME_NO_PROTECTION) { KeAcquireSpinLock( PExtList_EnumData->pSpinLock, &PExtList_EnumData->oldIrql ); } // // Grab the first element // PExtList_EnumData->pDevExtCurrent = CONTAINING_EXTENSION( PExtList_EnumData->pListHead->Flink, PExtList_EnumData->ExtOffset ); // // Return null if the list is empty (leave the internal pointer alone // though... // if (ACPIExtListIsFinished(PExtList_EnumData)) { return NULL ; } return PExtList_EnumData->pDevExtCurrent ; ACPIDebugExit( "ACPIExtListStartEnum" ); } BOOLEAN EXPORT ACPIExtListTestElement( IN OUT PEXTENSIONLIST_ENUMDATA PExtList_EnumData, IN BOOLEAN ContinueEnumeration ) /*++ Routine Description: Arguments: Return Value: --*/ { ACPIDebugEnter( "ACPIExtListTestElement" ); // // If finished or stopping, simply release the spinlock // if (ACPIExtListIsFinished(PExtList_EnumData)||(!ContinueEnumeration)) { if (PExtList_EnumData->WalkScheme != WALKSCHEME_NO_PROTECTION) { KeReleaseSpinLock( PExtList_EnumData->pSpinLock, PExtList_EnumData->oldIrql ); } return FALSE ; } if (PExtList_EnumData->WalkScheme == WALKSCHEME_REFERENCE_ENTRIES) { // // Always update the reference count to make sure that no one will // ever delete the node while our spinlock is down // InterlockedIncrement( &(PExtList_EnumData->pDevExtCurrent->ReferenceCount) ); // // Relinquish the spin lock // KeReleaseSpinLock( PExtList_EnumData->pSpinLock, PExtList_EnumData->oldIrql ); } return TRUE ; ACPIDebugExit( "ACPIExtListTestElement" ); } PDEVICE_EXTENSION EXPORT ACPIExtListEnumNext( IN OUT PEXTENSIONLIST_ENUMDATA PExtList_EnumData ) /*++ Routine Description: Arguments: Return Value: --*/ { LONG oldReferenceCount ; PDEVICE_EXTENSION nextExtension ; BOOLEAN enumComplete ; PLIST_ENTRY listEntry ; ACPIDebugEnter( "ACPIExtListEnumNext" ); if (PExtList_EnumData->WalkScheme != WALKSCHEME_REFERENCE_ENTRIES) { PExtList_EnumData->pDevExtCurrent = CONTAINING_EXTENSION( CONTAINING_LIST(PExtList_EnumData->pDevExtCurrent, PExtList_EnumData->ExtOffset)->Flink, PExtList_EnumData->ExtOffset ); enumComplete = ACPIExtListIsFinished(PExtList_EnumData) ; return enumComplete ? NULL : PExtList_EnumData->pDevExtCurrent ; } // // Reacquire the spin lock // KeAcquireSpinLock( PExtList_EnumData->pSpinLock, &PExtList_EnumData->oldIrql ); // // Decrement the reference count on the node // oldReferenceCount = InterlockedDecrement( &(PExtList_EnumData->pDevExtCurrent->ReferenceCount) ); ASSERT(!ACPIExtListIsFinished(PExtList_EnumData)) ; // // Next element // nextExtension = CONTAINING_EXTENSION( CONTAINING_LIST(PExtList_EnumData->pDevExtCurrent, PExtList_EnumData->ExtOffset)->Flink, PExtList_EnumData->ExtOffset ); // // Remove the node, if necessary // if (oldReferenceCount == 0) { // // Deleted the old extension // ACPIInitDeleteDeviceExtension( PExtList_EnumData->pDevExtCurrent ); } PExtList_EnumData->pDevExtCurrent = nextExtension ; enumComplete = ACPIExtListIsFinished(PExtList_EnumData) ; return enumComplete ? NULL : PExtList_EnumData->pDevExtCurrent ; ACPIDebugExit( "ACPIExtListEnumNext" ); } VOID EXPORT ACPIExtListExitEnumEarly( IN OUT PEXTENSIONLIST_ENUMDATA PExtList_EnumData ) /*++ Routine Description: Arguments: Return Value: --*/ { ACPIDebugEnter( "ACPIExtListExitEnumEarly" ); // // Relinquish the spin lock // if (PExtList_EnumData->WalkScheme == WALKSCHEME_HOLD_SPINLOCK) { KeReleaseSpinLock( PExtList_EnumData->pSpinLock, PExtList_EnumData->oldIrql ); } return ; ACPIDebugExit( "ACPIExtListExitEnumEarly" ); } BOOLEAN EXPORT ACPIExtListIsMemberOfRelation( IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_RELATIONS DeviceRelations ) /*++ Routine Description: This routine takes a given device object and a set of relations and checks to see if the object is already in the relation list. Arguments: DeviceObject - Device object to look for DeviceRelations - Relations we should examine Return Value: BOOLEAN - TRUE if DeviceObject is a member of the relation. --*/ { ULONG index = 0; ACPIDebugEnter( "ACPIExtListIsMemberOfRelation" ); // // If the list is empty, the answer is obvious... // if (DeviceRelations == NULL) return FALSE ; for (index = 0; index < DeviceRelations->Count; index++) { if (DeviceRelations->Objects[index] == DeviceObject) { return TRUE ; } } return FALSE ; ACPIDebugExit( "ACPIExtListIsMemberOfRelation" ); }