Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

pnprlist.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1998 Microsoft Corporation 00004 00005 Module Name: 00006 00007 pnprlist.c 00008 00009 Abstract: 00010 00011 This module contains routines to manipulate relations list. Relation lists 00012 are used by Plug and Play during the processing of device removal and 00013 ejection. 00014 00015 These routines are all pageable and can't be called at raised IRQL or with 00016 a spinlock held. 00017 00018 Author: 00019 00020 Robert Nelson (robertn) Apr, 1998. 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 #include "iop.h" 00027 00028 #ifdef POOL_TAGGING 00029 #undef ExAllocatePool 00030 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'lrpP') 00031 #endif 00032 00033 #ifdef ALLOC_PRAGMA 00034 #pragma alloc_text(PAGE, IopAddRelationToList) 00035 #pragma alloc_text(PAGE, IopAllocateRelationList) 00036 #pragma alloc_text(PAGE, IopCompressRelationList) 00037 #pragma alloc_text(PAGE, IopEnumerateRelations) 00038 #pragma alloc_text(PAGE, IopFreeRelationList) 00039 #pragma alloc_text(PAGE, IopGetRelationsCount) 00040 #pragma alloc_text(PAGE, IopGetRelationsTaggedCount) 00041 #pragma alloc_text(PAGE, IopIsRelationInList) 00042 #pragma alloc_text(PAGE, IopMergeRelationLists) 00043 #pragma alloc_text(PAGE, IopRemoveIndirectRelationsFromList) 00044 #pragma alloc_text(PAGE, IopRemoveRelationFromList) 00045 #pragma alloc_text(PAGE, IopSetAllRelationsTags) 00046 #pragma alloc_text(PAGE, IopSetRelationsTag) 00047 #endif 00048 00049 #define RELATION_FLAGS 0x00000003 00050 00051 #define RELATION_FLAG_TAGGED 0x00000001 00052 #define RELATION_FLAG_DESCENDANT 0x00000002 00053 00054 NTSTATUS 00055 IopAddRelationToList( 00056 IN PRELATION_LIST List, 00057 IN PDEVICE_OBJECT DeviceObject, 00058 IN BOOLEAN DirectDescendant, 00059 IN BOOLEAN Tagged 00060 ) 00061 00062 /*++ 00063 00064 Routine Description: 00065 00066 Adds an element to a relation list. 00067 00068 If this is the first DeviceObject of a particular level then a new 00069 RELATION_LIST_ENTRY will be allocated. 00070 00071 This routine should only be called on an uncompressed relation list, 00072 otherwise it is likely that STATUS_INVALID_PARAMETER will be returned. 00073 00074 Arguments: 00075 00076 List Relation list to which the DeviceObject is added. 00077 00078 DeviceObject DeviceObject to be added to List. It must be a 00079 PhysicalDeviceObject (PDO). 00080 00081 DirectDescendant Indicates whether DeviceObject is a direct descendant of 00082 the original target device of this remove. 00083 00084 Tagged Indicates whether DeviceObject should be tagged in List. 00085 00086 Return Value: 00087 00088 STATUS_SUCCESS 00089 00090 The DeviceObject was added successfully. 00091 00092 STATUS_OBJECT_NAME_COLLISION 00093 00094 The DeviceObject already exists in the relation list. 00095 00096 STATUS_INSUFFICIENT_RESOURCES 00097 00098 There isn't enough PagedPool available to allocate a new 00099 RELATION_LIST_ENTRY. 00100 00101 STATUS_INVALID_PARAMETER 00102 00103 The level of the DEVICE_NODE associated with DeviceObject is less than 00104 FirstLevel or greater than the MaxLevel. 00105 00106 STATUS_NO_SUCH_DEVICE 00107 00108 DeviceObject is not a PhysicalDeviceObject (PDO), it doesn't have a 00109 DEVICE_NODE associated with it. 00110 00111 --*/ 00112 00113 { 00114 PDEVICE_NODE deviceNode; 00115 PRELATION_LIST_ENTRY entry; 00116 ULONG level; 00117 ULONG index; 00118 ULONG flags; 00119 00120 PAGED_CODE(); 00121 00122 flags = 0; 00123 00124 if (Tagged) { 00125 Tagged = 1; 00126 flags |= RELATION_FLAG_TAGGED; 00127 } 00128 00129 if (DirectDescendant) { 00130 flags |= RELATION_FLAG_DESCENDANT; 00131 } 00132 00133 if ((deviceNode = DeviceObject->DeviceObjectExtension->DeviceNode) != NULL) { 00134 level = deviceNode->Level; 00135 00136 // 00137 // Since this routine is called with the DeviceNode Tree locked and 00138 // List is initially allocated with enough entries to hold the deepest 00139 // DEVICE_NODE this ASSERT should never fire. If it does then either 00140 // the tree is changing or we were given a compressed list. 00141 // 00142 ASSERT(List->FirstLevel <= level && level <= List->MaxLevel); 00143 00144 if (List->FirstLevel <= level && level <= List->MaxLevel) { 00145 00146 if ((entry = List->Entries[ level - List->FirstLevel ]) == NULL) { 00147 00148 // 00149 // This is the first DeviceObject of its level, allocate a new 00150 // RELATION_LIST_ENTRY. 00151 // 00152 entry = ExAllocatePool( PagedPool, 00153 sizeof(RELATION_LIST_ENTRY) + 00154 IopNumberDeviceNodes * sizeof(PDEVICE_OBJECT)); 00155 00156 if (entry == NULL) { 00157 return STATUS_INSUFFICIENT_RESOURCES; 00158 } 00159 00160 // 00161 // We always allocate enough Devices to hold the whole tree as 00162 // a simplification. Since each entry is a PDEVICE_OBJECT and 00163 // there is generally under 50 devices on a machine this means 00164 // under 1K for each entry. The excess space will be freed when 00165 // the list is compressed. 00166 // 00167 entry->Count = 0; 00168 entry->MaxCount = IopNumberDeviceNodes; 00169 00170 List->Entries[ level - List->FirstLevel ] = entry; 00171 } 00172 00173 // 00174 // There should always be room for a DeviceObject since the Entry is 00175 // initially dimensioned large enough to hold all the DEVICE_NODES 00176 // in the system. 00177 // 00178 ASSERT(entry->Count < entry->MaxCount); 00179 00180 if (entry->Count < entry->MaxCount) { 00181 // 00182 // Search the list to see if DeviceObject has already been 00183 // added. 00184 // 00185 for (index = 0; index < entry->Count; index++) { 00186 if (((ULONG_PTR)entry->Devices[ index ] & ~RELATION_FLAGS) == (ULONG_PTR)DeviceObject) { 00187 00188 // 00189 // DeviceObject already exists in the list. However 00190 // the Direct Descendant flag may differ. We will 00191 // override it if DirectDescendant is TRUE. This could 00192 // happen if we merged two relation lists. 00193 00194 if (DirectDescendant) { 00195 entry->Devices[ index ] = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ index ] | RELATION_FLAG_DESCENDANT); 00196 } 00197 00198 return STATUS_OBJECT_NAME_COLLISION; 00199 } 00200 } 00201 } else { 00202 // 00203 // There isn't room in the Entry for another DEVICE_OBJECT, the 00204 // list has probably already been compressed. 00205 // 00206 return STATUS_INVALID_PARAMETER; 00207 } 00208 00209 // 00210 // Take out a reference on DeviceObject, we will release it when we 00211 // free the list or remove the DeviceObject from the list. 00212 // 00213 ObReferenceObject( DeviceObject ); 00214 00215 entry->Devices[ index ] = (PDEVICE_OBJECT)((ULONG_PTR)DeviceObject | flags); 00216 entry->Count++; 00217 00218 List->Count++; 00219 List->TagCount += Tagged; 00220 00221 return STATUS_SUCCESS; 00222 } else { 00223 // 00224 // There isn't an Entry available for the level of this 00225 // DEVICE_OBJECT, the list has probably already been compressed. 00226 // 00227 00228 return STATUS_INVALID_PARAMETER; 00229 } 00230 } else { 00231 // 00232 // DeviceObject is not a PhysicalDeviceObject (PDO). 00233 // 00234 return STATUS_NO_SUCH_DEVICE; 00235 } 00236 } 00237 00238 PRELATION_LIST 00239 IopAllocateRelationList( 00240 VOID 00241 ) 00242 00243 /*++ 00244 00245 Routine Description: 00246 00247 Allocate a new Relations List. The list is initially sized large enough to 00248 hold the deepest DEVICE_NODE encountered since the system started. 00249 00250 Arguments: 00251 00252 NONE 00253 00254 Return Value: 00255 00256 Newly allocated list if enough PagedPool is available, otherwise NULL. 00257 00258 --*/ 00259 00260 { 00261 PRELATION_LIST list; 00262 ULONG maxLevel; 00263 ULONG listSize; 00264 00265 PAGED_CODE(); 00266 00267 // 00268 // Level number of the deepest DEVICE_NODE allocated since the system 00269 // started. 00270 // 00271 maxLevel = IopMaxDeviceNodeLevel; 00272 listSize = sizeof(RELATION_LIST) + maxLevel * sizeof(PRELATION_LIST_ENTRY); 00273 00274 if ((list = ExAllocatePool( PagedPool, listSize )) != NULL) { 00275 RtlZeroMemory(list, listSize); 00276 // list->FirstLevel = 0; 00277 // list->Count = 0; 00278 // list->Tagged = 0; 00279 list->MaxLevel = maxLevel; 00280 } 00281 00282 return list; 00283 } 00284 00285 NTSTATUS 00286 IopCompressRelationList( 00287 IN OUT PRELATION_LIST *List 00288 ) 00289 00290 /*++ 00291 00292 Routine Description: 00293 00294 Compresses the relation list by reallocating the list and all the entries so 00295 that they a just large enough to hold their current contents. 00296 00297 Once a list has been compressed IopAddRelationToList and 00298 IopMergeRelationLists targetting this list are both likely to fail. 00299 00300 Arguments: 00301 00302 List Relation List to compress. 00303 00304 Return Value: 00305 00306 STATUS_SUCCESS 00307 00308 The list was compressed. Although this routine does allocate memory and 00309 the allocation can fail, the routine itself will never fail. Since the 00310 memory we are allocating is always smaller then the memory it is 00311 replacing we just keep the old memory if the allocation fails. 00312 00313 --*/ 00314 00315 { 00316 PRELATION_LIST oldList, newList; 00317 PRELATION_LIST_ENTRY oldEntry, newEntry; 00318 ULONG lowestLevel; 00319 ULONG highestLevel; 00320 ULONG index; 00321 00322 PAGED_CODE(); 00323 00324 oldList = *List; 00325 00326 // 00327 // Initialize lowestLevel and highestLevel with illegal values chosen so 00328 // that the first real entry will override them. 00329 // 00330 lowestLevel = oldList->MaxLevel; 00331 highestLevel = oldList->FirstLevel; 00332 00333 // 00334 // Loop through the list looking for allocated entries. 00335 // 00336 for (index = 0; index <= (oldList->MaxLevel - oldList->FirstLevel); index++) { 00337 00338 if ((oldEntry = oldList->Entries[ index ]) != NULL) { 00339 // 00340 // This entry is allocated, update lowestLevel and highestLevel if 00341 // necessary. 00342 // 00343 if (lowestLevel > index) { 00344 lowestLevel = index; 00345 } 00346 00347 if (highestLevel < index) { 00348 highestLevel = index; 00349 } 00350 00351 if (oldEntry->Count < oldEntry->MaxCount) { 00352 00353 // 00354 // This entry is only partially full. Allocate a new entry 00355 // which is just the right size to hold the current number of 00356 // PDEVICE_OBJECTs. 00357 // 00358 newEntry = ExAllocatePool( PagedPool, 00359 sizeof(RELATION_LIST_ENTRY) + 00360 (oldEntry->Count - 1) * sizeof(PDEVICE_OBJECT)); 00361 00362 if (newEntry != NULL) { 00363 00364 // 00365 // Initialize Count and MaxCount to the number of 00366 // PDEVICE_OBJECTs in the old entry. 00367 // 00368 newEntry->Count = oldEntry->Count; 00369 newEntry->MaxCount = oldEntry->Count; 00370 00371 // 00372 // Copy the PDEVICE_OBJECTs from the old entry to the new 00373 // one. 00374 // 00375 RtlCopyMemory( newEntry->Devices, 00376 oldEntry->Devices, 00377 oldEntry->Count * sizeof(PDEVICE_OBJECT)); 00378 00379 // 00380 // Free the old entry and store the new entry in the list. 00381 // 00382 ExFreePool( oldEntry ); 00383 00384 oldList->Entries[ index ] = newEntry; 00385 } 00386 } 00387 } 00388 } 00389 00390 // 00391 // Assert that the old list isn't empty. 00392 // 00393 ASSERT(lowestLevel <= highestLevel); 00394 00395 if (lowestLevel > highestLevel) { 00396 // 00397 // The list is empty - we shouldn't get asked to compress an empty list 00398 // but lets do it anyways. 00399 // 00400 lowestLevel = 0; 00401 highestLevel = 0; 00402 } 00403 00404 // 00405 // Check if the old list had unused entries at the beginning or the end of 00406 // the Entries array. 00407 // 00408 if (lowestLevel != oldList->FirstLevel || highestLevel != oldList->MaxLevel) { 00409 00410 // 00411 // Allocate a new List with just enough Entries to hold those between 00412 // FirstLevel and MaxLevel inclusive. 00413 // 00414 newList = ExAllocatePool( PagedPool, 00415 sizeof(RELATION_LIST) + 00416 (highestLevel - lowestLevel) * sizeof(PRELATION_LIST_ENTRY)); 00417 00418 if (newList != NULL) { 00419 // 00420 // Copy the old list to the new list and return it to the caller. 00421 // 00422 newList->Count = oldList->Count; 00423 newList->TagCount = oldList->TagCount; 00424 newList->FirstLevel = lowestLevel; 00425 newList->MaxLevel = highestLevel; 00426 00427 RtlCopyMemory( newList->Entries, 00428 &oldList->Entries[ lowestLevel ], 00429 (highestLevel - lowestLevel + 1) * sizeof(PRELATION_LIST_ENTRY)); 00430 00431 ExFreePool( oldList ); 00432 00433 *List = newList; 00434 } 00435 } 00436 00437 return STATUS_SUCCESS; 00438 } 00439 00440 BOOLEAN 00441 IopEnumerateRelations( 00442 IN PRELATION_LIST List, 00443 IN OUT PULONG Marker, 00444 OUT PDEVICE_OBJECT *DeviceObject, 00445 OUT BOOLEAN *DirectDescendant, OPTIONAL 00446 OUT BOOLEAN *Tagged, OPTIONAL 00447 IN BOOLEAN Reverse 00448 ) 00449 00450 /*++ 00451 00452 Routine Description: 00453 00454 Enumerates the relations in a list. 00455 00456 Arguments: 00457 00458 List Relation list to be enumerated. 00459 00460 Marker Cookie used to maintain current place in the list. It 00461 must be initialized to 0 the first time 00462 IopEnumerateRelations is called. 00463 00464 DeviceObject Returned Relation. 00465 00466 DirectDescendant If specified then it is set if the relation is a direct 00467 descendant of the original target device of this remove. 00468 00469 Tagged If specified then it is set if the relation is tagged 00470 otherwise it is cleared. 00471 00472 Reverse Direction of traversal, TRUE means from deepest to 00473 closest to the root, FALSE means from the root down. 00474 00475 If Reverse changes on a subsequent call then the 00476 previously enumerated relation is skipped. For example, 00477 given the sequence A, B, C, D, E. If 00478 IopEnumerateRelations is called thrice with Reverse set 00479 to FALSE and then called repeatedly with Reverse set to 00480 TRUE until it returns FALSE, the sequence would be: A, 00481 B, C, B, A. 00482 00483 Once the end has been reached it is not possible to 00484 change directions. 00485 00486 00487 Return Value: 00488 00489 TRUE 00490 00491 DeviceObject and optionally Tagged have been set to the next relation. 00492 00493 FALSE 00494 00495 There are no more relations. 00496 00497 --*/ 00498 00499 { 00500 PRELATION_LIST_ENTRY entry; 00501 LONG levelIndex; 00502 ULONG entryIndex; 00503 00504 PAGED_CODE(); 00505 00506 // 00507 // The basic assumptions of our use of Marker is that there will never be 00508 // more than 16M DeviceNodes at any one level and that the tree will never 00509 // be more than 127 deep. 00510 // 00511 // The format of Marker is 00512 // Bit 31 = Valid (used to distinguish the initial call 00513 // Bit 30-24 = Current index into entries 00514 // Bit 23-0 = Current index into devices, 0xFFFFFF means last 00515 // 00516 if (*Marker == ~0U) { 00517 // 00518 // We've reached the end. 00519 // 00520 return FALSE; 00521 } 00522 00523 if (*Marker == 0) { 00524 // 00525 // This is the initial call to IopEnumerateRelations 00526 // 00527 if (Reverse) { 00528 // 00529 // Initialize levelIndex to the last element of Entries 00530 // 00531 levelIndex = List->MaxLevel - List->FirstLevel; 00532 } else { 00533 // 00534 // Initialize levelIndex to the first element of Entries 00535 // 00536 levelIndex = 0; 00537 } 00538 // 00539 // Initialize entryIndex to unknown element of Devices. If we are going 00540 // in reverse then this will appear to be beyond the last element and 00541 // we'll adjust it the last one. If we are going forward then this will 00542 // appear to be just prior to the first element so when we increment it, 00543 // it will become zero. 00544 // 00545 entryIndex = ~0U; 00546 } else { 00547 // 00548 // Bit 31 is our valid bit, used to distinguish level 0, device 0 from 00549 // the first time call. 00550 // 00551 ASSERT(*Marker & ((ULONG)1 << 31)); 00552 // 00553 // Current level stored in bits 30-24. 00554 // 00555 levelIndex = (*Marker >> 24) & 0x7F; 00556 // 00557 // Current device stored in bits 23-0. 00558 // 00559 entryIndex = *Marker & 0x00FFFFFF; 00560 } 00561 00562 if (Reverse) { 00563 // 00564 // We are traversing the list bottom up, from the deepest device towards 00565 // the root. 00566 // 00567 for ( ; levelIndex >= 0; levelIndex--) { 00568 00569 // 00570 // Since the Entries array can be sparse find the next allocated 00571 // Entry. 00572 // 00573 if ((entry = List->Entries[ levelIndex ]) != NULL) { 00574 00575 if (entryIndex > entry->Count) { 00576 // 00577 // entryIndex (the current one) is greater than Count, this 00578 // will be the case where it is 0xFFFFFF, in other words 00579 // unspecified. Adjust it so that it is one past the last 00580 // one in this Entry. 00581 // 00582 entryIndex = entry->Count; 00583 } 00584 00585 if (entryIndex > 0) { 00586 00587 // 00588 // The current entry is beyond the first entry so the next 00589 // entry (which is the one we are looking for is immediately 00590 // prior, adjust entryIndex. 00591 // 00592 entryIndex--; 00593 00594 // 00595 // Get the device object and remove the tag. 00596 // 00597 *DeviceObject = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ entryIndex ] & ~RELATION_FLAGS); 00598 00599 if (Tagged != NULL) { 00600 // 00601 // The caller is interested in the tag value. 00602 // 00603 *Tagged = (BOOLEAN)((ULONG_PTR)entry->Devices[ entryIndex ] & RELATION_FLAG_TAGGED); 00604 } 00605 00606 if (DirectDescendant != NULL) { 00607 // 00608 // The caller is interested in the DirectDescendant value. 00609 // 00610 *DirectDescendant = (BOOLEAN)((ULONG_PTR)entry->Devices[ entryIndex ] & RELATION_FLAG_DESCENDANT); 00611 } 00612 00613 // 00614 // Update the marker (info for current device) 00615 // 00616 *Marker = ((ULONG)1 << 31) | (levelIndex << 24) | (entryIndex & 0x00FFFFFF); 00617 00618 return TRUE; 00619 } 00620 } 00621 00622 // 00623 // The current device object has been deleted or the current 00624 // device object is the first one in this Entry. 00625 // We need to continue to search backwards through the other 00626 // Entries. 00627 // 00628 entryIndex = ~0U; 00629 } 00630 } else { 00631 for ( ; levelIndex <= (LONG)(List->MaxLevel - List->FirstLevel); levelIndex++) { 00632 00633 // 00634 // Since the Entries array can be sparse find the next allocated 00635 // Entry. 00636 // 00637 if ((entry = List->Entries[ levelIndex ]) != NULL) { 00638 00639 // 00640 // entryIndex is the index of the current device or 0xFFFFFFFF 00641 // if this is the first time we have been called or the current 00642 // current device is the last one in its Entry. Increment the 00643 // index to point to the next device. 00644 // 00645 entryIndex++; 00646 00647 if (entryIndex < entry->Count) { 00648 00649 // 00650 // The next device is within this entry. 00651 // 00652 // 00653 // Get the device object and remove the tag. 00654 // 00655 *DeviceObject = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ entryIndex ] & ~RELATION_FLAGS); 00656 00657 if (Tagged != NULL) { 00658 // 00659 // The caller is interested in the tag value. 00660 // 00661 *Tagged = (BOOLEAN)((ULONG_PTR)entry->Devices[ entryIndex ] & RELATION_FLAG_TAGGED); 00662 } 00663 00664 if (DirectDescendant != NULL) { 00665 // 00666 // The caller is interested in the DirectDescendant value. 00667 // 00668 *DirectDescendant = (BOOLEAN)((ULONG_PTR)entry->Devices[ entryIndex ] & RELATION_FLAG_DESCENDANT); 00669 } 00670 00671 // 00672 // Update the marker (info for current device) 00673 // 00674 *Marker = ((ULONG)1 << 31) | (levelIndex << 24) | (entryIndex & 0x00FFFFFF); 00675 00676 return TRUE; 00677 } 00678 } 00679 00680 // 00681 // The current device has been removed or we have processed the 00682 // last device in the current entry. 00683 // Set entryIndex so that it is just before the first device in 00684 // the next entry. Continue the search looking for the next 00685 // allocated Entry. 00686 // 00687 entryIndex = ~0U; 00688 } 00689 } 00690 00691 // 00692 // We are at the end of the list 00693 // 00694 *Marker = ~0U; 00695 *DeviceObject = NULL; 00696 00697 if (Tagged != NULL) { 00698 *Tagged = FALSE; 00699 } 00700 00701 if (DirectDescendant != NULL) { 00702 *DirectDescendant = FALSE; 00703 } 00704 00705 return FALSE; 00706 } 00707 00708 VOID 00709 IopFreeRelationList( 00710 IN PRELATION_LIST List 00711 ) 00712 00713 /*++ 00714 00715 Routine Description: 00716 00717 Free a relation list allocated by IopAllocateRelationList. 00718 00719 Arguments: 00720 00721 List The list to be freed. 00722 00723 Return Value: 00724 00725 NONE. 00726 00727 --*/ 00728 00729 { 00730 PRELATION_LIST_ENTRY entry; 00731 ULONG levelIndex; 00732 ULONG entryIndex; 00733 00734 PAGED_CODE(); 00735 00736 // 00737 // Search the list looking for allocated Entries. 00738 // 00739 for (levelIndex = 0; levelIndex <= (List->MaxLevel - List->FirstLevel); levelIndex++) { 00740 00741 if ((entry = List->Entries[ levelIndex ]) != NULL) { 00742 // 00743 // This entry has been allocated. 00744 // 00745 for (entryIndex = 0; entryIndex < entry->Count; entryIndex++) { 00746 // 00747 // Dereference all the Devices in the entry. 00748 // 00749 ObDereferenceObject((PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ entryIndex ] & ~RELATION_FLAGS)); 00750 } 00751 // 00752 // Free the Entry. 00753 // 00754 ExFreePool( entry ); 00755 } 00756 } 00757 00758 // 00759 // Free the list. It isn't necessary to dereference the DeviceObject that 00760 // was the original target that caused the list to be created. This 00761 // DeviceObject is also in one of the Entries and its reference is taken 00762 // and released there. 00763 // 00764 ExFreePool( List ); 00765 } 00766 00767 ULONG 00768 IopGetRelationsCount( 00769 PRELATION_LIST List 00770 ) 00771 00772 /*++ 00773 00774 Routine Description: 00775 00776 Returns the total number of relations (Device Objects) in all the entries. 00777 00778 Arguments: 00779 00780 List Relation List. 00781 00782 Return Value: 00783 00784 Count of relations (Device Objects). 00785 00786 --*/ 00787 00788 { 00789 PAGED_CODE(); 00790 00791 return List->Count; 00792 } 00793 00794 ULONG 00795 IopGetRelationsTaggedCount( 00796 PRELATION_LIST List 00797 ) 00798 00799 /*++ 00800 00801 Routine Description: 00802 00803 Returns the total number of relations (Device Objects) in all the entries 00804 which are tagged. 00805 00806 Arguments: 00807 00808 List Relation List. 00809 00810 Return Value: 00811 00812 Count of tagged relations (Device Objects). 00813 00814 --*/ 00815 00816 { 00817 PAGED_CODE(); 00818 00819 return List->TagCount; 00820 } 00821 00822 BOOLEAN 00823 IopIsRelationInList( 00824 PRELATION_LIST List, 00825 PDEVICE_OBJECT DeviceObject 00826 ) 00827 00828 /*++ 00829 00830 Routine Description: 00831 00832 Checks if a relation (Device Object) exists in the specified relation list. 00833 00834 Arguments: 00835 00836 List Relation list to check. 00837 00838 DeviceObject Relation to be checked. 00839 00840 00841 Return Value: 00842 00843 TRUE 00844 00845 Relation exists. 00846 00847 FALSE 00848 00849 Relation is not in the list. 00850 00851 --*/ 00852 00853 { 00854 PDEVICE_NODE deviceNode; 00855 PRELATION_LIST_ENTRY entry; 00856 ULONG level; 00857 ULONG index; 00858 00859 PAGED_CODE(); 00860 00861 if ((deviceNode = DeviceObject->DeviceObjectExtension->DeviceNode) != NULL) { 00862 // 00863 // The device object is a PDO. 00864 // 00865 level = deviceNode->Level; 00866 00867 if (List->FirstLevel <= level && level <= List->MaxLevel) { 00868 // 00869 // The level is within the range of levels stored in this list. 00870 // 00871 if ((entry = List->Entries[ level - List->FirstLevel ]) != NULL) { 00872 // 00873 // There is an Entry for this level. 00874 // 00875 for (index = 0; index < entry->Count; index++) { 00876 // 00877 // For each Device in the entry, compare it to the given 00878 // DeviceObject 00879 if (((ULONG_PTR)entry->Devices[ index ] & ~RELATION_FLAGS) == (ULONG_PTR)DeviceObject) { 00880 // 00881 // It matches 00882 // 00883 return TRUE; 00884 } 00885 } 00886 } 00887 } 00888 } 00889 00890 // 00891 // It wasn't a PDO 00892 // or the level wasn't in the range of levels in this list 00893 // or there are no DeviceObjects at the same level in this list 00894 // or the DeviceObject isn't in the Entry for its level in this list 00895 // 00896 return FALSE; 00897 } 00898 00899 NTSTATUS 00900 IopMergeRelationLists( 00901 IN OUT PRELATION_LIST TargetList, 00902 IN PRELATION_LIST SourceList, 00903 IN BOOLEAN Tagged 00904 ) 00905 00906 /*++ 00907 00908 Routine Description: 00909 00910 Merges two relation lists by copying all the relations from the source list 00911 to the target list. Source list remains unchanged. 00912 00913 Arguments: 00914 00915 TargetList List to which the relations from Sourcelist are added. 00916 00917 SourceList List of relations to be added to TargetList. 00918 00919 Tagged TRUE if relations from SourceList should be tagged when added to 00920 TargetList. If FALSE then relations added from SourceList are 00921 untagged. 00922 00923 Return Value: 00924 00925 STATUS_SUCCESS 00926 00927 All the relations in SourceList were added to TargetList successfully. 00928 00929 STATUS_OBJECT_NAME_COLLISION 00930 00931 One of the relations in SourceList already exists in TargetList. This 00932 is a fatal error and TargetList may already have some of the relations 00933 from SourceList added. This could be dealt with more gracefully if 00934 necessary but the current callers of IopMergeRelationLists avoid this 00935 situation. 00936 00937 STATUS_INSUFFICIENT_RESOURCES 00938 00939 There isn't enough PagedPool available to allocate a new 00940 RELATION_LIST_ENTRY. 00941 00942 STATUS_INVALID_PARAMETER 00943 00944 The level of one of the relations in SourceList is less than FirstLevel 00945 or greater than the MaxLevel. This is a fatal error and TargetList may 00946 already have some of the relations from SourceList added. The only way 00947 this could happen is if the tree lock isn't held or if TargetList has 00948 been compressed by IopCompressRelationList. Both situations would be 00949 bugs in the caller. 00950 00951 STATUS_NO_SUCH_DEVICE 00952 00953 One of the relations in SourceList is not a PhysicalDeviceObject (PDO), 00954 it doesn't have a DEVICE_NODE associated with it. This is a fatal error 00955 and TargetList may already have some of the relations from SourceList 00956 added. This should never happen since it was a PDO when it was added to 00957 SourceList. 00958 00959 00960 --*/ 00961 00962 { 00963 PRELATION_LIST_ENTRY entry; 00964 ULONG levelIndex; 00965 ULONG entryIndex; 00966 NTSTATUS status = STATUS_SUCCESS; 00967 00968 PAGED_CODE(); 00969 00970 // 00971 // For each level entry in SourceList 00972 // 00973 for (levelIndex = 0; 00974 levelIndex <= (SourceList->MaxLevel - SourceList->FirstLevel); 00975 levelIndex++) { 00976 00977 if ((entry = SourceList->Entries[ levelIndex ]) != NULL) { 00978 // 00979 // The Entry has Devices 00980 // 00981 for (entryIndex = 0; entryIndex < entry->Count; entryIndex++) { 00982 // 00983 // For each Device in the Entry, add it to the target List. 00984 // 00985 status = IopAddRelationToList( TargetList, 00986 (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ entryIndex ] & ~RELATION_FLAGS), 00987 FALSE, 00988 Tagged); 00989 00990 // 00991 // BUGBUG - Need to handle STATUS_INSUFFICIENT_RESOURCES more 00992 // gracefully. Currently the only way this can happen is 00993 // during Eject and that code isn't enabled yet. 00994 // 00995 ASSERT(NT_SUCCESS(status)); 00996 00997 if (!NT_SUCCESS(status)) { 00998 // 00999 // BUGBUG - We should undo the damage we've done to 01000 // TargetList by removing those relations we've added from 01001 // SourceList. 01002 // 01003 break; 01004 } 01005 } 01006 } 01007 } 01008 01009 return status; 01010 } 01011 01012 NTSTATUS 01013 IopRemoveIndirectRelationsFromList( 01014 IN PRELATION_LIST List 01015 ) 01016 01017 /*++ 01018 01019 Routine Description: 01020 01021 Removes all the relations without the DirectDescendant flag from a relation 01022 list. 01023 01024 Arguments: 01025 01026 List List from which to remove the relations. 01027 01028 01029 Return Value: 01030 01031 STATUS_SUCCESS 01032 01033 The relations were removed successfully. 01034 01035 --*/ 01036 01037 { 01038 PDEVICE_OBJECT deviceObject; 01039 PRELATION_LIST_ENTRY entry; 01040 ULONG level; 01041 LONG index; 01042 01043 PAGED_CODE(); 01044 01045 // 01046 // For each Entry in the list. 01047 // 01048 for (level = List->FirstLevel; level <= List->MaxLevel; level++) { 01049 01050 // 01051 // If the entry is allocated. 01052 // 01053 if ((entry = List->Entries[ level - List->FirstLevel ]) != NULL) { 01054 01055 // 01056 // For each Device in the list. 01057 // 01058 for (index = entry->Count - 1; index >= 0; index--) { 01059 if (!((ULONG_PTR)entry->Devices[ index ] & RELATION_FLAG_DESCENDANT)) { 01060 01061 deviceObject = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ index ] & ~RELATION_FLAGS); 01062 01063 ObDereferenceObject( deviceObject ); 01064 01065 if ((ULONG_PTR)entry->Devices[ index ] & RELATION_FLAG_TAGGED) { 01066 List->TagCount--; 01067 } 01068 01069 if (index < ((LONG)entry->Count - 1)) { 01070 01071 RtlMoveMemory( &entry->Devices[ index ], 01072 &entry->Devices[ index + 1 ], 01073 (entry->Count - index - 1) * sizeof(PDEVICE_OBJECT)); 01074 } 01075 01076 if (--entry->Count == 0) { 01077 List->Entries[ level - List->FirstLevel ] = NULL; 01078 ExFreePool(entry); 01079 } 01080 01081 List->Count--; 01082 } 01083 } 01084 } 01085 } 01086 return STATUS_SUCCESS; 01087 } 01088 01089 NTSTATUS 01090 IopRemoveRelationFromList( 01091 PRELATION_LIST List, 01092 PDEVICE_OBJECT DeviceObject 01093 ) 01094 01095 /*++ 01096 01097 Routine Description: 01098 01099 Removes a relation from a relation list. 01100 01101 Arguments: 01102 01103 List List from which to remove the relation. 01104 01105 DeviceObject Relation to remove. 01106 01107 Return Value: 01108 01109 STATUS_SUCCESS 01110 01111 The relation was removed successfully. 01112 01113 STATUS_NO_SUCH_DEVICE 01114 01115 The relation doesn't exist in the list. 01116 01117 --*/ 01118 01119 { 01120 PDEVICE_NODE deviceNode; 01121 PRELATION_LIST_ENTRY entry; 01122 ULONG level; 01123 LONG index; 01124 01125 PAGED_CODE(); 01126 01127 if ((deviceNode = DeviceObject->DeviceObjectExtension->DeviceNode) != NULL) { 01128 level = deviceNode->Level; 01129 01130 ASSERT(List->FirstLevel <= level && level <= List->MaxLevel); 01131 01132 if (List->FirstLevel <= level && level <= List->MaxLevel) { 01133 if ((entry = List->Entries[ level - List->FirstLevel ]) != NULL) { 01134 for (index = entry->Count - 1; index >= 0; index--) { 01135 if (((ULONG_PTR)entry->Devices[ index ] & ~RELATION_FLAGS) == (ULONG_PTR)DeviceObject) { 01136 01137 ObDereferenceObject( DeviceObject ); 01138 01139 if (((ULONG_PTR)entry->Devices[ index ] & RELATION_FLAG_TAGGED) != 0) { 01140 List->TagCount--; 01141 } 01142 if (index < ((LONG)entry->Count - 1)) { 01143 01144 RtlMoveMemory( &entry->Devices[ index ], 01145 &entry->Devices[ index + 1 ], 01146 (entry->Count - index - 1) * sizeof(PDEVICE_OBJECT)); 01147 } 01148 01149 if (--entry->Count == 0) { 01150 List->Entries[ level - List->FirstLevel ] = NULL; 01151 ExFreePool(entry); 01152 } 01153 01154 List->Count--; 01155 01156 return STATUS_SUCCESS; 01157 } 01158 } 01159 } 01160 } 01161 } 01162 return STATUS_NO_SUCH_DEVICE; 01163 } 01164 01165 VOID 01166 IopSetAllRelationsTags( 01167 PRELATION_LIST List, 01168 BOOLEAN Tagged 01169 ) 01170 01171 /*++ 01172 01173 Routine Description: 01174 01175 Tags or untags all the relations in a relations list. 01176 01177 Arguments: 01178 01179 List Relation list containing relations to be tagged or untagged. 01180 01181 Tagged TRUE if the relations should be tagged, FALSE if they are to be 01182 untagged. 01183 01184 Return Value: 01185 01186 NONE 01187 01188 --*/ 01189 01190 { 01191 PRELATION_LIST_ENTRY entry; 01192 ULONG level; 01193 ULONG index; 01194 01195 PAGED_CODE(); 01196 01197 // 01198 // For each Entry in the list. 01199 // 01200 for (level = List->FirstLevel; level <= List->MaxLevel; level++) { 01201 01202 // 01203 // If the entry is allocated. 01204 // 01205 if ((entry = List->Entries[ level - List->FirstLevel ]) != NULL) { 01206 01207 // 01208 // For each Device in the list. 01209 // 01210 for (index = 0; index < entry->Count; index++) { 01211 01212 // 01213 // Set or clear the tag based on the argument Tagged. 01214 // 01215 if (Tagged) { 01216 entry->Devices[ index ] = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ index ] | RELATION_FLAG_TAGGED); 01217 } else { 01218 entry->Devices[ index ] = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ index ] & ~RELATION_FLAG_TAGGED); 01219 } 01220 } 01221 } 01222 } 01223 01224 // 01225 // If we are setting the tags then update the TagCount to the number of 01226 // relations in the list. Otherwise reset it to zero. 01227 // 01228 List->TagCount = Tagged ? List->Count : 0; 01229 } 01230 01231 NTSTATUS 01232 IopSetRelationsTag( 01233 IN PRELATION_LIST List, 01234 IN PDEVICE_OBJECT DeviceObject, 01235 IN BOOLEAN Tagged 01236 ) 01237 01238 /*++ 01239 01240 Routine Description: 01241 01242 Sets or clears a tag on a specified relation in a relations list. This 01243 routine is also used by some callers to determine if a relation exists in 01244 a list and if so to set the tag. 01245 01246 Arguments: 01247 01248 List List containing relation to be tagged or untagged. 01249 01250 DeviceObject Relation to be tagged or untagged. 01251 01252 Tagged TRUE if relation is to be tagged, FALSE if it is to be 01253 untagged. 01254 01255 Return Value: 01256 01257 STATUS_SUCCESS 01258 01259 The relation was tagged successfully. 01260 01261 STATUS_NO_SUCH_DEVICE 01262 01263 The relation doesn't exist in the list. 01264 01265 --*/ 01266 01267 { 01268 PDEVICE_NODE deviceNode; 01269 PRELATION_LIST_ENTRY entry; 01270 ULONG level; 01271 LONG index; 01272 01273 PAGED_CODE(); 01274 01275 if ((deviceNode = DeviceObject->DeviceObjectExtension->DeviceNode) != NULL) { 01276 // 01277 // DeviceObject is a PhysicalDeviceObject (PDO), get its level. 01278 // 01279 level = deviceNode->Level; 01280 01281 if (List->FirstLevel <= level && level <= List->MaxLevel) { 01282 // 01283 // The level is within the range of levels in this List. 01284 // 01285 if ((entry = List->Entries[ level - List->FirstLevel ]) != NULL) { 01286 // 01287 // The Entry for this level is allocated. Search each device 01288 // in the Entry looking for a match. 01289 // 01290 for (index = entry->Count - 1; index >= 0; index--) { 01291 01292 if (((ULONG_PTR)entry->Devices[ index ] & ~RELATION_FLAGS) == (ULONG_PTR)DeviceObject) { 01293 01294 // 01295 // We found a match 01296 // 01297 if ((ULONG_PTR)entry->Devices[ index ] & RELATION_FLAG_TAGGED) { 01298 // 01299 // The relation is already tagged so to simplify the 01300 // logic below decrement the TagCount. We'll 01301 // increment it later if the caller still wants it 01302 // to be tagged. 01303 // 01304 List->TagCount--; 01305 } 01306 01307 if (Tagged) { 01308 // 01309 // Set the tag and increment the number of tagged 01310 // relations. 01311 // 01312 entry->Devices[ index ] = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ index ] | RELATION_FLAG_TAGGED); 01313 List->TagCount++; 01314 } else { 01315 // 01316 // Clear the tag. 01317 // 01318 entry->Devices[ index ] = (PDEVICE_OBJECT)((ULONG_PTR)entry->Devices[ index ] & ~RELATION_FLAG_TAGGED); 01319 } 01320 01321 return STATUS_SUCCESS; 01322 } 01323 } 01324 } 01325 } 01326 } 01327 01328 // 01329 // It wasn't a PDO 01330 // or the level wasn't in the range of levels in this list 01331 // or there are no DeviceObjects at the same level in this list 01332 // or the DeviceObject isn't in the Entry for its level in this list 01333 // 01334 return STATUS_NO_SUCH_DEVICE; 01335 } 01336

Generated on Sat May 15 19:41:23 2004 for test by doxygen 1.3.7