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

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