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.

3820 lines
126 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. pnpioapi.c
  5. Abstract:
  6. This module contains the plug-and-play IO system APIs.
  7. Author:
  8. Shie-Lin Tzong (shielint) 3-Jan-1995
  9. Andrew Thornton (andrewth) 5-Sept-1996
  10. Paula Tomlinson (paulat) 1-May-1997
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "pnpmgrp.h"
  16. #pragma hdrstop
  17. #include <stddef.h>
  18. #include <wdmguid.h>
  19. #ifdef POOL_TAGGING
  20. #undef ExAllocatePool
  21. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'oipP')
  22. #endif
  23. //
  24. // Define device state work item.
  25. //
  26. typedef struct _DEVICE_WORK_ITEM {
  27. WORK_QUEUE_ITEM WorkItem;
  28. PDEVICE_OBJECT DeviceObject;
  29. PVOID Context;
  30. } DEVICE_WORK_ITEM, *PDEVICE_WORK_ITEM;
  31. NTSTATUS
  32. IopQueueDeviceWorkItem(
  33. IN PDEVICE_OBJECT PhysicalDeviceObject,
  34. IN VOID (*WorkerRoutine)(PVOID),
  35. IN PVOID Context
  36. );
  37. VOID
  38. IopRequestDeviceEjectWorker(
  39. PVOID Context
  40. );
  41. BOOLEAN
  42. IopIsReportedAlready(
  43. IN HANDLE Handle,
  44. IN PUNICODE_STRING ServiceName,
  45. IN PCM_RESOURCE_LIST ResourceList,
  46. OUT PBOOLEAN MatchingKey
  47. );
  48. //
  49. // Definitions for IoOpenDeviceRegistryKey
  50. //
  51. #define PATH_CURRENTCONTROLSET_HW_PROFILE_CURRENT TEXT("\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet")
  52. #define PATH_CURRENTCONTROLSET TEXT("\\Registry\\Machine\\System\\CurrentControlSet")
  53. #define PATH_ENUM TEXT("Enum\\")
  54. #define PATH_CONTROL_CLASS TEXT("Control\\Class\\")
  55. #define PATH_CCS_CONTROL_CLASS PATH_CURRENTCONTROLSET TEXT("\\") REGSTR_KEY_CONTROL TEXT("\\") REGSTR_KEY_CLASS
  56. #define MAX_RESTPATH_BUF_LEN 512
  57. //
  58. // Definitions for PpCreateLegacyDeviceIds
  59. //
  60. #define LEGACY_COMPATIBLE_ID_BASE TEXT("DETECTED")
  61. NTSTATUS
  62. PpCreateLegacyDeviceIds(
  63. IN PDEVICE_OBJECT DeviceObject,
  64. IN PUNICODE_STRING DriverName,
  65. IN PCM_RESOURCE_LIST Resources
  66. );
  67. //
  68. // An IO_GET_LEGACY_VETO_LIST_CONTEXT structure.
  69. //
  70. typedef struct {
  71. PWSTR * VetoList;
  72. ULONG VetoListLength;
  73. PPNP_VETO_TYPE VetoType;
  74. NTSTATUS * Status;
  75. } IO_GET_LEGACY_VETO_LIST_CONTEXT, *PIO_GET_LEGACY_VETO_LIST_CONTEXT;
  76. BOOLEAN
  77. IopAppendLegacyVeto(
  78. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context,
  79. IN PUNICODE_STRING VetoName
  80. );
  81. BOOLEAN
  82. IopGetLegacyVetoListDevice(
  83. IN PDEVICE_NODE DeviceNode,
  84. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context
  85. );
  86. BOOLEAN
  87. IopGetLegacyVetoListDeviceNode(
  88. IN PDEVICE_NODE DeviceNode,
  89. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context
  90. );
  91. VOID
  92. IopGetLegacyVetoListDrivers(
  93. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context
  94. );
  95. #ifdef ALLOC_PRAGMA
  96. #pragma alloc_text(PAGE, IoForwardAndCatchIrp)
  97. #pragma alloc_text(PAGE, IoGetDeviceProperty)
  98. #pragma alloc_text(PAGE, IoGetDmaAdapter)
  99. #pragma alloc_text(PAGE, IoGetLegacyVetoList)
  100. #pragma alloc_text(PAGE, IoIsWdmVersionAvailable)
  101. #pragma alloc_text(PAGE, IoOpenDeviceRegistryKey)
  102. #pragma alloc_text(PAGE, IoReportDetectedDevice)
  103. #pragma alloc_text(PAGE, IoSynchronousInvalidateDeviceRelations)
  104. #pragma alloc_text(PAGE, PpCreateLegacyDeviceIds)
  105. #pragma alloc_text(PAGE, IopAppendLegacyVeto)
  106. #pragma alloc_text(PAGE, IopGetLegacyVetoListDevice)
  107. #pragma alloc_text(PAGE, IopGetLegacyVetoListDeviceNode)
  108. #pragma alloc_text(PAGE, IopGetLegacyVetoListDrivers)
  109. #pragma alloc_text(PAGE, IopIsReportedAlready)
  110. #pragma alloc_text(PAGE, IopOpenDeviceParametersSubkey)
  111. #pragma alloc_text(PAGE, IopOpenOrCreateDeviceRegistryKey)
  112. #pragma alloc_text(PAGE, IopRequestDeviceEjectWorker)
  113. #pragma alloc_text(PAGE, IopResourceRequirementsChanged)
  114. #pragma alloc_text(PAGE, PiGetDeviceRegistryProperty)
  115. #endif // ALLOC_PRAGMA
  116. NTSTATUS
  117. IoGetDeviceProperty(
  118. IN PDEVICE_OBJECT DeviceObject,
  119. IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
  120. IN ULONG BufferLength,
  121. OUT PVOID PropertyBuffer,
  122. OUT PULONG ResultLength
  123. )
  124. /*++
  125. Routine Description:
  126. This routine lets drivers query the registry properties associated with the
  127. specified device.
  128. Parameters:
  129. DeviceObject - Supplies the device object whoes registry property is to be
  130. returned. This device object should be the one created by
  131. a bus driver.
  132. DeviceProperty - Specifies what device property to get.
  133. BufferLength - Specifies the length, in byte, of the PropertyBuffer.
  134. PropertyBuffer - Supplies a pointer to a buffer to receive property data.
  135. ResultLength - Supplies a pointer to a variable to receive the size of the
  136. property data returned.
  137. ReturnValue:
  138. Status code that indicates whether or not the function was successful. If
  139. PropertyBuffer is not big enough to hold requested data, STATUS_BUFFER_TOO_SMALL
  140. will be returned and ResultLength will be set to the number of bytes actually
  141. required.
  142. --*/
  143. {
  144. NTSTATUS status;
  145. PDEVICE_NODE deviceNode;
  146. DEVICE_CAPABILITIES capabilities;
  147. PWSTR valueName, keyName = NULL;
  148. ULONG valueType, length, configFlags;
  149. DEVICE_INSTALL_STATE deviceInstallState;
  150. POBJECT_NAME_INFORMATION deviceObjectName;
  151. PWSTR deviceInstanceName;
  152. PWCHAR enumeratorNameEnd;
  153. GUID busTypeGuid;
  154. PAGED_CODE();
  155. //
  156. // Initialize out parameters
  157. //
  158. *ResultLength = 0;
  159. if (!IS_PDO(DeviceObject)) {
  160. if ((DeviceProperty != DevicePropertyInstallState) &&
  161. ((DeviceProperty != DevicePropertyEnumeratorName) ||
  162. (NULL == DeviceObject->DeviceObjectExtension->DeviceNode))) {
  163. //
  164. // We'll use the verifier to fail anyone who passes in something
  165. // that is not a PDO *except* for the DevicePropertyInstallState.
  166. // This is because our check for if something is a PDO really means
  167. // is this a PDO that PNP knows about. For the most part these are
  168. // the same, but the DevicePropertyInstallState will get called by
  169. // classpnp, for device objects that *it* thinks it reported as
  170. // PDOs, but PartMgr actually swallowed. This is a gross exception
  171. // to make, so PartMgr really should be fixed.
  172. //
  173. // The arbiters attempt to retrieve the Enumerator Name property
  174. // in determining whether "driver shared" resource allocations may
  175. // be accommodated. The PDO used may be of the "legacy resource
  176. // devnode" placeholder variety. The IS_PDO() macro explicitly
  177. // disallows these devnodes, so we must special-case this as well,
  178. // in order to avoid a verifier failure. Note that our behavior
  179. // here is correct--we want the get-property call to fail for these
  180. // legacy resource devnodes.
  181. //
  182. PpvUtilFailDriver(
  183. PPVERROR_DDI_REQUIRES_PDO,
  184. (PVOID) _ReturnAddress(),
  185. DeviceObject,
  186. NULL
  187. );
  188. }
  189. return STATUS_INVALID_DEVICE_REQUEST;
  190. }
  191. deviceNode = (PDEVICE_NODE) DeviceObject->DeviceObjectExtension->DeviceNode;
  192. //
  193. // Map Device Property to registry value name and value type.
  194. //
  195. switch(DeviceProperty) {
  196. case DevicePropertyPhysicalDeviceObjectName:
  197. ASSERT (0 == (1 & BufferLength)); // had better be an even length
  198. //
  199. // Create a buffer for the Obj manager.
  200. //
  201. length = BufferLength + sizeof (OBJECT_NAME_INFORMATION);
  202. deviceObjectName = (POBJECT_NAME_INFORMATION)ExAllocatePool(
  203. PagedPool,
  204. length);
  205. if (NULL == deviceObjectName) {
  206. return STATUS_INSUFFICIENT_RESOURCES;
  207. }
  208. status = ObQueryNameString (DeviceObject,
  209. deviceObjectName,
  210. length,
  211. ResultLength);
  212. if (STATUS_INFO_LENGTH_MISMATCH == status) {
  213. status = STATUS_BUFFER_TOO_SMALL;
  214. }
  215. if (NT_SUCCESS (status)) {
  216. if (deviceObjectName->Name.Length == 0) {
  217. //
  218. // PDO has no NAME, probably it's been deleted
  219. //
  220. *ResultLength = 0;
  221. } else {
  222. *ResultLength = deviceObjectName->Name.Length + sizeof(UNICODE_NULL);
  223. if (*ResultLength > BufferLength) {
  224. status = STATUS_BUFFER_TOO_SMALL;
  225. } else {
  226. RtlCopyMemory(PropertyBuffer,
  227. deviceObjectName->Name.Buffer,
  228. deviceObjectName->Name.Length);
  229. //
  230. // NULL terminate.
  231. //
  232. *(PWCHAR)(((PUCHAR)PropertyBuffer) + deviceObjectName->Name.Length) = L'\0';
  233. }
  234. }
  235. } else {
  236. *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
  237. }
  238. ExFreePool (deviceObjectName);
  239. return status;
  240. case DevicePropertyBusTypeGuid:
  241. status = PpBusTypeGuidGet(deviceNode->ChildBusTypeIndex, &busTypeGuid);
  242. if (NT_SUCCESS(status)) {
  243. *ResultLength = sizeof(GUID);
  244. if(*ResultLength <= BufferLength) {
  245. RtlCopyMemory(PropertyBuffer,
  246. &busTypeGuid,
  247. sizeof(GUID));
  248. } else {
  249. status = STATUS_BUFFER_TOO_SMALL;
  250. }
  251. }
  252. return status;
  253. case DevicePropertyLegacyBusType:
  254. if (deviceNode->ChildInterfaceType != InterfaceTypeUndefined) {
  255. *ResultLength = sizeof(INTERFACE_TYPE);
  256. if(*ResultLength <= BufferLength) {
  257. *(PINTERFACE_TYPE)PropertyBuffer = deviceNode->ChildInterfaceType;
  258. status = STATUS_SUCCESS;
  259. } else {
  260. status = STATUS_BUFFER_TOO_SMALL;
  261. }
  262. } else {
  263. status = STATUS_OBJECT_NAME_NOT_FOUND;
  264. }
  265. return status;
  266. case DevicePropertyBusNumber:
  267. //
  268. // Retrieve the property from the parent's devnode field.
  269. //
  270. if ((deviceNode->ChildBusNumber & 0x80000000) != 0x80000000) {
  271. *ResultLength = sizeof(ULONG);
  272. if(*ResultLength <= BufferLength) {
  273. *(PULONG)PropertyBuffer = deviceNode->ChildBusNumber;
  274. status = STATUS_SUCCESS;
  275. } else {
  276. status = STATUS_BUFFER_TOO_SMALL;
  277. }
  278. } else {
  279. status = STATUS_OBJECT_NAME_NOT_FOUND;
  280. }
  281. return status;
  282. case DevicePropertyEnumeratorName:
  283. ASSERT (0 == (1 & BufferLength)); // had better be an even length
  284. deviceInstanceName = deviceNode->InstancePath.Buffer;
  285. //
  286. // There should always be a string here, except for (possibly)
  287. // HTREE\Root\0, but no one should ever be calling us with that PDO
  288. // anyway.
  289. //
  290. ASSERT (deviceInstanceName);
  291. //
  292. // We know we're going to find a separator character (\) in the string,
  293. // so the fact that unicode strings may not be null-terminated isn't
  294. // a problem.
  295. //
  296. enumeratorNameEnd = wcschr(deviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
  297. ASSERT (enumeratorNameEnd);
  298. //
  299. // Compute required length, minus null terminating character.
  300. //
  301. length = (ULONG)((PUCHAR)enumeratorNameEnd - (PUCHAR)deviceInstanceName);
  302. //
  303. // Store required length in caller-supplied OUT parameter.
  304. //
  305. *ResultLength = length + sizeof(UNICODE_NULL);
  306. if(*ResultLength > BufferLength) {
  307. status = STATUS_BUFFER_TOO_SMALL;
  308. } else {
  309. RtlCopyMemory((PUCHAR)PropertyBuffer, (PUCHAR)deviceInstanceName, length);
  310. *(PWCHAR)((PUCHAR)PropertyBuffer + length) = UNICODE_NULL;
  311. status = STATUS_SUCCESS;
  312. }
  313. return status;
  314. case DevicePropertyAddress:
  315. status = PpIrpQueryCapabilities(DeviceObject, &capabilities);
  316. if (NT_SUCCESS(status) && (capabilities.Address != 0xFFFFFFFF)) {
  317. *ResultLength = sizeof(ULONG);
  318. if(*ResultLength <= BufferLength) {
  319. *(PULONG)PropertyBuffer = capabilities.Address;
  320. status = STATUS_SUCCESS;
  321. } else {
  322. status = STATUS_BUFFER_TOO_SMALL;
  323. }
  324. } else {
  325. status = STATUS_OBJECT_NAME_NOT_FOUND;
  326. }
  327. return status;
  328. case DevicePropertyRemovalPolicy:
  329. *ResultLength = sizeof(ULONG);
  330. if(*ResultLength <= BufferLength) {
  331. PpHotSwapGetDevnodeRemovalPolicy(
  332. deviceNode,
  333. TRUE, // Include Registry Override
  334. (PDEVICE_REMOVAL_POLICY) PropertyBuffer
  335. );
  336. status = STATUS_SUCCESS;
  337. } else {
  338. status = STATUS_BUFFER_TOO_SMALL;
  339. }
  340. return status;
  341. case DevicePropertyUINumber:
  342. valueName = REGSTR_VALUE_UI_NUMBER;
  343. valueType = REG_DWORD;
  344. break;
  345. case DevicePropertyLocationInformation:
  346. valueName = REGSTR_VALUE_LOCATION_INFORMATION;
  347. valueType = REG_SZ;
  348. break;
  349. case DevicePropertyDeviceDescription:
  350. valueName = REGSTR_VALUE_DEVICE_DESC;
  351. valueType = REG_SZ;
  352. break;
  353. case DevicePropertyHardwareID:
  354. valueName = REGSTR_VALUE_HARDWAREID;
  355. valueType = REG_MULTI_SZ;
  356. break;
  357. case DevicePropertyCompatibleIDs:
  358. valueName = REGSTR_VALUE_COMPATIBLEIDS;
  359. valueType = REG_MULTI_SZ;
  360. break;
  361. case DevicePropertyBootConfiguration:
  362. keyName = REGSTR_KEY_LOG_CONF;
  363. valueName = REGSTR_VAL_BOOTCONFIG;
  364. valueType = REG_RESOURCE_LIST;
  365. break;
  366. case DevicePropertyBootConfigurationTranslated:
  367. return STATUS_NOT_SUPPORTED;
  368. break;
  369. case DevicePropertyClassName:
  370. valueName = REGSTR_VALUE_CLASS;
  371. valueType = REG_SZ;
  372. break;
  373. case DevicePropertyClassGuid:
  374. valueName = REGSTR_VALUE_CLASSGUID;
  375. valueType = REG_SZ;
  376. break;
  377. case DevicePropertyDriverKeyName:
  378. valueName = REGSTR_VALUE_DRIVER;
  379. valueType = REG_SZ;
  380. break;
  381. case DevicePropertyManufacturer:
  382. valueName = REGSTR_VAL_MFG;
  383. valueType = REG_SZ;
  384. break;
  385. case DevicePropertyFriendlyName:
  386. valueName = REGSTR_VALUE_FRIENDLYNAME;
  387. valueType = REG_SZ;
  388. break;
  389. case DevicePropertyInstallState:
  390. if (deviceNode == IopRootDeviceNode) {
  391. //
  392. // The root devnode is always installed, by definition. We
  393. // specifically set it's InstallState here because the
  394. // CONFIGFLAG_REINSTALL flag will wunfortunately still exist on the
  395. // root devnode reg key on a running system (we should fix that
  396. // later).
  397. //
  398. deviceInstallState = InstallStateInstalled;
  399. status = STATUS_SUCCESS;
  400. } else {
  401. //
  402. // For all other devnodes, walk up the devnode tree, retrieving the
  403. // install state of all ancestors up to (but not including) the root
  404. // devnode. We'll stop when we've reached the top of the tree, or
  405. // when some intermediate device has an "uninstalled" install state.
  406. //
  407. valueName = REGSTR_VALUE_CONFIG_FLAGS;
  408. valueType = REG_DWORD;
  409. do {
  410. //
  411. // Get the ConfigFlags registry value.
  412. //
  413. length = sizeof(ULONG);
  414. status = PiGetDeviceRegistryProperty(
  415. deviceNode->PhysicalDeviceObject,
  416. valueType,
  417. valueName,
  418. keyName,
  419. (PVOID)&configFlags,
  420. &length
  421. );
  422. if (NT_SUCCESS(status)) {
  423. //
  424. // The install state is just a subset of the device's ConfigFlags
  425. //
  426. if (configFlags & CONFIGFLAG_REINSTALL) {
  427. deviceInstallState = InstallStateNeedsReinstall;
  428. } else if (configFlags & CONFIGFLAG_FAILEDINSTALL) {
  429. deviceInstallState = InstallStateFailedInstall;
  430. } else if (configFlags & CONFIGFLAG_FINISH_INSTALL) {
  431. deviceInstallState = InstallStateFinishInstall;
  432. } else {
  433. deviceInstallState = InstallStateInstalled;
  434. }
  435. } else {
  436. deviceInstallState = InstallStateFailedInstall;
  437. break;
  438. }
  439. deviceNode = deviceNode->Parent;
  440. } while ((deviceInstallState == InstallStateInstalled) &&
  441. (deviceNode != IopRootDeviceNode));
  442. }
  443. if (NT_SUCCESS(status)) {
  444. *ResultLength = sizeof(ULONG);
  445. if(*ResultLength <= BufferLength) {
  446. *(PDEVICE_INSTALL_STATE)PropertyBuffer = deviceInstallState;
  447. } else {
  448. status = STATUS_BUFFER_TOO_SMALL;
  449. }
  450. }
  451. return status;
  452. default:
  453. return STATUS_INVALID_PARAMETER_2;
  454. }
  455. //
  456. // Get the registry value.
  457. //
  458. *ResultLength = BufferLength;
  459. status = PiGetDeviceRegistryProperty(
  460. DeviceObject,
  461. valueType,
  462. valueName,
  463. keyName,
  464. PropertyBuffer,
  465. ResultLength
  466. );
  467. return status;
  468. }
  469. NTSTATUS
  470. PiGetDeviceRegistryProperty(
  471. IN PDEVICE_OBJECT DeviceObject,
  472. IN ULONG ValueType,
  473. IN PWSTR ValueName,
  474. IN PWSTR KeyName,
  475. OUT PVOID Buffer,
  476. IN OUT PULONG BufferLength
  477. )
  478. {
  479. NTSTATUS status;
  480. HANDLE handle, subKeyHandle;
  481. UNICODE_STRING unicodeKey;
  482. PKEY_VALUE_FULL_INFORMATION keyValueInformation = NULL;
  483. PAGED_CODE();
  484. //
  485. // Enter critical section and acquire a lock on the registry. Both these
  486. // mechanisms are required to prevent deadlock in the case where an APC
  487. // routine calls this routine after the registry resource has been claimed
  488. // in this case it would wait blocking this thread so the registry would
  489. // never be released -> deadlock. Critical sectioning the registry manipulatio
  490. // portion solves this problem
  491. //
  492. PiLockPnpRegistry(TRUE);
  493. //
  494. // Based on the PDO specified by caller, find the handle of its device
  495. // instance registry key.
  496. //
  497. status = IopDeviceObjectToDeviceInstance(DeviceObject, &handle, KEY_READ);
  498. if (NT_SUCCESS(status)) {
  499. //
  500. // If the data is stored in a subkey then open this key and close the old one
  501. //
  502. if (KeyName) {
  503. RtlInitUnicodeString(&unicodeKey, KeyName);
  504. status = IopOpenRegistryKeyEx( &subKeyHandle,
  505. handle,
  506. &unicodeKey,
  507. KEY_READ
  508. );
  509. if(NT_SUCCESS(status)){
  510. ZwClose(handle);
  511. handle = subKeyHandle;
  512. }
  513. }
  514. if (NT_SUCCESS(status)) {
  515. //
  516. // Read the registry value of the desired value name
  517. //
  518. status = IopGetRegistryValue (handle,
  519. ValueName,
  520. &keyValueInformation);
  521. }
  522. //
  523. // We have finished using the registry so clean up and release our resources
  524. //
  525. ZwClose(handle);
  526. }
  527. PiUnlockPnpRegistry();
  528. //
  529. // If we have been sucessfull in finding the info hand it back to the caller
  530. //
  531. if (NT_SUCCESS(status)) {
  532. //
  533. // Check that the buffer we have been given is big enough and that the value returned is
  534. // of the correct registry type
  535. //
  536. if (*BufferLength >= keyValueInformation->DataLength) {
  537. if (keyValueInformation->Type == ValueType) {
  538. RtlCopyMemory( Buffer,
  539. KEY_VALUE_DATA(keyValueInformation),
  540. keyValueInformation->DataLength);
  541. } else {
  542. status = STATUS_INVALID_PARAMETER_2;
  543. }
  544. } else {
  545. status = STATUS_BUFFER_TOO_SMALL;
  546. }
  547. *BufferLength = keyValueInformation->DataLength;
  548. ExFreePool(keyValueInformation);
  549. }
  550. return status;
  551. }
  552. NTSTATUS
  553. IoOpenDeviceRegistryKey(
  554. IN PDEVICE_OBJECT PhysicalDeviceObject,
  555. IN ULONG DevInstKeyType,
  556. IN ACCESS_MASK DesiredAccess,
  557. OUT PHANDLE DevInstRegKey
  558. )
  559. /*++
  560. Routine Description:
  561. This routine returns a handle to an opened registry key that the driver
  562. may use to store/retrieve configuration information specific to a particular
  563. device instance.
  564. The driver must call ZwClose to close the handle returned from this api
  565. when access is no longer required.
  566. Parameters:
  567. DeviceObject - Supples the device object of the physical device instance to
  568. open a registry storage key for. Normally it is a device object
  569. created by the hal bus extender.
  570. DevInstKeyType - Supplies flags specifying which storage key associated with
  571. the device instance is to be opened. May be a combination of
  572. the following value:
  573. PLUGPLAY_REGKEY_DEVICE - Open a key for storing device specific
  574. (driver-independent) information relating to the device instance.
  575. The flag may not be specified with PLUGPLAY_REGKEY_DRIVER.
  576. PLUGPLAY_REGKEY_DRIVER - Open a key for storing driver-specific
  577. information relating to the device instance, This flag may
  578. not be specified with PLUGPLAY_REGKEY_DEVICE.
  579. PLUGPLAY_REGKEY_CURRENT_HWPROFILE - If this flag is specified,
  580. then a key in the current hardware profile branch will be
  581. opened for the specified storage type. This allows the driver
  582. to access configuration information that is hardware profile
  583. specific.
  584. DesiredAccess - Specifies the access mask for the key to be opened.
  585. DevInstRegKey - Supplies the address of a variable that receives a handle to the
  586. opened key for the specified registry storage location.
  587. Return Value:
  588. Status code that indicates whether or not the function was successful.
  589. --*/
  590. {
  591. //
  592. // IoOpenDeviceRegistryKey does not support creating a driver key if none
  593. // exists. This is for internal use only.
  594. //
  595. return IopOpenOrCreateDeviceRegistryKey(PhysicalDeviceObject,
  596. DevInstKeyType,
  597. DesiredAccess,
  598. FALSE, // do not create
  599. DevInstRegKey);
  600. }
  601. NTSTATUS
  602. IopOpenOrCreateDeviceRegistryKey(
  603. IN PDEVICE_OBJECT PhysicalDeviceObject,
  604. IN ULONG DevInstKeyType,
  605. IN ACCESS_MASK DesiredAccess,
  606. IN BOOLEAN Create,
  607. OUT PHANDLE DevInstRegKey
  608. )
  609. /*++
  610. Routine Description:
  611. This routine returns a handle to an opened registry key that the driver
  612. may use to store/retrieve configuration information specific to a particular
  613. device instance.
  614. The driver must call ZwClose to close the handle returned from this api
  615. when access is no longer required.
  616. Parameters:
  617. DeviceObject - Supples the device object of the physical device instance to
  618. open a registry storage key for. Normally it is a device object
  619. created by the hal bus extender.
  620. DevInstKeyType - Supplies flags specifying which storage key associated with
  621. the device instance is to be opened. May be a combination of
  622. the following value:
  623. PLUGPLAY_REGKEY_DEVICE - Open a key for storing device specific
  624. (driver-independent) information relating to the device instance.
  625. The flag may not be specified with PLUGPLAY_REGKEY_DRIVER.
  626. PLUGPLAY_REGKEY_DRIVER - Open a key for storing driver-specific
  627. information relating to the device instance, This flag may
  628. not be specified with PLUGPLAY_REGKEY_DEVICE.
  629. PLUGPLAY_REGKEY_CURRENT_HWPROFILE - If this flag is specified,
  630. then a key in the current hardware profile branch will be
  631. opened for the specified storage type. This allows the driver
  632. to access configuration information that is hardware profile
  633. specific.
  634. DesiredAccess - Specifies the access mask for the key to be opened.
  635. Create - Specifies whether the key should be created if not present (applies
  636. only to PLUGPLAY_REGKEY_DRIVER; for PLUGPLAY_REGKEY_DEVICE,
  637. a key is always created).
  638. DevInstRegKey - Supplies the address of a variable that receives a handle to the
  639. opened key for the specified registry storage location.
  640. Return Value:
  641. Status code that indicates whether or not the function was successful.
  642. Notes:
  643. ** The Create parameter ONLY applies to DevInstKeyType == PLUGPLAY_REGKEY_DRIVER!
  644. -- For PLUGPLAY_REGKEY_DEVICE, a key is always created, so this parameter
  645. will be ignored.
  646. -- A hardware-profile-specific subkey will only be created for
  647. PLUGPLAY_REGKEY_DRIVER | PLUGPLAY_REGKEY_CURRENT_HWPROFILE
  648. if a corresponding non-hardware-profile-specific Driver key has already
  649. been created for the device in the global CurrentControlSet.
  650. If this routine is needed to create a hardware-profile-specific Driver key
  651. when no global Driver key exists yet for the device, then you must modify
  652. the code below to first search for and create an available driver instance
  653. key in both the global AND hardware profile-specific CurrentControlSet
  654. branches.
  655. --*/
  656. {
  657. NTSTATUS status, appendStatus;
  658. HANDLE hBasePath;
  659. UNICODE_STRING unicodeBasePath, unicodeRestPath;
  660. WCHAR drvInst[GUID_STRING_LEN + 5];
  661. ULONG drvInstLength;
  662. PAGED_CODE();
  663. //
  664. // Until SCSIPORT stops passing non PDOs allow the system to boot.
  665. //
  666. // ASSERT_PDO(PhysicalDeviceObject);
  667. //
  668. //
  669. // Initialise out parameters
  670. //
  671. *DevInstRegKey = NULL;
  672. //
  673. // Allocate a buffer to build the RestPath string in
  674. //
  675. unicodeRestPath.Buffer = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, MAX_RESTPATH_BUF_LEN);
  676. if (unicodeRestPath.Buffer == NULL) {
  677. status = STATUS_INSUFFICIENT_RESOURCES;
  678. goto clean0;
  679. }
  680. unicodeRestPath.Length=0;
  681. unicodeRestPath.MaximumLength=MAX_RESTPATH_BUF_LEN;
  682. //
  683. // Select the base path to the CurrentControlSet based on if we are dealing with
  684. // a hardware profile or not
  685. //
  686. if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) {
  687. PiWstrToUnicodeString(&unicodeBasePath, PATH_CURRENTCONTROLSET_HW_PROFILE_CURRENT);
  688. } else {
  689. PiWstrToUnicodeString(&unicodeBasePath, PATH_CURRENTCONTROLSET);
  690. }
  691. //
  692. // Enter critical section and acquire a lock on the registry. Both these
  693. // mechanisms are required to prevent deadlock in the case where an APC
  694. // routine calls this routine after the registry resource has been claimed
  695. // in this case it would wait blocking this thread so the registry would
  696. // never be released -> deadlock. Critical sectioning the registry manipulation
  697. // portion solves this problem
  698. //
  699. PiLockPnpRegistry(TRUE);
  700. //
  701. // Open the base registry key
  702. //
  703. status = IopOpenRegistryKeyEx( &hBasePath,
  704. NULL,
  705. &unicodeBasePath,
  706. KEY_READ
  707. );
  708. if(!NT_SUCCESS(status)) {
  709. goto clean1;
  710. }
  711. //
  712. // Build the RestPath string
  713. //
  714. switch (DevInstKeyType) {
  715. case PLUGPLAY_REGKEY_DEVICE:
  716. case PLUGPLAY_REGKEY_DEVICE + PLUGPLAY_REGKEY_CURRENT_HWPROFILE:
  717. {
  718. PDEVICE_NODE pDeviceNode;
  719. //
  720. // Initialise the rest path with Enum\
  721. //
  722. appendStatus = RtlAppendUnicodeToString(&unicodeRestPath, PATH_ENUM);
  723. ASSERT(NT_SUCCESS( appendStatus ));
  724. //
  725. // Get the Enumerator\DeviceID\InstanceID path from the DeviceNode
  726. //
  727. pDeviceNode = (PDEVICE_NODE) PhysicalDeviceObject->DeviceObjectExtension->DeviceNode;
  728. //
  729. // Ensure this is a PDO and not an FDO (only PDO's have a DeviceNode)
  730. //
  731. if (pDeviceNode) {
  732. appendStatus = RtlAppendUnicodeStringToString(&unicodeRestPath, &(pDeviceNode->InstancePath));
  733. ASSERT(NT_SUCCESS( appendStatus ));
  734. } else {
  735. status = STATUS_INVALID_DEVICE_REQUEST;
  736. }
  737. break;
  738. }
  739. case PLUGPLAY_REGKEY_DRIVER:
  740. case PLUGPLAY_REGKEY_DRIVER + PLUGPLAY_REGKEY_CURRENT_HWPROFILE:
  741. {
  742. HANDLE hDeviceKey;
  743. //
  744. // Initialise the rest path with Control\Class\
  745. //
  746. appendStatus = RtlAppendUnicodeToString(&unicodeRestPath, PATH_CONTROL_CLASS);
  747. ASSERT(NT_SUCCESS( appendStatus ));
  748. //
  749. // Open the device instance key for this device
  750. //
  751. status = IopDeviceObjectToDeviceInstance(PhysicalDeviceObject, &hDeviceKey, KEY_READ);
  752. if(!NT_SUCCESS(status)){
  753. goto clean1;
  754. }
  755. //
  756. // See if we have a driver value
  757. //
  758. status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName, sizeof(drvInst), drvInst, &drvInstLength);
  759. if(NT_SUCCESS(status)){
  760. //
  761. // Append <DevInstClass>\<ClassInstanceOrdinal>
  762. //
  763. appendStatus = RtlAppendUnicodeToString(&unicodeRestPath, drvInst);
  764. ASSERT(NT_SUCCESS( appendStatus ));
  765. } else if ((status == STATUS_OBJECT_NAME_NOT_FOUND) &&
  766. Create &&
  767. ((DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) == 0)) {
  768. //
  769. // No Driver value exists for this device yet, but we've been
  770. // explicitly asked to create one now.
  771. //
  772. // NOTE: 01-Dec-2001 : Jim Cavalaris (jamesca)
  773. //
  774. // Note that we only do this for the global driver key - not the
  775. // hardware profile specific one. If this routine is used to
  776. // create hardware profile keys also, then you must search for
  777. // and create an available driver instance key in both the
  778. // global AND hardware profile-specific CurrentControlSet
  779. // branches.
  780. //
  781. WCHAR classGUID[GUID_STRING_LEN];
  782. ULONG classGUIDLength;
  783. HANDLE hClassGUIDKey;
  784. //
  785. // See if we have a class GUID value.
  786. //
  787. status = IoGetDeviceProperty(PhysicalDeviceObject,
  788. DevicePropertyClassGuid,
  789. sizeof(classGUID),
  790. classGUID,
  791. &classGUIDLength);
  792. if (NT_SUCCESS(status)) {
  793. //
  794. // Open or create the key for this device's Class.
  795. //
  796. appendStatus = RtlAppendUnicodeToString(&unicodeRestPath, classGUID);
  797. ASSERT(NT_SUCCESS( appendStatus ));
  798. status = IopCreateRegistryKeyEx(&hClassGUIDKey,
  799. hBasePath,
  800. &unicodeRestPath,
  801. KEY_ALL_ACCESS, // need to create
  802. REG_OPTION_NON_VOLATILE,
  803. NULL);
  804. if (NT_SUCCESS(status)) {
  805. ULONG instance;
  806. WCHAR instanceOrdinal[5];
  807. UNICODE_STRING tempString;
  808. HANDLE hDriverInstanceKey;
  809. ULONG disposition;
  810. for (instance = 0; instance < 9999; instance++) {
  811. //
  812. // Find the first available class instance key.
  813. //
  814. StringCbPrintfW(instanceOrdinal, sizeof(instanceOrdinal), TEXT("%04u"), instance);
  815. RtlInitUnicodeString(&tempString, instanceOrdinal);
  816. hDriverInstanceKey = NULL;
  817. status = IopCreateRegistryKeyEx(&hDriverInstanceKey,
  818. hClassGUIDKey,
  819. &tempString,
  820. DesiredAccess,
  821. REG_OPTION_NON_VOLATILE,
  822. &disposition);
  823. if (NT_SUCCESS(status)) {
  824. if (disposition == REG_CREATED_NEW_KEY) {
  825. //
  826. // Set the Driver registry value in the
  827. // device instance key.
  828. //
  829. StringCbPrintfW(drvInst,
  830. sizeof(drvInst),
  831. TEXT("%s\\%s"),
  832. classGUID,
  833. instanceOrdinal);
  834. PiWstrToUnicodeString(&tempString, REGSTR_VALUE_DRIVER);
  835. status = ZwSetValueKey(hDeviceKey,
  836. &tempString,
  837. TITLE_INDEX_VALUE,
  838. REG_SZ,
  839. drvInst,
  840. (ULONG)((wcslen(drvInst)+1) * sizeof(WCHAR)));
  841. if (NT_SUCCESS(status)) {
  842. appendStatus = RtlAppendUnicodeToString(&unicodeRestPath, TEXT("\\"));
  843. ASSERT(NT_SUCCESS( appendStatus ));
  844. appendStatus = RtlAppendUnicodeToString(&unicodeRestPath, instanceOrdinal);
  845. ASSERT(NT_SUCCESS( appendStatus ));
  846. } else {
  847. //
  848. // Delete the key we just created.
  849. //
  850. ZwDeleteKey(hDriverInstanceKey);
  851. }
  852. //
  853. // Always close the key we just created, so we
  854. // can open it below for the DesiredAccess of
  855. // the caller.
  856. //
  857. ZwClose(hDriverInstanceKey);
  858. break;
  859. }
  860. //
  861. // Always close the key we just created, so we
  862. // can open it below for the DesiredAccess of
  863. // the caller.
  864. //
  865. ZwClose(hDriverInstanceKey);
  866. }
  867. }
  868. if (instance == 9999) {
  869. status = STATUS_UNSUCCESSFUL;
  870. }
  871. ZwClose(hClassGUIDKey);
  872. }
  873. }
  874. }
  875. ZwClose(hDeviceKey);
  876. break;
  877. }
  878. default:
  879. //
  880. // ISSUE 2001/02/08 ADRIAO - This is parameter #2, not parameter #3!
  881. //
  882. status = STATUS_INVALID_PARAMETER_3;
  883. goto clean2;
  884. }
  885. //
  886. // If we succeeded in building the rest path then open the key and hand it back to the caller
  887. //
  888. if (NT_SUCCESS(status)){
  889. if (DevInstKeyType == PLUGPLAY_REGKEY_DEVICE) {
  890. status = IopOpenDeviceParametersSubkey(DevInstRegKey,
  891. hBasePath,
  892. &unicodeRestPath,
  893. DesiredAccess);
  894. } else {
  895. status = IopCreateRegistryKeyEx( DevInstRegKey,
  896. hBasePath,
  897. &unicodeRestPath,
  898. DesiredAccess,
  899. REG_OPTION_NON_VOLATILE,
  900. NULL
  901. );
  902. }
  903. }
  904. //
  905. // Free up resources
  906. //
  907. clean2:
  908. ZwClose(hBasePath);
  909. clean1:
  910. PiUnlockPnpRegistry();
  911. ExFreePool(unicodeRestPath.Buffer);
  912. clean0:
  913. return status;
  914. }
  915. NTSTATUS
  916. IoSynchronousInvalidateDeviceRelations(
  917. IN PDEVICE_OBJECT DeviceObject,
  918. IN DEVICE_RELATION_TYPE Type
  919. )
  920. /*++
  921. Routine Description:
  922. This API notifies the system that changes have occurred in the device
  923. relations of the specified type for the supplied DeviceObject. All
  924. cached information concerning the relationships must be invalidated,
  925. and if needed re-obtained via IRP_MN_QUERY_DEVICE_RELATIONS.
  926. This routine performs device enumeration synchronously.
  927. Note, A driver can NOT call this IO api while processing pnp irps AND
  928. A driver can NOT call this api from any system thread except the system
  929. threads created by the driver itself.
  930. Parameters:
  931. DeviceObject - the PDEVICE_OBJECT for which the specified relation type
  932. information has been invalidated. This pointer is valid
  933. for the duration of the call.
  934. Type - specifies the type of the relation being invalidated.
  935. ReturnValue:
  936. Status code that indicates whether or not the function was successful.
  937. --*/
  938. {
  939. PDEVICE_NODE deviceNode;
  940. NTSTATUS status = STATUS_SUCCESS;
  941. KEVENT completionEvent;
  942. PAGED_CODE();
  943. ASSERT_PDO(DeviceObject);
  944. switch (Type) {
  945. case BusRelations:
  946. if (PnPInitialized) {
  947. deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
  948. if (deviceNode->State == DeviceNodeStarted) {
  949. KeInitializeEvent( &completionEvent, NotificationEvent, FALSE );
  950. status = PipRequestDeviceAction( DeviceObject,
  951. ReenumerateDeviceTree,
  952. FALSE,
  953. 0,
  954. &completionEvent,
  955. NULL );
  956. if (NT_SUCCESS(status)) {
  957. status = KeWaitForSingleObject( &completionEvent,
  958. Executive,
  959. KernelMode,
  960. FALSE,
  961. NULL);
  962. }
  963. } else {
  964. status = STATUS_UNSUCCESSFUL;
  965. }
  966. } else {
  967. status = STATUS_UNSUCCESSFUL;
  968. }
  969. break;
  970. case EjectionRelations:
  971. //
  972. // For Ejection relation change, we will ignore it. We don't keep track
  973. // the Ejection relation. We will query the Ejection relation only when
  974. // we are requested to eject a device.
  975. //
  976. status = STATUS_NOT_SUPPORTED;
  977. break;
  978. case PowerRelations:
  979. //
  980. // Call off to Po code, which will do the right thing
  981. //
  982. PoInvalidateDevicePowerRelations(DeviceObject);
  983. break;
  984. }
  985. return status;
  986. }
  987. VOID
  988. IoInvalidateDeviceRelations(
  989. IN PDEVICE_OBJECT DeviceObject,
  990. IN DEVICE_RELATION_TYPE Type
  991. )
  992. /*++
  993. Routine Description:
  994. This API notifies the system that changes have occurred in the device
  995. relations of the specified type for the supplied DeviceObject. All
  996. cached information concerning the relationships must be invalidated,
  997. and if needed re-obtained via IRP_MN_QUERY_DEVICE_RELATIONS.
  998. Parameters:
  999. DeviceObject - the PDEVICE_OBJECT for which the specified relation type
  1000. information has been invalidated. This pointer is valid
  1001. for the duration of the call.
  1002. Type - specifies the type of the relation being invalidated.
  1003. ReturnValue:
  1004. none.
  1005. --*/
  1006. {
  1007. PDEVICE_NODE deviceNode;
  1008. ASSERT_PDO(DeviceObject);
  1009. switch (Type) {
  1010. case BusRelations:
  1011. case SingleBusRelations:
  1012. //
  1013. // If the call was made before PnP completes device enumeration
  1014. // we can safely ignore it. PnP manager will do it without
  1015. // driver's request.
  1016. //
  1017. deviceNode = (PDEVICE_NODE) DeviceObject->DeviceObjectExtension->DeviceNode;
  1018. if (deviceNode) {
  1019. PipRequestDeviceAction( DeviceObject,
  1020. Type == BusRelations ?
  1021. ReenumerateDeviceTree : ReenumerateDeviceOnly,
  1022. FALSE,
  1023. 0,
  1024. NULL,
  1025. NULL );
  1026. }
  1027. break;
  1028. case EjectionRelations:
  1029. //
  1030. // For Ejection relation change, we will ignore it. We don't keep track
  1031. // the Ejection relation. We will query the Ejection relation only when
  1032. // we are requested to eject a device.
  1033. break;
  1034. case PowerRelations:
  1035. //
  1036. // Call off to Po code, which will do the right thing
  1037. //
  1038. PoInvalidateDevicePowerRelations(DeviceObject);
  1039. break;
  1040. }
  1041. }
  1042. VOID
  1043. IoRequestDeviceEject(
  1044. IN PDEVICE_OBJECT DeviceObject
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. This API notifies that the device eject button has been pressed. This API must
  1049. be called at IRQL <= DISPATCH_LEVEL.
  1050. This API informs PnP that a device eject has been requested, the device will
  1051. not necessarily be ejected as a result of this API. The device will only be
  1052. ejected if the drivers associated with it agree to stop and the device is
  1053. successfully powered down. Note that eject in this context refers to device
  1054. eject, not to media (floppies, cds, tapes) eject. For example, eject of a
  1055. cd-rom disk drive, not ejection of a cd-rom disk.
  1056. Arguments:
  1057. DeviceObject - the PDEVICE_OBJECT for the device whose eject button has
  1058. been pressed. This pointer is valid for the duration of
  1059. the call, if the API wants to keep a copy of it, it
  1060. should obtain its own reference to the object
  1061. (ObReferenceObject).
  1062. ReturnValue:
  1063. None.
  1064. --*/
  1065. {
  1066. ASSERT_PDO(DeviceObject);
  1067. IopQueueDeviceWorkItem(DeviceObject, IopRequestDeviceEjectWorker, NULL);
  1068. }
  1069. VOID
  1070. IopRequestDeviceEjectWorker(
  1071. IN PVOID Context
  1072. )
  1073. {
  1074. PDEVICE_WORK_ITEM deviceWorkItem = (PDEVICE_WORK_ITEM)Context;
  1075. PDEVICE_OBJECT deviceObject = deviceWorkItem->DeviceObject;
  1076. ExFreePool(deviceWorkItem);
  1077. //
  1078. // Queue the event, we'll return immediately after it's queued.
  1079. //
  1080. PpSetTargetDeviceRemove( deviceObject,
  1081. TRUE,
  1082. TRUE,
  1083. FALSE,
  1084. TRUE,
  1085. CM_PROB_HELD_FOR_EJECT,
  1086. NULL,
  1087. NULL,
  1088. NULL,
  1089. NULL);
  1090. ObDereferenceObject(deviceObject);
  1091. }
  1092. NTSTATUS
  1093. IoReportDetectedDevice(
  1094. IN PDRIVER_OBJECT DriverObject,
  1095. IN INTERFACE_TYPE LegacyBusType,
  1096. IN ULONG BusNumber,
  1097. IN ULONG SlotNumber,
  1098. IN PCM_RESOURCE_LIST ResourceList,
  1099. IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements OPTIONAL,
  1100. IN BOOLEAN ResourceAssigned,
  1101. IN OUT PDEVICE_OBJECT *DeviceObject
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. PnP device drivers call this API to report any device detected. This routine
  1106. creates a Physical Device object, reference the Physical Device object and
  1107. returns back to the callers. Once the detected device is reported, the Pnp manager
  1108. considers the device has been fully controlled by the reporting drivers. Thus it
  1109. will not invoke AddDevice entry and send StartDevice irp to the driver.
  1110. The driver needs to report the resources it used to detect this device such that
  1111. pnp manager can perform duplicates detection on this device.
  1112. The caller must dereference the DeviceObject once it no longer needs it.
  1113. Parameters:
  1114. DriverObject - Supplies the driver object of the driver who detected
  1115. this device.
  1116. ResourceList - Supplies a pointer to the resource list which the driver used
  1117. to detect the device.
  1118. ResourceRequirements - supplies a pointer to the resource requirements list
  1119. for the detected device. This is optional.
  1120. ResourceAssigned - if TRUE, the driver already called IoReportResourceUsage or
  1121. IoAssignResource to get the ownership of the resources. Otherwise,
  1122. the PnP manager will call IoReportResourceUsage to allocate the
  1123. resources for the driver.
  1124. DeviceObject - if NULL, this routine will create a PDO and return it thru this variable.
  1125. Otherwise, a PDO is already created and this routine will simply use the supplied
  1126. PDO.
  1127. Return Value:
  1128. Status code that indicates whether or not the function was successful.
  1129. --*/
  1130. {
  1131. WCHAR buffer[MAX_DEVICE_ID_LEN], *end, *name;
  1132. NTSTATUS status;
  1133. UNICODE_STRING deviceName, instanceName, unicodeName, *serviceName, driverName;
  1134. PDEVICE_NODE deviceNode;
  1135. ULONG length, i = 0, disposition, tmpValue, listSize = 0;
  1136. HANDLE handle = NULL, handle1, logConfHandle = NULL, controlHandle = NULL, enumHandle;
  1137. PCM_RESOURCE_LIST cmResource;
  1138. PWSTR p;
  1139. PDEVICE_OBJECT deviceObject;
  1140. BOOLEAN newlyCreated = FALSE;
  1141. PAGED_CODE();
  1142. if (*DeviceObject) {
  1143. deviceObject = *DeviceObject;
  1144. //
  1145. // The PDO is already known. simply handle the resourcelist and resreq list.
  1146. // This is a hack for NDIS drivers.
  1147. //
  1148. deviceNode = (PDEVICE_NODE)(*DeviceObject)->DeviceObjectExtension->DeviceNode;
  1149. if (!deviceNode) {
  1150. return STATUS_NO_SUCH_DEVICE;
  1151. }
  1152. PiLockPnpRegistry(FALSE);
  1153. //
  1154. // Write ResourceList and ResReq list to the device instance
  1155. //
  1156. status = IopDeviceObjectToDeviceInstance (*DeviceObject,
  1157. &handle,
  1158. KEY_ALL_ACCESS
  1159. );
  1160. if (!NT_SUCCESS(status)) {
  1161. PiUnlockPnpRegistry();
  1162. return status;
  1163. }
  1164. if (ResourceAssigned) {
  1165. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_NO_RESOURCE_AT_INIT);
  1166. tmpValue = 1;
  1167. ZwSetValueKey(handle,
  1168. &unicodeName,
  1169. TITLE_INDEX_VALUE,
  1170. REG_DWORD,
  1171. &tmpValue,
  1172. sizeof(tmpValue)
  1173. );
  1174. }
  1175. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  1176. status = IopCreateRegistryKeyEx( &logConfHandle,
  1177. handle,
  1178. &unicodeName,
  1179. KEY_ALL_ACCESS,
  1180. REG_OPTION_NON_VOLATILE,
  1181. NULL
  1182. );
  1183. ZwClose(handle);
  1184. if (NT_SUCCESS(status)) {
  1185. //
  1186. // Write the ResourceList and and ResourceRequirements to the logconf key under
  1187. // device instance key.
  1188. //
  1189. if (ResourceList) {
  1190. PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_BOOTCONFIG);
  1191. ZwSetValueKey(
  1192. logConfHandle,
  1193. &unicodeName,
  1194. TITLE_INDEX_VALUE,
  1195. REG_RESOURCE_LIST,
  1196. ResourceList,
  1197. listSize = IopDetermineResourceListSize(ResourceList)
  1198. );
  1199. }
  1200. if (ResourceRequirements) {
  1201. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_BASIC_CONFIG_VECTOR);
  1202. ZwSetValueKey(
  1203. logConfHandle,
  1204. &unicodeName,
  1205. TITLE_INDEX_VALUE,
  1206. REG_RESOURCE_REQUIREMENTS_LIST,
  1207. ResourceRequirements,
  1208. ResourceRequirements->ListSize
  1209. );
  1210. }
  1211. ZwClose(logConfHandle);
  1212. }
  1213. PiUnlockPnpRegistry();
  1214. if (NT_SUCCESS(status)) {
  1215. goto checkResource;
  1216. } else {
  1217. return status;
  1218. }
  1219. }
  1220. //
  1221. // Normal case: *DeviceObject is NULL
  1222. //
  1223. *DeviceObject = NULL;
  1224. serviceName = &DriverObject->DriverExtension->ServiceKeyName;
  1225. //
  1226. // Special handling for driver object created thru IoCreateDriver.
  1227. // When a builtin driver calls IoReportDetectedDevice, the ServiceKeyName of
  1228. // the driver object is set to \Driver\DriverName. To create a detected device
  1229. // instance key, we will take only the DriverName.
  1230. //
  1231. if (DriverObject->Flags & DRVO_BUILTIN_DRIVER) {
  1232. p = serviceName->Buffer + (serviceName->Length / sizeof(WCHAR)) - 1;
  1233. driverName.Length = 0;
  1234. while (*p != '\\' && (p != serviceName->Buffer)) {
  1235. p--;
  1236. driverName.Length += sizeof(WCHAR);
  1237. }
  1238. if (p == serviceName->Buffer) {
  1239. return STATUS_UNSUCCESSFUL;
  1240. } else {
  1241. p++;
  1242. driverName.Buffer = p;
  1243. driverName.MaximumLength = driverName.Length + sizeof(WCHAR);
  1244. }
  1245. } else {
  1246. //
  1247. // Before doing anything first perform duplicate detection
  1248. //
  1249. status = IopDuplicateDetection( LegacyBusType,
  1250. BusNumber,
  1251. SlotNumber,
  1252. &deviceNode
  1253. );
  1254. if (NT_SUCCESS(status) && deviceNode) {
  1255. deviceObject = deviceNode->PhysicalDeviceObject;
  1256. if (PipAreDriversLoaded(deviceNode) ||
  1257. (PipDoesDevNodeHaveProblem(deviceNode) &&
  1258. deviceNode->Problem != CM_PROB_NOT_CONFIGURED &&
  1259. deviceNode->Problem != CM_PROB_REINSTALL &&
  1260. deviceNode->Problem != CM_PROB_FAILED_INSTALL)) {
  1261. ObDereferenceObject(deviceObject);
  1262. return STATUS_NO_SUCH_DEVICE;
  1263. }
  1264. deviceNode->Flags &= ~DNF_HAS_PROBLEM;
  1265. deviceNode->Problem = 0;
  1266. IopDeleteLegacyKey(DriverObject);
  1267. goto checkResource;
  1268. }
  1269. driverName.Buffer = NULL;
  1270. }
  1271. //
  1272. // Create a PDO
  1273. //
  1274. status = IoCreateDevice( IoPnpDriverObject,
  1275. sizeof(IOPNP_DEVICE_EXTENSION),
  1276. NULL,
  1277. FILE_DEVICE_CONTROLLER,
  1278. FILE_AUTOGENERATED_DEVICE_NAME,
  1279. FALSE,
  1280. &deviceObject );
  1281. if (NT_SUCCESS(status)) {
  1282. deviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; // Mark this is a PDO
  1283. status = PipAllocateDeviceNode(deviceObject, &deviceNode);
  1284. if (status != STATUS_SYSTEM_HIVE_TOO_LARGE && deviceNode) {
  1285. //
  1286. // First delete the Legacy_DriverName key and subkeys from Enum\Root, if exits.
  1287. //
  1288. if (!(DriverObject->Flags & DRVO_BUILTIN_DRIVER)) {
  1289. IopDeleteLegacyKey(DriverObject);
  1290. }
  1291. //
  1292. // Create the compatible id list we'll use for this made-up device.
  1293. //
  1294. status = PpCreateLegacyDeviceIds(
  1295. deviceObject,
  1296. ((DriverObject->Flags & DRVO_BUILTIN_DRIVER) ?
  1297. &driverName : serviceName),
  1298. ResourceList);
  1299. PiLockPnpRegistry(FALSE);
  1300. if(!NT_SUCCESS(status)) {
  1301. goto exit;
  1302. }
  1303. //
  1304. // Create/Open a registry key for the device instance and
  1305. // write the addr of the device object to registry
  1306. //
  1307. if (DriverObject->Flags & DRVO_BUILTIN_DRIVER) {
  1308. name = driverName.Buffer;
  1309. } else {
  1310. name = serviceName->Buffer;
  1311. }
  1312. StringCchPrintfExW(
  1313. buffer,
  1314. sizeof(buffer) / sizeof(WCHAR),
  1315. &end,
  1316. NULL,
  1317. 0,
  1318. L"ROOT\\%s",
  1319. name);
  1320. length = (ULONG)((PBYTE)end - (PBYTE)buffer);
  1321. deviceName.MaximumLength = sizeof(buffer);
  1322. ASSERT(length <= sizeof(buffer) - 10);
  1323. deviceName.Length = (USHORT)length;
  1324. deviceName.Buffer = buffer;
  1325. status = IopOpenRegistryKeyEx( &enumHandle,
  1326. NULL,
  1327. &CmRegistryMachineSystemCurrentControlSetEnumName,
  1328. KEY_ALL_ACCESS
  1329. );
  1330. if (!NT_SUCCESS(status)) {
  1331. goto exit;
  1332. }
  1333. status = IopCreateRegistryKeyEx( &handle1,
  1334. enumHandle,
  1335. &deviceName,
  1336. KEY_ALL_ACCESS,
  1337. REG_OPTION_NON_VOLATILE,
  1338. &disposition
  1339. );
  1340. if (NT_SUCCESS(status)) {
  1341. deviceName.Buffer[deviceName.Length / sizeof(WCHAR)] =
  1342. OBJ_NAME_PATH_SEPARATOR;
  1343. deviceName.Length += sizeof(UNICODE_NULL);
  1344. length += sizeof(UNICODE_NULL);
  1345. if (disposition != REG_CREATED_NEW_KEY) {
  1346. for ( ; ; ) {
  1347. deviceName.Length = (USHORT)length;
  1348. PiUlongToInstanceKeyUnicodeString(&instanceName,
  1349. buffer + deviceName.Length / sizeof(WCHAR),
  1350. sizeof(buffer) - deviceName.Length,
  1351. i
  1352. );
  1353. deviceName.Length = (USHORT)(deviceName.Length + instanceName.Length);
  1354. status = IopCreateRegistryKeyEx( &handle,
  1355. handle1,
  1356. &instanceName,
  1357. KEY_ALL_ACCESS,
  1358. REG_OPTION_NON_VOLATILE,
  1359. &disposition
  1360. );
  1361. if (NT_SUCCESS(status)) {
  1362. if (disposition == REG_CREATED_NEW_KEY) {
  1363. ZwClose(handle1);
  1364. break;
  1365. } else {
  1366. PKEY_VALUE_FULL_INFORMATION keyValueInformation = NULL;
  1367. BOOLEAN migratedKey = FALSE, matchingKey = FALSE;
  1368. //
  1369. // Check if the key exists because it was
  1370. // explicitly migrated during textmode setup.
  1371. //
  1372. status = IopGetRegistryValue(handle,
  1373. REGSTR_VALUE_MIGRATED,
  1374. &keyValueInformation);
  1375. if (NT_SUCCESS(status)) {
  1376. if ((keyValueInformation->Type == REG_DWORD) &&
  1377. (keyValueInformation->DataLength == sizeof(ULONG)) &&
  1378. ((*(PULONG)KEY_VALUE_DATA(keyValueInformation)) != 0)) {
  1379. migratedKey = TRUE;
  1380. }
  1381. ExFreePool(keyValueInformation);
  1382. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_MIGRATED);
  1383. ZwDeleteValueKey(handle, &unicodeName);
  1384. }
  1385. if (IopIsReportedAlready(handle, serviceName, ResourceList, &matchingKey)) {
  1386. ASSERT(matchingKey);
  1387. //
  1388. // Write the reported resources to registry in case the irq changed
  1389. //
  1390. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  1391. status = IopCreateRegistryKeyEx( &logConfHandle,
  1392. handle,
  1393. &unicodeName,
  1394. KEY_ALL_ACCESS,
  1395. REG_OPTION_NON_VOLATILE,
  1396. NULL
  1397. );
  1398. if (NT_SUCCESS(status)) {
  1399. //
  1400. // Write the ResourceList and and ResourceRequirements to the device instance key
  1401. //
  1402. if (ResourceList) {
  1403. PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_BOOTCONFIG);
  1404. ZwSetValueKey(
  1405. logConfHandle,
  1406. &unicodeName,
  1407. TITLE_INDEX_VALUE,
  1408. REG_RESOURCE_LIST,
  1409. ResourceList,
  1410. listSize = IopDetermineResourceListSize(ResourceList)
  1411. );
  1412. }
  1413. if (ResourceRequirements) {
  1414. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_BASIC_CONFIG_VECTOR);
  1415. ZwSetValueKey(
  1416. logConfHandle,
  1417. &unicodeName,
  1418. TITLE_INDEX_VALUE,
  1419. REG_RESOURCE_REQUIREMENTS_LIST,
  1420. ResourceRequirements,
  1421. ResourceRequirements->ListSize
  1422. );
  1423. }
  1424. ZwClose(logConfHandle);
  1425. }
  1426. PiUnlockPnpRegistry();
  1427. IoDeleteDevice(deviceObject);
  1428. ZwClose(handle1);
  1429. deviceObject = IopDeviceObjectFromDeviceInstance(&deviceName); // Add a reference
  1430. ZwClose(handle);
  1431. ZwClose(enumHandle);
  1432. ASSERT(deviceObject);
  1433. if (deviceObject == NULL) {
  1434. status = STATUS_UNSUCCESSFUL;
  1435. return status;
  1436. }
  1437. deviceNode = (PDEVICE_NODE)
  1438. deviceObject->DeviceObjectExtension->DeviceNode;
  1439. if (PipAreDriversLoaded(deviceNode) ||
  1440. (PipDoesDevNodeHaveProblem(deviceNode) &&
  1441. deviceNode->Problem != CM_PROB_NOT_CONFIGURED &&
  1442. deviceNode->Problem != CM_PROB_REINSTALL &&
  1443. deviceNode->Problem != CM_PROB_FAILED_INSTALL)) {
  1444. ObDereferenceObject(deviceObject);
  1445. return STATUS_NO_SUCH_DEVICE;
  1446. }
  1447. goto checkResource;
  1448. } else if (matchingKey && migratedKey) {
  1449. //
  1450. // We opened an existing key whose Service
  1451. // and Resources match those being reported
  1452. // for this device. No device is yet
  1453. // reported as using this instance, so we'll
  1454. // use it, and treat is as a new key.
  1455. //
  1456. disposition = REG_CREATED_NEW_KEY;
  1457. ZwClose(handle1);
  1458. break;
  1459. } else {
  1460. i++;
  1461. ZwClose(handle);
  1462. continue;
  1463. }
  1464. }
  1465. } else {
  1466. ZwClose(handle1);
  1467. ZwClose(enumHandle);
  1468. goto exit;
  1469. }
  1470. }
  1471. } else {
  1472. //
  1473. // This is a new device key. So, instance is 0. Create it.
  1474. //
  1475. PiUlongToInstanceKeyUnicodeString(&instanceName,
  1476. buffer + deviceName.Length / sizeof(WCHAR),
  1477. sizeof(buffer) - deviceName.Length,
  1478. i
  1479. );
  1480. deviceName.Length = (USHORT)(deviceName.Length + instanceName.Length);
  1481. status = IopCreateRegistryKeyEx( &handle,
  1482. handle1,
  1483. &instanceName,
  1484. KEY_ALL_ACCESS,
  1485. REG_OPTION_NON_VOLATILE,
  1486. &disposition
  1487. );
  1488. ZwClose(handle1);
  1489. if (!NT_SUCCESS(status)) {
  1490. ZwClose(enumHandle);
  1491. goto exit;
  1492. }
  1493. ASSERT(disposition == REG_CREATED_NEW_KEY);
  1494. }
  1495. } else {
  1496. ZwClose(enumHandle);
  1497. goto exit;
  1498. }
  1499. ASSERT(disposition == REG_CREATED_NEW_KEY);
  1500. newlyCreated = TRUE;
  1501. //
  1502. // Initialize new device instance registry key
  1503. //
  1504. if (ResourceAssigned) {
  1505. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_NO_RESOURCE_AT_INIT);
  1506. tmpValue = 1;
  1507. ZwSetValueKey(handle,
  1508. &unicodeName,
  1509. TITLE_INDEX_VALUE,
  1510. REG_DWORD,
  1511. &tmpValue,
  1512. sizeof(tmpValue)
  1513. );
  1514. }
  1515. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  1516. logConfHandle = NULL;
  1517. status = IopCreateRegistryKeyEx( &logConfHandle,
  1518. handle,
  1519. &unicodeName,
  1520. KEY_ALL_ACCESS,
  1521. REG_OPTION_NON_VOLATILE,
  1522. NULL
  1523. );
  1524. ASSERT(status == STATUS_SUCCESS);
  1525. if (NT_SUCCESS(status)) {
  1526. //
  1527. // Write the ResourceList and and ResourceRequirements to the logconf key under
  1528. // device instance key.
  1529. //
  1530. if (ResourceList) {
  1531. PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_BOOTCONFIG);
  1532. ZwSetValueKey(
  1533. logConfHandle,
  1534. &unicodeName,
  1535. TITLE_INDEX_VALUE,
  1536. REG_RESOURCE_LIST,
  1537. ResourceList,
  1538. listSize = IopDetermineResourceListSize(ResourceList)
  1539. );
  1540. }
  1541. if (ResourceRequirements) {
  1542. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_BASIC_CONFIG_VECTOR);
  1543. ZwSetValueKey(
  1544. logConfHandle,
  1545. &unicodeName,
  1546. TITLE_INDEX_VALUE,
  1547. REG_RESOURCE_REQUIREMENTS_LIST,
  1548. ResourceRequirements,
  1549. ResourceRequirements->ListSize
  1550. );
  1551. }
  1552. //ZwClose(logConfHandle);
  1553. }
  1554. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CONFIG_FLAGS);
  1555. tmpValue = CONFIGFLAG_FINISH_INSTALL;
  1556. ZwSetValueKey(handle,
  1557. &unicodeName,
  1558. TITLE_INDEX_VALUE,
  1559. REG_DWORD,
  1560. &tmpValue,
  1561. sizeof(tmpValue)
  1562. );
  1563. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_LEGACY);
  1564. tmpValue = 0;
  1565. ZwSetValueKey(
  1566. handle,
  1567. &unicodeName,
  1568. TITLE_INDEX_VALUE,
  1569. REG_DWORD,
  1570. &tmpValue,
  1571. sizeof(ULONG)
  1572. );
  1573. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  1574. controlHandle = NULL;
  1575. IopCreateRegistryKeyEx( &controlHandle,
  1576. handle,
  1577. &unicodeName,
  1578. KEY_ALL_ACCESS,
  1579. REG_OPTION_VOLATILE,
  1580. NULL
  1581. );
  1582. ASSERT(status == STATUS_SUCCESS);
  1583. if (NT_SUCCESS(status)) {
  1584. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_DEVICE_REPORTED);
  1585. tmpValue = 1;
  1586. status = ZwSetValueKey(controlHandle,
  1587. &unicodeName,
  1588. TITLE_INDEX_VALUE,
  1589. REG_DWORD,
  1590. &tmpValue,
  1591. sizeof(ULONG)
  1592. );
  1593. status = ZwSetValueKey(handle,
  1594. &unicodeName,
  1595. TITLE_INDEX_VALUE,
  1596. REG_DWORD,
  1597. &tmpValue,
  1598. sizeof(ULONG)
  1599. );
  1600. //ZwClose(controlHandle);
  1601. }
  1602. ZwClose(enumHandle);
  1603. //
  1604. // Create Service value name and set it to the calling driver's service
  1605. // key name.
  1606. //
  1607. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_SERVICE);
  1608. p = (PWSTR)ExAllocatePool(PagedPool, serviceName->Length + sizeof(UNICODE_NULL));
  1609. if (!p) {
  1610. PiUnlockPnpRegistry();
  1611. goto CleanupRegistry;
  1612. }
  1613. RtlCopyMemory(p, serviceName->Buffer, serviceName->Length);
  1614. p[serviceName->Length / sizeof (WCHAR)] = UNICODE_NULL;
  1615. ZwSetValueKey(
  1616. handle,
  1617. &unicodeName,
  1618. TITLE_INDEX_VALUE,
  1619. REG_SZ,
  1620. p,
  1621. serviceName->Length + sizeof(UNICODE_NULL)
  1622. );
  1623. if (DriverObject->Flags & DRVO_BUILTIN_DRIVER) {
  1624. deviceNode->ServiceName = *serviceName;
  1625. } else {
  1626. ExFreePool(p);
  1627. }
  1628. PiUnlockPnpRegistry();
  1629. //ZwClose(logConfHandle);
  1630. //ZwClose(controlHandle);
  1631. //ZwClose(handle);
  1632. //
  1633. // Register the device for the driver and save the device
  1634. // instance path in device node.
  1635. //
  1636. if (!(DriverObject->Flags & DRVO_BUILTIN_DRIVER)) {
  1637. PpDeviceRegistration( &deviceName,
  1638. TRUE,
  1639. &deviceNode->ServiceName
  1640. );
  1641. }
  1642. status = PipConcatenateUnicodeStrings(&deviceNode->InstancePath, &deviceName, NULL);
  1643. if (NT_SUCCESS(status)) {
  1644. deviceNode->Flags = DNF_MADEUP | DNF_ENUMERATED;
  1645. PipSetDevNodeState(deviceNode, DeviceNodeInitialized, NULL);
  1646. PpDevNodeInsertIntoTree(IopRootDeviceNode, deviceNode);
  1647. //
  1648. // Add an entry into the table to set up a mapping between the DO
  1649. // and the instance path.
  1650. //
  1651. status = IopMapDeviceObjectToDeviceInstance(deviceObject, &deviceNode->InstancePath);
  1652. ASSERT(NT_SUCCESS(status));
  1653. //
  1654. // Add a reference to the DeviceObject for ourself
  1655. //
  1656. ObReferenceObject(deviceObject);
  1657. IopNotifySetupDeviceArrival(deviceObject, NULL, FALSE);
  1658. goto checkResource;
  1659. }
  1660. }
  1661. IoDeleteDevice(deviceObject);
  1662. status = STATUS_INSUFFICIENT_RESOURCES;
  1663. }
  1664. return status;
  1665. checkResource:
  1666. //
  1667. // At this point the *DeviceObject is established. Check if we need to report resources for
  1668. // the detected device. If we failed to
  1669. //
  1670. if (ResourceAssigned) {
  1671. //ASSERT(deviceNode->ResourceList == NULL); // make sure we have not reported resources yet.
  1672. //
  1673. // If the driver specifies it already has acquired the resource. We will put a flag
  1674. // in the device instance path to not to allocate resources at boot time. The Driver
  1675. // may do detection and report it again.
  1676. //
  1677. deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED; // do not need resources for this boot.
  1678. if (ResourceList) {
  1679. //
  1680. // Write the resource list to the reported device instance key.
  1681. //
  1682. listSize = IopDetermineResourceListSize(ResourceList);
  1683. IopWriteAllocatedResourcesToRegistry (deviceNode, ResourceList, listSize);
  1684. }
  1685. } else {
  1686. BOOLEAN conflict;
  1687. if (ResourceList && ResourceList->Count && ResourceList->List[0].PartialResourceList.Count) {
  1688. if (listSize == 0) {
  1689. listSize = IopDetermineResourceListSize(ResourceList);
  1690. }
  1691. cmResource = (PCM_RESOURCE_LIST) ExAllocatePool(PagedPool, listSize);
  1692. if (cmResource) {
  1693. RtlCopyMemory(cmResource, ResourceList, listSize);
  1694. PiWstrToUnicodeString(&unicodeName, PNPMGR_STR_PNP_MANAGER);
  1695. status = IoReportResourceUsageInternal(
  1696. ArbiterRequestLegacyReported,
  1697. &unicodeName, // DriverClassName OPTIONAL,
  1698. deviceObject->DriverObject, // DriverObject,
  1699. NULL, // DriverList OPTIONAL,
  1700. 0, // DriverListSize OPTIONAL,
  1701. deviceNode->PhysicalDeviceObject,
  1702. // DeviceObject OPTIONAL,
  1703. cmResource, // DeviceList OPTIONAL,
  1704. listSize, // DeviceListSize OPTIONAL,
  1705. FALSE, // OverrideConflict,
  1706. &conflict // ConflictDetected
  1707. );
  1708. ExFreePool(cmResource);
  1709. if (!NT_SUCCESS(status) || conflict) {
  1710. status = STATUS_CONFLICTING_ADDRESSES;
  1711. PipSetDevNodeProblem(deviceNode, CM_PROB_NORMAL_CONFLICT);
  1712. }
  1713. } else {
  1714. status = STATUS_INSUFFICIENT_RESOURCES;
  1715. PipSetDevNodeProblem(deviceNode, CM_PROB_OUT_OF_MEMORY);
  1716. }
  1717. } else {
  1718. ASSERT(ResourceRequirements == NULL);
  1719. deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED; // do not need resources for this boot.
  1720. }
  1721. }
  1722. if (NT_SUCCESS(status)) {
  1723. IopDoDeferredSetInterfaceState(deviceNode);
  1724. PipSetDevNodeState(deviceNode, DeviceNodeStartPostWork, NULL);
  1725. *DeviceObject = deviceObject;
  1726. if (newlyCreated) {
  1727. if (controlHandle) {
  1728. ZwClose(controlHandle);
  1729. }
  1730. if (logConfHandle) {
  1731. ZwClose(logConfHandle);
  1732. }
  1733. ZwClose(handle);
  1734. }
  1735. //
  1736. // Make sure we enumerate and process this device's children.
  1737. //
  1738. PipRequestDeviceAction(deviceObject, ReenumerateDeviceOnly, FALSE, 0, NULL, NULL);
  1739. return status;
  1740. }
  1741. CleanupRegistry:
  1742. IopReleaseDeviceResources(deviceNode, FALSE);
  1743. if (newlyCreated) {
  1744. IoDeleteDevice(deviceObject);
  1745. if (controlHandle) {
  1746. ZwDeleteKey(controlHandle);
  1747. }
  1748. if (logConfHandle) {
  1749. ZwDeleteKey(logConfHandle);
  1750. }
  1751. if (handle) {
  1752. ZwDeleteKey(handle);
  1753. }
  1754. }
  1755. return status;
  1756. exit:
  1757. PiUnlockPnpRegistry();
  1758. IoDeleteDevice(*DeviceObject);
  1759. return status;
  1760. }
  1761. BOOLEAN
  1762. IopIsReportedAlready(
  1763. IN HANDLE Handle,
  1764. IN PUNICODE_STRING ServiceName,
  1765. IN PCM_RESOURCE_LIST ResourceList,
  1766. IN PBOOLEAN MatchingKey
  1767. )
  1768. /*++
  1769. Routine Description:
  1770. This routine determines if the reported device instance is already reported
  1771. or not.
  1772. Parameters:
  1773. Handle - Supplies a handle to the reported device instance key.
  1774. ServiceName - supplies a pointer to the unicode service key name.
  1775. ResourceList - supplies a pointer to the reported Resource list.
  1776. MatchingKey - supplies a pointer to a variable to receive whether the
  1777. ServiceName and ResourceList properties for this key match those
  1778. reported.
  1779. Return Value:
  1780. Status code that indicates whether or not the function was successful.
  1781. --*/
  1782. {
  1783. PKEY_VALUE_FULL_INFORMATION keyValueInfo1 = NULL, keyValueInfo2 = NULL;
  1784. NTSTATUS status;
  1785. UNICODE_STRING unicodeName;
  1786. HANDLE logConfHandle, controlHandle = NULL;
  1787. BOOLEAN returnValue = FALSE;
  1788. PCM_RESOURCE_LIST cmResource = NULL;
  1789. ULONG tmpValue;
  1790. PAGED_CODE();
  1791. //
  1792. // Assume no match unless we determine otherwise.
  1793. //
  1794. *MatchingKey = FALSE;
  1795. //
  1796. // Check if "Service" value matches what the caller passed in.
  1797. //
  1798. status = IopGetRegistryValue(Handle, REGSTR_VALUE_SERVICE, &keyValueInfo1);
  1799. if (NT_SUCCESS(status)) {
  1800. if ((keyValueInfo1->Type == REG_SZ) &&
  1801. (keyValueInfo1->DataLength != 0)) {
  1802. unicodeName.Buffer = (PWSTR)KEY_VALUE_DATA(keyValueInfo1);
  1803. unicodeName.MaximumLength = unicodeName.Length = (USHORT)keyValueInfo1->DataLength;
  1804. if (unicodeName.Buffer[(keyValueInfo1->DataLength / sizeof(WCHAR)) - 1] == UNICODE_NULL) {
  1805. unicodeName.Length -= sizeof(WCHAR);
  1806. }
  1807. if (RtlEqualUnicodeString(ServiceName, &unicodeName, TRUE)) {
  1808. //
  1809. // Next check if resources are the same
  1810. //
  1811. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  1812. status = IopOpenRegistryKeyEx( &logConfHandle,
  1813. Handle,
  1814. &unicodeName,
  1815. KEY_READ
  1816. );
  1817. if (NT_SUCCESS(status)) {
  1818. status = IopGetRegistryValue(logConfHandle,
  1819. REGSTR_VAL_BOOTCONFIG,
  1820. &keyValueInfo2);
  1821. ZwClose(logConfHandle);
  1822. if (NT_SUCCESS(status)) {
  1823. if ((keyValueInfo2->Type == REG_RESOURCE_LIST) &&
  1824. (keyValueInfo2->DataLength != 0)) {
  1825. cmResource = (PCM_RESOURCE_LIST)KEY_VALUE_DATA(keyValueInfo2);
  1826. if (ResourceList && cmResource &&
  1827. PipIsDuplicatedDevices(ResourceList, cmResource, NULL, NULL)) {
  1828. *MatchingKey = TRUE;
  1829. }
  1830. }
  1831. }
  1832. }
  1833. if (!ResourceList && !cmResource) {
  1834. *MatchingKey = TRUE;
  1835. }
  1836. }
  1837. }
  1838. }
  1839. //
  1840. // If this registry key is for a device reported during the same boot
  1841. // this is not a duplicate.
  1842. //
  1843. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  1844. status = IopOpenRegistryKeyEx( &controlHandle,
  1845. Handle,
  1846. &unicodeName,
  1847. KEY_ALL_ACCESS
  1848. );
  1849. if (NT_SUCCESS(status)) {
  1850. status = IopGetRegistryValue(controlHandle,
  1851. REGSTR_VALUE_DEVICE_REPORTED,
  1852. &keyValueInfo1);
  1853. if (NT_SUCCESS(status)) {
  1854. goto exit;
  1855. }
  1856. if (*MatchingKey == TRUE) {
  1857. returnValue = TRUE;
  1858. //
  1859. // Mark this key has been used.
  1860. //
  1861. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_DEVICE_REPORTED);
  1862. tmpValue = 1;
  1863. status = ZwSetValueKey(controlHandle,
  1864. &unicodeName,
  1865. TITLE_INDEX_VALUE,
  1866. REG_DWORD,
  1867. &tmpValue,
  1868. sizeof(ULONG)
  1869. );
  1870. if (!NT_SUCCESS(status)) {
  1871. returnValue = FALSE;
  1872. }
  1873. }
  1874. }
  1875. exit:
  1876. if (controlHandle) {
  1877. ZwClose(controlHandle);
  1878. }
  1879. if (keyValueInfo1) {
  1880. ExFreePool(keyValueInfo1);
  1881. }
  1882. if (keyValueInfo2) {
  1883. ExFreePool(keyValueInfo2);
  1884. }
  1885. return returnValue;
  1886. }
  1887. VOID
  1888. IoInvalidateDeviceState(
  1889. IN PDEVICE_OBJECT PhysicalDeviceObject
  1890. )
  1891. /*++
  1892. Routine Description:
  1893. This API will cause the PnP manager to send the specified PDO an IRP_MN_QUERY_PNP_DEVICE_STATE
  1894. IRP.
  1895. Parameters:
  1896. PhysicalDeviceObject - Provides a pointer to the PDO who's state is to be invalidated.
  1897. Return Value:
  1898. none.
  1899. --*/
  1900. {
  1901. PDEVICE_NODE deviceNode;
  1902. ASSERT_PDO(PhysicalDeviceObject);
  1903. //
  1904. // If the call was made before PnP completes device enumeration
  1905. // we can safely ignore it. PnP manager will do it without
  1906. // driver's request. If the device was already removed or surprised
  1907. // removed then ignore it as well since this is only valid for started
  1908. // devices.
  1909. //
  1910. deviceNode = (PDEVICE_NODE)PhysicalDeviceObject->DeviceObjectExtension->DeviceNode;
  1911. if (deviceNode->State != DeviceNodeStarted) {
  1912. return;
  1913. }
  1914. PipRequestDeviceAction( PhysicalDeviceObject,
  1915. RequeryDeviceState,
  1916. FALSE,
  1917. 0,
  1918. NULL,
  1919. NULL);
  1920. }
  1921. NTSTATUS
  1922. IopQueueDeviceWorkItem(
  1923. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1924. IN VOID (*WorkerRoutine)(PVOID),
  1925. IN PVOID Context
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. This API will cause the PnP manager to send the specified PDO an
  1930. IRP_MN_QUERY_PNP_DEVICE_STATE IRP.
  1931. Parameters:
  1932. PhysicalDeviceObject - Provides a pointer to the PDO who's state is to be
  1933. invalidated.
  1934. Return Value:
  1935. none.
  1936. --*/
  1937. {
  1938. PDEVICE_WORK_ITEM deviceWorkItem;
  1939. //
  1940. // Since this routine can be called at DPC level we need to queue
  1941. // a work item and process it when the irql drops.
  1942. //
  1943. deviceWorkItem = ExAllocatePool(NonPagedPool, sizeof(DEVICE_WORK_ITEM));
  1944. if (deviceWorkItem == NULL) {
  1945. //
  1946. // Failed to allocate memory for work item. Nothing we can do ...
  1947. //
  1948. return STATUS_INSUFFICIENT_RESOURCES;
  1949. }
  1950. ObReferenceObject(PhysicalDeviceObject);
  1951. deviceWorkItem->DeviceObject = PhysicalDeviceObject;
  1952. deviceWorkItem->Context = Context;
  1953. ExInitializeWorkItem( &deviceWorkItem->WorkItem,
  1954. WorkerRoutine,
  1955. deviceWorkItem);
  1956. //
  1957. // Queue a work item to do the enumeration
  1958. //
  1959. ExQueueWorkItem( &deviceWorkItem->WorkItem, DelayedWorkQueue );
  1960. return STATUS_SUCCESS;
  1961. }
  1962. //
  1963. // Private routines
  1964. //
  1965. VOID
  1966. IopResourceRequirementsChanged(
  1967. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1968. IN BOOLEAN StopRequired
  1969. )
  1970. /*++
  1971. Routine Description:
  1972. This routine handles request of device resource requirements list change.
  1973. Parameters:
  1974. PhysicalDeviceObject - Provides a pointer to the PDO who's state is to be invalidated.
  1975. StopRequired - Supplies a BOOLEAN value to indicate if the resources reallocation needs
  1976. to be done after device stopped.
  1977. Return Value:
  1978. none.
  1979. --*/
  1980. {
  1981. PAGED_CODE();
  1982. PipRequestDeviceAction( PhysicalDeviceObject,
  1983. ResourceRequirementsChanged,
  1984. FALSE,
  1985. StopRequired,
  1986. NULL,
  1987. NULL );
  1988. }
  1989. BOOLEAN
  1990. IoIsWdmVersionAvailable(
  1991. IN UCHAR MajorVersion,
  1992. IN UCHAR MinorVersion
  1993. )
  1994. /*++
  1995. Routine Description:
  1996. This routine reports whether WDM functionality is available that
  1997. is greater than or equal to the specified major and minor version.
  1998. Parameters:
  1999. MajorVersion - Supplies the WDM major version that is required.
  2000. MinorVersion - Supplies the WDM minor version that is required.
  2001. Return Value:
  2002. If WDM support is available at _at least_ the requested level, the
  2003. return value is TRUE, otherwise it is FALSE.
  2004. --*/
  2005. {
  2006. return ((MajorVersion < WDM_MAJORVERSION) ||
  2007. ((MajorVersion == WDM_MAJORVERSION) && (MinorVersion <= WDM_MINORVERSION)));
  2008. }
  2009. NTKERNELAPI
  2010. PDMA_ADAPTER
  2011. IoGetDmaAdapter(
  2012. IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
  2013. IN PDEVICE_DESCRIPTION DeviceDescription,
  2014. IN OUT PULONG NumberOfMapRegisters
  2015. )
  2016. /*++
  2017. Routine Description:
  2018. This function returns the appropriate DMA adapter object for the device
  2019. defined in the device description structure. This code is a wrapper
  2020. which queries the bus interface standard and then calls the returned
  2021. get DMA adapter function. If an adapter object was not retrieved then
  2022. a legecy function is attempted.
  2023. Arguments:
  2024. PhysicalDeviceObject - Optionally, supplies the PDO for the device
  2025. requesting the DMA adapter. If not supplied, this routine performs the
  2026. function of the non-PnP HalGetDmaAdapter routine.
  2027. DeviceDescriptor - Supplies a description of the deivce.
  2028. NumberOfMapRegisters - Returns the maximum number of map registers which
  2029. may be allocated by the device driver.
  2030. Return Value:
  2031. A pointer to the requested adapter object or NULL if an adapter could not
  2032. be created.
  2033. --*/
  2034. {
  2035. KEVENT event;
  2036. NTSTATUS status;
  2037. PIRP irp;
  2038. IO_STATUS_BLOCK ioStatusBlock;
  2039. PIO_STACK_LOCATION irpStack;
  2040. BUS_INTERFACE_STANDARD busInterface;
  2041. PDMA_ADAPTER dmaAdapter = NULL;
  2042. PDEVICE_DESCRIPTION deviceDescriptionToUse;
  2043. DEVICE_DESCRIPTION privateDeviceDescription;
  2044. ULONG resultLength;
  2045. PDEVICE_OBJECT targetDevice;
  2046. PAGED_CODE();
  2047. if (PhysicalDeviceObject != NULL) {
  2048. ASSERT_PDO(PhysicalDeviceObject);
  2049. //
  2050. // First off, determine whether or not the caller has requested that we
  2051. // automatically fill in the proper InterfaceType value into the
  2052. // DEVICE_DESCRIPTION structure used in retrieving the DMA adapter object.
  2053. // If so, then retrieve that interface type value into our own copy of
  2054. // the DEVICE_DESCRIPTION buffer.
  2055. //
  2056. if ((DeviceDescription->InterfaceType == InterfaceTypeUndefined) ||
  2057. (DeviceDescription->InterfaceType == PNPBus)) {
  2058. //
  2059. // Make a copy of the caller-supplied device description, so
  2060. // we can modify it to fill in the correct interface type.
  2061. //
  2062. RtlCopyMemory(&privateDeviceDescription,
  2063. DeviceDescription,
  2064. sizeof(DEVICE_DESCRIPTION)
  2065. );
  2066. status = IoGetDeviceProperty(PhysicalDeviceObject,
  2067. DevicePropertyLegacyBusType,
  2068. sizeof(privateDeviceDescription.InterfaceType),
  2069. (PVOID)&(privateDeviceDescription.InterfaceType),
  2070. &resultLength
  2071. );
  2072. if (!NT_SUCCESS(status)) {
  2073. ASSERT(status == STATUS_OBJECT_NAME_NOT_FOUND);
  2074. //
  2075. // Since the enumerator didn't tell us what interface type to
  2076. // use for this PDO, we'll fall back to our default. This is
  2077. // ISA for machines where the legacy bus is ISA or EISA, and it
  2078. // is MCA for machines whose legacy bus is MicroChannel.
  2079. //
  2080. privateDeviceDescription.InterfaceType = PnpDefaultInterfaceType;
  2081. }
  2082. //
  2083. // Use our private device description buffer from now on.
  2084. //
  2085. deviceDescriptionToUse = &privateDeviceDescription;
  2086. } else {
  2087. //
  2088. // Use the caller-supplied device description.
  2089. //
  2090. deviceDescriptionToUse = DeviceDescription;
  2091. }
  2092. //
  2093. // Now, query for the BUS_INTERFACE_STANDARD interface from the PDO.
  2094. //
  2095. KeInitializeEvent( &event, NotificationEvent, FALSE );
  2096. targetDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  2097. irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
  2098. targetDevice,
  2099. NULL,
  2100. 0,
  2101. NULL,
  2102. &event,
  2103. &ioStatusBlock );
  2104. if (irp == NULL) {
  2105. return NULL;
  2106. }
  2107. RtlZeroMemory( &busInterface, sizeof( BUS_INTERFACE_STANDARD ));
  2108. irpStack = IoGetNextIrpStackLocation( irp );
  2109. irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  2110. irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_INTERFACE_STANDARD;
  2111. irpStack->Parameters.QueryInterface.Size = sizeof( BUS_INTERFACE_STANDARD );
  2112. irpStack->Parameters.QueryInterface.Version = 1;
  2113. irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) &busInterface;
  2114. irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  2115. //
  2116. // Initialize the status to error in case the ACPI driver decides not to
  2117. // set it correctly.
  2118. //
  2119. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2120. status = IoCallDriver(targetDevice, irp);
  2121. if (status == STATUS_PENDING) {
  2122. KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
  2123. status = ioStatusBlock.Status;
  2124. }
  2125. ObDereferenceObject(targetDevice);
  2126. if (NT_SUCCESS( status)) {
  2127. if (busInterface.GetDmaAdapter != NULL) {
  2128. dmaAdapter = busInterface.GetDmaAdapter( busInterface.Context,
  2129. deviceDescriptionToUse,
  2130. NumberOfMapRegisters );
  2131. }
  2132. //
  2133. // Dereference the interface
  2134. //
  2135. busInterface.InterfaceDereference( busInterface.Context );
  2136. }
  2137. } else {
  2138. //
  2139. // The caller didn't specify the PDO, so we'll just use the device
  2140. // description exactly as they specified it (i.e., we can't attempt to
  2141. // make our own determination of what interface type to use).
  2142. //
  2143. deviceDescriptionToUse = DeviceDescription;
  2144. }
  2145. //
  2146. // If there is no DMA adapter, try the legacy mode code.
  2147. //
  2148. #if !defined(NO_LEGACY_DRIVERS)
  2149. if (dmaAdapter == NULL) {
  2150. dmaAdapter = HalGetDmaAdapter( PhysicalDeviceObject,
  2151. deviceDescriptionToUse,
  2152. NumberOfMapRegisters );
  2153. }
  2154. #endif // NO_LEGACY_DRIVERS
  2155. return( dmaAdapter );
  2156. }
  2157. NTSTATUS
  2158. IopOpenDeviceParametersSubkey(
  2159. OUT HANDLE *ParamKeyHandle,
  2160. IN HANDLE ParentKeyHandle,
  2161. IN PUNICODE_STRING SubKeyString,
  2162. IN ACCESS_MASK DesiredAccess
  2163. )
  2164. /*++
  2165. Routine Description:
  2166. This routine opens or creates a "Device Parameters" subkey of the specified
  2167. ParentKeyHandle. If this routine creates a new "Device Parameters" subkey,
  2168. it will apply the necessary ACLs to it.
  2169. Parameters:
  2170. ParamKeyHandle - Supplies the address of a variable that receives a handle
  2171. to the opened "Device Parameters" subkey. The caller must call ZwClose
  2172. to close the handle returned from this api when access is no longer
  2173. required.
  2174. ParentKeyHandle - Supplies a handle to the base key off which the path
  2175. specified by the SubStringKey parameter will be opened.
  2176. SubKeyString - Supplies a path to the subkey that should be opened under the
  2177. ParentKeyHandle, such that the resulting key will serve as the parent of
  2178. the "Device Parameters" subkey.
  2179. DesiredAccess - Specifies the access mask for the key to be opened.
  2180. Return Value:
  2181. NTSTATUS code.
  2182. --*/
  2183. {
  2184. NTSTATUS status;
  2185. ULONG disposition;
  2186. ULONG lengthSD;
  2187. PSECURITY_DESCRIPTOR oldSD = NULL;
  2188. SECURITY_DESCRIPTOR newSD;
  2189. ACL_SIZE_INFORMATION aclSizeInfo;
  2190. PACL oldDacl;
  2191. PACL newDacl = NULL;
  2192. ULONG sizeDacl;
  2193. BOOLEAN daclPresent, daclDefaulted;
  2194. PACCESS_ALLOWED_ACE ace;
  2195. ULONG aceIndex;
  2196. HANDLE deviceKeyHandle;
  2197. UNICODE_STRING deviceParamString;
  2198. //
  2199. // First try and open the device key
  2200. //
  2201. status = IopOpenRegistryKeyEx( &deviceKeyHandle,
  2202. ParentKeyHandle,
  2203. SubKeyString,
  2204. KEY_WRITE
  2205. );
  2206. if (!NT_SUCCESS(status)) {
  2207. return status;
  2208. }
  2209. PiWstrToUnicodeString(&deviceParamString, REGSTR_KEY_DEVICEPARAMETERS);
  2210. status = IopCreateRegistryKeyEx( ParamKeyHandle,
  2211. deviceKeyHandle,
  2212. &deviceParamString,
  2213. DesiredAccess | READ_CONTROL | WRITE_DAC,
  2214. REG_OPTION_NON_VOLATILE,
  2215. &disposition
  2216. );
  2217. ZwClose(deviceKeyHandle);
  2218. if (!NT_SUCCESS(status)) {
  2219. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2220. "IopOpenDeviceParametersSubkey: IopCreateRegistryKeyEx failed, status = %8.8X\n", status));
  2221. return status;
  2222. }
  2223. if (disposition == REG_CREATED_NEW_KEY) {
  2224. //
  2225. // Need to set an ACL on the key if it was created
  2226. //
  2227. //
  2228. // Get the security descriptor from the key so we can add the
  2229. // administrator.
  2230. //
  2231. status = ZwQuerySecurityObject(*ParamKeyHandle,
  2232. DACL_SECURITY_INFORMATION,
  2233. NULL,
  2234. 0,
  2235. &lengthSD);
  2236. if (status == STATUS_BUFFER_TOO_SMALL) {
  2237. oldSD = ExAllocatePool( PagedPool, lengthSD );
  2238. if (oldSD != NULL) {
  2239. status = ZwQuerySecurityObject(*ParamKeyHandle,
  2240. DACL_SECURITY_INFORMATION,
  2241. oldSD,
  2242. lengthSD,
  2243. &lengthSD);
  2244. if (!NT_SUCCESS(status)) {
  2245. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2246. "IopOpenDeviceParametersSubkey: ZwQuerySecurityObject failed, status = %8.8X\n", status));
  2247. goto Cleanup0;
  2248. }
  2249. } else {
  2250. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2251. "IopOpenDeviceParametersSubkey: Failed to allocate memory, status = %8.8X\n", status));
  2252. status = STATUS_NO_MEMORY;
  2253. goto Cleanup0;
  2254. }
  2255. } else {
  2256. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2257. "IopOpenDeviceParametersSubkey: ZwQuerySecurityObject failed %8.8X\n",status));
  2258. status = STATUS_UNSUCCESSFUL;
  2259. goto Cleanup0;
  2260. }
  2261. status = RtlCreateSecurityDescriptor( (PSECURITY_DESCRIPTOR) &newSD,
  2262. SECURITY_DESCRIPTOR_REVISION );
  2263. ASSERT( NT_SUCCESS( status ) );
  2264. if (!NT_SUCCESS(status)) {
  2265. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2266. "IopOpenDeviceParametersSubkey: RtlCreateSecurityDescriptor failed, status = %8.8X\n", status));
  2267. goto Cleanup0;
  2268. }
  2269. //
  2270. // get the current DACL
  2271. //
  2272. status = RtlGetDaclSecurityDescriptor(oldSD, &daclPresent, &oldDacl, &daclDefaulted);
  2273. //
  2274. // RtlGetDaclSecurityDescriptor will return either SUCCESS or a SD VERSION error
  2275. // if latter, then something wrong with ZwQuerySecurityObject
  2276. // or RtlGetDaclSecurityDescriptor changed
  2277. //
  2278. ASSERT(NT_SUCCESS(status));
  2279. if (!NT_SUCCESS(status)) {
  2280. IopDbgPrint(( IOP_IOAPI_ERROR_LEVEL,
  2281. "IopOpenDeviceParametersSubkey: RtlGetDaclSecurityDescriptor failed, status = %8.8X\n", status));
  2282. goto Cleanup0;
  2283. }
  2284. //
  2285. // calculate the size of the new DACL
  2286. //
  2287. if (daclPresent) {
  2288. status = RtlQueryInformationAcl( oldDacl,
  2289. &aclSizeInfo,
  2290. sizeof(ACL_SIZE_INFORMATION),
  2291. AclSizeInformation);
  2292. if (!NT_SUCCESS(status)) {
  2293. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2294. "IopOpenDeviceParametersSubkey: RtlQueryInformationAcl failed, status = %8.8X\n", status));
  2295. goto Cleanup0;
  2296. }
  2297. sizeDacl = aclSizeInfo.AclBytesInUse;
  2298. } else {
  2299. sizeDacl = sizeof(ACL);
  2300. aclSizeInfo.AceCount = 0;
  2301. }
  2302. sizeDacl += sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(SeAliasAdminsSid) - sizeof(ULONG);
  2303. //
  2304. // create and initialize the new DACL
  2305. //
  2306. newDacl = ExAllocatePool(PagedPool, sizeDacl);
  2307. if (newDacl == NULL) {
  2308. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2309. "IopOpenDeviceParametersSubkey: ExAllocatePool failed\n"));
  2310. goto Cleanup0;
  2311. }
  2312. status = RtlCreateAcl(newDacl, sizeDacl, ACL_REVISION);
  2313. if (!NT_SUCCESS(status)) {
  2314. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2315. "IopOpenDeviceParametersSubkey: RtlCreateAcl failed, status = %8.8X\n", status));
  2316. goto Cleanup0;
  2317. }
  2318. //
  2319. // copy the current (original) DACL into this new one
  2320. //
  2321. if (daclPresent) {
  2322. for (aceIndex = 0; aceIndex < aclSizeInfo.AceCount; aceIndex++) {
  2323. status = RtlGetAce(oldDacl, aceIndex, (PVOID *)&ace);
  2324. if (!NT_SUCCESS(status)) {
  2325. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2326. "IopOpenDeviceParametersSubkey: RtlGetAce failed, status = %8.8X\n", status));
  2327. goto Cleanup0;
  2328. }
  2329. //
  2330. // We need to skip copying any ACEs which refer to the Administrator
  2331. // to ensure that our full control ACE is the one and only.
  2332. //
  2333. if ((ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE &&
  2334. ace->Header.AceType != ACCESS_DENIED_ACE_TYPE) ||
  2335. !RtlEqualSid((PSID)&ace->SidStart, SeAliasAdminsSid)) {
  2336. status = RtlAddAce( newDacl,
  2337. ACL_REVISION,
  2338. ~0U,
  2339. ace,
  2340. ace->Header.AceSize
  2341. );
  2342. if (!NT_SUCCESS(status)) {
  2343. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2344. "IopOpenDeviceParametersSubkey: RtlAddAce failed, status = %8.8X\n", status));
  2345. goto Cleanup0;
  2346. }
  2347. }
  2348. }
  2349. }
  2350. //
  2351. // and my new admin-full ace to this new DACL
  2352. //
  2353. status = RtlAddAccessAllowedAceEx( newDacl,
  2354. ACL_REVISION,
  2355. CONTAINER_INHERIT_ACE,
  2356. KEY_ALL_ACCESS,
  2357. SeAliasAdminsSid
  2358. );
  2359. if (!NT_SUCCESS(status)) {
  2360. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2361. "IopOpenDeviceParametersSubkey: RtlAddAccessAllowedAceEx failed, status = %8.8X\n", status));
  2362. goto Cleanup0;
  2363. }
  2364. //
  2365. // Set the new DACL in the absolute security descriptor
  2366. //
  2367. status = RtlSetDaclSecurityDescriptor( (PSECURITY_DESCRIPTOR) &newSD,
  2368. TRUE,
  2369. newDacl,
  2370. FALSE
  2371. );
  2372. if (!NT_SUCCESS(status)) {
  2373. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2374. "IopOpenDeviceParametersSubkey: RtlSetDaclSecurityDescriptor failed, status = %8.8X\n", status));
  2375. goto Cleanup0;
  2376. }
  2377. //
  2378. // validate the new security descriptor
  2379. //
  2380. status = RtlValidSecurityDescriptor(&newSD);
  2381. if (!NT_SUCCESS(status)) {
  2382. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2383. "IopOpenDeviceParametersSubkey: RtlValidSecurityDescriptor failed, status = %8.8X\n", status));
  2384. goto Cleanup0;
  2385. }
  2386. status = ZwSetSecurityObject( *ParamKeyHandle,
  2387. DACL_SECURITY_INFORMATION,
  2388. &newSD
  2389. );
  2390. if (!NT_SUCCESS(status)) {
  2391. IopDbgPrint(( IOP_IOAPI_WARNING_LEVEL,
  2392. "IopOpenDeviceParametersSubkey: ZwSetSecurityObject failed, status = %8.8X\n", status));
  2393. goto Cleanup0;
  2394. }
  2395. }
  2396. //
  2397. // If we encounter an error updating the DACL we still return success.
  2398. //
  2399. Cleanup0:
  2400. if (oldSD != NULL) {
  2401. ExFreePool(oldSD);
  2402. }
  2403. if (newDacl != NULL) {
  2404. ExFreePool(newDacl);
  2405. }
  2406. return STATUS_SUCCESS;
  2407. }
  2408. NTSTATUS
  2409. PpCreateLegacyDeviceIds(
  2410. IN PDEVICE_OBJECT DeviceObject,
  2411. IN PUNICODE_STRING DriverName,
  2412. IN PCM_RESOURCE_LIST Resources
  2413. )
  2414. {
  2415. PIOPNP_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  2416. PWCHAR buffer, end;
  2417. ULONG length = 0;
  2418. INTERFACE_TYPE interface;
  2419. static const WCHAR* interfaceNames[] ={L"",
  2420. L"Internal",
  2421. L"Isa",
  2422. L"Eisa",
  2423. L"MicroChannel",
  2424. L"TurboChannel",
  2425. L"PCIBus",
  2426. L"VMEBus",
  2427. L"NuBus",
  2428. L"PCMCIABus",
  2429. L"CBus",
  2430. L"MPIBus",
  2431. L"MPSABus",
  2432. L"ProcessorInternal",
  2433. L"InternalPowerBus",
  2434. L"PNPISABus",
  2435. L"PNPBus",
  2436. L"Other",
  2437. L"Root"};
  2438. PAGED_CODE();
  2439. if(Resources != NULL) {
  2440. interface = Resources->List[0].InterfaceType;
  2441. if((interface > MaximumInterfaceType) ||
  2442. (interface < InterfaceTypeUndefined)) {
  2443. interface = MaximumInterfaceType;
  2444. }
  2445. } else {
  2446. interface = Internal;
  2447. }
  2448. interface++;
  2449. //
  2450. // The compatible ID generated will be
  2451. // DETECTED<InterfaceName>\<Driver Name>
  2452. //
  2453. length = (ULONG)(wcslen(LEGACY_COMPATIBLE_ID_BASE) * sizeof(WCHAR));
  2454. length += (ULONG)(wcslen(interfaceNames[interface]) * sizeof(WCHAR));
  2455. length += sizeof(L'\\');
  2456. length += DriverName->Length;
  2457. length += sizeof(UNICODE_NULL);
  2458. length += (ULONG)(wcslen(LEGACY_COMPATIBLE_ID_BASE) * sizeof(WCHAR));
  2459. length += sizeof(L'\\');
  2460. length += DriverName->Length;
  2461. length += sizeof(UNICODE_NULL) * 2;
  2462. buffer = ExAllocatePool(PagedPool, length);
  2463. deviceExtension->CompatibleIdList = buffer;
  2464. if(buffer == NULL) {
  2465. return STATUS_INSUFFICIENT_RESOURCES;
  2466. }
  2467. deviceExtension->CompatibleIdListSize = length;
  2468. RtlZeroMemory(buffer, length);
  2469. StringCchPrintfExW(
  2470. buffer,
  2471. length / sizeof(WCHAR),
  2472. &end,
  2473. NULL,
  2474. 0,
  2475. L"%ws%ws\\%wZ",
  2476. LEGACY_COMPATIBLE_ID_BASE,
  2477. interfaceNames[interface],
  2478. DriverName);
  2479. //
  2480. // Adjust the buffer to point to the end and generate the second
  2481. // compatible id string.
  2482. //
  2483. length = (ULONG)(end - buffer);
  2484. buffer = end + 1;
  2485. StringCchPrintfW(buffer, length, L"%ws\\%wZ", LEGACY_COMPATIBLE_ID_BASE, DriverName);
  2486. return STATUS_SUCCESS;
  2487. }
  2488. BOOLEAN
  2489. IopAppendLegacyVeto(
  2490. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context,
  2491. IN PUNICODE_STRING VetoName
  2492. )
  2493. /*++
  2494. Routine Description:
  2495. This routine appends a veto (driver name or device instance path) to the
  2496. veto list.
  2497. Parameters:
  2498. Context - An IO_GET_LEGACY_VETO_LIST_CONTEXT pointer.
  2499. VetoName - The name of the driver/device to append to the veto list.
  2500. ReturnValue:
  2501. A BOOLEAN which indicates whether the append operation was successful.
  2502. --*/
  2503. {
  2504. ULONG Length;
  2505. PWSTR Buffer;
  2506. //
  2507. // Compute the length of the (new) veto list. This is the length of
  2508. // the old veto list + the size of the new veto + the size of the
  2509. // terminating '\0'.
  2510. //
  2511. Length = Context->VetoListLength + VetoName->Length + sizeof (WCHAR);
  2512. //
  2513. // Allocate the new veto list.
  2514. //
  2515. Buffer = ExAllocatePool(
  2516. NonPagedPool,
  2517. Length
  2518. );
  2519. //
  2520. // If we succeeded in allocating the new veto list, copy the old
  2521. // veto list to the new list, append the new veto, and finally,
  2522. // append a terminating '\0'. Otherwise, update the status to
  2523. // indicate an error; IopGetLegacyVetoList will free the veto list
  2524. // before it returns.
  2525. //
  2526. if (Buffer != NULL) {
  2527. if (*Context->VetoList != NULL) {
  2528. RtlCopyMemory(
  2529. Buffer,
  2530. *Context->VetoList,
  2531. Context->VetoListLength
  2532. );
  2533. ExFreePool(*Context->VetoList);
  2534. }
  2535. RtlCopyMemory(
  2536. &Buffer[Context->VetoListLength / sizeof (WCHAR)],
  2537. VetoName->Buffer,
  2538. VetoName->Length
  2539. );
  2540. Buffer[Length / sizeof (WCHAR) - 1] = L'\0';
  2541. *Context->VetoList = Buffer;
  2542. Context->VetoListLength = Length;
  2543. return TRUE;
  2544. } else {
  2545. *Context->Status = STATUS_INSUFFICIENT_RESOURCES;
  2546. return FALSE;
  2547. }
  2548. }
  2549. BOOLEAN
  2550. IopGetLegacyVetoListDevice(
  2551. IN PDEVICE_NODE DeviceNode,
  2552. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context
  2553. )
  2554. /*++
  2555. Routine Description:
  2556. This routine determines whether the specified device node should be added to
  2557. the veto list, and if so, calls IopAppendLegacyVeto to add it.
  2558. Parameters:
  2559. DeviceNode - The device node to be added.
  2560. Context - An IO_GET_LEGACY_VETO_LIST_CONTEXT pointer.
  2561. ReturnValue:
  2562. A BOOLEAN value which indicates whether the device node enumeration
  2563. process should be terminated or not.
  2564. --*/
  2565. {
  2566. PDEVICE_CAPABILITIES DeviceCapabilities;
  2567. //
  2568. // A device node should be added added to the veto list, if it has the
  2569. // NonDynamic capability.
  2570. //
  2571. DeviceCapabilities = IopDeviceNodeFlagsToCapabilities(DeviceNode);
  2572. if (DeviceCapabilities->NonDynamic) {
  2573. //
  2574. // Update the veto type. If an error occurrs while adding the device
  2575. // node to the veto list, or the caller did not provide a veto list
  2576. // pointer, terminate the enumeration process now.
  2577. //
  2578. *Context->VetoType = PNP_VetoLegacyDevice;
  2579. if (Context->VetoList != NULL) {
  2580. if (!IopAppendLegacyVeto(Context, &DeviceNode->InstancePath)) {
  2581. return FALSE;
  2582. }
  2583. } else {
  2584. return FALSE;
  2585. }
  2586. }
  2587. return TRUE;
  2588. }
  2589. BOOLEAN
  2590. IopGetLegacyVetoListDeviceNode(
  2591. IN PDEVICE_NODE DeviceNode,
  2592. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context
  2593. )
  2594. /*++
  2595. Routine Description:
  2596. This routine recusively walks the device tree, invoking
  2597. IopGetLegacyVetoListDevice to add device nodes to the veto list
  2598. (as appropriate).
  2599. Parameters:
  2600. DeviceNode - The device node.
  2601. Context - An IO_GET_LEGACY_VETO_LIST_CONTEXT pointer.
  2602. ReturnValue:
  2603. A BOOLEAN value which indicates whether the device tree enumeration
  2604. process should be terminated or not.
  2605. --*/
  2606. {
  2607. PDEVICE_NODE Child;
  2608. //
  2609. // Determine whether the device node should be added to the veto
  2610. // list and add it. If an operation is unsuccessful or we determine
  2611. // the veto type but the caller doesn't need the veto list, then we
  2612. // terminate our search now.
  2613. //
  2614. if (!IopGetLegacyVetoListDevice(DeviceNode, Context)) {
  2615. return FALSE;
  2616. }
  2617. //
  2618. // Call ourselves recursively to enumerate our children. If while
  2619. // enumerating our children we determine we can terminate the search
  2620. // prematurely, do so.
  2621. //
  2622. for (Child = DeviceNode->Child;
  2623. Child != NULL;
  2624. Child = Child->Sibling) {
  2625. if (!IopGetLegacyVetoListDeviceNode(Child, Context)) {
  2626. return FALSE;
  2627. }
  2628. }
  2629. return TRUE;
  2630. }
  2631. VOID
  2632. IopGetLegacyVetoListDrivers(
  2633. IN PIO_GET_LEGACY_VETO_LIST_CONTEXT Context
  2634. )
  2635. {
  2636. PDRIVER_OBJECT driverObject;
  2637. OBJECT_ATTRIBUTES attributes;
  2638. UNICODE_STRING driverString;
  2639. POBJECT_DIRECTORY_INFORMATION dirInfo;
  2640. HANDLE directoryHandle;
  2641. ULONG dirInfoLength, neededLength, dirContext;
  2642. NTSTATUS status;
  2643. BOOLEAN restartScan;
  2644. dirInfoLength = 0;
  2645. dirInfo = NULL;
  2646. restartScan = TRUE;
  2647. //
  2648. // Get handle to \\Driver directory
  2649. //
  2650. PiWstrToUnicodeString(&driverString, L"\\Driver");
  2651. InitializeObjectAttributes(&attributes,
  2652. &driverString,
  2653. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2654. NULL,
  2655. NULL
  2656. );
  2657. status = ZwOpenDirectoryObject(&directoryHandle,
  2658. DIRECTORY_QUERY,
  2659. &attributes
  2660. );
  2661. if (!NT_SUCCESS(status)) {
  2662. *Context->Status = status;
  2663. return;
  2664. }
  2665. for (;;) {
  2666. //
  2667. // Get info on next object in directory. If the buffer is too
  2668. // small, reallocate it and try again. Otherwise, any failure
  2669. // including STATUS_NO_MORE_ENTRIES breaks us out.
  2670. //
  2671. status = ZwQueryDirectoryObject(directoryHandle,
  2672. dirInfo,
  2673. dirInfoLength,
  2674. TRUE, // force one at a time
  2675. restartScan,
  2676. &dirContext,
  2677. &neededLength);
  2678. if (status == STATUS_BUFFER_TOO_SMALL) {
  2679. dirInfoLength = neededLength;
  2680. if (dirInfo != NULL) {
  2681. ExFreePool(dirInfo);
  2682. }
  2683. dirInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, dirInfoLength);
  2684. if (dirInfo == NULL) {
  2685. *Context->Status = STATUS_INSUFFICIENT_RESOURCES;
  2686. break;
  2687. }
  2688. status = ZwQueryDirectoryObject(directoryHandle,
  2689. dirInfo,
  2690. dirInfoLength,
  2691. TRUE, // force one at a time
  2692. restartScan,
  2693. &dirContext,
  2694. &neededLength);
  2695. }
  2696. restartScan = FALSE;
  2697. if (!NT_SUCCESS(status)) {
  2698. break;
  2699. }
  2700. //
  2701. // Have name of object. Create object path and use
  2702. // ObReferenceObjectByName() to get DriverObject. This may
  2703. // fail non-fatally if DriverObject has gone away in the interim.
  2704. //
  2705. driverString.MaximumLength = sizeof(L"\\Driver\\") +
  2706. dirInfo->Name.Length;
  2707. driverString.Length = driverString.MaximumLength - sizeof(WCHAR);
  2708. driverString.Buffer = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION,
  2709. driverString.MaximumLength);
  2710. if (driverString.Buffer == NULL) {
  2711. *Context->Status = STATUS_INSUFFICIENT_RESOURCES;
  2712. break;
  2713. }
  2714. StringCbPrintfW(driverString.Buffer, driverString.MaximumLength, L"\\Driver\\%ws", dirInfo->Name.Buffer);
  2715. status = ObReferenceObjectByName(&driverString,
  2716. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  2717. NULL, // access state
  2718. 0, // access mask
  2719. IoDriverObjectType,
  2720. KernelMode,
  2721. NULL, // parse context
  2722. &driverObject);
  2723. ExFreePool(driverString.Buffer);
  2724. if (NT_SUCCESS(status)) {
  2725. ASSERT(driverObject->Type == IO_TYPE_DRIVER);
  2726. if (driverObject->Flags & DRVO_LEGACY_RESOURCES) {
  2727. //
  2728. // Update the veto type. If the caller provided a
  2729. // veto list pointer, add the driver to the veto list.
  2730. // If an error occurs while adding the driver to the
  2731. // veto list, or the caller did not provide a veto
  2732. // list pointer, terminate the driver enumeration now.
  2733. //
  2734. // NOTE: Driver may be loaded but not running,
  2735. // distinction is not made here.
  2736. *Context->VetoType = PNP_VetoLegacyDriver;
  2737. if (Context->VetoList != NULL) {
  2738. IopAppendLegacyVeto(Context, &dirInfo->Name);
  2739. }
  2740. }
  2741. ObDereferenceObject(driverObject);
  2742. //
  2743. // Early out if we have a veto and the caller didn't want a list or
  2744. // we hit some error already
  2745. //
  2746. if (((*Context->VetoType == PNP_VetoLegacyDriver) &&
  2747. (Context->VetoList == NULL)) ||
  2748. !NT_SUCCESS(*Context->Status)) {
  2749. break;
  2750. }
  2751. }
  2752. }
  2753. if (dirInfo != NULL) {
  2754. ExFreePool(dirInfo);
  2755. }
  2756. ZwClose(directoryHandle);
  2757. }
  2758. NTSTATUS
  2759. IoGetLegacyVetoList(
  2760. OUT PWSTR *VetoList OPTIONAL,
  2761. OUT PPNP_VETO_TYPE VetoType
  2762. )
  2763. /*++
  2764. Routine Description:
  2765. This routine is used by PNP and PO to determine whether legacy drivers and
  2766. devices are installed in the system. This routine is conceptually a
  2767. QUERY_REMOVE_DEVICE and QUERY_POWER-like interface for legacy drivers
  2768. and devices.
  2769. Parameters:
  2770. VetoList - A pointer to a PWSTR. (Optional) If specified,
  2771. IoGetLegacyVetoList will allocate a veto list, and return a
  2772. pointer to the veto list in VetoList.
  2773. VetoType - A pointer to a PNP_VETO_TYPE. If no legacy drivers
  2774. or devices are found in the system, VetoType is assigned
  2775. PNP_VetoTypeUnknown. If one or more legacy drivers are installed,
  2776. VetoType is assigned PNP_VetoLegacyDriver. If one or more
  2777. legacy devices are installed, VetoType is assigned
  2778. PNP_VetoLegacyDevice. VetoType is assigned independent of
  2779. whether a VetoList is created.
  2780. ReturnValue:
  2781. An NTSTATUS value indicating whether the IoGetLegacyVetoList() operation
  2782. was successful.
  2783. --*/
  2784. {
  2785. NTSTATUS Status;
  2786. IO_GET_LEGACY_VETO_LIST_CONTEXT Context;
  2787. UNICODE_STRING UnicodeString;
  2788. PAGED_CODE();
  2789. //
  2790. // Initialize the veto list.
  2791. //
  2792. if (VetoList != NULL) {
  2793. *VetoList = NULL;
  2794. }
  2795. //
  2796. // Initialize the veto type.
  2797. //
  2798. ASSERT(VetoType != NULL);
  2799. *VetoType = PNP_VetoTypeUnknown;
  2800. //
  2801. // Initialize the status.
  2802. //
  2803. Status = STATUS_SUCCESS;
  2804. if (PnPInitialized == FALSE) {
  2805. //
  2806. // Can't touch anything, but nothing is really started either.
  2807. //
  2808. return Status;
  2809. }
  2810. //
  2811. // Initialize our local context.
  2812. //
  2813. Context.VetoList = VetoList;
  2814. Context.VetoListLength = 0;
  2815. Context.VetoType = VetoType;
  2816. Context.Status = &Status;
  2817. //
  2818. // Enumerate all driver objects. This process can: (1) modify
  2819. // the veto list, (2) modify the veto type and/or (3) modify the
  2820. // status.
  2821. //
  2822. IopGetLegacyVetoListDrivers(&Context);
  2823. //
  2824. // If the driver enumeration process was successful and no legacy
  2825. // drivers were detected, enumerate all device nodes. The same
  2826. // context values as above may be modified during device enumeration.
  2827. //
  2828. if (NT_SUCCESS(Status)) {
  2829. if (*VetoType == PNP_VetoTypeUnknown) {
  2830. PpDevNodeLockTree(PPL_SIMPLE_READ);
  2831. IopGetLegacyVetoListDeviceNode(
  2832. IopRootDeviceNode,
  2833. &Context
  2834. );
  2835. PpDevNodeUnlockTree(PPL_SIMPLE_READ);
  2836. }
  2837. }
  2838. //
  2839. // If the previous operation(s) was/were successful, and the caller
  2840. // provided a veto list pointer and we have constructed a veto
  2841. // list, terminate the veto list with an empty string, i.e. MULTI_SZ.
  2842. //
  2843. if (NT_SUCCESS(Status)) {
  2844. if (*VetoType != PNP_VetoTypeUnknown) {
  2845. if (VetoList != NULL) {
  2846. PiWstrToUnicodeString(
  2847. &UnicodeString,
  2848. L""
  2849. );
  2850. IopAppendLegacyVeto(
  2851. &Context,
  2852. &UnicodeString
  2853. );
  2854. }
  2855. }
  2856. }
  2857. //
  2858. // If a previous operation was unsuccessful, free any veto list we may have
  2859. // allocated along the way.
  2860. //
  2861. if (!NT_SUCCESS(Status)) {
  2862. if (VetoList != NULL && *VetoList != NULL) {
  2863. ExFreePool(*VetoList);
  2864. *VetoList = NULL;
  2865. }
  2866. }
  2867. return Status;
  2868. }
  2869. NTSTATUS
  2870. PnpCompletionRoutine(
  2871. IN PDEVICE_OBJECT DeviceObject,
  2872. IN PIRP Irp,
  2873. IN PKEVENT Event
  2874. )
  2875. /*++
  2876. Routine Description:
  2877. This function is used to stop further processing on an Irp which has been
  2878. passed to IoForwardAndCatchIrp. It signals a event which has been passed
  2879. in the context parameter to indicate that the Irp processing is complete.
  2880. It then returns STATUS_MORE_PROCESSING_REQUIRED in order to stop processing
  2881. on this Irp.
  2882. Arguments:
  2883. DeviceObject -
  2884. Contains the device which set up this completion routine.
  2885. Irp -
  2886. Contains the Irp which is being stopped.
  2887. Event -
  2888. Contains the event which is used to signal that this Irp has been
  2889. completed.
  2890. Return Value:
  2891. Returns STATUS_MORE_PROCESSING_REQUIRED in order to stop processing on the
  2892. Irp.
  2893. --*/
  2894. {
  2895. UNREFERENCED_PARAMETER( DeviceObject );
  2896. UNREFERENCED_PARAMETER( Irp );
  2897. //
  2898. // This will allow the ForwardAndCatchIrp call to continue on its way.
  2899. //
  2900. KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
  2901. //
  2902. // This will ensure that nothing else touches the Irp, since the original
  2903. // caller has now continued, and the Irp may not exist anymore.
  2904. //
  2905. return STATUS_MORE_PROCESSING_REQUIRED;
  2906. }
  2907. NTKERNELAPI
  2908. BOOLEAN
  2909. IoForwardAndCatchIrp(
  2910. IN PDEVICE_OBJECT DeviceObject,
  2911. IN PIRP Irp
  2912. )
  2913. /*++
  2914. Routine Description:
  2915. This function is used with devices which may be stacked, and may not use
  2916. file objects to communicate.
  2917. Forwards an IRP to the specified driver after initializing the next
  2918. stack location, and regains control of the Irp on completion from that
  2919. driver.
  2920. Arguments:
  2921. DeviceObject -
  2922. Contains the device to forward the Irp to.
  2923. Irp -
  2924. Contains the Irp which is being forwarded to the specified driver.
  2925. Return Value:
  2926. Returns TRUE if the IRP was forwarded, else FALSE if no stack space
  2927. was available.
  2928. --*/
  2929. {
  2930. KEVENT Event;
  2931. PAGED_CODE();
  2932. //
  2933. // Ensure that there is another stack location before copying parameters.
  2934. //
  2935. ASSERT(Irp->CurrentLocation > 1);
  2936. if (Irp->CurrentLocation == 1) {
  2937. return FALSE;
  2938. }
  2939. IoCopyCurrentIrpStackLocationToNext(Irp);
  2940. //
  2941. // Set up a completion routine so that the Irp is not actually
  2942. // completed. Thus the caller can get control of the Irp back after
  2943. // this next driver is done with it.
  2944. //
  2945. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  2946. IoSetCompletionRoutine(Irp, PnpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
  2947. if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING) {
  2948. //
  2949. // Wait for completion which will occur when the CompletionRoutine
  2950. // signals this event. Wait in KernelMode so that the current stack
  2951. // is not paged out, since there is an event object on this stack.
  2952. //
  2953. KeWaitForSingleObject(
  2954. &Event,
  2955. Suspended,
  2956. KernelMode,
  2957. FALSE,
  2958. NULL);
  2959. }
  2960. return TRUE;
  2961. }
  2962. NTSTATUS
  2963. IoGetDeviceInstanceName(
  2964. IN PDEVICE_OBJECT PhysicalDeviceObject,
  2965. OUT PUNICODE_STRING InstanceName
  2966. )
  2967. {
  2968. NTSTATUS status;
  2969. PDEVICE_NODE deviceNode;
  2970. ASSERT_PDO(PhysicalDeviceObject);
  2971. deviceNode = PhysicalDeviceObject->DeviceObjectExtension->DeviceNode;
  2972. status = PipConcatenateUnicodeStrings( InstanceName,
  2973. &deviceNode->InstancePath,
  2974. NULL);
  2975. return status;
  2976. }
  2977. VOID
  2978. IoControlPnpDeviceActionQueue(
  2979. BOOLEAN Lock
  2980. )
  2981. {
  2982. if (Lock) {
  2983. PiLockDeviceActionQueue();
  2984. } else {
  2985. PiUnlockDeviceActionQueue();
  2986. }
  2987. }