Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2577 lines
80 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. pnpdel.c
  5. Abstract:
  6. This module contains routines to perform device removal
  7. Author:
  8. Robert B. Nelson (RobertN) Jun 1, 1998.
  9. Revision History:
  10. --*/
  11. #include "pnpmgrp.h"
  12. #include "wdmguid.h"
  13. #ifdef POOL_TAGGING
  14. #undef ExAllocatePool
  15. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'edpP')
  16. #endif
  17. //
  18. // Kernel mode PNP specific routines.
  19. //
  20. VOID
  21. IopDelayedRemoveWorker(
  22. IN PVOID Context
  23. );
  24. BOOLEAN
  25. IopDeleteLockedDeviceNode(
  26. IN PDEVICE_NODE DeviceNode,
  27. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  28. IN PRELATION_LIST RelationsList,
  29. IN ULONG Problem,
  30. OUT PNP_VETO_TYPE *VetoType OPTIONAL,
  31. OUT PUNICODE_STRING VetoName OPTIONAL
  32. );
  33. NTSTATUS
  34. IopProcessRelation(
  35. IN PDEVICE_NODE DeviceNode,
  36. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  37. IN BOOLEAN IsDirectDescendant,
  38. OUT PNP_VETO_TYPE *VetoType,
  39. OUT PUNICODE_STRING VetoName,
  40. IN OUT PRELATION_LIST RelationsList
  41. );
  42. VOID
  43. IopSurpriseRemoveLockedDeviceNode(
  44. IN PDEVICE_NODE DeviceNode,
  45. IN OUT PRELATION_LIST RelationsList
  46. );
  47. BOOLEAN
  48. IopQueryRemoveLockedDeviceNode(
  49. IN PDEVICE_NODE DeviceNode,
  50. OUT PNP_VETO_TYPE *VetoType,
  51. OUT PUNICODE_STRING VetoName
  52. );
  53. VOID
  54. IopCancelRemoveLockedDeviceNode(
  55. IN PDEVICE_NODE DeviceNode
  56. );
  57. VOID
  58. IopRemoveLockedDeviceNode(
  59. IN PDEVICE_NODE DeviceNode,
  60. IN ULONG Problem,
  61. IN OUT PRELATION_LIST RelationsList
  62. );
  63. typedef struct {
  64. BOOLEAN TreeDeletion;
  65. BOOLEAN DescendantNode;
  66. } REMOVAL_WALK_CONTEXT, *PREMOVAL_WALK_CONTEXT;
  67. NTSTATUS
  68. PipRequestDeviceRemovalWorker(
  69. IN PDEVICE_NODE DeviceNode,
  70. IN PVOID Context
  71. );
  72. NTSTATUS
  73. PiProcessBusRelations(
  74. IN PDEVICE_NODE DeviceNode,
  75. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  76. IN BOOLEAN IsDirectDescendant,
  77. OUT PNP_VETO_TYPE *VetoType,
  78. OUT PUNICODE_STRING VetoName,
  79. IN OUT PRELATION_LIST RelationsList
  80. );
  81. WORK_QUEUE_ITEM IopDeviceRemovalWorkItem;
  82. #ifdef ALLOC_PRAGMA
  83. #pragma alloc_text(PAGE, IopChainDereferenceComplete)
  84. #pragma alloc_text(PAGE, IopDelayedRemoveWorker)
  85. #pragma alloc_text(PAGE, IopDeleteLockedDeviceNode)
  86. #pragma alloc_text(PAGE, IopSurpriseRemoveLockedDeviceNode)
  87. #pragma alloc_text(PAGE, IopQueryRemoveLockedDeviceNode)
  88. #pragma alloc_text(PAGE, IopCancelRemoveLockedDeviceNode)
  89. #pragma alloc_text(PAGE, IopDeleteLockedDeviceNodes)
  90. #pragma alloc_text(PAGE, IopInvalidateRelationsInList)
  91. #pragma alloc_text(PAGE, IopBuildRemovalRelationList)
  92. #pragma alloc_text(PAGE, IopProcessCompletedEject)
  93. #pragma alloc_text(PAGE, IopProcessRelation)
  94. #pragma alloc_text(PAGE, IopQueuePendingEject)
  95. #pragma alloc_text(PAGE, IopQueuePendingSurpriseRemoval)
  96. #pragma alloc_text(PAGE, IopUnloadAttachedDriver)
  97. #pragma alloc_text(PAGE, IopUnlinkDeviceRemovalRelations)
  98. #pragma alloc_text(PAGE, PipRequestDeviceRemoval)
  99. #pragma alloc_text(PAGE, PipRequestDeviceRemovalWorker)
  100. #pragma alloc_text(PAGE, PipIsBeingRemovedSafely)
  101. #pragma alloc_text(PAGE, PiProcessBusRelations)
  102. #endif
  103. VOID
  104. IopChainDereferenceComplete(
  105. IN PDEVICE_OBJECT PhysicalDeviceObject,
  106. IN BOOLEAN OnCleanStack
  107. )
  108. /*++
  109. Routine Description:
  110. This routine is invoked when the reference count on a PDO and all its
  111. attached devices transitions to a zero. It tags the devnode as ready for
  112. removal. If all the devnodes are tagged then IopDelayedRemoveWorker is
  113. called to actually send the remove IRPs.
  114. Arguments:
  115. PhysicalDeviceObject - Supplies a pointer to the PDO whose references just
  116. went to zero.
  117. OnCleanStack - Indicates whether the current thread is in the middle a
  118. driver operation.
  119. Return Value:
  120. None.
  121. --*/
  122. {
  123. PPENDING_RELATIONS_LIST_ENTRY entry;
  124. PLIST_ENTRY link;
  125. ULONG count;
  126. ULONG taggedCount;
  127. NTSTATUS status;
  128. PAGED_CODE();
  129. KeEnterCriticalRegion();
  130. ExAcquireResourceExclusiveLite(&IopSurpriseRemoveListLock, TRUE);
  131. //
  132. // Find the relation list this devnode is a member of.
  133. //
  134. for (link = IopPendingSurpriseRemovals.Flink;
  135. link != &IopPendingSurpriseRemovals;
  136. link = link->Flink) {
  137. entry = CONTAINING_RECORD(link, PENDING_RELATIONS_LIST_ENTRY, Link);
  138. //
  139. // Tag the devnode as ready for remove. If it isn't in this list
  140. //
  141. status = IopSetRelationsTag( entry->RelationsList, PhysicalDeviceObject, TRUE );
  142. if (NT_SUCCESS(status)) {
  143. taggedCount = IopGetRelationsTaggedCount( entry->RelationsList );
  144. count = IopGetRelationsCount( entry->RelationsList );
  145. if (taggedCount == count) {
  146. //
  147. // Remove relations list from list of pending surprise removals.
  148. //
  149. RemoveEntryList( link );
  150. ExReleaseResourceLite(&IopSurpriseRemoveListLock);
  151. KeLeaveCriticalRegion();
  152. if ((!OnCleanStack) ||
  153. (PsGetCurrentProcess() != PsInitialSystemProcess)) {
  154. //
  155. // Queue a work item to do the removal so we call the driver
  156. // in the system process context rather than the random one
  157. // we're in now.
  158. //
  159. ExInitializeWorkItem( &entry->WorkItem,
  160. IopDelayedRemoveWorker,
  161. entry);
  162. ExQueueWorkItem(&entry->WorkItem, DelayedWorkQueue);
  163. } else {
  164. //
  165. // We are already in the system process and not in some
  166. // random ObDeref call, so call the worker inline.
  167. //
  168. IopDelayedRemoveWorker( entry );
  169. }
  170. return;
  171. }
  172. break;
  173. }
  174. }
  175. ASSERT(link != &IopPendingSurpriseRemovals);
  176. ExReleaseResourceLite(&IopSurpriseRemoveListLock);
  177. KeLeaveCriticalRegion();
  178. }
  179. VOID
  180. IopDelayedRemoveWorker(
  181. IN PVOID Context
  182. )
  183. /*++
  184. Routine Description:
  185. This routine is usually called from a worker thread to actually send the
  186. remove IRPs once the reference count on a PDO and all its attached devices
  187. transitions to a zero.
  188. Arguments:
  189. Context - Supplies a pointer to the pending relations list entry which has
  190. the relations list of PDOs we need to remove.
  191. Return Value:
  192. None.
  193. --*/
  194. {
  195. PPENDING_RELATIONS_LIST_ENTRY entry = (PPENDING_RELATIONS_LIST_ENTRY)Context;
  196. PAGED_CODE();
  197. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  198. IopDeleteLockedDeviceNodes( entry->DeviceObject,
  199. entry->RelationsList,
  200. RemoveDevice, // OperationCode
  201. FALSE, // ProcessIndirectDescendants
  202. entry->Problem, // Problem
  203. NULL, // VetoType
  204. NULL); // VetoName
  205. //
  206. // The final reference on DeviceNodes in the DeviceNodeDeletePendingCloses
  207. // state is dropped here.
  208. //
  209. IopFreeRelationList( entry->RelationsList );
  210. ExFreePool( entry );
  211. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  212. }
  213. BOOLEAN
  214. IopDeleteLockedDeviceNode(
  215. IN PDEVICE_NODE DeviceNode,
  216. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  217. IN PRELATION_LIST RelationsList,
  218. IN ULONG Problem,
  219. OUT PNP_VETO_TYPE *VetoType OPTIONAL,
  220. OUT PUNICODE_STRING VetoName OPTIONAL
  221. )
  222. /*++
  223. Routine Description:
  224. This function assumes that the specified device is a bus and will
  225. recursively remove all its children.
  226. Arguments:
  227. DeviceNode - Supplies a pointer to the device node to be removed.
  228. VetoType - Pointer to address that receives the veto type if the operation
  229. failed.
  230. VetoName - Pointer to a unicode string that will receive data appropriate
  231. to the veto type.
  232. Return Value:
  233. NTSTATUS code.
  234. --*/
  235. {
  236. BOOLEAN success;
  237. PAGED_CODE();
  238. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  239. "IopDeleteLockedDeviceNode: Entered\n DeviceNode = 0x%p\n OperationCode = 0x%08X\n RelationsList = 0x%p\n Problem = %d\n",
  240. DeviceNode,
  241. OperationCode,
  242. RelationsList,
  243. Problem));
  244. success = TRUE;
  245. switch(OperationCode) {
  246. case SurpriseRemoveDevice:
  247. IopSurpriseRemoveLockedDeviceNode(DeviceNode, RelationsList);
  248. break;
  249. case RemoveDevice:
  250. IopRemoveLockedDeviceNode(DeviceNode, Problem, RelationsList);
  251. break;
  252. case QueryRemoveDevice:
  253. ASSERT(VetoType && VetoName);
  254. success = IopQueryRemoveLockedDeviceNode(
  255. DeviceNode,
  256. VetoType,
  257. VetoName
  258. );
  259. break;
  260. case CancelRemoveDevice:
  261. IopCancelRemoveLockedDeviceNode(DeviceNode);
  262. break;
  263. default:
  264. ASSERT(0);
  265. break;
  266. }
  267. return success;
  268. }
  269. VOID
  270. IopSurpriseRemoveLockedDeviceNode(
  271. IN PDEVICE_NODE DeviceNode,
  272. IN OUT PRELATION_LIST RelationsList
  273. )
  274. /*++
  275. Routine Description:
  276. This function sends a surprise remove IRP to a devnode and processes the
  277. results.
  278. Arguments:
  279. DeviceNode - Supplies a pointer to the device node to be surprise removed.
  280. Return Value:
  281. None.
  282. --*/
  283. {
  284. PNP_DEVNODE_STATE devnodeState, schedulerState;
  285. PDEVICE_OBJECT deviceObject;
  286. PDEVICE_NODE child, nextChild;
  287. NTSTATUS status;
  288. PAGED_CODE();
  289. UNREFERENCED_PARAMETER (RelationsList);
  290. schedulerState = DeviceNode->State;
  291. ASSERT((schedulerState == DeviceNodeAwaitingQueuedDeletion) ||
  292. (schedulerState == DeviceNodeAwaitingQueuedRemoval));
  293. //
  294. // Clear the scheduling state (DeviceNodeAwaitingQueuedDeletion) off
  295. // the state stack.
  296. //
  297. PipRestoreDevNodeState(DeviceNode);
  298. devnodeState = DeviceNode->State;
  299. //
  300. // Do our state updates.
  301. //
  302. PpHotSwapInitRemovalPolicy(DeviceNode);
  303. if (devnodeState == DeviceNodeRemovePendingCloses) {
  304. //
  305. // If the state is DeviceNodeRemovePendingCloses, we should have got
  306. // here via DeviceNodeAwaitingQueuedDeletion. We're probably surprise
  307. // removing a device that was already surprise failed.
  308. //
  309. ASSERT(schedulerState == DeviceNodeAwaitingQueuedDeletion);
  310. //ASSERT(DeviceNode->Child == NULL);
  311. PipSetDevNodeState(DeviceNode, DeviceNodeDeletePendingCloses, NULL);
  312. return;
  313. }
  314. //
  315. // Detach any children from the tree here. If they needed SurpriseRemove
  316. // IRPs, they already will have received them.
  317. //
  318. for(child = DeviceNode->Child; child; child = nextChild) {
  319. //
  320. // Grab a copy of the next sibling before we blow away this devnode.
  321. //
  322. nextChild = child->Sibling;
  323. if (child->Flags & DNF_ENUMERATED) {
  324. child->Flags &= ~DNF_ENUMERATED;
  325. }
  326. //
  327. // If the child has resources and we are wiping out the parent, we need
  328. // to drop the resources (the parent will lose them when his arbiter is
  329. // nuked with the upcoming SurpriseRemoveDevice.)
  330. //
  331. if (PipDoesDevNodeHaveResources(child)) {
  332. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  333. "IopSurpriseRemoveLockedDeviceNode: Releasing resources for child device = 0x%p\n",
  334. child->PhysicalDeviceObject));
  335. //
  336. // ADRIAO N.B. 2000/08/21 -
  337. // Note that if the child stack has no drivers then a Remove
  338. // IRP could be sent here. The stack would be unable to distinguish
  339. // this from AddDevice cleanup.
  340. //
  341. /*
  342. if ((child->State == DeviceNodeUninitialized) ||
  343. (child->State == DeviceNodeInitialized)) {
  344. IopRemoveDevice(child->PhysicalDeviceObject, IRP_MN_REMOVE_DEVICE);
  345. }
  346. */
  347. IopReleaseDeviceResources(child, FALSE);
  348. }
  349. //
  350. // The devnode will be removed from the tree in
  351. // IopUnlinkDeviceRemovalRelations. We don't remove it here as we want
  352. // the tree structure in place for the upcoming broadcast down to user
  353. // mode.
  354. //
  355. // Note - Children in the Uninitialized/Initialized states are not
  356. // put directly into DeviceNodeDeleted today. This could be
  357. // done but we'd have to verify what happens to API calls in
  358. // response to SurpriseRemoval notifications. (Actually, those
  359. // API's are blocked in ppcontrol.c, hotplug cannot in fact
  360. // walk the tree!)
  361. //
  362. PipSetDevNodeState(child, DeviceNodeDeletePendingCloses, NULL);
  363. }
  364. //
  365. // Only send surprise removes where neccessary.
  366. //
  367. // ISSUE - 2000/08/24 - ADRIAO: Maintaining noncorrect Win2K behavior
  368. // Win2K erroneously sent SR's to nonstarted nodes.
  369. //
  370. deviceObject = DeviceNode->PhysicalDeviceObject;
  371. status = IopRemoveDevice(deviceObject, IRP_MN_SURPRISE_REMOVAL);
  372. if ((devnodeState == DeviceNodeStarted) ||
  373. (devnodeState == DeviceNodeStopped) ||
  374. (devnodeState == DeviceNodeStartPostWork) ||
  375. (devnodeState == DeviceNodeRestartCompletion)) {
  376. //deviceObject = DeviceNode->PhysicalDeviceObject;
  377. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  378. "IopSurpriseRemoveLockedDeviceNode: Sending surprise remove irp to device = 0x%p\n",
  379. deviceObject));
  380. //status = IopRemoveDevice(deviceObject, IRP_MN_SURPRISE_REMOVAL);
  381. //
  382. // Disable any device interfaces that may still be enabled for this
  383. // device after the removal.
  384. //
  385. IopDisableDeviceInterfaces(&DeviceNode->InstancePath);
  386. if (NT_SUCCESS(status)) {
  387. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  388. "IopSurpriseRemoveLockedDeviceNode: Releasing devices resources\n"));
  389. IopReleaseDeviceResources(DeviceNode, FALSE);
  390. }
  391. if (DeviceNode->Flags & DNF_ENUMERATED) {
  392. PipSetDevNodeState(DeviceNode, DeviceNodeRemovePendingCloses, NULL);
  393. } else {
  394. ASSERT(schedulerState == DeviceNodeAwaitingQueuedDeletion);
  395. PipSetDevNodeState(DeviceNode, DeviceNodeDeletePendingCloses, NULL);
  396. }
  397. }
  398. ASSERT(DeviceNode->DockInfo.DockStatus != DOCK_ARRIVING);
  399. }
  400. BOOLEAN
  401. IopQueryRemoveLockedDeviceNode(
  402. IN PDEVICE_NODE DeviceNode,
  403. OUT PNP_VETO_TYPE *VetoType,
  404. OUT PUNICODE_STRING VetoName
  405. )
  406. /*++
  407. Routine Description:
  408. This function sends a query remove IRP to a devnode and processes the
  409. results.
  410. Arguments:
  411. DeviceNode - Supplies a pointer to the device node to be query removed.
  412. VetoType - Pointer to address that receives the veto type if the operation
  413. failed.
  414. VetoName - Pointer to a unicode string that will receive data appropriate
  415. to the veto type.
  416. Return Value:
  417. BOOLEAN (success/failure).
  418. --*/
  419. {
  420. PNP_DEVNODE_STATE devnodeState;
  421. PDEVICE_OBJECT deviceObject;
  422. NTSTATUS status;
  423. PAGED_CODE();
  424. devnodeState = DeviceNode->State;
  425. switch(devnodeState) {
  426. case DeviceNodeUninitialized:
  427. case DeviceNodeInitialized:
  428. case DeviceNodeRemoved:
  429. //
  430. // Don't send Queries to devices that haven't been started.
  431. //
  432. ASSERT(DeviceNode->Child == NULL);
  433. return TRUE;
  434. case DeviceNodeDriversAdded:
  435. case DeviceNodeResourcesAssigned:
  436. case DeviceNodeStartCompletion:
  437. case DeviceNodeStartPostWork:
  438. //
  439. // ISSUE - 2000/08/24 - ADRIAO: Maintaining noncorrect Win2K behavior
  440. // Win2K erroneously sent QR's to all nodes.
  441. //
  442. break;
  443. case DeviceNodeStarted:
  444. //
  445. // This guy needs to be queried
  446. //
  447. break;
  448. case DeviceNodeAwaitingQueuedRemoval:
  449. case DeviceNodeAwaitingQueuedDeletion:
  450. case DeviceNodeRemovePendingCloses:
  451. case DeviceNodeStopped:
  452. case DeviceNodeRestartCompletion:
  453. //
  454. // These states should have been culled by IopProcessRelation
  455. //
  456. ASSERT(0);
  457. return TRUE;
  458. case DeviceNodeQueryStopped:
  459. case DeviceNodeEnumeratePending:
  460. case DeviceNodeStartPending:
  461. case DeviceNodeEnumerateCompletion:
  462. case DeviceNodeQueryRemoved:
  463. case DeviceNodeDeletePendingCloses:
  464. case DeviceNodeDeleted:
  465. case DeviceNodeUnspecified:
  466. default:
  467. //
  468. // None of these should be seen here.
  469. //
  470. ASSERT(0);
  471. return TRUE;
  472. }
  473. ASSERT(PipAreDriversLoaded(DeviceNode));
  474. deviceObject = DeviceNode->PhysicalDeviceObject;
  475. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  476. "IopQueryRemoveLockedDeviceNode: Sending QueryRemove irp to device = 0x%p\n",
  477. deviceObject));
  478. status = IopRemoveDevice(deviceObject, IRP_MN_QUERY_REMOVE_DEVICE);
  479. if (!NT_SUCCESS(status)) {
  480. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  481. "IopQueryRemoveLockedDeviceNode: QueryRemove vetoed by device = 0x%p, sending CancelRemove\n",
  482. deviceObject));
  483. IopRemoveDevice(deviceObject, IRP_MN_CANCEL_REMOVE_DEVICE);
  484. *VetoType = PNP_VetoDevice;
  485. RtlCopyUnicodeString(VetoName, &DeviceNode->InstancePath);
  486. return FALSE;
  487. }
  488. PipSetDevNodeState(DeviceNode, DeviceNodeQueryRemoved, NULL);
  489. return TRUE;
  490. }
  491. VOID
  492. IopCancelRemoveLockedDeviceNode(
  493. IN PDEVICE_NODE DeviceNode
  494. )
  495. /*++
  496. Routine Description:
  497. This function sends a cancel remove IRP to a devnode and processes the
  498. results.
  499. Arguments:
  500. DeviceNode - Supplies a pointer to the device node to be cancel removed.
  501. Return Value:
  502. None.
  503. --*/
  504. {
  505. PDEVICE_OBJECT deviceObject;
  506. PAGED_CODE();
  507. if (DeviceNode->State != DeviceNodeQueryRemoved) {
  508. return;
  509. }
  510. //
  511. // ISSUE - 2000/08/24 - ADRIAO: Maintaining noncorrect Win2K behavior
  512. // Win2K erroneously sent QR's to all nodes.
  513. //
  514. //ASSERT(DeviceNode->PreviousState == DeviceNodeStarted);
  515. deviceObject = DeviceNode->PhysicalDeviceObject;
  516. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  517. "IopCancelRemoveLockedDeviceNode: Sending CancelRemove irp to device = 0x%p\n",
  518. deviceObject));
  519. IopRemoveDevice(deviceObject, IRP_MN_CANCEL_REMOVE_DEVICE);
  520. PipRestoreDevNodeState(DeviceNode);
  521. }
  522. VOID
  523. IopRemoveLockedDeviceNode(
  524. IN PDEVICE_NODE DeviceNode,
  525. IN ULONG Problem,
  526. IN OUT PRELATION_LIST RelationsList
  527. )
  528. /*++
  529. Routine Description:
  530. This function sends a remove IRP to a devnode and processes the
  531. results.
  532. Arguments:
  533. DeviceNode - Supplies a pointer to the device node to be removed.
  534. Return Value:
  535. None.
  536. --*/
  537. {
  538. PDEVICE_OBJECT deviceObject = DeviceNode->PhysicalDeviceObject;
  539. PDEVICE_OBJECT *attachedDevices, device1, *device2;
  540. PDRIVER_OBJECT *attachedDrivers, *driver;
  541. ULONG length = 0;
  542. PDEVICE_NODE child, nextChild;
  543. BOOLEAN removeIrpNeeded;
  544. PAGED_CODE();
  545. UNREFERENCED_PARAMETER (RelationsList);
  546. //
  547. // Do our state updates.
  548. //
  549. PpHotSwapInitRemovalPolicy(DeviceNode);
  550. //
  551. // Make sure we WILL drop our references to its children.
  552. //
  553. for(child = DeviceNode->Child; child; child = nextChild) {
  554. //
  555. // Grab a copy of the next sibling before we blow away this devnode.
  556. //
  557. nextChild = child->Sibling;
  558. if (child->Flags & DNF_ENUMERATED) {
  559. child->Flags &= ~DNF_ENUMERATED;
  560. }
  561. ASSERT(child->State == DeviceNodeRemoved);
  562. ASSERT(!PipAreDriversLoaded(child));
  563. //
  564. // If the child has resources and we are wiping out the parent, we need
  565. // to drop the resources (the parent will lose them when his arbiter is
  566. // nuked with the upcoming RemoveDevice.)
  567. //
  568. if (PipDoesDevNodeHaveResources(child)) {
  569. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  570. "IopRemoveLockedDeviceNode: Releasing resources for child device = 0x%p\n",
  571. child->PhysicalDeviceObject));
  572. //
  573. // ADRIAO N.B. 2000/08/21 -
  574. // Note that the child stack has no drivers and as such a
  575. // Remove IRP could be sent here. The stack would be unable to
  576. // distinguish this from AddDevice cleanup.
  577. //
  578. IopRemoveDevice(child->PhysicalDeviceObject, IRP_MN_REMOVE_DEVICE);
  579. IopReleaseDeviceResources(child, FALSE);
  580. }
  581. //
  582. // The devnode will be removed from the tree in
  583. // IopUnlinkDeviceRemovalRelations. We don't remove it here as we want
  584. // the tree structure in place for the upcoming broadcast down to user
  585. // mode.
  586. //
  587. PipSetDevNodeState(child, DeviceNodeDeleted, NULL);
  588. }
  589. if ((DeviceNode->State == DeviceNodeAwaitingQueuedDeletion) ||
  590. (DeviceNode->State == DeviceNodeAwaitingQueuedRemoval)) {
  591. if (!(DeviceNode->Flags & DNF_ENUMERATED)) {
  592. ASSERT(DeviceNode->State == DeviceNodeAwaitingQueuedDeletion);
  593. //
  594. // This happens when pnpevent shortcircuits the surprise remove path
  595. // upon discovering a nonstarted device has been removed from the
  596. // system. This devnode will need a final remove if it alone has been
  597. // pulled from the tree (we don't here know if the parent is going to
  598. // get pulled too, which would make this remove IRP unneccessary.)
  599. //
  600. //PipRestoreDevNodeState(DeviceNode);
  601. PipSetDevNodeState(DeviceNode, DeviceNodeDeletePendingCloses, NULL);
  602. } else {
  603. ASSERT(DeviceNode->State == DeviceNodeAwaitingQueuedRemoval);
  604. PipRestoreDevNodeState(DeviceNode);
  605. }
  606. }
  607. //
  608. // Do the final remove cleanup on the device...
  609. //
  610. switch(DeviceNode->State) {
  611. case DeviceNodeUninitialized:
  612. case DeviceNodeInitialized:
  613. case DeviceNodeRemoved:
  614. //
  615. // ISSUE - 2000/08/24 - ADRIAO: Maintaining noncorrect Win2K behavior
  616. // Win2K erroneously sent SR's and R's to all
  617. // nodes. Those bugs must be fixed in tandem.
  618. //
  619. //removeIrpNeeded = FALSE;
  620. removeIrpNeeded = TRUE;
  621. break;
  622. case DeviceNodeDriversAdded:
  623. case DeviceNodeResourcesAssigned:
  624. case DeviceNodeStartCompletion:
  625. case DeviceNodeStartPostWork:
  626. case DeviceNodeQueryRemoved:
  627. case DeviceNodeRemovePendingCloses:
  628. case DeviceNodeDeletePendingCloses:
  629. //
  630. // Expected.
  631. //
  632. removeIrpNeeded = TRUE;
  633. break;
  634. case DeviceNodeStarted:
  635. case DeviceNodeStopped:
  636. case DeviceNodeRestartCompletion:
  637. case DeviceNodeQueryStopped:
  638. case DeviceNodeEnumeratePending:
  639. case DeviceNodeStartPending:
  640. case DeviceNodeEnumerateCompletion:
  641. case DeviceNodeAwaitingQueuedRemoval:
  642. case DeviceNodeAwaitingQueuedDeletion:
  643. case DeviceNodeDeleted:
  644. case DeviceNodeUnspecified:
  645. default:
  646. //
  647. // None of these should be seen here.
  648. //
  649. ASSERT(0);
  650. removeIrpNeeded = TRUE;
  651. break;
  652. }
  653. //
  654. // Add a reference to each FDO attached to the PDO such that the FDOs won't
  655. // actually go away until the removal operation is completed.
  656. // Note we need to make a copy of all the attached devices because we won't be
  657. // able to traverse the attached chain when the removal operation is done.
  658. //
  659. // ISSUE - 2000/08/21 - ADRIAO: Low resource path
  660. // The allocation failure cases here are quite broken, and now that
  661. // IofCallDriver and IofCompleteRequest reference things appropriately, all
  662. // this is strictly unneccessary.
  663. //
  664. device1 = deviceObject->AttachedDevice;
  665. while (device1) {
  666. length++;
  667. device1 = device1->AttachedDevice;
  668. }
  669. attachedDevices = NULL;
  670. attachedDrivers = NULL;
  671. if (length != 0) {
  672. length = (length + 2) * sizeof(PDEVICE_OBJECT);
  673. attachedDevices = (PDEVICE_OBJECT *) ExAllocatePool(PagedPool, length);
  674. if (attachedDevices) {
  675. attachedDrivers = (PDRIVER_OBJECT *) ExAllocatePool(PagedPool, length);
  676. if (attachedDrivers) {
  677. RtlZeroMemory(attachedDevices, length);
  678. RtlZeroMemory(attachedDrivers, length);
  679. device1 = deviceObject->AttachedDevice;
  680. device2 = attachedDevices;
  681. driver = attachedDrivers;
  682. while (device1) {
  683. ObReferenceObject(device1);
  684. *device2++ = device1;
  685. *driver++ = device1->DriverObject;
  686. device1 = device1->AttachedDevice;
  687. }
  688. } else {
  689. ExFreePool(attachedDevices);
  690. attachedDevices = NULL;
  691. }
  692. }
  693. }
  694. if (removeIrpNeeded) {
  695. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  696. "IopRemoveLockedDeviceNode: Sending remove irp to device = 0x%p\n",
  697. deviceObject));
  698. IopRemoveDevice(deviceObject, IRP_MN_REMOVE_DEVICE);
  699. if (DeviceNode->State == DeviceNodeQueryRemoved) {
  700. //
  701. // Disable any device interfaces that may still be enabled for this
  702. // device after the removal.
  703. //
  704. IopDisableDeviceInterfaces(&DeviceNode->InstancePath);
  705. }
  706. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  707. "IopRemoveLockedDeviceNode: Releasing devices resources\n"));
  708. //
  709. // ISSUE - 2000/3/8 - RobertN - This doesn't take into account the
  710. // cleanup of surprise removed devices. We will query for boot configs
  711. // unnecessarily. We should probably also check if the parent is NULL.
  712. //
  713. IopReleaseDeviceResources(
  714. DeviceNode,
  715. (BOOLEAN) ((DeviceNode->Flags & DNF_ENUMERATED) != 0)
  716. );
  717. }
  718. if (!(DeviceNode->Flags & DNF_ENUMERATED)) {
  719. //
  720. // If the device is a dock, remove it from the list of dock devices
  721. // and change the current Hardware Profile, if necessary.
  722. //
  723. ASSERT(DeviceNode->DockInfo.DockStatus != DOCK_ARRIVING) ;
  724. if ((DeviceNode->DockInfo.DockStatus == DOCK_DEPARTING)||
  725. (DeviceNode->DockInfo.DockStatus == DOCK_EJECTIRP_COMPLETED)) {
  726. PpProfileCommitTransitioningDock(DeviceNode, DOCK_DEPARTING);
  727. }
  728. }
  729. //
  730. // Remove the reference to the attached FDOs to allow them to be actually
  731. // deleted.
  732. //
  733. device2 = attachedDevices;
  734. if (device2 != NULL) {
  735. driver = attachedDrivers;
  736. while (*device2) {
  737. (*device2)->DeviceObjectExtension->ExtensionFlags &= ~(DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED);
  738. (*device2)->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING;
  739. IopUnloadAttachedDriver(*driver);
  740. ObDereferenceObject(*device2);
  741. device2++;
  742. driver++;
  743. }
  744. ExFreePool(attachedDevices);
  745. ExFreePool(attachedDrivers);
  746. }
  747. deviceObject->DeviceObjectExtension->ExtensionFlags &= ~(DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED);
  748. deviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING;
  749. //
  750. // Now mark this one removed if it's still in the tree.
  751. //
  752. if (DeviceNode->Flags & DNF_ENUMERATED) {
  753. ASSERT(DeviceNode->Parent);
  754. PipSetDevNodeState(DeviceNode, DeviceNodeRemoved, NULL);
  755. } else if (DeviceNode->Parent != NULL) {
  756. //
  757. // The devnode will be removed from the tree in
  758. // IopUnlinkDeviceRemovalRelations.
  759. //
  760. PipSetDevNodeState(DeviceNode, DeviceNodeDeleted, NULL);
  761. } else {
  762. ASSERT(DeviceNode->State == DeviceNodeDeletePendingCloses);
  763. PipSetDevNodeState(DeviceNode, DeviceNodeDeleted, NULL);
  764. }
  765. //
  766. // Set the problem codes appropriatly. We don't change the problem codes
  767. // on a devnode unless:
  768. // a) It disappeared.
  769. // b) We're disabling it.
  770. //
  771. if ((!PipDoesDevNodeHaveProblem(DeviceNode)) ||
  772. (Problem == CM_PROB_DEVICE_NOT_THERE) ||
  773. (Problem == CM_PROB_DISABLED)) {
  774. PipClearDevNodeProblem(DeviceNode);
  775. PipSetDevNodeProblem(DeviceNode, Problem);
  776. }
  777. }
  778. NTSTATUS
  779. IopDeleteLockedDeviceNodes(
  780. IN PDEVICE_OBJECT DeviceObject,
  781. IN PRELATION_LIST RelationsList,
  782. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  783. IN BOOLEAN ProcessIndirectDescendants,
  784. IN ULONG Problem,
  785. OUT PNP_VETO_TYPE *VetoType OPTIONAL,
  786. OUT PUNICODE_STRING VetoName OPTIONAL
  787. )
  788. /*++
  789. Routine Description:
  790. This routine performs requested operation on the DeviceObject and
  791. the device objects specified in the DeviceRelations.
  792. Arguments:
  793. DeviceObject - Supplies a pointer to the device object.
  794. DeviceRelations - supplies a pointer to the device's removal relations.
  795. OperationCode - Operation code, i.e., QueryRemove, CancelRemove, Remove...
  796. VetoType - Pointer to address that receives the veto type if the operation
  797. failed.
  798. VetoName - Pointer to a unicode string that will receive data appropriate
  799. to the veto type.
  800. Return Value:
  801. NTSTATUS code.
  802. --*/
  803. {
  804. NTSTATUS status = STATUS_SUCCESS;
  805. PDEVICE_NODE deviceNode;
  806. PDEVICE_OBJECT relatedDeviceObject;
  807. ULONG marker;
  808. BOOLEAN directDescendant;
  809. PAGED_CODE();
  810. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  811. "IopDeleteLockedDeviceNodes: Entered\n DeviceObject = 0x%p\n RelationsList = 0x%p\n OperationCode = %d\n",
  812. DeviceObject,
  813. RelationsList,
  814. OperationCode));
  815. deviceNode = (PDEVICE_NODE) DeviceObject->DeviceObjectExtension->DeviceNode;
  816. marker = 0;
  817. while (IopEnumerateRelations( RelationsList,
  818. &marker,
  819. &relatedDeviceObject,
  820. &directDescendant,
  821. NULL,
  822. TRUE)) {
  823. //
  824. // Depending on the operation we need to do different things.
  825. //
  826. // QueryRemoveDevice / CancelRemoveDevice
  827. // Process both direct and indirect descendants
  828. //
  829. // SurpriseRemoveDevice / RemoveDevice
  830. // Ignore indirect descendants
  831. //
  832. if (directDescendant || ProcessIndirectDescendants) {
  833. deviceNode = (PDEVICE_NODE)relatedDeviceObject->DeviceObjectExtension->DeviceNode;
  834. if (!IopDeleteLockedDeviceNode( deviceNode,
  835. OperationCode,
  836. RelationsList,
  837. Problem,
  838. VetoType,
  839. VetoName)) {
  840. ASSERT(OperationCode == QueryRemoveDevice);
  841. while (IopEnumerateRelations( RelationsList,
  842. &marker,
  843. &relatedDeviceObject,
  844. NULL,
  845. NULL,
  846. FALSE)) {
  847. deviceNode = (PDEVICE_NODE)relatedDeviceObject->DeviceObjectExtension->DeviceNode;
  848. IopDeleteLockedDeviceNode( deviceNode,
  849. CancelRemoveDevice,
  850. RelationsList,
  851. Problem,
  852. VetoType,
  853. VetoName);
  854. }
  855. status = STATUS_UNSUCCESSFUL;
  856. goto exit;
  857. }
  858. }
  859. }
  860. exit:
  861. return status;
  862. }
  863. NTSTATUS
  864. IopBuildRemovalRelationList(
  865. IN PDEVICE_OBJECT DeviceObject,
  866. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  867. OUT PNP_VETO_TYPE *VetoType,
  868. OUT PUNICODE_STRING VetoName,
  869. OUT PRELATION_LIST *RelationsList
  870. )
  871. /*++
  872. Routine Description:
  873. This routine locks the device subtrees for removal operation and returns
  874. a list of device objects which need to be removed with the specified
  875. DeviceObject.
  876. Caller must hold a reference to the DeviceObject.
  877. Arguments:
  878. DeviceObject - Supplies a pointer to the device object to be removed.
  879. OperationCode - Operation code, i.e., QueryEject, CancelEject, Eject...
  880. VetoType - Pointer to address that receives the veto type if the operation
  881. failed.
  882. VetoName - Pointer to a unicode string that will receive data appropriate
  883. to the veto type.
  884. RelationList - supplies a pointer to a variable to receive the device's
  885. relations.
  886. Return Value:
  887. NTSTATUS code.
  888. --*/
  889. {
  890. NTSTATUS status;
  891. PDEVICE_NODE deviceNode;
  892. PRELATION_LIST newRelationsList;
  893. PAGED_CODE();
  894. *RelationsList = NULL;
  895. deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
  896. //
  897. // Obviously no one should try to delete the whole device node tree.
  898. //
  899. ASSERT(DeviceObject != IopRootDeviceNode->PhysicalDeviceObject);
  900. if ((newRelationsList = IopAllocateRelationList(OperationCode)) == NULL) {
  901. return STATUS_INSUFFICIENT_RESOURCES;
  902. }
  903. //
  904. // First process the object itself
  905. //
  906. status = IopProcessRelation(
  907. deviceNode,
  908. OperationCode,
  909. TRUE,
  910. VetoType,
  911. VetoName,
  912. newRelationsList
  913. );
  914. ASSERT(status != STATUS_INVALID_DEVICE_REQUEST);
  915. if (NT_SUCCESS(status)) {
  916. IopCompressRelationList(&newRelationsList);
  917. *RelationsList = newRelationsList;
  918. //
  919. // At this point we have a list of all the relations, those that are
  920. // direct descendants of the original device we are ejecting or
  921. // removing have the DirectDescendant bit set.
  922. //
  923. // Relations which were merged from an existing eject have the tagged
  924. // bit set.
  925. //
  926. // All of the relations and their parents are locked.
  927. //
  928. // There is a reference on each device object by virtue of it being in
  929. // the list. There is another one on each device object because it is
  930. // locked and the lock count is >= 1.
  931. //
  932. // There is also a reference on each relation's parent and it's lock
  933. // count is >= 1.
  934. //
  935. } else {
  936. IopFreeRelationList(newRelationsList);
  937. }
  938. return status;
  939. }
  940. NTSTATUS
  941. PiProcessBusRelations(
  942. IN PDEVICE_NODE DeviceNode,
  943. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  944. IN BOOLEAN IsDirectDescendant,
  945. OUT PNP_VETO_TYPE *VetoType,
  946. OUT PUNICODE_STRING VetoName,
  947. IN OUT PRELATION_LIST RelationsList
  948. )
  949. /*++
  950. Routine Description:
  951. This routine processes the BusRelations for the specified devnode.
  952. Caller must hold the device tree lock.
  953. Arguments:
  954. DeviceNode - Supplies a pointer to the device object to be collected.
  955. OperationCode - Operation code, i.e., QueryRemove, QueryEject, ...
  956. IsDirectDescendant - TRUE if the device object is a direct descendant
  957. of the node the operation is being performed upon.
  958. VetoType - Pointer to address that receives the veto type if the operation
  959. failed.
  960. VetoName - Pointer to a unicode string that will receive data appropriate
  961. to the veto type.
  962. RelationList - supplies a pointer to a variable to receive the device's
  963. removal relations.
  964. Return Value:
  965. NTSTATUS code.
  966. --*/
  967. {
  968. PDEVICE_NODE child;
  969. PDEVICE_OBJECT childDeviceObject;
  970. NTSTATUS status;
  971. PAGED_CODE();
  972. for(child = DeviceNode->Child;
  973. child != NULL;
  974. child = child->Sibling) {
  975. childDeviceObject = child->PhysicalDeviceObject;
  976. status = IopProcessRelation(
  977. child,
  978. OperationCode,
  979. IsDirectDescendant,
  980. VetoType,
  981. VetoName,
  982. RelationsList
  983. );
  984. ASSERT(status == STATUS_SUCCESS || status == STATUS_UNSUCCESSFUL);
  985. if (!NT_SUCCESS(status)) {
  986. return status;
  987. }
  988. }
  989. return STATUS_SUCCESS;
  990. }
  991. NTSTATUS
  992. IopProcessRelation(
  993. IN PDEVICE_NODE DeviceNode,
  994. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  995. IN BOOLEAN IsDirectDescendant,
  996. OUT PNP_VETO_TYPE *VetoType,
  997. OUT PUNICODE_STRING VetoName,
  998. IN OUT PRELATION_LIST RelationsList
  999. )
  1000. /*++
  1001. Routine Description:
  1002. This routine builds the list of device objects that need to be removed or
  1003. examined when the passed in device object is torn down.
  1004. Caller must hold the device tree lock.
  1005. Arguments:
  1006. DeviceNode - Supplies a pointer to the device object to be collected.
  1007. OperationCode - Operation code, i.e., QueryRemove, QueryEject, ...
  1008. IsDirectDescendant - TRUE if the device object is a direct descendant
  1009. of the node the operation is being performed upon.
  1010. VetoType - Pointer to address that receives the veto type if the operation
  1011. failed.
  1012. VetoName - Pointer to a unicode string that will receive data appropriate
  1013. to the veto type.
  1014. RelationList - supplies a pointer to a variable to receive the device's
  1015. removal relations.
  1016. Return Value:
  1017. NTSTATUS code.
  1018. --*/
  1019. {
  1020. PDEVICE_NODE relatedDeviceNode;
  1021. PDEVICE_OBJECT relatedDeviceObject;
  1022. PDEVICE_RELATIONS deviceRelations;
  1023. PLIST_ENTRY ejectLink;
  1024. PPENDING_RELATIONS_LIST_ENTRY ejectEntry;
  1025. PRELATION_LIST pendingRelationList;
  1026. NTSTATUS status;
  1027. ULONG i;
  1028. PNP_DEVNODE_STATE devnodeState;
  1029. PAGED_CODE();
  1030. if (OperationCode == QueryRemoveDevice || OperationCode == EjectDevice) {
  1031. if (DeviceNode->State == DeviceNodeDeleted) {
  1032. //
  1033. // The device has already been removed, fail the attempt.
  1034. //
  1035. return STATUS_UNSUCCESSFUL;
  1036. }
  1037. if ((DeviceNode->State == DeviceNodeAwaitingQueuedRemoval) ||
  1038. (DeviceNode->State == DeviceNodeAwaitingQueuedDeletion)) {
  1039. //
  1040. // The device has failed or is going away. Let the queued
  1041. // remove deal with it.
  1042. //
  1043. return STATUS_UNSUCCESSFUL;
  1044. }
  1045. if ((DeviceNode->State == DeviceNodeRemovePendingCloses) ||
  1046. (DeviceNode->State == DeviceNodeDeletePendingCloses)) {
  1047. //
  1048. // The device is in the process of being surprise removed, let it finish
  1049. //
  1050. *VetoType = PNP_VetoOutstandingOpen;
  1051. RtlCopyUnicodeString(VetoName, &DeviceNode->InstancePath);
  1052. return STATUS_UNSUCCESSFUL;
  1053. }
  1054. if ((DeviceNode->State == DeviceNodeStopped) ||
  1055. (DeviceNode->State == DeviceNodeRestartCompletion)) {
  1056. //
  1057. // We are recovering from a rebalance. This should never happen and
  1058. // this return code will cause us to ASSERT.
  1059. //
  1060. return STATUS_INVALID_DEVICE_REQUEST;
  1061. }
  1062. } else if (DeviceNode->State == DeviceNodeDeleted) {
  1063. //
  1064. // The device has already been removed, ignore it. We should only have
  1065. // seen such a thing if it got handed to us in a Removal or Ejection
  1066. // relation.
  1067. //
  1068. ASSERT(!IsDirectDescendant);
  1069. return STATUS_SUCCESS;
  1070. }
  1071. status = IopAddRelationToList( RelationsList,
  1072. DeviceNode->PhysicalDeviceObject,
  1073. IsDirectDescendant,
  1074. FALSE);
  1075. if (status == STATUS_SUCCESS) {
  1076. if (!(DeviceNode->Flags & DNF_LOCKED_FOR_EJECT)) {
  1077. //
  1078. // Then process the bus relations
  1079. //
  1080. status = PiProcessBusRelations(
  1081. DeviceNode,
  1082. OperationCode,
  1083. IsDirectDescendant,
  1084. VetoType,
  1085. VetoName,
  1086. RelationsList
  1087. );
  1088. if (!NT_SUCCESS(status)) {
  1089. return status;
  1090. }
  1091. //
  1092. // Retrieve the state of the devnode when it failed.
  1093. //
  1094. devnodeState = DeviceNode->State;
  1095. if ((devnodeState == DeviceNodeAwaitingQueuedRemoval) ||
  1096. (devnodeState == DeviceNodeAwaitingQueuedDeletion)) {
  1097. devnodeState = DeviceNode->PreviousState;
  1098. }
  1099. //
  1100. // Next the removal relations
  1101. //
  1102. if ((devnodeState == DeviceNodeStarted) ||
  1103. (devnodeState == DeviceNodeStopped) ||
  1104. (devnodeState == DeviceNodeStartPostWork) ||
  1105. (devnodeState == DeviceNodeRestartCompletion)) {
  1106. status = IopQueryDeviceRelations( RemovalRelations,
  1107. DeviceNode->PhysicalDeviceObject,
  1108. TRUE,
  1109. &deviceRelations);
  1110. if (NT_SUCCESS(status) && deviceRelations) {
  1111. for (i = 0; i < deviceRelations->Count; i++) {
  1112. relatedDeviceObject = deviceRelations->Objects[i];
  1113. relatedDeviceNode = (PDEVICE_NODE)relatedDeviceObject->DeviceObjectExtension->DeviceNode;
  1114. ASSERT(relatedDeviceNode);
  1115. if (relatedDeviceNode) {
  1116. status = IopProcessRelation(
  1117. relatedDeviceNode,
  1118. OperationCode,
  1119. FALSE,
  1120. VetoType,
  1121. VetoName,
  1122. RelationsList
  1123. );
  1124. }
  1125. ObDereferenceObject( relatedDeviceObject );
  1126. ASSERT(status == STATUS_SUCCESS ||
  1127. status == STATUS_UNSUCCESSFUL);
  1128. if (!NT_SUCCESS(status)) {
  1129. ExFreePool(deviceRelations);
  1130. return status;
  1131. }
  1132. }
  1133. ExFreePool(deviceRelations);
  1134. } else {
  1135. if (status != STATUS_NOT_SUPPORTED) {
  1136. IopDbgPrint((IOP_LOADUNLOAD_WARNING_LEVEL,
  1137. "IopProcessRelation: IopQueryDeviceRelations failed, DeviceObject = 0x%p, status = 0x%08X\n",
  1138. DeviceNode->PhysicalDeviceObject, status));
  1139. }
  1140. }
  1141. }
  1142. //
  1143. // Finally the eject relations if we are doing an eject operation
  1144. //
  1145. if (OperationCode != QueryRemoveDevice &&
  1146. OperationCode != RemoveFailedDevice &&
  1147. OperationCode != RemoveUnstartedFailedDevice) {
  1148. status = IopQueryDeviceRelations( EjectionRelations,
  1149. DeviceNode->PhysicalDeviceObject,
  1150. TRUE,
  1151. &deviceRelations);
  1152. if (NT_SUCCESS(status) && deviceRelations) {
  1153. for (i = 0; i < deviceRelations->Count; i++) {
  1154. relatedDeviceObject = deviceRelations->Objects[i];
  1155. relatedDeviceNode = (PDEVICE_NODE)relatedDeviceObject->DeviceObjectExtension->DeviceNode;
  1156. ASSERT(relatedDeviceNode);
  1157. if (relatedDeviceNode) {
  1158. status = IopProcessRelation(
  1159. relatedDeviceNode,
  1160. OperationCode,
  1161. FALSE,
  1162. VetoType,
  1163. VetoName,
  1164. RelationsList
  1165. );
  1166. }
  1167. ObDereferenceObject( relatedDeviceObject );
  1168. ASSERT(status == STATUS_SUCCESS ||
  1169. status == STATUS_UNSUCCESSFUL);
  1170. if (!NT_SUCCESS(status)) {
  1171. ExFreePool(deviceRelations);
  1172. return status;
  1173. }
  1174. }
  1175. ExFreePool(deviceRelations);
  1176. } else {
  1177. if (status != STATUS_NOT_SUPPORTED) {
  1178. IopDbgPrint((IOP_LOADUNLOAD_WARNING_LEVEL,
  1179. "IopProcessRelation: IopQueryDeviceRelations failed, DeviceObject = 0x%p, status = 0x%08X\n",
  1180. DeviceNode->PhysicalDeviceObject,
  1181. status));
  1182. }
  1183. }
  1184. }
  1185. status = STATUS_SUCCESS;
  1186. } else {
  1187. //
  1188. // Look to see if this device is already part of a pending ejection.
  1189. // If it is and we are doing an ejection then we will subsume it
  1190. // within the larger ejection. If we aren't doing an ejection then
  1191. // we better be processing the removal of one of the ejected devices.
  1192. //
  1193. for(ejectLink = IopPendingEjects.Flink;
  1194. ejectLink != &IopPendingEjects;
  1195. ejectLink = ejectLink->Flink) {
  1196. ejectEntry = CONTAINING_RECORD( ejectLink,
  1197. PENDING_RELATIONS_LIST_ENTRY,
  1198. Link);
  1199. if (ejectEntry->RelationsList != NULL &&
  1200. IopIsRelationInList(ejectEntry->RelationsList, DeviceNode->PhysicalDeviceObject)) {
  1201. if (OperationCode == EjectDevice) {
  1202. status = IopRemoveRelationFromList(RelationsList, DeviceNode->PhysicalDeviceObject);
  1203. ASSERT(NT_SUCCESS(status));
  1204. IopCancelPendingEject(ejectEntry);
  1205. pendingRelationList = ejectEntry->RelationsList;
  1206. ejectEntry->RelationsList = NULL;
  1207. //
  1208. // If a parent fails eject and it has a child that is
  1209. // infinitely pending an eject, this means the child now
  1210. // wakes up. One suggestion brought up that does not involve
  1211. // a code change is to amend the WDM spec to say if driver
  1212. // gets a start IRP for a device pending eject, it should
  1213. // cancel the eject IRP automatically.
  1214. //
  1215. IopMergeRelationLists(RelationsList, pendingRelationList, FALSE);
  1216. IopFreeRelationList(pendingRelationList);
  1217. if (IsDirectDescendant) {
  1218. //
  1219. // If IsDirectDescendant is specified then we need to
  1220. // get that bit set on the relation that caused us to
  1221. // do the merge. IopAddRelationToList will fail with
  1222. // STATUS_OBJECT_NAME_COLLISION but the bit will still
  1223. // be set as a side effect.
  1224. //
  1225. IopAddRelationToList( RelationsList,
  1226. DeviceNode->PhysicalDeviceObject,
  1227. TRUE,
  1228. FALSE);
  1229. }
  1230. } else if (OperationCode != QueryRemoveDevice) {
  1231. //
  1232. // Either the device itself disappeared or an ancestor
  1233. // of this device failed in some way. In both cases this
  1234. // happened before we completed the eject IRP. We'll
  1235. // remove it from the list in the pending ejection and
  1236. // return it.
  1237. //
  1238. status = IopRemoveRelationFromList( ejectEntry->RelationsList,
  1239. DeviceNode->PhysicalDeviceObject);
  1240. DeviceNode->Flags &= ~DNF_LOCKED_FOR_EJECT;
  1241. ASSERT(NT_SUCCESS(status));
  1242. } else {
  1243. //
  1244. // Someone is trying to take offline a supertree of this
  1245. // device which happens to be prepared for ejection.
  1246. // Whistler like Win2K won't let this happen (doing so
  1247. // isn't too hard, it involves writing code to cancel
  1248. // the outstanding eject and free the relation list.)
  1249. //
  1250. ASSERT(0);
  1251. return STATUS_INVALID_DEVICE_REQUEST;
  1252. }
  1253. break;
  1254. }
  1255. }
  1256. ASSERT(ejectLink != &IopPendingEjects);
  1257. if (ejectLink == &IopPendingEjects) {
  1258. PP_SAVE_DEVICEOBJECT_TO_TRIAGE_DUMP(DeviceNode->PhysicalDeviceObject);
  1259. KeBugCheckEx( PNP_DETECTED_FATAL_ERROR,
  1260. PNP_ERR_DEVICE_MISSING_FROM_EJECT_LIST,
  1261. (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
  1262. 0,
  1263. 0);
  1264. }
  1265. }
  1266. } else if (status == STATUS_OBJECT_NAME_COLLISION) {
  1267. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  1268. "IopProcessRelation: Duplicate relation, DeviceObject = 0x%p\n",
  1269. DeviceNode->PhysicalDeviceObject));
  1270. status = PiProcessBusRelations(
  1271. DeviceNode,
  1272. OperationCode,
  1273. IsDirectDescendant,
  1274. VetoType,
  1275. VetoName,
  1276. RelationsList
  1277. );
  1278. } else if (status != STATUS_INSUFFICIENT_RESOURCES) {
  1279. PP_SAVE_DEVICEOBJECT_TO_TRIAGE_DUMP(DeviceNode->PhysicalDeviceObject);
  1280. KeBugCheckEx( PNP_DETECTED_FATAL_ERROR,
  1281. PNP_ERR_UNEXPECTED_ADD_RELATION_ERR,
  1282. (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
  1283. (ULONG_PTR)RelationsList,
  1284. status);
  1285. }
  1286. return status;
  1287. }
  1288. BOOLEAN
  1289. IopQueuePendingEject(
  1290. PPENDING_RELATIONS_LIST_ENTRY Entry
  1291. )
  1292. {
  1293. PAGED_CODE();
  1294. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  1295. InsertTailList(&IopPendingEjects, &Entry->Link);
  1296. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  1297. return TRUE;
  1298. }
  1299. NTSTATUS
  1300. IopInvalidateRelationsInList(
  1301. IN PRELATION_LIST RelationsList,
  1302. IN PLUGPLAY_DEVICE_DELETE_TYPE OperationCode,
  1303. IN BOOLEAN OnlyIndirectDescendants,
  1304. IN BOOLEAN RestartDevNode
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. Iterate over the relations in the list creating a second list containing the
  1309. parent of each entry skipping parents which are also in the list. In other
  1310. words, if the list contains node P and node C where node C is a child of node
  1311. P then the parent of node P would be added but not node P itself.
  1312. Arguments:
  1313. RelationsList - List of relations
  1314. OperationCode - Type of operation the invalidation is associated
  1315. with.
  1316. OnlyIndirectDescendants - Indirect relations are those which aren't direct
  1317. descendants (bus relations) of the PDO originally
  1318. targetted for the operation or its direct
  1319. descendants. This would include Removal or
  1320. Eject relations.
  1321. RestartDevNode - If true then any node who's parent was invalidated
  1322. is restarted. This flag requires that all the
  1323. relations in the list have been previously
  1324. sent a remove IRP.
  1325. Return Value:
  1326. NTSTATUS code.
  1327. --*/
  1328. {
  1329. PRELATION_LIST parentsList;
  1330. PDEVICE_OBJECT deviceObject, parentObject;
  1331. PDEVICE_NODE deviceNode;
  1332. ULONG marker;
  1333. BOOLEAN directDescendant, tagged;
  1334. PAGED_CODE();
  1335. parentsList = IopAllocateRelationList(OperationCode);
  1336. if (parentsList == NULL) {
  1337. return STATUS_INSUFFICIENT_RESOURCES;
  1338. }
  1339. IopSetAllRelationsTags( RelationsList, FALSE );
  1340. //
  1341. // Traverse the list creating a new list with the topmost parents of
  1342. // each sublist contained in RelationsList.
  1343. //
  1344. marker = 0;
  1345. while (IopEnumerateRelations( RelationsList,
  1346. &marker,
  1347. &deviceObject,
  1348. &directDescendant,
  1349. &tagged,
  1350. TRUE)) {
  1351. if (!OnlyIndirectDescendants || !directDescendant) {
  1352. if (!tagged) {
  1353. parentObject = deviceObject;
  1354. while (IopSetRelationsTag( RelationsList, parentObject, TRUE ) == STATUS_SUCCESS) {
  1355. deviceNode = parentObject->DeviceObjectExtension->DeviceNode;
  1356. if (RestartDevNode) {
  1357. deviceNode->Flags &= ~DNF_LOCKED_FOR_EJECT;
  1358. //
  1359. // Bring the devnode back online if it:
  1360. // a) It is still physically present
  1361. // b) It was held for an eject
  1362. //
  1363. if ((deviceNode->Flags & DNF_ENUMERATED) &&
  1364. PipIsDevNodeProblem(deviceNode, CM_PROB_HELD_FOR_EJECT)) {
  1365. ASSERT(deviceNode->Child == NULL);
  1366. ASSERT(!PipAreDriversLoaded(deviceNode));
  1367. //
  1368. // This operation is a reorder barrier. This keeps
  1369. // our subsequent enumeration from draining prior
  1370. // to our problem clearing.
  1371. //
  1372. PipRequestDeviceAction( parentObject,
  1373. ClearEjectProblem,
  1374. TRUE,
  1375. 0,
  1376. NULL,
  1377. NULL );
  1378. }
  1379. }
  1380. if (deviceNode->Parent != NULL) {
  1381. parentObject = deviceNode->Parent->PhysicalDeviceObject;
  1382. } else {
  1383. parentObject = NULL;
  1384. break;
  1385. }
  1386. }
  1387. if (parentObject != NULL) {
  1388. IopAddRelationToList( parentsList, parentObject, FALSE, FALSE );
  1389. }
  1390. }
  1391. }
  1392. }
  1393. //
  1394. // Reenumerate each of the parents
  1395. //
  1396. marker = 0;
  1397. while (IopEnumerateRelations( parentsList,
  1398. &marker,
  1399. &deviceObject,
  1400. NULL,
  1401. NULL,
  1402. FALSE)) {
  1403. PipRequestDeviceAction( deviceObject,
  1404. ReenumerateDeviceTree,
  1405. FALSE,
  1406. 0,
  1407. NULL,
  1408. NULL );
  1409. }
  1410. //
  1411. // Free the parents list
  1412. //
  1413. IopFreeRelationList( parentsList );
  1414. return STATUS_SUCCESS;
  1415. }
  1416. VOID
  1417. IopProcessCompletedEject(
  1418. IN PVOID Context
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. This routine is called at passive level from a worker thread that was queued
  1423. either when an eject IRP completed (see io\pnpirp.c - IopDeviceEjectComplete
  1424. or io\pnpirp.c - IopEjectDevice), or when a warm eject needs to be performed.
  1425. We also may need to fire off any enumerations of parents of ejected devices
  1426. to verify they have indeed left.
  1427. Arguments:
  1428. Context - Pointer to the pending relations list which contains the device
  1429. to eject (warm) and the list of parents to reenumerate.
  1430. Return Value:
  1431. None.
  1432. --*/
  1433. {
  1434. PPENDING_RELATIONS_LIST_ENTRY entry = (PPENDING_RELATIONS_LIST_ENTRY)Context;
  1435. NTSTATUS status = STATUS_SUCCESS;
  1436. PAGED_CODE();
  1437. if ((entry->LightestSleepState != PowerSystemWorking) &&
  1438. (entry->LightestSleepState != PowerSystemUnspecified)) {
  1439. //
  1440. // For docks, WinLogon gets to do the honors. For other devices, the
  1441. // user must infer when it's safe to remove the device (if we've powered
  1442. // up, it may not be safe now!)
  1443. //
  1444. entry->DisplaySafeRemovalDialog = FALSE;
  1445. //
  1446. // This is a warm eject request, initiate it here.
  1447. //
  1448. status = IopWarmEjectDevice(entry->DeviceObject, entry->LightestSleepState);
  1449. //
  1450. // We're back and we either succeeded or failed. Either way...
  1451. //
  1452. }
  1453. if (entry->DockInterface) {
  1454. entry->DockInterface->ProfileDepartureSetMode(
  1455. entry->DockInterface->Context,
  1456. PDS_UPDATE_DEFAULT
  1457. );
  1458. entry->DockInterface->InterfaceDereference(
  1459. entry->DockInterface->Context
  1460. );
  1461. }
  1462. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  1463. RemoveEntryList( &entry->Link );
  1464. //
  1465. // Check if the RelationsList pointer in the context structure is NULL. If
  1466. // so, this means we were cancelled because this eject is part of a new
  1467. // larger eject. In that case all we want to do is unlink and free the
  1468. // context structure.
  1469. //
  1470. //
  1471. // Two interesting points about such code.
  1472. //
  1473. // 1) If you wait forever to complete an eject of a dock, we *wait* forever
  1474. // in the Query profile change state. No sneaky adding another dock. You
  1475. // must finish what you started...
  1476. // 2) Let's say you are ejecting a dock, and it is taking a long time. If
  1477. // you try to eject the parent, that eject will *not* grab this lower
  1478. // eject as we will block on the profile change semaphore. Again, finish
  1479. // what you started...
  1480. //
  1481. if (entry->RelationsList != NULL) {
  1482. if (entry->ProfileChangingEject) {
  1483. PpProfileMarkAllTransitioningDocksEjected();
  1484. }
  1485. IopInvalidateRelationsInList(
  1486. entry->RelationsList,
  1487. EjectDevice,
  1488. FALSE,
  1489. TRUE
  1490. );
  1491. //
  1492. // Free the relations list
  1493. //
  1494. IopFreeRelationList( entry->RelationsList );
  1495. } else {
  1496. entry->DisplaySafeRemovalDialog = FALSE;
  1497. }
  1498. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  1499. //
  1500. // Complete the event
  1501. //
  1502. if (entry->DeviceEvent != NULL ) {
  1503. PpCompleteDeviceEvent( entry->DeviceEvent, status );
  1504. }
  1505. if (entry->DisplaySafeRemovalDialog) {
  1506. PpSetDeviceRemovalSafe(entry->DeviceObject, NULL, NULL);
  1507. }
  1508. ObDereferenceObject(entry->DeviceObject);
  1509. ExFreePool( entry );
  1510. }
  1511. VOID
  1512. IopQueuePendingSurpriseRemoval(
  1513. IN PDEVICE_OBJECT DeviceObject,
  1514. IN PRELATION_LIST List,
  1515. IN ULONG Problem
  1516. )
  1517. {
  1518. PPENDING_RELATIONS_LIST_ENTRY entry;
  1519. PAGED_CODE();
  1520. entry = (PPENDING_RELATIONS_LIST_ENTRY) PiAllocateCriticalMemory(
  1521. SurpriseRemoveDevice,
  1522. NonPagedPool,
  1523. sizeof(PENDING_RELATIONS_LIST_ENTRY),
  1524. 'rcpP'
  1525. );
  1526. ASSERT(entry != NULL);
  1527. entry->DeviceObject = DeviceObject;
  1528. entry->RelationsList = List;
  1529. entry->Problem = Problem;
  1530. entry->ProfileChangingEject = FALSE ;
  1531. KeEnterCriticalRegion();
  1532. ExAcquireResourceExclusiveLite(&IopSurpriseRemoveListLock, TRUE);
  1533. InsertTailList(&IopPendingSurpriseRemovals, &entry->Link);
  1534. ExReleaseResourceLite(&IopSurpriseRemoveListLock);
  1535. KeLeaveCriticalRegion();
  1536. }
  1537. VOID
  1538. IopUnlinkDeviceRemovalRelations(
  1539. IN PDEVICE_OBJECT RemovedDeviceObject,
  1540. IN OUT PRELATION_LIST RelationsList,
  1541. IN UNLOCK_UNLINK_ACTION UnlinkAction
  1542. )
  1543. /*++
  1544. Routine Description:
  1545. This routine unlocks the device tree deletion operation.
  1546. If there is any pending kernel deletion, this routine initiates
  1547. a worker thread to perform the work.
  1548. Arguments:
  1549. RemovedDeviceObject - Supplies a pointer to the device object to which the
  1550. remove was originally targetted (as opposed to one of the relations).
  1551. DeviceRelations - supplies a pointer to the device's removal relations.
  1552. UnlinkAction - Specifies which devnodes will be unlinked from the devnode
  1553. tree.
  1554. UnLinkRemovedDeviceNodes - Devnodes which are no longer enumerated and
  1555. have been sent a REMOVE_DEVICE IRP are unlinked.
  1556. UnlinkAllDeviceNodesPendingClose - This is used when a device is
  1557. surprise removed. Devnodes in RelationsList are unlinked from the
  1558. tree if they don't have children and aren't consuming any resources.
  1559. UnlinkOnlyChildDeviceNodesPendingClose - This is used when a device fails
  1560. while started. We unlink any child devnodes of the device which
  1561. failed but not the failed device's devnode.
  1562. Return Value:
  1563. NTSTATUS code.
  1564. --*/
  1565. {
  1566. PDEVICE_NODE deviceNode;
  1567. PDEVICE_OBJECT deviceObject;
  1568. ULONG marker;
  1569. PAGED_CODE();
  1570. UNREFERENCED_PARAMETER (RemovedDeviceObject);
  1571. PpDevNodeLockTree(PPL_TREEOP_BLOCK_READS_FROM_ALLOW);
  1572. if (ARGUMENT_PRESENT(RelationsList)) {
  1573. marker = 0;
  1574. while (IopEnumerateRelations( RelationsList,
  1575. &marker,
  1576. &deviceObject,
  1577. NULL,
  1578. NULL,
  1579. TRUE)) {
  1580. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  1581. //
  1582. // There are three different scenarios in which we want to unlink a
  1583. // devnode from the tree.
  1584. //
  1585. // 1) A devnode is no longer enumerated and has been sent a
  1586. // remove IRP.
  1587. //
  1588. // 2) A devnode has been surprise removed, has no children, has
  1589. // no resources or they've been freed. UnlinkAction will be
  1590. // UnlinkAllDeviceNodesPendingClose.
  1591. //
  1592. // 3) A devnode has failed and a surprise remove IRP has been sent.
  1593. // Then we want to remove children without resources but not the
  1594. // failed devnode itself. UnlinkAction will be
  1595. // UnlinkOnlyChildDeviceNodesPendingClose.
  1596. //
  1597. switch(UnlinkAction) {
  1598. case UnlinkRemovedDeviceNodes:
  1599. //
  1600. // Removes have been sent to every devnode in this relation
  1601. // list. Deconstruct the tree appropriately.
  1602. //
  1603. ASSERT(deviceNode->State != DeviceNodeDeletePendingCloses);
  1604. break;
  1605. case UnlinkAllDeviceNodesPendingClose:
  1606. ASSERT((deviceNode->State == DeviceNodeDeletePendingCloses) ||
  1607. (deviceNode->State == DeviceNodeDeleted));
  1608. break;
  1609. case UnlinkOnlyChildDeviceNodesPendingClose:
  1610. #if DBG
  1611. if (RemovedDeviceObject != deviceObject) {
  1612. ASSERT((deviceNode->State == DeviceNodeDeletePendingCloses) ||
  1613. (deviceNode->State == DeviceNodeDeleted));
  1614. } else {
  1615. ASSERT(deviceNode->State == DeviceNodeRemovePendingCloses);
  1616. }
  1617. #endif
  1618. break;
  1619. default:
  1620. ASSERT(0);
  1621. break;
  1622. }
  1623. //
  1624. // Deconstruct the tree appropriately.
  1625. //
  1626. if ((deviceNode->State == DeviceNodeDeletePendingCloses) ||
  1627. (deviceNode->State == DeviceNodeDeleted)) {
  1628. ASSERT(!(deviceNode->Flags & DNF_ENUMERATED));
  1629. //
  1630. // Remove the devnode from the tree.
  1631. //
  1632. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  1633. "IopUnlinkDeviceRemovalRelations: Cleaning up registry values, instance = %wZ\n",
  1634. &deviceNode->InstancePath));
  1635. PiLockPnpRegistry(TRUE);
  1636. IopCleanupDeviceRegistryValues(&deviceNode->InstancePath);
  1637. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  1638. "IopUnlinkDeviceRemovalRelations: Removing DevNode tree, DevNode = 0x%p\n",
  1639. deviceNode));
  1640. PpDevNodeRemoveFromTree(deviceNode);
  1641. PiUnlockPnpRegistry();
  1642. if (deviceNode->State == DeviceNodeDeleted) {
  1643. ASSERT(PipDoesDevNodeHaveProblem(deviceNode));
  1644. IopRemoveRelationFromList(RelationsList, deviceObject);
  1645. //
  1646. // Ashes to ashes
  1647. // Memory to freelist
  1648. //
  1649. ObDereferenceObject(deviceObject); // Added during Enum
  1650. } else {
  1651. //
  1652. // There is still one more ref on the device object, one
  1653. // holding it to the relation list. Once the final removes
  1654. // are sent the relationlist will be freed and then the
  1655. // final ref will be dropped.
  1656. //
  1657. ObDereferenceObject(deviceObject); // Added during Enum
  1658. }
  1659. } else {
  1660. ASSERT(deviceNode->Flags & DNF_ENUMERATED);
  1661. }
  1662. }
  1663. }
  1664. PpDevNodeUnlockTree(PPL_TREEOP_BLOCK_READS_FROM_ALLOW);
  1665. }
  1666. //
  1667. // The routines below are specific to kernel mode PnP configMgr.
  1668. //
  1669. NTSTATUS
  1670. IopUnloadAttachedDriver(
  1671. IN PDRIVER_OBJECT DriverObject
  1672. )
  1673. /*++
  1674. Routine Description:
  1675. This function unloads the driver for the specified device object if it does not
  1676. control any other device object.
  1677. Arguments:
  1678. DeviceObject - Supplies a pointer to a device object
  1679. Return Value:
  1680. NTSTATUS code.
  1681. --*/
  1682. {
  1683. NTSTATUS status;
  1684. PWCHAR buffer;
  1685. UNICODE_STRING unicodeName;
  1686. ULONG bufferSize;
  1687. PUNICODE_STRING serviceName = &DriverObject->DriverExtension->ServiceKeyName;
  1688. PAGED_CODE();
  1689. if (DriverObject->DriverSection != NULL) {
  1690. if (DriverObject->DeviceObject == NULL) {
  1691. bufferSize = CmRegistryMachineSystemCurrentControlSetServices.Length +
  1692. serviceName->Length + sizeof(WCHAR) +
  1693. sizeof(L"\\");
  1694. buffer = (PWCHAR) ExAllocatePool(
  1695. PagedPool,
  1696. bufferSize);
  1697. if (!buffer) {
  1698. return STATUS_INSUFFICIENT_RESOURCES;
  1699. }
  1700. StringCbPrintfW(
  1701. buffer,
  1702. bufferSize,
  1703. L"%s\\%s",
  1704. CmRegistryMachineSystemCurrentControlSetServices.Buffer,
  1705. serviceName->Buffer);
  1706. RtlInitUnicodeString(&unicodeName, buffer);
  1707. status = IopUnloadDriver(&unicodeName, TRUE);
  1708. if (NT_SUCCESS(status)) {
  1709. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  1710. "****** Unloaded driver (%wZ)\n",
  1711. serviceName));
  1712. } else {
  1713. IopDbgPrint((IOP_LOADUNLOAD_WARNING_LEVEL,
  1714. "****** Error unloading driver (%wZ), status = 0x%08X\n",
  1715. serviceName,
  1716. status));
  1717. }
  1718. ExFreePool(unicodeName.Buffer);
  1719. }
  1720. else {
  1721. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  1722. "****** Skipping unload of driver (%wZ), DriverObject->DeviceObject != NULL\n",
  1723. serviceName));
  1724. }
  1725. }
  1726. else {
  1727. //
  1728. // This is a boot driver, can't be unloaded just return SUCCESS
  1729. //
  1730. IopDbgPrint((IOP_LOADUNLOAD_INFO_LEVEL,
  1731. "****** Skipping unload of boot driver (%wZ)\n",
  1732. serviceName));
  1733. }
  1734. return STATUS_SUCCESS;
  1735. }
  1736. VOID
  1737. PipRequestDeviceRemoval(
  1738. IN PDEVICE_NODE DeviceNode,
  1739. IN BOOLEAN TreeDeletion,
  1740. IN ULONG Problem
  1741. )
  1742. /*++
  1743. Routine Description:
  1744. This routine queues a work item to remove or delete a device.
  1745. Arguments:
  1746. DeviceNode - Supplies a pointer to the device object to be cleaned up.
  1747. TreeDeletion - If TRUE, the devnode is physically missing and should
  1748. eventually end up in the deleted state. If FALSE, the
  1749. stack just needs to be torn down.
  1750. Problem - Problem code to assign to the removed stack.
  1751. Return Value:
  1752. None.
  1753. --*/
  1754. {
  1755. REMOVAL_WALK_CONTEXT removalWalkContext;
  1756. NTSTATUS status;
  1757. PAGED_CODE();
  1758. ASSERT(DeviceNode != NULL);
  1759. if (DeviceNode) {
  1760. if (DeviceNode->InstancePath.Length == 0) {
  1761. IopDbgPrint((IOP_ERROR_LEVEL, "Driver %wZ reported child %p missing right after enumerating it!\n", &DeviceNode->Parent->ServiceName, DeviceNode));
  1762. ASSERT(DeviceNode->InstancePath.Length != 0);
  1763. }
  1764. PPDEVNODE_ASSERT_LOCK_HELD(PPL_TREEOP_ALLOW_READS);
  1765. removalWalkContext.TreeDeletion = TreeDeletion;
  1766. removalWalkContext.DescendantNode = FALSE;
  1767. status = PipRequestDeviceRemovalWorker(
  1768. DeviceNode,
  1769. (PVOID) &removalWalkContext
  1770. );
  1771. ASSERT(NT_SUCCESS(status));
  1772. //
  1773. // Queue the event, we'll return immediately after it's queued.
  1774. //
  1775. PpSetTargetDeviceRemove(
  1776. DeviceNode->PhysicalDeviceObject,
  1777. TRUE,
  1778. TRUE,
  1779. FALSE,
  1780. FALSE,
  1781. Problem,
  1782. NULL,
  1783. NULL,
  1784. NULL,
  1785. NULL
  1786. );
  1787. }
  1788. }
  1789. NTSTATUS
  1790. PipRequestDeviceRemovalWorker(
  1791. IN PDEVICE_NODE DeviceNode,
  1792. IN PVOID Context
  1793. )
  1794. /*++
  1795. Routine Description:
  1796. This function is a worker routine for PipRequestDeviceRemoval routine. It
  1797. is used to mark an entire subtree for removal.
  1798. Arguments:
  1799. DeviceNode - Supplies a pointer to the device node to mark.
  1800. Context - Points to a boolean that indicates whether the removal is
  1801. physical or stack specific.
  1802. Return Value:
  1803. NTSTATUS value.
  1804. --*/
  1805. {
  1806. PREMOVAL_WALK_CONTEXT removalWalkContext;
  1807. PNP_DEVNODE_STATE sentinelState;
  1808. PAGED_CODE();
  1809. removalWalkContext = (PREMOVAL_WALK_CONTEXT) Context;
  1810. switch(DeviceNode->State) {
  1811. case DeviceNodeUninitialized:
  1812. ASSERT(removalWalkContext->TreeDeletion);
  1813. break;
  1814. case DeviceNodeInitialized:
  1815. //
  1816. // This can happen on a non-descendant node if it fails AddDevice.
  1817. //
  1818. break;
  1819. case DeviceNodeDriversAdded:
  1820. //
  1821. // Happens when a parent stops enumerating a kid who had a
  1822. // resource conflict. This can also happen if AddDevice fails when
  1823. // a lower filter is attached but the service fails.
  1824. //
  1825. break;
  1826. case DeviceNodeResourcesAssigned:
  1827. //
  1828. // Happens when a parent stops enumerating a kid who has been
  1829. // assigned resources but hadn't yet been started.
  1830. //
  1831. ASSERT(removalWalkContext->TreeDeletion);
  1832. break;
  1833. case DeviceNodeStartPending:
  1834. //
  1835. // Not implemented yet.
  1836. //
  1837. ASSERT(0);
  1838. break;
  1839. case DeviceNodeStartCompletion:
  1840. case DeviceNodeStartPostWork:
  1841. //
  1842. // These are operational states for taking Added to Started. No
  1843. // descendant should be in this state as the engine currently
  1844. // finishes these before progressing to the next node.
  1845. //
  1846. // Note that DeviceNodeStartPostWork can occur on a legacy added
  1847. // root enumerated devnode. Since the root itself cannot disappear
  1848. // or be removed the below asserts still hold true.
  1849. //
  1850. // ISSUE - 2000/08/12 - ADRIAO: IoReportResourceUsage sync problems
  1851. //
  1852. ASSERT(!removalWalkContext->DescendantNode);
  1853. ASSERT(!removalWalkContext->TreeDeletion);
  1854. break;
  1855. case DeviceNodeStarted:
  1856. break;
  1857. case DeviceNodeQueryStopped:
  1858. //
  1859. // Internal rebalance engine state, should never be seen.
  1860. //
  1861. ASSERT(0);
  1862. break;
  1863. case DeviceNodeStopped:
  1864. ASSERT(removalWalkContext->DescendantNode);
  1865. ASSERT(removalWalkContext->TreeDeletion);
  1866. break;
  1867. case DeviceNodeRestartCompletion:
  1868. //
  1869. // This is an operational state for taking Stopped to Started. No
  1870. // descendant should be in this state as the engine currently
  1871. // finishes these before progressing to the next node.
  1872. //
  1873. ASSERT(!removalWalkContext->DescendantNode);
  1874. ASSERT(!removalWalkContext->TreeDeletion);
  1875. break;
  1876. case DeviceNodeEnumeratePending:
  1877. //
  1878. // Not implemented yet.
  1879. //
  1880. ASSERT(0);
  1881. break;
  1882. case DeviceNodeAwaitingQueuedRemoval:
  1883. case DeviceNodeAwaitingQueuedDeletion:
  1884. //
  1885. // ISSUE - 2000/08/30 - ADRIAO: Excessive reenum race
  1886. // Here we hit a case where we didn't flush the removes in the
  1887. // queue due to excessive enumeration. Flushing the last removes
  1888. // is problematic as they themselves will queue up enums! Until a
  1889. // better solution is found, we convert the state here. Bleargh!!!
  1890. // Note that this can also happen because PipDeviceActionWorker
  1891. // doesn't flush enums in the case of failed
  1892. // PipProcessQueryDeviceState or PipCallDriverAddDevice!
  1893. //
  1894. ASSERT(removalWalkContext->TreeDeletion);
  1895. //ASSERT(0);
  1896. PipRestoreDevNodeState(DeviceNode);
  1897. PipSetDevNodeState(DeviceNode, DeviceNodeAwaitingQueuedDeletion, NULL);
  1898. return STATUS_SUCCESS;
  1899. case DeviceNodeRemovePendingCloses:
  1900. case DeviceNodeRemoved:
  1901. ASSERT(removalWalkContext->TreeDeletion);
  1902. break;
  1903. case DeviceNodeEnumerateCompletion:
  1904. case DeviceNodeQueryRemoved:
  1905. case DeviceNodeDeletePendingCloses:
  1906. case DeviceNodeDeleted:
  1907. case DeviceNodeUnspecified:
  1908. default:
  1909. ASSERT(0);
  1910. break;
  1911. }
  1912. //
  1913. // Give the devnode a sentinel state that will keep the start/enum engine
  1914. // at bay until the removal engine processes the tree.
  1915. //
  1916. sentinelState = (removalWalkContext->TreeDeletion) ?
  1917. DeviceNodeAwaitingQueuedDeletion :
  1918. DeviceNodeAwaitingQueuedRemoval;
  1919. PipSetDevNodeState(DeviceNode, sentinelState, NULL);
  1920. //
  1921. // All subsequent nodes are descendants, and all subsequent removals are
  1922. // deletions.
  1923. //
  1924. removalWalkContext->DescendantNode = TRUE;
  1925. removalWalkContext->TreeDeletion = TRUE;
  1926. return PipForAllChildDeviceNodes(
  1927. DeviceNode,
  1928. PipRequestDeviceRemovalWorker,
  1929. (PVOID) removalWalkContext
  1930. );
  1931. }
  1932. BOOLEAN
  1933. PipIsBeingRemovedSafely(
  1934. IN PDEVICE_NODE DeviceNode
  1935. )
  1936. /*++
  1937. Routine Description:
  1938. This function looks at a device with a physical remove queued against it
  1939. and indicates whether it is safe to remove.
  1940. Arguments:
  1941. DeviceNode - Supplies a pointer to the device node to examine. The devnode
  1942. should be in the DeviceNodeAwaitingQueuedDeletion state.
  1943. Return Value:
  1944. BOOLEAN - TRUE iff the devnode is safe to be removed.
  1945. --*/
  1946. {
  1947. PAGED_CODE();
  1948. ASSERT(DeviceNode->State == DeviceNodeAwaitingQueuedDeletion);
  1949. if (IopDeviceNodeFlagsToCapabilities(DeviceNode)->SurpriseRemovalOK) {
  1950. return TRUE;
  1951. }
  1952. if ((DeviceNode->PreviousState != DeviceNodeStarted) &&
  1953. (DeviceNode->PreviousState != DeviceNodeStopped) &&
  1954. (DeviceNode->PreviousState != DeviceNodeStartPostWork) &&
  1955. (DeviceNode->PreviousState != DeviceNodeRestartCompletion)) {
  1956. return TRUE;
  1957. }
  1958. return FALSE;
  1959. }