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

devnode.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1996 Microsoft Corporation 00004 00005 Module Name: 00006 00007 devnode.c 00008 00009 Abstract: 00010 00011 This file contains routines to maintain our private device node list. 00012 00013 Author: 00014 00015 Forrest Foltz (forrestf) 27-Mar-1996 00016 00017 Revision History: 00018 00019 Modified for nt kernel. 00020 00021 --*/ 00022 00023 #include "iop.h" 00024 00025 // 00026 // Internal definitions 00027 // 00028 00029 typedef struct _ENUM_CONTEXT{ 00030 PENUM_CALLBACK CallersCallback; 00031 PVOID CallersContext; 00032 } ENUM_CONTEXT, *PENUM_CONTEXT; 00033 00034 // 00035 // Internal References 00036 // 00037 00038 NTSTATUS 00039 IopForAllDeviceNodesCallback( 00040 IN PDEVICE_NODE DeviceNode, 00041 IN PVOID Context 00042 ); 00043 00044 #ifdef ALLOC_PRAGMA 00045 #pragma alloc_text(PAGE, IopAllocateDeviceNode) 00046 #pragma alloc_text(PAGE, IopForAllDeviceNodes) 00047 #pragma alloc_text(PAGE, IopForAllChildDeviceNodes) 00048 #pragma alloc_text(PAGE, IopForAllDeviceNodesCallback) 00049 #pragma alloc_text(PAGE, IopDestroyDeviceNode) 00050 #pragma alloc_text(PAGE, IopInsertTreeDeviceNode) 00051 #pragma alloc_text(PAGE, IopRemoveTreeDeviceNode) 00052 #endif 00053 00054 00055 PDEVICE_NODE 00056 IopAllocateDeviceNode( 00057 IN PDEVICE_OBJECT PhysicalDeviceObject 00058 ) 00059 00060 /*++ 00061 00062 Routine Description: 00063 00064 This function allocates a device node from nonpaged pool and initializes 00065 the fields which do not require to hold lock to do so. Since adding 00066 the device node to pnp mgr's device node tree requires acquiring lock, 00067 this routine does not add the device node to device node tree. 00068 00069 Arguments: 00070 00071 PhysicalDeviceObject - Supplies a pointer to its corresponding physical device 00072 object. 00073 00074 Return Value: 00075 00076 a pointer to the newly created device node. Null is returned if failed. 00077 00078 --*/ 00079 { 00080 PDEVICE_NODE deviceNode; 00081 00082 PAGED_CODE(); 00083 00084 deviceNode = ExAllocatePoolWithTag( 00085 NonPagedPool, 00086 sizeof(DEVICE_NODE), 00087 IOP_DNOD_TAG 00088 ); 00089 00090 if (deviceNode == NULL ){ 00091 return NULL; 00092 } 00093 00094 InterlockedIncrement (&IopNumberDeviceNodes); 00095 00096 RtlZeroMemory(deviceNode, sizeof(DEVICE_NODE)); 00097 deviceNode->InterfaceType = InterfaceTypeUndefined; 00098 deviceNode->BusNumber = (ULONG)-1; 00099 deviceNode->ChildInterfaceType = InterfaceTypeUndefined; 00100 deviceNode->ChildBusNumber = (ULONG)-1; 00101 deviceNode->ChildBusTypeIndex = (USHORT)-1; 00102 00103 KeInitializeEvent( &deviceNode->EnumerationMutex, 00104 SynchronizationEvent, 00105 TRUE ); 00106 00107 InitializeListHead(&deviceNode->DeviceArbiterList); 00108 InitializeListHead(&deviceNode->DeviceTranslatorList); 00109 00110 if (PhysicalDeviceObject){ 00111 00112 deviceNode->PhysicalDeviceObject = PhysicalDeviceObject; 00113 PhysicalDeviceObject->DeviceObjectExtension->DeviceNode = (PVOID)deviceNode; 00114 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 00115 } 00116 00117 InitializeListHead(&deviceNode->TargetDeviceNotify); 00118 00119 InitializeListHead(&deviceNode->DockInfo.ListEntry); 00120 00121 InitializeListHead(&deviceNode->PendedSetInterfaceState); 00122 00123 return deviceNode; 00124 } 00125 00126 NTSTATUS 00127 IopForAllDeviceNodes( 00128 IN PENUM_CALLBACK Callback, 00129 IN PVOID Context 00130 ) 00131 00132 /*++ 00133 00134 Routine Description: 00135 00136 This function walks the device node tree and perform caller specified 00137 'Callback' function for each device node. 00138 00139 Note, this routine (or its worker routine) traverses the tree in a top 00140 down manner. 00141 00142 Arguments: 00143 00144 Callback - Supplies the call back routine for each device node. 00145 00146 Context - Supplies a parameter/context for the callback function. 00147 00148 Return Value: 00149 00150 Status returned from Callback, if not successfull then the tree walking stops. 00151 00152 --*/ 00153 { 00154 ENUM_CONTEXT enumContext; 00155 NTSTATUS status; 00156 00157 PAGED_CODE(); 00158 00159 enumContext.CallersCallback = Callback; 00160 enumContext.CallersContext = Context; 00161 00162 // 00163 // Start with a pointer to the root device node, recursively examine all the 00164 // children until we the callback function says stop or we've looked at all 00165 // of them. 00166 // 00167 00168 IopAcquireEnumerationLock(IopRootDeviceNode); 00169 00170 status = IopForAllChildDeviceNodes(IopRootDeviceNode, 00171 IopForAllDeviceNodesCallback, 00172 (PVOID)&enumContext ); 00173 00174 IopReleaseEnumerationLock(IopRootDeviceNode); 00175 return status; 00176 } 00177 00178 NTSTATUS 00179 IopForAllChildDeviceNodes( 00180 IN PDEVICE_NODE Parent, 00181 IN PENUM_CALLBACK Callback, 00182 IN PVOID Context 00183 ) 00184 00185 /*++ 00186 00187 Routine Description: 00188 00189 This function walks the Parent's device node subtree and perform caller specified 00190 'Callback' function for each device node under Parent. 00191 00192 Note, befor calling this rotuine, callers must acquire the enumeration mutex 00193 of the 'Parent' device node to make sure its children won't go away unless the 00194 call tells them to. 00195 00196 Arguments: 00197 00198 Parent - Supplies a pointer to the device node whose subtree is to be walked. 00199 00200 Callback - Supplies the call back routine for each device node. 00201 00202 Context - Supplies a parameter/context for the callback function. 00203 00204 Return Value: 00205 00206 NTSTATUS value. 00207 00208 --*/ 00209 00210 { 00211 PDEVICE_NODE nextChild = Parent->Child; 00212 PDEVICE_NODE child; 00213 NTSTATUS status = STATUS_SUCCESS; 00214 00215 PAGED_CODE(); 00216 00217 // 00218 // Process siblings until we find the end of the sibling list or 00219 // the Callback() returns FALSE. Set result = TRUE at the top of 00220 // the loop so that if there are no siblings we will return TRUE, 00221 // e.g. Keep Enumerating. 00222 // 00223 // Note, we need to find next child before calling Callback function 00224 // in case the current child is deleted by the Callback function. 00225 // 00226 00227 while (nextChild && NT_SUCCESS(status)) { 00228 child = nextChild; 00229 nextChild = child->Sibling; 00230 status = Callback(child, Context); 00231 } 00232 00233 return status; 00234 } 00235 00236 NTSTATUS 00237 IopForAllDeviceNodesCallback( 00238 IN PDEVICE_NODE DeviceNode, 00239 IN PVOID Context 00240 ) 00241 00242 /*++ 00243 00244 Routine Description: 00245 00246 This function is the worker routine for IopForAllChildDeviceNodes routine. 00247 00248 Arguments: 00249 00250 DeviceNode - Supplies a pointer to the device node whose subtree is to be walked. 00251 00252 Context - Supplies a context which contains the caller specified call back 00253 function and parameter. 00254 00255 Return Value: 00256 00257 NTSTATUS value. 00258 00259 --*/ 00260 00261 { 00262 PENUM_CONTEXT enumContext; 00263 NTSTATUS status; 00264 00265 PAGED_CODE(); 00266 00267 enumContext = (PENUM_CONTEXT)Context; 00268 00269 // 00270 // First call the caller's callback for this devnode 00271 // 00272 00273 status = 00274 enumContext->CallersCallback(DeviceNode, enumContext->CallersContext); 00275 00276 if (NT_SUCCESS(status)) { 00277 00278 // 00279 // Now enumerate the children, if any. 00280 // 00281 00282 IopAcquireEnumerationLock(DeviceNode); 00283 00284 if( DeviceNode->Child) { 00285 00286 status = IopForAllChildDeviceNodes( 00287 DeviceNode, 00288 IopForAllDeviceNodesCallback, 00289 Context); 00290 } 00291 IopReleaseEnumerationLock(DeviceNode); 00292 } 00293 00294 return status; 00295 } 00296 VOID 00297 IopDestroyDeviceNode( 00298 IN PDEVICE_NODE DeviceNode 00299 ) 00300 00301 /*++ 00302 00303 Routine Description: 00304 00305 This function is invoked by IopDeleteDevice to clean up the device object's 00306 device node structure. 00307 00308 Arguments: 00309 00310 DeviceNode - Supplies a pointer to the device node whose subtree is to be walked. 00311 00312 Context - Supplies a context which contains the caller specified call back 00313 function and parameter. 00314 00315 Return Value: 00316 00317 NTSTATUS value. 00318 00319 --*/ 00320 00321 { 00322 PLIST_ENTRY listHead, nextEntry, entry; 00323 PPI_RESOURCE_TRANSLATOR_ENTRY handlerEntry; 00324 PINTERFACE interface; 00325 00326 PAGED_CODE(); 00327 00328 if (DeviceNode) { 00329 00330 if ((DeviceNode->PhysicalDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) && 00331 DeviceNode->Parent != NULL) { 00332 00333 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 00334 PNP_ERR_ACTIVE_PDO_FREED, 00335 (ULONG_PTR)DeviceNode->PhysicalDeviceObject, 00336 0, 00337 0); 00338 } 00339 00340 #if DBG 00341 00342 // 00343 // If Only Parent is NOT NULL, most likely the driver forgot to 00344 // release resources before deleting its FDO. (The driver previously 00345 // call legacy assign resource interface.) 00346 // 00347 00348 ASSERT(DeviceNode->Child == NULL && 00349 DeviceNode->Sibling == NULL && 00350 DeviceNode->LastChild == NULL 00351 ); 00352 00353 ASSERT(DeviceNode->DockInfo.SerialNumber == NULL && 00354 IsListEmpty(&DeviceNode->DockInfo.ListEntry)); 00355 00356 if (DeviceNode->PhysicalDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) { 00357 ASSERT (DeviceNode->Parent == 0); 00358 } 00359 00360 if (DeviceNode->PreviousResourceList) { 00361 ExFreePool(DeviceNode->PreviousResourceList); 00362 } 00363 if (DeviceNode->PreviousResourceRequirements) { 00364 ExFreePool(DeviceNode->PreviousResourceRequirements); 00365 } 00366 00367 // 00368 // device should not appear to be not-disableable if/when we get here 00369 // if either of these two lines ASSERT, email: jamiehun 00370 // 00371 00372 ASSERT((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) == 0); 00373 ASSERT(DeviceNode->DisableableDepends == 0); 00374 00375 #endif 00376 // 00377 // If this devicenode is our internal one used for legacy 00378 // resource allocation, then clean up. Find this devicenode 00379 // in the list of legacy resource devnodes hanging off the 00380 // legacy devicenode in the tree and remove it. 00381 // 00382 // BUGBUG: SantoshJ 10/15/99: We should be releasing 00383 // resources assigned to this device. 00384 // 00385 00386 if (DeviceNode->Flags & DNF_LEGACY_RESOURCE_DEVICENODE) { 00387 00388 PDEVICE_NODE resourceDeviceNode; 00389 00390 for ( resourceDeviceNode = (PDEVICE_NODE)DeviceNode->OverUsed1.LegacyDeviceNode; 00391 resourceDeviceNode; 00392 resourceDeviceNode = resourceDeviceNode->OverUsed2.NextResourceDeviceNode) { 00393 00394 if (resourceDeviceNode->OverUsed2.NextResourceDeviceNode == DeviceNode) { 00395 00396 resourceDeviceNode->OverUsed2.NextResourceDeviceNode = DeviceNode->OverUsed2.NextResourceDeviceNode; 00397 break; 00398 00399 } 00400 } 00401 } 00402 00403 if (DeviceNode->DuplicatePDO) { 00404 ObDereferenceObject(DeviceNode->DuplicatePDO); 00405 } 00406 if (DeviceNode->ServiceName.Length != 0) { 00407 ExFreePool(DeviceNode->ServiceName.Buffer); 00408 } 00409 if (DeviceNode->InstancePath.Length != 0) { 00410 ExFreePool(DeviceNode->InstancePath.Buffer); 00411 } 00412 if (DeviceNode->ResourceRequirements) { 00413 ExFreePool(DeviceNode->ResourceRequirements); 00414 } 00415 00416 // 00417 // Dereference all the arbiters and translators on this PDO. 00418 // 00419 IopUncacheInterfaceInformation(DeviceNode->PhysicalDeviceObject) ; 00420 00421 // 00422 // Release any pended IoSetDeviceInterface structures 00423 // 00424 00425 while (!IsListEmpty(&DeviceNode->PendedSetInterfaceState)) { 00426 00427 PPENDING_SET_INTERFACE_STATE entry; 00428 00429 entry = (PPENDING_SET_INTERFACE_STATE)RemoveHeadList(&DeviceNode->PendedSetInterfaceState); 00430 00431 ExFreePool(entry->LinkName.Buffer); 00432 00433 ExFreePool(entry); 00434 } 00435 00436 DeviceNode->PhysicalDeviceObject->DeviceObjectExtension->DeviceNode = NULL; 00437 ExFreePool(DeviceNode); 00438 IopNumberDeviceNodes--; 00439 } 00440 } 00441 // 00442 // Code to support Power manager's need to traverse the device node tree in inverse order, 00443 // (from the leaves towards the root.) 00444 // 00445 00446 VOID 00447 IopInsertTreeDeviceNode ( 00448 IN PDEVICE_NODE ParentNode, 00449 IN PDEVICE_NODE DeviceNode 00450 ) 00451 // N.B. Caller must own the device tree lock 00452 { 00453 PDEVICE_NODE deviceNode; 00454 PLIST_ENTRY *p; 00455 LONG i; 00456 00457 // 00458 // Put this devnode at the end of the parent's list of children. 00459 // 00460 00461 DeviceNode->Parent = ParentNode; 00462 if (ParentNode->LastChild) { 00463 ASSERT(ParentNode->LastChild->Sibling == NULL); 00464 ParentNode->LastChild->Sibling = DeviceNode; 00465 ParentNode->LastChild = DeviceNode; 00466 } else { 00467 ASSERT(ParentNode->Child == NULL); 00468 ParentNode->Child = ParentNode->LastChild = DeviceNode; 00469 } 00470 00471 // 00472 // Determine the depth of the devnode. 00473 // 00474 00475 for (deviceNode = DeviceNode; 00476 deviceNode != IopRootDeviceNode; 00477 deviceNode = deviceNode->Parent) { 00478 DeviceNode->Level++; 00479 } 00480 00481 if (DeviceNode->Level > IopMaxDeviceNodeLevel) { 00482 IopMaxDeviceNodeLevel = DeviceNode->Level; 00483 } 00484 00485 // 00486 // Tree has changed 00487 // 00488 00489 IoDeviceNodeTreeSequence += 1; 00490 } 00491 00492 00493 VOID 00494 IopRemoveTreeDeviceNode ( 00495 IN PDEVICE_NODE DeviceNode 00496 ) 00497 /*++ 00498 00499 Routine Description: 00500 00501 This function removes the device node from the device node tree 00502 00503 N.B. The caller must own the device tree lock of the parent's enumeration lock 00504 00505 Arguments: 00506 00507 DeviceNode - Device node to remove 00508 00509 Return Value: 00510 00511 00512 --*/ 00513 { 00514 PDEVICE_NODE *Node; 00515 00516 // 00517 // Ulink the pointer to this device node. (If this is the 00518 // first entry, unlink it from the parents child pointer, else 00519 // remove it from the sibling list) 00520 // 00521 00522 Node = &DeviceNode->Parent->Child; 00523 while (*Node != DeviceNode) { 00524 Node = &(*Node)->Sibling; 00525 } 00526 *Node = DeviceNode->Sibling; 00527 00528 if (DeviceNode->Parent->Child == NULL) { 00529 DeviceNode->Parent->LastChild = NULL; 00530 } else { 00531 while (*Node) { 00532 Node = &(*Node)->Sibling; 00533 } 00534 DeviceNode->Parent->LastChild = CONTAINING_RECORD(Node, DEVICE_NODE, Sibling); 00535 } 00536 00537 00538 // 00539 // Orphan any outstanding device change notifications on these nodes. 00540 // 00541 IopOrphanNotification(DeviceNode); 00542 00543 // 00544 // No longer linked 00545 // 00546 00547 DeviceNode->Parent = NULL; 00548 DeviceNode->Child = NULL; 00549 DeviceNode->Sibling = NULL; 00550 DeviceNode->LastChild = NULL; 00551 } 00552 00553 #if DBG 00554 00555 VOID 00556 IopCheckForTargetDevice ( 00557 IN PDEVICE_OBJECT TargetDevice, 00558 IN PDEVICE_OBJECT DeviceObject 00559 ) 00560 { 00561 if (!TargetDevice || !DeviceObject) { 00562 return ; 00563 } 00564 00565 ASSERT (DeviceObject != TargetDevice); 00566 00567 while (DeviceObject->AttachedDevice) { 00568 DeviceObject = DeviceObject->AttachedDevice; 00569 ASSERT (DeviceObject != TargetDevice); 00570 } 00571 } 00572 00573 VOID 00574 IopCheckDeviceNodeTree ( 00575 IN PDEVICE_OBJECT TargetDevice OPTIONAL, 00576 IN PDEVICE_NODE TargetNode OPTIONAL 00577 ) 00578 // scan the device node tree and make sure this TargetDevice and TargetNode 00579 // are not in the tree 00580 { 00581 KIRQL OldIrql; 00582 PDEVICE_NODE Node; 00583 00584 return ; // bugbug: not tested 00585 00586 IopAcquireDeviceTreeLock(); 00587 ExAcquireSpinLock (&IopDatabaseLock, &OldIrql); 00588 00589 // 00590 // Find left most node 00591 // 00592 00593 Node = IopRootDeviceNode; 00594 while (Node->Child) { 00595 Node = Node->Child; 00596 } 00597 00598 // 00599 // Run the entire tree 00600 // 00601 00602 while (Node != IopRootDeviceNode) { 00603 00604 // 00605 // Verify this isn't the target node 00606 // 00607 00608 ASSERT (Node != TargetNode); 00609 00610 // 00611 // Verify target device isn't on the node somehow 00612 // 00613 00614 IopCheckForTargetDevice (TargetDevice, Node->PhysicalDeviceObject); 00615 IopCheckForTargetDevice (TargetDevice, Node->DuplicatePDO); 00616 00617 // 00618 // Next node 00619 // 00620 00621 if (Node->Sibling) { 00622 Node = Node->Sibling; 00623 while (Node->Child) { 00624 Node = Node->Child; 00625 } 00626 } else { 00627 Node = Node->Parent; 00628 } 00629 } 00630 00631 ExReleaseSpinLock (&IopDatabaseLock, OldIrql); 00632 IopReleaseDeviceTreeLock (); 00633 00634 } 00635 #endif 00636

Generated on Sat May 15 19:39:40 2004 for test by doxygen 1.3.7