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.

7180 lines
222 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. pnpenum.c
  5. Abstract:
  6. This module contains routines to perform device enumeration
  7. Author:
  8. Shie-Lin Tzong (shielint) Sept. 5, 1996.
  9. Revision History:
  10. James Cavalaris (t-jcaval) July 29, 1997.
  11. Added IopProcessCriticalDeviceRoutine.
  12. --*/
  13. #include "pnpmgrp.h"
  14. #pragma hdrstop
  15. #include <setupblk.h>
  16. #ifdef POOL_TAGGING
  17. #undef ExAllocatePool
  18. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'nepP')
  19. #endif
  20. #define MAX_REENUMERATION_ATTEMPTS 32
  21. typedef struct _DRIVER_LIST_ENTRY DRIVER_LIST_ENTRY, *PDRIVER_LIST_ENTRY;
  22. typedef struct _PI_DEVICE_REQUEST {
  23. LIST_ENTRY ListEntry;
  24. PDEVICE_OBJECT DeviceObject;
  25. DEVICE_REQUEST_TYPE RequestType;
  26. BOOLEAN ReorderingBarrier;
  27. ULONG_PTR RequestArgument;
  28. PKEVENT CompletionEvent;
  29. PNTSTATUS CompletionStatus;
  30. } PI_DEVICE_REQUEST, *PPI_DEVICE_REQUEST;
  31. struct _DRIVER_LIST_ENTRY {
  32. PDRIVER_OBJECT DriverObject;
  33. PDRIVER_LIST_ENTRY NextEntry;
  34. };
  35. typedef enum _ADD_DRIVER_STAGE {
  36. LowerDeviceFilters = 0,
  37. LowerClassFilters,
  38. DeviceService,
  39. UpperDeviceFilters,
  40. UpperClassFilters,
  41. MaximumAddStage
  42. } ADD_DRIVER_STAGE;
  43. typedef enum _ENUM_TYPE {
  44. EnumTypeNone,
  45. EnumTypeShallow,
  46. EnumTypeDeep
  47. } ENUM_TYPE;
  48. #define VerifierTypeFromServiceType(service) \
  49. (VF_DEVOBJ_TYPE) (service + 2)
  50. typedef struct {
  51. PDEVICE_NODE DeviceNode;
  52. BOOLEAN LoadDriver;
  53. PADD_CONTEXT AddContext;
  54. PDRIVER_LIST_ENTRY DriverLists[MaximumAddStage];
  55. } QUERY_CONTEXT, *PQUERY_CONTEXT;
  56. //
  57. // Hash routine from CNTFS (see cntfs\prefxsup.c)
  58. // (used here in the construction of unique ids)
  59. //
  60. #define HASH_UNICODE_STRING( _pustr, _phash ) { \
  61. PWCHAR _p = (_pustr)->Buffer; \
  62. PWCHAR _ep = _p + ((_pustr)->Length/sizeof(WCHAR)); \
  63. ULONG _chHolder =0; \
  64. \
  65. while( _p < _ep ) { \
  66. _chHolder = 37 * _chHolder + (unsigned int) (*_p++); \
  67. } \
  68. \
  69. *(_phash) = abs(314159269 * _chHolder) % 1000000007; \
  70. }
  71. // Parent prefixes are of the form %x&%x&%x
  72. #define MAX_PARENT_PREFIX (8 + 8 + 8 + 2)
  73. #if 0
  74. #define ASSERT_INITED(x) \
  75. ASSERTMSG("DO_DEVICE_INITIALIZING not cleared on device object", \
  76. ((((x)->Flags) & DO_DEVICE_INITIALIZING) == 0))
  77. #else
  78. #if DBG
  79. #define ASSERT_INITED(x) \
  80. if (((x)->Flags & DO_DEVICE_INITIALIZING) != 0) \
  81. DbgPrint("DO_DEVICE_INITIALIZING flag not cleared on DO %#08lx\n", x);
  82. #else
  83. #define ASSERT_INITED(x) /* nothing */
  84. #endif
  85. #endif
  86. #define PiSetDeviceInstanceSzValue(k, n, v) { \
  87. if (k && *(v)) { \
  88. UNICODE_STRING u; \
  89. PiWstrToUnicodeString(&u, n); \
  90. ZwSetValueKey( \
  91. k, \
  92. &u, \
  93. TITLE_INDEX_VALUE, \
  94. REG_SZ, \
  95. *(v), \
  96. (ULONG)((wcslen(*(v))+1) * sizeof(WCHAR))); \
  97. } \
  98. if (*v) { \
  99. ExFreePool(*v); \
  100. *(v) = NULL; \
  101. } \
  102. }
  103. #define PiSetDeviceInstanceMultiSzValue(k, n, v, s) { \
  104. if (k && *(v)) { \
  105. UNICODE_STRING u; \
  106. PiWstrToUnicodeString(&u, n); \
  107. ZwSetValueKey( \
  108. k, \
  109. &u, \
  110. TITLE_INDEX_VALUE, \
  111. REG_MULTI_SZ, \
  112. *(v), \
  113. s); \
  114. } \
  115. if (*(v)) { \
  116. ExFreePool(*v); \
  117. *(v) = NULL; \
  118. } \
  119. }
  120. #if DBG
  121. VOID
  122. PipAssertDevnodesInConsistentState(
  123. VOID
  124. );
  125. #else
  126. #define PipAssertDevnodesInConsistentState()
  127. #endif
  128. NTSTATUS
  129. PipCallDriverAddDevice(
  130. IN PDEVICE_NODE DeviceNode,
  131. IN BOOLEAN LoadDriver,
  132. IN PADD_CONTEXT AddContext
  133. );
  134. NTSTATUS
  135. PipCallDriverAddDeviceQueryRoutine(
  136. IN PWSTR ValueName,
  137. IN ULONG ValueType,
  138. IN PWCHAR ValueData,
  139. IN ULONG ValueLength,
  140. IN PQUERY_CONTEXT Context,
  141. IN ULONG ServiceType
  142. );
  143. NTSTATUS
  144. PipChangeDeviceObjectFromRegistryProperties(
  145. IN PDEVICE_OBJECT PhysicalDeviceObject,
  146. IN HANDLE DeviceClassPropKey,
  147. IN HANDLE DevicePropKey,
  148. IN BOOLEAN UsePdoCharacteristics
  149. );
  150. VOID
  151. PipDeviceActionWorker(
  152. IN PVOID Context
  153. );
  154. NTSTATUS
  155. PipEnumerateDevice(
  156. IN PDEVICE_NODE DeviceNode,
  157. IN BOOLEAN Synchronous
  158. );
  159. BOOLEAN
  160. PipGetRegistryDwordWithFallback(
  161. IN PUNICODE_STRING valueName,
  162. IN HANDLE PrimaryKey,
  163. IN HANDLE SecondaryKey,
  164. IN OUT PULONG Value
  165. );
  166. PSECURITY_DESCRIPTOR
  167. PipGetRegistrySecurityWithFallback(
  168. IN PUNICODE_STRING valueName,
  169. IN HANDLE PrimaryKey,
  170. IN HANDLE SecondaryKey
  171. );
  172. NTSTATUS
  173. PipMakeGloballyUniqueId(
  174. IN PDEVICE_OBJECT DeviceObject,
  175. IN PWCHAR UniqueId,
  176. OUT PWCHAR *GloballyUniqueId
  177. );
  178. NTSTATUS
  179. PipProcessCriticalDeviceRoutine(
  180. IN HANDLE hDevInstance,
  181. IN PBOOLEAN FoundMatch,
  182. IN PUNICODE_STRING ServiceName,
  183. IN PUNICODE_STRING ClassGuid,
  184. IN PUNICODE_STRING Driver,
  185. IN PUNICODE_STRING LowerFilters,
  186. IN PUNICODE_STRING UpperFilters
  187. );
  188. NTSTATUS
  189. PipProcessDevNodeTree(
  190. IN PDEVICE_NODE SubtreeRootDeviceNode,
  191. IN BOOLEAN LoadDriver,
  192. IN BOOLEAN ReallocateResources,
  193. IN ENUM_TYPE EnumType,
  194. IN BOOLEAN Synchronous,
  195. IN BOOLEAN ProcessOnlyIntermediateStates,
  196. IN PADD_CONTEXT AddContext,
  197. IN PPI_DEVICE_REQUEST Request
  198. );
  199. NTSTATUS
  200. PipProcessNewDeviceNode(
  201. IN OUT PDEVICE_NODE DeviceNode
  202. );
  203. NTSTATUS
  204. PiProcessQueryDeviceState(
  205. IN PDEVICE_OBJECT DeviceObject
  206. );
  207. NTSTATUS
  208. PipProcessRestartPhase1(
  209. IN PDEVICE_NODE DeviceNode,
  210. IN BOOLEAN Synchronous
  211. );
  212. NTSTATUS
  213. PipProcessRestartPhase2(
  214. IN PDEVICE_NODE DeviceNode
  215. );
  216. NTSTATUS
  217. PipProcessStartPhase1(
  218. IN PDEVICE_NODE DeviceNode,
  219. IN BOOLEAN Synchronous
  220. );
  221. NTSTATUS
  222. PipProcessStartPhase2(
  223. IN PDEVICE_NODE DeviceNode
  224. );
  225. NTSTATUS
  226. PipProcessStartPhase3(
  227. IN PDEVICE_NODE DeviceNode
  228. );
  229. NTSTATUS
  230. PiRestartDevice(
  231. IN PPI_DEVICE_REQUEST Request
  232. );
  233. NTSTATUS
  234. PiProcessHaltDevice(
  235. IN PPI_DEVICE_REQUEST Request
  236. );
  237. NTSTATUS
  238. PiResetProblemDevicesWorker(
  239. IN PDEVICE_NODE DeviceNode,
  240. IN PVOID Context
  241. );
  242. VOID
  243. PiMarkDeviceTreeForReenumeration(
  244. IN PDEVICE_NODE DeviceNode,
  245. IN BOOLEAN Subtree
  246. );
  247. NTSTATUS
  248. PiMarkDeviceTreeForReenumerationWorker(
  249. IN PDEVICE_NODE DeviceNode,
  250. IN PVOID Context
  251. );
  252. BOOLEAN
  253. PiCollapseEnumRequests(
  254. PLIST_ENTRY ListHead
  255. );
  256. NTSTATUS
  257. PiProcessAddBootDevices(
  258. IN PPI_DEVICE_REQUEST Request
  259. );
  260. NTSTATUS
  261. PiProcessClearDeviceProblem(
  262. IN PPI_DEVICE_REQUEST Request
  263. );
  264. NTSTATUS
  265. PiProcessRequeryDeviceState(
  266. IN PPI_DEVICE_REQUEST Request
  267. );
  268. NTSTATUS
  269. PiProcessResourceRequirementsChanged(
  270. IN PPI_DEVICE_REQUEST Request
  271. );
  272. NTSTATUS
  273. PiProcessReenumeration(
  274. IN PPI_DEVICE_REQUEST Request
  275. );
  276. NTSTATUS
  277. PiProcessSetDeviceProblem(
  278. IN PPI_DEVICE_REQUEST Request
  279. );
  280. NTSTATUS
  281. PiProcessShutdownPnpDevices(
  282. IN PDEVICE_NODE DeviceNode
  283. );
  284. NTSTATUS
  285. PiProcessStartSystemDevices(
  286. IN PPI_DEVICE_REQUEST Request
  287. );
  288. NTSTATUS
  289. PiBuildDeviceNodeInstancePath(
  290. IN PDEVICE_NODE DeviceNode,
  291. IN PWCHAR BusID,
  292. IN PWCHAR DeviceID,
  293. IN PWCHAR InstanceID
  294. );
  295. NTSTATUS
  296. PiCreateDeviceInstanceKey(
  297. IN PDEVICE_NODE DeviceNode,
  298. OUT PHANDLE InstanceHandle,
  299. OUT PULONG Disposition
  300. );
  301. NTSTATUS
  302. PiQueryAndAllocateBootResources(
  303. IN PDEVICE_NODE DeviceNode,
  304. IN HANDLE LogConfKey
  305. );
  306. NTSTATUS
  307. PiQueryResourceRequirements(
  308. IN PDEVICE_NODE DeviceNode,
  309. IN HANDLE LogConfKey
  310. );
  311. #ifdef ALLOC_PRAGMA
  312. #pragma alloc_text(PAGE, IoShutdownPnpDevices)
  313. #pragma alloc_text(PAGE, PipCallDriverAddDevice)
  314. #pragma alloc_text(PAGE, PipCallDriverAddDeviceQueryRoutine)
  315. #pragma alloc_text(PAGE, PipChangeDeviceObjectFromRegistryProperties)
  316. #pragma alloc_text(PAGE, PipEnumerateDevice)
  317. #pragma alloc_text(PAGE, PipGetRegistryDwordWithFallback)
  318. #pragma alloc_text(PAGE, PipGetRegistrySecurityWithFallback)
  319. #pragma alloc_text(PAGE, PipMakeGloballyUniqueId)
  320. #pragma alloc_text(PAGE, PipProcessCriticalDevice)
  321. #pragma alloc_text(PAGE, PipProcessCriticalDeviceRoutine)
  322. #pragma alloc_text(PAGE, PipProcessDevNodeTree)
  323. #pragma alloc_text(PAGE, PipProcessNewDeviceNode)
  324. #pragma alloc_text(PAGE, PiProcessQueryDeviceState)
  325. #pragma alloc_text(PAGE, PipQueryDeviceCapabilities)
  326. #pragma alloc_text(PAGE, PiProcessHaltDevice)
  327. #pragma alloc_text(PAGE, PpResetProblemDevices)
  328. #pragma alloc_text(PAGE, PiResetProblemDevicesWorker)
  329. #pragma alloc_text(PAGE, PiMarkDeviceTreeForReenumeration)
  330. #pragma alloc_text(PAGE, PiMarkDeviceTreeForReenumerationWorker)
  331. #pragma alloc_text(PAGE, PiProcessAddBootDevices)
  332. #pragma alloc_text(PAGE, PiProcessClearDeviceProblem)
  333. #pragma alloc_text(PAGE, PiProcessRequeryDeviceState)
  334. #pragma alloc_text(PAGE, PiRestartDevice)
  335. #pragma alloc_text(PAGE, PiProcessResourceRequirementsChanged)
  336. #pragma alloc_text(PAGE, PiProcessReenumeration)
  337. #pragma alloc_text(PAGE, PiProcessSetDeviceProblem)
  338. #pragma alloc_text(PAGE, PiProcessShutdownPnpDevices)
  339. #pragma alloc_text(PAGE, PiProcessStartSystemDevices)
  340. #pragma alloc_text(PAGE, PiBuildDeviceNodeInstancePath)
  341. #pragma alloc_text(PAGE, PiCreateDeviceInstanceKey)
  342. #pragma alloc_text(PAGE, PiQueryAndAllocateBootResources)
  343. #pragma alloc_text(PAGE, PiQueryResourceRequirements)
  344. #pragma alloc_text(PAGELK, PiLockDeviceActionQueue)
  345. #pragma alloc_text(PAGELK, PiUnlockDeviceActionQueue)
  346. //#pragma alloc_text(NONPAGE, PiCollapseEnumRequests)
  347. //#pragma alloc_text(NONPAGE, PpRemoveDeviceActionRequests)
  348. //#pragma alloc_text(NONPAGE, PiMarkDeviceStackStartPending)
  349. #endif
  350. //
  351. // This flag indicates if the device's InvalidateDeviceRelation is in progress.
  352. // To read or write this flag, callers must get IopPnpSpinlock.
  353. //
  354. BOOLEAN PipEnumerationInProgress;
  355. BOOLEAN PipTearDownPnpStacksOnShutdown;
  356. WORK_QUEUE_ITEM PipDeviceEnumerationWorkItem;
  357. //
  358. // Internal constant strings
  359. //
  360. #define DEVICE_PREFIX_STRING TEXT("\\Device\\")
  361. #define DOSDEVICES_PREFIX_STRING TEXT("\\DosDevices\\")
  362. VOID
  363. PiLockDeviceActionQueue(
  364. VOID
  365. )
  366. {
  367. KIRQL oldIrql;
  368. for (;;) {
  369. //
  370. // Lock the device tree so that power operations dont overlap PnP
  371. // operations like rebalance.
  372. //
  373. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  374. ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  375. if (!PipEnumerationInProgress) {
  376. //
  377. // Device action worker queue is empty. Make it so that new requests
  378. // get queued but new device action worker item does not get kicked
  379. // off.
  380. //
  381. PipEnumerationInProgress = TRUE;
  382. KeClearEvent(&PiEnumerationLock);
  383. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  384. break;
  385. }
  386. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  387. //
  388. // Unlock the tree so device action worker can finish current processing.
  389. //
  390. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  391. //
  392. // Wait for current device action worker item to complete.
  393. //
  394. KeWaitForSingleObject(
  395. &PiEnumerationLock,
  396. Executive,
  397. KernelMode,
  398. FALSE,
  399. NULL );
  400. }
  401. }
  402. VOID
  403. PiUnlockDeviceActionQueue(
  404. VOID
  405. )
  406. {
  407. KIRQL oldIrql;
  408. //
  409. // Check if we need to kick off the enumeration worker here.
  410. //
  411. ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  412. if (!IsListEmpty(&IopPnpEnumerationRequestList)) {
  413. ExInitializeWorkItem(&PipDeviceEnumerationWorkItem, PipDeviceActionWorker, NULL);
  414. ExQueueWorkItem(&PipDeviceEnumerationWorkItem, DelayedWorkQueue);
  415. } else {
  416. PipEnumerationInProgress = FALSE;
  417. KeSetEvent(&PiEnumerationLock, 0, FALSE);
  418. }
  419. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  420. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  421. }
  422. NTSTATUS
  423. PipRequestDeviceAction(
  424. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  425. IN DEVICE_REQUEST_TYPE RequestType,
  426. IN BOOLEAN ReorderingBarrier,
  427. IN ULONG_PTR RequestArgument,
  428. IN PKEVENT CompletionEvent OPTIONAL,
  429. IN PNTSTATUS CompletionStatus OPTIONAL
  430. )
  431. /*++
  432. Routine Description:
  433. This routine queues a work item to enumerate a device. This is for IO
  434. internal use only.
  435. Arguments:
  436. DeviceObject - Supplies a pointer to the device object to be enumerated.
  437. if NULL, this is a request to retry resources allocation
  438. failed devices.
  439. Request - the reason for the enumeration.
  440. Return Value:
  441. NTSTATUS code.
  442. --*/
  443. {
  444. PPI_DEVICE_REQUEST request;
  445. KIRQL oldIrql;
  446. if (PpPnpShuttingDown) {
  447. return STATUS_TOO_LATE;
  448. }
  449. //
  450. // If this node is ready for enumeration, enqueue it
  451. //
  452. request = ExAllocatePool(NonPagedPool, sizeof(PI_DEVICE_REQUEST));
  453. if (request) {
  454. //
  455. // Put this request onto the pending list
  456. //
  457. if (DeviceObject == NULL) {
  458. DeviceObject = IopRootDeviceNode->PhysicalDeviceObject;
  459. }
  460. ObReferenceObject(DeviceObject);
  461. request->DeviceObject = DeviceObject;
  462. request->RequestType = RequestType;
  463. request->ReorderingBarrier = ReorderingBarrier;
  464. request->RequestArgument = RequestArgument;
  465. request->CompletionEvent = CompletionEvent;
  466. request->CompletionStatus = CompletionStatus;
  467. InitializeListHead(&request->ListEntry);
  468. //
  469. // Insert the request to the request queue. If the request queue is
  470. // not currently being worked on, request a worker thread to start it.
  471. //
  472. ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  473. InsertTailList(&IopPnpEnumerationRequestList, &request->ListEntry);
  474. if (RequestType == AddBootDevices ||
  475. RequestType == ReenumerateBootDevices ||
  476. RequestType == ReenumerateRootDevices) {
  477. ASSERT(!PipEnumerationInProgress);
  478. //
  479. // This is a special request used when booting the system. Instead
  480. // of queuing a work item it synchronously calls the worker routine.
  481. //
  482. PipEnumerationInProgress = TRUE;
  483. KeClearEvent(&PiEnumerationLock);
  484. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  485. PipDeviceActionWorker(NULL);
  486. } else if (PnPBootDriversLoaded && !PipEnumerationInProgress) {
  487. PipEnumerationInProgress = TRUE;
  488. KeClearEvent(&PiEnumerationLock);
  489. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  490. //
  491. // Queue a work item to do the enumeration
  492. //
  493. ExInitializeWorkItem(&PipDeviceEnumerationWorkItem, PipDeviceActionWorker, NULL);
  494. ExQueueWorkItem(&PipDeviceEnumerationWorkItem, DelayedWorkQueue);
  495. } else {
  496. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  497. }
  498. } else {
  499. return STATUS_INSUFFICIENT_RESOURCES;
  500. }
  501. return STATUS_SUCCESS;
  502. }
  503. VOID
  504. PipDeviceActionWorker(
  505. IN PVOID Context
  506. )
  507. /*++
  508. Routine Description:
  509. This function drains items from the "PnP Action queue". The action queue
  510. contains a list of operations that must be synchronized wrt to Start & Enum.
  511. Parameters:
  512. Context - Not used.
  513. ReturnValue:
  514. None.
  515. --*/
  516. {
  517. PPI_DEVICE_REQUEST request;
  518. PPI_DEVICE_REQUEST collapsedRequest;
  519. PLIST_ENTRY entry;
  520. BOOLEAN assignResources;
  521. BOOLEAN bootProcess;
  522. BOOLEAN newDevice;
  523. ADD_CONTEXT addContext;
  524. KIRQL oldIrql;
  525. NTSTATUS status;
  526. BOOLEAN dereferenceDevice;
  527. UNREFERENCED_PARAMETER(Context);
  528. assignResources = FALSE;
  529. bootProcess = FALSE;
  530. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  531. for ( ; ; ) {
  532. status = STATUS_SUCCESS;
  533. //
  534. // PipProcessDevNodeTree always dereferences passed in device. Set this
  535. // to false if PipProcessDevNodeTree is called with the device in the
  536. // original request.
  537. //
  538. dereferenceDevice = TRUE;
  539. ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  540. entry = RemoveHeadList(&IopPnpEnumerationRequestList);
  541. if (entry == &IopPnpEnumerationRequestList) {
  542. if (assignResources == FALSE && bootProcess == FALSE) {
  543. //
  544. // No more processing.
  545. //
  546. break;
  547. }
  548. entry = NULL;
  549. }
  550. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  551. if (entry == NULL) {
  552. ASSERT(assignResources || bootProcess);
  553. if (assignResources || bootProcess) {
  554. addContext.DriverStartType = SERVICE_DEMAND_START;
  555. ObReferenceObject(IopRootDeviceNode->PhysicalDeviceObject);
  556. status = PipProcessDevNodeTree( IopRootDeviceNode,
  557. PnPBootDriversInitialized, // LoadDriver
  558. assignResources, // ReallocateResources
  559. EnumTypeNone,
  560. FALSE,
  561. FALSE,
  562. &addContext,
  563. NULL);
  564. if (!NT_SUCCESS(status)) {
  565. status = STATUS_SUCCESS;
  566. }
  567. assignResources = FALSE;
  568. bootProcess = FALSE;
  569. }
  570. continue;
  571. }
  572. //
  573. // We have a list of requests to process. Processing depends on the type
  574. // of the first one in the list.
  575. //
  576. ASSERT(entry);
  577. request = CONTAINING_RECORD(entry, PI_DEVICE_REQUEST, ListEntry);
  578. InitializeListHead(&request->ListEntry);
  579. if (PP_DO_TO_DN(request->DeviceObject)->State == DeviceNodeDeleted) {
  580. status = STATUS_UNSUCCESSFUL;
  581. } else {
  582. switch (request->RequestType) {
  583. case AddBootDevices:
  584. //
  585. // Boot driver initialization.
  586. //
  587. status = PiProcessAddBootDevices(request);
  588. break;
  589. case AssignResources:
  590. //
  591. // Resources were freed, we want to try to satisfy any
  592. // DNF_INSUFFICIENT_RESOURCES devices.
  593. //
  594. assignResources = TRUE;
  595. break;
  596. case ClearDeviceProblem:
  597. case ClearEjectProblem:
  598. status = PiProcessClearDeviceProblem(request);
  599. break;
  600. case HaltDevice:
  601. status = PiProcessHaltDevice(request);
  602. break;
  603. case RequeryDeviceState:
  604. status = PiProcessRequeryDeviceState(request);
  605. break;
  606. case ResetDevice:
  607. status = PiRestartDevice(request);
  608. break;
  609. case ResourceRequirementsChanged:
  610. status = PiProcessResourceRequirementsChanged(request);
  611. if (!NT_SUCCESS(status)) {
  612. //
  613. // The device wasn't started when IopResourceRequirementsChanged
  614. // was called.
  615. //
  616. assignResources = TRUE;
  617. status = STATUS_SUCCESS;
  618. }
  619. break;
  620. case ReenumerateBootDevices:
  621. //
  622. // Indicate that this is during boot driver initialization phase.
  623. //
  624. bootProcess = TRUE;
  625. break;
  626. case RestartEnumeration: // Used after completion of async I/O
  627. case ReenumerateRootDevices:
  628. case ReenumerateDeviceTree:
  629. //
  630. // FALL THROUGH...
  631. //
  632. case ReenumerateDeviceOnly:
  633. status = PiProcessReenumeration(request);
  634. dereferenceDevice = FALSE;
  635. break;
  636. case SetDeviceProblem:
  637. status = PiProcessSetDeviceProblem(request);
  638. break;
  639. case ShutdownPnpDevices:
  640. status = PiProcessShutdownPnpDevices(IopRootDeviceNode);
  641. break;
  642. case StartDevice:
  643. status = PiRestartDevice(request);
  644. break;
  645. case StartSystemDevices:
  646. status = PiProcessStartSystemDevices(request);
  647. dereferenceDevice = FALSE;
  648. break;
  649. }
  650. }
  651. //
  652. // Free the list.
  653. //
  654. do {
  655. entry = RemoveHeadList(&request->ListEntry);
  656. collapsedRequest = CONTAINING_RECORD(entry, PI_DEVICE_REQUEST, ListEntry);
  657. //
  658. // Done with this enumeration request
  659. //
  660. if (collapsedRequest->CompletionStatus) {
  661. *collapsedRequest->CompletionStatus = status;
  662. }
  663. if (collapsedRequest->CompletionEvent) {
  664. KeSetEvent(collapsedRequest->CompletionEvent, 0, FALSE);
  665. }
  666. //
  667. // Only dereference the original request, the rest get dereferenced
  668. // when we collapse.
  669. //
  670. if ((collapsedRequest == request && dereferenceDevice)) {
  671. ObDereferenceObject(collapsedRequest->DeviceObject);
  672. }
  673. ExFreePool(collapsedRequest);
  674. } while (collapsedRequest != request);
  675. }
  676. PipEnumerationInProgress = FALSE;
  677. KeSetEvent(&PiEnumerationLock, 0, FALSE);
  678. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  679. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  680. }
  681. NTSTATUS
  682. IoShutdownPnpDevices(
  683. VOID
  684. )
  685. /*++
  686. Routine Description:
  687. This function is called by the IO system driver verifier during shutdown.
  688. It queues a work item to Query/Remove all the devices in the tree. All
  689. the ones supporting removal will be removed and their drivers unloaded if
  690. all instances of their devices are removed.
  691. This API should only be called once during shutdown, it has no effect on the
  692. second and subsequent calls.
  693. Parameters:
  694. NONE.
  695. Return Value:
  696. STATUS_SUCCESS if the process was successfully completed. Doesn't mean
  697. any devices were actually removed. Otherwise an error code indicating the
  698. error. There is no guarantee that no devices have been removed if an error
  699. occurs however in the current implementation the only time an error will
  700. be reported is if the operation couldn't be queued.
  701. --*/
  702. {
  703. KEVENT actionEvent;
  704. NTSTATUS actionStatus;
  705. NTSTATUS status;
  706. PAGED_CODE();
  707. KeInitializeEvent(&actionEvent, NotificationEvent, FALSE);
  708. status = PipRequestDeviceAction( NULL,
  709. ShutdownPnpDevices,
  710. FALSE,
  711. 0,
  712. &actionEvent,
  713. &actionStatus);
  714. if (NT_SUCCESS(status)) {
  715. //
  716. // Wait for the event we just queued to finish since synchronous
  717. // operation was requested (non alertable wait).
  718. //
  719. // FUTURE ITEM - Use a timeout here?
  720. //
  721. status = KeWaitForSingleObject( &actionEvent,
  722. Executive,
  723. KernelMode,
  724. FALSE,
  725. NULL);
  726. if (NT_SUCCESS(status)) {
  727. status = actionStatus;
  728. }
  729. }
  730. return status;
  731. }
  732. NTSTATUS
  733. PipEnumerateDevice(
  734. IN PDEVICE_NODE DeviceNode,
  735. IN BOOLEAN Synchronous
  736. )
  737. /*++
  738. Routine Description:
  739. This function assumes that the specified physical device object is
  740. a bus and will enumerate all of the children PDOs on the bus.
  741. Arguments:
  742. DeviceObject - Supplies a pointer to the physical device object to be
  743. enumerated.
  744. StartContext - supplies a pointer to the START_CONTEXT to control how to
  745. add/start new devices.
  746. Return Value:
  747. NTSTATUS code.
  748. --*/
  749. {
  750. NTSTATUS status;
  751. PDEVICE_OBJECT deviceObject;
  752. PAGED_CODE();
  753. DeviceNode->Flags &= ~DNF_REENUMERATE;
  754. //
  755. // First get a reference to the PDO to make sure it won't go away.
  756. //
  757. deviceObject = DeviceNode->PhysicalDeviceObject;
  758. status = IopQueryDeviceRelations( BusRelations,
  759. deviceObject,
  760. Synchronous,
  761. &DeviceNode->OverUsed1.PendingDeviceRelations);
  762. return status;
  763. }
  764. NTSTATUS
  765. PipEnumerateCompleted(
  766. IN PDEVICE_NODE DeviceNode
  767. )
  768. {
  769. PDEVICE_NODE childDeviceNode, nextChildDeviceNode;
  770. PDEVICE_OBJECT childDeviceObject;
  771. BOOLEAN childRemoved;
  772. NTSTATUS status, allocationStatus;
  773. ULONG i;
  774. if (DeviceNode->OverUsed1.PendingDeviceRelations == NULL) {
  775. PipSetDevNodeState(DeviceNode, DeviceNodeStarted, NULL);
  776. return STATUS_SUCCESS;
  777. }
  778. //
  779. // Walk all the child device nodes and mark them as not present
  780. //
  781. childDeviceNode = DeviceNode->Child;
  782. while (childDeviceNode) {
  783. childDeviceNode->Flags &= ~DNF_ENUMERATED;
  784. childDeviceNode = childDeviceNode->Sibling;
  785. }
  786. //
  787. // Check all the PDOs returned see if any new one or any one disappeared.
  788. //
  789. for (i = 0; i < DeviceNode->OverUsed1.PendingDeviceRelations->Count; i++) {
  790. childDeviceObject = DeviceNode->OverUsed1.PendingDeviceRelations->Objects[i];
  791. ASSERT_INITED(childDeviceObject);
  792. if (childDeviceObject->DeviceObjectExtension->ExtensionFlags & DOE_DELETE_PENDING) {
  793. PP_SAVE_DEVICEOBJECT_TO_TRIAGE_DUMP(childDeviceObject);
  794. KeBugCheckEx( PNP_DETECTED_FATAL_ERROR,
  795. PNP_ERR_PDO_ENUMERATED_AFTER_DELETION,
  796. (ULONG_PTR)childDeviceObject,
  797. 0,
  798. 0);
  799. }
  800. //
  801. // We've found another physical device, see if there is
  802. // already a devnode for it.
  803. //
  804. childDeviceNode = (PDEVICE_NODE)childDeviceObject->DeviceObjectExtension->DeviceNode;
  805. if (childDeviceNode == NULL) {
  806. //
  807. // Device node doesn't exist, create one.
  808. //
  809. allocationStatus = PipAllocateDeviceNode(
  810. childDeviceObject,
  811. &childDeviceNode);
  812. if (childDeviceNode) {
  813. //
  814. // We've found or created a devnode for the PDO that the
  815. // bus driver just enumerated.
  816. //
  817. childDeviceNode->Flags |= DNF_ENUMERATED;
  818. //
  819. // Mark the device object a bus enumerated device
  820. //
  821. childDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
  822. //
  823. // Put this new device node at the head of the parent's list
  824. // of children.
  825. //
  826. PpDevNodeInsertIntoTree(DeviceNode, childDeviceNode);
  827. if (allocationStatus == STATUS_SYSTEM_HIVE_TOO_LARGE) {
  828. PipSetDevNodeProblem(childDeviceNode, CM_PROB_REGISTRY_TOO_LARGE);
  829. }
  830. } else {
  831. //
  832. // Had a problem creating a devnode. Pretend we've never
  833. // seen it.
  834. //
  835. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  836. "PipEnumerateDevice: Failed to allocate device node\n"));
  837. ObDereferenceObject(childDeviceObject);
  838. }
  839. } else {
  840. //
  841. // The device is alreay enumerated. Remark it and release the
  842. // device object reference.
  843. //
  844. childDeviceNode->Flags |= DNF_ENUMERATED;
  845. if (childDeviceNode->DockInfo.DockStatus == DOCK_EJECTIRP_COMPLETED) {
  846. //
  847. // A dock that was listed as departing in an eject relation
  848. // didn't actually leave. Remove it from the profile transition
  849. // list...
  850. //
  851. PpProfileCancelTransitioningDock(childDeviceNode, DOCK_DEPARTING);
  852. }
  853. ASSERT(!(childDeviceNode->Flags & DNF_DEVICE_GONE));
  854. ObDereferenceObject(childDeviceObject);
  855. }
  856. }
  857. ExFreePool(DeviceNode->OverUsed1.PendingDeviceRelations);
  858. DeviceNode->OverUsed1.PendingDeviceRelations = NULL;
  859. //
  860. // If we get here, the enumeration was successful. Process any missing
  861. // devnodes.
  862. //
  863. childRemoved = FALSE;
  864. for (childDeviceNode = DeviceNode->Child;
  865. childDeviceNode != NULL;
  866. childDeviceNode = nextChildDeviceNode) {
  867. //
  868. // First, we need to remember the 'next child' because the 'child' will be
  869. // removed and we won't be able to find the 'next child.'
  870. //
  871. nextChildDeviceNode = childDeviceNode->Sibling;
  872. if (!(childDeviceNode->Flags & DNF_ENUMERATED)) {
  873. if (!(childDeviceNode->Flags & DNF_DEVICE_GONE)) {
  874. childDeviceNode->Flags |= DNF_DEVICE_GONE;
  875. PipRequestDeviceRemoval(
  876. childDeviceNode,
  877. TRUE,
  878. CM_PROB_DEVICE_NOT_THERE
  879. );
  880. childRemoved = TRUE;
  881. }
  882. }
  883. }
  884. ASSERT(DeviceNode->State == DeviceNodeEnumerateCompletion);
  885. PipSetDevNodeState(DeviceNode, DeviceNodeStarted, NULL);
  886. //
  887. // The root enumerator gets confused if we reenumerate it before we process
  888. // newly reported PDOs. Since it can't possibly create the scenario we are
  889. // trying to fix, we won't bother waiting for the removes to complete before
  890. // processing the new devnodes.
  891. //
  892. if (childRemoved && DeviceNode != IopRootDeviceNode) {
  893. status = STATUS_PNP_RESTART_ENUMERATION;
  894. } else {
  895. status = STATUS_SUCCESS;
  896. }
  897. return status;
  898. }
  899. VOID
  900. PiMarkDeviceStackStartPending(
  901. IN PDEVICE_OBJECT DeviceObject,
  902. IN BOOLEAN Set
  903. )
  904. /*++
  905. Routine Description:
  906. This function marks the entire device stack with DOE_START_PENDING.
  907. Arguments:
  908. DeviceObject - PDO for the device stack.
  909. Return Value:
  910. None.
  911. --*/
  912. {
  913. PDEVICE_OBJECT attachedDevice;
  914. KIRQL irql;
  915. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  916. for (attachedDevice = DeviceObject;
  917. attachedDevice != NULL;
  918. attachedDevice = attachedDevice->AttachedDevice) {
  919. if (Set) {
  920. attachedDevice->DeviceObjectExtension->ExtensionFlags |= DOE_START_PENDING;
  921. } else {
  922. attachedDevice->DeviceObjectExtension->ExtensionFlags &= ~DOE_START_PENDING;
  923. }
  924. }
  925. KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, irql);
  926. }
  927. NTSTATUS
  928. PiBuildDeviceNodeInstancePath(
  929. IN PDEVICE_NODE DeviceNode,
  930. IN PWCHAR BusID,
  931. IN PWCHAR DeviceID,
  932. IN PWCHAR InstanceID
  933. )
  934. /*++
  935. Routine Description:
  936. This function builds the instance path (BusID\DeviceID\InstanceID). If
  937. successful, it will free the storage for any existing instance path and
  938. replace with the new one.
  939. Arguments:
  940. DeviceNode - DeviceNode for which the instance path will be built.
  941. BusID - Bus ID.
  942. DeviceID - Device ID.
  943. InstanceID - Instance ID.
  944. Return Value:
  945. NTSTATUS.
  946. --*/
  947. {
  948. ULONG length;
  949. PWCHAR instancePath;
  950. PAGED_CODE();
  951. if (BusID == NULL || DeviceID == NULL || InstanceID == NULL) {
  952. ASSERT( PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) ||
  953. PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) ||
  954. PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY));
  955. return STATUS_UNSUCCESSFUL;
  956. }
  957. length = (ULONG)((wcslen(BusID) + wcslen(DeviceID) + wcslen(InstanceID) + 2) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
  958. instancePath = (PWCHAR)ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, length);
  959. if (!instancePath) {
  960. return STATUS_INSUFFICIENT_RESOURCES;
  961. }
  962. //
  963. // Construct the instance path as <BUS>\<DEVICE>\<INSTANCE>. This should always be NULL terminated
  964. // since we have precomputed the length that we pass into this counted routine.
  965. //
  966. _snwprintf(instancePath, length / sizeof(WCHAR), L"%s\\%s\\%s", BusID, DeviceID, InstanceID);
  967. //
  968. // Free old instance path.
  969. //
  970. if (DeviceNode->InstancePath.Buffer != NULL) {
  971. IopCleanupDeviceRegistryValues(&DeviceNode->InstancePath);
  972. ExFreePool(DeviceNode->InstancePath.Buffer);
  973. }
  974. RtlInitUnicodeString(&DeviceNode->InstancePath, instancePath);
  975. return STATUS_SUCCESS;
  976. }
  977. NTSTATUS
  978. PiCreateDeviceInstanceKey(
  979. IN PDEVICE_NODE DeviceNode,
  980. OUT PHANDLE InstanceKey,
  981. OUT PULONG Disposition
  982. )
  983. /*++
  984. Routine Description:
  985. This function will create the device instance key.
  986. Arguments:
  987. DeviceNode - DeviceNode for which the instance path will be built.
  988. InstanceKey - Will recieve the instance key handle.
  989. Disposition - Will recieve the disposition whether the key existed or was newly created.
  990. Return Value:
  991. NTSTATUS.
  992. --*/
  993. {
  994. NTSTATUS status;
  995. HANDLE enumHandle;
  996. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  997. UNICODE_STRING unicodeString;
  998. PAGED_CODE();
  999. *InstanceKey = NULL;
  1000. *Disposition = 0;
  1001. PiLockPnpRegistry(FALSE);
  1002. status = IopOpenRegistryKeyEx(
  1003. &enumHandle,
  1004. NULL,
  1005. &CmRegistryMachineSystemCurrentControlSetEnumName,
  1006. KEY_ALL_ACCESS
  1007. );
  1008. if (NT_SUCCESS(status)) {
  1009. status = IopCreateRegistryKeyEx(
  1010. InstanceKey,
  1011. enumHandle,
  1012. &DeviceNode->InstancePath,
  1013. KEY_ALL_ACCESS,
  1014. REG_OPTION_NON_VOLATILE,
  1015. Disposition
  1016. );
  1017. if (NT_SUCCESS(status)) {
  1018. //
  1019. // Keys migrated by textmode setup should be treated as "new".
  1020. // Migrated keys are identified by the presence of non-zero
  1021. // REG_DWORD value "Migrated" under the device instance key.
  1022. //
  1023. if (*Disposition != REG_CREATED_NEW_KEY) {
  1024. keyValueInformation = NULL;
  1025. IopGetRegistryValue(
  1026. *InstanceKey,
  1027. REGSTR_VALUE_MIGRATED,
  1028. &keyValueInformation);
  1029. if (keyValueInformation) {
  1030. if ( keyValueInformation->Type == REG_DWORD &&
  1031. keyValueInformation->DataLength == sizeof(ULONG) &&
  1032. *(PULONG)KEY_VALUE_DATA(keyValueInformation) != 0) {
  1033. *Disposition = REG_CREATED_NEW_KEY;
  1034. }
  1035. PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_MIGRATED);
  1036. ZwDeleteValueKey(*InstanceKey, &unicodeString);
  1037. ExFreePool(keyValueInformation);
  1038. }
  1039. }
  1040. } else {
  1041. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  1042. "PpCreateDeviceInstanceKey: Unable to create %wZ\n",
  1043. &DeviceNode->InstancePath));
  1044. ASSERT(*InstanceKey != NULL);
  1045. }
  1046. ZwClose(enumHandle);
  1047. } else {
  1048. //
  1049. // This would be very bad.
  1050. //
  1051. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  1052. "PpCreateDeviceInstanceKey: Unable to open %wZ\n",
  1053. &CmRegistryMachineSystemCurrentControlSetEnumName));
  1054. ASSERT(enumHandle != NULL);
  1055. }
  1056. PiUnlockPnpRegistry();
  1057. return status;
  1058. }
  1059. NTSTATUS
  1060. PiQueryAndAllocateBootResources(
  1061. IN PDEVICE_NODE DeviceNode,
  1062. IN HANDLE LogConfKey
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. This function will query the BOOT resources for the device and reserve them from the arbiter.
  1067. Arguments:
  1068. DeviceNode - DeviceNode for which the BOOT resources need to be queried.
  1069. LogConfKey - Handle to the LogConf key under the device instance key.
  1070. Return Value:
  1071. NTSTATUS.
  1072. --*/
  1073. {
  1074. NTSTATUS status;
  1075. PCM_RESOURCE_LIST cmResource;
  1076. ULONG cmLength;
  1077. UNICODE_STRING unicodeString;
  1078. PAGED_CODE();
  1079. status = STATUS_SUCCESS;
  1080. cmResource = NULL;
  1081. cmLength = 0;
  1082. if (DeviceNode->BootResources == NULL) {
  1083. status = IopQueryDeviceResources(
  1084. DeviceNode->PhysicalDeviceObject,
  1085. QUERY_RESOURCE_LIST,
  1086. &cmResource,
  1087. &cmLength);
  1088. if (!NT_SUCCESS(status)) {
  1089. ASSERT(cmResource == NULL && cmLength == 0);
  1090. cmResource = NULL;
  1091. cmLength = 0;
  1092. }
  1093. } else {
  1094. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  1095. "PNPENUM: %ws already has BOOT config in PiQueryAndAllocateBootResources!\n",
  1096. DeviceNode->InstancePath.Buffer));
  1097. }
  1098. //
  1099. // Write boot resources to registry
  1100. //
  1101. if (LogConfKey && DeviceNode->BootResources == NULL) {
  1102. PiWstrToUnicodeString(&unicodeString, REGSTR_VAL_BOOTCONFIG);
  1103. PiLockPnpRegistry(FALSE);
  1104. if (cmResource) {
  1105. ZwSetValueKey(
  1106. LogConfKey,
  1107. &unicodeString,
  1108. TITLE_INDEX_VALUE,
  1109. REG_RESOURCE_LIST,
  1110. cmResource,
  1111. cmLength);
  1112. } else {
  1113. ZwDeleteValueKey(LogConfKey, &unicodeString);
  1114. }
  1115. PiUnlockPnpRegistry();
  1116. if (cmResource) {
  1117. //
  1118. // This device consumes BOOT resources. Reserve its boot resources
  1119. //
  1120. status = (*IopAllocateBootResourcesRoutine)(
  1121. ArbiterRequestPnpEnumerated,
  1122. DeviceNode->PhysicalDeviceObject,
  1123. cmResource);
  1124. if (NT_SUCCESS(status)) {
  1125. DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
  1126. }
  1127. }
  1128. }
  1129. if (cmResource) {
  1130. ExFreePool(cmResource);
  1131. }
  1132. return status;
  1133. }
  1134. NTSTATUS
  1135. PiQueryResourceRequirements(
  1136. IN PDEVICE_NODE DeviceNode,
  1137. IN HANDLE LogConfKey
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. This function will query the resource requirements for the device.
  1142. Arguments:
  1143. DeviceNode - DeviceNode for which the resource requirements need to be queried.
  1144. LogConfKey - Handle to the LogConf key under the device instance key.
  1145. Return Value:
  1146. NTSTATUS.
  1147. --*/
  1148. {
  1149. NTSTATUS status;
  1150. PIO_RESOURCE_REQUIREMENTS_LIST ioResource;
  1151. ULONG ioLength;
  1152. UNICODE_STRING unicodeString;
  1153. PAGED_CODE();
  1154. //
  1155. // Query the device's basic config vector.
  1156. //
  1157. status = PpIrpQueryResourceRequirements(
  1158. DeviceNode->PhysicalDeviceObject,
  1159. &ioResource);
  1160. if (!NT_SUCCESS(status)) {
  1161. ASSERT(ioResource == NULL);
  1162. ioResource = NULL;
  1163. }
  1164. if (ioResource) {
  1165. ioLength = ioResource->ListSize;
  1166. } else {
  1167. ioLength = 0;
  1168. }
  1169. //
  1170. // Write resource requirements to registry
  1171. //
  1172. if (LogConfKey) {
  1173. PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_BASIC_CONFIG_VECTOR);
  1174. PiLockPnpRegistry(FALSE);
  1175. if (ioResource) {
  1176. ZwSetValueKey(
  1177. LogConfKey,
  1178. &unicodeString,
  1179. TITLE_INDEX_VALUE,
  1180. REG_RESOURCE_REQUIREMENTS_LIST,
  1181. ioResource,
  1182. ioLength);
  1183. DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED;
  1184. DeviceNode->ResourceRequirements = ioResource;
  1185. ioResource = NULL;
  1186. } else {
  1187. ZwDeleteValueKey(LogConfKey, &unicodeString);
  1188. }
  1189. PiUnlockPnpRegistry();
  1190. }
  1191. if (ioResource) {
  1192. ExFreePool(ioResource);
  1193. }
  1194. return status;
  1195. }
  1196. NTSTATUS
  1197. PipProcessNewDeviceNode(
  1198. IN PDEVICE_NODE DeviceNode
  1199. /*++
  1200. Routine Description:
  1201. This function will process a new device.
  1202. Arguments:
  1203. DeviceNode - New DeviceNode.
  1204. Return Value:
  1205. NTSTATUS.
  1206. --*/
  1207. )
  1208. {
  1209. NTSTATUS status, finalStatus;
  1210. PDEVICE_OBJECT deviceObject, dupeDeviceObject;
  1211. PWCHAR busID, deviceID, instanceID, description, location, uniqueInstanceID, hwIDs, compatibleIDs;
  1212. DEVICE_CAPABILITIES capabilities;
  1213. BOOLEAN globallyUnique, criticalDevice, configuredBySetup, isRemoteBootCard;
  1214. ULONG instanceIDLength, disposition, configFlags, problem, hwIDLength, compatibleIDLength;
  1215. HANDLE instanceKey, logConfKey;
  1216. PDEVICE_NODE dupeDeviceNode;
  1217. UNICODE_STRING unicodeString;
  1218. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1219. IO_STACK_LOCATION irpSp;
  1220. GUID busTypeGuid;
  1221. PAGED_CODE();
  1222. finalStatus = STATUS_SUCCESS;
  1223. criticalDevice = FALSE;
  1224. isRemoteBootCard = FALSE;
  1225. logConfKey = NULL;
  1226. instanceKey = NULL;
  1227. disposition = 0;
  1228. deviceObject = DeviceNode->PhysicalDeviceObject;
  1229. status = PpQueryDeviceID(DeviceNode, &busID, &deviceID);
  1230. if (!NT_SUCCESS(status)) {
  1231. if (status == STATUS_PNP_INVALID_ID) {
  1232. finalStatus = STATUS_UNSUCCESSFUL;
  1233. } else {
  1234. finalStatus = status;
  1235. }
  1236. }
  1237. //
  1238. // Query the device's capabilities.
  1239. //
  1240. status = PipQueryDeviceCapabilities(DeviceNode, &capabilities);
  1241. //
  1242. // Process the capabilities before saving them.
  1243. //
  1244. DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
  1245. globallyUnique = FALSE;
  1246. if (NT_SUCCESS(status)) {
  1247. if (capabilities.NoDisplayInUI) {
  1248. DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
  1249. }
  1250. if (capabilities.UniqueID) {
  1251. globallyUnique = TRUE;
  1252. }
  1253. }
  1254. //
  1255. // Record, is this a dock?
  1256. //
  1257. if (capabilities.DockDevice) {
  1258. if (DeviceNode->DockInfo.DockStatus == DOCK_EJECTIRP_COMPLETED) {
  1259. ASSERT(DeviceNode->DockInfo.DockStatus != DOCK_EJECTIRP_COMPLETED);
  1260. PpProfileCancelTransitioningDock(DeviceNode, DOCK_DEPARTING);
  1261. }
  1262. DeviceNode->DockInfo.DockStatus = DOCK_QUIESCENT;
  1263. } else {
  1264. DeviceNode->DockInfo.DockStatus = DOCK_NOTDOCKDEVICE;
  1265. }
  1266. //
  1267. // Initialize the stack location to pass to IopSynchronousCall()
  1268. //
  1269. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1270. //
  1271. // Query the device's description.
  1272. //
  1273. irpSp.MajorFunction = IRP_MJ_PNP;
  1274. irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_TEXT;
  1275. irpSp.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
  1276. irpSp.Parameters.QueryDeviceText.LocaleId = PsDefaultSystemLocaleId;
  1277. status = IopSynchronousCall(deviceObject, &irpSp, (PULONG_PTR)&description);
  1278. if (!NT_SUCCESS(status)) {
  1279. description = NULL;
  1280. }
  1281. //
  1282. // Initialize the stack location to pass to IopSynchronousCall()
  1283. //
  1284. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1285. //
  1286. // Query the device's location information.
  1287. //
  1288. irpSp.MajorFunction = IRP_MJ_PNP;
  1289. irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_TEXT;
  1290. irpSp.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
  1291. irpSp.Parameters.QueryDeviceText.LocaleId = PsDefaultSystemLocaleId;
  1292. status = IopSynchronousCall(deviceObject, &irpSp, (PULONG_PTR)&location);
  1293. if (!NT_SUCCESS(status)) {
  1294. location = NULL;
  1295. }
  1296. //
  1297. // Query the instance ID for the new devnode.
  1298. //
  1299. status = PpQueryInstanceID(DeviceNode, &instanceID, &instanceIDLength);
  1300. if (!globallyUnique) {
  1301. if ( !PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) &&
  1302. DeviceNode->Parent != IopRootDeviceNode) {
  1303. uniqueInstanceID = NULL;
  1304. status = PipMakeGloballyUniqueId(deviceObject, instanceID, &uniqueInstanceID);
  1305. if (instanceID != NULL) {
  1306. ExFreePool(instanceID);
  1307. }
  1308. instanceID = uniqueInstanceID;
  1309. if (instanceID) {
  1310. instanceIDLength = ((ULONG)wcslen(instanceID) + 1) * sizeof(WCHAR);
  1311. } else {
  1312. instanceIDLength = 0;
  1313. ASSERT(!NT_SUCCESS(status));
  1314. }
  1315. }
  1316. } else if (status == STATUS_NOT_SUPPORTED) {
  1317. PipSetDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA);
  1318. DeviceNode->Parent->Flags |= DNF_CHILD_WITH_INVALID_ID;
  1319. PpSetInvalidIDEvent(&DeviceNode->Parent->InstancePath);
  1320. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  1321. "PpQueryID: Bogus ID returned by %wZ\n",
  1322. &DeviceNode->Parent->ServiceName));
  1323. ASSERT(status != STATUS_NOT_SUPPORTED || !globallyUnique);
  1324. }
  1325. RetryDuplicateId:
  1326. if (!NT_SUCCESS(status)) {
  1327. finalStatus = status;
  1328. if (!PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA)) {
  1329. if (status == STATUS_INSUFFICIENT_RESOURCES) {
  1330. PipSetDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY);
  1331. } else {
  1332. //
  1333. // Perhaps some other problem code?
  1334. //
  1335. PipSetDevNodeProblem(DeviceNode, CM_PROB_REGISTRY);
  1336. }
  1337. }
  1338. }
  1339. //
  1340. // Build the device instance path and create the instance key.
  1341. //
  1342. status = PiBuildDeviceNodeInstancePath(DeviceNode, busID, deviceID, instanceID);
  1343. if (NT_SUCCESS(status)) {
  1344. status = PiCreateDeviceInstanceKey(DeviceNode, &instanceKey, &disposition);
  1345. }
  1346. if (!NT_SUCCESS(status)) {
  1347. finalStatus = status;
  1348. }
  1349. //
  1350. // Mark the devnode as initialized.
  1351. //
  1352. PiMarkDeviceStackStartPending(deviceObject, TRUE);
  1353. //
  1354. // ISSUE: Should not mark the state if the IDs were invalid.
  1355. //
  1356. PipSetDevNodeState(DeviceNode, DeviceNodeInitialized, NULL);
  1357. if ( !PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) &&
  1358. !PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) &&
  1359. !PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY)) {
  1360. //
  1361. // Check if we are encountering this device for the very first time.
  1362. //
  1363. if (disposition == REG_CREATED_NEW_KEY) {
  1364. //
  1365. // Save the description only for new devices so we dont clobber
  1366. // the inf written description for already installed devices.
  1367. //
  1368. PiLockPnpRegistry(FALSE);
  1369. PiSetDeviceInstanceSzValue(instanceKey, REGSTR_VAL_DEVDESC, &description);
  1370. PiUnlockPnpRegistry();
  1371. } else {
  1372. //
  1373. // Check if there is another device with the same name.
  1374. //
  1375. dupeDeviceObject = IopDeviceObjectFromDeviceInstance(&DeviceNode->InstancePath);
  1376. if (dupeDeviceObject) {
  1377. if (dupeDeviceObject != deviceObject) {
  1378. if (globallyUnique) {
  1379. globallyUnique = FALSE;
  1380. PipSetDevNodeProblem(DeviceNode, CM_PROB_DUPLICATE_DEVICE);
  1381. dupeDeviceNode = dupeDeviceObject->DeviceObjectExtension->DeviceNode;
  1382. ASSERT(dupeDeviceNode);
  1383. if (dupeDeviceNode->Parent == DeviceNode->Parent) {
  1384. //
  1385. // Definite driver screw up. If the verifier is enabled
  1386. // we will fail the driver. Otherwise, we will attempt
  1387. // to uniquify the second device to keep the system
  1388. // alive.
  1389. //
  1390. PpvUtilFailDriver(
  1391. PPVERROR_DUPLICATE_PDO_ENUMERATED,
  1392. (PVOID) deviceObject->DriverObject->MajorFunction[IRP_MJ_PNP],
  1393. deviceObject,
  1394. (PVOID)dupeDeviceObject);
  1395. }
  1396. ObDereferenceObject(dupeDeviceObject);
  1397. status = PipMakeGloballyUniqueId(deviceObject, instanceID, &uniqueInstanceID);
  1398. if (instanceID != NULL) {
  1399. ExFreePool(instanceID);
  1400. }
  1401. instanceID = uniqueInstanceID;
  1402. if (instanceID) {
  1403. instanceIDLength = ((ULONG)wcslen(instanceID) + 1) * sizeof(WCHAR);
  1404. } else {
  1405. instanceIDLength = 0;
  1406. ASSERT(!NT_SUCCESS(status));
  1407. }
  1408. //
  1409. // Cleanup and retry.
  1410. //
  1411. goto RetryDuplicateId;
  1412. }
  1413. //
  1414. // No need to clean up the ref as we're going to crash the
  1415. // system.
  1416. //
  1417. //ObDereferenceObject(dupCheckDeviceObject);
  1418. PpvUtilFailDriver(
  1419. PPVERROR_DUPLICATE_PDO_ENUMERATED,
  1420. (PVOID) deviceObject->DriverObject->MajorFunction[IRP_MJ_PNP],
  1421. deviceObject,
  1422. (PVOID)dupeDeviceObject);
  1423. PP_SAVE_DEVICEOBJECT_TO_TRIAGE_DUMP(deviceObject);
  1424. PP_SAVE_DEVICEOBJECT_TO_TRIAGE_DUMP(dupeDeviceObject);
  1425. KeBugCheckEx(
  1426. PNP_DETECTED_FATAL_ERROR,
  1427. PNP_ERR_DUPLICATE_PDO,
  1428. (ULONG_PTR)deviceObject,
  1429. (ULONG_PTR)dupeDeviceObject,
  1430. 0);
  1431. }
  1432. ObDereferenceObject(dupeDeviceObject);
  1433. }
  1434. }
  1435. }
  1436. if ( !PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) &&
  1437. !PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) &&
  1438. !PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY)) {
  1439. PiLockPnpRegistry(FALSE);
  1440. //
  1441. // Save device location and capabilities.
  1442. //
  1443. PiSetDeviceInstanceSzValue(instanceKey, REGSTR_VALUE_LOCATION_INFORMATION, &location);
  1444. IopSaveDeviceCapabilities(DeviceNode, &capabilities);
  1445. //
  1446. // ADRIAO N.B. 2001/05/29 - Raw device issue
  1447. // processCriticalDevice has no effect on raw devnodes. A raw
  1448. // devnode with CONFIGFLAG_FAILED_INSTALL or CONFIGFLAG_REINSTALL
  1449. // should be started anyway if it's in the CDDB (not that NULL CDDB
  1450. // entries are supported yet), but that doesn't happen today. This
  1451. // means that boot volumes with CONFIGFLAG_REINSTALL will lead to a
  1452. // definite 7B.
  1453. //
  1454. problem = 0;
  1455. criticalDevice = (disposition == REG_CREATED_NEW_KEY)? TRUE : FALSE;
  1456. status = IopGetRegistryValue(instanceKey, REGSTR_VALUE_CONFIG_FLAGS, &keyValueInformation);
  1457. if (NT_SUCCESS(status)) {
  1458. configFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  1459. if (configFlags & CONFIGFLAG_REINSTALL) {
  1460. problem = CM_PROB_REINSTALL;
  1461. criticalDevice = TRUE;
  1462. } else if (configFlags & CONFIGFLAG_FAILEDINSTALL) {
  1463. problem = CM_PROB_FAILED_INSTALL;
  1464. criticalDevice = TRUE;
  1465. }
  1466. ExFreePool(keyValueInformation);
  1467. } else {
  1468. configFlags = 0;
  1469. problem = CM_PROB_NOT_CONFIGURED;
  1470. criticalDevice = TRUE;
  1471. }
  1472. if (problem) {
  1473. if (capabilities.RawDeviceOK) {
  1474. configFlags |= CONFIGFLAG_FINISH_INSTALL;
  1475. PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_CONFIG_FLAGS);
  1476. ZwSetValueKey(
  1477. instanceKey,
  1478. &unicodeString,
  1479. TITLE_INDEX_VALUE,
  1480. REG_DWORD,
  1481. &configFlags,
  1482. sizeof(configFlags));
  1483. } else {
  1484. PipSetDevNodeProblem(DeviceNode, problem);
  1485. }
  1486. }
  1487. status = IopMapDeviceObjectToDeviceInstance(DeviceNode->PhysicalDeviceObject, &DeviceNode->InstancePath);
  1488. ASSERT(NT_SUCCESS(status));
  1489. if (!NT_SUCCESS(status)) {
  1490. finalStatus = status;
  1491. }
  1492. PiUnlockPnpRegistry();
  1493. }
  1494. PpQueryHardwareIDs(
  1495. DeviceNode,
  1496. &hwIDs,
  1497. &hwIDLength);
  1498. PpQueryCompatibleIDs(
  1499. DeviceNode,
  1500. &compatibleIDs,
  1501. &compatibleIDLength);
  1502. PiLockPnpRegistry(FALSE);
  1503. DeviceNode->Flags |= DNF_IDS_QUERIED;
  1504. if ( !PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) &&
  1505. !PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) &&
  1506. !PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY)) {
  1507. PiWstrToUnicodeString(&unicodeString, REGSTR_KEY_LOG_CONF);
  1508. IopCreateRegistryKeyEx(
  1509. &logConfKey,
  1510. instanceKey,
  1511. &unicodeString,
  1512. KEY_ALL_ACCESS,
  1513. REG_OPTION_NON_VOLATILE,
  1514. NULL);
  1515. }
  1516. PiUnlockPnpRegistry();
  1517. PiQueryResourceRequirements(DeviceNode, logConfKey);
  1518. PiLockPnpRegistry(FALSE);
  1519. if (IoRemoteBootClient && (IopLoaderBlock != NULL)) {
  1520. if ( !PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) &&
  1521. !PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) &&
  1522. !PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY)) {
  1523. if (hwIDs) {
  1524. isRemoteBootCard = IopIsRemoteBootCard(
  1525. DeviceNode->ResourceRequirements,
  1526. (PLOADER_PARAMETER_BLOCK)IopLoaderBlock,
  1527. hwIDs);
  1528. }
  1529. if (!isRemoteBootCard && compatibleIDs) {
  1530. isRemoteBootCard = IopIsRemoteBootCard(
  1531. DeviceNode->ResourceRequirements,
  1532. (PLOADER_PARAMETER_BLOCK)IopLoaderBlock,
  1533. compatibleIDs);
  1534. }
  1535. }
  1536. }
  1537. PiSetDeviceInstanceMultiSzValue(instanceKey, REGSTR_VALUE_HARDWAREID, &hwIDs, hwIDLength);
  1538. PiSetDeviceInstanceMultiSzValue(instanceKey, REGSTR_VALUE_COMPATIBLEIDS, &compatibleIDs, compatibleIDLength);
  1539. status = STATUS_SUCCESS;
  1540. if (isRemoteBootCard) {
  1541. status = IopSetupRemoteBootCard(
  1542. (PLOADER_PARAMETER_BLOCK)IopLoaderBlock,
  1543. instanceKey,
  1544. &DeviceNode->InstancePath);
  1545. if (!NT_SUCCESS(status)) {
  1546. finalStatus = status;
  1547. }
  1548. }
  1549. PiUnlockPnpRegistry();
  1550. //
  1551. // we've pretty much got the PDO information ready, apart from Child bus information
  1552. // get that now, because class-installer may want it
  1553. //
  1554. if (NT_SUCCESS(IopQueryPnpBusInformation(
  1555. deviceObject,
  1556. &busTypeGuid,
  1557. &DeviceNode->ChildInterfaceType,
  1558. &DeviceNode->ChildBusNumber))) {
  1559. DeviceNode->ChildBusTypeIndex = PpBusTypeGuidGetIndex(&busTypeGuid);
  1560. } else {
  1561. DeviceNode->ChildBusTypeIndex = 0xffff;
  1562. DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
  1563. DeviceNode->ChildBusNumber = 0xfffffff0;
  1564. }
  1565. if (NT_SUCCESS(status)) {
  1566. if (criticalDevice) {
  1567. //
  1568. // Process the device as a critical device.
  1569. //
  1570. // This will attempt to locate a match for the device in the
  1571. // CriticalDeviceDatabase using the device's hardware and compatible
  1572. // ids. If a match is found, critical device settings such as Service,
  1573. // ClassGUID (to determine Class filters), and device LowerFilters and
  1574. // UpperFilters will be applied to the device.
  1575. //
  1576. // If DevicePath location information matching this device is present
  1577. // critical device database entry, this routine will also pre-install
  1578. // the new device with those settings.
  1579. //
  1580. if (!capabilities.HardwareDisabled && !PipIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART)) {
  1581. PipProcessCriticalDevice(DeviceNode);
  1582. }
  1583. }
  1584. ASSERT(!PipDoesDevNodeHaveProblem(DeviceNode) ||
  1585. PipIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) ||
  1586. PipIsDevNodeProblem(DeviceNode, CM_PROB_REINSTALL) ||
  1587. PipIsDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL) ||
  1588. PipIsDevNodeProblem(DeviceNode, CM_PROB_PARTIAL_LOG_CONF) ||
  1589. PipIsDevNodeProblem(DeviceNode, CM_PROB_HARDWARE_DISABLED) ||
  1590. PipIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART) ||
  1591. PipIsDevNodeProblem(DeviceNode, CM_PROB_DUPLICATE_DEVICE) ||
  1592. PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) ||
  1593. PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) ||
  1594. PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY));
  1595. if (!PipIsDevNodeProblem(DeviceNode, CM_PROB_DISABLED) &&
  1596. !PipIsDevNodeProblem(DeviceNode, CM_PROB_HARDWARE_DISABLED) &&
  1597. !PipIsDevNodeProblem(DeviceNode, CM_PROB_NEED_RESTART) &&
  1598. !PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) &&
  1599. !PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) &&
  1600. !PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY)) {
  1601. IopIsDeviceInstanceEnabled(instanceKey, &DeviceNode->InstancePath, TRUE);
  1602. }
  1603. }
  1604. PiQueryAndAllocateBootResources(DeviceNode, logConfKey);
  1605. if ( !PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA) &&
  1606. !PipIsDevNodeProblem(DeviceNode, CM_PROB_OUT_OF_MEMORY) &&
  1607. !PipIsDevNodeProblem(DeviceNode, CM_PROB_REGISTRY)) {
  1608. PiLockPnpRegistry(FALSE);
  1609. IopSaveDeviceCapabilities(DeviceNode, &capabilities);
  1610. PiUnlockPnpRegistry();
  1611. PpHotSwapUpdateRemovalPolicy(DeviceNode);
  1612. //
  1613. // Create new value entry under ServiceKeyName\Enum to reflect the newly
  1614. // added made-up device instance node.
  1615. //
  1616. status = IopNotifySetupDeviceArrival( deviceObject,
  1617. instanceKey,
  1618. TRUE);
  1619. configuredBySetup = NT_SUCCESS(status) ? TRUE : FALSE;
  1620. status = PpDeviceRegistration(
  1621. &DeviceNode->InstancePath,
  1622. TRUE,
  1623. &DeviceNode->ServiceName
  1624. );
  1625. if (NT_SUCCESS(status)) {
  1626. if ( (configuredBySetup || isRemoteBootCard) &&
  1627. PipIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED)) {
  1628. PipClearDevNodeProblem(DeviceNode);
  1629. }
  1630. }
  1631. //
  1632. // Add an event so user-mode will attempt to install this device later.
  1633. //
  1634. PpSetPlugPlayEvent(&GUID_DEVICE_ENUMERATED, deviceObject);
  1635. }
  1636. //
  1637. // Cleanup.
  1638. //
  1639. if (hwIDs) {
  1640. ExFreePool(hwIDs);
  1641. }
  1642. if (compatibleIDs) {
  1643. ExFreePool(compatibleIDs);
  1644. }
  1645. if (logConfKey) {
  1646. ZwClose(logConfKey);
  1647. }
  1648. if (instanceKey) {
  1649. ZwClose(instanceKey);
  1650. }
  1651. if (instanceID) {
  1652. ExFreePool(instanceID);
  1653. }
  1654. if (location) {
  1655. ExFreePool(location);
  1656. }
  1657. if (description) {
  1658. ExFreePool(description);
  1659. }
  1660. if (busID) {
  1661. ExFreePool(busID);
  1662. }
  1663. return finalStatus;
  1664. }
  1665. NTSTATUS
  1666. PipCallDriverAddDevice(
  1667. IN PDEVICE_NODE DeviceNode,
  1668. IN BOOLEAN LoadDriver,
  1669. IN PADD_CONTEXT Context
  1670. )
  1671. /*++
  1672. Routine Description:
  1673. This function checks if the driver for the DeviceNode is present and loads
  1674. the driver if necessary.
  1675. Arguments:
  1676. DeviceNode - Supplies a pointer to the device node to be enumerated.
  1677. LoadDriver - Supplies a BOOLEAN value to indicate should a driver be loaded
  1678. to complete enumeration.
  1679. Context - Supplies a pointer to ADD_CONTEXT to control how the device be added.
  1680. Return Value:
  1681. NTSTATUS code.
  1682. --*/
  1683. {
  1684. HANDLE enumKey, instanceKey, controlKey, classKey = NULL, classPropsKey = NULL;
  1685. PKEY_VALUE_FULL_INFORMATION keyValueInformation = NULL;
  1686. RTL_QUERY_REGISTRY_TABLE queryTable[3];
  1687. QUERY_CONTEXT queryContext;
  1688. BOOLEAN deviceRaw = FALSE;
  1689. BOOLEAN usePdoCharacteristics = TRUE;
  1690. NTSTATUS status;
  1691. PDEVICE_OBJECT deviceObject;
  1692. PDEVICE_OBJECT fdoDeviceObject, topOfPdoStack, topOfLowerFilterStack;
  1693. BOOLEAN deviceObjectHasBeenAttached = FALSE;
  1694. UNICODE_STRING unicodeClassGuid;
  1695. IopDbgPrint(( IOP_ENUMERATION_TRACE_LEVEL,
  1696. "PipCallDriverAddDevice: Processing devnode %#08lx\n",
  1697. DeviceNode));
  1698. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  1699. "PipCallDriverAddDevice: DevNode flags going in = %#08lx\n",
  1700. DeviceNode->Flags));
  1701. //
  1702. // The device node may have been started at this point. This is because
  1703. // some ill-behaved miniport drivers call IopReportedDetectedDevice at
  1704. // DriverEntry for the devices which we already know about.
  1705. //
  1706. ASSERT_INITED(DeviceNode->PhysicalDeviceObject);
  1707. IopDbgPrint(( IOP_ENUMERATION_TRACE_LEVEL,
  1708. "PipCallDriverAddDevice:\t%s load driver\n",
  1709. LoadDriver? "Will" : "Won't"));
  1710. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  1711. "PipCallDriverAddDevice:\tOpening registry key %wZ\n",
  1712. &DeviceNode->InstancePath));
  1713. //
  1714. // Open the HKLM\System\CCS\Enum key.
  1715. //
  1716. status = IopOpenRegistryKeyEx( &enumKey,
  1717. NULL,
  1718. &CmRegistryMachineSystemCurrentControlSetEnumName,
  1719. KEY_READ
  1720. );
  1721. if (!NT_SUCCESS(status)) {
  1722. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1723. "PipCallDriverAddDevice:\tUnable to open HKLM\\SYSTEM\\CCS\\ENUM\n"));
  1724. return status;
  1725. }
  1726. //
  1727. // Open the instance key for this devnode
  1728. //
  1729. status = IopOpenRegistryKeyEx( &instanceKey,
  1730. enumKey,
  1731. &DeviceNode->InstancePath,
  1732. KEY_READ
  1733. );
  1734. ZwClose(enumKey);
  1735. if (!NT_SUCCESS(status)) {
  1736. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1737. "PipCallDriverAddDevice:\t\tError %#08lx opening %wZ enum key\n",
  1738. status, &DeviceNode->InstancePath));
  1739. return status;
  1740. }
  1741. //
  1742. // Get the class value to locate the class key for this devnode
  1743. //
  1744. status = IopGetRegistryValue(instanceKey,
  1745. REGSTR_VALUE_CLASSGUID,
  1746. &keyValueInformation);
  1747. if(NT_SUCCESS(status)) {
  1748. if ( keyValueInformation->Type == REG_SZ &&
  1749. keyValueInformation->DataLength) {
  1750. IopRegistryDataToUnicodeString(
  1751. &unicodeClassGuid,
  1752. (PWSTR) KEY_VALUE_DATA(keyValueInformation),
  1753. keyValueInformation->DataLength);
  1754. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  1755. "PipCallDriverAddDevice:\t\tClass GUID is %wZ\n",
  1756. &unicodeClassGuid));
  1757. if (InitSafeBootMode) {
  1758. if (!IopSafebootDriverLoad(&unicodeClassGuid)) {
  1759. PKEY_VALUE_FULL_INFORMATION ClassValueInformation = NULL;
  1760. NTSTATUS s;
  1761. //
  1762. // don't load the driver
  1763. //
  1764. IopDbgPrint((IOP_ENUMERATION_WARNING_LEVEL,
  1765. "SAFEBOOT: skipping device = %wZ\n", &unicodeClassGuid));
  1766. s = IopGetRegistryValue(instanceKey,
  1767. REGSTR_VAL_DEVDESC,
  1768. &ClassValueInformation);
  1769. if (NT_SUCCESS(s)) {
  1770. UNICODE_STRING ClassString;
  1771. RtlInitUnicodeString(&ClassString, (PCWSTR) KEY_VALUE_DATA(ClassValueInformation));
  1772. IopBootLog(&ClassString, FALSE);
  1773. } else {
  1774. IopBootLog(&unicodeClassGuid, FALSE);
  1775. }
  1776. ZwClose(instanceKey);
  1777. return STATUS_UNSUCCESSFUL;
  1778. }
  1779. }
  1780. //
  1781. // Open the class key
  1782. //
  1783. status = IopOpenRegistryKeyEx( &controlKey,
  1784. NULL,
  1785. &CmRegistryMachineSystemCurrentControlSetControlClass,
  1786. KEY_READ
  1787. );
  1788. if (NT_SUCCESS(status)) {
  1789. status = IopOpenRegistryKeyEx( &classKey,
  1790. controlKey,
  1791. &unicodeClassGuid,
  1792. KEY_READ
  1793. );
  1794. if (!NT_SUCCESS(status)) {
  1795. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1796. "PipCallDriverAddDevice:\tUnable to open GUID key "
  1797. "%wZ - %#08lx\n",
  1798. &unicodeClassGuid,status));
  1799. }
  1800. ZwClose(controlKey);
  1801. } else {
  1802. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1803. "PipCallDriverAddDevice:\tUnable to open "
  1804. "HKLM\\SYSTEM\\CCS\\CONTROL\\CLASS - %#08lx\n",
  1805. status));
  1806. }
  1807. if (classKey != NULL) {
  1808. UNICODE_STRING unicodeProperties;
  1809. PiWstrToUnicodeString(&unicodeProperties, REGSTR_KEY_DEVICE_PROPERTIES );
  1810. status = IopOpenRegistryKeyEx( &classPropsKey,
  1811. classKey,
  1812. &unicodeProperties,
  1813. KEY_READ
  1814. );
  1815. if (!NT_SUCCESS(status)) {
  1816. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1817. "PipCallDriverAddDevice:\tUnable to open GUID\\Properties key "
  1818. "%wZ - %#08lx\n",
  1819. &unicodeClassGuid,status));
  1820. }
  1821. }
  1822. }
  1823. ExFreePool(keyValueInformation);
  1824. keyValueInformation = NULL;
  1825. }
  1826. //
  1827. // Check to see if there's a service assigned to this device node. If
  1828. // there's not then we can bail out without wasting too much time.
  1829. //
  1830. RtlZeroMemory(&queryContext, sizeof(queryContext));
  1831. queryContext.DeviceNode = DeviceNode;
  1832. queryContext.LoadDriver = LoadDriver;
  1833. queryContext.AddContext = Context;
  1834. RtlZeroMemory(queryTable, sizeof(queryTable));
  1835. queryTable[0].QueryRoutine =
  1836. (PRTL_QUERY_REGISTRY_ROUTINE) PipCallDriverAddDeviceQueryRoutine;
  1837. queryTable[0].Name = REGSTR_VAL_LOWERFILTERS;
  1838. queryTable[0].EntryContext = (PVOID) UIntToPtr(LowerDeviceFilters);
  1839. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  1840. (PWSTR) instanceKey,
  1841. queryTable,
  1842. &queryContext,
  1843. NULL);
  1844. if (NT_SUCCESS(status)) {
  1845. if (classKey != NULL) {
  1846. queryTable[0].QueryRoutine =
  1847. (PRTL_QUERY_REGISTRY_ROUTINE) PipCallDriverAddDeviceQueryRoutine;
  1848. queryTable[0].Name = REGSTR_VAL_LOWERFILTERS;
  1849. queryTable[0].EntryContext = (PVOID) UIntToPtr(LowerClassFilters);
  1850. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  1851. (PWSTR) classKey,
  1852. queryTable,
  1853. &queryContext,
  1854. NULL);
  1855. if (!NT_SUCCESS(status)) {
  1856. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1857. "PipCallDriverAddDevice\t\tError %#08lx reading LowerClassFilters "
  1858. "value for %wZ\n", status, &DeviceNode->InstancePath));
  1859. }
  1860. }
  1861. if (NT_SUCCESS(status)) {
  1862. queryTable[0].QueryRoutine = (PRTL_QUERY_REGISTRY_ROUTINE) PipCallDriverAddDeviceQueryRoutine;
  1863. queryTable[0].Name = REGSTR_VALUE_SERVICE;
  1864. queryTable[0].EntryContext = (PVOID) UIntToPtr(DeviceService);
  1865. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  1866. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  1867. (PWSTR) instanceKey,
  1868. queryTable,
  1869. &queryContext,
  1870. NULL);
  1871. if (!NT_SUCCESS(status)) {
  1872. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1873. "PipCallDriverAddDevice\t\tError %#08lx reading service "
  1874. "value for %wZ\n", status, &DeviceNode->InstancePath));
  1875. }
  1876. }
  1877. } else {
  1878. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  1879. "PipCallDriverAddDevice\t\tError %#08lx reading LowerDeviceFilters "
  1880. "value for %wZ\n", status, &DeviceNode->InstancePath));
  1881. }
  1882. if (DeviceNode->Flags & DNF_LEGACY_DRIVER) {
  1883. //
  1884. // One of the services for this device is a legacy driver. Don't try
  1885. // to add any filters since we'll just mess up the device stack.
  1886. //
  1887. status = STATUS_SUCCESS;
  1888. goto Cleanup;
  1889. } else if (NT_SUCCESS(status)) {
  1890. //
  1891. // Call was successful so we must have been able to reference the
  1892. // driver object.
  1893. //
  1894. ASSERT(queryContext.DriverLists[DeviceService] != NULL);
  1895. if (queryContext.DriverLists[DeviceService]->NextEntry != NULL) {
  1896. //
  1897. // There's more than one service assigned to this device. Configuration
  1898. // error
  1899. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  1900. "PipCallDriverAddDevice: Configuration Error - more "
  1901. "than one service in driver list\n"));
  1902. PipSetDevNodeProblem(DeviceNode, CM_PROB_REGISTRY);
  1903. status = STATUS_UNSUCCESSFUL;
  1904. goto Cleanup;
  1905. }
  1906. //
  1907. // this is the only case (FDO specified) where we can ignore PDO's characteristics
  1908. //
  1909. usePdoCharacteristics = FALSE;
  1910. } else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1911. if (!IopDeviceNodeFlagsToCapabilities(DeviceNode)->RawDeviceOK) {
  1912. //
  1913. // The device cannot be used raw. Bail out now.
  1914. //
  1915. status = STATUS_UNSUCCESSFUL;
  1916. goto Cleanup;
  1917. } else {
  1918. //
  1919. // Raw device access is okay.
  1920. //
  1921. PipClearDevNodeProblem(DeviceNode);
  1922. usePdoCharacteristics = TRUE; // shouldn't need to do this, but better be safe than sorry
  1923. deviceRaw = TRUE;
  1924. status = STATUS_SUCCESS;
  1925. }
  1926. } else {
  1927. //
  1928. // something else went wrong while parsing the service key. The
  1929. // query routine will have set the flags appropriately so we can
  1930. // just bail out.
  1931. //
  1932. goto Cleanup;
  1933. }
  1934. //
  1935. // For each type of filter driver we want to build a list of the driver
  1936. // objects to be loaded. We'll build all the driver lists if we can
  1937. // and deal with error conditions afterwards.
  1938. //
  1939. //
  1940. // First get all the information we have to out of the instance key and
  1941. // the device node.
  1942. //
  1943. RtlZeroMemory(queryTable, sizeof(queryTable));
  1944. queryTable[0].QueryRoutine =
  1945. (PRTL_QUERY_REGISTRY_ROUTINE) PipCallDriverAddDeviceQueryRoutine;
  1946. queryTable[0].Name = REGSTR_VAL_UPPERFILTERS;
  1947. queryTable[0].EntryContext = (PVOID) UIntToPtr(UpperDeviceFilters);
  1948. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  1949. (PWSTR) instanceKey,
  1950. queryTable,
  1951. &queryContext,
  1952. NULL);
  1953. if (NT_SUCCESS(status) && classKey) {
  1954. queryTable[0].QueryRoutine =
  1955. (PRTL_QUERY_REGISTRY_ROUTINE) PipCallDriverAddDeviceQueryRoutine;
  1956. queryTable[0].Name = REGSTR_VAL_UPPERFILTERS;
  1957. queryTable[0].EntryContext = (PVOID) UIntToPtr(UpperClassFilters);
  1958. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  1959. (PWSTR) classKey,
  1960. queryTable,
  1961. &queryContext,
  1962. NULL);
  1963. }
  1964. if (NT_SUCCESS(status)) {
  1965. UCHAR serviceType = 0;
  1966. PDRIVER_LIST_ENTRY listEntry = queryContext.DriverLists[serviceType];
  1967. //
  1968. // Make sure there's no more than one device service. Anything else is
  1969. // a configuration error.
  1970. //
  1971. ASSERT(!(DeviceNode->Flags & DNF_LEGACY_DRIVER));
  1972. ASSERTMSG(
  1973. "Error - Device has no service but cannot be run RAW\n",
  1974. ((queryContext.DriverLists[DeviceService] != NULL) || (deviceRaw)));
  1975. //
  1976. // Do preinit work.
  1977. //
  1978. fdoDeviceObject = NULL;
  1979. topOfLowerFilterStack = NULL;
  1980. topOfPdoStack = IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject);
  1981. //
  1982. // It's okay to try adding all the drivers.
  1983. //
  1984. for (serviceType = 0; serviceType < MaximumAddStage; serviceType++) {
  1985. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  1986. "PipCallDriverAddDevice: Adding Services (type %d)\n",
  1987. serviceType));
  1988. if (serviceType == DeviceService) {
  1989. topOfLowerFilterStack = IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject);
  1990. if (deviceRaw && (queryContext.DriverLists[serviceType] == NULL)) {
  1991. //
  1992. // Mark the devnode as added, as it has no service.
  1993. //
  1994. ASSERT(queryContext.DriverLists[serviceType] == NULL);
  1995. PipSetDevNodeState(DeviceNode, DeviceNodeDriversAdded, NULL);
  1996. } else {
  1997. //
  1998. // Since we are going to see a service, grab a pointer to
  1999. // the current top of the stack. While here, assert there
  2000. // is exactly one service driver to load...
  2001. //
  2002. ASSERT(queryContext.DriverLists[serviceType]);
  2003. ASSERT(!queryContext.DriverLists[serviceType]->NextEntry);
  2004. }
  2005. }
  2006. for (listEntry = queryContext.DriverLists[serviceType];
  2007. listEntry != NULL;
  2008. listEntry = listEntry->NextEntry) {
  2009. PDRIVER_ADD_DEVICE addDeviceRoutine;
  2010. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  2011. "PipCallDriverAddDevice:\tAdding driver %#08lx\n",
  2012. listEntry->DriverObject));
  2013. ASSERT(listEntry->DriverObject);
  2014. ASSERT(listEntry->DriverObject->DriverExtension);
  2015. ASSERT(listEntry->DriverObject->DriverExtension->AddDevice);
  2016. //
  2017. // Invoke the driver's AddDevice() entry point.
  2018. //
  2019. addDeviceRoutine =
  2020. listEntry->DriverObject->DriverExtension->AddDevice;
  2021. status = PpvUtilCallAddDevice(
  2022. DeviceNode->PhysicalDeviceObject,
  2023. listEntry->DriverObject,
  2024. addDeviceRoutine,
  2025. VerifierTypeFromServiceType(serviceType)
  2026. );
  2027. IopDbgPrint(( IOP_ENUMERATION_TRACE_LEVEL,
  2028. "PipCallDriverAddDevice:\t\tRoutine returned "
  2029. "%#08lx\n", status));
  2030. if (NT_SUCCESS(status)) {
  2031. //
  2032. // If this is a service, mark the it is legal for a filter to succeed AddDevice
  2033. // but fail to attach anything to the top of the stack.
  2034. //
  2035. if (serviceType == DeviceService) {
  2036. fdoDeviceObject = topOfLowerFilterStack->AttachedDevice;
  2037. ASSERT(fdoDeviceObject);
  2038. }
  2039. PipSetDevNodeState(DeviceNode, DeviceNodeDriversAdded, NULL);
  2040. } else if (serviceType == DeviceService) {
  2041. //
  2042. // Mark the stack appropriately.
  2043. //
  2044. IovUtilMarkStack(
  2045. DeviceNode->PhysicalDeviceObject,
  2046. topOfPdoStack->AttachedDevice,
  2047. fdoDeviceObject,
  2048. FALSE
  2049. );
  2050. //
  2051. // If service fails, then add failed. (Alternately, if
  2052. // filter drivers return failure, we keep going.)
  2053. //
  2054. PipRequestDeviceRemoval(DeviceNode, FALSE, CM_PROB_FAILED_ADD);
  2055. goto Cleanup;
  2056. }
  2057. if (IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject)->Flags & DO_DEVICE_INITIALIZING) {
  2058. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  2059. "***************** DO_DEVICE_INITIALIZING not cleared on %#08lx\n",
  2060. IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject)));
  2061. }
  2062. ASSERT_INITED(IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject));
  2063. }
  2064. }
  2065. //
  2066. // Mark the stack appropriately. We tell the verifier the stack is raw
  2067. // if the fdo is NULL and we made it this far.
  2068. //
  2069. IovUtilMarkStack(
  2070. DeviceNode->PhysicalDeviceObject,
  2071. topOfPdoStack->AttachedDevice,
  2072. fdoDeviceObject,
  2073. ((fdoDeviceObject == NULL) || deviceRaw)
  2074. );
  2075. //
  2076. // change PDO and all attached objects
  2077. // to have properties specified in the registry
  2078. //
  2079. PipChangeDeviceObjectFromRegistryProperties(DeviceNode->PhysicalDeviceObject, classPropsKey, instanceKey, usePdoCharacteristics);
  2080. //
  2081. // CapabilityFlags are refreshed with call to IopSaveDeviceCapabilities after device is started
  2082. //
  2083. } else {
  2084. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2085. "PipCallDriverAddDevice: Error %#08lx while building "
  2086. "driver load list\n", status));
  2087. goto Cleanup;
  2088. }
  2089. deviceObject = DeviceNode->PhysicalDeviceObject;
  2090. status = IopQueryLegacyBusInformation(
  2091. deviceObject,
  2092. NULL,
  2093. &DeviceNode->InterfaceType,
  2094. &DeviceNode->BusNumber
  2095. );
  2096. if (NT_SUCCESS(status)) {
  2097. IopInsertLegacyBusDeviceNode(DeviceNode, DeviceNode->InterfaceType, DeviceNode->BusNumber);
  2098. } else {
  2099. DeviceNode->InterfaceType = InterfaceTypeUndefined;
  2100. DeviceNode->BusNumber = 0xfffffff0;
  2101. }
  2102. status = STATUS_SUCCESS;
  2103. ASSERT(DeviceNode->State == DeviceNodeDriversAdded);
  2104. Cleanup:
  2105. {
  2106. UCHAR i;
  2107. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  2108. "PipCallDriverAddDevice: DevNode flags leaving = %#08lx\n",
  2109. DeviceNode->Flags));
  2110. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  2111. "PipCallDriverAddDevice: Cleaning up\n"));
  2112. //
  2113. // Free the entries in the driver load list & release the references on
  2114. // their driver objects.
  2115. //
  2116. for (i = 0; i < MaximumAddStage; i++) {
  2117. PDRIVER_LIST_ENTRY listHead = queryContext.DriverLists[i];
  2118. while(listHead != NULL) {
  2119. PDRIVER_LIST_ENTRY tmp = listHead;
  2120. listHead = listHead->NextEntry;
  2121. ASSERT(tmp->DriverObject != NULL);
  2122. //
  2123. // Let the driver unload if it hasn't created any device
  2124. // objects. We only do this if the paging stack is already
  2125. // online (the same filter may be needed by more than one card).
  2126. // IopInitializeBootDrivers will take care of cleaning up any
  2127. // leftover drivers after boot.
  2128. //
  2129. if (PnPBootDriversInitialized) {
  2130. IopUnloadAttachedDriver(tmp->DriverObject);
  2131. }
  2132. ObDereferenceObject(tmp->DriverObject);
  2133. ExFreePool(tmp);
  2134. }
  2135. }
  2136. }
  2137. ZwClose(instanceKey);
  2138. if (classKey != NULL) {
  2139. ZwClose(classKey);
  2140. }
  2141. if (classPropsKey != NULL) {
  2142. ZwClose(classPropsKey);
  2143. }
  2144. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  2145. "PipCallDriverAddDevice: Returning status %#08lx\n", status));
  2146. return status;
  2147. }
  2148. NTSTATUS
  2149. PipCallDriverAddDeviceQueryRoutine(
  2150. IN PWSTR ValueName,
  2151. IN ULONG ValueType,
  2152. IN PWCHAR ValueData,
  2153. IN ULONG ValueLength,
  2154. IN PQUERY_CONTEXT Context,
  2155. IN ULONG ServiceType
  2156. )
  2157. /*++
  2158. Routine Description:
  2159. This routine is called to build a list of driver objects which need to
  2160. be Added to a physical device object. Each time it is called with a
  2161. service name it will locate a driver object for that device and append
  2162. it to the proper driver list for the device node.
  2163. In the event a driver object cannot be located or that it cannot be loaded
  2164. at this time, this routine will return an error and will set the flags
  2165. in the device node in the context appropriately.
  2166. Arguments:
  2167. ValueName - the name of the value
  2168. ValueType - the type of the value
  2169. ValueData - the data in the value (unicode string data)
  2170. ValueLength - the number of bytes in the value data
  2171. Context - a structure which contains the device node, the context passed
  2172. to PipCallDriverAddDevice and the driver lists for the device
  2173. node.
  2174. EntryContext - the index of the driver list the routine should append
  2175. nodes to.
  2176. Return Value:
  2177. STATUS_SUCCESS if the driver was located and added to the list
  2178. successfully or if there was a non-fatal error while handling the
  2179. driver.
  2180. an error value indicating why the driver could not be added to the list.
  2181. --*/
  2182. {
  2183. UNICODE_STRING unicodeServiceName;
  2184. UNICODE_STRING unicodeDriverName;
  2185. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  2186. ULONG i;
  2187. ULONG loadType;
  2188. PWSTR prefixString = L"\\Driver\\";
  2189. BOOLEAN madeupService;
  2190. USHORT groupIndex;
  2191. PDRIVER_OBJECT driverObject = NULL;
  2192. NTSTATUS status = STATUS_SUCCESS;
  2193. NTSTATUS driverEntryStatus;
  2194. BOOLEAN freeDriverName = FALSE;
  2195. HANDLE handle, serviceKey;
  2196. #if DBG
  2197. PDRIVER_OBJECT tempDrvObj;
  2198. #endif
  2199. //
  2200. // Preinit
  2201. //
  2202. serviceKey = NULL;
  2203. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  2204. "PipCallDriverAddDevice:\t\tValue %ws [Type %d, Len %d] @ "
  2205. "%#08lx\n",
  2206. ValueName, ValueType, ValueLength, ValueData));
  2207. //
  2208. // First check and make sure that the value type is okay. An invalid type
  2209. // is not a fatal error.
  2210. //
  2211. if (ValueType != REG_SZ) {
  2212. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2213. "PipCallDriverAddDevice:\t\tValueType %d invalid for "
  2214. "ServiceType %d\n",
  2215. ValueType,ServiceType));
  2216. return STATUS_SUCCESS;
  2217. }
  2218. //
  2219. // Make sure the string is a reasonable length.
  2220. //
  2221. if (ValueLength <= sizeof(WCHAR)) {
  2222. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2223. "PipCallDriverAddDevice:\t\tValueLength %d is too short\n",
  2224. ValueLength));
  2225. return STATUS_SUCCESS;
  2226. }
  2227. RtlInitUnicodeString(&unicodeServiceName, ValueData);
  2228. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  2229. "PipCallDriverAddDevice:\t\t\tService Name %wZ\n",
  2230. &unicodeServiceName));
  2231. //
  2232. // Check the service name to see if it should be used directly to reference
  2233. // the driver object. If the string begins with "\Driver", make sure the
  2234. // madeupService flag is set.
  2235. //
  2236. madeupService = TRUE;
  2237. i = 0;
  2238. while(*prefixString != L'\0') {
  2239. if (unicodeServiceName.Buffer[i] != *prefixString) {
  2240. madeupService = FALSE;
  2241. break;
  2242. }
  2243. i++;
  2244. prefixString++;
  2245. }
  2246. //
  2247. // Get the driver name from the service key. We need this to figure out
  2248. // if the driver is already in memory.
  2249. //
  2250. if (madeupService) {
  2251. RtlInitUnicodeString(&unicodeDriverName, unicodeServiceName.Buffer);
  2252. } else {
  2253. //
  2254. // BUGBUG - (RBN) Hack to set the service name in the devnode if it
  2255. // isn't already set.
  2256. //
  2257. // This probably should be done earlier somewhere else after the
  2258. // INF is run, but if we don't do it now we'll blow up when we
  2259. // call IopGetDriverLoadType below.
  2260. //
  2261. if (Context->DeviceNode->ServiceName.Length == 0) {
  2262. Context->DeviceNode->ServiceName = unicodeServiceName;
  2263. Context->DeviceNode->ServiceName.Buffer = ExAllocatePool( NonPagedPool,
  2264. unicodeServiceName.MaximumLength );
  2265. if (Context->DeviceNode->ServiceName.Buffer != NULL) {
  2266. RtlCopyMemory( Context->DeviceNode->ServiceName.Buffer,
  2267. unicodeServiceName.Buffer,
  2268. unicodeServiceName.MaximumLength );
  2269. } else {
  2270. PiWstrToUnicodeString( &Context->DeviceNode->ServiceName, NULL );
  2271. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2272. "PipCallDriverAddDevice:\t\t\tCannot allocate memory for service name in devnode\n"));
  2273. status = STATUS_UNSUCCESSFUL;
  2274. goto Cleanup;
  2275. }
  2276. }
  2277. //
  2278. // Check in the registry to find the name of the driver object
  2279. // for this device.
  2280. //
  2281. status = PipOpenServiceEnumKeys(&unicodeServiceName,
  2282. KEY_READ,
  2283. &serviceKey,
  2284. NULL,
  2285. FALSE);
  2286. if (!NT_SUCCESS(status)) {
  2287. //
  2288. // Cannot open the service key for this driver. This is a
  2289. // fatal error.
  2290. //
  2291. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2292. "PipCallDriverAddDevice:\t\t\tStatus %#08lx "
  2293. "opening service key\n",
  2294. status));
  2295. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_REGISTRY);
  2296. goto Cleanup;
  2297. }
  2298. status = IopGetDriverNameFromKeyNode(serviceKey, &unicodeDriverName);
  2299. if (!NT_SUCCESS(status)) {
  2300. //
  2301. // Can't get the driver name from the service key. This is a
  2302. // fatal error.
  2303. //
  2304. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2305. "PipCallDriverAddDevice:\t\t\tStatus %#08lx "
  2306. "getting driver name\n",
  2307. status));
  2308. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_REGISTRY);
  2309. goto Cleanup;
  2310. } else {
  2311. freeDriverName = TRUE;
  2312. }
  2313. //
  2314. // Note that we don't close the service key here. We may need it later.
  2315. //
  2316. }
  2317. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  2318. "PipCallDriverAddDevice:\t\t\tDriverName is %wZ\n",
  2319. &unicodeDriverName));
  2320. driverObject = IopReferenceDriverObjectByName(&unicodeDriverName);
  2321. if (driverObject == NULL) {
  2322. //
  2323. // We couldn't find a driver object. It's possible the driver isn't
  2324. // loaded & initialized so check to see if we can try to load it
  2325. // now.
  2326. //
  2327. if (madeupService) {
  2328. //
  2329. // The madeup service's driver doesn't seem to exist yet.
  2330. // We will fail the request without setting a problem code so
  2331. // we will try it again later. (Root Enumerated devices...)
  2332. //
  2333. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  2334. "PipCallDriverAddDevice:\t\t\tCannot find driver "
  2335. "object for madeup service\n"));
  2336. status = STATUS_UNSUCCESSFUL;
  2337. goto Cleanup;
  2338. }
  2339. //
  2340. // Get the start type. We always need this in case the service is
  2341. // disabled. Default to SERVICE_DISABLED if the service's start type
  2342. // is missing or corrupted.
  2343. //
  2344. loadType = SERVICE_DISABLED;
  2345. status = IopGetRegistryValue(serviceKey, L"Start", &keyValueInformation);
  2346. if (NT_SUCCESS(status)) {
  2347. if (keyValueInformation->Type == REG_DWORD) {
  2348. if (keyValueInformation->DataLength == sizeof(ULONG)) {
  2349. loadType = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  2350. }
  2351. }
  2352. ExFreePool(keyValueInformation);
  2353. }
  2354. if (ServiceType != DeviceService && !PnPBootDriversInitialized) {
  2355. //
  2356. // Get the group index. We need this because PipLoadBootFilterDriver
  2357. // uses the group index as an index into it's internally sorted
  2358. // list of loaded boot drivers.
  2359. //
  2360. groupIndex = PpInitGetGroupOrderIndex(serviceKey);
  2361. //
  2362. // If we are in BootDriverInitialization phase and trying to load a
  2363. // filter driver
  2364. //
  2365. status = PipLoadBootFilterDriver(
  2366. &unicodeDriverName,
  2367. groupIndex,
  2368. &driverObject
  2369. );
  2370. if (NT_SUCCESS(status)) {
  2371. ASSERT(driverObject);
  2372. #if DBG
  2373. tempDrvObj = IopReferenceDriverObjectByName(&unicodeDriverName);
  2374. ASSERT(tempDrvObj == driverObject);
  2375. #else
  2376. ObReferenceObject(driverObject);
  2377. #endif
  2378. } else if (status != STATUS_DRIVER_BLOCKED &&
  2379. status != STATUS_DRIVER_BLOCKED_CRITICAL) {
  2380. goto Cleanup;
  2381. }
  2382. } else {
  2383. if (!Context->LoadDriver) {
  2384. //
  2385. // We're not supposed to try and load a driver - most likely our
  2386. // disk drivers aren't initialized yet. We need to stop the add
  2387. // process but we can't mark the devnode as failed or we won't
  2388. // be called again when we can load the drivers.
  2389. //
  2390. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  2391. "PipCallDriverAddDevice:\t\t\tNot allowed to load "
  2392. "drivers yet\n"));
  2393. status = STATUS_UNSUCCESSFUL;
  2394. goto Cleanup;
  2395. }
  2396. if (loadType > Context->AddContext->DriverStartType) {
  2397. if (loadType == SERVICE_DISABLED &&
  2398. !PipDoesDevNodeHaveProblem(Context->DeviceNode)) {
  2399. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_DISABLED_SERVICE);
  2400. }
  2401. //
  2402. // The service is either disabled or we are not at the right
  2403. // time to load it. Don't load it, but make sure we can get
  2404. // called again. If a service is marked as demand start, we
  2405. // always load it.
  2406. //
  2407. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  2408. "PipCallDriverAddDevice:\t\t\tService is disabled or not at right time to load it\n"));
  2409. status = STATUS_UNSUCCESSFUL;
  2410. goto Cleanup;
  2411. }
  2412. //
  2413. // Check in the registry to find the name of the driver object
  2414. // for this device.
  2415. //
  2416. status = PipOpenServiceEnumKeys(&unicodeServiceName,
  2417. KEY_READ,
  2418. &handle,
  2419. NULL,
  2420. FALSE);
  2421. if (!NT_SUCCESS(status)) {
  2422. //
  2423. // Cannot open the service key for this driver. This is a
  2424. // fatal error.
  2425. //
  2426. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2427. "PipCallDriverAddDevice:\t\t\tStatus %#08lx "
  2428. "opening service key\n",
  2429. status));
  2430. //
  2431. // Convert the status values into something more definite.
  2432. //
  2433. if (status != STATUS_INSUFFICIENT_RESOURCES) {
  2434. status = STATUS_ILL_FORMED_SERVICE_ENTRY;
  2435. }
  2436. } else {
  2437. //
  2438. // The handle we pass in here will be closed by IopLoadDriver.
  2439. // Note that IopLoadDriver return success without actually
  2440. // loading the driver. This happens in the safe mode boot case.
  2441. //
  2442. status = IopLoadDriver(
  2443. handle,
  2444. FALSE,
  2445. (ServiceType != DeviceService)? TRUE : FALSE,
  2446. &driverEntryStatus);
  2447. //
  2448. // Convert the status values into something more definite.
  2449. //
  2450. if (!NT_SUCCESS(status)) {
  2451. if (status == STATUS_FAILED_DRIVER_ENTRY) {
  2452. //
  2453. // Preserve insufficient resources return by the driver
  2454. //
  2455. if (driverEntryStatus == STATUS_INSUFFICIENT_RESOURCES) {
  2456. status = STATUS_INSUFFICIENT_RESOURCES;
  2457. }
  2458. } else if ((status != STATUS_INSUFFICIENT_RESOURCES) &&
  2459. (status != STATUS_PLUGPLAY_NO_DEVICE) &&
  2460. (status != STATUS_DRIVER_FAILED_PRIOR_UNLOAD) &&
  2461. (status != STATUS_DRIVER_BLOCKED) &&
  2462. (status != STATUS_DRIVER_BLOCKED_CRITICAL)) {
  2463. //
  2464. // Assume this happened because the driver could not be
  2465. // loaded.
  2466. //
  2467. status = STATUS_DRIVER_UNABLE_TO_LOAD;
  2468. }
  2469. }
  2470. if (PnPInitialized) {
  2471. IopCallDriverReinitializationRoutines();
  2472. }
  2473. }
  2474. //
  2475. // Try and get a pointer to the driver object for the service.
  2476. //
  2477. driverObject = IopReferenceDriverObjectByName(&unicodeDriverName);
  2478. if (driverObject) {
  2479. if (!NT_SUCCESS(status)) {
  2480. //
  2481. // The driver should not be in memory upon failure.
  2482. //
  2483. ASSERT(!driverObject);
  2484. ObDereferenceObject(driverObject);
  2485. driverObject = NULL;
  2486. }
  2487. } else {
  2488. if (NT_SUCCESS(status)) {
  2489. //
  2490. // Driver was probably not loaded because of safe mode.
  2491. //
  2492. ASSERT(InitSafeBootMode);
  2493. status = STATUS_NOT_SAFE_MODE_DRIVER;
  2494. }
  2495. }
  2496. }
  2497. }
  2498. //
  2499. // If we still dont have a driver object, then something failed.
  2500. //
  2501. if (driverObject == NULL) {
  2502. //
  2503. // Apparently the load didn't work out very well.
  2504. //
  2505. ASSERT(!NT_SUCCESS(status));
  2506. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  2507. "PipCallDriverAddDevice:\t\t\tUnable to reference "
  2508. "driver %wZ (%x)\n", &unicodeDriverName, status));
  2509. if (!PipDoesDevNodeHaveProblem(Context->DeviceNode)) {
  2510. switch(status) {
  2511. case STATUS_ILL_FORMED_SERVICE_ENTRY:
  2512. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_DRIVER_SERVICE_KEY_INVALID);
  2513. break;
  2514. case STATUS_INSUFFICIENT_RESOURCES:
  2515. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_OUT_OF_MEMORY);
  2516. break;
  2517. case STATUS_PLUGPLAY_NO_DEVICE:
  2518. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_LEGACY_SERVICE_NO_DEVICES);
  2519. break;
  2520. case STATUS_DRIVER_FAILED_PRIOR_UNLOAD:
  2521. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD);
  2522. break;
  2523. case STATUS_DRIVER_UNABLE_TO_LOAD:
  2524. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_DRIVER_FAILED_LOAD);
  2525. break;
  2526. case STATUS_FAILED_DRIVER_ENTRY:
  2527. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_FAILED_DRIVER_ENTRY);
  2528. break;
  2529. case STATUS_DRIVER_BLOCKED_CRITICAL:
  2530. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_DRIVER_BLOCKED);
  2531. Context->DeviceNode->Flags |= DNF_DRIVER_BLOCKED;
  2532. break;
  2533. case STATUS_DRIVER_BLOCKED:
  2534. Context->DeviceNode->Flags |= DNF_DRIVER_BLOCKED;
  2535. status = STATUS_SUCCESS;
  2536. break;
  2537. default:
  2538. case STATUS_NOT_SAFE_MODE_DRIVER:
  2539. ASSERT(0);
  2540. PipSetDevNodeProblem(Context->DeviceNode, CM_PROB_FAILED_ADD);
  2541. break;
  2542. }
  2543. SAVE_FAILURE_INFO(Context->DeviceNode, status);
  2544. } else {
  2545. //
  2546. // We're very curious - when does this happen?
  2547. //
  2548. ASSERT(0);
  2549. }
  2550. goto Cleanup;
  2551. }
  2552. if (!(driverObject->Flags & DRVO_INITIALIZED)) {
  2553. ObDereferenceObject(driverObject);
  2554. status = STATUS_UNSUCCESSFUL;
  2555. goto Cleanup;
  2556. }
  2557. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  2558. "PipCallDriverAddDevice:\t\t\tDriver Reference %#08lx\n",
  2559. driverObject));
  2560. //
  2561. // Check to see if the driver is a legacy driver rather than a Pnp one.
  2562. //
  2563. if (IopIsLegacyDriver(driverObject)) {
  2564. //
  2565. // It is. Since the legacy driver may have already obtained a
  2566. // handle to the device object, we need to assume this device
  2567. // has been added and started.
  2568. //
  2569. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  2570. "PipCallDriverAddDevice:\t\t\tDriver is a legacy "
  2571. "driver\n"));
  2572. if (ServiceType == DeviceService) {
  2573. Context->DeviceNode->Flags |= DNF_LEGACY_DRIVER;
  2574. PipSetDevNodeState(Context->DeviceNode, DeviceNodeStarted, NULL);
  2575. status = STATUS_UNSUCCESSFUL;
  2576. } else {
  2577. //
  2578. // We allow someone to plug in a legacy driver as a filter driver.
  2579. // In this case, the legacy driver will be loaded but will not be part
  2580. // of our pnp driver stack.
  2581. //
  2582. status = STATUS_SUCCESS;
  2583. }
  2584. goto Cleanup;
  2585. }
  2586. //
  2587. // There's a chance the driver detected this PDO during it's driver entry
  2588. // routine. If it did then just bail out.
  2589. //
  2590. if (Context->DeviceNode->State != DeviceNodeInitialized &&
  2591. Context->DeviceNode->State != DeviceNodeDriversAdded) {
  2592. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  2593. "PipCallDriverAddDevice\t\t\tDevNode was reported "
  2594. "as detected during driver entry\n"));
  2595. status = STATUS_UNSUCCESSFUL;
  2596. goto Cleanup;
  2597. }
  2598. //
  2599. // Add the driver to the list.
  2600. //
  2601. {
  2602. PDRIVER_LIST_ENTRY listEntry;
  2603. PDRIVER_LIST_ENTRY *runner = &(Context->DriverLists[ServiceType]);
  2604. status = STATUS_SUCCESS;
  2605. //
  2606. // Allocate a new list entry to queue this driver object for the caller
  2607. //
  2608. listEntry = ExAllocatePool(PagedPool, sizeof(DRIVER_LIST_ENTRY));
  2609. if (listEntry == NULL) {
  2610. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  2611. "PipCallDriverAddDevice:\t\t\tUnable to allocate list "
  2612. "entry\n"));
  2613. status = STATUS_INSUFFICIENT_RESOURCES;
  2614. goto Cleanup;
  2615. }
  2616. listEntry->DriverObject = driverObject;
  2617. listEntry->NextEntry = NULL;
  2618. while(*runner != NULL) {
  2619. runner = &((*runner)->NextEntry);
  2620. }
  2621. *runner = listEntry;
  2622. }
  2623. Cleanup:
  2624. if (serviceKey) {
  2625. ZwClose(serviceKey);
  2626. }
  2627. if (freeDriverName) {
  2628. RtlFreeUnicodeString(&unicodeDriverName);
  2629. }
  2630. return status;
  2631. }
  2632. NTSTATUS
  2633. PiRestartDevice(
  2634. IN PPI_DEVICE_REQUEST Request
  2635. )
  2636. {
  2637. ADD_CONTEXT addContext;
  2638. NTSTATUS status;
  2639. PDEVICE_NODE deviceNode;
  2640. PAGED_CODE();
  2641. ASSERT(Request->DeviceObject != NULL);
  2642. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  2643. if (PipIsDevNodeDeleted(deviceNode)) {
  2644. return STATUS_DELETE_PENDING;
  2645. } else if (PipDoesDevNodeHaveProblem(deviceNode)) {
  2646. return STATUS_UNSUCCESSFUL;
  2647. }
  2648. switch(deviceNode->State) {
  2649. case DeviceNodeStartPending:
  2650. //
  2651. // Not wired up today, but if the device is starting then we should
  2652. // in theory defer completing this request until the IRP is
  2653. // completed.
  2654. //
  2655. ASSERT(0);
  2656. //
  2657. // Fall through
  2658. //
  2659. case DeviceNodeStarted:
  2660. case DeviceNodeQueryStopped:
  2661. case DeviceNodeStopped:
  2662. case DeviceNodeRestartCompletion:
  2663. case DeviceNodeEnumeratePending:
  2664. return STATUS_SUCCESS;
  2665. case DeviceNodeInitialized:
  2666. //
  2667. // ISSUE - 2000/08/23 - AdriaO: Question,
  2668. // When this happens, isn't it a bug in user mode?
  2669. //
  2670. // Anyway, fall on through...
  2671. //
  2672. //ASSERT(0);
  2673. case DeviceNodeRemoved:
  2674. ASSERT(!(deviceNode->UserFlags & DNUF_WILL_BE_REMOVED));
  2675. IopRestartDeviceNode(deviceNode);
  2676. break;
  2677. case DeviceNodeUninitialized:
  2678. case DeviceNodeDriversAdded:
  2679. case DeviceNodeResourcesAssigned:
  2680. case DeviceNodeEnumerateCompletion:
  2681. case DeviceNodeStartCompletion:
  2682. case DeviceNodeStartPostWork:
  2683. //
  2684. // ISSUE - 2000/08/23 - AdriaO: Question,
  2685. // When this happens, isn't it a bug in user mode?
  2686. //
  2687. //ASSERT(0);
  2688. break;
  2689. case DeviceNodeAwaitingQueuedDeletion:
  2690. case DeviceNodeAwaitingQueuedRemoval:
  2691. case DeviceNodeQueryRemoved:
  2692. case DeviceNodeRemovePendingCloses:
  2693. case DeviceNodeDeletePendingCloses:
  2694. return STATUS_UNSUCCESSFUL;
  2695. case DeviceNodeDeleted:
  2696. case DeviceNodeUnspecified:
  2697. default:
  2698. ASSERT(0);
  2699. return STATUS_UNSUCCESSFUL;
  2700. }
  2701. if (Request->RequestType == StartDevice) {
  2702. addContext.DriverStartType = SERVICE_DEMAND_START;
  2703. ObReferenceObject(deviceNode->PhysicalDeviceObject);
  2704. status = PipProcessDevNodeTree(
  2705. deviceNode,
  2706. PnPBootDriversInitialized, // LoadDriver
  2707. FALSE, // ReallocateResources
  2708. EnumTypeNone,
  2709. Request->CompletionEvent != NULL, // Synchronous
  2710. FALSE,
  2711. &addContext,
  2712. Request);
  2713. }
  2714. return STATUS_SUCCESS;
  2715. }
  2716. NTSTATUS
  2717. PipQueryDeviceCapabilities(
  2718. IN PDEVICE_NODE DeviceNode,
  2719. OUT PDEVICE_CAPABILITIES Capabilities
  2720. )
  2721. /*++
  2722. Routine Description:
  2723. This routine will issue an irp to the DeviceObject to retrieve the
  2724. pnp device capabilities.
  2725. Should only be called twice - first from PipProcessNewDeviceNode,
  2726. and second from IopQueryAndSaveDeviceNodeCapabilities, called after
  2727. device is started. If you consider calling this device, see if
  2728. DeviceNode->CapabilityFlags does what you need instead (accessed
  2729. via IopDeviceNodeFlagsToCapabilities(...).
  2730. Arguments:
  2731. DeviceNode - the device object the request should be sent to.
  2732. Capabilities - a capabilities structure to be filled in by the driver.
  2733. Return Value:
  2734. status
  2735. --*/
  2736. {
  2737. IO_STACK_LOCATION irpStack;
  2738. NTSTATUS status;
  2739. //
  2740. // Initialize the capabilities structure.
  2741. //
  2742. RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
  2743. Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
  2744. Capabilities->Version = 1;
  2745. Capabilities->Address = Capabilities->UINumber = (ULONG)-1;
  2746. //
  2747. // Initialize the stack location to pass to IopSynchronousCall()
  2748. //
  2749. RtlZeroMemory(&irpStack, sizeof(IO_STACK_LOCATION));
  2750. //
  2751. // Query the device's capabilities
  2752. //
  2753. irpStack.MajorFunction = IRP_MJ_PNP;
  2754. irpStack.MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  2755. irpStack.Parameters.DeviceCapabilities.Capabilities = Capabilities;
  2756. status = IopSynchronousCall(DeviceNode->PhysicalDeviceObject,
  2757. &irpStack,
  2758. NULL);
  2759. ASSERT(status != STATUS_PENDING);
  2760. return status;
  2761. }
  2762. NTSTATUS
  2763. PipMakeGloballyUniqueId(
  2764. IN PDEVICE_OBJECT DeviceObject,
  2765. IN PWCHAR UniqueId,
  2766. OUT PWCHAR *GloballyUniqueId
  2767. )
  2768. {
  2769. NTSTATUS status;
  2770. ULONG length;
  2771. PWSTR id, Prefix = NULL;
  2772. HANDLE enumKey;
  2773. HANDLE instanceKey;
  2774. UCHAR keyBuffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)];
  2775. PKEY_VALUE_PARTIAL_INFORMATION keyValue, stringValueBuffer = NULL;
  2776. UNICODE_STRING valueName;
  2777. ULONG uniqueIdValue, Hash, hashInstance;
  2778. PDEVICE_NODE parentNode;
  2779. PAGED_CODE();
  2780. id = NULL;
  2781. //
  2782. // We need to build an instance id to uniquely identify this
  2783. // device. We will accomplish this by producing a prefix that will be
  2784. // prepended to the non-unique device id supplied.
  2785. //
  2786. //
  2787. // To 'unique-ify' the child's instance ID, we will retrieve
  2788. // the unique "UniqueParentID" number that has been assigned
  2789. // to the parent and use it to construct a prefix. This is
  2790. // the legacy mechanism supported here so that existing device
  2791. // settings are not lost on upgrade.
  2792. //
  2793. PiLockPnpRegistry(FALSE);
  2794. parentNode = ((PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode)->Parent;
  2795. status = IopOpenRegistryKeyEx( &enumKey,
  2796. NULL,
  2797. &CmRegistryMachineSystemCurrentControlSetEnumName,
  2798. KEY_READ | KEY_WRITE
  2799. );
  2800. if (!NT_SUCCESS(status)) {
  2801. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2802. "PipMakeGloballyUniqueId:\tUnable to open HKLM\\SYSTEM\\CCS\\ENUM (status %08lx)\n",
  2803. status));
  2804. goto clean0;
  2805. }
  2806. //
  2807. // Open the instance key for this devnode
  2808. //
  2809. status = IopOpenRegistryKeyEx( &instanceKey,
  2810. enumKey,
  2811. &parentNode->InstancePath,
  2812. KEY_READ | KEY_WRITE
  2813. );
  2814. if (!NT_SUCCESS(status)) {
  2815. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  2816. "PipMakeGloballyUniqueId:\tUnable to open registry key for %wZ (status %08lx)\n",
  2817. &parentNode->InstancePath,
  2818. status));
  2819. goto clean1;
  2820. }
  2821. //
  2822. // Attempt to retrieve the "UniqueParentID" value from the device
  2823. // instance key.
  2824. //
  2825. keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)keyBuffer;
  2826. PiWstrToUnicodeString(&valueName, REGSTR_VALUE_UNIQUE_PARENT_ID);
  2827. status = ZwQueryValueKey(instanceKey,
  2828. &valueName,
  2829. KeyValuePartialInformation,
  2830. keyValue,
  2831. sizeof(keyBuffer),
  2832. &length
  2833. );
  2834. if (NT_SUCCESS(status)) {
  2835. ASSERT(keyValue->Type == REG_DWORD);
  2836. ASSERT(keyValue->DataLength == sizeof(ULONG));
  2837. if ((keyValue->Type != REG_DWORD) ||
  2838. (keyValue->DataLength != sizeof(ULONG))) {
  2839. status = STATUS_INVALID_PARAMETER;
  2840. goto clean2;
  2841. }
  2842. uniqueIdValue = *(PULONG)(keyValue->Data);
  2843. //
  2844. // OK, we have a unique parent ID number to prefix to the
  2845. // instance ID.
  2846. Prefix = (PWSTR)ExAllocatePool(PagedPool, 9 * sizeof(WCHAR));
  2847. if (!Prefix) {
  2848. status = STATUS_INSUFFICIENT_RESOURCES;
  2849. goto clean2;
  2850. }
  2851. swprintf(Prefix, L"%x", uniqueIdValue);
  2852. } else {
  2853. //
  2854. // This is the current mechanism for finding existing
  2855. // device instance prefixes and calculating new ones if
  2856. // required.
  2857. //
  2858. //
  2859. // Attempt to retrieve the "ParentIdPrefix" value from the device
  2860. // instance key.
  2861. //
  2862. PiWstrToUnicodeString(&valueName, REGSTR_VALUE_PARENT_ID_PREFIX);
  2863. length = (MAX_PARENT_PREFIX + 1) * sizeof(WCHAR) +
  2864. FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  2865. stringValueBuffer = ExAllocatePool(PagedPool,
  2866. length);
  2867. if (stringValueBuffer) {
  2868. status = ZwQueryValueKey(instanceKey,
  2869. &valueName,
  2870. KeyValuePartialInformation,
  2871. stringValueBuffer,
  2872. length,
  2873. &length);
  2874. }
  2875. else {
  2876. status = STATUS_INSUFFICIENT_RESOURCES;
  2877. goto clean2;
  2878. }
  2879. if (NT_SUCCESS(status)) {
  2880. ASSERT(stringValueBuffer->Type == REG_SZ);
  2881. if (stringValueBuffer->Type != REG_SZ) {
  2882. status = STATUS_INVALID_PARAMETER;
  2883. goto clean2;
  2884. }
  2885. //
  2886. // Parent has already been assigned a "ParentIdPrefix".
  2887. //
  2888. Prefix = (PWSTR) ExAllocatePool(PagedPool,
  2889. stringValueBuffer->DataLength);
  2890. if (!Prefix)
  2891. {
  2892. status = STATUS_INSUFFICIENT_RESOURCES;
  2893. goto clean2;
  2894. }
  2895. wcscpy(Prefix, (PWSTR) stringValueBuffer->Data);
  2896. }
  2897. else
  2898. {
  2899. //
  2900. // Parent has not been assigned a "ParentIdPrefix".
  2901. // Compute the prefix:
  2902. // * Compute Hash
  2903. // * Look for value of the form:
  2904. // NextParentId.<level>.<hash>:REG_DWORD: <NextInstance>
  2905. // under CCS\Enum. If not present, create it.
  2906. // * Assign the new "ParentIdPrefix" which will be of
  2907. // of the form:
  2908. // <level>&<hash>&<instance>
  2909. //
  2910. // Allocate a buffer once for the NextParentId... value
  2911. // and for the prefix.
  2912. length = (ULONG)(max(wcslen(REGSTR_VALUE_NEXT_PARENT_ID) + 2 + 8 + 8,
  2913. MAX_PARENT_PREFIX) + 1);
  2914. // Device instances are case in-sensitive. Upcase before
  2915. // performing hash to ensure that the hash is case-insensitve.
  2916. status = RtlUpcaseUnicodeString(&valueName,
  2917. &parentNode->InstancePath,
  2918. TRUE);
  2919. if (!NT_SUCCESS(status))
  2920. {
  2921. goto clean2;
  2922. }
  2923. HASH_UNICODE_STRING(&valueName, &Hash);
  2924. RtlFreeUnicodeString(&valueName);
  2925. Prefix = (PWSTR) ExAllocatePool(PagedPool,
  2926. length * sizeof(WCHAR));
  2927. if (!Prefix) {
  2928. status = STATUS_INSUFFICIENT_RESOURCES;
  2929. goto clean2;
  2930. }
  2931. // Check for existence of "NextParentId...." value and update.
  2932. swprintf(Prefix, L"%s.%x.%x", REGSTR_VALUE_NEXT_PARENT_ID,
  2933. Hash, parentNode->Level);
  2934. RtlInitUnicodeString(&valueName, Prefix);
  2935. keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)keyBuffer;
  2936. status = ZwQueryValueKey(enumKey,
  2937. &valueName,
  2938. KeyValuePartialInformation,
  2939. keyValue,
  2940. sizeof(keyBuffer),
  2941. &length
  2942. );
  2943. if (NT_SUCCESS(status) && (keyValue->Type == REG_DWORD) &&
  2944. (keyValue->DataLength == sizeof(ULONG))) {
  2945. hashInstance = *(PULONG)(keyValue->Data);
  2946. }
  2947. else {
  2948. hashInstance = 0;
  2949. }
  2950. hashInstance++;
  2951. status = ZwSetValueKey(enumKey,
  2952. &valueName,
  2953. TITLE_INDEX_VALUE,
  2954. REG_DWORD,
  2955. &hashInstance,
  2956. sizeof(hashInstance)
  2957. );
  2958. if (!NT_SUCCESS(status)) {
  2959. goto clean2;
  2960. }
  2961. hashInstance--;
  2962. // Create actual ParentIdPrefix string
  2963. PiWstrToUnicodeString(&valueName, REGSTR_VALUE_PARENT_ID_PREFIX);
  2964. length = swprintf(Prefix, L"%x&%x&%x", parentNode->Level,
  2965. Hash, hashInstance) + 1;
  2966. status = ZwSetValueKey(instanceKey,
  2967. &valueName,
  2968. TITLE_INDEX_VALUE,
  2969. REG_SZ,
  2970. Prefix,
  2971. length * sizeof(WCHAR)
  2972. );
  2973. if (!NT_SUCCESS(status))
  2974. {
  2975. goto clean2;
  2976. }
  2977. }
  2978. }
  2979. // Construct the instance id from the non-unique id (if any)
  2980. // provided by the child and the prefix we've constructed.
  2981. length = (ULONG)(wcslen(Prefix) + (UniqueId ? wcslen(UniqueId) : 0) + 2);
  2982. id = (PWSTR)ExAllocatePool(PagedPool, length * sizeof(WCHAR));
  2983. if (!id) {
  2984. status = STATUS_INSUFFICIENT_RESOURCES;
  2985. } else if (UniqueId) {
  2986. swprintf(id, L"%s&%s", Prefix, UniqueId);
  2987. } else {
  2988. wcscpy(id, Prefix);
  2989. }
  2990. clean2:
  2991. ZwClose(instanceKey);
  2992. clean1:
  2993. ZwClose(enumKey);
  2994. clean0:
  2995. PiUnlockPnpRegistry();
  2996. if (stringValueBuffer) {
  2997. ExFreePool(stringValueBuffer);
  2998. }
  2999. if (Prefix) {
  3000. ExFreePool(Prefix);
  3001. }
  3002. *GloballyUniqueId = id;
  3003. return status;
  3004. }
  3005. BOOLEAN
  3006. PipProcessCriticalDevice(
  3007. IN PDEVICE_NODE DeviceNode
  3008. )
  3009. /*++
  3010. Routine Description:
  3011. This routine will check whether the device is a "critical" one (see the
  3012. top of this file for a description of critical). If the device is critical
  3013. then it will be assigned a service based on the contents of
  3014. IopCriticalDeviceList.
  3015. Arguments:
  3016. DeviceNode - the device node to process
  3017. Return Value:
  3018. TRUE if the device is critical
  3019. FALSE otherwise
  3020. --*/
  3021. {
  3022. HANDLE enumKey;
  3023. HANDLE instanceKey;
  3024. UNICODE_STRING service, classGuid, driver, lowerFilters, upperFilters;
  3025. UNICODE_STRING serviceValue, guidValue, driverValue, lowerFiltersValue, upperFiltersValue;
  3026. BOOLEAN foundMatch = FALSE;
  3027. NTSTATUS status;
  3028. #if DBG_SCOPE
  3029. PWCHAR str;
  3030. ULONG length;
  3031. #endif
  3032. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3033. "PipIsCriticalPnpDevice called for devnode %#08lx\n", DeviceNode));
  3034. //
  3035. // Open the HKLM\System\CCS\Enum key.
  3036. //
  3037. status = IopOpenRegistryKeyEx( &enumKey,
  3038. NULL,
  3039. &CmRegistryMachineSystemCurrentControlSetEnumName,
  3040. KEY_READ
  3041. );
  3042. if (!NT_SUCCESS(status)) {
  3043. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  3044. "PipIsCriticalPnpDevice: couldn't open enum key %#08lx\n", status));
  3045. return FALSE;
  3046. }
  3047. //
  3048. // Open the instance key for this devnode
  3049. //
  3050. status = IopOpenRegistryKeyEx( &instanceKey,
  3051. enumKey,
  3052. &DeviceNode->InstancePath,
  3053. KEY_ALL_ACCESS
  3054. );
  3055. ZwClose(enumKey);
  3056. if (!NT_SUCCESS(status)) {
  3057. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  3058. "PipIsCriticalPnpDevice: couldn't open instance path key %wZ [%#08lx]\n",
  3059. &(DeviceNode->InstancePath), status));
  3060. return FALSE;
  3061. }
  3062. //
  3063. // Call IopProcessCriticalDeviceRoutine to
  3064. // enumerate entries in the CriticalDeviceDatabase
  3065. // and compare with HardwareId and CompatibleIds
  3066. // value data from instanceKey.
  3067. //
  3068. PiWstrToUnicodeString(&service, NULL);
  3069. PiWstrToUnicodeString(&classGuid, NULL);
  3070. PiWstrToUnicodeString(&driver, NULL);
  3071. PiWstrToUnicodeString(&lowerFilters, NULL);
  3072. PiWstrToUnicodeString(&upperFilters, NULL);
  3073. status = PipProcessCriticalDeviceRoutine(instanceKey,
  3074. &foundMatch,
  3075. &service,
  3076. &classGuid,
  3077. &driver,
  3078. &lowerFilters,
  3079. &upperFilters);
  3080. if (!NT_SUCCESS(status) || !foundMatch) {
  3081. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3082. "PipProcessCriticalDevice: No match found for devnode %wZ [%#08lx]\n",
  3083. &DeviceNode->InstancePath, status));
  3084. ZwClose(instanceKey);
  3085. return FALSE;
  3086. }
  3087. //
  3088. // If we get here then this is a "critical" device and we know the service
  3089. // to setup for it. Set the service value in the registry.
  3090. //
  3091. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3092. "PipProcessCriticalDevice: Setting up critical service\n"));
  3093. PiWstrToUnicodeString(&serviceValue, REGSTR_VALUE_SERVICE);
  3094. PiWstrToUnicodeString(&guidValue, REGSTR_VALUE_CLASSGUID);
  3095. PiWstrToUnicodeString(&driverValue, REGSTR_VALUE_DRIVER);
  3096. PiWstrToUnicodeString(&lowerFiltersValue, REGSTR_VALUE_LOWERFILTERS);
  3097. PiWstrToUnicodeString(&upperFiltersValue, REGSTR_VALUE_UPPERFILTERS);
  3098. if (classGuid.Buffer) {
  3099. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3100. "PipProcessCriticalDevice: classGuid is %wZ\n",
  3101. &classGuid));
  3102. status = ZwSetValueKey(instanceKey,
  3103. &guidValue,
  3104. 0L,
  3105. REG_SZ,
  3106. classGuid.Buffer,
  3107. classGuid.Length + sizeof(UNICODE_NULL));
  3108. }
  3109. if (driver.Buffer) {
  3110. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3111. "PipProcessCriticalDevice: driver is %wZ\n",
  3112. &driver));
  3113. status = ZwSetValueKey(instanceKey,
  3114. &driverValue,
  3115. 0L,
  3116. REG_SZ,
  3117. driver.Buffer,
  3118. driver.Length + sizeof(UNICODE_NULL));
  3119. }
  3120. if (lowerFilters.Buffer) {
  3121. #if DBG_SCOPE
  3122. str = lowerFilters.Buffer;
  3123. while ((length = (ULONG)wcslen(str)) != 0) {
  3124. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3125. "PipProcessCriticalDevice: lower filter is %ws\n",
  3126. str));
  3127. str += (length + 1);
  3128. }
  3129. #endif
  3130. status = ZwSetValueKey(instanceKey,
  3131. &lowerFiltersValue,
  3132. 0L,
  3133. REG_MULTI_SZ,
  3134. lowerFilters.Buffer,
  3135. lowerFilters.Length); // + sizeof(UNICODE_NULL));
  3136. }
  3137. if (upperFilters.Buffer) {
  3138. #if DBG_SCOPE
  3139. str = upperFilters.Buffer;
  3140. while ((length = (ULONG)wcslen(str)) != 0) {
  3141. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3142. "PipProcessCriticalDevice: upper filter is %ws\n",
  3143. str));
  3144. str += (length + 1);
  3145. }
  3146. #endif
  3147. status = ZwSetValueKey(instanceKey,
  3148. &upperFiltersValue,
  3149. 0L,
  3150. REG_MULTI_SZ,
  3151. upperFilters.Buffer,
  3152. upperFilters.Length); // + sizeof(UNICODE_NULL));
  3153. }
  3154. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3155. "PipProcessCriticalDevice: service is %wZ\n",
  3156. &service));
  3157. status = ZwSetValueKey(instanceKey,
  3158. &serviceValue,
  3159. 0L,
  3160. REG_SZ,
  3161. service.Buffer,
  3162. service.Length + sizeof(UNICODE_NULL));
  3163. //
  3164. // If the service was set properly set the CONFIGFLAG_FINISH_INSTALL so
  3165. // we will still get a new hw found popup and go through the class
  3166. // installer.
  3167. //
  3168. if (NT_SUCCESS(status)) {
  3169. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  3170. UNICODE_STRING valueName;
  3171. PKEY_VALUE_PARTIAL_INFORMATION keyInfo =
  3172. (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  3173. ULONG flags = 0;
  3174. ULONG valueLength;
  3175. NTSTATUS tmpStatus;
  3176. PiWstrToUnicodeString(&valueName, REGSTR_VALUE_CONFIG_FLAGS);
  3177. tmpStatus = ZwQueryValueKey(instanceKey,
  3178. &valueName,
  3179. KeyValuePartialInformation,
  3180. keyInfo,
  3181. sizeof(buffer),
  3182. &valueLength);
  3183. if (NT_SUCCESS(tmpStatus) && (keyInfo->Type == REG_DWORD)) {
  3184. flags = *(PULONG)keyInfo->Data;
  3185. }
  3186. flags &= ~(CONFIGFLAG_REINSTALL | CONFIGFLAG_FAILEDINSTALL);
  3187. flags |= CONFIGFLAG_FINISH_INSTALL;
  3188. ZwSetValueKey(instanceKey,
  3189. &valueName,
  3190. 0L,
  3191. REG_DWORD,
  3192. &flags,
  3193. sizeof(ULONG));
  3194. ASSERT(!PipDoesDevNodeHaveProblem(DeviceNode) ||
  3195. PipIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) ||
  3196. PipIsDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL) ||
  3197. PipIsDevNodeProblem(DeviceNode, CM_PROB_REINSTALL));
  3198. PipClearDevNodeProblem(DeviceNode);
  3199. }
  3200. ZwClose(instanceKey);
  3201. RtlFreeUnicodeString(&service);
  3202. RtlFreeUnicodeString(&classGuid);
  3203. RtlFreeUnicodeString(&driver);
  3204. RtlFreeUnicodeString(&lowerFilters);
  3205. RtlFreeUnicodeString(&upperFilters);
  3206. return (BOOLEAN)NT_SUCCESS(status);
  3207. }
  3208. NTSTATUS
  3209. PipProcessCriticalDeviceRoutine(
  3210. IN HANDLE HDevInstance,
  3211. IN PBOOLEAN FoundMatch,
  3212. IN PUNICODE_STRING ServiceName,
  3213. IN PUNICODE_STRING ClassGuid,
  3214. IN PUNICODE_STRING Driver,
  3215. IN PUNICODE_STRING LowerFilters,
  3216. IN PUNICODE_STRING UpperFilters
  3217. )
  3218. /*++
  3219. Routine Description:
  3220. This routine will enumerate all values of the CriticalDeviceDatabase
  3221. registry key, and compare each with entries within
  3222. the HardwareId and CompatibleIds values of key associated
  3223. with the current device instance.
  3224. Arguments:
  3225. HDevInstance - HANDLE to device instance.
  3226. FoundMatch - receives TRUE if a match was found.
  3227. ServiceName - receives name of service to be assigned to
  3228. the device instance pointed to by HDevInstance.
  3229. ClassGuid - receives name of class GUID to be assigned to
  3230. the device instance pointed to by HDevInstance.
  3231. Driver - receives name of "class GUID\InstanceID" to be assigned to
  3232. the device instance pointed to by HDevInstance.
  3233. LowerFilters - receives name of lower filters to be assigned to
  3234. the device instance pointed to by HDevInstance.
  3235. UpperFilters - receives name of upper filters to be assigned to
  3236. the device instance pointed to by HDevInstance.
  3237. Return Value:
  3238. NTSTATUS code
  3239. --*/
  3240. {
  3241. NTSTATUS status;
  3242. HANDLE hRegistryMachine, hCriticalDeviceKey,
  3243. hCriticalEntry;
  3244. PWSTR keyValueInfoTag[2];
  3245. PKEY_VALUE_FULL_INFORMATION keyValueInfo[2];
  3246. BUFFER_INFO infoBuffer;
  3247. ULONG enumIndex, idIndex, resultSize, stringLength;
  3248. UNICODE_STRING tmpUnicodeString, unicodeCriticalEntry,
  3249. unicodeCriticalDeviceKeyName;
  3250. PWCHAR stringStart, bufferEnd, ptr, ids;
  3251. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  3252. #define INITIAL_INFOBUFFER_SIZE sizeof(KEY_VALUE_FULL_INFORMATION) + 8*sizeof(WCHAR) + 255*sizeof(WCHAR)
  3253. infoBuffer.Buffer = NULL;
  3254. keyValueInfo[0] = NULL;
  3255. keyValueInfo[1] = NULL;
  3256. ids = NULL;
  3257. //
  3258. // Get handle to \REGISTRY\MACHINE registry key.
  3259. //
  3260. status = IopOpenRegistryKeyEx( &hRegistryMachine,
  3261. NULL,
  3262. &CmRegistryMachineName,
  3263. KEY_READ
  3264. );
  3265. if (!NT_SUCCESS(status)) {
  3266. return status;
  3267. }
  3268. //
  3269. // Open CriticalDeviceDatabase registry key to enumerate through.
  3270. //
  3271. // This key contains hardware id's for so called "critical" devices. These
  3272. // are devices for which, for one reason or another, we cannot wait for
  3273. // config manager to bring them on line. These are primarily devices which
  3274. // are necessary in order to bring the system up into user mode so that
  3275. // config manager can be run (disks, keyboards, video, etc...)
  3276. //
  3277. PiWstrToUnicodeString(&unicodeCriticalDeviceKeyName, REGSTR_PATH_CRITICALDEVICEDATABASE);
  3278. status = IopOpenRegistryKeyEx( &hCriticalDeviceKey,
  3279. hRegistryMachine,
  3280. &unicodeCriticalDeviceKeyName,
  3281. KEY_READ
  3282. );
  3283. //
  3284. // Close handle to \REGISTRY\MACHINE.
  3285. //
  3286. ZwClose(hRegistryMachine);
  3287. //
  3288. // Check success in opening CriticalDeviceDatabase key.
  3289. //
  3290. if (!NT_SUCCESS(status)) {
  3291. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3292. "PipProcessCriticalDeviceRoutine: Unable to open %wZ key, status = %#08lx\n",
  3293. &unicodeCriticalDeviceKeyName, status));
  3294. return status;
  3295. }
  3296. //
  3297. // Allocate a buffer to store KeyValueFullInformation
  3298. // of values from CriticalDeviceDatabase key.
  3299. //
  3300. status = IopAllocateBuffer( &infoBuffer,
  3301. INITIAL_INFOBUFFER_SIZE );
  3302. if (!NT_SUCCESS(status)) {
  3303. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3304. "PipProcessCriticalDeviceRoutine: Unable to allocate buffer to hold key values, status = %\n"));
  3305. goto cleanup;
  3306. }
  3307. //
  3308. // Retrieve the HardwareId and CompatibleIds device instance registry key
  3309. // values.
  3310. //
  3311. keyValueInfoTag[0] = REGSTR_VALUE_HARDWAREID;
  3312. keyValueInfoTag[1] = REGSTR_VALUE_COMPATIBLEIDS;
  3313. for (idIndex=0; idIndex < 2; idIndex++) {
  3314. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3315. "PipProcessCriticalDeviceRoutine: Processing %ws entries\n",
  3316. keyValueInfoTag[idIndex]));
  3317. //
  3318. // Read Key Value Information from HardwareId and CompatibleIds
  3319. //
  3320. status = IopGetRegistryValue(HDevInstance,
  3321. keyValueInfoTag[idIndex],
  3322. &keyValueInfo[idIndex]);
  3323. if (!NT_SUCCESS(status)) {
  3324. //
  3325. // Error retrieving the registry value, skip it and move on.
  3326. //
  3327. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3328. "PipProcessCriticalDeviceRoutine: Error retrieving %ws value, status = %#08lx\n",
  3329. keyValueInfoTag[idIndex], status));
  3330. status = STATUS_SUCCESS;
  3331. continue;
  3332. } else if ((keyValueInfo[idIndex]->Type != REG_MULTI_SZ) ||
  3333. (keyValueInfo[idIndex]->DataLength == 0)) {
  3334. //
  3335. // The registry value is not valid, skip it and move on.
  3336. //
  3337. ExFreePool(keyValueInfo[idIndex]);
  3338. keyValueInfo[idIndex] = NULL;
  3339. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3340. "PipProcessCriticalDeviceRoutine: Invalid %ws registry value, skipping.\n",
  3341. keyValueInfoTag[idIndex]));
  3342. continue;
  3343. } else {
  3344. ASSERT(keyValueInfo[idIndex]);
  3345. ids = (PWCHAR)KEY_VALUE_DATA(keyValueInfo[idIndex]);
  3346. //
  3347. // Make sure all of the IDs match '\' replacement policy.
  3348. //
  3349. tmpUnicodeString.Buffer = ids;
  3350. tmpUnicodeString.Length = (USHORT)keyValueInfo[idIndex]->DataLength;
  3351. tmpUnicodeString.MaximumLength = tmpUnicodeString.Length;
  3352. IopReplaceSeperatorWithPound(&tmpUnicodeString,
  3353. &tmpUnicodeString);
  3354. //
  3355. // Find start and end of this REG_MULTI_SZ
  3356. //
  3357. ptr = ids;
  3358. stringStart = ptr;
  3359. bufferEnd = (PWCHAR)((PUCHAR)ptr + keyValueInfo[idIndex]->DataLength);
  3360. while(ptr != bufferEnd) {
  3361. if (!*ptr) {
  3362. //
  3363. // Found null-terminated end of a single SZ within the MULTI_SZ.
  3364. //
  3365. stringLength = (ULONG)((PUCHAR)ptr - (PUCHAR)stringStart);
  3366. tmpUnicodeString.Buffer = stringStart;
  3367. tmpUnicodeString.Length = (USHORT)stringLength;
  3368. tmpUnicodeString.MaximumLength = (USHORT)stringLength + sizeof(UNICODE_NULL);
  3369. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3370. "PipProcessCriticalDeviceRoutine: Searching for %ws entry: %wZ\n",
  3371. keyValueInfoTag[idIndex], &tmpUnicodeString));
  3372. //
  3373. // Enumerate through Critical Device entries.
  3374. //
  3375. // For each CriticalDeviceDatabase value entry compare with all entries of HardwareId
  3376. // and CompatibleIds REG_MULTI_SZ for a match
  3377. //
  3378. enumIndex = 0;
  3379. while (((status = ZwEnumerateKey( hCriticalDeviceKey,
  3380. enumIndex,
  3381. KeyBasicInformation,
  3382. (PVOID) infoBuffer.Buffer,
  3383. infoBuffer.MaxSize,
  3384. &resultSize)) != STATUS_NO_MORE_ENTRIES)) {
  3385. if (status == STATUS_BUFFER_OVERFLOW) {
  3386. //
  3387. // Buffer allocated to hold value was too small;
  3388. // resize to specified length, and try again.
  3389. //
  3390. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3391. "PipProcessCriticalDeviceRoutine: Resizing buffer...\n"));
  3392. status = IopResizeBuffer( &infoBuffer,
  3393. resultSize,
  3394. FALSE );
  3395. if (!NT_SUCCESS(status)) {
  3396. //
  3397. // If we can't resize the buffer to the required
  3398. // size, we can't do much more.
  3399. //
  3400. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3401. "PipProcessCriticalDeviceRoutine: Error resizing buffer, status = %#08lx\n",
  3402. status));
  3403. goto cleanup;
  3404. }
  3405. continue;
  3406. } else if (!NT_SUCCESS(status)) {
  3407. //
  3408. // ZwEnumerateKey returned failure status other than
  3409. // STATUS_NO_MORE_ENTRIES or STATUS_BUFFER_OVERFLOW.
  3410. //
  3411. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3412. "PipProcessCriticalDeviceRoutine: Failed to enumerate critical device, status = %#08lx\n",
  3413. status));
  3414. goto cleanup;
  3415. }
  3416. //
  3417. // Store CriticalDeviceDatabase entry in a unicode string to do
  3418. // case-insensitive comparisons with HardwareId/CompatibleIds entries
  3419. // from the new device's instance key.
  3420. //
  3421. unicodeCriticalEntry.Buffer = ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->Name;
  3422. unicodeCriticalEntry.Length = (USHORT) ((PKEY_BASIC_INFORMATION)(infoBuffer.Buffer))->NameLength;
  3423. unicodeCriticalEntry.MaximumLength = unicodeCriticalEntry.Length;
  3424. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3425. "PipProcessCriticalDeviceRoutine: \t key (%u) enumerated: %wZ\n",
  3426. enumIndex,
  3427. &unicodeCriticalEntry));
  3428. //
  3429. // Check for a case-insenitive unicode string match.
  3430. //
  3431. if (RtlEqualUnicodeString(&tmpUnicodeString,
  3432. &unicodeCriticalEntry,
  3433. TRUE)) {
  3434. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3435. "PipProcessCriticalDeviceRoutine: ***** Critical Device %wZ: Matched to Device %wZ.\n",
  3436. &tmpUnicodeString,
  3437. &unicodeCriticalEntry));
  3438. //
  3439. // Query registry values of the critical device match.
  3440. //
  3441. #define NUM_QUERIES 5
  3442. status = IopOpenRegistryKeyEx( &hCriticalEntry,
  3443. hCriticalDeviceKey,
  3444. &unicodeCriticalEntry,
  3445. KEY_READ
  3446. );
  3447. if (!NT_SUCCESS(status)) {
  3448. goto cleanup;
  3449. }
  3450. parameters = (PRTL_QUERY_REGISTRY_TABLE)
  3451. ExAllocatePool(NonPagedPool,
  3452. sizeof(RTL_QUERY_REGISTRY_TABLE)*(NUM_QUERIES+1));
  3453. if (!parameters) {
  3454. ZwClose(hCriticalEntry);
  3455. status = STATUS_INSUFFICIENT_RESOURCES;
  3456. goto cleanup;
  3457. }
  3458. //
  3459. // RTL_QUERY_REGISTRY_DIRECT uses system provided QueryRoutine.
  3460. // Look at the DDK documentation for more details on this flag.
  3461. //
  3462. RtlZeroMemory(parameters,
  3463. sizeof(RTL_QUERY_REGISTRY_TABLE) * (NUM_QUERIES + 1));
  3464. parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3465. parameters[0].Name = REGSTR_VALUE_SERVICE;
  3466. parameters[0].EntryContext = ServiceName;
  3467. parameters[0].DefaultType = REG_SZ;
  3468. parameters[0].DefaultData = L"";
  3469. parameters[0].DefaultLength = 0;
  3470. parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3471. parameters[1].Name = REGSTR_VALUE_CLASSGUID;
  3472. parameters[1].EntryContext = ClassGuid;
  3473. parameters[1].DefaultType = REG_SZ;
  3474. parameters[1].DefaultData = L"";
  3475. parameters[1].DefaultLength = 0;
  3476. parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
  3477. parameters[2].Name = REGSTR_VALUE_LOWERFILTERS;
  3478. parameters[2].EntryContext = LowerFilters;
  3479. parameters[2].DefaultType = REG_MULTI_SZ;
  3480. parameters[2].DefaultData = L"";
  3481. parameters[2].DefaultLength = 0;
  3482. parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
  3483. parameters[3].Name = REGSTR_VALUE_UPPERFILTERS;
  3484. parameters[3].EntryContext = UpperFilters;
  3485. parameters[3].DefaultType = REG_MULTI_SZ;
  3486. parameters[3].DefaultData = L"";
  3487. parameters[3].DefaultLength = 0;
  3488. parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3489. parameters[4].Name = REGSTR_VALUE_DRIVER;
  3490. parameters[4].EntryContext = Driver;
  3491. parameters[4].DefaultType = REG_SZ;
  3492. parameters[4].DefaultData = L"";
  3493. parameters[4].DefaultLength = 0;
  3494. status = RtlQueryRegistryValues(
  3495. RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL,
  3496. (PWSTR) hCriticalEntry,
  3497. parameters,
  3498. NULL,
  3499. NULL
  3500. );
  3501. ExFreePool(parameters);
  3502. ZwClose(hCriticalEntry);
  3503. if (NT_SUCCESS(status)) {
  3504. //
  3505. // Sanity check all of the values...
  3506. // 1) There is a service name
  3507. // 2) If there is a class guid, it is of the proper length
  3508. //
  3509. if (ServiceName->Buffer &&
  3510. ServiceName->Length &&
  3511. ((ClassGuid->Length == 0) || (ClassGuid->Length >= 38*sizeof(WCHAR))) &&
  3512. ((Driver->Length == 0) || (Driver->Length >= 38*sizeof(WCHAR)))) {
  3513. //
  3514. // Caller expects XxxFilters->Buffer == NULL, so make
  3515. // the default case look like that
  3516. //
  3517. if (UpperFilters->Length <= 2 && UpperFilters->Buffer) {
  3518. RtlFreeUnicodeString(UpperFilters);
  3519. }
  3520. if (LowerFilters->Length <= 2 && LowerFilters->Buffer) {
  3521. RtlFreeUnicodeString(LowerFilters);
  3522. }
  3523. if (ClassGuid->Length == 0 && ClassGuid->Buffer) {
  3524. RtlFreeUnicodeString(ClassGuid);
  3525. }
  3526. if (Driver->Length == 0 && Driver->Buffer) {
  3527. RtlFreeUnicodeString(Driver);
  3528. }
  3529. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3530. "PipProcessCriticalDeviceRoutine: ***** Using ServiceName %wZ.\n",
  3531. ServiceName));
  3532. if (ClassGuid->Buffer) {
  3533. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3534. "PipProcessCriticalDeviceRoutine: ***** Using ClassGuid %wZ.\n",
  3535. ClassGuid));
  3536. }
  3537. if (Driver->Buffer) {
  3538. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3539. "PipProcessCriticalDeviceRoutine: ***** Using Driver %wZ.\n",
  3540. Driver));
  3541. }
  3542. //
  3543. // We have a ServiceName match from the
  3544. // CriticalDeviceDatabase, so we're done.
  3545. //
  3546. *FoundMatch = TRUE;
  3547. goto cleanup;
  3548. }
  3549. } else {
  3550. //
  3551. // Just continue searching the database.
  3552. //
  3553. status = STATUS_SUCCESS;
  3554. }
  3555. //
  3556. // Free any strings that may have been allocated by
  3557. // RtlQueryRegistryValues
  3558. //
  3559. RtlFreeUnicodeString(ServiceName);
  3560. RtlFreeUnicodeString(ClassGuid);
  3561. RtlFreeUnicodeString(Driver);
  3562. RtlFreeUnicodeString(LowerFilters);
  3563. RtlFreeUnicodeString(UpperFilters);
  3564. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3565. "PipProcessCriticalDeviceRoutine: Found no ServiceName for %wZ\n",
  3566. &unicodeCriticalEntry));
  3567. }
  3568. //
  3569. // enumerate next key value.
  3570. //
  3571. enumIndex++;
  3572. }
  3573. //
  3574. // See if we're at the end of the MULTI_SZ
  3575. //
  3576. if (((ptr + 1) == bufferEnd) || !*(ptr + 1)) {
  3577. break;
  3578. } else {
  3579. stringStart = ptr + 1;
  3580. }
  3581. }
  3582. //
  3583. // advance to next character.
  3584. //
  3585. ptr++;
  3586. }
  3587. ids = NULL;
  3588. }
  3589. }
  3590. //
  3591. // No match with a ServiceName was found.
  3592. //
  3593. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3594. "PipProcessCriticalDeviceRoutine: No match found for this device.\n"));
  3595. *FoundMatch = FALSE;
  3596. status = STATUS_SUCCESS;
  3597. cleanup:
  3598. if (infoBuffer.Buffer) {
  3599. IopFreeBuffer(&infoBuffer);
  3600. }
  3601. if (hCriticalDeviceKey) {
  3602. ZwClose(hCriticalDeviceKey);
  3603. }
  3604. if (keyValueInfo[0]) {
  3605. ExFreePool(keyValueInfo[0]);
  3606. }
  3607. if (keyValueInfo[1]) {
  3608. ExFreePool(keyValueInfo[1]);
  3609. }
  3610. return status;
  3611. }
  3612. BOOLEAN
  3613. PipGetRegistryDwordWithFallback(
  3614. IN PUNICODE_STRING valueName,
  3615. IN HANDLE PrimaryKey,
  3616. IN HANDLE SecondaryKey,
  3617. IN OUT PULONG Value
  3618. )
  3619. /*++
  3620. Routine Description:
  3621. If
  3622. (1) Primary key has a value named "ValueName" that is REG_DWORD, return it
  3623. Else If
  3624. (2) Secondary key has a value named "ValueName" that is REG_DWORD, return it
  3625. Else
  3626. (3) Leave Value untouched and return error
  3627. Arguments:
  3628. ValueName - Unicode name of value to query
  3629. PrimaryKey - If non-null, check this first
  3630. SecondaryKey - If non-null, check this second
  3631. Value - IN = default value, OUT = actual value
  3632. Return Value:
  3633. TRUE if value found
  3634. --*/
  3635. {
  3636. PKEY_VALUE_FULL_INFORMATION info;
  3637. PUCHAR data;
  3638. NTSTATUS status;
  3639. HANDLE Keys[3];
  3640. int count = 0;
  3641. int index;
  3642. BOOLEAN set = FALSE;
  3643. if (PrimaryKey != NULL) {
  3644. Keys[count++] = PrimaryKey;
  3645. }
  3646. if (SecondaryKey != NULL) {
  3647. Keys[count++] = SecondaryKey;
  3648. }
  3649. Keys[count] = NULL;
  3650. for (index = 0; index < count && !set; index ++) {
  3651. info = NULL;
  3652. try {
  3653. status = IopGetRegistryValue(Keys[index],
  3654. valueName->Buffer,
  3655. &info);
  3656. if (NT_SUCCESS(status) && info->Type == REG_DWORD) {
  3657. data = ((PUCHAR) info) + info->DataOffset;
  3658. *Value = *((PULONG) data);
  3659. set = TRUE;
  3660. }
  3661. } except(EXCEPTION_EXECUTE_HANDLER) {
  3662. //
  3663. // do nothing
  3664. //
  3665. }
  3666. if (info) {
  3667. ExFreePool(info);
  3668. }
  3669. }
  3670. return set;
  3671. }
  3672. PSECURITY_DESCRIPTOR
  3673. PipGetRegistrySecurityWithFallback(
  3674. IN PUNICODE_STRING valueName,
  3675. IN HANDLE PrimaryKey,
  3676. IN HANDLE SecondaryKey
  3677. )
  3678. /*++
  3679. Routine Description:
  3680. If
  3681. (1) Primary key has a binary value named "ValueName" that is
  3682. REG_BINARY and appears to be a valid security descriptor, return it
  3683. Else
  3684. (2) do same for Secondary key
  3685. Else
  3686. (3) Return NULL
  3687. Arguments:
  3688. ValueName - Unicode name of value to query
  3689. PrimaryKey - If non-null, check this first
  3690. SecondaryKey - If non-null, check this second
  3691. Return Value:
  3692. Security Descriptor if found, else NULL
  3693. --*/
  3694. {
  3695. PKEY_VALUE_FULL_INFORMATION info;
  3696. PUCHAR data;
  3697. NTSTATUS status;
  3698. HANDLE Keys[3];
  3699. int count = 0;
  3700. int index;
  3701. BOOLEAN set = FALSE;
  3702. PSECURITY_DESCRIPTOR secDesc = NULL;
  3703. PSECURITY_DESCRIPTOR allocDesc = NULL;
  3704. if (PrimaryKey != NULL) {
  3705. Keys[count++] = PrimaryKey;
  3706. }
  3707. if (SecondaryKey != NULL) {
  3708. Keys[count++] = SecondaryKey;
  3709. }
  3710. Keys[count] = NULL;
  3711. for (index = 0; index < count && !set; index ++) {
  3712. info = NULL;
  3713. try {
  3714. status = IopGetRegistryValue(Keys[index],
  3715. valueName->Buffer,
  3716. &info);
  3717. if (NT_SUCCESS(status) && info->Type == REG_BINARY) {
  3718. data = ((PUCHAR) info) + info->DataOffset;
  3719. secDesc = (PSECURITY_DESCRIPTOR)data;
  3720. /*if (SeValidSecurityDescriptor( SECURITY_DESCRIPTOR_MIN_LENGTH,
  3721. secDesc)) {*/
  3722. status = SeCaptureSecurityDescriptor(secDesc,
  3723. KernelMode,
  3724. PagedPool,
  3725. TRUE,
  3726. &allocDesc);
  3727. if (NT_SUCCESS(status)) {
  3728. set = TRUE;
  3729. }
  3730. /*} else {
  3731. //
  3732. // Perhaps this happened due to a corrupted registry entry?
  3733. //
  3734. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  3735. "PipChangeDeviceObjectFromRegistryProperties: Security descriptor not valid!\n"));
  3736. ASSERT(0);
  3737. }*/
  3738. }
  3739. } except(EXCEPTION_EXECUTE_HANDLER) {
  3740. //
  3741. // do nothing
  3742. //
  3743. }
  3744. if (info) {
  3745. ExFreePool(info);
  3746. }
  3747. }
  3748. if (set) {
  3749. return allocDesc;
  3750. }
  3751. return NULL;
  3752. }
  3753. NTSTATUS
  3754. PipChangeDeviceObjectFromRegistryProperties(
  3755. IN PDEVICE_OBJECT PhysicalDeviceObject,
  3756. IN HANDLE DeviceClassPropKey,
  3757. IN HANDLE DevicePropKey,
  3758. IN BOOLEAN UsePdoCharacteristics
  3759. )
  3760. /*++
  3761. Routine Description:
  3762. This routine will obtain settings from either
  3763. (1) DevNode settings (via DevicePropKey) or
  3764. (2) Class settings (via DeviceClassPropKey)
  3765. applying to PDO and all attached device objects
  3766. Properties set/ changed are:
  3767. * DeviceType - the I/O system type for the device object
  3768. * DeviceCharacteristics - the I/O system characteristic flags to be
  3769. set for the device object
  3770. * Exclusive - the device can only be accessed exclusively
  3771. * Security - security for the device
  3772. The routine will then use the DeviceType and DeviceCharacteristics specified
  3773. to determine whether a VPB should be allocated as well as to set default
  3774. security if none is specified in the registry.
  3775. Arguments:
  3776. PhysicalDeviceObject - the PDO we are to configure
  3777. DeviceClassPropKey - a handle to Control\<Class>\Properties protected key
  3778. DevicePropKey - a handle to Enum\<Instance> protected key
  3779. Return Value:
  3780. status
  3781. --*/
  3782. {
  3783. UNICODE_STRING valueName;
  3784. NTSTATUS status;
  3785. BOOLEAN deviceTypeSpec = FALSE;
  3786. BOOLEAN characteristicsSpec = FALSE;
  3787. BOOLEAN exclusiveSpec = FALSE;
  3788. BOOLEAN securityForce = FALSE;
  3789. UCHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  3790. SECURITY_INFORMATION securityInformation = 0;
  3791. PSECURITY_DESCRIPTOR securityDescriptor = NULL;
  3792. PACL allocatedAcl = NULL;
  3793. ULONG deviceType = 0;
  3794. ULONG characteristics = 0;
  3795. ULONG exclusive = 0;
  3796. ULONG prevCharacteristics = 0;
  3797. PDEVICE_OBJECT StackIterator = NULL;
  3798. PDEVICE_NODE deviceNode = NULL;
  3799. ASSERT(PhysicalDeviceObject);
  3800. deviceNode = PhysicalDeviceObject->DeviceObjectExtension->DeviceNode;
  3801. ASSERT(deviceNode);
  3802. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3803. "PipChangeDeviceObjectFromRegistryProperties: Modifying device stack for PDO: %08x\n",PhysicalDeviceObject));
  3804. //
  3805. // Iterate through all device objects to get our starting settings (OR everyone together)
  3806. // generally, a PDO should take on the characteristics of whoever is above the PDO, and not used in the equation
  3807. // the exception being if it's being used RAW
  3808. // we detect this by absense of service name, or it's the only Device Object.
  3809. //
  3810. StackIterator = PhysicalDeviceObject;
  3811. if (UsePdoCharacteristics || StackIterator->AttachedDevice == NULL) {
  3812. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3813. "PipChangeDeviceObjectFromRegistryProperties: Assuming PDO is being used RAW\n"));
  3814. } else {
  3815. StackIterator = StackIterator->AttachedDevice;
  3816. IopDbgPrint(( IOP_ENUMERATION_VERBOSE_LEVEL,
  3817. "PipChangeDeviceObjectFromRegistryProperties: Ignoring PDO's settings\n"));
  3818. }
  3819. //
  3820. // we can't propagate DO_EXCLUSIVE, since it happens to break some devices (eg, Serial)
  3821. // but we do propagage certain characteristics flags
  3822. //
  3823. for ( ; StackIterator != NULL; StackIterator = StackIterator->AttachedDevice) {
  3824. prevCharacteristics |= StackIterator->Characteristics;
  3825. }
  3826. //
  3827. // 1) Get Device type, DevicePropKey preferred over DeviceClassPropKey
  3828. //
  3829. PiWstrToUnicodeString(&valueName, REGSTR_VAL_DEVICE_TYPE);
  3830. deviceTypeSpec = PipGetRegistryDwordWithFallback(&valueName,DevicePropKey,DeviceClassPropKey,&deviceType);
  3831. PiWstrToUnicodeString(&valueName, REGSTR_VAL_DEVICE_CHARACTERISTICS);
  3832. characteristicsSpec = PipGetRegistryDwordWithFallback(&valueName,DevicePropKey,DeviceClassPropKey,&characteristics);
  3833. PiWstrToUnicodeString(&valueName, REGSTR_VAL_DEVICE_EXCLUSIVE);
  3834. exclusiveSpec = PipGetRegistryDwordWithFallback(&valueName,DevicePropKey,DeviceClassPropKey,&exclusive);
  3835. if (!characteristicsSpec) {
  3836. characteristics = 0;
  3837. }
  3838. characteristics = (characteristics | prevCharacteristics) & FILE_CHARACTERISTICS_PROPAGATED; // mask only applicable characteristics
  3839. PiWstrToUnicodeString(&valueName, REGSTR_VAL_DEVICE_SECURITY_DESCRIPTOR);
  3840. securityDescriptor = PipGetRegistrySecurityWithFallback(&valueName,DevicePropKey,DeviceClassPropKey);
  3841. if (securityDescriptor == NULL) {
  3842. //
  3843. // determine if we should create internal default
  3844. //
  3845. if (deviceTypeSpec) {
  3846. BOOLEAN hasName = (PhysicalDeviceObject->Flags & DO_DEVICE_HAS_NAME) ? TRUE : FALSE;
  3847. securityDescriptor = IopCreateDefaultDeviceSecurityDescriptor(
  3848. (DEVICE_TYPE)deviceType,
  3849. characteristics,
  3850. hasName,
  3851. &buffer[0],
  3852. &allocatedAcl,
  3853. &securityInformation
  3854. );
  3855. if (securityDescriptor) {
  3856. securityForce = TRUE; // forced default security descriptor
  3857. } else {
  3858. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  3859. "PipChangeDeviceObjectFromRegistryProperties: Was not able to get default security descriptor\n"));
  3860. }
  3861. }
  3862. } else {
  3863. //
  3864. // further process the security information we're given to set "securityInformation"
  3865. //
  3866. PSID sid;
  3867. PACL acl;
  3868. BOOLEAN present, tmp;
  3869. securityInformation = 0;
  3870. //
  3871. // See what information is in the captured descriptor so we can build
  3872. // up a securityInformation block to go with it.
  3873. //
  3874. status = RtlGetOwnerSecurityDescriptor(securityDescriptor, &sid, &tmp);
  3875. if (NT_SUCCESS(status) && (sid != NULL)) {
  3876. securityInformation |= OWNER_SECURITY_INFORMATION;
  3877. }
  3878. status = RtlGetGroupSecurityDescriptor(securityDescriptor, &sid, &tmp);
  3879. if (NT_SUCCESS(status) && (sid != NULL)) {
  3880. securityInformation |= GROUP_SECURITY_INFORMATION;
  3881. }
  3882. status = RtlGetSaclSecurityDescriptor(securityDescriptor,
  3883. &present,
  3884. &acl,
  3885. &tmp);
  3886. if (NT_SUCCESS(status) && (present)) {
  3887. securityInformation |= SACL_SECURITY_INFORMATION;
  3888. }
  3889. status = RtlGetDaclSecurityDescriptor(securityDescriptor,
  3890. &present,
  3891. &acl,
  3892. &tmp);
  3893. if (NT_SUCCESS(status) && (present)) {
  3894. securityInformation |= DACL_SECURITY_INFORMATION;
  3895. }
  3896. }
  3897. #if DBG
  3898. if (deviceTypeSpec == FALSE && characteristicsSpec == FALSE && exclusiveSpec == FALSE && securityDescriptor == NULL) {
  3899. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3900. "PipChangeDeviceObjectFromRegistryProperties: No property changes\n"));
  3901. } else {
  3902. if (deviceTypeSpec) {
  3903. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3904. "PipChangeDeviceObjectFromRegistryProperties: Overide DeviceType=%08x\n",
  3905. deviceType));
  3906. }
  3907. if (characteristicsSpec) {
  3908. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3909. "PipChangeDeviceObjectFromRegistryProperties: Overide DeviceCharacteristics=%08x\n",
  3910. characteristics));
  3911. }
  3912. if (exclusiveSpec) {
  3913. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3914. "PipChangeDeviceObjectFromRegistryProperties: Overide Exclusive=%d\n",(exclusive?1:0)));
  3915. }
  3916. if (securityForce) {
  3917. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3918. "PipChangeDeviceObjectFromRegistryProperties: Overide Security based on DeviceType & DeviceCharacteristics\n"));
  3919. }
  3920. if (securityDescriptor == NULL) {
  3921. IopDbgPrint(( IOP_ENUMERATION_INFO_LEVEL,
  3922. "PipChangeDeviceObjectFromRegistryProperties: Overide Security\n"));
  3923. }
  3924. }
  3925. #endif
  3926. //
  3927. // modify apropriate characteristics of PDO to be the same as those of rest of stack
  3928. // eg, PDO may be initialized as Raw-Capable Secure Open, but then be modified to be more lax
  3929. //
  3930. PhysicalDeviceObject->Characteristics = (PhysicalDeviceObject->Characteristics & ~FILE_CHARACTERISTICS_PROPAGATED) | characteristics;
  3931. ASSERT((PhysicalDeviceObject->Characteristics & FILE_CHARACTERISTICS_PROPAGATED) == characteristics); // sanity (checks bit bounds)
  3932. //
  3933. // exclusivity flag applies only to PDO
  3934. // if someone is relying on this flag, they better not name the FDO or any filter DO's
  3935. // otherwise the device can be opened via two handles.
  3936. //
  3937. if (exclusiveSpec && exclusive) {
  3938. PhysicalDeviceObject->Flags |= DO_EXCLUSIVE;
  3939. }
  3940. //
  3941. // iterate through rest of objects
  3942. // these flags were used to create characteristics & deviceType, so
  3943. // we will only end up setting flags, not clearing them
  3944. //
  3945. for (StackIterator = PhysicalDeviceObject->AttachedDevice;
  3946. StackIterator != NULL;
  3947. StackIterator = StackIterator->AttachedDevice) {
  3948. //
  3949. // modify characteristics (set only)
  3950. //
  3951. StackIterator->Characteristics |= characteristics;
  3952. ASSERT((StackIterator->Characteristics & FILE_CHARACTERISTICS_PROPAGATED) == characteristics); // sanity (checks we only needed to set)
  3953. }
  3954. if (deviceTypeSpec) {
  3955. //
  3956. // modify device type - PDO only
  3957. //
  3958. PhysicalDeviceObject->DeviceType = deviceType;
  3959. }
  3960. if (securityDescriptor != NULL) {
  3961. //
  3962. // modify security (applied to whole stack)
  3963. //
  3964. status = ObSetSecurityObjectByPointer(PhysicalDeviceObject,
  3965. securityInformation,
  3966. securityDescriptor);
  3967. if (NT_SUCCESS(status) == FALSE) {
  3968. IopDbgPrint(( IOP_ENUMERATION_ERROR_LEVEL,
  3969. "PipChangeDeviceObjectFromRegistryProperties: Set security failed (%08x)\n",status));
  3970. }
  3971. }
  3972. //
  3973. // cleanup
  3974. //
  3975. if ((securityDescriptor != NULL) && !securityForce) {
  3976. ExFreePool(securityDescriptor);
  3977. }
  3978. if (allocatedAcl) {
  3979. ExFreePool(allocatedAcl);
  3980. }
  3981. return STATUS_SUCCESS;
  3982. }
  3983. NTSTATUS
  3984. PipProcessDevNodeTree(
  3985. IN PDEVICE_NODE SubtreeRootDeviceNode,
  3986. IN BOOLEAN LoadDriver,
  3987. IN BOOLEAN ReallocateResources,
  3988. IN ENUM_TYPE EnumType,
  3989. IN BOOLEAN Synchronous,
  3990. IN BOOLEAN ProcessOnlyIntermediateStates,
  3991. IN PADD_CONTEXT AddContext,
  3992. IN PPI_DEVICE_REQUEST Request
  3993. )
  3994. /*--
  3995. Routine Description:
  3996. This function is called to handle state transitions related to starting
  3997. Devnodes. The basic sequence of operations is inheritted from the previous
  3998. implementation.
  3999. Resources freed
  4000. 1) Allocate resources to all candidates in the tree.
  4001. 2) Traverse the tree searching for a Devnodes ready to be started.
  4002. 3) Start the Devnode.
  4003. 4) Enumerate its children.
  4004. 5) Initialize all the children up to the point of resource allocation.
  4005. 6) Continue searching for DevNodes to start, if one is found return to
  4006. step 3.
  4007. 7) Once the entire tree is processed start over at step 1 until either
  4008. no children are enumerated or no resources are allocated.
  4009. A Devnode's resource requirements change
  4010. If the Devnode wasn't started then treat it the same as the Resources
  4011. freed case. If it was started then it would have been handled directly
  4012. by our caller.
  4013. Start Devnodes during boot
  4014. 1) Allocate resources to all candidates in the tree (based on
  4015. IopBootConfigsReserved).
  4016. 2) Traverse the tree searching for Devnodes ready to be started.
  4017. 3) Start the Devnode.
  4018. 4) Enumerate its children.
  4019. 5) Initialize all the children up to the point of resource allocation.
  4020. 6) Continue searching for DevNodes to start, if one is found return to
  4021. step 3.
  4022. Devnode newly created by user-mode.
  4023. 1) Reset Devnode to uninitialized state.
  4024. 2) Process Devnode to DeviceNodeDriversAdded state.
  4025. 3) Allocate resources to this Devnode.
  4026. 4) Start the Devnode.
  4027. 5) Enumerate its children.
  4028. 6) Initialize any children up to the point of resource allocation.
  4029. 7) Allocate resources to all candidates in the tree below the initial
  4030. Devnode.
  4031. 8) Traverse the tree starting at the initial Devnode searching for
  4032. a Devnode ready to be started.
  4033. 9) Start the Devnode.
  4034. 10) Enumerate its children.
  4035. 11) Initialize all the children up to the point of resource allocation.
  4036. 12) Start over at step 7 until either no children are enumerated or no
  4037. resources are allocated.
  4038. Device node newly created by IoReportDetectedDevice.
  4039. 1) Do post start IRP processing
  4040. 2) Continue from step 5 of the process for Devnodes newly created by
  4041. user-mode.
  4042. Reenumeration of a single Devnode (and processing of changes resulting from
  4043. that enumeration)
  4044. 1) Enumerate Devnode's children
  4045. 2) Initialize any children up to the point of resource allocation.
  4046. 3) Allocate resources to all candidates in the tree below the initial
  4047. Devnode.
  4048. 4) Traverse the tree starting at the initial Devnode searching for
  4049. a Devnode ready to be started.
  4050. 5) Start the Devnode.
  4051. 6) Enumerate its children.
  4052. 7) Initialize all the children up to the point of resource allocation.
  4053. 8) Start over at step 3 until either no children are enumerated or no
  4054. resources are allocated.
  4055. Reenumeration of a subtree.
  4056. Parameters:
  4057. SubtreeRootDeviceNode - Root of this tree walk. Depending on the
  4058. ProcessOnlyIntermediaryStates parameter, the
  4059. PDO for this devnode may need to be referenced.
  4060. LoadDriver - Indicates whether drivers should be loaded on this pass
  4061. (typically TRUE unless boot drivers aren't yet ready)
  4062. ReallocateResources - TRUE iff resource reallocation should be attempted.
  4063. EnumType - Specifies type of enumeration.
  4064. Synchronous - TRUE iff the operation should be performed synchronously
  4065. (always TRUE currently)
  4066. ProcessOnlyIntermediateStates - TRUE if only intermediary states should be
  4067. processed. If FALSE, the caller places
  4068. a reference on the PDO that this routine
  4069. will drop.
  4070. AddContext - Constraints for AddDevice
  4071. Request - Device action worker that triggered this processing.
  4072. Return Value:
  4073. NTSTATUS - Note: Always successful if ProcessOnlyIntermediaryStates is TRUE.
  4074. ++*/
  4075. {
  4076. PDEVICE_NODE currentNode;
  4077. PDEVICE_NODE startRoot;
  4078. PDEVICE_NODE enumeratedBus;
  4079. PDEVICE_NODE originalSubtree;
  4080. BOOLEAN processComplete;
  4081. BOOLEAN newDevice;
  4082. BOOLEAN rebalancePerformed;
  4083. NTSTATUS status;
  4084. ULONG reenumAttempts;
  4085. enum {
  4086. SameNode,
  4087. SiblingNode,
  4088. ChildNode
  4089. } nextNode;
  4090. PAGED_CODE();
  4091. originalSubtree = SubtreeRootDeviceNode;
  4092. //
  4093. // Collapse enum requests if appropriate.
  4094. //
  4095. if (Request && !Request->ReorderingBarrier &&
  4096. EnumType != EnumTypeShallow && !ProcessOnlyIntermediateStates) {
  4097. if (PiCollapseEnumRequests(&Request->ListEntry)) {
  4098. SubtreeRootDeviceNode = IopRootDeviceNode;
  4099. }
  4100. }
  4101. reenumAttempts = 0;
  4102. startRoot = NULL;
  4103. enumeratedBus = NULL;
  4104. processComplete = FALSE;
  4105. newDevice = TRUE;
  4106. while (newDevice) {
  4107. newDevice = FALSE;
  4108. if (!ProcessOnlyIntermediateStates) {
  4109. //
  4110. // Process the whole device tree to assign resources to those devices
  4111. // who have been successfully added to their drivers.
  4112. //
  4113. rebalancePerformed = FALSE;
  4114. newDevice = IopProcessAssignResources( SubtreeRootDeviceNode,
  4115. ReallocateResources,
  4116. &rebalancePerformed);
  4117. if (rebalancePerformed == TRUE) {
  4118. //
  4119. // Before we do any other processing, we need to restart
  4120. // all rebalance participants.
  4121. //
  4122. status = PipProcessDevNodeTree( IopRootDeviceNode,
  4123. LoadDriver,
  4124. FALSE,
  4125. EnumType,
  4126. Synchronous,
  4127. TRUE,
  4128. AddContext,
  4129. Request);
  4130. ASSERT(NT_SUCCESS(status));
  4131. }
  4132. }
  4133. if (processComplete && !newDevice) {
  4134. break;
  4135. }
  4136. //
  4137. // Process the entire subtree.
  4138. //
  4139. currentNode = SubtreeRootDeviceNode;
  4140. processComplete = FALSE;
  4141. while (!processComplete) {
  4142. //
  4143. // Dont process devnodes with problem.
  4144. //
  4145. status = STATUS_SUCCESS;
  4146. nextNode = SiblingNode;
  4147. if (!PipDoesDevNodeHaveProblem(currentNode)) {
  4148. switch (currentNode->State) {
  4149. case DeviceNodeUninitialized:
  4150. if (!ProcessOnlyIntermediateStates) {
  4151. if (currentNode->Parent == enumeratedBus && startRoot == NULL) {
  4152. startRoot = currentNode;
  4153. }
  4154. if((!ReallocateResources && EnumType == EnumTypeNone) || startRoot) {
  4155. status = PipProcessNewDeviceNode(currentNode);
  4156. if (NT_SUCCESS(status)) {
  4157. nextNode = SameNode;
  4158. }
  4159. }
  4160. }
  4161. break;
  4162. case DeviceNodeInitialized:
  4163. if (!ProcessOnlyIntermediateStates) {
  4164. if (!ReallocateResources || startRoot) {
  4165. status = PipCallDriverAddDevice( currentNode,
  4166. LoadDriver,
  4167. AddContext);
  4168. if (NT_SUCCESS(status)) {
  4169. nextNode = SameNode;
  4170. newDevice = TRUE;
  4171. } else {
  4172. //
  4173. // ISSUE - 2000/08/31 - ADRIAO: Not draining
  4174. // We should really drain the removes here.
  4175. // We don't because we cannot distinguish
  4176. // AddDevice's that fail due to non-present
  4177. // boot drivers from AddDevice's that fail due
  4178. // to a problem requiring remove.
  4179. //
  4180. //status = STATUS_PNP_RESTART_ENUMERATION;
  4181. }
  4182. }
  4183. }
  4184. break;
  4185. case DeviceNodeResourcesAssigned:
  4186. if (!ProcessOnlyIntermediateStates) {
  4187. if (ReallocateResources && startRoot == NULL) {
  4188. //
  4189. // If we assigned resources to this previously
  4190. // conflicting devnode, remember him so that we will
  4191. // initial processing on devices in that subtree.
  4192. //
  4193. startRoot = currentNode;
  4194. }
  4195. status = PipProcessStartPhase1(currentNode, Synchronous);
  4196. if (NT_SUCCESS(status)) {
  4197. nextNode = SameNode;
  4198. } else {
  4199. //
  4200. // Cleanup is currently handled in the
  4201. // DeviceNodeStartCompletion phase, thus
  4202. // PipProcessStartPhase1 should always succeed.
  4203. //
  4204. ASSERT(0);
  4205. nextNode = SiblingNode;
  4206. }
  4207. } else {
  4208. nextNode = SiblingNode;
  4209. }
  4210. break;
  4211. case DeviceNodeStartCompletion:
  4212. status = PipProcessStartPhase2(currentNode);
  4213. if (NT_SUCCESS(status)) {
  4214. nextNode = SameNode;
  4215. } else {
  4216. status = STATUS_PNP_RESTART_ENUMERATION;
  4217. ASSERT(currentNode->State != DeviceNodeStartCompletion);
  4218. }
  4219. break;
  4220. case DeviceNodeStartPostWork:
  4221. status = PipProcessStartPhase3(currentNode);
  4222. if (NT_SUCCESS(status)) {
  4223. nextNode = SameNode;
  4224. } else {
  4225. status = STATUS_PNP_RESTART_ENUMERATION;
  4226. ASSERT(!ProcessOnlyIntermediateStates);
  4227. }
  4228. break;
  4229. case DeviceNodeStarted:
  4230. nextNode = ChildNode;
  4231. if (!ProcessOnlyIntermediateStates) {
  4232. if ((currentNode->Flags & DNF_REENUMERATE)) {
  4233. status = PipEnumerateDevice(currentNode, Synchronous);
  4234. if (NT_SUCCESS(status)) {
  4235. //
  4236. // Remember the bus we just enumerated.
  4237. //
  4238. enumeratedBus = currentNode;
  4239. nextNode = SameNode;
  4240. } else if (status == STATUS_PENDING) {
  4241. nextNode = SiblingNode;
  4242. }
  4243. }
  4244. }
  4245. break;
  4246. case DeviceNodeEnumerateCompletion:
  4247. status = PipEnumerateCompleted(currentNode);
  4248. nextNode = ChildNode;
  4249. break;
  4250. case DeviceNodeStopped:
  4251. status = PipProcessRestartPhase1(currentNode, Synchronous);
  4252. if (NT_SUCCESS(status)) {
  4253. nextNode = SameNode;
  4254. } else {
  4255. //
  4256. // Cleanup is currently handled in the
  4257. // DeviceNodeStartCompletion phase, thus
  4258. // PipProcessRestartPhase1 should always succeed.
  4259. //
  4260. ASSERT(0);
  4261. nextNode = SiblingNode;
  4262. }
  4263. break;
  4264. case DeviceNodeRestartCompletion:
  4265. status = PipProcessRestartPhase2(currentNode);
  4266. if (NT_SUCCESS(status)) {
  4267. nextNode = SameNode;
  4268. } else {
  4269. status = STATUS_PNP_RESTART_ENUMERATION;
  4270. ASSERT(currentNode->State != DeviceNodeRestartCompletion);
  4271. }
  4272. break;
  4273. case DeviceNodeDriversAdded:
  4274. case DeviceNodeAwaitingQueuedDeletion:
  4275. case DeviceNodeAwaitingQueuedRemoval:
  4276. case DeviceNodeRemovePendingCloses:
  4277. case DeviceNodeRemoved:
  4278. nextNode = SiblingNode;
  4279. break;
  4280. case DeviceNodeStartPending:
  4281. case DeviceNodeEnumeratePending:
  4282. case DeviceNodeQueryStopped:
  4283. case DeviceNodeQueryRemoved:
  4284. case DeviceNodeDeletePendingCloses:
  4285. case DeviceNodeDeleted:
  4286. case DeviceNodeUnspecified:
  4287. default:
  4288. ASSERT(0);
  4289. nextNode = SiblingNode;
  4290. break;
  4291. }
  4292. }
  4293. //
  4294. // If we need to wait for the queued removals to complete before
  4295. // we progress,we need to do the following:
  4296. // 1. capture the instance paths for all the parents of the current
  4297. // node upto the subtree root where we started
  4298. // 2. drop the reference to the subtree root allowing it to be
  4299. // deleted (if required)
  4300. // 3. drop the tree lock
  4301. // 4. wait for the removal queue to empty
  4302. // 5. re-acquire the tree lock
  4303. // 6. resume processing
  4304. //
  4305. if (status == STATUS_PNP_RESTART_ENUMERATION &&
  4306. !ProcessOnlyIntermediateStates) {
  4307. PDEVICE_OBJECT entryDeviceObject;
  4308. UNICODE_STRING unicodeName;
  4309. PWCHAR devnodeList;
  4310. PWCHAR currentEntry;
  4311. PWCHAR rootEntry;
  4312. WCHAR buffer[MAX_INSTANCE_PATH_LENGTH];
  4313. status = PipProcessDevNodeTree( IopRootDeviceNode,
  4314. LoadDriver,
  4315. ReallocateResources,
  4316. EnumType,
  4317. Synchronous,
  4318. TRUE,
  4319. AddContext,
  4320. Request);
  4321. ASSERT(NT_SUCCESS(status));
  4322. PipAssertDevnodesInConsistentState();
  4323. if (++reenumAttempts < MAX_REENUMERATION_ATTEMPTS) {
  4324. devnodeList = ExAllocatePool( PagedPool,
  4325. (currentNode->Level + 1) * MAX_INSTANCE_PATH_LENGTH * sizeof(WCHAR));
  4326. if (devnodeList) {
  4327. currentEntry = devnodeList;
  4328. for ( ; ; ) {
  4329. rootEntry = currentEntry;
  4330. ASSERT(currentNode->InstancePath.Length < MAX_INSTANCE_PATH_LENGTH);
  4331. memcpy( currentEntry,
  4332. currentNode->InstancePath.Buffer,
  4333. currentNode->InstancePath.Length );
  4334. currentEntry += currentNode->InstancePath.Length / sizeof(WCHAR);
  4335. *currentEntry++ = UNICODE_NULL;
  4336. if (currentNode == SubtreeRootDeviceNode) {
  4337. break;
  4338. }
  4339. currentNode = currentNode->Parent;
  4340. }
  4341. } else {
  4342. ASSERT(SubtreeRootDeviceNode->InstancePath.Length < MAX_INSTANCE_PATH_LENGTH);
  4343. memcpy( buffer,
  4344. SubtreeRootDeviceNode->InstancePath.Buffer,
  4345. SubtreeRootDeviceNode->InstancePath.Length );
  4346. rootEntry = buffer;
  4347. }
  4348. } else {
  4349. rootEntry = NULL;
  4350. devnodeList = NULL;
  4351. }
  4352. ObDereferenceObject(originalSubtree->PhysicalDeviceObject);
  4353. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  4354. PpSynchronizeDeviceEventQueue();
  4355. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  4356. if (reenumAttempts >= MAX_REENUMERATION_ATTEMPTS) {
  4357. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  4358. "Restarted reenumeration %d times, giving up!\n", reenumAttempts));
  4359. ASSERT(reenumAttempts < MAX_REENUMERATION_ATTEMPTS);
  4360. return STATUS_UNSUCCESSFUL;
  4361. }
  4362. RtlInitUnicodeString(&unicodeName, rootEntry);
  4363. entryDeviceObject = IopDeviceObjectFromDeviceInstance(&unicodeName);
  4364. if (entryDeviceObject == NULL) {
  4365. if (devnodeList) {
  4366. ExFreePool(devnodeList);
  4367. }
  4368. return STATUS_UNSUCCESSFUL;
  4369. }
  4370. SubtreeRootDeviceNode = entryDeviceObject->DeviceObjectExtension->DeviceNode;
  4371. originalSubtree = currentNode = SubtreeRootDeviceNode;
  4372. //
  4373. // Try to start processing where we left off.
  4374. //
  4375. if (devnodeList) {
  4376. for(currentEntry = devnodeList;
  4377. currentEntry != rootEntry;
  4378. currentEntry += ((unicodeName.Length / sizeof(WCHAR))+1)) {
  4379. RtlInitUnicodeString(&unicodeName, currentEntry);
  4380. entryDeviceObject = IopDeviceObjectFromDeviceInstance(&unicodeName);
  4381. if (entryDeviceObject != NULL) {
  4382. currentNode = entryDeviceObject->DeviceObjectExtension->DeviceNode;
  4383. ObDereferenceObject(entryDeviceObject);
  4384. break;
  4385. }
  4386. }
  4387. ExFreePool(devnodeList);
  4388. }
  4389. nextNode = SameNode;
  4390. }
  4391. //
  4392. // This code advances the current node based on nextNode.
  4393. //
  4394. switch (nextNode) {
  4395. case SameNode:
  4396. break;
  4397. case ChildNode:
  4398. if (currentNode->Child != NULL) {
  4399. currentNode = currentNode->Child;
  4400. break;
  4401. }
  4402. // FALLTHRU - No more children so advance to sibling
  4403. case SiblingNode:
  4404. while (currentNode != SubtreeRootDeviceNode) {
  4405. if (currentNode == startRoot) {
  4406. //
  4407. // We completed processing of the new subtree.
  4408. //
  4409. if (EnumType != EnumTypeNone) {
  4410. enumeratedBus = startRoot->Parent;
  4411. }
  4412. startRoot = NULL;
  4413. } else if (currentNode == enumeratedBus) {
  4414. enumeratedBus = enumeratedBus->Parent;
  4415. }
  4416. if (currentNode->Sibling != NULL) {
  4417. currentNode = currentNode->Sibling;
  4418. break;
  4419. }
  4420. if (currentNode->Parent != NULL) {
  4421. currentNode = currentNode->Parent;
  4422. }
  4423. }
  4424. if (currentNode == SubtreeRootDeviceNode) {
  4425. processComplete = TRUE;
  4426. }
  4427. break;
  4428. }
  4429. }
  4430. }
  4431. if (!ProcessOnlyIntermediateStates) {
  4432. PipAssertDevnodesInConsistentState();
  4433. ObDereferenceObject(originalSubtree->PhysicalDeviceObject);
  4434. }
  4435. return STATUS_SUCCESS;
  4436. }
  4437. NTSTATUS
  4438. PipProcessStartPhase1(
  4439. IN PDEVICE_NODE DeviceNode,
  4440. IN BOOLEAN Synchronous
  4441. )
  4442. {
  4443. PDEVICE_OBJECT deviceObject;
  4444. NTSTATUS status = STATUS_SUCCESS;
  4445. PNP_VETO_TYPE vetoType;
  4446. PAGED_CODE();
  4447. ASSERT(DeviceNode->State == DeviceNodeResourcesAssigned);
  4448. deviceObject = DeviceNode->PhysicalDeviceObject;
  4449. IopUncacheInterfaceInformation(deviceObject);
  4450. if (DeviceNode->DockInfo.DockStatus != DOCK_NOTDOCKDEVICE) {
  4451. //
  4452. // This is a dock so we a little bit of work before starting it.
  4453. // Take the profile change semaphore. We do this whenever a dock
  4454. // is in our list, even if no query is going to occur.
  4455. //
  4456. PpProfileBeginHardwareProfileTransition(FALSE);
  4457. //
  4458. // Tell the profile code what dock device object may be bringing the
  4459. // new hardware profile online.
  4460. //
  4461. PpProfileIncludeInHardwareProfileTransition(DeviceNode, DOCK_ARRIVING);
  4462. //
  4463. // Ask everyone if this is really a good idea right now.
  4464. //
  4465. status = PpProfileQueryHardwareProfileChange(
  4466. FALSE,
  4467. PROFILE_PERHAPS_IN_PNPEVENT,
  4468. &vetoType,
  4469. NULL
  4470. );
  4471. }
  4472. if (NT_SUCCESS(status)) {
  4473. status = IopStartDevice(deviceObject);
  4474. }
  4475. //
  4476. // Failure cleanup is handled in PipProcessStartPhase2, thus we write away
  4477. // the failure code and always succeed.
  4478. //
  4479. PipSetDevNodeState(DeviceNode, DeviceNodeStartCompletion, NULL);
  4480. DeviceNode->CompletionStatus = status;
  4481. return STATUS_SUCCESS;
  4482. }
  4483. NTSTATUS
  4484. PipProcessStartPhase2(
  4485. IN PDEVICE_NODE DeviceNode
  4486. )
  4487. {
  4488. ULONG problem = CM_PROB_FAILED_START;
  4489. NTSTATUS status;
  4490. PAGED_CODE();
  4491. status = DeviceNode->CompletionStatus;
  4492. if (DeviceNode->DockInfo.DockStatus != DOCK_NOTDOCKDEVICE) {
  4493. if (NT_SUCCESS(status)) {
  4494. //
  4495. // Commit the current Hardware Profile as necessary.
  4496. //
  4497. PpProfileCommitTransitioningDock(DeviceNode, DOCK_ARRIVING);
  4498. } else {
  4499. PpProfileCancelHardwareProfileTransition();
  4500. }
  4501. }
  4502. if (!NT_SUCCESS(status)) {
  4503. SAVE_FAILURE_INFO(DeviceNode, DeviceNode->CompletionStatus);
  4504. //
  4505. // Handle certain problems determined by the status code
  4506. //
  4507. switch(status) {
  4508. case STATUS_PNP_REBOOT_REQUIRED:
  4509. problem = CM_PROB_NEED_RESTART;
  4510. break;
  4511. default:
  4512. problem = CM_PROB_FAILED_START;
  4513. break;
  4514. }
  4515. PipRequestDeviceRemoval(DeviceNode, FALSE, problem);
  4516. if (DeviceNode->DockInfo.DockStatus != DOCK_NOTDOCKDEVICE) {
  4517. ASSERT(DeviceNode->DockInfo.DockStatus == DOCK_QUIESCENT);
  4518. IoRequestDeviceEject(DeviceNode->PhysicalDeviceObject);
  4519. }
  4520. } else {
  4521. IopDoDeferredSetInterfaceState(DeviceNode);
  4522. //
  4523. // Reserve legacy resources for the legacy interface and bus number.
  4524. //
  4525. if (!IopBootConfigsReserved && DeviceNode->InterfaceType != InterfaceTypeUndefined) {
  4526. //
  4527. // ISA = EISA.
  4528. //
  4529. if (DeviceNode->InterfaceType == Isa) {
  4530. IopAllocateLegacyBootResources(Eisa, DeviceNode->BusNumber);
  4531. }
  4532. IopAllocateLegacyBootResources(DeviceNode->InterfaceType, DeviceNode->BusNumber);
  4533. }
  4534. //
  4535. // This code path currently doesn't expect any of the above functions
  4536. // to fail. If they do, a removal should be queued and failure should
  4537. // be returned.
  4538. //
  4539. ASSERT(DeviceNode->State == DeviceNodeStartCompletion);
  4540. PipSetDevNodeState(DeviceNode, DeviceNodeStartPostWork, NULL);
  4541. }
  4542. return status;
  4543. }
  4544. NTSTATUS
  4545. PipProcessStartPhase3(
  4546. IN PDEVICE_NODE DeviceNode
  4547. )
  4548. {
  4549. NTSTATUS status;
  4550. PDEVICE_OBJECT deviceObject;
  4551. HANDLE handle;
  4552. PWCHAR ids;
  4553. UNICODE_STRING unicodeName;
  4554. PAGED_CODE();
  4555. deviceObject = DeviceNode->PhysicalDeviceObject;
  4556. if (!(DeviceNode->Flags & DNF_IDS_QUERIED)) {
  4557. PWCHAR compatibleIds, hwIds;
  4558. ULONG hwIdLength, compatibleIdLength;
  4559. //
  4560. // If the DNF_NEED_QUERY_IDS is set, the device is a reported device.
  4561. // It should already be started. We need to enumerate its children and ask
  4562. // the HardwareId and the Compatible ids of the detected device.
  4563. //
  4564. status = IopDeviceObjectToDeviceInstance (deviceObject,
  4565. &handle,
  4566. KEY_READ
  4567. );
  4568. if (NT_SUCCESS(status)) {
  4569. PpQueryHardwareIDs(
  4570. DeviceNode,
  4571. &hwIds,
  4572. &hwIdLength);
  4573. PpQueryCompatibleIDs(
  4574. DeviceNode,
  4575. &compatibleIds,
  4576. &compatibleIdLength);
  4577. if (hwIds || compatibleIds) {
  4578. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  4579. PKEY_VALUE_PARTIAL_INFORMATION keyInfo =
  4580. (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4581. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  4582. ULONG flags, length;
  4583. PWCHAR oldID, newID;
  4584. PiLockPnpRegistry(FALSE);
  4585. //
  4586. // Read the current config flags.
  4587. //
  4588. PiWstrToUnicodeString (&unicodeName, REGSTR_VALUE_CONFIG_FLAGS);
  4589. status = ZwQueryValueKey(handle,
  4590. &unicodeName,
  4591. KeyValuePartialInformation,
  4592. keyInfo,
  4593. sizeof(buffer),
  4594. &length
  4595. );
  4596. if (NT_SUCCESS(status) && (keyInfo->Type == REG_DWORD)) {
  4597. flags = *(PULONG)keyInfo->Data;
  4598. } else {
  4599. flags = 0;
  4600. }
  4601. if (hwIds) {
  4602. if (!(flags & CONFIGFLAG_FINISH_INSTALL)) {
  4603. status = IopGetRegistryValue (handle,
  4604. REGSTR_VALUE_HARDWAREID,
  4605. &keyValueInformation);
  4606. if (NT_SUCCESS(status)) {
  4607. if (keyValueInformation->Type == REG_MULTI_SZ) {
  4608. ids = (PWCHAR)KEY_VALUE_DATA(keyValueInformation);
  4609. //
  4610. // Check if the old and new IDs are identical.
  4611. //
  4612. for (oldID = ids, newID = hwIds;
  4613. *oldID && *newID;
  4614. oldID += wcslen(oldID) + 1, newID += wcslen(newID) + 1) {
  4615. if (_wcsicmp(oldID, newID)) {
  4616. break;
  4617. }
  4618. }
  4619. if (*oldID || *newID) {
  4620. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  4621. "IopStartAndEnumerateDevice: Hardware ID has changed for %wZ\n", &DeviceNode->InstancePath));
  4622. flags |= CONFIGFLAG_FINISH_INSTALL;
  4623. }
  4624. }
  4625. ExFreePool(keyValueInformation);
  4626. }
  4627. }
  4628. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_HARDWAREID);
  4629. ZwSetValueKey(handle,
  4630. &unicodeName,
  4631. TITLE_INDEX_VALUE,
  4632. REG_MULTI_SZ,
  4633. hwIds,
  4634. hwIdLength);
  4635. ExFreePool(hwIds);
  4636. }
  4637. //
  4638. // create CompatibleId value name. It is a MULTI_SZ,
  4639. //
  4640. if (compatibleIds) {
  4641. if (!(flags & CONFIGFLAG_FINISH_INSTALL)) {
  4642. status = IopGetRegistryValue (handle,
  4643. REGSTR_VALUE_COMPATIBLEIDS,
  4644. &keyValueInformation);
  4645. if (NT_SUCCESS(status)) {
  4646. if (keyValueInformation->Type == REG_MULTI_SZ) {
  4647. ids = (PWCHAR)KEY_VALUE_DATA(keyValueInformation);
  4648. //
  4649. // Check if the old and new IDs are identical.
  4650. //
  4651. for (oldID = ids, newID = compatibleIds;
  4652. *oldID && *newID;
  4653. oldID += wcslen(oldID) + 1, newID += wcslen(newID) + 1) {
  4654. if (_wcsicmp(oldID, newID)) {
  4655. break;
  4656. }
  4657. }
  4658. if (*oldID || *newID) {
  4659. IopDbgPrint(( IOP_ENUMERATION_WARNING_LEVEL,
  4660. "IopStartAndEnumerateDevice: Compatible ID has changed for %wZ\n", &DeviceNode->InstancePath));
  4661. flags |= CONFIGFLAG_FINISH_INSTALL;
  4662. }
  4663. }
  4664. ExFreePool(keyValueInformation);
  4665. }
  4666. }
  4667. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_COMPATIBLEIDS);
  4668. ZwSetValueKey(handle,
  4669. &unicodeName,
  4670. TITLE_INDEX_VALUE,
  4671. REG_MULTI_SZ,
  4672. compatibleIds,
  4673. compatibleIdLength);
  4674. ExFreePool(compatibleIds);
  4675. }
  4676. //
  4677. // If we set the finish install flag, then write out the flags.
  4678. //
  4679. if (flags & CONFIGFLAG_FINISH_INSTALL) {
  4680. PiWstrToUnicodeString (&unicodeName, REGSTR_VALUE_CONFIG_FLAGS);
  4681. ZwSetValueKey(handle,
  4682. &unicodeName,
  4683. TITLE_INDEX_VALUE,
  4684. REG_DWORD,
  4685. &flags,
  4686. sizeof(flags)
  4687. );
  4688. }
  4689. PiUnlockPnpRegistry();
  4690. }
  4691. ZwClose(handle);
  4692. DeviceNode->Flags |= DNF_IDS_QUERIED;
  4693. }
  4694. }
  4695. if (PipIsDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA)) {
  4696. return STATUS_UNSUCCESSFUL;
  4697. }
  4698. DeviceNode->Flags |= DNF_REENUMERATE;
  4699. IopQueryAndSaveDeviceNodeCapabilities(DeviceNode);
  4700. status = PiProcessQueryDeviceState(deviceObject);
  4701. //
  4702. // The device has been started, attempt to enumerate the device.
  4703. //
  4704. PpSetPlugPlayEvent( &GUID_DEVICE_ARRIVAL,
  4705. DeviceNode->PhysicalDeviceObject);
  4706. if (!NT_SUCCESS(status)) {
  4707. return status;
  4708. }
  4709. PpvUtilTestStartedPdoStack(deviceObject);
  4710. PipSetDevNodeState( DeviceNode, DeviceNodeStarted, NULL );
  4711. return STATUS_SUCCESS;
  4712. }
  4713. NTSTATUS
  4714. PiProcessQueryDeviceState(
  4715. IN PDEVICE_OBJECT DeviceObject
  4716. )
  4717. {
  4718. PDEVICE_NODE deviceNode;
  4719. PNP_DEVICE_STATE deviceState;
  4720. NTSTATUS status;
  4721. ULONG problem;
  4722. PAGED_CODE();
  4723. //
  4724. // If the device was removed or surprised removed while the work
  4725. // item was queued then ignore it.
  4726. //
  4727. status = IopQueryDeviceState(DeviceObject, &deviceState);
  4728. //
  4729. // Now perform the appropriate action based on the returned state
  4730. //
  4731. if (!NT_SUCCESS(status)) {
  4732. return STATUS_SUCCESS;
  4733. }
  4734. deviceNode = DeviceObject->DeviceObjectExtension->DeviceNode;
  4735. if (deviceState & PNP_DEVICE_DONT_DISPLAY_IN_UI) {
  4736. deviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
  4737. } else {
  4738. deviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
  4739. }
  4740. if (deviceState & PNP_DEVICE_NOT_DISABLEABLE) {
  4741. if ((deviceNode->UserFlags & DNUF_NOT_DISABLEABLE)==0) {
  4742. //
  4743. // this node itself is not disableable
  4744. //
  4745. deviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
  4746. //
  4747. // propagate up tree
  4748. //
  4749. IopIncDisableableDepends(deviceNode);
  4750. }
  4751. } else {
  4752. if (deviceNode->UserFlags & DNUF_NOT_DISABLEABLE) {
  4753. //
  4754. // this node itself is now disableable
  4755. //
  4756. //
  4757. // check tree
  4758. //
  4759. IopDecDisableableDepends(deviceNode);
  4760. deviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
  4761. }
  4762. }
  4763. //
  4764. // everything here can only be turned on (state set)
  4765. //
  4766. if (deviceState & (PNP_DEVICE_DISABLED | PNP_DEVICE_REMOVED)) {
  4767. problem = (deviceState & PNP_DEVICE_DISABLED) ?
  4768. CM_PROB_HARDWARE_DISABLED : CM_PROB_DEVICE_NOT_THERE;
  4769. PipRequestDeviceRemoval(deviceNode, FALSE, problem);
  4770. status = STATUS_UNSUCCESSFUL;
  4771. } else if (deviceState & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) {
  4772. if (deviceState & PNP_DEVICE_FAILED) {
  4773. IopResourceRequirementsChanged(DeviceObject, TRUE);
  4774. } else {
  4775. IopResourceRequirementsChanged(DeviceObject, FALSE);
  4776. }
  4777. } else if (deviceState & PNP_DEVICE_FAILED) {
  4778. PipRequestDeviceRemoval(deviceNode, FALSE, CM_PROB_FAILED_POST_START);
  4779. status = STATUS_UNSUCCESSFUL;
  4780. }
  4781. return status;
  4782. }
  4783. NTSTATUS
  4784. PipProcessRestartPhase1(
  4785. IN PDEVICE_NODE DeviceNode,
  4786. IN BOOLEAN Synchronous
  4787. )
  4788. {
  4789. NTSTATUS status;
  4790. PAGED_CODE();
  4791. ASSERT(DeviceNode->State == DeviceNodeStopped);
  4792. status = IopStartDevice(DeviceNode->PhysicalDeviceObject);
  4793. //
  4794. // Failure cleanup is handled in PipProcessRestartPhase2, thus we write away
  4795. // the failure code and always succeed.
  4796. //
  4797. DeviceNode->CompletionStatus = status;
  4798. PipSetDevNodeState(DeviceNode, DeviceNodeRestartCompletion, NULL);
  4799. return STATUS_SUCCESS;
  4800. }
  4801. NTSTATUS
  4802. PipProcessRestartPhase2(
  4803. IN PDEVICE_NODE DeviceNode
  4804. )
  4805. {
  4806. ULONG problem;
  4807. NTSTATUS status;
  4808. PAGED_CODE();
  4809. status = DeviceNode->CompletionStatus;
  4810. if (!NT_SUCCESS(status)) {
  4811. SAVE_FAILURE_INFO(DeviceNode, status);
  4812. //
  4813. // Handle certain problems determined by the status code
  4814. //
  4815. switch (status) {
  4816. case STATUS_PNP_REBOOT_REQUIRED:
  4817. problem = CM_PROB_NEED_RESTART;
  4818. break;
  4819. default:
  4820. problem = CM_PROB_FAILED_START;
  4821. break;
  4822. }
  4823. PipRequestDeviceRemoval(DeviceNode, FALSE, problem);
  4824. if (DeviceNode->DockInfo.DockStatus != DOCK_NOTDOCKDEVICE) {
  4825. ASSERT(DeviceNode->DockInfo.DockStatus == DOCK_QUIESCENT);
  4826. IoRequestDeviceEject(DeviceNode->PhysicalDeviceObject);
  4827. }
  4828. } else {
  4829. PipSetDevNodeState(DeviceNode, DeviceNodeStarted, NULL);
  4830. }
  4831. return status;
  4832. }
  4833. NTSTATUS
  4834. PiProcessHaltDevice(
  4835. IN PPI_DEVICE_REQUEST Request
  4836. )
  4837. /*++
  4838. Routine Description:
  4839. This routine simulates a surprise removal scenario on the passed in device
  4840. node.
  4841. Arguments:
  4842. DeviceNode - DeviceNode to halt
  4843. Flags - PNP_HALT_ALLOW_NONDISABLEABLE_DEVICES - Allows halt on nodes
  4844. marked non-disableable.
  4845. Return Value:
  4846. NTSTATUS.
  4847. --*/
  4848. {
  4849. ULONG flags = (ULONG)Request->RequestArgument;
  4850. PDEVICE_NODE deviceNode;
  4851. PAGED_CODE();
  4852. ASSERT(Request->DeviceObject != NULL);
  4853. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  4854. if (PipIsDevNodeDeleted(deviceNode)) {
  4855. return STATUS_DELETE_PENDING;
  4856. }
  4857. if (flags & (~PNP_HALT_ALLOW_NONDISABLEABLE_DEVICES)) {
  4858. return STATUS_INVALID_PARAMETER_2;
  4859. }
  4860. if (deviceNode->Flags & (DNF_MADEUP | DNF_LEGACY_DRIVER)) {
  4861. //
  4862. // Sending surprise removes to legacy devnodes would be a bad idea.
  4863. // Today, if a legacy devnode fails it is manually taken to the removed
  4864. // state rather than being put through the engine.
  4865. //
  4866. return STATUS_INVALID_DEVICE_REQUEST;
  4867. }
  4868. if ((!(deviceNode->Flags & PNP_HALT_ALLOW_NONDISABLEABLE_DEVICES)) &&
  4869. deviceNode->DisableableDepends) {
  4870. return STATUS_INVALID_DEVICE_REQUEST;
  4871. }
  4872. if (deviceNode->State != DeviceNodeStarted) {
  4873. return STATUS_INVALID_DEVICE_STATE;
  4874. }
  4875. PipRequestDeviceRemoval(deviceNode, FALSE, CM_PROB_HALTED);
  4876. return STATUS_SUCCESS;
  4877. }
  4878. VOID
  4879. PpResetProblemDevices(
  4880. IN PDEVICE_NODE DeviceNode,
  4881. IN ULONG Problem
  4882. )
  4883. /*++
  4884. Routine Description:
  4885. This routine resets all non-configured devices *beneath* the passed in
  4886. devnode so a subsequent enum will kick off new hardware installation
  4887. on them.
  4888. Arguments:
  4889. DeviceNode - DeviceNode to halt
  4890. Return Value:
  4891. None.
  4892. --*/
  4893. {
  4894. PAGED_CODE();
  4895. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  4896. PipForDeviceNodeSubtree(
  4897. DeviceNode,
  4898. PiResetProblemDevicesWorker,
  4899. (PVOID)(ULONG_PTR)Problem
  4900. );
  4901. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  4902. }
  4903. NTSTATUS
  4904. PiResetProblemDevicesWorker(
  4905. IN PDEVICE_NODE DeviceNode,
  4906. IN PVOID Context
  4907. )
  4908. /*++
  4909. Routine Description:
  4910. This is a worker routine for PiResetNonConfiguredDevices. If the devnode
  4911. has the problem CM_PROB_NOT_CONFIGURED, the devnode is reset so a
  4912. subsequent reenumeration will bring it back.
  4913. Arguments:
  4914. DeviceNode - Device to reset if it has the correct problem.
  4915. Context - Not used.
  4916. Return Value:
  4917. NTSTATUS, non-successful statuses terminate the tree walk.
  4918. --*/
  4919. {
  4920. PAGED_CODE();
  4921. if (PipIsDevNodeProblem(DeviceNode, (ULONG)(ULONG_PTR)Context)) {
  4922. //
  4923. // We only need to queue it as an enumeration will drop behind it soon
  4924. // afterwards...
  4925. //
  4926. PipRequestDeviceAction(
  4927. DeviceNode->PhysicalDeviceObject,
  4928. ClearDeviceProblem,
  4929. TRUE,
  4930. 0,
  4931. NULL,
  4932. NULL
  4933. );
  4934. }
  4935. return STATUS_SUCCESS;
  4936. }
  4937. VOID
  4938. PiMarkDeviceTreeForReenumeration(
  4939. IN PDEVICE_NODE DeviceNode,
  4940. IN BOOLEAN Subtree
  4941. )
  4942. /*++
  4943. Routine Description:
  4944. This routine marks the devnode for reenumeration.
  4945. Arguments:
  4946. DeviceNode - DeviceNode to mark for re-enumeration
  4947. Subtree - If TRUE, the entire subtree is marked for re-enumeration.
  4948. Return Value:
  4949. None.
  4950. --*/
  4951. {
  4952. PAGED_CODE();
  4953. PPDEVNODE_ASSERT_LOCK_HELD(PPL_TREEOP_ALLOW_READS);
  4954. PiMarkDeviceTreeForReenumerationWorker(DeviceNode, NULL);
  4955. if (Subtree) {
  4956. PipForDeviceNodeSubtree(
  4957. DeviceNode,
  4958. PiMarkDeviceTreeForReenumerationWorker,
  4959. NULL
  4960. );
  4961. }
  4962. }
  4963. NTSTATUS
  4964. PiMarkDeviceTreeForReenumerationWorker(
  4965. IN PDEVICE_NODE DeviceNode,
  4966. IN PVOID Context
  4967. )
  4968. /*++
  4969. Routine Description:
  4970. This is a worker routine for PiMarkDeviceTreeForReenumeration. It marks all
  4971. started devnodes with DNF_REENUMERATE so that the subsequent tree
  4972. processing will reenumerate the device.
  4973. Arguments:
  4974. DeviceNode - Device to mark if started.
  4975. Context - Not used.
  4976. Return Value:
  4977. NTSTATUS, non-successful statuses terminate the tree walk.
  4978. --*/
  4979. {
  4980. PAGED_CODE();
  4981. UNREFERENCED_PARAMETER(Context);
  4982. if (DeviceNode->State == DeviceNodeStarted) {
  4983. if (DeviceNode->Flags & DNF_REENUMERATE) {
  4984. IopDbgPrint((IOP_ENUMERATION_INFO_LEVEL,
  4985. "PiMarkDeviceTreeForReenumerationWorker: Collapsed enum request on %wZ\n", &DeviceNode->InstancePath));
  4986. } else {
  4987. IopDbgPrint((IOP_ENUMERATION_VERBOSE_LEVEL,
  4988. "PiMarkDeviceTreeForReenumerationWorker: Reenumerating %wZ\n", &DeviceNode->InstancePath));
  4989. }
  4990. DeviceNode->Flags |= DNF_REENUMERATE;
  4991. }
  4992. return STATUS_SUCCESS;
  4993. }
  4994. BOOLEAN
  4995. PiCollapseEnumRequests(
  4996. PLIST_ENTRY ListHead
  4997. )
  4998. /*++
  4999. Routine Description:
  5000. This function collapses reenumeration requests in the device action queue.
  5001. Parameters:
  5002. ListHead - The collapses requests get added to the end of this list.
  5003. ReturnValue:
  5004. None.
  5005. --*/
  5006. {
  5007. KIRQL oldIrql;
  5008. PPI_DEVICE_REQUEST request;
  5009. PLIST_ENTRY entry, next, last;
  5010. PDEVICE_NODE deviceNode;
  5011. ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  5012. last = ListHead->Blink;
  5013. //
  5014. // Walk the list and build the list of collapsed requests.
  5015. //
  5016. for (entry = IopPnpEnumerationRequestList.Flink;
  5017. entry != &IopPnpEnumerationRequestList;
  5018. entry = next) {
  5019. next = entry->Flink;
  5020. request = CONTAINING_RECORD(entry, PI_DEVICE_REQUEST, ListEntry);
  5021. if (request->ReorderingBarrier) {
  5022. break;
  5023. }
  5024. switch(request->RequestType) {
  5025. case ReenumerateRootDevices:
  5026. case ReenumerateDeviceTree:
  5027. case RestartEnumeration:
  5028. //
  5029. // Add it to our request list and mark the subtree.
  5030. //
  5031. RemoveEntryList(entry);
  5032. InsertTailList(ListHead, entry);
  5033. break;
  5034. default:
  5035. break;
  5036. }
  5037. }
  5038. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  5039. if (last == ListHead) {
  5040. entry = ListHead->Flink;
  5041. } else {
  5042. entry = last;
  5043. }
  5044. while (entry != ListHead) {
  5045. request = CONTAINING_RECORD(entry, PI_DEVICE_REQUEST, ListEntry);
  5046. deviceNode = (PDEVICE_NODE)request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5047. PiMarkDeviceTreeForReenumeration(deviceNode, TRUE);
  5048. ObDereferenceObject(request->DeviceObject);
  5049. request->DeviceObject = NULL;
  5050. entry = entry->Flink;
  5051. }
  5052. return (last != ListHead->Blink)? TRUE : FALSE;
  5053. }
  5054. NTSTATUS
  5055. PiProcessAddBootDevices(
  5056. IN PPI_DEVICE_REQUEST Request
  5057. )
  5058. /*++
  5059. Routine Description:
  5060. This function processes the AddBootDevices device action.
  5061. Parameters:
  5062. Request - AddBootDevices device action request.
  5063. DeviceNode - Devnode on which the action needs to be performed.
  5064. ReturnValue:
  5065. STATUS_SUCCESS.
  5066. --*/
  5067. {
  5068. PDEVICE_NODE deviceNode;
  5069. ADD_CONTEXT addContext;
  5070. PAGED_CODE();
  5071. ASSERT(Request->DeviceObject != NULL);
  5072. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5073. //
  5074. // If the device has been added (or failed) skip it.
  5075. //
  5076. // If we know the device is a duplicate of another device which
  5077. // has been enumerated at this point. we will skip this device.
  5078. //
  5079. if (deviceNode->State == DeviceNodeInitialized &&
  5080. !PipDoesDevNodeHaveProblem(deviceNode) &&
  5081. !(deviceNode->Flags & DNF_DUPLICATE) &&
  5082. deviceNode->DuplicatePDO == NULL) {
  5083. //
  5084. // Invoke driver's AddDevice Entry for the device.
  5085. //
  5086. addContext.DriverStartType = SERVICE_BOOT_START;
  5087. PipCallDriverAddDevice(deviceNode, PnPBootDriversInitialized, &addContext);
  5088. }
  5089. return STATUS_SUCCESS;
  5090. }
  5091. NTSTATUS
  5092. PiProcessClearDeviceProblem(
  5093. IN PPI_DEVICE_REQUEST Request
  5094. )
  5095. /*++
  5096. Routine Description:
  5097. This function processes the ClearDeviceProblem device action.
  5098. Parameters:
  5099. Request - ClearDeviceProblem device action request.
  5100. DeviceNode - Devnode on which the action needs to be performed.
  5101. ReturnValue:
  5102. STATUS_SUCCESS or STATUS_INVALID_PARAMETER_2.
  5103. --*/
  5104. {
  5105. NTSTATUS status;
  5106. PDEVICE_NODE deviceNode;
  5107. PAGED_CODE();
  5108. status = STATUS_SUCCESS;
  5109. ASSERT(Request->DeviceObject != NULL);
  5110. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5111. if (deviceNode->State == DeviceNodeUninitialized ||
  5112. deviceNode->State == DeviceNodeInitialized ||
  5113. deviceNode->State == DeviceNodeRemoved) {
  5114. if (PipDoesDevNodeHaveProblem(deviceNode)) {
  5115. if ((Request->RequestType == ClearDeviceProblem) &&
  5116. (PipIsProblemReadonly(deviceNode->Problem))) {
  5117. //
  5118. // ClearDeviceProblem is a user mode request, and we don't let
  5119. // user mode clear readonly problems!
  5120. //
  5121. status = STATUS_INVALID_PARAMETER_2;
  5122. } else if ((Request->RequestType == ClearEjectProblem) &&
  5123. (!PipIsDevNodeProblem(deviceNode, CM_PROB_HELD_FOR_EJECT))) {
  5124. //
  5125. // Clear eject problem means clear CM_PROB_HELD_FOR_EJECT. If
  5126. // it received another problem, we leave it alone.
  5127. //
  5128. status = STATUS_INVALID_DEVICE_REQUEST;
  5129. } else {
  5130. deviceNode->Flags &= ~(DNF_HAS_PROBLEM | DNF_HAS_PRIVATE_PROBLEM);
  5131. deviceNode->Problem = 0;
  5132. if (deviceNode->State != DeviceNodeUninitialized) {
  5133. IopRestartDeviceNode(deviceNode);
  5134. }
  5135. ASSERT(status == STATUS_SUCCESS);
  5136. }
  5137. }
  5138. } else if (PipIsDevNodeDeleted(deviceNode)) {
  5139. status = STATUS_DELETE_PENDING;
  5140. }
  5141. return status;
  5142. }
  5143. NTSTATUS
  5144. PiProcessRequeryDeviceState(
  5145. IN PPI_DEVICE_REQUEST Request
  5146. )
  5147. /*++
  5148. Routine Description:
  5149. This function processes the RequeryDeviceState device action.
  5150. Parameters:
  5151. Request - RequeryDeviceState device action request.
  5152. DeviceNode - Devnode on which the action needs to be performed.
  5153. ReturnValue:
  5154. STATUS_SUCCESS.
  5155. --*/
  5156. {
  5157. PDEVICE_NODE deviceNode;
  5158. NTSTATUS status;
  5159. PAGED_CODE();
  5160. status = STATUS_SUCCESS;
  5161. ASSERT(Request->DeviceObject != NULL);
  5162. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5163. if (deviceNode->State == DeviceNodeStarted) {
  5164. PiProcessQueryDeviceState(Request->DeviceObject);
  5165. //
  5166. // PCMCIA driver uses this when switching between Cardbus and R2 cards.
  5167. //
  5168. IopUncacheInterfaceInformation(Request->DeviceObject);
  5169. } else if (PipIsDevNodeDeleted(deviceNode)) {
  5170. status = STATUS_DELETE_PENDING;
  5171. }
  5172. return status;
  5173. }
  5174. NTSTATUS
  5175. PiProcessResourceRequirementsChanged(
  5176. IN PPI_DEVICE_REQUEST Request
  5177. )
  5178. /*++
  5179. Routine Description:
  5180. This function processes the ResourceRequirementsChanged device action.
  5181. Parameters:
  5182. Request - ResourceRequirementsChanged device action request.
  5183. DeviceNode - Devnode on which the action needs to be performed.
  5184. ReturnValue:
  5185. STATUS_SUCCESS or STATUS_UNSUCCESSFUL.
  5186. --*/
  5187. {
  5188. NTSTATUS status;
  5189. ADD_CONTEXT addContext;
  5190. PDEVICE_NODE deviceNode;
  5191. PAGED_CODE();
  5192. ASSERT(Request->DeviceObject != NULL);
  5193. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5194. if (PipIsDevNodeDeleted(deviceNode)) {
  5195. return STATUS_DELETE_PENDING;
  5196. }
  5197. //
  5198. // Clear the NO_RESOURCE_REQUIRED flags.
  5199. //
  5200. deviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
  5201. //
  5202. // If for some reason this device did not start, we need to clear some flags
  5203. // such that it can be started later. In this case, we call IopRequestDeviceEnumeration
  5204. // with NULL device object, so the devices will be handled in non-started case. They will
  5205. // be assigned resources, started and enumerated.
  5206. //
  5207. deviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED;
  5208. PipClearDevNodeProblem(deviceNode);
  5209. //
  5210. // If the device is already started, we call IopRequestDeviceEnumeration with
  5211. // the device object.
  5212. //
  5213. if (deviceNode->State == DeviceNodeStarted) {
  5214. if (Request->RequestArgument == FALSE) {
  5215. deviceNode->Flags |= DNF_NON_STOPPED_REBALANCE;
  5216. } else {
  5217. //
  5218. // Explicitly clear it.
  5219. //
  5220. deviceNode->Flags &= ~DNF_NON_STOPPED_REBALANCE;
  5221. }
  5222. //
  5223. // Reallocate resources for this devNode.
  5224. //
  5225. IopReallocateResources(deviceNode);
  5226. addContext.DriverStartType = SERVICE_DEMAND_START;
  5227. status = PipProcessDevNodeTree( IopRootDeviceNode,
  5228. PnPBootDriversInitialized, // LoadDriver
  5229. FALSE, // ReallocateResources
  5230. EnumTypeNone, // ShallowReenumeration
  5231. Request->CompletionEvent != NULL, // Synchronous
  5232. TRUE, // ProcessOnlyIntermediateStates
  5233. &addContext,
  5234. Request);
  5235. ASSERT(NT_SUCCESS(status));
  5236. if (!NT_SUCCESS(status)) {
  5237. status = STATUS_SUCCESS;
  5238. }
  5239. } else {
  5240. status = STATUS_UNSUCCESSFUL;
  5241. }
  5242. return status;
  5243. }
  5244. NTSTATUS
  5245. PiProcessReenumeration(
  5246. IN PPI_DEVICE_REQUEST Request
  5247. )
  5248. /*++
  5249. Routine Description:
  5250. This function processes the RestartEnumeration\ReenumerateRootDevices\
  5251. ReenumerateDeviceTree\ReenumerateDeviceOnly device action.
  5252. Parameters:
  5253. RequestList - List of reenumeration requests.
  5254. ReturnValue:
  5255. STATUS_SUCCESS.
  5256. --*/
  5257. {
  5258. PDEVICE_NODE deviceNode;
  5259. ADD_CONTEXT addContext;
  5260. ENUM_TYPE enumType;
  5261. PAGED_CODE();
  5262. ASSERT(Request->DeviceObject != NULL);
  5263. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5264. if (PipIsDevNodeDeleted(deviceNode)) {
  5265. return STATUS_DELETE_PENDING;
  5266. }
  5267. enumType = (Request->RequestType == ReenumerateDeviceOnly)? EnumTypeShallow : EnumTypeDeep;
  5268. PiMarkDeviceTreeForReenumeration(
  5269. deviceNode,
  5270. enumType != EnumTypeShallow);
  5271. addContext.DriverStartType = SERVICE_DEMAND_START;
  5272. PipProcessDevNodeTree(
  5273. deviceNode,
  5274. PnPBootDriversInitialized, // LoadDriver
  5275. FALSE, // ReallocateResources
  5276. enumType,
  5277. TRUE, // Synchronous
  5278. FALSE,
  5279. &addContext,
  5280. Request);
  5281. return STATUS_SUCCESS;
  5282. }
  5283. NTSTATUS
  5284. PiProcessSetDeviceProblem(
  5285. IN PPI_DEVICE_REQUEST Request
  5286. )
  5287. /*++
  5288. Routine Description:
  5289. This function processes the SetDeviceProblem device action.
  5290. Parameters:
  5291. Request - SetDeviceProblem device action request.
  5292. DeviceNode - Devnode on which the action needs to be performed.
  5293. ReturnValue:
  5294. STATUS_SUCCESS or STATUS_INVALID_PARAMETER_2.
  5295. --*/
  5296. {
  5297. PPLUGPLAY_CONTROL_STATUS_DATA statusData;
  5298. ULONG flags, userFlags;
  5299. NTSTATUS status;
  5300. PDEVICE_NODE deviceNode;
  5301. PAGED_CODE();
  5302. ASSERT(Request->DeviceObject != NULL);
  5303. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5304. if (PipIsDevNodeDeleted(deviceNode)) {
  5305. return STATUS_DELETE_PENDING;
  5306. }
  5307. status = STATUS_SUCCESS;
  5308. statusData = (PPLUGPLAY_CONTROL_STATUS_DATA)Request->RequestArgument;
  5309. userFlags = 0;
  5310. flags = 0;
  5311. if (statusData->DeviceStatus & DN_WILL_BE_REMOVED) {
  5312. userFlags |= DNUF_WILL_BE_REMOVED;
  5313. }
  5314. if (statusData->DeviceStatus & DN_NEED_RESTART) {
  5315. userFlags |= DNUF_NEED_RESTART;
  5316. }
  5317. if (statusData->DeviceStatus & DN_PRIVATE_PROBLEM) {
  5318. flags |= DNF_HAS_PRIVATE_PROBLEM;
  5319. }
  5320. if (statusData->DeviceStatus & DN_HAS_PROBLEM) {
  5321. flags |= DNF_HAS_PROBLEM;
  5322. }
  5323. if (statusData->DeviceProblem == CM_PROB_NEED_RESTART) {
  5324. flags &= ~DNF_HAS_PROBLEM;
  5325. userFlags |= DNUF_NEED_RESTART;
  5326. }
  5327. if (flags & (DNF_HAS_PROBLEM | DNF_HAS_PRIVATE_PROBLEM)) {
  5328. ASSERT(!PipIsDevNodeDNStarted(deviceNode));
  5329. //
  5330. // ISSUE - 2000/12/07 - ADRIAO:
  5331. // This set of code allows you to clear read only
  5332. // problems by first changing it to a resetable problem,
  5333. // then clearing. This is not intentional.
  5334. //
  5335. if ( ((deviceNode->State == DeviceNodeInitialized) ||
  5336. (deviceNode->State == DeviceNodeRemoved)) &&
  5337. !PipIsProblemReadonly(statusData->DeviceProblem)) {
  5338. deviceNode->Problem = statusData->DeviceProblem;
  5339. deviceNode->Flags |= flags;
  5340. deviceNode->UserFlags |= userFlags;
  5341. } else {
  5342. status = STATUS_INVALID_PARAMETER_2;
  5343. }
  5344. } else {
  5345. deviceNode->Flags |= flags;
  5346. deviceNode->UserFlags |= userFlags;
  5347. }
  5348. return status;
  5349. }
  5350. NTSTATUS
  5351. PiProcessShutdownPnpDevices(
  5352. IN OUT PDEVICE_NODE DeviceNode
  5353. )
  5354. /*++
  5355. Routine Description:
  5356. This function processes the ShutdownPnpDevices device action. Walks the tree
  5357. issuing IRP_MN_QUERY_REMOVE \ IRP_MN_REMOVE_DEVICE to each stack.
  5358. Parameters:
  5359. DeviceNode - Root devnode.
  5360. ReturnValue:
  5361. STATUS_SUCCESS.
  5362. --*/
  5363. {
  5364. KEVENT userEvent;
  5365. ULONG eventResult;
  5366. WCHAR vetoName[80];
  5367. UNICODE_STRING vetoNameString = { 0, sizeof(vetoName), vetoName };
  5368. PNP_VETO_TYPE vetoType;
  5369. NTSTATUS status;
  5370. PAGED_CODE();
  5371. ASSERT(DeviceNode == IopRootDeviceNode);
  5372. status = STATUS_SUCCESS;
  5373. if (PipTearDownPnpStacksOnShutdown ||
  5374. (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_PNP)) {
  5375. DeviceNode->UserFlags |= DNUF_SHUTDOWN_QUERIED;
  5376. for ( ; ; ) {
  5377. //
  5378. // Acquire the registry lock to prevent in process removals causing
  5379. // Devnodes to be unlinked from the tree.
  5380. //
  5381. PiLockPnpRegistry(FALSE);
  5382. //
  5383. // Walk the tree looking for devnodes we haven't QueryRemoved yet.
  5384. //
  5385. DeviceNode = DeviceNode->Child;
  5386. while (DeviceNode != NULL) {
  5387. if (DeviceNode->UserFlags & DNUF_SHUTDOWN_SUBTREE_DONE) {
  5388. if (DeviceNode == IopRootDeviceNode) {
  5389. //
  5390. // We've processed the entire devnode tree - we're done
  5391. //
  5392. DeviceNode = NULL;
  5393. break;
  5394. }
  5395. if (DeviceNode->Sibling == NULL) {
  5396. DeviceNode = DeviceNode->Parent;
  5397. DeviceNode->UserFlags |= DNUF_SHUTDOWN_SUBTREE_DONE;
  5398. } else {
  5399. DeviceNode = DeviceNode->Sibling;
  5400. }
  5401. continue;
  5402. }
  5403. if (DeviceNode->UserFlags & DNUF_SHUTDOWN_QUERIED) {
  5404. if (DeviceNode->Child == NULL) {
  5405. DeviceNode->UserFlags |= DNUF_SHUTDOWN_SUBTREE_DONE;
  5406. if (DeviceNode->Sibling == NULL) {
  5407. DeviceNode = DeviceNode->Parent;
  5408. DeviceNode->UserFlags |= DNUF_SHUTDOWN_SUBTREE_DONE;
  5409. } else {
  5410. DeviceNode = DeviceNode->Sibling;
  5411. }
  5412. } else {
  5413. DeviceNode = DeviceNode->Child;
  5414. }
  5415. continue;
  5416. }
  5417. break;
  5418. }
  5419. if (DeviceNode != NULL) {
  5420. DeviceNode->UserFlags |= DNUF_SHUTDOWN_QUERIED;
  5421. //
  5422. // Queue this device event
  5423. //
  5424. KeInitializeEvent(&userEvent, NotificationEvent, FALSE);
  5425. vetoNameString.Length = 0;
  5426. //
  5427. // Queue the event, this call will return immediately. Note that status
  5428. // is the status of the PpSetTargetDeviceChange while result is the
  5429. // outcome of the actual event.
  5430. //
  5431. status = PpSetTargetDeviceRemove(DeviceNode->PhysicalDeviceObject,
  5432. FALSE, // KernelInitiated
  5433. TRUE, // NoRestart
  5434. FALSE, // DoEject
  5435. CM_PROB_SYSTEM_SHUTDOWN,
  5436. &userEvent,
  5437. &eventResult,
  5438. &vetoType,
  5439. &vetoNameString);
  5440. } else {
  5441. status = STATUS_UNSUCCESSFUL;
  5442. }
  5443. PiUnlockPnpRegistry();
  5444. if (DeviceNode == NULL) {
  5445. //
  5446. // We've processed the entire tree.
  5447. //
  5448. break;
  5449. }
  5450. //
  5451. // Let the removes drain...
  5452. //
  5453. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  5454. if (NT_SUCCESS(status)) {
  5455. //
  5456. // Wait for the event we just queued to finish since synchronous
  5457. // operation was requested (non alertable wait).
  5458. //
  5459. // FUTURE ITEM - Use a timeout here?
  5460. //
  5461. status = KeWaitForSingleObject( &userEvent,
  5462. Executive,
  5463. KernelMode,
  5464. FALSE,
  5465. NULL);
  5466. if (NT_SUCCESS(status)) {
  5467. status = eventResult;
  5468. }
  5469. }
  5470. //
  5471. // Require lock, start on the next
  5472. //
  5473. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  5474. }
  5475. }
  5476. //
  5477. // Prevent any more events or action worker items from being queued
  5478. //
  5479. PpPnpShuttingDown = TRUE;
  5480. //
  5481. // Drain the event queue
  5482. //
  5483. PpDevNodeUnlockTree(PPL_TREEOP_ALLOW_READS);
  5484. PpSynchronizeDeviceEventQueue();
  5485. PpDevNodeLockTree(PPL_TREEOP_ALLOW_READS);
  5486. return status;
  5487. }
  5488. NTSTATUS
  5489. PiProcessStartSystemDevices(
  5490. IN PPI_DEVICE_REQUEST Request
  5491. )
  5492. /*++
  5493. Routine Description:
  5494. This function processes the StartSystemDevices device action.
  5495. Parameters:
  5496. RequestList - List of reenumeration requests.
  5497. ReturnValue:
  5498. STATUS_SUCCESS.
  5499. --*/
  5500. {
  5501. PDEVICE_NODE deviceNode;
  5502. ADD_CONTEXT addContext;
  5503. PAGED_CODE();
  5504. deviceNode = (PDEVICE_NODE)Request->DeviceObject->DeviceObjectExtension->DeviceNode;
  5505. addContext.DriverStartType = SERVICE_DEMAND_START;
  5506. PipProcessDevNodeTree(
  5507. deviceNode,
  5508. PnPBootDriversInitialized, // LoadDriver
  5509. FALSE, // ReallocateResources
  5510. EnumTypeNone,
  5511. Request->CompletionEvent != NULL, // Synchronous
  5512. FALSE,
  5513. &addContext,
  5514. Request);
  5515. return STATUS_SUCCESS;
  5516. }
  5517. VOID
  5518. PpRemoveDeviceActionRequests(
  5519. IN PDEVICE_OBJECT DeviceObject
  5520. )
  5521. {
  5522. KIRQL oldIrql;
  5523. PPI_DEVICE_REQUEST request;
  5524. PLIST_ENTRY entry, next;
  5525. ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  5526. //
  5527. // Walk the list and build the list of collapsed requests.
  5528. //
  5529. for (entry = IopPnpEnumerationRequestList.Flink;
  5530. entry != &IopPnpEnumerationRequestList;
  5531. entry = next) {
  5532. next = entry->Flink;
  5533. request = CONTAINING_RECORD(entry, PI_DEVICE_REQUEST, ListEntry);
  5534. if (request->DeviceObject == DeviceObject) {
  5535. RemoveEntryList(entry);
  5536. if (request->CompletionStatus) {
  5537. *request->CompletionStatus = STATUS_NO_SUCH_DEVICE;
  5538. }
  5539. if (request->CompletionEvent) {
  5540. KeSetEvent(request->CompletionEvent, 0, FALSE);
  5541. }
  5542. ObDereferenceObject(request->DeviceObject);
  5543. ExFreePool(request);
  5544. }
  5545. }
  5546. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  5547. }
  5548. #if DBG
  5549. VOID
  5550. PipAssertDevnodesInConsistentState(
  5551. VOID
  5552. )
  5553. {
  5554. PDEVICE_NODE deviceNode;
  5555. deviceNode = IopRootDeviceNode;
  5556. do {
  5557. ASSERT(deviceNode->State == DeviceNodeUninitialized ||
  5558. deviceNode->State == DeviceNodeInitialized ||
  5559. deviceNode->State == DeviceNodeDriversAdded ||
  5560. deviceNode->State == DeviceNodeResourcesAssigned ||
  5561. deviceNode->State == DeviceNodeStarted ||
  5562. deviceNode->State == DeviceNodeStartPostWork ||
  5563. deviceNode->State == DeviceNodeAwaitingQueuedDeletion ||
  5564. deviceNode->State == DeviceNodeAwaitingQueuedRemoval ||
  5565. deviceNode->State == DeviceNodeRemovePendingCloses ||
  5566. deviceNode->State == DeviceNodeRemoved);
  5567. if (deviceNode->Child != NULL) {
  5568. deviceNode = deviceNode->Child;
  5569. } else {
  5570. while (deviceNode->Sibling == NULL) {
  5571. if (deviceNode->Parent != NULL) {
  5572. deviceNode = deviceNode->Parent;
  5573. } else {
  5574. break;
  5575. }
  5576. }
  5577. if (deviceNode->Sibling != NULL) {
  5578. deviceNode = deviceNode->Sibling;
  5579. }
  5580. }
  5581. } while (deviceNode != IopRootDeviceNode);
  5582. }
  5583. #endif