Source code of Windows XP (NT5)
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.

2573 lines
78 KiB

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