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

pnpdel.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1996 Microsoft Corporation 00004 00005 Module Name: 00006 00007 enum.c 00008 00009 Abstract: 00010 00011 This module contains routines to perform device removal 00012 00013 Author: 00014 00015 Robert B. Nelson (RobertN) Jun 1, 1998. 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "iop.h" 00022 #include "wdmguid.h" 00023 00024 #ifdef POOL_TAGGING 00025 #undef ExAllocatePool 00026 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'edpP') 00027 #endif 00028 00029 // 00030 // Kernel mode PNP specific routines. 00031 // 00032 00033 NTSTATUS 00034 IopCancelPendingEject( 00035 IN PPENDING_RELATIONS_LIST_ENTRY EjectEntry 00036 ); 00037 00038 VOID 00039 IopDelayedRemoveWorker( 00040 IN PVOID Context 00041 ); 00042 00043 BOOLEAN 00044 IopDeleteLockedDeviceNode( 00045 IN PDEVICE_NODE DeviceNode, 00046 IN ULONG IrpCode, 00047 IN PRELATION_LIST RelationsList, 00048 IN BOOLEAN IsKernelInitiated, 00049 IN ULONG Problem 00050 ); 00051 00052 NTSTATUS 00053 IopProcessRelation( 00054 IN PDEVICE_OBJECT DeviceObject, 00055 IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode, 00056 IN PRELATION_LIST RelationsList, 00057 IN BOOLEAN IsKernelInitiated, 00058 IN BOOLEAN IsDirectDescendant 00059 ); 00060 00061 NTSTATUS 00062 IopUnloadAttachedDriver( 00063 IN PDRIVER_OBJECT DriverObject 00064 ); 00065 00066 WORK_QUEUE_ITEM IopDeviceRemovalWorkItem; 00067 00068 #ifdef ALLOC_PRAGMA 00069 #pragma alloc_text(PAGE, IopChainDereferenceComplete) 00070 #pragma alloc_text(PAGE, IopDelayedRemoveWorker) 00071 #pragma alloc_text(PAGE, IopDeleteLockedDeviceNode) 00072 #pragma alloc_text(PAGE, IopDeleteLockedDeviceNodes) 00073 #pragma alloc_text(PAGE, IopLockDeviceRemovalRelations) 00074 #pragma alloc_text(PAGE, IopProcessCompletedEject) 00075 #pragma alloc_text(PAGE, IopProcessRelation) 00076 #pragma alloc_text(PAGE, IopQueuePendingEject) 00077 #pragma alloc_text(PAGE, IopQueuePendingSurpriseRemoval) 00078 #pragma alloc_text(PAGE, IopRequestDeviceRemoval) 00079 #pragma alloc_text(PAGE, IopUnloadAttachedDriver) 00080 #pragma alloc_text(PAGE, IopUnlockDeviceRemovalRelations) 00081 #endif 00082 00083 VOID 00084 IopChainDereferenceComplete( 00085 IN PDEVICE_OBJECT PhysicalDeviceObject 00086 ) 00087 00088 /*++ 00089 00090 Routine Description: 00091 00092 This routine is invoked when the reference count on a PDO and all its 00093 attached devices transitions to a zero. It tags the devnode as ready for 00094 removal. If all the devnodes are tagged then IopDelayedRemoveWorker is 00095 called to actually send the remove IRPs. 00096 00097 Arguments: 00098 00099 PhysicalDeviceObject - Supplies a pointer to the PDO whose references just 00100 went to zero. 00101 00102 Return Value: 00103 00104 None. 00105 00106 --*/ 00107 00108 { 00109 PPENDING_RELATIONS_LIST_ENTRY entry; 00110 PLIST_ENTRY link; 00111 ULONG count; 00112 ULONG taggedCount; 00113 NTSTATUS status; 00114 00115 PAGED_CODE(); 00116 00117 // 00118 // Lock the whole device node tree so no one can touch the tree. 00119 // 00120 00121 IopAcquireDeviceTreeLock(); 00122 00123 // 00124 // Find the relation list this devnode is a member of. 00125 // 00126 for (link = IopPendingSurpriseRemovals.Flink; 00127 link != &IopPendingSurpriseRemovals; 00128 link = link->Flink) { 00129 00130 entry = CONTAINING_RECORD(link, PENDING_RELATIONS_LIST_ENTRY, Link); 00131 00132 // 00133 // Tag the devnode as ready for remove. If it isn't in this list 00134 // 00135 status = IopSetRelationsTag( entry->RelationsList, PhysicalDeviceObject, TRUE ); 00136 00137 if (NT_SUCCESS(status)) { 00138 taggedCount = IopGetRelationsTaggedCount( entry->RelationsList ); 00139 count = IopGetRelationsCount( entry->RelationsList ); 00140 00141 if (taggedCount == count) { 00142 // 00143 // Remove relations list from list of pending surprise removals. 00144 // 00145 RemoveEntryList( link ); 00146 00147 IopReleaseDeviceTreeLock(); 00148 00149 if (PsGetCurrentProcess() != PsInitialSystemProcess) { 00150 00151 // 00152 // Queue a work item to do the removal so we call the driver 00153 // in the system process context rather than the random one 00154 // we're in now. 00155 // 00156 00157 ExInitializeWorkItem( &entry->WorkItem, 00158 IopDelayedRemoveWorker, 00159 entry); 00160 00161 ExQueueWorkItem(&entry->WorkItem, DelayedWorkQueue); 00162 00163 } else { 00164 00165 // 00166 // We are already in the system process, so call the 00167 // worker inline. 00168 // 00169 00170 IopDelayedRemoveWorker( entry ); 00171 00172 } 00173 00174 return; 00175 } 00176 00177 break; 00178 } 00179 } 00180 00181 IopReleaseDeviceTreeLock(); 00182 00183 ASSERT(link != &IopPendingSurpriseRemovals); 00184 } 00185 00186 VOID 00187 IopDelayedRemoveWorker( 00188 IN PVOID Context 00189 ) 00190 00191 /*++ 00192 00193 Routine Description: 00194 00195 This routine is usually called from a worker thread to actually send the 00196 remove IRPs once the reference count on a PDO and all its attached devices 00197 transitions to a zero. 00198 00199 Arguments: 00200 00201 Context - Supplies a pointer to the pending relations list entry which has 00202 the relations list of PDOs we need to remove. 00203 00204 Return Value: 00205 00206 None. 00207 00208 --*/ 00209 00210 { 00211 PPENDING_RELATIONS_LIST_ENTRY entry = (PPENDING_RELATIONS_LIST_ENTRY)Context; 00212 00213 PAGED_CODE(); 00214 00215 IopSetAllRelationsTags( entry->RelationsList, FALSE ); 00216 00217 IopDeleteLockedDeviceNodes( entry->DeviceObject, 00218 entry->RelationsList, 00219 RemoveDevice, // OperationCode 00220 TRUE, // IsKernelInitiated 00221 FALSE, // ProcessIndirectDescendants 00222 entry->Problem, // Problem 00223 NULL); // VetoingDevice 00224 00225 IopFreeRelationList( entry->RelationsList ); 00226 00227 ExFreePool( entry ); 00228 } 00229 00230 00231 BOOLEAN 00232 IopDeleteLockedDeviceNode( 00233 IN PDEVICE_NODE DeviceNode, 00234 IN ULONG IrpCode, 00235 IN PRELATION_LIST RelationsList, 00236 IN BOOLEAN IsKernelInitiated, 00237 IN ULONG Problem 00238 ) 00239 00240 /*++ 00241 00242 Routine Description: 00243 00244 This function assumes that the specified device is a bus and will 00245 recursively remove all its children. 00246 00247 Arguments: 00248 00249 DeviceNode - Supplies a pointer to the device node to be removed. 00250 00251 Return Value: 00252 00253 NTSTATUS code. 00254 00255 --*/ 00256 00257 { 00258 PDEVICE_OBJECT deviceObject = DeviceNode->PhysicalDeviceObject; 00259 PDEVICE_OBJECT *attachedDevices, device1, *device2; 00260 PDRIVER_OBJECT *attachedDrivers, *driver; 00261 ULONG length = 0; 00262 BOOLEAN success = TRUE; 00263 NTSTATUS status; 00264 00265 PAGED_CODE(); 00266 00267 PIDBGMSG( PIDBG_REMOVAL, 00268 ("IopDeleteLockedDeviceNode: Entered\n DeviceNode = 0x%p\n IrpCode = 0x%08X\n RelationsList = 0x%p\n IsKernelInitiated = %d\n Problem = %d\n", 00269 DeviceNode, 00270 IrpCode, 00271 RelationsList, 00272 IsKernelInitiated, 00273 Problem)); 00274 00275 // 00276 // If this device has been deleted, simply return. 00277 // 00278 00279 if (!IsKernelInitiated && !(DeviceNode->Flags & DNF_ADDED)) { 00280 PIDBGMSG(PIDBG_REMOVAL, ("IopDeleteLockedDeviceNode: Device already deleted\n")); 00281 if (IrpCode == IRP_MN_REMOVE_DEVICE) { 00282 while (deviceObject) { 00283 deviceObject->DeviceObjectExtension->ExtensionFlags &= ~(DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED); 00284 deviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING; 00285 deviceObject = deviceObject->AttachedDevice; 00286 } 00287 } 00288 return TRUE; 00289 } 00290 00291 if (IrpCode == IRP_MN_SURPRISE_REMOVAL) { 00292 00293 // 00294 // Send irp to remove the device... 00295 // 00296 00297 PIDBGMSG( PIDBG_REMOVAL, 00298 ("IopDeleteLockedDeviceNode: Sending surprise remove irp to device = 0x%p\n", 00299 deviceObject)); 00300 00301 status = IopRemoveDevice(deviceObject, IRP_MN_SURPRISE_REMOVAL); 00302 00303 if (NT_SUCCESS(status)) { 00304 00305 PIDBGMSG(PIDBG_REMOVAL, ("IopDeleteLockedDeviceNode: Releasing devices resources\n")); 00306 00307 IopReleaseDeviceResources(DeviceNode, FALSE); 00308 00309 } else if (!(DeviceNode->Flags & DNF_NO_RESOURCE_REQUIRED)) { 00310 success = FALSE; 00311 } 00312 00313 ASSERT(DeviceNode->DockInfo.DockStatus != DOCK_ARRIVING); 00314 00315 } else if (IrpCode == IRP_MN_REMOVE_DEVICE) { 00316 00317 PDEVICE_NODE child, nextChild, parent; 00318 PDEVICE_OBJECT childPDO; 00319 00320 // 00321 // Make sure we WILL drop our references to its children. 00322 // 00323 00324 child = DeviceNode->Child; 00325 while (child) { 00326 if (child->Flags & DNF_ENUMERATED) { 00327 child->Flags &= ~DNF_ENUMERATED; 00328 } 00329 00330 ASSERT(!(child->Flags & DNF_ADDED)); 00331 00332 if (child->Flags & (DNF_HAS_RESOURCE | DNF_RESOURCE_REPORTED | DNF_HAS_BOOT_CONFIG)) { 00333 00334 // 00335 // Send irp to remove the about to be orphaned child device... 00336 // 00337 00338 PIDBGMSG( PIDBG_REMOVAL, 00339 ("IopDeleteLockedDeviceNode: Sending remove irp to orphaned child device = 0x%p\n", 00340 child->PhysicalDeviceObject)); 00341 00342 IopRemoveDevice(child->PhysicalDeviceObject, IRP_MN_REMOVE_DEVICE); 00343 00344 PIDBGMSG(PIDBG_REMOVAL, 00345 ("IopDeleteLockedDeviceNode: Releasing resources for child device = 0x%p\n", 00346 child->PhysicalDeviceObject)); 00347 00348 IopReleaseDeviceResources(child, FALSE); 00349 00350 // 00351 // BUGBUG - what if the resources aren't released??? 00352 // 00353 } 00354 00355 // 00356 // 00357 nextChild = child->Sibling; 00358 parent = child->Parent; 00359 00360 PIDBGMSG( PIDBG_REMOVAL, 00361 ("IopDeleteLockedDeviceNode: Cleaning up registry values, instance = %wZ\n", 00362 &child->InstancePath)); 00363 00364 KeEnterCriticalRegion(); 00365 ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE); 00366 00367 IopCleanupDeviceRegistryValues(&child->InstancePath, FALSE); 00368 00369 PIDBGMSG( PIDBG_REMOVAL, 00370 ("IopDeleteLockedDeviceNode: Removing DevNode tree, DevNode = 0x%p\n", 00371 child)); 00372 00373 childPDO = child->PhysicalDeviceObject; 00374 IopRemoveTreeDeviceNode(child); 00375 IopRemoveRelationFromList(RelationsList, childPDO); 00376 ObDereferenceObject(childPDO); // Added during Enum 00377 00378 ExReleaseResource(&PpRegistryDeviceResource); 00379 KeLeaveCriticalRegion(); 00380 00381 if (child->LockCount != 0) { 00382 00383 ASSERT(child->LockCount == 1); 00384 00385 child->LockCount = 0; 00386 00387 KeSetEvent(&child->EnumerationMutex, 0, FALSE); 00388 ObDereferenceObject(childPDO); 00389 00390 ASSERT(parent->LockCount > 0); 00391 00392 if (--parent->LockCount == 0) { 00393 KeSetEvent(&parent->EnumerationMutex, 0, FALSE); 00394 ObDereferenceObject(parent->PhysicalDeviceObject); 00395 } 00396 } 00397 00398 child = nextChild; 00399 } 00400 00401 // 00402 // Add a reference to each FDO attached to the PDO such that the FDOs won't 00403 // actually go away until the removal operation is completed. 00404 // Note we need to make a copy of all the attached devices because we won't be 00405 // able to traverse the attached chain when the removal operation is done. 00406 // 00407 00408 device1 = deviceObject->AttachedDevice; 00409 while (device1) { 00410 length++; 00411 device1 = device1->AttachedDevice; 00412 } 00413 00414 attachedDevices = NULL; 00415 attachedDrivers = NULL; 00416 if (length != 0) { 00417 length = (length + 2) * sizeof(PDEVICE_OBJECT); 00418 attachedDevices = (PDEVICE_OBJECT *)ExAllocatePool (PagedPool, length); 00419 if (!attachedDevices) { 00420 return FALSE; 00421 } 00422 attachedDrivers = (PDRIVER_OBJECT *)ExAllocatePool (PagedPool, length); 00423 if (!attachedDrivers) { 00424 ExFreePool(attachedDevices); 00425 return FALSE; 00426 } 00427 RtlZeroMemory(attachedDevices, length); 00428 RtlZeroMemory(attachedDrivers, length); 00429 device1 = deviceObject->AttachedDevice; 00430 device2 = attachedDevices; 00431 driver = attachedDrivers; 00432 while (device1) { 00433 ObReferenceObject(device1); 00434 *device2++ = device1; 00435 *driver++ = device1->DriverObject; 00436 device1 = device1->AttachedDevice; 00437 } 00438 } 00439 00440 // 00441 // Send irp to remove the device... 00442 // 00443 00444 PIDBGMSG( PIDBG_REMOVAL, 00445 ("IopDeleteLockedDeviceNode: Sending remove irp to device = 0x%p\n", 00446 deviceObject)); 00447 00448 IopRemoveDevice(deviceObject, IRP_MN_REMOVE_DEVICE); 00449 00450 PIDBGMSG(PIDBG_REMOVAL, ("IopDeleteLockedDeviceNode: Releasing devices resources\n")); 00451 00452 IopReleaseDeviceResources(DeviceNode, (BOOLEAN)!(DeviceNode->Flags & DNF_DEVICE_GONE)); 00453 00454 if (!(DeviceNode->Flags & DNF_ENUMERATED)) { 00455 // 00456 // If the device is a dock, remove it from the list of dock devices 00457 // and change the current Hardware Profile, if necessary. 00458 // 00459 ASSERT(DeviceNode->DockInfo.DockStatus != DOCK_ARRIVING) ; 00460 if ((DeviceNode->DockInfo.DockStatus == DOCK_DEPARTING)|| 00461 (DeviceNode->DockInfo.DockStatus == DOCK_EJECTIRP_COMPLETED)) { 00462 IopHardwareProfileCommitRemovedDock(DeviceNode); 00463 } 00464 } 00465 00466 // 00467 // Remove the reference to the attached FDOs to allow them to be actually 00468 // deleted. 00469 // 00470 00471 if (device2 = attachedDevices) { 00472 driver = attachedDrivers; 00473 while (*device2) { 00474 (*device2)->DeviceObjectExtension->ExtensionFlags &= ~(DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED); 00475 (*device2)->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING; 00476 IopUnloadAttachedDriver(*driver); 00477 ObDereferenceObject(*device2); 00478 device2++; 00479 driver++; 00480 } 00481 ExFreePool(attachedDevices); 00482 ExFreePool(attachedDrivers); 00483 } 00484 00485 // 00486 // Now mark this one deleted. 00487 // 00488 00489 if (!(DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM)) { 00490 00491 ASSERT(!IopDoesDevNodeHaveProblem(DeviceNode) || 00492 IopIsDevNodeProblem(DeviceNode, Problem) || 00493 Problem == CM_PROB_DEVICE_NOT_THERE || 00494 Problem == CM_PROB_DISABLED); 00495 00496 IopClearDevNodeProblem(DeviceNode); 00497 IopSetDevNodeProblem(DeviceNode, Problem); 00498 } 00499 00500 deviceObject->DeviceObjectExtension->ExtensionFlags &= ~(DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED); 00501 deviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING; 00502 00503 if (DeviceNode->Flags & DNF_REMOVE_PENDING_CLOSES) { 00504 00505 ASSERT(DeviceNode->LockCount == 0); 00506 00507 DeviceNode->Flags &= ~DNF_REMOVE_PENDING_CLOSES; 00508 00509 if ((DeviceNode->Flags & DNF_DEVICE_GONE) && DeviceNode->Parent != NULL) { 00510 00511 ASSERT(DeviceNode->Child == NULL); 00512 00513 PIDBGMSG( PIDBG_REMOVAL, 00514 ("IopDeleteLockedDeviceNode: Cleaning up registry values, instance = %wZ\n", 00515 &DeviceNode->InstancePath)); 00516 00517 KeEnterCriticalRegion(); 00518 ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE); 00519 00520 IopCleanupDeviceRegistryValues(&DeviceNode->InstancePath, FALSE); 00521 00522 ExReleaseResource(&PpRegistryDeviceResource); 00523 KeLeaveCriticalRegion(); 00524 00525 PIDBGMSG( PIDBG_REMOVAL, 00526 ("IopDeleteLockedDeviceNode: Removing DevNode tree, DevNode = 0x%p\n", 00527 DeviceNode)); 00528 00529 IopRemoveTreeDeviceNode(DeviceNode); 00530 ObDereferenceObject(deviceObject); // Added during Enum 00531 } 00532 } 00533 00534 } else { 00535 00536 // 00537 // The request is QUERY or cancel. If it is query return FALSE on failure. 00538 // 00539 00540 PIDBGMSG( PIDBG_REMOVAL, 00541 ("IopDeleteLockedDeviceNode: Sending QueryRemove/CancelRemove irp to device = 0x%p\n", 00542 deviceObject)); 00543 00544 status = IopRemoveDevice(deviceObject, IrpCode); 00545 if (!NT_SUCCESS(status) && IrpCode == IRP_MN_QUERY_REMOVE_DEVICE) { 00546 PIDBGMSG( PIDBG_REMOVAL, 00547 ("IopDeleteLockedDeviceNode: QueryRemove vetoed by device = 0x%p\n", 00548 deviceObject)); 00549 00550 success = FALSE; 00551 } 00552 } 00553 return success; 00554 } 00555 00556 NTSTATUS 00557 IopDeleteLockedDeviceNodes( 00558 IN PDEVICE_OBJECT DeviceObject, 00559 IN PRELATION_LIST RelationsList, 00560 IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode, 00561 IN BOOLEAN IsKernelInitiated, 00562 IN BOOLEAN ProcessIndirectDescendants, 00563 IN ULONG Problem, 00564 OUT PDEVICE_OBJECT *VetoingDevice OPTIONAL 00565 ) 00566 00567 /*++ 00568 00569 Routine Description: 00570 00571 This routine performs requested operation on the DeviceObject and 00572 the device objects specified in the DeviceRelations. 00573 00574 Arguments: 00575 00576 DeviceObject - Supplies a pointer to the device object. 00577 00578 DeviceRelations - supplies a pointer to the device's removal relations. 00579 00580 OperationCode - Operation code, i.e., QueryRemove, CancelRemove, Remove... 00581 00582 Return Value: 00583 00584 NTSTATUS code. 00585 00586 --*/ 00587 00588 { 00589 NTSTATUS status = STATUS_SUCCESS; 00590 PDEVICE_NODE deviceNode; 00591 PDEVICE_OBJECT deviceObject, relatedDeviceObject; 00592 ULONG i; 00593 ULONG marker; 00594 ULONG irpCode; 00595 BOOLEAN tagged, directDescendant; 00596 00597 PAGED_CODE(); 00598 00599 PIDBGMSG( PIDBG_REMOVAL, 00600 ("IopDeleteLockedDeviceNodes: Entered\n DeviceObject = 0x%p\n RelationsList = 0x%p\n OperationCode = %d\n", 00601 DeviceObject, 00602 RelationsList, 00603 OperationCode)); 00604 00605 deviceNode = (PDEVICE_NODE) DeviceObject->DeviceObjectExtension->DeviceNode; 00606 00607 switch (OperationCode) { 00608 case QueryRemoveDevice: 00609 irpCode = IRP_MN_QUERY_REMOVE_DEVICE; 00610 break; 00611 00612 case CancelRemoveDevice: 00613 irpCode = IRP_MN_CANCEL_REMOVE_DEVICE; 00614 break; 00615 00616 case RemoveDevice: 00617 irpCode = IRP_MN_REMOVE_DEVICE; 00618 break; 00619 00620 case SurpriseRemoveDevice: 00621 irpCode = IRP_MN_SURPRISE_REMOVAL; 00622 break; 00623 00624 case EjectDevice: 00625 default: 00626 ASSERT(0); 00627 return STATUS_INVALID_PARAMETER; 00628 } 00629 00630 marker = 0; 00631 while (IopEnumerateRelations( RelationsList, 00632 &marker, 00633 &deviceObject, 00634 &directDescendant, 00635 &tagged, 00636 TRUE)) { 00637 00638 // 00639 // Depending on the operation we need to do different things. 00640 // 00641 // QueryRemoveDevice / CancelRemoveDevice 00642 // Ignore tagged relations - they were processed by a previous eject 00643 // Process both direct and indirect descendants 00644 // 00645 // SurpriseRemoveDevice / RemoveDevice 00646 // None of the relations should be tagged 00647 // Ignore indirect descendants 00648 // 00649 00650 if (!tagged && (directDescendant || ProcessIndirectDescendants)) { 00651 deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode; 00652 00653 if (OperationCode == SurpriseRemoveDevice) { 00654 deviceNode->Flags |= DNF_REMOVE_PENDING_CLOSES; 00655 } 00656 00657 if (OperationCode == QueryRemoveDevice && !(deviceNode->Flags & DNF_STARTED)) { 00658 // 00659 // Don't send Queries to devices without FDOs (or filters) 00660 // 00661 continue; 00662 } 00663 00664 if (!IopDeleteLockedDeviceNode( deviceNode, 00665 irpCode, 00666 RelationsList, 00667 IsKernelInitiated, 00668 Problem)) { 00669 00670 if (OperationCode == QueryRemoveDevice) { 00671 00672 if (VetoingDevice != NULL) { 00673 *VetoingDevice = deviceObject; 00674 } 00675 00676 IopDeleteLockedDeviceNode( deviceNode, 00677 IRP_MN_CANCEL_REMOVE_DEVICE, 00678 RelationsList, 00679 IsKernelInitiated, 00680 Problem); 00681 00682 while (IopEnumerateRelations( RelationsList, 00683 &marker, 00684 &deviceObject, 00685 NULL, 00686 &tagged, 00687 FALSE)) { 00688 00689 if (!tagged) { 00690 00691 deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode; 00692 00693 IopDeleteLockedDeviceNode( deviceNode, 00694 IRP_MN_CANCEL_REMOVE_DEVICE, 00695 RelationsList, 00696 IsKernelInitiated, 00697 Problem); 00698 } 00699 } 00700 00701 status = STATUS_UNSUCCESSFUL; 00702 goto exit; 00703 } 00704 } 00705 } 00706 } 00707 00708 // 00709 // As long as there is device removed, try satisfy the DNF_INSUFFICIENT_RESOURCES 00710 // devices. 00711 // 00712 00713 if (OperationCode == RemoveDevice) { 00714 PIDBGMSG( PIDBG_REMOVAL, 00715 ("IopDeleteLockedDeviceNodes: Calling IopRequestDeviceEnumeration\n")); 00716 00717 IopRequestDeviceAction(NULL, AssignResources, NULL, NULL); 00718 } 00719 00720 exit: 00721 return status; 00722 } 00723 00724 NTSTATUS 00725 IopLockDeviceRemovalRelations( 00726 IN PDEVICE_OBJECT DeviceObject, 00727 IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode, 00728 OUT PRELATION_LIST *RelationsList, 00729 IN BOOLEAN IsKernelInitiated 00730 ) 00731 00732 /*++ 00733 00734 Routine Description: 00735 00736 This routine locks the device subtrees for removal operation and returns 00737 a list of device objects which need to be removed with the specified 00738 DeviceObject. 00739 00740 Caller must hold a reference to the DeviceObject. 00741 00742 Arguments: 00743 00744 DeviceObject - Supplies a pointer to the device object to be removed. 00745 00746 OperationCode - Operation code, i.e., QueryEject, CancelEject, Eject... 00747 00748 DeviceRelations - supplies a pointer to a variable to receive the device's 00749 removal relations. 00750 00751 Return Value: 00752 00753 NTSTATUS code. 00754 00755 --*/ 00756 00757 { 00758 NTSTATUS status; 00759 PDEVICE_OBJECT deviceObject; 00760 PDEVICE_NODE deviceNode, parent; 00761 PRELATION_LIST relationsList; 00762 ULONG marker; 00763 BOOLEAN tagged; 00764 00765 PAGED_CODE(); 00766 00767 *RelationsList = NULL; 00768 00769 deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode; 00770 00771 if (!IsKernelInitiated && !(deviceNode->Flags & DNF_ADDED) && OperationCode != EjectDevice) { 00772 00773 return STATUS_SUCCESS; 00774 } 00775 00776 // 00777 // Obviously no one should try to delete the whole device node tree. 00778 // 00779 00780 ASSERT(DeviceObject != IopRootDeviceNode->PhysicalDeviceObject); 00781 00782 // 00783 // Lock the whole device node tree so no one can touch the tree. 00784 // 00785 00786 IopAcquireDeviceTreeLock(); 00787 00788 if (IsKernelInitiated) { 00789 // 00790 // For kernel initiated removes it means that the device itself is 00791 // physically gone. 00792 // 00793 00794 // 00795 // We'll take advantage of that signal to go and check if there 00796 // previously was a QueryRemove done on this devnode. If 00797 // so, we need to reenumerate the parents of all the relations in 00798 // case some of them were speculative. 00799 // 00800 } 00801 00802 if ((relationsList = IopAllocateRelationList()) == NULL) { 00803 00804 IopReleaseDeviceTreeLock(); 00805 return STATUS_INSUFFICIENT_RESOURCES; 00806 } 00807 00808 // 00809 // First process the object itself 00810 // 00811 status = IopProcessRelation( DeviceObject, 00812 OperationCode, 00813 relationsList, 00814 IsKernelInitiated, 00815 TRUE); 00816 00817 ASSERT(status != STATUS_INVALID_DEVICE_REQUEST); 00818 00819 marker = 0; 00820 while (IopEnumerateRelations( relationsList, 00821 &marker, 00822 &deviceObject, 00823 NULL, 00824 &tagged, 00825 FALSE)) { 00826 00827 deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode; 00828 00829 // 00830 // If we were successful we need to lock the parents of each of the 00831 // relations, otherwise we need to unlock each relation. 00832 // 00833 00834 00835 if (NT_SUCCESS(status)) { 00836 // 00837 // For all the device nodes in the DeviceRelations, we need to lock 00838 // their parents' enumeration mutex. 00839 // 00840 00841 if (tagged) { 00842 00843 // 00844 // If the tagged bit is set then the relation was merged from 00845 // a pending eject. In this case the devnode isn't locked so 00846 // we do it now. 00847 // 00848 00849 if (deviceNode->LockCount++ == 0) { 00850 ObReferenceObject(deviceNode->PhysicalDeviceObject); 00851 KeClearEvent(&deviceNode->EnumerationMutex); 00852 } 00853 } 00854 00855 parent = deviceNode->Parent; 00856 00857 if (parent->LockCount++ == 0) { 00858 ObReferenceObject(parent->PhysicalDeviceObject); 00859 KeClearEvent(&parent->EnumerationMutex); 00860 } 00861 00862 } else { 00863 00864 if (!tagged) { 00865 00866 // 00867 // If the tagged bit is set then the relation was merged from 00868 // an pending eject. In this case the devnode isn't locked so 00869 // we don't need to unlock it, all the others we unlock now. 00870 // 00871 00872 ASSERT(deviceNode->LockCount > 0); 00873 00874 if (--deviceNode->LockCount == 0) { 00875 KeSetEvent(&deviceNode->EnumerationMutex, 0, FALSE); 00876 ObDereferenceObject(deviceObject); 00877 } 00878 } 00879 } 00880 } 00881 00882 // 00883 // Release the device tree. 00884 // 00885 00886 IopReleaseDeviceTreeLock(); 00887 00888 if (NT_SUCCESS(status)) { 00889 IopCompressRelationList(&relationsList); 00890 *RelationsList = relationsList; 00891 00892 // 00893 // At this point we have a list of all the relations, those that are 00894 // direct descendants of the original device we are ejecting or 00895 // removing have the DirectDescendant bit set. 00896 // 00897 // Relations which were merged from an existing eject have the tagged 00898 // bit set. 00899 // 00900 // All of the relations and their parents are locked. 00901 // 00902 // There is a reference on each device object by virtue of it being in 00903 // the list. There is another one on each device object because it is 00904 // locked and the lock count is >= 1. 00905 // 00906 // There is also a reference on each relation's parent and it's lock 00907 // count is >= 1. 00908 // 00909 } else { 00910 IopFreeRelationList(relationsList); 00911 } 00912 00913 return status; 00914 } 00915 00916 NTSTATUS 00917 IopProcessRelation( 00918 IN PDEVICE_OBJECT DeviceObject, 00919 IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode, 00920 IN PRELATION_LIST RelationsList, 00921 IN BOOLEAN IsKernelInitiated, 00922 IN BOOLEAN IsDirectDescendant 00923 ) 00924 /*++ 00925 00926 Routine Description: 00927 00928 This routine builds the list of device objects that need to be removed or 00929 examined when the passed in device object is torn down. 00930 00931 Caller must hold the device tree lock. 00932 00933 Arguments: 00934 00935 ADRIAO BUGBUG 01/07/1999 - fill this out. 00936 00937 Return Value: 00938 00939 NTSTATUS code. 00940 00941 --*/ 00942 { 00943 PDEVICE_NODE deviceNode, relatedDeviceNode; 00944 PDEVICE_OBJECT relatedDeviceObject; 00945 PDEVICE_RELATIONS deviceRelations; 00946 PLIST_ENTRY ejectLink; 00947 PPENDING_RELATIONS_LIST_ENTRY ejectEntry; 00948 PRELATION_LIST pendingRelationList; 00949 PIRP pendingIrp; 00950 NTSTATUS status; 00951 ULONG i; 00952 00953 PAGED_CODE(); 00954 00955 deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode; 00956 00957 if (deviceNode == NULL || deviceNode->Parent == NULL) { 00958 ASSERT(deviceNode != NULL); 00959 00960 // 00961 // The device has already been removed 00962 // 00963 return STATUS_UNSUCCESSFUL; 00964 } 00965 00966 if ((OperationCode == QueryRemoveDevice || OperationCode == EjectDevice) && 00967 (deviceNode->Flags & DNF_REMOVE_PENDING_CLOSES)) { 00968 00969 // 00970 // The device is in the process of being surprise removed, let it finish 00971 // 00972 return STATUS_UNSUCCESSFUL; 00973 } 00974 00975 status = IopAddRelationToList( RelationsList, 00976 DeviceObject, 00977 IsDirectDescendant, 00978 FALSE); 00979 00980 if (status == STATUS_SUCCESS) { 00981 00982 ASSERT(deviceNode->LockCount == 0); 00983 00984 if (!(deviceNode->Flags & DNF_LOCKED_FOR_EJECT)) { 00985 ObReferenceObject(DeviceObject); 00986 00987 KeClearEvent(&deviceNode->EnumerationMutex); 00988 00989 deviceNode->LockCount++; 00990 00991 // 00992 // Then process the bus relations 00993 // 00994 for (relatedDeviceNode = deviceNode->Child; 00995 relatedDeviceNode != NULL; 00996 ) { 00997 00998 relatedDeviceObject = relatedDeviceNode->PhysicalDeviceObject; 00999 01000 relatedDeviceNode = relatedDeviceNode->Sibling; 01001 01002 status = IopProcessRelation( relatedDeviceObject, 01003 OperationCode, 01004 RelationsList, 01005 IsKernelInitiated, 01006 IsDirectDescendant 01007 ); 01008 01009 ASSERT(status == STATUS_SUCCESS || status == STATUS_UNSUCCESSFUL); 01010 01011 if (status == STATUS_INSUFFICIENT_RESOURCES || 01012 status == STATUS_INVALID_DEVICE_REQUEST) { 01013 return status; 01014 } 01015 } 01016 01017 // 01018 // Next the removal relations 01019 // 01020 01021 01022 if (deviceNode->Flags & DNF_STARTED) { 01023 status = IopQueryDeviceRelations( RemovalRelations, 01024 DeviceObject, 01025 FALSE, 01026 &deviceRelations); 01027 01028 if (NT_SUCCESS(status) && deviceRelations) { 01029 01030 for (i = 0; i < deviceRelations->Count; i++) { 01031 01032 relatedDeviceObject = deviceRelations->Objects[i]; 01033 01034 status = IopProcessRelation( relatedDeviceObject, 01035 OperationCode, 01036 RelationsList, 01037 IsKernelInitiated, 01038 FALSE); 01039 01040 01041 ObDereferenceObject( relatedDeviceObject ); 01042 01043 ASSERT(status == STATUS_SUCCESS || 01044 status == STATUS_UNSUCCESSFUL); 01045 01046 if (status == STATUS_INSUFFICIENT_RESOURCES || 01047 status == STATUS_INVALID_DEVICE_REQUEST) { 01048 01049 ExFreePool(deviceRelations); 01050 01051 return status; 01052 } 01053 } 01054 01055 ExFreePool(deviceRelations); 01056 } else { 01057 if (status != STATUS_NOT_SUPPORTED) { 01058 PIDBGMSG( PIDBG_WARNING, 01059 ("IopProcessRelation: IopQueryDeviceRelations failed, DeviceObject = 0x%p, status = 0x%08X\n", 01060 DeviceObject, status)); 01061 } 01062 } 01063 } 01064 01065 // 01066 // Finally the eject relations if we are doing an eject operation 01067 // 01068 01069 if (OperationCode != QueryRemoveDevice && 01070 OperationCode != RemoveFailedDevice && 01071 OperationCode != RemoveUnstartedFailedDevice) { 01072 status = IopQueryDeviceRelations( EjectionRelations, 01073 DeviceObject, 01074 FALSE, 01075 &deviceRelations); 01076 01077 if (NT_SUCCESS(status) && deviceRelations) { 01078 01079 for (i = 0; i < deviceRelations->Count; i++) { 01080 01081 relatedDeviceObject = deviceRelations->Objects[i]; 01082 01083 status = IopProcessRelation( relatedDeviceObject, 01084 OperationCode, 01085 RelationsList, 01086 IsKernelInitiated, 01087 FALSE); 01088 01089 ObDereferenceObject( relatedDeviceObject ); 01090 01091 ASSERT(status == STATUS_SUCCESS || 01092 status == STATUS_UNSUCCESSFUL); 01093 01094 if (status == STATUS_INSUFFICIENT_RESOURCES || 01095 status == STATUS_INVALID_DEVICE_REQUEST) { 01096 01097 ExFreePool(deviceRelations); 01098 01099 return status; 01100 } 01101 } 01102 01103 ExFreePool(deviceRelations); 01104 } else { 01105 if (status != STATUS_NOT_SUPPORTED) { 01106 PIDBGMSG( PIDBG_WARNING, 01107 ("IopProcessRelation: IopQueryDeviceRelations failed, DeviceObject = 0x%p, status = 0x%08X\n", 01108 DeviceObject, status)); 01109 } 01110 } 01111 } 01112 01113 status = STATUS_SUCCESS; 01114 01115 } else { 01116 01117 // 01118 // Look to see if this device is already part of a pending ejection. 01119 // If it is and we are doing an ejection then we will subsume it 01120 // within the larger ejection. If we aren't doing an ejection then 01121 // we better be processing the removal of one of the ejected devices. 01122 // 01123 01124 for (ejectLink = IopPendingEjects.Flink; 01125 ejectLink != &IopPendingEjects; 01126 ejectLink = ejectLink->Flink) { 01127 01128 ejectEntry = CONTAINING_RECORD( ejectLink, 01129 PENDING_RELATIONS_LIST_ENTRY, 01130 Link); 01131 01132 if (ejectEntry->RelationsList != NULL && 01133 IopIsRelationInList(ejectEntry->RelationsList, DeviceObject)) { 01134 01135 01136 if (OperationCode == EjectDevice) { 01137 01138 status = IopRemoveRelationFromList(RelationsList, DeviceObject); 01139 01140 ASSERT(NT_SUCCESS(status)); 01141 01142 pendingIrp = InterlockedExchangePointer(&ejectEntry->EjectIrp, NULL); 01143 pendingRelationList = ejectEntry->RelationsList; 01144 ejectEntry->RelationsList = NULL; 01145 01146 if (pendingIrp != NULL) { 01147 IoCancelIrp(pendingIrp); 01148 } 01149 01150 // 01151 // ADRIAO BUGBUG 11/10/98 - 01152 // If a parent fails eject and it has a child that is 01153 // infinitely pending an eject, this means the child now 01154 // wakes up. One suggestion brought up that does not involve 01155 // a code change is to amend the WDM spec to say if driver 01156 // gets a start IRP for a device pending eject, it should 01157 // cancel the eject IRP automatically. 01158 // 01159 IopMergeRelationLists(RelationsList, pendingRelationList, TRUE); 01160 01161 IopFreeRelationList(pendingRelationList); 01162 01163 if (IsDirectDescendant) { 01164 // 01165 // If IsDirectDescendant is specified then we need to 01166 // get that bit set on the relation that caused us to 01167 // do the merge. IopAddRelationToList will fail with 01168 // STATUS_OBJECT_NAME_COLLISION but the bit will still 01169 // be set as a side effect. 01170 // 01171 IopAddRelationToList( RelationsList, 01172 DeviceObject, 01173 TRUE, 01174 FALSE); 01175 } 01176 } else if (OperationCode == RemoveDevice) { 01177 01178 // 01179 // We haven't processed the completion of the eject IRP 01180 // before this device went away. We'll remove it from 01181 // the list in the pending ejection and return it. 01182 // 01183 01184 status = IopRemoveRelationFromList( ejectEntry->RelationsList, 01185 DeviceObject); 01186 01187 deviceNode->Flags &= ~DNF_LOCKED_FOR_EJECT; 01188 01189 ASSERT(NT_SUCCESS(status)); 01190 01191 ObReferenceObject(DeviceObject); 01192 01193 KeClearEvent(&deviceNode->EnumerationMutex); 01194 01195 deviceNode->LockCount++; 01196 } else { 01197 01198 ASSERT(0); 01199 01200 return STATUS_INVALID_DEVICE_REQUEST; 01201 } 01202 break; 01203 } 01204 } 01205 01206 ASSERT(ejectLink != &IopPendingEjects); 01207 01208 if (ejectLink == &IopPendingEjects) { 01209 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01210 PNP_ERR_DEVICE_MISSING_FROM_EJECT_LIST, 01211 (ULONG_PTR)DeviceObject, 01212 0, 01213 0); 01214 } 01215 } 01216 } else if (status == STATUS_OBJECT_NAME_COLLISION) { 01217 PIDBGMSG( PIDBG_INFORMATION, 01218 ("IopProcessRelation: Duplicate relation, DeviceObject = 0x%p\n", 01219 DeviceObject)); 01220 01221 status = STATUS_SUCCESS; 01222 } else if (status != STATUS_INSUFFICIENT_RESOURCES) { 01223 KeBugCheckEx( PNP_DETECTED_FATAL_ERROR, 01224 PNP_ERR_UNEXPECTED_ADD_RELATION_ERR, 01225 (ULONG_PTR)DeviceObject, 01226 (ULONG_PTR)RelationsList, 01227 status); 01228 } 01229 01230 return status; 01231 } 01232 01233 BOOLEAN 01234 IopQueuePendingEject( 01235 PPENDING_RELATIONS_LIST_ENTRY Entry 01236 ) 01237 { 01238 PAGED_CODE(); 01239 01240 IopAcquireDeviceTreeLock(); 01241 01242 InsertTailList(&IopPendingEjects, &Entry->Link); 01243 01244 IopReleaseDeviceTreeLock(); 01245 01246 return TRUE; 01247 } 01248 01249 NTSTATUS 01250 IopInvalidateRelationsInList( 01251 PRELATION_LIST RelationsList, 01252 BOOLEAN OnlyIndirectDescendants, 01253 BOOLEAN UnlockDevNode, 01254 BOOLEAN RestartDevNode 01255 ) 01256 01257 /*++ 01258 01259 Routine Description: 01260 01261 Iterate over the relations in the list creating a second list containing the 01262 parent of each entry skipping parents which are also in the list. In other 01263 words, if the list contains node P and node C where node C is a child of node 01264 P then the parent of node P would be added but not node P itself. 01265 01266 01267 Arguments: 01268 01269 RelationsList - List of relations 01270 01271 OnlyIndirectDescendants - Indirect relations are those which aren't direct 01272 descendants (bus relations) of the PDO originally 01273 targetted for the operation or its direct 01274 descendants. This would include Removal or 01275 Eject relations. 01276 01277 UnlockDevNode - If true then any node who's parent was invalidated 01278 is unlocked. In the case where the parent is also 01279 in the list the node is still unlocked as will the 01280 parent be once we process it. 01281 01282 RestartDevNode - If true then any node who's parent was invalidated 01283 is restarted. This flag requires that all the 01284 relations in the list have been previously 01285 sent a remove IRP. 01286 01287 01288 Return Value: 01289 01290 NTSTATUS code. 01291 01292 --*/ 01293 01294 { 01295 PRELATION_LIST parentsList; 01296 PDEVICE_OBJECT deviceObject, parentObject; 01297 PDEVICE_NODE deviceNode, parentNode; 01298 ULONG marker; 01299 BOOLEAN directDescendant, tagged; 01300 01301 PAGED_CODE(); 01302 01303 parentsList = IopAllocateRelationList(); 01304 01305 if (parentsList == NULL) { 01306 return STATUS_INSUFFICIENT_RESOURCES; 01307 } 01308 01309 IopSetAllRelationsTags( RelationsList, FALSE ); 01310 01311 // 01312 // Traverse the list creating a new list with the topmost parents of 01313 // each sublist contained in RelationsList. 01314 // 01315 01316 marker = 0; 01317 01318 while (IopEnumerateRelations( RelationsList, 01319 &marker, 01320 &deviceObject, 01321 &directDescendant, 01322 &tagged, 01323 TRUE)) { 01324 01325 if (!OnlyIndirectDescendants || !directDescendant) { 01326 01327 if (!tagged) { 01328 01329 parentObject = deviceObject; 01330 01331 while (IopSetRelationsTag( RelationsList, parentObject, TRUE ) == STATUS_SUCCESS) { 01332 01333 deviceNode = parentObject->DeviceObjectExtension->DeviceNode; 01334 01335 if (RestartDevNode) { 01336 01337 deviceNode->Flags &= ~DNF_LOCKED_FOR_EJECT; 01338 01339 if ((deviceNode->Flags & (DNF_PROCESSED | DNF_ENUMERATED)) == 01340 (DNF_PROCESSED | DNF_ENUMERATED)) { 01341 01342 ASSERT(deviceNode->Child == NULL); 01343 ASSERT(!(deviceNode->Flags & DNF_ADDED)); 01344 01345 IopClearDevNodeProblem( deviceNode ); 01346 IopRestartDeviceNode( deviceNode ); 01347 } 01348 } 01349 01350 if (UnlockDevNode) { 01351 parentNode = deviceNode->Parent; 01352 01353 ASSERT(parentNode != NULL); 01354 01355 ASSERT(deviceNode->LockCount > 0); 01356 01357 if (--deviceNode->LockCount == 0) { 01358 KeSetEvent(&deviceNode->EnumerationMutex, 0, FALSE); 01359 ObDereferenceObject(deviceNode->PhysicalDeviceObject); 01360 } 01361 01362 ASSERT(parentNode->LockCount > 0); 01363 01364 if (--parentNode->LockCount == 0) { 01365 KeSetEvent(&parentNode->EnumerationMutex, 0, FALSE); 01366 ObDereferenceObject(parentNode->PhysicalDeviceObject); 01367 } 01368 } 01369 01370 if (deviceNode->Parent != NULL) { 01371 01372 parentObject = deviceNode->Parent->PhysicalDeviceObject; 01373 01374 } else { 01375 parentObject = NULL; 01376 break; 01377 } 01378 } 01379 01380 if (parentObject != NULL) { 01381 IopAddRelationToList( parentsList, parentObject, FALSE, FALSE ); 01382 } 01383 } 01384 01385 } 01386 } 01387 01388 // 01389 // Reenumerate each of the parents 01390 // 01391 01392 marker = 0; 01393 01394 while (IopEnumerateRelations( parentsList, 01395 &marker, 01396 &deviceObject, 01397 NULL, 01398 NULL, 01399 FALSE)) { 01400 01401 IopRequestDeviceAction( deviceObject, 01402 ReenumerateDeviceTree, 01403 NULL, 01404 NULL ); 01405 } 01406 01407 // 01408 // Free the parents list 01409 // 01410 01411 IopFreeRelationList( parentsList ); 01412 01413 return STATUS_SUCCESS; 01414 } 01415 01416 VOID 01417 IopProcessCompletedEject( 01418 IN PVOID Context 01419 ) 01420 /*++ 01421 01422 Routine Description: 01423 01424 This routine is called at passive level from a worker thread that was queued 01425 either when an eject IRP completed (see io\pnpirp.c - IopDeviceEjectComplete 01426 or io\pnpirp.c - IopEjectDevice), or when a warm eject needs to be performed. 01427 We also may need to fire off any enumerations of parents of ejected devices 01428 to verify they have indeed left. 01429 01430 Arguments: 01431 01432 Context - Pointer to the pending relations list which contains the device 01433 to eject (warm) and the list of parents to reenumerate. 01434 01435 Return Value: 01436 01437 None. 01438 01439 --*/ 01440 { 01441 PPENDING_RELATIONS_LIST_ENTRY entry = (PPENDING_RELATIONS_LIST_ENTRY)Context; 01442 NTSTATUS status = STATUS_SUCCESS; 01443 01444 PAGED_CODE(); 01445 01446 if ((entry->LightestSleepState != PowerSystemWorking) && 01447 (entry->LightestSleepState != PowerSystemUnspecified)) { 01448 01449 // 01450 // For docks, WinLogon gets to do the honors. For other devices, the 01451 // user must infer when it's safe to remove the device (if we've powered 01452 // up, it may not be safe now!) 01453 // 01454 entry->DisplaySafeRemovalDialog = FALSE; 01455 01456 // 01457 // This is a warm eject request, initiate it here. 01458 // 01459 status = IopWarmEjectDevice(entry->DeviceObject, entry->LightestSleepState); 01460 01461 // 01462 // We're back and we either succeeded or failed. Either way... 01463 // 01464 } 01465 01466 if (entry->DockInterface) { 01467 01468 entry->DockInterface->ProfileDepartureSetMode( 01469 entry->DockInterface->Context, 01470 PDS_UPDATE_DEFAULT 01471 ); 01472 01473 entry->DockInterface->InterfaceDereference( 01474 entry->DockInterface->Context 01475 ); 01476 } 01477 01478 IopAcquireDeviceTreeLock(); 01479 01480 RemoveEntryList( &entry->Link ); 01481 01482 // 01483 // Check if the RelationsList pointer in the context structure is NULL. If 01484 // so, this means we were cancelled because this eject is part of a new 01485 // larger eject. In that case all we want to do is unlink and free the 01486 // context structure. 01487 // 01488 01489 // 01490 // Two interesting points about such code. 01491 // 01492 // 1) If you wait forever to complete an eject of a dock, we *wait* forever 01493 // in the Query profile change state. No sneaky adding another dock. You 01494 // must finish what you started... 01495 // 2) Let's say you are ejecting a dock, and it is taking a long time. If 01496 // you try to eject the parent, that eject will *not* grab this lower 01497 // eject as we will block on the profile change semaphore. Again, finish 01498 // what you started... 01499 // 01500 01501 if (entry->RelationsList != NULL) { 01502 01503 if (entry->ProfileChangingEject) { 01504 01505 IopHardwareProfileSetMarkedDocksEjected(); 01506 } 01507 01508 IopInvalidateRelationsInList( entry->RelationsList, FALSE, FALSE, TRUE ); 01509 01510 // 01511 // Free the relations list 01512 // 01513 01514 IopFreeRelationList( entry->RelationsList ); 01515 01516 } else { 01517 01518 entry->DisplaySafeRemovalDialog = FALSE; 01519 } 01520 01521 IopReleaseDeviceTreeLock(); 01522 01523 // 01524 // Complete the event 01525 // 01526 if (entry->DeviceEvent != NULL ) { 01527 01528 PpCompleteDeviceEvent( entry->DeviceEvent, status ); 01529 } 01530 01531 if (entry->DisplaySafeRemovalDialog) { 01532 01533 PpSetDeviceRemovalSafe(entry->DeviceObject, NULL, NULL); 01534 } 01535 01536 ExFreePool( entry ); 01537 } 01538 01539 BOOLEAN 01540 IopQueuePendingSurpriseRemoval( 01541 IN PDEVICE_OBJECT DeviceObject, 01542 IN PRELATION_LIST List, 01543 IN ULONG Problem 01544 ) 01545 { 01546 PPENDING_RELATIONS_LIST_ENTRY entry; 01547 01548 PAGED_CODE(); 01549 01550 entry = ExAllocatePool( NonPagedPool, sizeof(PENDING_RELATIONS_LIST_ENTRY) ); 01551 01552 if (entry != NULL) { 01553 01554 entry->DeviceObject = DeviceObject; 01555 entry->RelationsList = List; 01556 entry->Problem = Problem; 01557 entry->ProfileChangingEject = FALSE ; 01558 01559 IopAcquireDeviceTreeLock(); 01560 01561 InsertTailList(&IopPendingSurpriseRemovals, &entry->Link); 01562 01563 IopReleaseDeviceTreeLock(); 01564 01565 return TRUE; 01566 } 01567 01568 return FALSE; 01569 } 01570 01571 NTSTATUS 01572 IopUnlockDeviceRemovalRelations( 01573 IN PDEVICE_OBJECT DeviceObject, 01574 IN PRELATION_LIST RelationsList, 01575 IN UNLOCK_UNLINK_ACTION UnlinkAction 01576 ) 01577 01578 /*++ 01579 01580 Routine Description: 01581 01582 This routine unlocks the device tree deletion operation. 01583 If there is any pending kernel deletion, this routine initiates 01584 a worker thread to perform the work. 01585 01586 Arguments: 01587 01588 DeviceObject - Supplies a pointer to the device object to which the remove 01589 was originally targetted (as opposed to one of the relations). 01590 01591 DeviceRelations - supplies a pointer to the device's removal relations. 01592 01593 UnlinkAction - Specifies which devnodes will be unlinked from the devnode 01594 tree. 01595 01596 UnLinkRemovedDeviceNodes - Devnodes which are no longer enumerated and 01597 have been sent a REMOVE_DEVICE IRP are unlinked. 01598 01599 UnlinkAllDeviceNodesPendingClose - This is used when a device is 01600 surprise removed. Devnodes in RelationsList are unlinked from the 01601 tree if they don't have children and aren't consuming any resources. 01602 01603 UnlinkOnlyChildDeviceNodesPendingClose - This is used when a device fails 01604 while started. We unlink any child devnodes of the device which 01605 failed but not the failed device's devnode. 01606 01607 Return Value: 01608 01609 NTSTATUS code. 01610 01611 --*/ 01612 01613 { 01614 NTSTATUS status; 01615 PDEVICE_NODE deviceNode, parent; 01616 PDEVICE_OBJECT deviceObject, relatedDeviceObject; 01617 ULONG i; 01618 ULONG marker; 01619 01620 PAGED_CODE(); 01621 01622 KeEnterCriticalRegion(); 01623 ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE); 01624 01625 if (ARGUMENT_PRESENT(RelationsList)) { 01626 marker = 0; 01627 while (IopEnumerateRelations( RelationsList, 01628 &marker, 01629 &deviceObject, 01630 NULL, 01631 NULL, 01632 TRUE)) { 01633 01634 deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode; 01635 parent = deviceNode->Parent; 01636 01637 // 01638 // There are three different scenarios in which we want to unlink a 01639 // devnode from the tree. The first case is tested in the first 01640 // part of the condition. The other two in the second part. 01641 // 01642 // 1) A devnode is no longer enumerated and has been sent a 01643 // remove IRP. 01644 // 01645 // 2) A devnode has been surprise removed, has no children, has 01646 // no resources or they've been freed. UnlinkAction will be 01647 // UnlinkAllDeviceNodesPendingClose. 01648 // 01649 // 3) A devnode has failed and a surprise remove IRP has been sent. 01650 // Then we want to remove children without resources but not the 01651 // failed devnode itself. UnlinkAction will be 01652 // UnlinkOnlyChildDeviceNodesPendingClose. 01653 // 01654 01655 if ((!(deviceNode->Flags & (DNF_ENUMERATED | DNF_REMOVE_PENDING_CLOSES)) && 01656 IopDoesDevNodeHaveProblem(deviceNode)) || 01657 (UnlinkAction != UnlinkRemovedDeviceNodes && 01658 (deviceNode->Flags & DNF_REMOVE_PENDING_CLOSES) && 01659 !(deviceNode->Flags & DNF_RESOURCE_ASSIGNED) && 01660 deviceNode->Child == NULL && 01661 (UnlinkAction == UnlinkAllDeviceNodesPendingClose || 01662 deviceObject != DeviceObject))) { 01663 01664 PIDBGMSG( PIDBG_REMOVAL, 01665 ("IopUnlockDeviceRemovalRelations: Cleaning up registry values, instance = %wZ\n", 01666 &deviceNode->InstancePath)); 01667 01668 IopCleanupDeviceRegistryValues(&deviceNode->InstancePath, FALSE); 01669 01670 PIDBGMSG( PIDBG_REMOVAL, 01671 ("IopUnlockDeviceRemovalRelations: Removing DevNode tree, DevNode = 0x%p\n", 01672 deviceNode)); 01673 01674 IopRemoveTreeDeviceNode(deviceNode); 01675 01676 if (!(deviceNode->Flags & DNF_REMOVE_PENDING_CLOSES)) { 01677 IopRemoveRelationFromList(RelationsList, deviceObject); 01678 } 01679 ObDereferenceObject(deviceObject); // Added during enum 01680 } 01681 01682 ASSERT(deviceNode->LockCount > 0); 01683 01684 if (--deviceNode->LockCount == 0) { 01685 KeSetEvent(&deviceNode->EnumerationMutex, 0, FALSE); 01686 ObDereferenceObject(deviceObject); 01687 } 01688 01689 ASSERT(parent->LockCount > 0); 01690 01691 if (--parent->LockCount == 0) { 01692 KeSetEvent(&parent->EnumerationMutex, 0, FALSE); 01693 ObDereferenceObject(parent->PhysicalDeviceObject); 01694 } 01695 } 01696 } 01697 01698 ExReleaseResource(&PpRegistryDeviceResource); 01699 KeLeaveCriticalRegion(); 01700 01701 return STATUS_SUCCESS; 01702 } 01703 01704 // 01705 // The routines below are specific to kernel mode PnP configMgr. 01706 // 01707 NTSTATUS 01708 IopRequestDeviceRemoval( 01709 IN PDEVICE_OBJECT DeviceObject, 01710 IN ULONG Problem 01711 ) 01712 01713 /*++ 01714 01715 Routine Description: 01716 01717 This routine queues a work item to delete a device. (This is because 01718 to delete a device we need to lock device tree. Most of the places where 01719 we want to delete a device have DeviceNode Enumeration lock acquired.) 01720 This is for IO internal use only. 01721 01722 Arguments: 01723 01724 DeviceObject - Supplies a pointer to the device object to be eject. 01725 01726 Return Value: 01727 01728 NTSTATUS code. 01729 01730 --*/ 01731 01732 { 01733 PAGED_CODE(); 01734 01735 ASSERT(DeviceObject->DeviceObjectExtension->DeviceNode != NULL); 01736 01737 ASSERT(((PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode)->InstancePath.Length != 0); 01738 01739 // 01740 // Queue the event, we'll return immediately after it's queued. 01741 // 01742 01743 return PpSetTargetDeviceRemove( DeviceObject, 01744 TRUE, 01745 TRUE, 01746 FALSE, 01747 Problem, 01748 NULL, 01749 NULL, 01750 NULL, 01751 NULL); 01752 } 01753 01754 NTSTATUS 01755 IopUnloadAttachedDriver( 01756 IN PDRIVER_OBJECT DriverObject 01757 ) 01758 01759 /*++ 01760 01761 Routine Description: 01762 01763 This function unloads the driver for the specified device object if it does not 01764 control any other device object. 01765 01766 Arguments: 01767 01768 DeviceObject - Supplies a pointer to a device object 01769 01770 Return Value: 01771 01772 NTSTATUS code. 01773 01774 --*/ 01775 01776 { 01777 NTSTATUS status; 01778 PWCHAR buffer; 01779 UNICODE_STRING unicodeName; 01780 PUNICODE_STRING serviceName = &DriverObject->DriverExtension->ServiceKeyName; 01781 01782 PAGED_CODE(); 01783 01784 if (DriverObject->DriverSection != NULL) { 01785 if (DriverObject->DeviceObject == NULL) { 01786 buffer = (PWCHAR) ExAllocatePool( 01787 PagedPool, 01788 CmRegistryMachineSystemCurrentControlSetServices.Length + 01789 serviceName->Length + sizeof(WCHAR) + 01790 sizeof(L"\\")); 01791 if (!buffer) { 01792 return STATUS_INSUFFICIENT_RESOURCES; 01793 } 01794 swprintf(buffer, 01795 L"%s\\%s", 01796 CmRegistryMachineSystemCurrentControlSetServices.Buffer, 01797 serviceName->Buffer); 01798 RtlInitUnicodeString(&unicodeName, buffer); 01799 status = ZwUnloadDriver(&unicodeName); 01800 #if DBG 01801 if (NT_SUCCESS(status)) { 01802 DbgPrint("****** Unloaded driver (%wZ)\n", serviceName); 01803 } else { 01804 DbgPrint("****** Error unloading driver (%wZ), status = 0x%08X\n", serviceName, status); 01805 } 01806 #endif 01807 ExFreePool(unicodeName.Buffer); 01808 } 01809 #if DBG 01810 else { 01811 DbgPrint("****** Skipping unload of driver (%wZ), DriverObject->DeviceObject != NULL\n", serviceName); 01812 } 01813 #endif 01814 } 01815 #if DBG 01816 else { 01817 // 01818 // This is a boot driver, can't be unloaded just return SUCCESS 01819 // 01820 DbgPrint("****** Skipping unload of boot driver (%wZ)\n", serviceName); 01821 } 01822 #endif 01823 return STATUS_SUCCESS; 01824 }

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