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.

1293 lines
33 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devnode.c
  5. Abstract:
  6. This file contains routines to maintain our private device node list.
  7. Author:
  8. Forrest Foltz (forrestf) 27-Mar-1996
  9. Revision History:
  10. Modified for nt kernel.
  11. --*/
  12. #include "pnpmgrp.h"
  13. //
  14. // Internal definitions
  15. //
  16. typedef struct _ENUM_CONTEXT{
  17. PENUM_CALLBACK CallersCallback;
  18. PVOID CallersContext;
  19. } ENUM_CONTEXT, *PENUM_CONTEXT;
  20. //
  21. // Internal References
  22. //
  23. NTSTATUS
  24. PipForAllDeviceNodesCallback(
  25. IN PDEVICE_NODE DeviceNode,
  26. IN PVOID Context
  27. );
  28. BOOLEAN
  29. PipAreDriversLoadedWorker(
  30. IN PNP_DEVNODE_STATE CurrentNodeState,
  31. IN PNP_DEVNODE_STATE PreviousNodeState
  32. );
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text(PAGE, PipAreDriversLoaded)
  35. #pragma alloc_text(PAGE, PipAreDriversLoadedWorker)
  36. #pragma alloc_text(PAGE, PipAllocateDeviceNode)
  37. #pragma alloc_text(PAGE, PipForAllDeviceNodes)
  38. #pragma alloc_text(PAGE, PipForDeviceNodeSubtree)
  39. #pragma alloc_text(PAGE, PipForAllChildDeviceNodes)
  40. #pragma alloc_text(PAGE, PipForAllDeviceNodesCallback)
  41. #pragma alloc_text(PAGE, IopDestroyDeviceNode)
  42. //#pragma alloc_text(NONPAGE, PpDevNodeInsertIntoTree)
  43. //#pragma alloc_text(NONPAGE, PpDevNodeRemoveFromTree)
  44. #pragma alloc_text(PAGE, PpDevNodeLockTree)
  45. #pragma alloc_text(PAGE, PpDevNodeUnlockTree)
  46. #if DBG
  47. #pragma alloc_text(PAGE, PpDevNodeAssertLockLevel)
  48. #endif // DBG
  49. #endif // ALLOC_PRAGMA
  50. BOOLEAN
  51. PipAreDriversLoaded(
  52. IN PDEVICE_NODE DeviceNode
  53. )
  54. /*++
  55. Routine Description:
  56. This routine determines whether a devnode should be treated as if it has
  57. drivers attached to the PDO's stack (ie it's been added.)
  58. Arguments:
  59. DeviceNode - Device node to examine.
  60. Return Value:
  61. TRUE if drivers are loaded, FALSE otherwise.
  62. --*/
  63. {
  64. PAGED_CODE();
  65. return PipAreDriversLoadedWorker(
  66. DeviceNode->State,
  67. DeviceNode->PreviousState
  68. );
  69. }
  70. BOOLEAN
  71. PipAreDriversLoadedWorker(
  72. IN PNP_DEVNODE_STATE CurrentNodeState,
  73. IN PNP_DEVNODE_STATE PreviousNodeState
  74. )
  75. /*++
  76. Routine Description:
  77. This routine determines whether a devnode should be treated as if it has
  78. drivers attached to the PDO's stack (ie it's been added.)
  79. Arguments:
  80. CurrentNodeState - Current state of device node to examine.
  81. PreviousNodeState - Previous state of device node to examine.
  82. Return Value:
  83. TRUE if drivers are loaded, FALSE otherwise.
  84. --*/
  85. {
  86. switch(CurrentNodeState) {
  87. case DeviceNodeDriversAdded:
  88. case DeviceNodeResourcesAssigned:
  89. case DeviceNodeStartCompletion:
  90. case DeviceNodeStartPostWork:
  91. case DeviceNodeStarted:
  92. case DeviceNodeQueryStopped:
  93. case DeviceNodeStopped:
  94. case DeviceNodeRestartCompletion:
  95. case DeviceNodeEnumerateCompletion:
  96. case DeviceNodeQueryRemoved:
  97. case DeviceNodeRemovePendingCloses:
  98. case DeviceNodeDeletePendingCloses:
  99. case DeviceNodeAwaitingQueuedRemoval:
  100. return TRUE;
  101. case DeviceNodeAwaitingQueuedDeletion:
  102. return PipAreDriversLoadedWorker(
  103. PreviousNodeState,
  104. DeviceNodeUnspecified
  105. );
  106. case DeviceNodeUninitialized:
  107. case DeviceNodeInitialized:
  108. case DeviceNodeRemoved:
  109. return FALSE;
  110. case DeviceNodeDeleted:
  111. //
  112. // This can be seen by user mode because we defer delinking devices
  113. // from the tree during removal.
  114. //
  115. return FALSE;
  116. case DeviceNodeStartPending:
  117. case DeviceNodeEnumeratePending:
  118. case DeviceNodeUnspecified:
  119. default:
  120. ASSERT(0);
  121. return FALSE;
  122. }
  123. }
  124. BOOLEAN
  125. PipIsDevNodeDNStarted(
  126. IN PDEVICE_NODE DeviceNode
  127. )
  128. /*++
  129. Routine Description:
  130. This routine takes a devnode and determines whether the devnode should
  131. have the user mode DN_STARTED bit set.
  132. Arguments:
  133. DeviceNode - Device node to examine.
  134. Return Value:
  135. TRUE if the devnode should be considered started, FALSE otherwise.
  136. --*/
  137. {
  138. switch (DeviceNode->State) {
  139. case DeviceNodeStartPending:
  140. case DeviceNodeStartCompletion:
  141. case DeviceNodeStartPostWork:
  142. case DeviceNodeStarted:
  143. case DeviceNodeQueryStopped:
  144. case DeviceNodeEnumeratePending:
  145. case DeviceNodeEnumerateCompletion:
  146. case DeviceNodeStopped:
  147. case DeviceNodeRestartCompletion:
  148. return TRUE;
  149. case DeviceNodeUninitialized:
  150. case DeviceNodeInitialized:
  151. case DeviceNodeDriversAdded:
  152. case DeviceNodeResourcesAssigned:
  153. case DeviceNodeRemoved:
  154. case DeviceNodeQueryRemoved:
  155. case DeviceNodeRemovePendingCloses:
  156. case DeviceNodeDeletePendingCloses:
  157. case DeviceNodeAwaitingQueuedRemoval:
  158. case DeviceNodeAwaitingQueuedDeletion:
  159. return FALSE;
  160. case DeviceNodeDeleted:
  161. //
  162. // This can be seen by user mode because we defer delinking devices
  163. // from the tree during removal.
  164. //
  165. return FALSE;
  166. case DeviceNodeUnspecified:
  167. default:
  168. ASSERT(0);
  169. return FALSE;
  170. }
  171. }
  172. VOID
  173. PipClearDevNodeProblem(
  174. IN PDEVICE_NODE DeviceNode
  175. )
  176. {
  177. DeviceNode->Flags &= ~DNF_HAS_PROBLEM;
  178. DeviceNode->Problem = 0;
  179. }
  180. VOID
  181. PipSetDevNodeProblem(
  182. IN PDEVICE_NODE DeviceNode,
  183. IN ULONG Problem
  184. )
  185. {
  186. ASSERT(DeviceNode->State != DeviceNodeUninitialized || !(DeviceNode->Flags & DNF_ENUMERATED) || Problem == CM_PROB_INVALID_DATA);
  187. ASSERT(DeviceNode->State != DeviceNodeStarted);
  188. ASSERT(Problem != 0);
  189. DeviceNode->Flags |= DNF_HAS_PROBLEM; \
  190. DeviceNode->Problem = Problem;
  191. }
  192. VOID
  193. PipSetDevNodeState(
  194. IN PDEVICE_NODE DeviceNode,
  195. IN PNP_DEVNODE_STATE State,
  196. OUT PNP_DEVNODE_STATE *OldState OPTIONAL
  197. )
  198. /*++
  199. Routine Description:
  200. This routine sets a devnodes state and optional returns the prior state.
  201. The prior state is saved and can be restored via PipRestoreDevNodeState.
  202. Arguments:
  203. DeviceNode - Device node to update state.
  204. State - State to place devnode in.
  205. OldState - Optionally receives prior state of devnode.
  206. Return Value:
  207. None.
  208. --*/
  209. {
  210. PNP_DEVNODE_STATE previousState;
  211. KIRQL oldIrql;
  212. ASSERT(State != DeviceNodeQueryStopped || DeviceNode->State == DeviceNodeStarted);
  213. #if DBG
  214. if ((State == DeviceNodeDeleted) ||
  215. (State == DeviceNodeDeletePendingCloses)) {
  216. ASSERT(!(DeviceNode->Flags & DNF_ENUMERATED));
  217. }
  218. #endif
  219. KeAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  220. previousState = DeviceNode->State;
  221. if (DeviceNode->State != State) {
  222. //
  223. // Update the devnode's current and previous state.
  224. //
  225. DeviceNode->State = State;
  226. DeviceNode->PreviousState = previousState;
  227. //
  228. // Push prior state onto the history stack.
  229. //
  230. DeviceNode->StateHistory[DeviceNode->StateHistoryEntry] = previousState;
  231. DeviceNode->StateHistoryEntry++;
  232. DeviceNode->StateHistoryEntry %= STATE_HISTORY_SIZE;
  233. }
  234. KeReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  235. if (ARGUMENT_PRESENT(OldState)) {
  236. *OldState = previousState;
  237. }
  238. if (State == DeviceNodeDeleted) {
  239. PpRemoveDeviceActionRequests(DeviceNode->PhysicalDeviceObject);
  240. }
  241. }
  242. VOID
  243. PipRestoreDevNodeState(
  244. IN PDEVICE_NODE DeviceNode
  245. )
  246. /*++
  247. Routine Description:
  248. This routine restores a devnodes state to the state pushed by the last
  249. PipSetDevNodeState call. This function can only be called once for each
  250. call to PipSetDevNodeState.
  251. Arguments:
  252. DeviceNode - Device node to restore state.
  253. Return Value:
  254. None.
  255. --*/
  256. {
  257. PNP_DEVNODE_STATE previousState;
  258. KIRQL oldIrql;
  259. ASSERT((DeviceNode->State == DeviceNodeQueryRemoved) ||
  260. (DeviceNode->State == DeviceNodeQueryStopped) ||
  261. (DeviceNode->State == DeviceNodeAwaitingQueuedRemoval) ||
  262. (DeviceNode->State == DeviceNodeAwaitingQueuedDeletion));
  263. KeAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  264. //
  265. // Update the devnode's state.
  266. //
  267. previousState = DeviceNode->State;
  268. DeviceNode->State = DeviceNode->PreviousState;
  269. //
  270. // Push the old state onto the history stack.
  271. //
  272. DeviceNode->StateHistory[DeviceNode->StateHistoryEntry] = previousState;
  273. DeviceNode->StateHistoryEntry++;
  274. DeviceNode->StateHistoryEntry %= STATE_HISTORY_SIZE;
  275. #if DBG
  276. //
  277. // Put a sentinel on the stack - restoring twice is a bug.
  278. //
  279. DeviceNode->PreviousState = DeviceNodeUnspecified;
  280. #endif
  281. KeReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  282. }
  283. BOOLEAN
  284. PipIsProblemReadonly(
  285. IN ULONG Problem
  286. )
  287. /*++
  288. Routine Description:
  289. This routine returns TRUE if the specified CM_PROB code cannot be cleared
  290. by user mode, FALSE otherwise.
  291. Arguments:
  292. Problem - CM_PROB_...
  293. Return Value:
  294. TRUE/FALSE.
  295. --*/
  296. {
  297. switch(Problem) {
  298. case CM_PROB_OUT_OF_MEMORY: // Nonresettable due to IoReportResourceUsage path.
  299. case CM_PROB_NORMAL_CONFLICT:
  300. case CM_PROB_PARTIAL_LOG_CONF:
  301. case CM_PROB_DEVICE_NOT_THERE:
  302. case CM_PROB_HARDWARE_DISABLED:
  303. case CM_PROB_DISABLED_SERVICE:
  304. case CM_PROB_TRANSLATION_FAILED:
  305. case CM_PROB_NO_SOFTCONFIG:
  306. case CM_PROB_BIOS_TABLE:
  307. case CM_PROB_IRQ_TRANSLATION_FAILED:
  308. case CM_PROB_DUPLICATE_DEVICE:
  309. case CM_PROB_SYSTEM_SHUTDOWN:
  310. case CM_PROB_HELD_FOR_EJECT:
  311. case CM_PROB_REGISTRY_TOO_LARGE:
  312. case CM_PROB_INVALID_DATA:
  313. return TRUE;
  314. case CM_PROB_FAILED_INSTALL:
  315. case CM_PROB_FAILED_ADD:
  316. case CM_PROB_FAILED_START:
  317. case CM_PROB_NOT_CONFIGURED:
  318. case CM_PROB_NEED_RESTART:
  319. case CM_PROB_REINSTALL:
  320. case CM_PROB_REGISTRY:
  321. case CM_PROB_DISABLED:
  322. case CM_PROB_FAILED_DRIVER_ENTRY:
  323. case CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD:
  324. case CM_PROB_DRIVER_FAILED_LOAD:
  325. case CM_PROB_DRIVER_SERVICE_KEY_INVALID:
  326. case CM_PROB_LEGACY_SERVICE_NO_DEVICES:
  327. case CM_PROB_HALTED:
  328. case CM_PROB_FAILED_POST_START:
  329. case CM_PROB_WILL_BE_REMOVED:
  330. case CM_PROB_DRIVER_BLOCKED:
  331. return FALSE;
  332. case CM_PROB_PHANTOM:
  333. //
  334. // Should never see in kernel mode
  335. //
  336. case CM_PROB_DEVLOADER_FAILED:
  337. case CM_PROB_DEVLOADER_NOT_FOUND:
  338. case CM_PROB_REENUMERATION:
  339. case CM_PROB_VXDLDR:
  340. case CM_PROB_NOT_VERIFIED:
  341. case CM_PROB_LIAR:
  342. case CM_PROB_FAILED_FILTER:
  343. case CM_PROB_MOVED:
  344. case CM_PROB_TOO_EARLY:
  345. case CM_PROB_NO_VALID_LOG_CONF:
  346. case CM_PROB_UNKNOWN_RESOURCE:
  347. case CM_PROB_ENTRY_IS_WRONG_TYPE:
  348. case CM_PROB_LACKED_ARBITRATOR:
  349. case CM_PROB_BOOT_CONFIG_CONFLICT:
  350. case CM_PROB_DEVLOADER_NOT_READY:
  351. case CM_PROB_CANT_SHARE_IRQ:
  352. //
  353. // Win9x specific
  354. //
  355. default:
  356. ASSERT(0);
  357. //
  358. // We return TRUE in this path because that prevents these problems
  359. // from being set on devnodes (SetDeviceProblem won't allow usage
  360. // of ReadOnly problems)
  361. //
  362. return TRUE;
  363. }
  364. }
  365. NTSTATUS
  366. PipAllocateDeviceNode(
  367. IN PDEVICE_OBJECT PhysicalDeviceObject,
  368. OUT PDEVICE_NODE *DeviceNode
  369. )
  370. /*++
  371. Routine Description:
  372. This function allocates a device node from nonpaged pool and initializes
  373. the fields which do not require to hold lock to do so. Since adding
  374. the device node to pnp mgr's device node tree requires acquiring lock,
  375. this routine does not add the device node to device node tree.
  376. Arguments:
  377. PhysicalDeviceObject - Supplies a pointer to its corresponding physical device
  378. object.
  379. Return Value:
  380. a pointer to the newly created device node. Null is returned if failed.
  381. --*/
  382. {
  383. PAGED_CODE();
  384. *DeviceNode = ExAllocatePoolWithTag(
  385. NonPagedPool,
  386. sizeof(DEVICE_NODE),
  387. IOP_DNOD_TAG
  388. );
  389. if (*DeviceNode == NULL ){
  390. return STATUS_INSUFFICIENT_RESOURCES;
  391. }
  392. InterlockedIncrement((LONG *)&IopNumberDeviceNodes);
  393. RtlZeroMemory(*DeviceNode, sizeof(DEVICE_NODE));
  394. (*DeviceNode)->InterfaceType = InterfaceTypeUndefined;
  395. (*DeviceNode)->BusNumber = (ULONG)-1;
  396. (*DeviceNode)->ChildInterfaceType = InterfaceTypeUndefined;
  397. (*DeviceNode)->ChildBusNumber = (ULONG)-1;
  398. (*DeviceNode)->ChildBusTypeIndex = (USHORT)-1;
  399. (*DeviceNode)->State = DeviceNodeUninitialized;
  400. (*DeviceNode)->DisableableDepends = 0;
  401. PpHotSwapInitRemovalPolicy(*DeviceNode);
  402. InitializeListHead(&(*DeviceNode)->DeviceArbiterList);
  403. InitializeListHead(&(*DeviceNode)->DeviceTranslatorList);
  404. if (PhysicalDeviceObject){
  405. (*DeviceNode)->PhysicalDeviceObject = PhysicalDeviceObject;
  406. PhysicalDeviceObject->DeviceObjectExtension->DeviceNode = (PVOID)*DeviceNode;
  407. PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  408. }
  409. InitializeListHead(&(*DeviceNode)->TargetDeviceNotify);
  410. InitializeListHead(&(*DeviceNode)->DockInfo.ListEntry);
  411. InitializeListHead(&(*DeviceNode)->PendedSetInterfaceState);
  412. InitializeListHead(&(*DeviceNode)->LegacyBusListEntry);
  413. if (PpSystemHiveTooLarge) {
  414. return STATUS_SYSTEM_HIVE_TOO_LARGE;
  415. }
  416. return STATUS_SUCCESS;
  417. }
  418. NTSTATUS
  419. PipForAllDeviceNodes(
  420. IN PENUM_CALLBACK Callback,
  421. IN PVOID Context
  422. )
  423. /*++
  424. Routine Description:
  425. This function walks the device node tree and invokes the caller specified
  426. 'Callback' function for each device node.
  427. Note, this routine (or its worker routine) traverses the tree in a top
  428. down manner.
  429. Arguments:
  430. Callback - Supplies the call back routine for each device node.
  431. Context - Supplies a parameter/context for the callback function.
  432. Return Value:
  433. Status returned from Callback, if not successfull then the tree walking stops.
  434. --*/
  435. {
  436. PAGED_CODE();
  437. return PipForDeviceNodeSubtree(IopRootDeviceNode, Callback, Context);
  438. }
  439. NTSTATUS
  440. PipForDeviceNodeSubtree(
  441. IN PDEVICE_NODE DeviceNode,
  442. IN PENUM_CALLBACK Callback,
  443. IN PVOID Context
  444. )
  445. /*++
  446. Routine Description:
  447. This function walks the device node tree under but not including the passed
  448. in device node and perform caller specified 'Callback' function for each
  449. device node.
  450. Note, this routine (or its worker routine) traverses the tree in a top
  451. down manner.
  452. Arguments:
  453. Callback - Supplies the call back routine for each device node.
  454. Context - Supplies a parameter/context for the callback function.
  455. Return Value:
  456. Status returned from Callback, if not successfull then the tree walking stops.
  457. --*/
  458. {
  459. ENUM_CONTEXT enumContext;
  460. NTSTATUS status;
  461. PAGED_CODE();
  462. enumContext.CallersCallback = Callback;
  463. enumContext.CallersContext = Context;
  464. //
  465. // Start with a pointer to the root device node, recursively examine all the
  466. // children until we the callback function says stop or we've looked at all
  467. // of them.
  468. //
  469. PpDevNodeLockTree(PPL_SIMPLE_READ);
  470. status = PipForAllChildDeviceNodes(DeviceNode,
  471. PipForAllDeviceNodesCallback,
  472. (PVOID)&enumContext );
  473. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  474. return status;
  475. }
  476. NTSTATUS
  477. PipForAllChildDeviceNodes(
  478. IN PDEVICE_NODE Parent,
  479. IN PENUM_CALLBACK Callback,
  480. IN PVOID Context
  481. )
  482. /*++
  483. Routine Description:
  484. This function walks the Parent's device node subtree and perform caller specified
  485. 'Callback' function for each device node under Parent.
  486. Note, befor calling this rotuine, callers must acquire the enumeration mutex
  487. of the 'Parent' device node to make sure its children won't go away unless the
  488. call tells them to.
  489. Arguments:
  490. Parent - Supplies a pointer to the device node whose subtree is to be walked.
  491. Callback - Supplies the call back routine for each device node.
  492. Context - Supplies a parameter/context for the callback function.
  493. Return Value:
  494. NTSTATUS value.
  495. --*/
  496. {
  497. PDEVICE_NODE nextChild = Parent->Child;
  498. PDEVICE_NODE child;
  499. NTSTATUS status = STATUS_SUCCESS;
  500. PAGED_CODE();
  501. //
  502. // Process siblings until we find the end of the sibling list or
  503. // the Callback() returns FALSE. Set result = TRUE at the top of
  504. // the loop so that if there are no siblings we will return TRUE,
  505. // e.g. Keep Enumerating.
  506. //
  507. // Note, we need to find next child before calling Callback function
  508. // in case the current child is deleted by the Callback function.
  509. //
  510. while (nextChild && NT_SUCCESS(status)) {
  511. child = nextChild;
  512. nextChild = child->Sibling;
  513. status = Callback(child, Context);
  514. }
  515. return status;
  516. }
  517. NTSTATUS
  518. PipForAllDeviceNodesCallback(
  519. IN PDEVICE_NODE DeviceNode,
  520. IN PVOID Context
  521. )
  522. /*++
  523. Routine Description:
  524. This function is the worker routine for PipForAllChildDeviceNodes routine.
  525. Arguments:
  526. DeviceNode - Supplies a pointer to the device node whose subtree is to be walked.
  527. Context - Supplies a context which contains the caller specified call back
  528. function and parameter.
  529. Return Value:
  530. NTSTATUS value.
  531. --*/
  532. {
  533. PENUM_CONTEXT enumContext;
  534. NTSTATUS status;
  535. PAGED_CODE();
  536. enumContext = (PENUM_CONTEXT)Context;
  537. //
  538. // First call the caller's callback for this devnode
  539. //
  540. status =
  541. enumContext->CallersCallback(DeviceNode, enumContext->CallersContext);
  542. if (NT_SUCCESS(status)) {
  543. //
  544. // Now enumerate the children, if any.
  545. //
  546. if (DeviceNode->Child) {
  547. status = PipForAllChildDeviceNodes(
  548. DeviceNode,
  549. PipForAllDeviceNodesCallback,
  550. Context);
  551. }
  552. }
  553. return status;
  554. }
  555. VOID
  556. IopDestroyDeviceNode(
  557. IN PDEVICE_NODE DeviceNode
  558. )
  559. /*++
  560. Routine Description:
  561. This function is invoked by IopDeleteDevice to clean up the device object's
  562. device node structure.
  563. Arguments:
  564. DeviceNode - Supplies a pointer to the device node whose subtree is to be walked.
  565. Context - Supplies a context which contains the caller specified call back
  566. function and parameter.
  567. Return Value:
  568. NTSTATUS value.
  569. --*/
  570. {
  571. #if DBG
  572. PDEVICE_OBJECT dbgDeviceObject;
  573. #endif
  574. PAGED_CODE();
  575. if (DeviceNode) {
  576. if ((DeviceNode->PhysicalDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) &&
  577. DeviceNode->Parent != NULL) {
  578. PP_SAVE_DEVNODE_TO_TRIAGE_DUMP(DeviceNode);
  579. KeBugCheckEx( PNP_DETECTED_FATAL_ERROR,
  580. PNP_ERR_ACTIVE_PDO_FREED,
  581. (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
  582. 0,
  583. 0);
  584. }
  585. if (DeviceNode->Flags & DNF_LEGACY_RESOURCE_DEVICENODE) {
  586. //
  587. // Release the resources this device consumes (the devicenode will
  588. // get deleted after the release). Basically cleanup after bad
  589. // (legacy) drivers.
  590. //
  591. IopLegacyResourceAllocation( ArbiterRequestUndefined,
  592. IoPnpDriverObject,
  593. DeviceNode->PhysicalDeviceObject,
  594. NULL,
  595. NULL);
  596. return;
  597. }
  598. #if DBG
  599. //
  600. // If Only Parent is NOT NULL, most likely the driver forgot to
  601. // release resources before deleting its FDO. (The driver previously
  602. // call legacy assign resource interface.)
  603. //
  604. ASSERT(DeviceNode->Child == NULL &&
  605. DeviceNode->Sibling == NULL &&
  606. DeviceNode->LastChild == NULL
  607. );
  608. ASSERT(DeviceNode->DockInfo.SerialNumber == NULL &&
  609. IsListEmpty(&DeviceNode->DockInfo.ListEntry));
  610. if (DeviceNode->PhysicalDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) {
  611. ASSERT (DeviceNode->Parent == 0);
  612. }
  613. if (DeviceNode->PreviousResourceList) {
  614. ExFreePool(DeviceNode->PreviousResourceList);
  615. }
  616. if (DeviceNode->PreviousResourceRequirements) {
  617. ExFreePool(DeviceNode->PreviousResourceRequirements);
  618. }
  619. //
  620. // device should not appear to be not-disableable if/when we get here
  621. // if either of these two lines ASSERT, email: jamiehun
  622. //
  623. ASSERT((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) == 0);
  624. ASSERT(DeviceNode->DisableableDepends == 0);
  625. if (DeviceNode->InstancePath.Length) {
  626. dbgDeviceObject = IopDeviceObjectFromDeviceInstance(&DeviceNode->InstancePath);
  627. if (dbgDeviceObject) {
  628. ASSERT(dbgDeviceObject != DeviceNode->PhysicalDeviceObject);
  629. ObDereferenceObject(dbgDeviceObject);
  630. }
  631. }
  632. #endif
  633. if (DeviceNode->DuplicatePDO) {
  634. ObDereferenceObject(DeviceNode->DuplicatePDO);
  635. }
  636. if (DeviceNode->ServiceName.Length != 0) {
  637. ExFreePool(DeviceNode->ServiceName.Buffer);
  638. }
  639. if (DeviceNode->InstancePath.Length != 0) {
  640. ExFreePool(DeviceNode->InstancePath.Buffer);
  641. }
  642. if (DeviceNode->ResourceRequirements) {
  643. ExFreePool(DeviceNode->ResourceRequirements);
  644. }
  645. //
  646. // Dereference all the arbiters and translators on this PDO.
  647. //
  648. IopUncacheInterfaceInformation(DeviceNode->PhysicalDeviceObject) ;
  649. //
  650. // Release any pended IoSetDeviceInterface structures
  651. //
  652. while (!IsListEmpty(&DeviceNode->PendedSetInterfaceState)) {
  653. PPENDING_SET_INTERFACE_STATE entry;
  654. entry = (PPENDING_SET_INTERFACE_STATE)RemoveHeadList(&DeviceNode->PendedSetInterfaceState);
  655. ExFreePool(entry->LinkName.Buffer);
  656. ExFreePool(entry);
  657. }
  658. DeviceNode->PhysicalDeviceObject->DeviceObjectExtension->DeviceNode = NULL;
  659. ExFreePool(DeviceNode);
  660. IopNumberDeviceNodes--;
  661. }
  662. }
  663. VOID
  664. PpDevNodeInsertIntoTree(
  665. IN PDEVICE_NODE ParentNode,
  666. IN PDEVICE_NODE DeviceNode
  667. )
  668. /*++
  669. Routine Description:
  670. This function is called to insert a new devnode into the device tree.
  671. Note that there are two classes of callers:
  672. PnP callers
  673. Legacy callers
  674. All PnP callers hold the device tree lock. Legacy callers however come in
  675. with no locks, as they might be brought into being due to a PnP event. To
  676. deal with the later case, inserts are atomic and legacy callers can never
  677. remove themselves from the tree.
  678. Arguments:
  679. ParentNode - Supplies a pointer to the device node's parent
  680. DeviceNode - Supplies a pointer to the device node which needs to be
  681. inserted into the tree.
  682. Return Value:
  683. None.
  684. --*/
  685. {
  686. ULONG depth;
  687. KIRQL oldIrql;
  688. //
  689. // Acquire spinlock to deal with legacy/PnP synchronization.
  690. //
  691. KeAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  692. //
  693. // Determine the depth of the devnode.
  694. //
  695. depth = ParentNode->Level + 1;
  696. DeviceNode->Level = depth;
  697. //
  698. // Update the maximum depth of the tree.
  699. //
  700. if (depth > IopMaxDeviceNodeLevel) {
  701. IopMaxDeviceNodeLevel = depth;
  702. }
  703. //
  704. // Put this devnode at the end of the parent's list of children. Note that
  705. // the Child/Sibling fields are really the last things to be updated. This
  706. // has to be done as walkers of the tree hold no locks that protect the
  707. // tree from legacy inserts.
  708. //
  709. DeviceNode->Parent = ParentNode;
  710. KeMemoryBarrier();
  711. if (ParentNode->LastChild) {
  712. ASSERT(ParentNode->LastChild->Sibling == NULL);
  713. ParentNode->LastChild->Sibling = DeviceNode;
  714. ParentNode->LastChild = DeviceNode;
  715. } else {
  716. ASSERT(ParentNode->Child == NULL);
  717. ParentNode->Child = ParentNode->LastChild = DeviceNode;
  718. }
  719. KeReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  720. //
  721. // Tree has changed
  722. //
  723. IoDeviceNodeTreeSequence += 1;
  724. }
  725. VOID
  726. PpDevNodeRemoveFromTree(
  727. IN PDEVICE_NODE DeviceNode
  728. )
  729. /*++
  730. Routine Description:
  731. This function removes the device node from the device node tree
  732. Arguments:
  733. DeviceNode - Device node to remove
  734. Return Value:
  735. --*/
  736. {
  737. PDEVICE_NODE *node;
  738. KIRQL oldIrql;
  739. //
  740. // Acquire spinlock to deal with legacy/PnP synchronization.
  741. //
  742. KeAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  743. //
  744. // Unlink the pointer to this device node. (If this is the
  745. // first entry, unlink it from the parents child pointer, else
  746. // remove it from the sibling list)
  747. //
  748. node = &DeviceNode->Parent->Child;
  749. while (*node != DeviceNode) {
  750. node = &(*node)->Sibling;
  751. }
  752. *node = DeviceNode->Sibling;
  753. if (DeviceNode->Parent->Child == NULL) {
  754. DeviceNode->Parent->LastChild = NULL;
  755. } else {
  756. while (*node) {
  757. node = &(*node)->Sibling;
  758. }
  759. DeviceNode->Parent->LastChild = CONTAINING_RECORD(node, DEVICE_NODE, Sibling);
  760. }
  761. KeReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  762. //
  763. // Remove this device node from Legacy Bus information table.
  764. //
  765. IopRemoveLegacyBusDeviceNode(DeviceNode);
  766. //
  767. // Orphan any outstanding device change notifications on these nodes.
  768. //
  769. IopOrphanNotification(DeviceNode);
  770. //
  771. // No longer linked
  772. //
  773. DeviceNode->Parent = NULL;
  774. DeviceNode->Child = NULL;
  775. DeviceNode->Sibling = NULL;
  776. DeviceNode->LastChild = NULL;
  777. }
  778. VOID
  779. PpDevNodeLockTree(
  780. IN PNP_LOCK_LEVEL LockLevel
  781. )
  782. /*++
  783. Routine Description:
  784. This function acquires the tree lock with the appropriate level of
  785. restrictions.
  786. Arguments:
  787. LockLevel:
  788. PPL_SIMPLE_READ - Allows simple examination of the tree.
  789. PPL_TREEOP_ALLOW_READS - Called as part of a StartEnum/Remove/Power
  790. operation, blocks other such operations.
  791. Simple reads can go through however.
  792. PPL_TREEOP_BLOCK_READS - Called as part of a StartEnum/Remove/Power
  793. operation, blocks other such operations.
  794. Simple reads are also blocked.
  795. PPL_TREEOP_BLOCK_READS_FROM_ALLOW - Switch to PPL_TREEOP_BLOCK_READS
  796. when already in
  797. PPL_TREEOP_BLOCK_READS. Note that
  798. PpDevNodeUnlockTree must be
  799. subsequently called on both to
  800. release.
  801. Return Value:
  802. None.
  803. --*/
  804. {
  805. ULONG refCount, remainingCount;
  806. //
  807. // Block any attempt to suspend the thread via user mode.
  808. //
  809. KeEnterCriticalRegion();
  810. switch(LockLevel) {
  811. case PPL_SIMPLE_READ:
  812. ExAcquireSharedWaitForExclusive(&IopDeviceTreeLock, TRUE);
  813. break;
  814. case PPL_TREEOP_ALLOW_READS:
  815. ExAcquireResourceExclusiveLite(&PiEngineLock, TRUE);
  816. ExAcquireSharedWaitForExclusive(&IopDeviceTreeLock, TRUE);
  817. break;
  818. case PPL_TREEOP_BLOCK_READS:
  819. ExAcquireResourceExclusiveLite(&PiEngineLock, TRUE);
  820. ExAcquireResourceExclusiveLite(&IopDeviceTreeLock, TRUE);
  821. break;
  822. case PPL_TREEOP_BLOCK_READS_FROM_ALLOW:
  823. //
  824. // Drop the tree lock and require exclusive.
  825. //
  826. ASSERT(ExIsResourceAcquiredExclusiveLite(&PiEngineLock));
  827. //
  828. // "Shared" is a subset of exclusive. ExIsResourceAcquiredShared
  829. // will return nonzero if it's owned exclusive. We flush out that
  830. // case here.
  831. //
  832. ASSERT(ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock) &&
  833. (!ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeLock)));
  834. //
  835. // Drop the tree lock entirely.
  836. //
  837. refCount = ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock);
  838. for(remainingCount = refCount; remainingCount; remainingCount--) {
  839. ExReleaseResourceLite(&IopDeviceTreeLock);
  840. }
  841. //
  842. // Grab it exclusively while keeping the original count.
  843. //
  844. for(remainingCount = refCount; remainingCount; remainingCount--) {
  845. ExAcquireResourceExclusiveLite(&IopDeviceTreeLock, TRUE);
  846. }
  847. break;
  848. default:
  849. ASSERT(0);
  850. break;
  851. }
  852. }
  853. VOID
  854. PpDevNodeUnlockTree(
  855. IN PNP_LOCK_LEVEL LockLevel
  856. )
  857. /*++
  858. Routine Description:
  859. This function releases the tree lock with the appropriate level of
  860. restrictions.
  861. Arguments:
  862. LockLevel:
  863. PPL_SIMPLE_READ - Allows simple examination of the tree.
  864. PPL_TREEOP_ALLOW_READS - Called as part of a StartEnum/Remove/Power
  865. operation, blocks other such operations.
  866. Simple reads can go through however.
  867. PPL_TREEOP_BLOCK_READS - Called as part of a StartEnum/Remove/Power
  868. operation, blocks other such operations.
  869. Simple reads are also blocked.
  870. PPL_TREEOP_BLOCK_READS_FROM_ALLOW - Switch to PPL_TREEOP_BLOCK_READS
  871. when already in
  872. PPL_TREEOP_BLOCK_READS. Note that
  873. PpDevNodeUnlockTree must be
  874. subsequently called on both to
  875. release.
  876. Return Value:
  877. None.
  878. --*/
  879. {
  880. PPDEVNODE_ASSERT_LOCK_HELD(LockLevel);
  881. switch(LockLevel) {
  882. case PPL_SIMPLE_READ:
  883. ExReleaseResourceLite(&IopDeviceTreeLock);
  884. break;
  885. case PPL_TREEOP_ALLOW_READS:
  886. ExReleaseResourceLite(&IopDeviceTreeLock);
  887. ExReleaseResourceLite(&PiEngineLock);
  888. break;
  889. case PPL_TREEOP_BLOCK_READS:
  890. ExReleaseResourceLite(&IopDeviceTreeLock);
  891. ExReleaseResourceLite(&PiEngineLock);
  892. break;
  893. case PPL_TREEOP_BLOCK_READS_FROM_ALLOW:
  894. //
  895. // The engine lock should still be held here. Now we adjust the
  896. // tree lock. Go back to allow by converting the exclusive lock to
  897. // shared. Note that this doesn't chance the acquisition count.
  898. //
  899. ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeLock));
  900. ASSERT(ExIsResourceAcquiredExclusiveLite(&PiEngineLock));
  901. ExConvertExclusiveToSharedLite(&IopDeviceTreeLock);
  902. break;
  903. default:
  904. ASSERT(0);
  905. break;
  906. }
  907. KeLeaveCriticalRegion();
  908. }
  909. #if DBG
  910. VOID
  911. PpDevNodeAssertLockLevel(
  912. IN PNP_LOCK_LEVEL LockLevel,
  913. IN PCSTR File,
  914. IN ULONG Line
  915. )
  916. /*++
  917. Routine Description:
  918. This asserts the lock is currently held at the appropriate level.
  919. Arguments:
  920. LockLevel:
  921. PPL_SIMPLE_READ - Allows simple examination of the tree.
  922. PPL_TREEOP_ALLOW_READS - Called as part of a StartEnum/Remove/Power
  923. operation, blocks other such operations.
  924. Simple reads can go through however.
  925. PPL_TREEOP_BLOCK_READS - Called as part of a StartEnum/Remove/Power
  926. operation, blocks other such operations.
  927. Simple reads are also blocked.
  928. PPL_TREEOP_BLOCK_READS_FROM_ALLOW - Switch to PPL_TREEOP_BLOCK_READS
  929. when already in
  930. PPL_TREEOP_BLOCK_READS. Note that
  931. PpDevNodeUnlockTree must be
  932. subsequently called on both to
  933. release.
  934. File: Name of c-file asserting the lock is held.
  935. Line: Line number in above c-file.
  936. Return Value:
  937. None.
  938. --*/
  939. {
  940. switch(LockLevel) {
  941. case PPL_SIMPLE_READ:
  942. ASSERT(ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock));
  943. break;
  944. case PPL_TREEOP_ALLOW_READS:
  945. ASSERT(ExIsResourceAcquiredSharedLite(&IopDeviceTreeLock));
  946. ASSERT(ExIsResourceAcquiredExclusiveLite(&PiEngineLock));
  947. break;
  948. case PPL_TREEOP_BLOCK_READS_FROM_ALLOW:
  949. //
  950. // This isn't really a lock level, but this assert-o-matic function
  951. // is called from Unlock, in which case this level means "drop back
  952. // to PPL_TREEOP_ALLOW_READS *from* PPL_TREEOP_BLOCK_READS." So...
  953. //
  954. // Fall through
  955. //
  956. case PPL_TREEOP_BLOCK_READS:
  957. ASSERT(ExIsResourceAcquiredExclusiveLite(&IopDeviceTreeLock));
  958. ASSERT(ExIsResourceAcquiredExclusiveLite(&PiEngineLock));
  959. break;
  960. default:
  961. ASSERT(0);
  962. break;
  963. }
  964. }
  965. #endif // DBG