Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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