test: pnpdel.c Source File

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 }