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.

6489 lines
200 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. pnpsubs.c
  5. Abstract:
  6. This module contains the plug-and-play subroutines for the
  7. I/O system.
  8. Author:
  9. Shie-Lin Tzong (shielint) 3-Jan-1995
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "pnpmgrp.h"
  15. #pragma hdrstop
  16. //
  17. // Data structure for each entry in the device reference table.
  18. //
  19. typedef struct _DEVICE_REFERENCE {
  20. PDEVICE_OBJECT DeviceObject; // PDO
  21. PUNICODE_STRING DeviceInstance; // Pointer to instance path for the devnode for the PDO
  22. } DEVICE_REFERENCE, *PDEVICE_REFERENCE;
  23. #ifdef POOL_TAGGING
  24. #undef ExAllocatePool
  25. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'uspP')
  26. #endif
  27. #define PpLogEvent(s, r, st, d, ds)
  28. //
  29. // Regular data segment
  30. //
  31. #ifdef ALLOC_DATA_PRAGMA
  32. #pragma data_seg()
  33. #endif
  34. //
  35. // Table to map InstancePath to DO.
  36. //
  37. RTL_GENERIC_TABLE PpDeviceReferenceTable;
  38. //
  39. // Lock to synchronize access to the table.
  40. //
  41. FAST_MUTEX PpDeviceReferenceTableLock;
  42. //
  43. // Table of BusType GUIDs
  44. //
  45. GUID *PpBusTypeGuidArray;
  46. //
  47. // Number of entries in the BusTypeGuid table.
  48. //
  49. ULONG PpBusTypeGuidCount;
  50. //
  51. // Maximum number of entries in the BusTypeGuid table.
  52. //
  53. ULONG PpBusTypeGuidCountMax;
  54. //
  55. // Lock used to synchronize access to the BusTypeGuid table.
  56. //
  57. FAST_MUTEX PpBusTypeGuidLock;
  58. //
  59. // Prototype of internal functions
  60. //
  61. VOID
  62. IopDisableDevice(
  63. IN PDEVICE_NODE DeviceNode
  64. );
  65. BOOLEAN
  66. IopDeleteKeyRecursiveCallback(
  67. IN HANDLE KeyHandle,
  68. IN PUNICODE_STRING KeyName,
  69. IN OUT PVOID Context
  70. );
  71. NTSTATUS
  72. PipGenerateMadeupNodeName (
  73. IN PUNICODE_STRING ServiceKeyName,
  74. OUT PUNICODE_STRING MadeupNodeName
  75. );
  76. RTL_GENERIC_COMPARE_RESULTS
  77. NTAPI
  78. PiCompareInstancePath (
  79. PRTL_GENERIC_TABLE Table,
  80. PVOID FirstStruct,
  81. PVOID SecondStruct
  82. );
  83. ULONG
  84. PiFixupID(
  85. IN PWCHAR ID,
  86. IN ULONG MaxIDLength,
  87. IN BOOLEAN Multi,
  88. IN ULONG AllowedSeparators,
  89. IN PUNICODE_STRING LogString OPTIONAL
  90. );
  91. #ifdef ALLOC_PRAGMA
  92. #pragma alloc_text(INIT, PpInitializeDeviceReferenceTable)
  93. #pragma alloc_text(INIT, PipRegMultiSzToUnicodeStrings)
  94. #pragma alloc_text(INIT, PipFreeUnicodeStringList)
  95. #pragma alloc_text(INIT, PpBusTypeGuidInitialize)
  96. #pragma alloc_text(PAGE, PipApplyFunctionToServiceInstances)
  97. #pragma alloc_text(PAGE, PipApplyFunctionToSubKeys)
  98. #pragma alloc_text(PAGE, IopCleanupDeviceRegistryValues)
  99. #pragma alloc_text(PAGE, IopCmResourcesToIoResources)
  100. #pragma alloc_text(PAGE, PipConcatenateUnicodeStrings)
  101. #pragma alloc_text(PAGE, PipCreateMadeupNode)
  102. #pragma alloc_text(PAGE, PipGenerateMadeupNodeName)
  103. #pragma alloc_text(PAGE, IopCreateRegistryKeyEx)
  104. #pragma alloc_text(PAGE, IopDeleteKeyRecursive)
  105. #pragma alloc_text(PAGE, IopDeleteKeyRecursiveCallback)
  106. #pragma alloc_text(PAGE, IopDeleteLegacyKey)
  107. #pragma alloc_text(PAGE, IopDetermineResourceListSize)
  108. #pragma alloc_text(PAGE, IopSaveDeviceCapabilities)
  109. #pragma alloc_text(PAGE, IopQueryAndSaveDeviceNodeCapabilities)
  110. #pragma alloc_text(PAGE, IopDeviceObjectFromDeviceInstance)
  111. #pragma alloc_text(PAGE, IopDeviceObjectToDeviceInstance)
  112. #pragma alloc_text(PAGE, IopDisableDevice)
  113. #pragma alloc_text(PAGE, IopDriverLoadingFailed)
  114. #pragma alloc_text(PAGE, IopFilterResourceRequirementsList)
  115. #pragma alloc_text(PAGE, IopGetDeviceInstanceCsConfigFlags)
  116. #pragma alloc_text(PAGE, IopGetDeviceResourcesFromRegistry)
  117. #pragma alloc_text(PAGE, PipGetServiceInstanceCsConfigFlags)
  118. #pragma alloc_text(PAGE, IopIsAnyDeviceInstanceEnabled)
  119. #pragma alloc_text(PAGE, IopIsDeviceInstanceEnabled)
  120. #pragma alloc_text(PAGE, PipIsDuplicatedDevices)
  121. #pragma alloc_text(PAGE, IopIsLegacyDriver)
  122. #pragma alloc_text(PAGE, IopMergeCmResourceLists)
  123. #pragma alloc_text(PAGE, IopMergeFilteredResourceRequirementsList)
  124. #pragma alloc_text(PAGE, IopOpenCurrentHwProfileDeviceInstanceKey)
  125. #pragma alloc_text(PAGE, IopOpenRegistryKeyEx)
  126. #pragma alloc_text(PAGE, PipOpenServiceEnumKeys)
  127. #pragma alloc_text(PAGE, IopPrepareDriverLoading)
  128. #pragma alloc_text(PAGE, PipReadDeviceConfiguration)
  129. #pragma alloc_text(PAGE, IopRestartDeviceNode)
  130. #pragma alloc_text(PAGE, PipServiceInstanceToDeviceInstance)
  131. #pragma alloc_text(PAGE, IopMapDeviceObjectToDeviceInstance)
  132. #pragma alloc_text(PAGE, PiRegSzToString)
  133. #pragma alloc_text(PAGE, PiCompareInstancePath)
  134. #pragma alloc_text(PAGE, PiAllocateGenericTableEntry)
  135. #pragma alloc_text(PAGE, PiFreeGenericTableEntry)
  136. #pragma alloc_text(PAGE, PpSystemHiveLimitCallback)
  137. #pragma alloc_text(PAGE, PpBusTypeGuidGetIndex)
  138. #pragma alloc_text(PAGE, PpBusTypeGuidGet)
  139. #pragma alloc_text(PAGE, PpQueryDeviceID)
  140. #pragma alloc_text(PAGE, PpQueryID)
  141. #pragma alloc_text(PAGE, PiFixupID)
  142. #if DBG
  143. #pragma alloc_text(PAGE, IopDebugPrint)
  144. #endif
  145. #endif
  146. NTSTATUS
  147. PipCreateMadeupNode(
  148. IN PUNICODE_STRING ServiceKeyName,
  149. OUT PHANDLE ReturnedHandle,
  150. OUT PUNICODE_STRING KeyName,
  151. OUT PULONG InstanceNumber,
  152. IN BOOLEAN ResourceOwned
  153. )
  154. /*++
  155. Routine Description:
  156. This routine creates a new instance node under System\Enum\Root\LEGACY_<ServiceKeyName>
  157. key and all the required default value entries. Also a value entry under
  158. Service\<ServiceKeyName>\Enum is created to point to the newly created madeup
  159. entry. A handle and the keyname of the new key are returned to caller.
  160. Caller must free the unicode string when he is done with it.
  161. Parameters:
  162. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  163. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  164. that caused the driver to load. This is the RegistryPath parameter
  165. to the DriverEntry routine.
  166. ReturnedHandle - Supplies a variable to receive the handle of the
  167. newly created key.
  168. KeyName - Supplies a variable to receive the name of the newly created
  169. key.
  170. InstanceNumber - supplies a variable to receive the InstanceNumber value
  171. entry created under service\name\enum subkey.
  172. ResourceOwned - supplies a BOOLEAN variable to indicate if caller owns
  173. the registry resource shared.
  174. ADRIAO N.B. 08/25/2000 - All users of this function pass in TRUE...
  175. Return Value:
  176. Status code that indicates whether or not the function was successful.
  177. --*/
  178. {
  179. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  180. UNICODE_STRING tmpKeyName, unicodeInstanceName, unicodeString;
  181. UNICODE_STRING rootKeyName, unicodeValueName, unicodeKeyName;
  182. HANDLE handle, enumRootHandle;
  183. ULONG instance;
  184. UCHAR unicodeBuffer[20];
  185. ULONG tmpValue, disposition = 0;
  186. NTSTATUS status;
  187. PWSTR p;
  188. BOOLEAN releaseResource = FALSE;
  189. BOOLEAN successful;
  190. if (!ResourceOwned) {
  191. PiLockPnpRegistry(FALSE);
  192. releaseResource = TRUE;
  193. }
  194. //
  195. // Open LocalMachine\System\CurrentControlSet\Enum\Root
  196. //
  197. status = IopOpenRegistryKeyEx( &enumRootHandle,
  198. NULL,
  199. &CmRegistryMachineSystemCurrentControlSetEnumRootName,
  200. KEY_ALL_ACCESS
  201. );
  202. if (!NT_SUCCESS(status)) {
  203. goto local_exit0;
  204. }
  205. //
  206. // Generate the LEGACY_<ServiceKeyName> device id name from the
  207. // ServiceKeyName.
  208. //
  209. status = PipGenerateMadeupNodeName( ServiceKeyName,
  210. &unicodeKeyName);
  211. if (!NT_SUCCESS(status)) {
  212. ZwClose(enumRootHandle);
  213. goto local_exit0;
  214. }
  215. //
  216. // Open, and create if not already exist,
  217. // System\Enum\Root\LEGACY_<ServiceKeyName>
  218. //
  219. status = IopCreateRegistryKeyEx( &handle,
  220. enumRootHandle,
  221. &unicodeKeyName,
  222. KEY_ALL_ACCESS,
  223. REG_OPTION_NON_VOLATILE,
  224. NULL
  225. );
  226. ZwClose(enumRootHandle);
  227. if (!NT_SUCCESS(status)) {
  228. RtlFreeUnicodeString(&unicodeKeyName);
  229. goto local_exit0;
  230. }
  231. instance = 1;
  232. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_NEXT_INSTANCE);
  233. status = ZwSetValueKey(
  234. handle,
  235. &unicodeValueName,
  236. TITLE_INDEX_VALUE,
  237. REG_DWORD,
  238. &instance,
  239. sizeof(instance)
  240. );
  241. instance--;
  242. *InstanceNumber = instance;
  243. PiUlongToInstanceKeyUnicodeString(&unicodeInstanceName,
  244. unicodeBuffer + sizeof(WCHAR), // reserve first WCHAR space
  245. 20 - sizeof(WCHAR),
  246. instance
  247. );
  248. status = IopCreateRegistryKeyEx( ReturnedHandle,
  249. handle,
  250. &unicodeInstanceName,
  251. KEY_ALL_ACCESS,
  252. REG_OPTION_NON_VOLATILE,
  253. &disposition
  254. );
  255. ZwClose(handle);
  256. if (!NT_SUCCESS(status)) {
  257. RtlFreeUnicodeString(&unicodeKeyName);
  258. goto local_exit0;
  259. }
  260. //
  261. // Prepare newly created registry key name for returning to caller
  262. //
  263. *(PWSTR)unicodeBuffer = OBJ_NAME_PATH_SEPARATOR;
  264. unicodeInstanceName.Buffer = (PWSTR)unicodeBuffer;
  265. unicodeInstanceName.Length += sizeof(WCHAR);
  266. unicodeInstanceName.MaximumLength += sizeof(WCHAR);
  267. PiWstrToUnicodeString(&rootKeyName, REGSTR_KEY_ROOTENUM);
  268. PiWstrToUnicodeString(&tmpKeyName, L"\\");
  269. successful = PipConcatenateUnicodeStrings(&unicodeString, &tmpKeyName, &unicodeKeyName);
  270. RtlFreeUnicodeString(&unicodeKeyName);
  271. if (!successful) {
  272. goto local_exit0;
  273. }
  274. successful = PipConcatenateUnicodeStrings(&tmpKeyName, &rootKeyName, &unicodeString);
  275. RtlFreeUnicodeString(&unicodeString);
  276. if (!successful) {
  277. goto local_exit0;
  278. }
  279. successful = PipConcatenateUnicodeStrings(KeyName, &tmpKeyName, &unicodeInstanceName);
  280. if (!successful) {
  281. RtlFreeUnicodeString(&tmpKeyName);
  282. goto local_exit0;
  283. }
  284. if (disposition == REG_CREATED_NEW_KEY) {
  285. //
  286. // Create all the default value entry for the newly created key.
  287. // Service = ServiceKeyName
  288. // FoundAtEnum = 1
  289. // Class = "LegacyDriver"
  290. // ClassGUID = GUID for legacy driver class
  291. // ConfigFlags = 0
  292. //
  293. // Create "Control" subkey with "NewlyCreated" value key
  294. //
  295. PiWstrToUnicodeString(&unicodeValueName, REGSTR_KEY_CONTROL);
  296. status = IopCreateRegistryKeyEx( &handle,
  297. *ReturnedHandle,
  298. &unicodeValueName,
  299. KEY_ALL_ACCESS,
  300. REG_OPTION_VOLATILE,
  301. NULL
  302. );
  303. if (NT_SUCCESS(status)) {
  304. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_NEWLY_CREATED);
  305. tmpValue = 0;
  306. ZwSetValueKey(handle,
  307. &unicodeValueName,
  308. TITLE_INDEX_VALUE,
  309. REG_DWORD,
  310. &tmpValue,
  311. sizeof(tmpValue)
  312. );
  313. ZwClose(handle);
  314. }
  315. handle = *ReturnedHandle;
  316. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_SERVICE);
  317. p = (PWSTR)ExAllocatePool(PagedPool,
  318. ServiceKeyName->Length + sizeof(UNICODE_NULL));
  319. if(p) {
  320. RtlCopyMemory(p, ServiceKeyName->Buffer, ServiceKeyName->Length);
  321. p[ServiceKeyName->Length / sizeof (WCHAR)] = UNICODE_NULL;
  322. ZwSetValueKey(
  323. handle,
  324. &unicodeValueName,
  325. TITLE_INDEX_VALUE,
  326. REG_SZ,
  327. p,
  328. ServiceKeyName->Length + sizeof(UNICODE_NULL)
  329. );
  330. //
  331. // We'll keep the null-terminated service name buffer around for a while,
  332. // because we may need it later on for the DeviceDesc in case the service
  333. // has no DisplayName.
  334. //
  335. // ExFreePool(p);
  336. }
  337. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_LEGACY);
  338. tmpValue = 1;
  339. ZwSetValueKey(
  340. handle,
  341. &unicodeValueName,
  342. TITLE_INDEX_VALUE,
  343. REG_DWORD,
  344. &tmpValue,
  345. sizeof(tmpValue)
  346. );
  347. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_CONFIG_FLAGS);
  348. tmpValue = 0;
  349. ZwSetValueKey(
  350. handle,
  351. &unicodeValueName,
  352. TITLE_INDEX_VALUE,
  353. REG_DWORD,
  354. &tmpValue,
  355. sizeof(tmpValue)
  356. );
  357. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_CLASS);
  358. ZwSetValueKey(
  359. handle,
  360. &unicodeValueName,
  361. TITLE_INDEX_VALUE,
  362. REG_SZ,
  363. REGSTR_VALUE_LEGACY_DRIVER,
  364. sizeof(REGSTR_VALUE_LEGACY_DRIVER)
  365. );
  366. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_CLASSGUID);
  367. ZwSetValueKey(
  368. handle,
  369. &unicodeValueName,
  370. TITLE_INDEX_VALUE,
  371. REG_SZ,
  372. (PVOID)&REGSTR_VALUE_LEGACY_DRIVER_CLASS_GUID,
  373. sizeof(REGSTR_VALUE_LEGACY_DRIVER_CLASS_GUID)
  374. );
  375. //
  376. // Initialize DeviceDesc= value entry. If the service key has a "DisplayName"
  377. // value entry, it is used as the DeviceDesc value. Otherwise, the service key
  378. // name is used.
  379. //
  380. status = PipOpenServiceEnumKeys(ServiceKeyName,
  381. KEY_READ,
  382. &handle,
  383. NULL,
  384. FALSE
  385. );
  386. if (NT_SUCCESS(status)) {
  387. keyValueInformation = NULL;
  388. unicodeString.Length = 0;
  389. status = IopGetRegistryValue(handle,
  390. REGSTR_VALUE_DISPLAY_NAME,
  391. &keyValueInformation
  392. );
  393. if (NT_SUCCESS(status)) {
  394. if (keyValueInformation->Type == REG_SZ) {
  395. if (keyValueInformation->DataLength > sizeof(UNICODE_NULL)) {
  396. IopRegistryDataToUnicodeString(&unicodeString,
  397. (PWSTR)KEY_VALUE_DATA(keyValueInformation),
  398. keyValueInformation->DataLength
  399. );
  400. }
  401. }
  402. }
  403. if ((unicodeString.Length == 0) && p) {
  404. //
  405. // No DisplayName--use the service key name.
  406. //
  407. unicodeString.Length = ServiceKeyName->Length;
  408. unicodeString.MaximumLength = ServiceKeyName->Length + sizeof(UNICODE_NULL);
  409. unicodeString.Buffer = p;
  410. }
  411. if(unicodeString.Length) {
  412. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_DEVICE_DESC);
  413. ZwSetValueKey(*ReturnedHandle,
  414. &unicodeValueName,
  415. TITLE_INDEX_VALUE,
  416. REG_SZ,
  417. unicodeString.Buffer,
  418. unicodeString.Length + sizeof(UNICODE_NULL)
  419. );
  420. }
  421. if (keyValueInformation) {
  422. ExFreePool(keyValueInformation);
  423. }
  424. ZwClose(handle);
  425. }
  426. if(p) {
  427. ExFreePool(p);
  428. }
  429. }
  430. //
  431. // Create new value entry under ServiceKeyName\Enum to reflect the newly
  432. // added made-up device instance node.
  433. //
  434. PiUnlockPnpRegistry();
  435. releaseResource = FALSE;
  436. status = PpDeviceRegistration( KeyName, TRUE, NULL );
  437. if (ResourceOwned) {
  438. PiLockPnpRegistry(FALSE);
  439. }
  440. RtlFreeUnicodeString(&tmpKeyName);
  441. if (!NT_SUCCESS( status )) {
  442. //
  443. // There is no registry key for the ServiceKeyName information.
  444. //
  445. ZwClose(*ReturnedHandle);
  446. RtlFreeUnicodeString(KeyName);
  447. }
  448. local_exit0:
  449. if (releaseResource) {
  450. PiUnlockPnpRegistry();
  451. }
  452. return status;
  453. }
  454. NTSTATUS
  455. PipGenerateMadeupNodeName (
  456. IN PUNICODE_STRING ServiceKeyName,
  457. OUT PUNICODE_STRING MadeupNodeName
  458. )
  459. /*++
  460. Routine Description:
  461. This routine parses the ServiceKeyName string and replaces any space
  462. characters with an underscore character, and any invalid characters (not
  463. allowed in a "device instance") with their hexadecimal character
  464. representation.
  465. Invalid characters are:
  466. c < 0x20 (' ')
  467. c > 0x7F
  468. c == 0x2C (',')
  469. The resulting modified ServiceKeyName string is used to create a valid
  470. device id. Paged pool space is allocated for the destination string.
  471. Caller must release the space once done with it.
  472. Arguments:
  473. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  474. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  475. that caused the driver to load. This is the RegistryPath parameter
  476. to the DriverEntry routine.
  477. MadeupNodeName - Supplies a variable to receive the name of madeup device
  478. id. If successful, the caller is responsible for freeing the allocated
  479. buffer.
  480. Return Value:
  481. Status code that indicates whether or not the function was successful.
  482. --*/
  483. {
  484. PWCHAR BufferEnd, p, q;
  485. ULONG length;
  486. PWSTR buffer;
  487. //
  488. // We'll need at least as much room as the size of the unicode service key
  489. // name, plus the LEGACY_ prefix and terminating NULL char..
  490. //
  491. length = sizeof(REGSTR_KEY_MADEUP) + ServiceKeyName->Length;
  492. p = ServiceKeyName->Buffer;
  493. BufferEnd = (PWCHAR)((PUCHAR)p + ServiceKeyName->Length);
  494. while(p != BufferEnd) {
  495. if ((*p < L' ') || (*p > (WCHAR)0x7F) || (*p == L',')) {
  496. //
  497. // Each "invalid" character will be replaced with a '*' character
  498. // (size already accounted for in calculated length), plus one
  499. // character for each nibble of each byte in the invalid character.
  500. //
  501. length += 2*sizeof(WCHAR)*sizeof(WCHAR);
  502. }
  503. p++;
  504. }
  505. //
  506. // Allocate a buffer large enough to hold the converted
  507. // LEGACY_<ServiceKeyName> string.
  508. //
  509. buffer = (PWSTR)ExAllocatePool(PagedPool, length);
  510. if (!buffer) {
  511. return STATUS_INSUFFICIENT_RESOURCES;
  512. }
  513. MadeupNodeName->Buffer = buffer;
  514. MadeupNodeName->Length = (USHORT)(length - sizeof(UNICODE_NULL));
  515. MadeupNodeName->MaximumLength = (USHORT)length;
  516. RtlCopyMemory(buffer, REGSTR_KEY_MADEUP, sizeof(REGSTR_KEY_MADEUP));
  517. q = buffer + (sizeof(REGSTR_KEY_MADEUP) - sizeof(UNICODE_NULL))/sizeof(WCHAR);
  518. p = ServiceKeyName->Buffer;
  519. BufferEnd = (PWCHAR)((PUCHAR)p + ServiceKeyName->Length);
  520. while(p != BufferEnd) {
  521. if (*p == L' ') {
  522. //
  523. // replace ' ' with '_'
  524. //
  525. *q = L'_';
  526. q++;
  527. } else if ((*p < L' ') || (*p > (WCHAR)0x7F) || (*p == L',')) {
  528. //
  529. // replace invalid characters with '*' plus a character string
  530. // representation of the hexadecimal digits.
  531. //
  532. int i, nibble;
  533. *q = L'*';
  534. q++;
  535. for (i = 1; i <= 2*sizeof(WCHAR); i++) {
  536. nibble = ((USHORT)((*p) >> (0x10 - 4*i)) & 0xF);
  537. *q = nibble > 9 ? (nibble - 10 + L'A') : (nibble + L'0');
  538. q++;
  539. }
  540. } else {
  541. //
  542. // copy the existing character.
  543. //
  544. *q = *p;
  545. q++;
  546. }
  547. p++;
  548. }
  549. *q = UNICODE_NULL;
  550. //
  551. // Upcase the resulting device id.
  552. //
  553. RtlUpcaseUnicodeString(MadeupNodeName, MadeupNodeName, FALSE);
  554. //
  555. // Sanity check to make sure that the device id we generated is valid. At
  556. // this point, there should be absolutely no reason that it wouldn't be.
  557. //
  558. if (!PiFixupID(MadeupNodeName->Buffer, MAX_DEVICE_ID_LEN, FALSE, 0, NULL)) {
  559. ASSERT(0);
  560. RtlFreeUnicodeString(MadeupNodeName);
  561. return STATUS_INVALID_PARAMETER;
  562. }
  563. return STATUS_SUCCESS;
  564. }
  565. BOOLEAN
  566. PipConcatenateUnicodeStrings (
  567. OUT PUNICODE_STRING Destination,
  568. IN PUNICODE_STRING String1,
  569. IN PUNICODE_STRING String2 OPTIONAL
  570. )
  571. /*++
  572. Routine Description:
  573. This routine returns a buffer containing the concatenation of the
  574. two specified strings. Since String2 is optional, this function may
  575. also be used to make a copy of a unicode string. Paged pool space
  576. is allocated for the destination string. Caller must release the
  577. space once done with it.
  578. Parameters:
  579. Destination - Supplies a variable to receive the concatenated
  580. UNICODE_STRING.
  581. String1 - Supplies a pointer to the frist UNICODE_STRING.
  582. String2 - Supplies an optional pointer to the second UNICODE_STRING.
  583. Return Value:
  584. Status code that indicates whether or not the function was successful.
  585. --*/
  586. {
  587. ULONG length;
  588. PWSTR buffer;
  589. length = String1->Length + sizeof(UNICODE_NULL);
  590. if (ARGUMENT_PRESENT(String2)) {
  591. length += String2->Length;
  592. }
  593. buffer = (PWSTR)ExAllocatePool(PagedPool, length);
  594. if (!buffer) {
  595. return FALSE;
  596. }
  597. Destination->Buffer = buffer;
  598. Destination->Length = (USHORT)length - sizeof(UNICODE_NULL);
  599. Destination->MaximumLength = (USHORT)length;
  600. RtlCopyMemory (buffer, String1->Buffer, String1->Length);
  601. if(ARGUMENT_PRESENT(String2)) {
  602. RtlCopyMemory((PUCHAR)buffer + String1->Length,
  603. String2->Buffer,
  604. String2->Length
  605. );
  606. }
  607. buffer[length / sizeof(WCHAR) - 1] = UNICODE_NULL;
  608. return TRUE;
  609. }
  610. NTSTATUS
  611. IopPrepareDriverLoading (
  612. IN PUNICODE_STRING KeyName,
  613. IN HANDLE KeyHandle,
  614. IN PVOID ImageBase,
  615. IN BOOLEAN IsFilter
  616. )
  617. /*++
  618. Routine Description:
  619. This routine first checks if the driver is loadable. If its a
  620. PnP driver, it will always be loaded (we trust it to do the right
  621. things.) If it is a legacy driver, we need to check if its device
  622. has been disabled. Once we decide to load the driver, the Enum
  623. subkey of the service node will be checked for duplicates, if any.
  624. Parameters:
  625. KeyName - Supplies a pointer to the driver's service key unicode string
  626. KeyHandle - Supplies a handle to the driver service node in the registry
  627. that describes the driver to be loaded.
  628. Return Value:
  629. The function value is the final status of the load operation.
  630. --*/
  631. {
  632. NTSTATUS status;
  633. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  634. ULONG tmp, count;
  635. HANDLE serviceEnumHandle = NULL, sysEnumXxxHandle, controlHandle;
  636. UNICODE_STRING unicodeKeyName, unicodeValueName;
  637. BOOLEAN IsPlugPlayDriver;
  638. PIMAGE_NT_HEADERS header;
  639. GUID blockedDriverGuid;
  640. header = RtlImageNtHeader(ImageBase);
  641. status = STATUS_SUCCESS;
  642. IsPlugPlayDriver = (header &&
  643. (header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_WDM_DRIVER))? TRUE : FALSE;
  644. if (!IopIsAnyDeviceInstanceEnabled(KeyName, KeyHandle, (BOOLEAN)(IsPlugPlayDriver ? FALSE : TRUE))) {
  645. if (!IsPlugPlayDriver) {
  646. PiLockPnpRegistry(FALSE);
  647. //
  648. // First open registry ServiceKeyName\Enum branch
  649. //
  650. PiWstrToUnicodeString(&unicodeKeyName, REGSTR_KEY_ENUM);
  651. status = IopCreateRegistryKeyEx( &serviceEnumHandle,
  652. KeyHandle,
  653. &unicodeKeyName,
  654. KEY_ALL_ACCESS,
  655. REG_OPTION_VOLATILE,
  656. NULL
  657. );
  658. if (NT_SUCCESS(status)) {
  659. //
  660. // Find out how many device instances listed in the ServiceName's
  661. // Enum key.
  662. //
  663. count = 0;
  664. status = IopGetRegistryValue ( serviceEnumHandle,
  665. REGSTR_VALUE_COUNT,
  666. &keyValueInformation);
  667. if (NT_SUCCESS(status)) {
  668. if ( keyValueInformation->Type == REG_DWORD &&
  669. keyValueInformation->DataLength >= sizeof(ULONG)) {
  670. count = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  671. }
  672. ExFreePool(keyValueInformation);
  673. }
  674. if ( NT_SUCCESS(status) ||
  675. status == STATUS_OBJECT_PATH_NOT_FOUND ||
  676. status == STATUS_OBJECT_NAME_NOT_FOUND) {
  677. if (count) {
  678. status = STATUS_PLUGPLAY_NO_DEVICE;
  679. } else {
  680. //
  681. // If there is no Enum key or instance under Enum for the
  682. // legacy driver we will create a madeup node for it.
  683. //
  684. status = PipCreateMadeupNode( KeyName,
  685. &sysEnumXxxHandle,
  686. &unicodeKeyName,
  687. &tmp,
  688. TRUE);
  689. if (NT_SUCCESS(status)) {
  690. RtlFreeUnicodeString(&unicodeKeyName);
  691. //
  692. // Create and set Control\ActiveService value
  693. //
  694. PiWstrToUnicodeString(&unicodeValueName, REGSTR_KEY_CONTROL);
  695. status = IopCreateRegistryKeyEx( &controlHandle,
  696. sysEnumXxxHandle,
  697. &unicodeValueName,
  698. KEY_ALL_ACCESS,
  699. REG_OPTION_VOLATILE,
  700. NULL
  701. );
  702. if (NT_SUCCESS(status)) {
  703. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VAL_ACTIVESERVICE);
  704. ZwSetValueKey( controlHandle,
  705. &unicodeValueName,
  706. TITLE_INDEX_VALUE,
  707. REG_SZ,
  708. KeyName->Buffer,
  709. KeyName->Length + sizeof(UNICODE_NULL));
  710. ZwClose(controlHandle);
  711. }
  712. count++;
  713. //
  714. // Don't forget to update the "Count=" and "NextInstance=" value entries
  715. //
  716. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_COUNT);
  717. ZwSetValueKey( serviceEnumHandle,
  718. &unicodeValueName,
  719. TITLE_INDEX_VALUE,
  720. REG_DWORD,
  721. &count,
  722. sizeof(count));
  723. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VALUE_NEXT_INSTANCE);
  724. ZwSetValueKey( serviceEnumHandle,
  725. &unicodeValueName,
  726. TITLE_INDEX_VALUE,
  727. REG_DWORD,
  728. &count,
  729. sizeof(count));
  730. ZwClose(sysEnumXxxHandle);
  731. status = STATUS_SUCCESS;
  732. }
  733. }
  734. }
  735. ZwClose(serviceEnumHandle);
  736. }
  737. PiUnlockPnpRegistry();
  738. }
  739. }
  740. if (NT_SUCCESS(status)) {
  741. RtlZeroMemory(&blockedDriverGuid, sizeof(GUID));
  742. status = PpCheckInDriverDatabase(
  743. KeyName,
  744. KeyHandle,
  745. ImageBase,
  746. header->OptionalHeader.SizeOfImage,
  747. IsFilter,
  748. &blockedDriverGuid);
  749. if (status == STATUS_DRIVER_BLOCKED ||
  750. status == STATUS_DRIVER_BLOCKED_CRITICAL) {
  751. //
  752. // Notify the user-mode Plug and Play manager that a driver was just
  753. // blocked.
  754. //
  755. PpSetBlockedDriverEvent(&blockedDriverGuid);
  756. }
  757. }
  758. return status;
  759. }
  760. NTSTATUS
  761. PipServiceInstanceToDeviceInstance (
  762. IN HANDLE ServiceKeyHandle OPTIONAL,
  763. IN PUNICODE_STRING ServiceKeyName OPTIONAL,
  764. IN ULONG ServiceInstanceOrdinal,
  765. OUT PUNICODE_STRING DeviceInstanceRegistryPath OPTIONAL,
  766. OUT PHANDLE DeviceInstanceHandle OPTIONAL,
  767. IN ACCESS_MASK DesiredAccess
  768. )
  769. /*++
  770. Routine Description:
  771. This routine reads the service node enum entry to find the desired device instance
  772. under the System\Enum tree. It then optionally returns the registry path of the
  773. specified device instance (relative to HKLM\System\Enum) and an open handle
  774. to that registry key.
  775. It is the caller's responsibility to close the handle returned if
  776. DeviceInstanceHandle is supplied, and also to free the (PagedPool) memory
  777. allocated for the unicode string buffer of DeviceInstanceRegistryPath, if
  778. supplied.
  779. Parameters:
  780. ServiceKeyHandle - Optionally, supplies a handle to the driver service node in the
  781. registry that controls this device instance. If this argument is not specified,
  782. then ServiceKeyName is used to specify the service entry.
  783. ServiceKeyName - Optionally supplies the name of the service entry that controls
  784. the device instance. This must be specified if ServiceKeyHandle isn't given.
  785. ServiceInstanceOrdinal - Supplies the instance value under the service entry's
  786. volatile Enum subkey that references the desired device instance.
  787. DeviceInstanceRegistryPath - Optionally, supplies a pointer to a unicode string
  788. that will be initialized with the registry path (relative to HKLM\System\Enum)
  789. to the device instance key.
  790. DeviceInstanceHandle - Optionally, supplies a pointer to a variable that will
  791. receive a handle to the opened device instance registry key.
  792. DesiredAccess - If DeviceInstanceHandle is specified (i.e., the device instance
  793. key is to be opened), then this variable specifies the access that is needed
  794. to this key.
  795. Return Value:
  796. NT status code indicating whether the function was successful.
  797. --*/
  798. {
  799. WCHAR unicodeBuffer[20];
  800. UNICODE_STRING unicodeKeyName;
  801. NTSTATUS status;
  802. HANDLE handle;
  803. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  804. //
  805. // Open registry ServiceKeyName\Enum branch
  806. //
  807. if(ARGUMENT_PRESENT(ServiceKeyHandle)) {
  808. PiWstrToUnicodeString(&unicodeKeyName, REGSTR_KEY_ENUM);
  809. status = IopOpenRegistryKeyEx( &handle,
  810. ServiceKeyHandle,
  811. &unicodeKeyName,
  812. KEY_READ
  813. );
  814. } else {
  815. status = PipOpenServiceEnumKeys(ServiceKeyName,
  816. KEY_READ,
  817. NULL,
  818. &handle,
  819. FALSE
  820. );
  821. }
  822. if (!NT_SUCCESS( status )) {
  823. //
  824. // There is no registry key for the ServiceKeyName\Enum information.
  825. //
  826. return status;
  827. }
  828. //
  829. // Read a path to System\Enum hardware tree branch specified by the service
  830. // instance ordinal
  831. //
  832. swprintf(unicodeBuffer, REGSTR_VALUE_STANDARD_ULONG_FORMAT, ServiceInstanceOrdinal);
  833. status = IopGetRegistryValue ( handle,
  834. unicodeBuffer,
  835. &keyValueInformation
  836. );
  837. ZwClose(handle);
  838. if (!NT_SUCCESS( status )) {
  839. return status;
  840. } else {
  841. if(keyValueInformation->Type == REG_SZ) {
  842. IopRegistryDataToUnicodeString(&unicodeKeyName,
  843. (PWSTR)KEY_VALUE_DATA(keyValueInformation),
  844. keyValueInformation->DataLength
  845. );
  846. if(!unicodeKeyName.Length) {
  847. status = STATUS_OBJECT_PATH_NOT_FOUND;
  848. }
  849. } else {
  850. status = STATUS_INVALID_PLUGPLAY_DEVICE_PATH;
  851. }
  852. if(!NT_SUCCESS(status)) {
  853. goto PrepareForReturn;
  854. }
  855. }
  856. //
  857. // If the DeviceInstanceHandle argument was specified, open the device instance
  858. // key under HKLM\System\CurrentControlSet\Enum
  859. //
  860. if (ARGUMENT_PRESENT(DeviceInstanceHandle)) {
  861. status = IopOpenRegistryKeyEx( &handle,
  862. NULL,
  863. &CmRegistryMachineSystemCurrentControlSetEnumName,
  864. KEY_READ
  865. );
  866. if (NT_SUCCESS( status )) {
  867. status = IopOpenRegistryKeyEx( DeviceInstanceHandle,
  868. handle,
  869. &unicodeKeyName,
  870. DesiredAccess
  871. );
  872. ZwClose(handle);
  873. }
  874. if (!NT_SUCCESS( status )) {
  875. goto PrepareForReturn;
  876. }
  877. }
  878. //
  879. // If the DeviceInstanceRegistryPath argument was specified, then store a
  880. // copy of the device instance path in the supplied unicode string variable.
  881. //
  882. if (ARGUMENT_PRESENT(DeviceInstanceRegistryPath)) {
  883. if (!PipConcatenateUnicodeStrings(DeviceInstanceRegistryPath,
  884. &unicodeKeyName,
  885. NULL)) {
  886. if(ARGUMENT_PRESENT(DeviceInstanceHandle)) {
  887. ZwClose(*DeviceInstanceHandle);
  888. }
  889. status = STATUS_INSUFFICIENT_RESOURCES;
  890. }
  891. }
  892. PrepareForReturn:
  893. ExFreePool(keyValueInformation);
  894. return status;
  895. }
  896. NTSTATUS
  897. IopOpenRegistryKeyEx(
  898. OUT PHANDLE Handle,
  899. IN HANDLE BaseHandle OPTIONAL,
  900. IN PUNICODE_STRING KeyName,
  901. IN ACCESS_MASK DesiredAccess
  902. )
  903. /*++
  904. Routine Description:
  905. Opens a registry key using the name passed in based at the BaseHandle node.
  906. This name may specify a key that is actually a registry path.
  907. Arguments:
  908. Handle - Pointer to the handle which will contain the registry key that
  909. was opened.
  910. BaseHandle - Optional handle to the base path from which the key must be opened.
  911. If KeyName specifies a registry path that must be created, then this parameter
  912. must be specified, and KeyName must be a relative path.
  913. KeyName - Name of the Key that must be opened/created (possibly a registry path)
  914. DesiredAccess - Specifies the desired access that the caller needs to
  915. the key.
  916. Return Value:
  917. The function value is the final status of the operation.
  918. --*/
  919. {
  920. OBJECT_ATTRIBUTES objectAttributes;
  921. PAGED_CODE();
  922. InitializeObjectAttributes( &objectAttributes,
  923. KeyName,
  924. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  925. BaseHandle,
  926. (PSECURITY_DESCRIPTOR) NULL
  927. );
  928. //
  929. // Simply attempt to open the path, as specified.
  930. //
  931. return ZwOpenKey( Handle, DesiredAccess, &objectAttributes );
  932. }
  933. NTSTATUS
  934. IopCreateRegistryKeyEx(
  935. OUT PHANDLE Handle,
  936. IN HANDLE BaseHandle OPTIONAL,
  937. IN PUNICODE_STRING KeyName,
  938. IN ACCESS_MASK DesiredAccess,
  939. IN ULONG CreateOptions,
  940. OUT PULONG Disposition OPTIONAL
  941. )
  942. /*++
  943. Routine Description:
  944. Opens or creates a registry key using the name
  945. passed in based at the BaseHandle node. This name may specify a key
  946. that is actually a registry path, in which case each intermediate subkey
  947. will be created (if Create is TRUE).
  948. NOTE: Creating a registry path (i.e., more than one of the keys in the path
  949. do not presently exist) requires that a BaseHandle be specified.
  950. Arguments:
  951. Handle - Pointer to the handle which will contain the registry key that
  952. was opened.
  953. BaseHandle - Optional handle to the base path from which the key must be opened.
  954. If KeyName specifies a registry path that must be created, then this parameter
  955. must be specified, and KeyName must be a relative path.
  956. KeyName - Name of the Key that must be opened/created (possibly a registry path)
  957. DesiredAccess - Specifies the desired access that the caller needs to
  958. the key.
  959. CreateOptions - Options passed to ZwCreateKey.
  960. Disposition - If Create is TRUE, this optional pointer receives a ULONG indicating
  961. whether the key was newly created:
  962. REG_CREATED_NEW_KEY - A new Registry Key was created
  963. REG_OPENED_EXISTING_KEY - An existing Registry Key was opened
  964. Return Value:
  965. The function value is the final status of the operation.
  966. --*/
  967. {
  968. OBJECT_ATTRIBUTES objectAttributes;
  969. ULONG disposition, baseHandleIndex = 0, keyHandleIndex = 1, closeBaseHandle;
  970. HANDLE handles[2];
  971. BOOLEAN continueParsing;
  972. PWCHAR pathEndPtr, pathCurPtr, pathBeginPtr;
  973. ULONG pathComponentLength;
  974. UNICODE_STRING unicodeString;
  975. NTSTATUS status;
  976. PAGED_CODE();
  977. InitializeObjectAttributes( &objectAttributes,
  978. KeyName,
  979. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  980. BaseHandle,
  981. (PSECURITY_DESCRIPTOR) NULL
  982. );
  983. //
  984. // Attempt to create the path as specified. We have to try it this
  985. // way first, because it allows us to create a key without a BaseHandle
  986. // (if only the last component of the registry path is not present).
  987. //
  988. status = ZwCreateKey(&(handles[keyHandleIndex]),
  989. DesiredAccess,
  990. &objectAttributes,
  991. 0,
  992. (PUNICODE_STRING) NULL,
  993. CreateOptions,
  994. &disposition
  995. );
  996. if (status == STATUS_OBJECT_NAME_NOT_FOUND && ARGUMENT_PRESENT(BaseHandle)) {
  997. //
  998. // If we get to here, then there must be more than one element of the
  999. // registry path that does not currently exist. We will now parse the
  1000. // specified path, extracting each component and doing a ZwCreateKey on it.
  1001. //
  1002. handles[baseHandleIndex] = NULL;
  1003. handles[keyHandleIndex] = BaseHandle;
  1004. closeBaseHandle = 0;
  1005. continueParsing = TRUE;
  1006. pathBeginPtr = KeyName->Buffer;
  1007. pathEndPtr = (PWCHAR)((PCHAR)pathBeginPtr + KeyName->Length);
  1008. status = STATUS_SUCCESS;
  1009. while(continueParsing) {
  1010. //
  1011. // There's more to do, so close the previous base handle (if necessary),
  1012. // and replace it with the current key handle.
  1013. //
  1014. if(closeBaseHandle > 1) {
  1015. ZwClose(handles[baseHandleIndex]);
  1016. }
  1017. baseHandleIndex = keyHandleIndex;
  1018. keyHandleIndex = (keyHandleIndex + 1) & 1; // toggle between 0 and 1.
  1019. handles[keyHandleIndex] = NULL;
  1020. //
  1021. // Extract next component out of the specified registry path.
  1022. //
  1023. for (pathCurPtr = pathBeginPtr;
  1024. ((pathCurPtr < pathEndPtr) && (*pathCurPtr != OBJ_NAME_PATH_SEPARATOR));
  1025. pathCurPtr++);
  1026. pathComponentLength = (ULONG)((PCHAR)pathCurPtr - (PCHAR)pathBeginPtr);
  1027. if (pathComponentLength != 0) {
  1028. //
  1029. // Then we have a non-empty path component (key name). Attempt
  1030. // to create this key.
  1031. //
  1032. unicodeString.Buffer = pathBeginPtr;
  1033. unicodeString.Length = unicodeString.MaximumLength = (USHORT)pathComponentLength;
  1034. InitializeObjectAttributes(&objectAttributes,
  1035. &unicodeString,
  1036. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1037. handles[baseHandleIndex],
  1038. (PSECURITY_DESCRIPTOR) NULL
  1039. );
  1040. status = ZwCreateKey(&(handles[keyHandleIndex]),
  1041. DesiredAccess,
  1042. &objectAttributes,
  1043. 0,
  1044. (PUNICODE_STRING) NULL,
  1045. CreateOptions,
  1046. &disposition
  1047. );
  1048. if(NT_SUCCESS(status)) {
  1049. //
  1050. // Increment the closeBaseHandle value, which basically tells us whether
  1051. // the BaseHandle passed in has been 'shifted out' of our way, so that
  1052. // we should start closing our base handles when we're finished with them.
  1053. //
  1054. closeBaseHandle++;
  1055. } else {
  1056. continueParsing = FALSE;
  1057. continue;
  1058. }
  1059. } else {
  1060. //
  1061. // Either a path separator ('\') was included at the beginning of
  1062. // the path, or we hit 2 consecutive separators.
  1063. //
  1064. status = STATUS_INVALID_PARAMETER;
  1065. continueParsing = FALSE;
  1066. continue;
  1067. }
  1068. if((pathCurPtr == pathEndPtr) ||
  1069. ((pathBeginPtr = pathCurPtr + 1) == pathEndPtr)) {
  1070. //
  1071. // Then we've reached the end of the path
  1072. //
  1073. continueParsing = FALSE;
  1074. }
  1075. }
  1076. if(closeBaseHandle > 1) {
  1077. ZwClose(handles[baseHandleIndex]);
  1078. }
  1079. }
  1080. if(NT_SUCCESS(status)) {
  1081. *Handle = handles[keyHandleIndex];
  1082. if(ARGUMENT_PRESENT(Disposition)) {
  1083. *Disposition = disposition;
  1084. }
  1085. }
  1086. return status;
  1087. }
  1088. NTSTATUS
  1089. PipOpenServiceEnumKeys (
  1090. IN PUNICODE_STRING ServiceKeyName,
  1091. IN ACCESS_MASK DesiredAccess,
  1092. OUT PHANDLE ServiceHandle OPTIONAL,
  1093. OUT PHANDLE ServiceEnumHandle OPTIONAL,
  1094. IN BOOLEAN CreateEnum
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. This routine opens the HKEY_LOCAL_MACHINE\CurrentControlSet\Services\
  1099. ServiceKeyName and its Enum subkey and returns handles for both key.
  1100. It is caller's responsibility to close the returned handles.
  1101. Arguments:
  1102. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  1103. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  1104. that caused the driver to load. This is the RegistryPath parameter
  1105. to the DriverEntry routine.
  1106. DesiredAccess - Specifies the desired access to the keys.
  1107. ServiceHandle - Supplies a variable to receive a handle to ServiceKeyName.
  1108. A NULL ServiceHandle indicates caller does not want need the handle to
  1109. the ServiceKeyName.
  1110. ServiceEnumHandle - Supplies a variable to receive a handle to ServiceKeyName\Enum.
  1111. A NULL ServiceEnumHandle indicates caller does not need the handle to
  1112. the ServiceKeyName\Enum.
  1113. CreateEnum - Supplies a BOOLEAN variable to indicate should the Enum subkey be
  1114. created if not present.
  1115. Return Value:
  1116. status
  1117. --*/
  1118. {
  1119. HANDLE handle, serviceHandle, enumHandle;
  1120. UNICODE_STRING enumName;
  1121. NTSTATUS status;
  1122. //
  1123. // Open System\CurrentControlSet\Services
  1124. //
  1125. status = IopOpenRegistryKeyEx( &handle,
  1126. NULL,
  1127. &CmRegistryMachineSystemCurrentControlSetServices,
  1128. DesiredAccess
  1129. );
  1130. if (!NT_SUCCESS( status )) {
  1131. return status;
  1132. }
  1133. //
  1134. // Open the registry ServiceKeyName key.
  1135. //
  1136. status = IopOpenRegistryKeyEx( &serviceHandle,
  1137. handle,
  1138. ServiceKeyName,
  1139. DesiredAccess
  1140. );
  1141. ZwClose(handle);
  1142. if (!NT_SUCCESS( status )) {
  1143. //
  1144. // There is no registry key for the ServiceKeyName information.
  1145. //
  1146. return status;
  1147. }
  1148. if (ARGUMENT_PRESENT(ServiceEnumHandle) || CreateEnum) {
  1149. //
  1150. // Open registry ServiceKeyName\Enum branch if caller wants
  1151. // the handle or wants to create it.
  1152. //
  1153. PiWstrToUnicodeString(&enumName, REGSTR_KEY_ENUM);
  1154. if (CreateEnum) {
  1155. status = IopCreateRegistryKeyEx( &enumHandle,
  1156. serviceHandle,
  1157. &enumName,
  1158. DesiredAccess,
  1159. REG_OPTION_VOLATILE,
  1160. NULL
  1161. );
  1162. } else {
  1163. status = IopOpenRegistryKeyEx( &enumHandle,
  1164. serviceHandle,
  1165. &enumName,
  1166. DesiredAccess
  1167. );
  1168. }
  1169. if (!NT_SUCCESS( status )) {
  1170. //
  1171. // There is no registry key for the ServiceKeyName\Enum information.
  1172. //
  1173. ZwClose(serviceHandle);
  1174. return status;
  1175. }
  1176. if (ARGUMENT_PRESENT(ServiceEnumHandle)) {
  1177. *ServiceEnumHandle = enumHandle;
  1178. } else {
  1179. ZwClose(enumHandle);
  1180. }
  1181. }
  1182. //
  1183. // if caller wants to have the ServiceKey handle, we return it. Otherwise
  1184. // we close it.
  1185. //
  1186. if (ARGUMENT_PRESENT(ServiceHandle)) {
  1187. *ServiceHandle = serviceHandle;
  1188. } else {
  1189. ZwClose(serviceHandle);
  1190. }
  1191. return STATUS_SUCCESS;
  1192. }
  1193. NTSTATUS
  1194. IopGetDeviceInstanceCsConfigFlags(
  1195. IN PUNICODE_STRING DeviceInstance,
  1196. OUT PULONG CsConfigFlags
  1197. )
  1198. /*++
  1199. Routine Description:
  1200. This routine retrieves the csconfig flags for the specified device.
  1201. Arguments:
  1202. DeviceInstance - Supplies a pointer to the devnode's instance path
  1203. CsConfigFlags - Supplies a variable to receive the device's CsConfigFlags
  1204. Return Value:
  1205. status
  1206. --*/
  1207. {
  1208. NTSTATUS status;
  1209. HANDLE handle1, handle2;
  1210. UNICODE_STRING tempUnicodeString;
  1211. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1212. PAGED_CODE();
  1213. *CsConfigFlags = 0;
  1214. status = IopOpenRegistryKeyEx( &handle1,
  1215. NULL,
  1216. &CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent,
  1217. KEY_READ
  1218. );
  1219. if (!NT_SUCCESS(status)) {
  1220. return status;
  1221. }
  1222. //
  1223. // Now, we must open the System\CCS\Enum key under this.
  1224. //
  1225. //
  1226. // Open system\CurrentControlSet under current hardware profile key
  1227. //
  1228. PiWstrToUnicodeString(&tempUnicodeString, REGSTR_PATH_CURRENTCONTROLSET);
  1229. status = IopOpenRegistryKeyEx( &handle2,
  1230. handle1,
  1231. &tempUnicodeString,
  1232. KEY_READ
  1233. );
  1234. ZwClose(handle1);
  1235. if (!NT_SUCCESS(status)) {
  1236. return status;
  1237. }
  1238. PiWstrToUnicodeString(&tempUnicodeString, REGSTR_KEY_ENUM);
  1239. status = IopOpenRegistryKeyEx( &handle1,
  1240. handle2,
  1241. &tempUnicodeString,
  1242. KEY_READ
  1243. );
  1244. ZwClose(handle2);
  1245. if (!NT_SUCCESS(status)) {
  1246. return status;
  1247. }
  1248. status = IopOpenRegistryKeyEx( &handle2,
  1249. handle1,
  1250. DeviceInstance,
  1251. KEY_READ
  1252. );
  1253. ZwClose(handle1);
  1254. if (!NT_SUCCESS(status)) {
  1255. return status;
  1256. }
  1257. status = IopGetRegistryValue( handle2,
  1258. REGSTR_VALUE_CSCONFIG_FLAGS,
  1259. &keyValueInformation
  1260. );
  1261. ZwClose(handle2);
  1262. if (NT_SUCCESS(status)) {
  1263. if ((keyValueInformation->Type == REG_DWORD) &&
  1264. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  1265. *CsConfigFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  1266. }
  1267. ExFreePool(keyValueInformation);
  1268. }
  1269. return status;
  1270. }
  1271. NTSTATUS
  1272. PipGetServiceInstanceCsConfigFlags(
  1273. IN PUNICODE_STRING ServiceKeyName,
  1274. IN ULONG Instance,
  1275. OUT PULONG CsConfigFlags
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. This routine retrieves the csconfig flags for the specified device
  1280. which is specified by the instance number under ServiceKeyName\Enum.
  1281. Arguments:
  1282. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  1283. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  1284. that caused the driver to load.
  1285. Instance - Supplies the instance value under ServiceKeyName\Enum key
  1286. CsConfigFlags - Supplies a variable to receive the device's CsConfigFlags
  1287. Return Value:
  1288. status
  1289. --*/
  1290. {
  1291. NTSTATUS status;
  1292. HANDLE handle;
  1293. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1294. PAGED_CODE();
  1295. *CsConfigFlags = 0;
  1296. status = IopOpenCurrentHwProfileDeviceInstanceKey(&handle,
  1297. ServiceKeyName,
  1298. Instance,
  1299. KEY_READ,
  1300. FALSE
  1301. );
  1302. if(NT_SUCCESS(status)) {
  1303. status = IopGetRegistryValue(handle,
  1304. REGSTR_VALUE_CSCONFIG_FLAGS,
  1305. &keyValueInformation
  1306. );
  1307. if(NT_SUCCESS(status)) {
  1308. if((keyValueInformation->Type == REG_DWORD) &&
  1309. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  1310. *CsConfigFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  1311. }
  1312. ExFreePool(keyValueInformation);
  1313. }
  1314. ZwClose(handle);
  1315. }
  1316. return status;
  1317. }
  1318. NTSTATUS
  1319. IopOpenCurrentHwProfileDeviceInstanceKey(
  1320. OUT PHANDLE Handle,
  1321. IN PUNICODE_STRING ServiceKeyName,
  1322. IN ULONG Instance,
  1323. IN ACCESS_MASK DesiredAccess,
  1324. IN BOOLEAN Create
  1325. )
  1326. /*++
  1327. Routine Description:
  1328. This routine sets the csconfig flags for the specified device
  1329. which is specified by the instance number under ServiceKeyName\Enum.
  1330. Arguments:
  1331. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  1332. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  1333. that caused the driver to load. This is the RegistryPath parameter
  1334. to the DriverEntry routine.
  1335. Instance - Supplies the instance value under ServiceKeyName\Enum key
  1336. DesiredAccess - Specifies the desired access that the caller needs to
  1337. the key.
  1338. Create - Determines if the key is to be created if it does not exist.
  1339. Return Value:
  1340. status
  1341. --*/
  1342. {
  1343. NTSTATUS status;
  1344. UNICODE_STRING tempUnicodeString;
  1345. HANDLE profileHandle, profileEnumHandle, tmpHandle;
  1346. //
  1347. // See if we can open current hardware profile
  1348. //
  1349. if (Create) {
  1350. status = IopCreateRegistryKeyEx( &profileHandle,
  1351. NULL,
  1352. &CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent,
  1353. KEY_READ,
  1354. REG_OPTION_NON_VOLATILE,
  1355. NULL
  1356. );
  1357. } else {
  1358. status = IopOpenRegistryKeyEx( &profileHandle,
  1359. NULL,
  1360. &CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent,
  1361. KEY_READ
  1362. );
  1363. }
  1364. if(NT_SUCCESS(status)) {
  1365. //
  1366. // Now, we must open the System\CCS\Enum key under this.
  1367. //
  1368. //
  1369. // Open system\CurrentControlSet under current hardware profile key
  1370. //
  1371. PiWstrToUnicodeString(&tempUnicodeString, REGSTR_PATH_CURRENTCONTROLSET);
  1372. status = IopOpenRegistryKeyEx( &tmpHandle,
  1373. profileHandle,
  1374. &tempUnicodeString,
  1375. DesiredAccess
  1376. );
  1377. ZwClose(profileHandle);
  1378. if (!NT_SUCCESS(status)) {
  1379. return status;
  1380. }
  1381. PiWstrToUnicodeString(&tempUnicodeString, REGSTR_KEY_ENUM);
  1382. if (Create) {
  1383. status = IopCreateRegistryKeyEx( &profileEnumHandle,
  1384. tmpHandle,
  1385. &tempUnicodeString,
  1386. KEY_READ,
  1387. REG_OPTION_NON_VOLATILE,
  1388. NULL
  1389. );
  1390. } else {
  1391. status = IopOpenRegistryKeyEx( &profileEnumHandle,
  1392. tmpHandle,
  1393. &tempUnicodeString,
  1394. KEY_READ
  1395. );
  1396. }
  1397. ZwClose(tmpHandle);
  1398. if(NT_SUCCESS(status)) {
  1399. status = PipServiceInstanceToDeviceInstance(NULL,
  1400. ServiceKeyName,
  1401. Instance,
  1402. &tempUnicodeString,
  1403. NULL,
  1404. 0
  1405. );
  1406. if (NT_SUCCESS(status)) {
  1407. if (Create) {
  1408. status = IopCreateRegistryKeyEx( Handle,
  1409. profileEnumHandle,
  1410. &tempUnicodeString,
  1411. DesiredAccess,
  1412. REG_OPTION_NON_VOLATILE,
  1413. NULL
  1414. );
  1415. } else {
  1416. status = IopOpenRegistryKeyEx( Handle,
  1417. profileEnumHandle,
  1418. &tempUnicodeString,
  1419. DesiredAccess
  1420. );
  1421. }
  1422. RtlFreeUnicodeString(&tempUnicodeString);
  1423. }
  1424. ZwClose(profileEnumHandle);
  1425. }
  1426. }
  1427. return status;
  1428. }
  1429. NTSTATUS
  1430. PipApplyFunctionToSubKeys(
  1431. IN HANDLE BaseHandle OPTIONAL,
  1432. IN PUNICODE_STRING KeyName OPTIONAL,
  1433. IN ACCESS_MASK DesiredAccess,
  1434. IN ULONG Flags,
  1435. IN PIOP_SUBKEY_CALLBACK_ROUTINE SubKeyCallbackRoutine,
  1436. IN OUT PVOID Context
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. This routine enumerates all subkeys under the specified key, and calls
  1441. the specified callback routine for each subkey.
  1442. Arguments:
  1443. BaseHandle - Optional handle to the base registry path. If KeyName is also
  1444. specified, then KeyName represents a subkey under this path. If KeyName
  1445. is not specified, the subkeys are enumerated under this handle. If this
  1446. parameter is not specified, then the full path to the base key must be
  1447. given in KeyName.
  1448. KeyName - Optional name of the key whose subkeys are to be enumerated.
  1449. DesiredAccess - Specifies the desired access that the callback routine
  1450. needs to the subkeys. If no desired access is specified (i.e.,
  1451. DesiredAccess is zero), then no handle will be opened for the
  1452. subkeys, and the callback will be passed a NULL for its SubKeyHandle
  1453. parameter.
  1454. Flags - Controls the behavior of subkey enumeration. Currently, the
  1455. following flags are defined:
  1456. FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS - Specifies whether this
  1457. function should immediately terminate on all errors, or only on
  1458. critical ones. An example of a non-critical error is when an
  1459. enumerated subkey cannot be opened for the desired access.
  1460. FUNCTION_SUBKEY_DELETE_SUBKEYS - Specifies that each subkey should be
  1461. deleted after the specified SubKeyCallBackRoutine has been performed
  1462. on it. Note that this is NOT a recursive delete on each of the
  1463. subkeys, just an attempt to delete the subkey itself. It the subkey
  1464. contains children, this will fail.
  1465. SubKeyCallbackRoutine - Supplies a pointer to a function that will
  1466. be called for each subkey found under the
  1467. specified key. The prototype of the function
  1468. is as follows:
  1469. typedef BOOLEAN (*PIOP_SUBKEY_CALLBACK_ROUTINE) (
  1470. IN HANDLE SubKeyHandle,
  1471. IN PUNICODE_STRING SubKeyName,
  1472. IN OUT PVOID Context
  1473. );
  1474. where SubKeyHandle is the handle to an enumerated subkey under the
  1475. specified key, SubKeyName is its name, and Context is a pointer to
  1476. user-defined data.
  1477. This function should return TRUE to continue enumeration, or
  1478. FALSE to terminate it.
  1479. Context - Supplies a pointer to user-defined data that will be passed
  1480. in to the callback routine at each subkey invocation.
  1481. Return Value:
  1482. NT status code indicating whether the subkeys were successfully
  1483. enumerated. Note that this does not provide information on the
  1484. success or failure of the callback routine--if desired, this
  1485. information should be stored in the Context structure.
  1486. --*/
  1487. {
  1488. NTSTATUS Status;
  1489. BOOLEAN CloseHandle = FALSE, ContinueEnumeration;
  1490. HANDLE Handle, SubKeyHandle;
  1491. ULONG i, RequiredBufferLength;
  1492. PKEY_BASIC_INFORMATION KeyInformation = NULL;
  1493. // Use an initial key name buffer size large enough for a 20-character key
  1494. // (+ terminating NULL)
  1495. ULONG KeyInformationLength = sizeof(KEY_BASIC_INFORMATION) + (20 * sizeof(WCHAR));
  1496. UNICODE_STRING SubKeyName;
  1497. if(ARGUMENT_PRESENT(KeyName)) {
  1498. Status = IopOpenRegistryKeyEx( &Handle,
  1499. BaseHandle,
  1500. KeyName,
  1501. KEY_READ
  1502. );
  1503. if(!NT_SUCCESS(Status)) {
  1504. return Status;
  1505. } else {
  1506. CloseHandle = TRUE;
  1507. }
  1508. } else {
  1509. Handle = BaseHandle;
  1510. }
  1511. //
  1512. // Enumerate the subkeys until we run out of them.
  1513. //
  1514. i = 0;
  1515. SubKeyHandle = NULL;
  1516. for ( ; ; ) {
  1517. if (!KeyInformation) {
  1518. KeyInformation = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool,
  1519. KeyInformationLength
  1520. );
  1521. if (!KeyInformation) {
  1522. Status = STATUS_INSUFFICIENT_RESOURCES;
  1523. break;
  1524. }
  1525. }
  1526. Status = ZwEnumerateKey(Handle,
  1527. i,
  1528. KeyBasicInformation,
  1529. KeyInformation,
  1530. KeyInformationLength,
  1531. &RequiredBufferLength
  1532. );
  1533. if (!NT_SUCCESS(Status)) {
  1534. if (Status == STATUS_BUFFER_OVERFLOW ||
  1535. Status == STATUS_BUFFER_TOO_SMALL) {
  1536. //
  1537. // Try again with larger buffer.
  1538. //
  1539. ExFreePool(KeyInformation);
  1540. KeyInformation = NULL;
  1541. KeyInformationLength = RequiredBufferLength;
  1542. continue;
  1543. } else {
  1544. if (Status == STATUS_NO_MORE_ENTRIES) {
  1545. //
  1546. // No more subkeys.
  1547. //
  1548. Status = STATUS_SUCCESS;
  1549. }
  1550. //
  1551. // break out of loop
  1552. //
  1553. break;
  1554. }
  1555. }
  1556. //
  1557. // Initialize a unicode string with this key name. Note that this string
  1558. // WILL NOT be NULL-terminated.
  1559. //
  1560. SubKeyName.Length = SubKeyName.MaximumLength = (USHORT)KeyInformation->NameLength;
  1561. SubKeyName.Buffer = KeyInformation->Name;
  1562. //
  1563. // If DesiredAccess is non-zero, open a handle to this subkey.
  1564. //
  1565. if (DesiredAccess) {
  1566. Status = IopOpenRegistryKeyEx( &SubKeyHandle,
  1567. Handle,
  1568. &SubKeyName,
  1569. DesiredAccess
  1570. );
  1571. if (!NT_SUCCESS(Status)) {
  1572. //
  1573. // This is a non-critical error.
  1574. //
  1575. if(Flags & FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS) {
  1576. goto ContinueWithNextSubKey;
  1577. } else {
  1578. break;
  1579. }
  1580. }
  1581. }
  1582. //
  1583. // Invoke the supplied callback function for this subkey.
  1584. //
  1585. ContinueEnumeration = SubKeyCallbackRoutine(SubKeyHandle, &SubKeyName, Context);
  1586. if (DesiredAccess) {
  1587. if (ContinueEnumeration &&
  1588. (Flags & FUNCTIONSUBKEY_FLAG_DELETE_SUBKEYS)) {
  1589. //
  1590. // Delete the key when asked to, only if the callback routine
  1591. // was successful, otherwise we may not be able to.
  1592. //
  1593. Status = ZwDeleteKey(SubKeyHandle);
  1594. }
  1595. ZwClose(SubKeyHandle);
  1596. }
  1597. if(!ContinueEnumeration) {
  1598. //
  1599. // Enumeration has been aborted.
  1600. //
  1601. Status = STATUS_SUCCESS;
  1602. break;
  1603. }
  1604. ContinueWithNextSubKey:
  1605. if (!(Flags & FUNCTIONSUBKEY_FLAG_DELETE_SUBKEYS)) {
  1606. //
  1607. // Only increment the enumeration index for non-deleted subkeys
  1608. //
  1609. i++;
  1610. }
  1611. }
  1612. if(KeyInformation) {
  1613. ExFreePool(KeyInformation);
  1614. }
  1615. if(CloseHandle) {
  1616. ZwClose(Handle);
  1617. }
  1618. return Status;
  1619. }
  1620. NTSTATUS
  1621. PipRegMultiSzToUnicodeStrings(
  1622. IN PKEY_VALUE_FULL_INFORMATION KeyValueInformation,
  1623. OUT PUNICODE_STRING *UnicodeStringList,
  1624. OUT PULONG UnicodeStringCount
  1625. )
  1626. /*++
  1627. Routine Description:
  1628. This routine takes a KEY_VALUE_FULL_INFORMATION structure containing
  1629. a REG_MULTI_SZ value, and allocates an array of UNICODE_STRINGs,
  1630. initializing each one to a copy of one of the strings in the value entry.
  1631. All the resulting UNICODE_STRINGs will be NULL terminated
  1632. (MaximumLength = Length + sizeof(UNICODE_NULL)).
  1633. It is the responsibility of the caller to free the buffers for each
  1634. unicode string, as well as the buffer containing the UNICODE_STRING
  1635. array. This may be done by calling PipFreeUnicodeStringList.
  1636. Arguments:
  1637. KeyValueInformation - Supplies the buffer containing the REG_MULTI_SZ
  1638. value entry data.
  1639. UnicodeStringList - Receives a pointer to an array of UNICODE_STRINGs, each
  1640. initialized with a copy of one of the strings in the REG_MULTI_SZ.
  1641. UnicodeStringCount - Receives the number of strings in the
  1642. UnicodeStringList.
  1643. Returns:
  1644. NT status code indicating whether the function was successful.
  1645. NOTE: This function is only available during INIT time!
  1646. --*/
  1647. {
  1648. PWCHAR p, BufferEnd, StringStart;
  1649. ULONG StringCount, i, StringLength;
  1650. //
  1651. // First, make sure this is really a REG_MULTI_SZ value.
  1652. //
  1653. if(KeyValueInformation->Type != REG_MULTI_SZ) {
  1654. return STATUS_INVALID_PARAMETER;
  1655. }
  1656. //
  1657. // Make a preliminary pass through the buffer to count the number of strings
  1658. // There will always be at least one string returned (possibly empty).
  1659. //
  1660. StringCount = 0;
  1661. p = (PWCHAR)KEY_VALUE_DATA(KeyValueInformation);
  1662. BufferEnd = (PWCHAR)((PUCHAR)p + KeyValueInformation->DataLength);
  1663. while(p != BufferEnd) {
  1664. if(!*p) {
  1665. StringCount++;
  1666. if(((p + 1) == BufferEnd) || !*(p + 1)) {
  1667. break;
  1668. }
  1669. }
  1670. p++;
  1671. }
  1672. if(p == BufferEnd) {
  1673. StringCount++;
  1674. }
  1675. *UnicodeStringList = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING) * StringCount);
  1676. if(!(*UnicodeStringList)) {
  1677. return STATUS_INSUFFICIENT_RESOURCES;
  1678. }
  1679. //
  1680. // Now, make a second pass through the buffer making copies of each string.
  1681. //
  1682. i = 0;
  1683. StringStart = p = (PWCHAR)KEY_VALUE_DATA(KeyValueInformation);
  1684. while(p != BufferEnd) {
  1685. if(!*p) {
  1686. StringLength = (ULONG)((PUCHAR)p - (PUCHAR)StringStart) + sizeof(UNICODE_NULL);
  1687. (*UnicodeStringList)[i].Buffer = ExAllocatePool(PagedPool, StringLength);
  1688. if(!((*UnicodeStringList)[i].Buffer)) {
  1689. PipFreeUnicodeStringList(*UnicodeStringList, i);
  1690. return STATUS_INSUFFICIENT_RESOURCES;
  1691. }
  1692. RtlCopyMemory((*UnicodeStringList)[i].Buffer, StringStart, StringLength);
  1693. (*UnicodeStringList)[i].Length =
  1694. ((*UnicodeStringList)[i].MaximumLength = (USHORT)StringLength)
  1695. - sizeof(UNICODE_NULL);
  1696. i++;
  1697. if(((p + 1) == BufferEnd) || !*(p + 1)) {
  1698. break;
  1699. } else {
  1700. StringStart = p + 1;
  1701. }
  1702. }
  1703. p++;
  1704. }
  1705. if(p == BufferEnd) {
  1706. StringLength = (ULONG)((PUCHAR)p - (PUCHAR)StringStart);
  1707. (*UnicodeStringList)[i].Buffer = ExAllocatePool(PagedPool,
  1708. StringLength + sizeof(UNICODE_NULL)
  1709. );
  1710. if(!((*UnicodeStringList)[i].Buffer)) {
  1711. PipFreeUnicodeStringList(*UnicodeStringList, i);
  1712. return STATUS_INSUFFICIENT_RESOURCES;
  1713. }
  1714. if(StringLength) {
  1715. RtlCopyMemory((*UnicodeStringList)[i].Buffer, StringStart, StringLength);
  1716. }
  1717. (*UnicodeStringList)[i].Buffer[CB_TO_CWC(StringLength)] = UNICODE_NULL;
  1718. (*UnicodeStringList)[i].MaximumLength =
  1719. ((*UnicodeStringList)[i].Length = (USHORT)StringLength)
  1720. + sizeof(UNICODE_NULL);
  1721. }
  1722. *UnicodeStringCount = StringCount;
  1723. return STATUS_SUCCESS;
  1724. }
  1725. NTSTATUS
  1726. PipApplyFunctionToServiceInstances(
  1727. IN HANDLE ServiceKeyHandle OPTIONAL,
  1728. IN PUNICODE_STRING ServiceKeyName OPTIONAL,
  1729. IN ACCESS_MASK DesiredAccess,
  1730. IN BOOLEAN IgnoreNonCriticalErrors,
  1731. IN PIOP_SUBKEY_CALLBACK_ROUTINE DevInstCallbackRoutine,
  1732. IN OUT PVOID Context,
  1733. OUT PULONG ServiceInstanceOrdinal OPTIONAL
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. This routine enumerates all device instances referenced by the instance
  1738. ordinal entries under a service's volatile Enum key, and calls
  1739. the specified callback routine for each instance's corresponding subkey
  1740. under HKLM\System\Enum.
  1741. Arguments:
  1742. ServiceKeyHandle - Optional handle to the service entry. If this parameter
  1743. is not specified, then the service key name must be given in
  1744. ServiceKeyName (if both parameters are specified, then ServiceKeyHandle
  1745. is used, and ServiceKeyName is ignored).
  1746. ServiceKeyName - Optional name of the service entry key (under
  1747. HKLM\CurrentControlSet\Services). If this parameter is not specified,
  1748. then ServiceKeyHandle must contain a handle to the desired service key.
  1749. DesiredAccess - Specifies the desired access that the callback routine
  1750. needs to the enumerated device instance keys. If no desired access is
  1751. specified (i.e., DesiredAccess is zero), then no handle will be opened
  1752. for the device instance keys, and the callback will be passed a NULL for
  1753. its DeviceInstanceHandle parameter.
  1754. IgnoreNonCriticalErrors - Specifies whether this function should
  1755. immediately terminate on all errors, or only on critical ones.
  1756. An example of a non-critical error is when an enumerated device instance
  1757. key cannot be opened for the desired access.
  1758. DevInstCallbackRoutine - Supplies a pointer to a function that will
  1759. be called for each device instance key referenced by a service instance
  1760. entry under the service's volatile Enum subkey. The prototype of the
  1761. function is as follows:
  1762. typedef BOOLEAN (*PIOP_SUBKEY_CALLBACK_ROUTINE) (
  1763. IN HANDLE DeviceInstanceHandle,
  1764. IN PUNICODE_STRING DeviceInstancePath,
  1765. IN OUT PVOID Context
  1766. );
  1767. where DeviceInstanceHandle is the handle to an enumerated device instance
  1768. key, DeviceInstancePath is the registry path (relative to
  1769. HKLM\System\Enum) to this device instance, and Context is a pointer to
  1770. user-defined data.
  1771. This function should return TRUE to continue enumeration, or
  1772. FALSE to terminate it.
  1773. Context - Supplies a pointer to user-defined data that will be passed
  1774. in to the callback routine at each device instance key invocation.
  1775. ServiceInstanceOrdinal - Optionally, receives the service instance ordinal (1 based)
  1776. that terminated the enumeration, or the total number of instances enumerated
  1777. if the enumeration completed without being aborted.
  1778. Return Value:
  1779. NT status code indicating whether the device instance keys were successfully
  1780. enumerated. Note that this does not provide information on the success or
  1781. failure of the callback routine--if desired, this information should be
  1782. stored in the Context structure.
  1783. --*/
  1784. {
  1785. NTSTATUS Status;
  1786. HANDLE ServiceEnumHandle, SystemEnumHandle, DeviceInstanceHandle;
  1787. UNICODE_STRING TempUnicodeString;
  1788. ULONG ServiceInstanceCount, i, junk;
  1789. PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  1790. BOOLEAN ContinueEnumeration;
  1791. //
  1792. // First, open up the volatile Enum subkey under the specified service entry.
  1793. //
  1794. if(ARGUMENT_PRESENT(ServiceKeyHandle)) {
  1795. PiWstrToUnicodeString(&TempUnicodeString, REGSTR_KEY_ENUM);
  1796. Status = IopOpenRegistryKeyEx( &ServiceEnumHandle,
  1797. ServiceKeyHandle,
  1798. &TempUnicodeString,
  1799. KEY_READ
  1800. );
  1801. } else {
  1802. Status = PipOpenServiceEnumKeys(ServiceKeyName,
  1803. KEY_READ,
  1804. NULL,
  1805. &ServiceEnumHandle,
  1806. FALSE
  1807. );
  1808. }
  1809. if(!NT_SUCCESS(Status)) {
  1810. return Status;
  1811. }
  1812. //
  1813. // Find out how many instances are referenced in the service's Enum key.
  1814. //
  1815. ServiceInstanceCount = 0; // assume none.
  1816. Status = IopGetRegistryValue(ServiceEnumHandle,
  1817. REGSTR_VALUE_COUNT,
  1818. &KeyValueInformation
  1819. );
  1820. if (NT_SUCCESS(Status)) {
  1821. if((KeyValueInformation->Type == REG_DWORD) &&
  1822. (KeyValueInformation->DataLength >= sizeof(ULONG))) {
  1823. ServiceInstanceCount = *(PULONG)KEY_VALUE_DATA(KeyValueInformation);
  1824. }
  1825. ExFreePool(KeyValueInformation);
  1826. } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  1827. goto PrepareForReturn;
  1828. } else {
  1829. //
  1830. // If 'Count' value entry not found, consider this to mean there are simply
  1831. // no device instance controlled by this service.
  1832. //
  1833. Status = STATUS_SUCCESS;
  1834. }
  1835. //
  1836. // Now, enumerate each service instance, and call the specified callback function
  1837. // for the corresponding device instance.
  1838. //
  1839. if (ServiceInstanceCount) {
  1840. if (DesiredAccess) {
  1841. Status = IopOpenRegistryKeyEx( &SystemEnumHandle,
  1842. NULL,
  1843. &CmRegistryMachineSystemCurrentControlSetEnumName,
  1844. KEY_READ
  1845. );
  1846. if(!NT_SUCCESS(Status)) {
  1847. goto PrepareForReturn;
  1848. }
  1849. } else {
  1850. //
  1851. // Set DeviceInstanceHandle to NULL, since we won't be opening up the
  1852. // device instance keys.
  1853. //
  1854. DeviceInstanceHandle = NULL;
  1855. }
  1856. KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool(
  1857. PagedPool,
  1858. PNP_SCRATCH_BUFFER_SIZE);
  1859. if (!KeyValueInformation) {
  1860. Status = STATUS_INSUFFICIENT_RESOURCES;
  1861. goto PrepareForReturn;
  1862. }
  1863. for (i = 0; ; i++) {
  1864. Status = ZwEnumerateValueKey(
  1865. ServiceEnumHandle,
  1866. i,
  1867. KeyValueFullInformation,
  1868. KeyValueInformation,
  1869. PNP_SCRATCH_BUFFER_SIZE,
  1870. &junk
  1871. );
  1872. if (!NT_SUCCESS (Status)) {
  1873. if (Status == STATUS_NO_MORE_ENTRIES) {
  1874. Status = STATUS_SUCCESS;
  1875. break;
  1876. } else if (IgnoreNonCriticalErrors) {
  1877. continue;
  1878. } else {
  1879. break;
  1880. }
  1881. }
  1882. if (KeyValueInformation->Type != REG_SZ) {
  1883. continue;
  1884. }
  1885. ContinueEnumeration = TRUE;
  1886. TempUnicodeString.Length = 0;
  1887. IopRegistryDataToUnicodeString(&TempUnicodeString,
  1888. (PWSTR)KEY_VALUE_DATA(KeyValueInformation),
  1889. KeyValueInformation->DataLength
  1890. );
  1891. if (TempUnicodeString.Length) {
  1892. //
  1893. // We have retrieved a (non-empty) string for this service instance.
  1894. // If the user specified a non-zero value for the DesiredAccess
  1895. // parameter, we will attempt to open up the corresponding device
  1896. // instance key under HKLM\System\Enum.
  1897. //
  1898. if (DesiredAccess) {
  1899. Status = IopOpenRegistryKeyEx( &DeviceInstanceHandle,
  1900. SystemEnumHandle,
  1901. &TempUnicodeString,
  1902. DesiredAccess
  1903. );
  1904. }
  1905. if (NT_SUCCESS(Status)) {
  1906. //
  1907. // Invoke the specified callback routine for this device instance.
  1908. //
  1909. ContinueEnumeration = DevInstCallbackRoutine(DeviceInstanceHandle,
  1910. &TempUnicodeString,
  1911. Context
  1912. );
  1913. if (DesiredAccess) {
  1914. ZwClose(DeviceInstanceHandle);
  1915. }
  1916. } else if (IgnoreNonCriticalErrors) {
  1917. continue;
  1918. } else {
  1919. break;
  1920. }
  1921. } else {
  1922. continue;
  1923. }
  1924. if (!ContinueEnumeration) {
  1925. break;
  1926. }
  1927. }
  1928. if (ARGUMENT_PRESENT(ServiceInstanceOrdinal)) {
  1929. *ServiceInstanceOrdinal = i;
  1930. }
  1931. if (DesiredAccess) {
  1932. ZwClose(SystemEnumHandle);
  1933. }
  1934. ExFreePool(KeyValueInformation);
  1935. }
  1936. PrepareForReturn:
  1937. ZwClose(ServiceEnumHandle);
  1938. return Status;
  1939. }
  1940. BOOLEAN
  1941. PipIsDuplicatedDevices(
  1942. IN PCM_RESOURCE_LIST Configuration1,
  1943. IN PCM_RESOURCE_LIST Configuration2,
  1944. IN PHAL_BUS_INFORMATION BusInfo1 OPTIONAL,
  1945. IN PHAL_BUS_INFORMATION BusInfo2 OPTIONAL
  1946. )
  1947. /*++
  1948. Routine Description:
  1949. This routine compares two set of configurations and bus information to
  1950. determine if the resources indicate the same device. If BusInfo1 and
  1951. BusInfo2 both are absent, it means caller wants to compare the raw
  1952. resources.
  1953. Arguments:
  1954. Configuration1 - Supplies a pointer to the first set of resource.
  1955. Configuration2 - Supplies a pointer to the second set of resource.
  1956. BusInfo1 - Supplies a pointer to the first set of bus information.
  1957. BusInfo2 - Supplies a pointer to the second set of bus information.
  1958. Return Value:
  1959. returns TRUE if the two set of resources indicate the same device;
  1960. otherwise a value of FALSE is returned.
  1961. --*/
  1962. {
  1963. PCM_PARTIAL_RESOURCE_LIST list1, list2;
  1964. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor1, descriptor2;
  1965. ULONG i, j;
  1966. ULONG pass = 0;
  1967. //
  1968. // The BusInfo for both resources must be both present or not present.
  1969. //
  1970. if ((ARGUMENT_PRESENT(BusInfo1) && !ARGUMENT_PRESENT(BusInfo2)) ||
  1971. (!ARGUMENT_PRESENT(BusInfo1) && ARGUMENT_PRESENT(BusInfo2))) {
  1972. //
  1973. // Unable to determine.
  1974. //
  1975. return FALSE;
  1976. }
  1977. //
  1978. // Next check resources used by the two devices.
  1979. // Currently, we *only* check the Io ports.
  1980. //
  1981. if (Configuration1->Count == 0 || Configuration2->Count == 0) {
  1982. //
  1983. // If any one of the configuration data is empty, we assume
  1984. // the devices are not duplicates.
  1985. //
  1986. return FALSE;
  1987. }
  1988. RedoScan:
  1989. list1 = &(Configuration1->List[0].PartialResourceList);
  1990. list2 = &(Configuration2->List[0].PartialResourceList);
  1991. for(i = 0, descriptor1 = list1->PartialDescriptors;
  1992. i < list1->Count;
  1993. i++, descriptor1++) {
  1994. //
  1995. // If this is an i/o port or a memory range then look for a match
  1996. // in the other list.
  1997. //
  1998. if((descriptor1->Type == CmResourceTypePort) ||
  1999. (descriptor1->Type == CmResourceTypeMemory)) {
  2000. for(j = 0, descriptor2 = list2->PartialDescriptors;
  2001. j < list2->Count;
  2002. j++, descriptor2++) {
  2003. //
  2004. // If the types match then check to see if both addresses
  2005. // match as well. If bus info was provided then go ahead
  2006. // and translate the ranges first.
  2007. //
  2008. if(descriptor1->Type == descriptor2->Type) {
  2009. PHYSICAL_ADDRESS range1, range1Translated;
  2010. PHYSICAL_ADDRESS range2, range2Translated;
  2011. ULONG range1IoSpace, range2IoSpace;
  2012. range1 = descriptor1->u.Generic.Start;
  2013. range2 = descriptor2->u.Generic.Start;
  2014. if((range1.QuadPart == 0) ||
  2015. (BusInfo1 == NULL) ||
  2016. (HalTranslateBusAddress(
  2017. BusInfo1->BusType,
  2018. BusInfo1->BusNumber,
  2019. range1,
  2020. &range1IoSpace,
  2021. &range1Translated) == FALSE)) {
  2022. range1Translated = range1;
  2023. range1IoSpace =
  2024. (descriptor1->Type == CmResourceTypePort) ? TRUE :
  2025. FALSE;
  2026. }
  2027. if((range2.QuadPart == 0) ||
  2028. (BusInfo2 == NULL) ||
  2029. (HalTranslateBusAddress(
  2030. BusInfo2->BusType,
  2031. BusInfo2->BusNumber,
  2032. range2,
  2033. &range2IoSpace,
  2034. &range2Translated) == FALSE)) {
  2035. range2Translated = range2;
  2036. range2IoSpace =
  2037. (descriptor2->Type == CmResourceTypePort) ? TRUE :
  2038. FALSE;
  2039. }
  2040. //
  2041. // If the ranges are in the same space and start at the
  2042. // same location then break out and go on to the next
  2043. // range
  2044. //
  2045. if((range1Translated.QuadPart == range2Translated.QuadPart) &&
  2046. (range1IoSpace == range2IoSpace)) {
  2047. break;
  2048. }
  2049. }
  2050. }
  2051. //
  2052. // If we made it all the way through the resource list without
  2053. // finding a match then these are not duplicates.
  2054. //
  2055. if(j == list2->Count) {
  2056. return FALSE;
  2057. }
  2058. }
  2059. }
  2060. //
  2061. // If every resource in list 1 exists in list 2 then we also need to make
  2062. // sure that every resource in list 2 exists in list 1.
  2063. //
  2064. if(pass == 0) {
  2065. PVOID tmp ;
  2066. tmp = Configuration2;
  2067. Configuration2 = Configuration1;
  2068. Configuration1 = tmp;
  2069. tmp = BusInfo2;
  2070. BusInfo2 = BusInfo1;
  2071. BusInfo1 = tmp;
  2072. pass = 1;
  2073. goto RedoScan;
  2074. }
  2075. return TRUE;
  2076. }
  2077. VOID
  2078. PipFreeUnicodeStringList(
  2079. IN PUNICODE_STRING UnicodeStringList,
  2080. IN ULONG StringCount
  2081. )
  2082. /*++
  2083. Routine Description:
  2084. This routine frees the buffer for each UNICODE_STRING in the specified list
  2085. (there are StringCount of them), and then frees the memory used for the
  2086. string list itself.
  2087. Arguments:
  2088. UnicodeStringList - Supplies a pointer to an array of UNICODE_STRINGs.
  2089. StringCount - Supplies the number of strings in the UnicodeStringList array.
  2090. Returns:
  2091. None.
  2092. NOTE: This function is only available during INIT time!
  2093. --*/
  2094. {
  2095. ULONG i;
  2096. if(UnicodeStringList) {
  2097. for(i = 0; i < StringCount; i++) {
  2098. if(UnicodeStringList[i].Buffer) {
  2099. ExFreePool(UnicodeStringList[i].Buffer);
  2100. }
  2101. }
  2102. ExFreePool(UnicodeStringList);
  2103. }
  2104. }
  2105. NTSTATUS
  2106. IopDriverLoadingFailed(
  2107. IN HANDLE ServiceHandle OPTIONAL,
  2108. IN PUNICODE_STRING ServiceName OPTIONAL
  2109. )
  2110. /*++
  2111. Routine Description:
  2112. This routine is invoked when driver failed to start. All the device
  2113. instances controlled by this driver/service are marked as failing to
  2114. start.
  2115. Arguments:
  2116. ServiceKeyHandle - Optionally, supplies a handle to the driver service node in the
  2117. registry that controls this device instance. If this argument is not specified,
  2118. then ServiceKeyName is used to specify the service entry.
  2119. ServiceKeyName - Optionally supplies the name of the service entry that controls
  2120. the device instance. This must be specified if ServiceKeyHandle isn't given.
  2121. Returns:
  2122. None.
  2123. --*/
  2124. {
  2125. NTSTATUS status;
  2126. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  2127. BOOLEAN closeHandle = FALSE, deletePdo;
  2128. HANDLE handle, serviceEnumHandle, controlHandle, devInstHandle;
  2129. HANDLE sysEnumHandle = NULL;
  2130. ULONG deviceFlags, count, newCount, i, j;
  2131. UNICODE_STRING unicodeValueName, deviceInstanceName;
  2132. WCHAR unicodeBuffer[20];
  2133. //
  2134. // Open registry ServiceKeyName\Enum branch
  2135. //
  2136. if (!ARGUMENT_PRESENT(ServiceHandle)) {
  2137. status = PipOpenServiceEnumKeys(ServiceName,
  2138. KEY_READ,
  2139. &ServiceHandle,
  2140. &serviceEnumHandle,
  2141. FALSE
  2142. );
  2143. closeHandle = TRUE;
  2144. } else {
  2145. PiWstrToUnicodeString(&unicodeValueName, REGSTR_KEY_ENUM);
  2146. status = IopOpenRegistryKeyEx( &serviceEnumHandle,
  2147. ServiceHandle,
  2148. &unicodeValueName,
  2149. KEY_READ
  2150. );
  2151. }
  2152. if (!NT_SUCCESS( status )) {
  2153. //
  2154. // No Service Enum key? no device instance. Return FALSE.
  2155. //
  2156. return status;
  2157. }
  2158. //
  2159. // Set "STARTFAILED" flags. So, we won't load it again.
  2160. //
  2161. PiWstrToUnicodeString(&unicodeValueName, L"INITSTARTFAILED");
  2162. deviceFlags = 1;
  2163. ZwSetValueKey(
  2164. serviceEnumHandle,
  2165. &unicodeValueName,
  2166. TITLE_INDEX_VALUE,
  2167. REG_DWORD,
  2168. &deviceFlags,
  2169. sizeof(deviceFlags)
  2170. );
  2171. //
  2172. // Find out how many device instances listed in the ServiceName's
  2173. // Enum key.
  2174. //
  2175. status = IopGetRegistryValue ( serviceEnumHandle,
  2176. REGSTR_VALUE_COUNT,
  2177. &keyValueInformation
  2178. );
  2179. count = 0;
  2180. if (NT_SUCCESS(status)) {
  2181. if ((keyValueInformation->Type == REG_DWORD) &&
  2182. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  2183. count = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  2184. }
  2185. ExFreePool(keyValueInformation);
  2186. }
  2187. if (count == 0) {
  2188. ZwClose(serviceEnumHandle);
  2189. if (closeHandle) {
  2190. ZwClose(ServiceHandle);
  2191. }
  2192. return status;
  2193. }
  2194. //
  2195. // Open HTREE\ROOT\0 key so later we can remove device instance key
  2196. // from its AttachedComponents value name.
  2197. //
  2198. status = IopOpenRegistryKeyEx( &sysEnumHandle,
  2199. NULL,
  2200. &CmRegistryMachineSystemCurrentControlSetEnumName,
  2201. KEY_ALL_ACCESS
  2202. );
  2203. //
  2204. // Walk through each registered device instance to mark its Problem and
  2205. // StatusFlags as fail to start and reset its ActiveService
  2206. //
  2207. newCount = count;
  2208. for (i = 0; i < count; i++) {
  2209. deletePdo = FALSE;
  2210. status = PipServiceInstanceToDeviceInstance (
  2211. ServiceHandle,
  2212. ServiceName,
  2213. i,
  2214. &deviceInstanceName,
  2215. &handle,
  2216. KEY_ALL_ACCESS
  2217. );
  2218. if (NT_SUCCESS(status)) {
  2219. PDEVICE_OBJECT deviceObject;
  2220. PDEVICE_NODE deviceNode;
  2221. //
  2222. // If the device instance is a detected device reported during driver's
  2223. // DriverEntry we need to clean it up.
  2224. //
  2225. deviceObject = IopDeviceObjectFromDeviceInstance(&deviceInstanceName);
  2226. if (deviceObject) {
  2227. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  2228. if (deviceNode) {
  2229. IopReleaseDeviceResources(deviceNode, TRUE);
  2230. if ((deviceNode->Flags & DNF_MADEUP) &&
  2231. ((deviceNode->State == DeviceNodeStarted) ||
  2232. (deviceNode->State == DeviceNodeStartPostWork))) {
  2233. //
  2234. // Now mark this one deleted.
  2235. //
  2236. PipSetDevNodeState(deviceNode, DeviceNodeRemoved, NULL);
  2237. PipSetDevNodeProblem(deviceNode, CM_PROB_DEVICE_NOT_THERE);
  2238. deletePdo = TRUE;
  2239. }
  2240. }
  2241. ObDereferenceObject(deviceObject); // added via IopDeviceObjectFromDeviceInstance
  2242. }
  2243. PiLockPnpRegistry(FALSE);
  2244. PiWstrToUnicodeString(&unicodeValueName, REGSTR_KEY_CONTROL);
  2245. controlHandle = NULL;
  2246. status = IopOpenRegistryKeyEx( &controlHandle,
  2247. handle,
  2248. &unicodeValueName,
  2249. KEY_ALL_ACCESS
  2250. );
  2251. if (NT_SUCCESS(status)) {
  2252. status = IopGetRegistryValue(controlHandle,
  2253. REGSTR_VALUE_NEWLY_CREATED,
  2254. &keyValueInformation);
  2255. if (NT_SUCCESS(status)) {
  2256. ExFreePool(keyValueInformation);
  2257. }
  2258. if ((status != STATUS_OBJECT_NAME_NOT_FOUND) &&
  2259. (status != STATUS_OBJECT_PATH_NOT_FOUND)) {
  2260. //
  2261. // Remove the instance value name from service enum key
  2262. //
  2263. PiUlongToUnicodeString(&unicodeValueName, unicodeBuffer, 20, i);
  2264. status = ZwDeleteValueKey (serviceEnumHandle, &unicodeValueName);
  2265. if (NT_SUCCESS(status)) {
  2266. //
  2267. // If we can successfaully remove the instance value entry
  2268. // from service enum key, we then remove the device instance key
  2269. // Otherwise, we go thru normal path to mark driver loading failed
  2270. // in the device instance key.
  2271. //
  2272. newCount--;
  2273. ZwDeleteKey(controlHandle);
  2274. ZwDeleteKey(handle);
  2275. //
  2276. // We also want to delete the ROOT\LEGACY_<driver> key
  2277. //
  2278. if (sysEnumHandle) {
  2279. deviceInstanceName.Length -= 5 * sizeof(WCHAR);
  2280. deviceInstanceName.Buffer[deviceInstanceName.Length / sizeof(WCHAR)] =
  2281. UNICODE_NULL;
  2282. status = IopOpenRegistryKeyEx( &devInstHandle,
  2283. sysEnumHandle,
  2284. &deviceInstanceName,
  2285. KEY_ALL_ACCESS
  2286. );
  2287. if (NT_SUCCESS(status)) {
  2288. ZwDeleteKey(devInstHandle);
  2289. ZwClose(devInstHandle);
  2290. }
  2291. }
  2292. //
  2293. // If there is a PDO for this device, remove it
  2294. //
  2295. if (deletePdo) {
  2296. IoDeleteDevice(deviceObject);
  2297. }
  2298. ZwClose(controlHandle);
  2299. ZwClose(handle);
  2300. IopCleanupDeviceRegistryValues(&deviceInstanceName);
  2301. ExFreePool(deviceInstanceName.Buffer);
  2302. PiUnlockPnpRegistry();
  2303. continue;
  2304. }
  2305. }
  2306. }
  2307. //
  2308. // Reset Control\ActiveService value name.
  2309. //
  2310. if (controlHandle) {
  2311. PiWstrToUnicodeString(&unicodeValueName, REGSTR_VAL_ACTIVESERVICE);
  2312. ZwDeleteValueKey(controlHandle, &unicodeValueName);
  2313. ZwClose(controlHandle);
  2314. }
  2315. ZwClose(handle);
  2316. ExFreePool(deviceInstanceName.Buffer);
  2317. PiUnlockPnpRegistry();
  2318. }
  2319. }
  2320. //
  2321. // If some instance value entry is deleted, we need to update the count of instance
  2322. // value entries and rearrange the instance value entries under service enum key.
  2323. //
  2324. if (newCount != count) {
  2325. PiLockPnpRegistry(FALSE);
  2326. if (newCount != 0) {
  2327. j = 0;
  2328. i = 0;
  2329. while (i < count) {
  2330. PiUlongToUnicodeString(&unicodeValueName, unicodeBuffer, 20, i);
  2331. status = IopGetRegistryValue(serviceEnumHandle,
  2332. unicodeValueName.Buffer,
  2333. &keyValueInformation
  2334. );
  2335. if (NT_SUCCESS(status)) {
  2336. if (i != j) {
  2337. //
  2338. // Need to change the instance i to instance j
  2339. //
  2340. ZwDeleteValueKey(serviceEnumHandle, &unicodeValueName);
  2341. PiUlongToUnicodeString(&unicodeValueName, unicodeBuffer, 20, j);
  2342. ZwSetValueKey (serviceEnumHandle,
  2343. &unicodeValueName,
  2344. TITLE_INDEX_VALUE,
  2345. REG_SZ,
  2346. (PVOID)KEY_VALUE_DATA(keyValueInformation),
  2347. keyValueInformation->DataLength
  2348. );
  2349. }
  2350. ExFreePool(keyValueInformation);
  2351. j++;
  2352. }
  2353. i++;
  2354. }
  2355. }
  2356. //
  2357. // Don't forget to update the "Count=" and "NextInstance=" value entries
  2358. //
  2359. PiWstrToUnicodeString( &unicodeValueName, REGSTR_VALUE_COUNT);
  2360. ZwSetValueKey(serviceEnumHandle,
  2361. &unicodeValueName,
  2362. TITLE_INDEX_VALUE,
  2363. REG_DWORD,
  2364. &newCount,
  2365. sizeof (newCount)
  2366. );
  2367. PiWstrToUnicodeString( &unicodeValueName, REGSTR_VALUE_NEXT_INSTANCE);
  2368. ZwSetValueKey(serviceEnumHandle,
  2369. &unicodeValueName,
  2370. TITLE_INDEX_VALUE,
  2371. REG_DWORD,
  2372. &newCount,
  2373. sizeof (newCount)
  2374. );
  2375. PiUnlockPnpRegistry();
  2376. }
  2377. ZwClose(serviceEnumHandle);
  2378. if (closeHandle) {
  2379. ZwClose(ServiceHandle);
  2380. }
  2381. if (sysEnumHandle) {
  2382. ZwClose(sysEnumHandle);
  2383. }
  2384. return STATUS_SUCCESS;
  2385. }
  2386. VOID
  2387. IopDisableDevice(
  2388. IN PDEVICE_NODE DeviceNode
  2389. )
  2390. /*++
  2391. Routine Description:
  2392. This routine tries to ask a bus driver stopping decoding resources
  2393. Arguments:
  2394. DeviceNode - Specifies the device to be disabled.
  2395. Handle - specifies the device instance handle.
  2396. Returns:
  2397. None.
  2398. --*/
  2399. {
  2400. NTSTATUS status;
  2401. //
  2402. // If the device has boot config, we will query-remove and remove the device to free
  2403. // the boot config if possible.
  2404. //
  2405. status = IopRemoveDevice (DeviceNode->PhysicalDeviceObject, IRP_MN_QUERY_REMOVE_DEVICE);
  2406. if (NT_SUCCESS(status)) {
  2407. status = IopRemoveDevice (DeviceNode->PhysicalDeviceObject, IRP_MN_REMOVE_DEVICE);
  2408. ASSERT(NT_SUCCESS(status));
  2409. IopReleaseDeviceResources(DeviceNode, TRUE);
  2410. } else {
  2411. IopRemoveDevice (DeviceNode->PhysicalDeviceObject, IRP_MN_CANCEL_REMOVE_DEVICE);
  2412. }
  2413. if (PipDoesDevNodeHaveProblem(DeviceNode)) {
  2414. ASSERT(PipIsDevNodeProblem(DeviceNode, CM_PROB_NOT_CONFIGURED) ||
  2415. PipIsDevNodeProblem(DeviceNode, CM_PROB_FAILED_INSTALL) ||
  2416. PipIsDevNodeProblem(DeviceNode, CM_PROB_REINSTALL));
  2417. PipClearDevNodeProblem(DeviceNode);
  2418. }
  2419. PipSetDevNodeProblem(DeviceNode, CM_PROB_DISABLED);
  2420. }
  2421. BOOLEAN
  2422. IopIsAnyDeviceInstanceEnabled(
  2423. IN PUNICODE_STRING ServiceKeyName,
  2424. IN HANDLE ServiceHandle OPTIONAL,
  2425. IN BOOLEAN LegacyIncluded
  2426. )
  2427. /*++
  2428. Routine Description:
  2429. This routine checks if any of the devices instances is turned on for the specified
  2430. service. This routine is used for Pnp Driver only and is temporary function to support
  2431. SUR.
  2432. Arguments:
  2433. ServiceKeyName - Specifies the service key unicode name
  2434. ServiceHandle - Optionally supplies a handle to the service key to be checked.
  2435. LegacyIncluded - TRUE, a legacy device instance key is counted as a device instance.
  2436. FALSE, a legacy device instance key is not counted.
  2437. Returns:
  2438. A BOOLEAN value.
  2439. --*/
  2440. {
  2441. NTSTATUS status;
  2442. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  2443. HANDLE serviceEnumHandle, handle, controlHandle;
  2444. ULONG i, count, deviceFlags;
  2445. UNICODE_STRING unicodeName, instancePath;
  2446. BOOLEAN enabled, closeHandle = FALSE;
  2447. PDEVICE_OBJECT physicalDeviceObject;
  2448. PDEVICE_NODE deviceNode;
  2449. //
  2450. // Open registry ServiceKeyName\Enum branch
  2451. //
  2452. if (!ARGUMENT_PRESENT(ServiceHandle)) {
  2453. status = PipOpenServiceEnumKeys(ServiceKeyName,
  2454. KEY_READ,
  2455. &ServiceHandle,
  2456. &serviceEnumHandle,
  2457. FALSE
  2458. );
  2459. closeHandle = TRUE;
  2460. } else {
  2461. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_ENUM);
  2462. status = IopOpenRegistryKeyEx( &serviceEnumHandle,
  2463. ServiceHandle,
  2464. &unicodeName,
  2465. KEY_READ
  2466. );
  2467. }
  2468. if (!NT_SUCCESS( status )) {
  2469. //
  2470. // No Service Enum key? no device instance. Return FALSE.
  2471. //
  2472. return FALSE;
  2473. }
  2474. //
  2475. // Find out how many device instances listed in the ServiceName's
  2476. // Enum key.
  2477. //
  2478. status = IopGetRegistryValue ( serviceEnumHandle,
  2479. REGSTR_VALUE_COUNT,
  2480. &keyValueInformation
  2481. );
  2482. ZwClose(serviceEnumHandle);
  2483. count = 0;
  2484. if (NT_SUCCESS(status)) {
  2485. if ((keyValueInformation->Type == REG_DWORD) &&
  2486. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  2487. count = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  2488. }
  2489. ExFreePool(keyValueInformation);
  2490. }
  2491. if (count == 0) {
  2492. if (closeHandle) {
  2493. ZwClose(ServiceHandle);
  2494. }
  2495. return FALSE;
  2496. }
  2497. //
  2498. // Walk through each registered device instance to check it is enabled.
  2499. //
  2500. enabled = FALSE;
  2501. for (i = 0; i < count; i++) {
  2502. //
  2503. // Get device instance handle. If it fails, we will skip this device
  2504. // instance.
  2505. //
  2506. status = PipServiceInstanceToDeviceInstance (
  2507. ServiceHandle,
  2508. NULL,
  2509. i,
  2510. &instancePath,
  2511. &handle,
  2512. KEY_ALL_ACCESS
  2513. );
  2514. if (!NT_SUCCESS(status)) {
  2515. continue;
  2516. }
  2517. physicalDeviceObject = IopDeviceObjectFromDeviceInstance(&instancePath);
  2518. ExFreePool(instancePath.Buffer);
  2519. if (physicalDeviceObject) {
  2520. deviceNode = (PDEVICE_NODE)physicalDeviceObject->DeviceObjectExtension->DeviceNode;
  2521. if (deviceNode && (PipIsDevNodeProblem(deviceNode, CM_PROB_DISABLED) || PipIsDevNodeProblem(deviceNode, CM_PROB_HARDWARE_DISABLED))) {
  2522. ZwClose(handle);
  2523. ObDereferenceObject(physicalDeviceObject);
  2524. continue;
  2525. }
  2526. } else {
  2527. deviceNode = NULL;
  2528. }
  2529. //
  2530. // Check if the device instance has been disabled.
  2531. // First check global flag: CONFIGFLAG and then CSCONFIGFLAG.
  2532. //
  2533. deviceFlags = 0;
  2534. status = IopGetRegistryValue(handle,
  2535. REGSTR_VALUE_CONFIG_FLAGS,
  2536. &keyValueInformation);
  2537. if (NT_SUCCESS(status)) {
  2538. if ((keyValueInformation->Type == REG_DWORD) &&
  2539. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  2540. deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  2541. }
  2542. ExFreePool(keyValueInformation);
  2543. }
  2544. if (deviceFlags & CONFIGFLAG_DISABLED) {
  2545. //
  2546. // Convert this flag into the hardware profile-specific version, so it'll
  2547. // look the same as the CsConfigFlags we retrieve below.
  2548. //
  2549. deviceFlags = CSCONFIGFLAG_DISABLED;
  2550. } else {
  2551. status = PipGetServiceInstanceCsConfigFlags( ServiceKeyName,
  2552. i,
  2553. &deviceFlags
  2554. );
  2555. if (!NT_SUCCESS(status)) {
  2556. deviceFlags = 0;
  2557. }
  2558. }
  2559. //
  2560. // If the device is disabled (either globally, or specifically for this
  2561. // hardware profile), then mark the devnode as DNF_DISABLED.
  2562. //
  2563. if ((deviceFlags & CSCONFIGFLAG_DISABLED) || (deviceFlags & CSCONFIGFLAG_DO_NOT_START)) {
  2564. if (deviceNode) {
  2565. IopDisableDevice(deviceNode);
  2566. }
  2567. }
  2568. if (physicalDeviceObject) {
  2569. ObDereferenceObject(physicalDeviceObject);
  2570. }
  2571. //
  2572. // Finally, we need to set the STATUSFLAGS of the device instance to
  2573. // indicate if the driver is successfully started.
  2574. //
  2575. if (!(deviceFlags & (CSCONFIGFLAG_DISABLED | CSCONFIGFLAG_DO_NOT_CREATE | CSCONFIGFLAG_DO_NOT_START))) {
  2576. ULONG legacy;
  2577. //
  2578. // Check should legacy instance key be counted as an enabled device
  2579. //
  2580. if (LegacyIncluded == FALSE) {
  2581. //
  2582. // The legacy variable must be initialized to zero. Because the device
  2583. // instance key may be an enumerated device. In this case, there is no
  2584. // legacy value name.
  2585. //
  2586. legacy = 0;
  2587. status = IopGetRegistryValue(handle,
  2588. REGSTR_VALUE_LEGACY,
  2589. &keyValueInformation
  2590. );
  2591. if (NT_SUCCESS(status)) {
  2592. if ((keyValueInformation->Type == REG_DWORD) &&
  2593. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  2594. legacy = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  2595. }
  2596. ExFreePool(keyValueInformation);
  2597. }
  2598. } else {
  2599. legacy = 0;
  2600. }
  2601. if (legacy == 0) {
  2602. //
  2603. // Mark that the driver has at least a device instance to work with.
  2604. //
  2605. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  2606. status = IopCreateRegistryKeyEx( &controlHandle,
  2607. handle,
  2608. &unicodeName,
  2609. KEY_ALL_ACCESS,
  2610. REG_OPTION_VOLATILE,
  2611. NULL
  2612. );
  2613. if (NT_SUCCESS(status)) {
  2614. PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_ACTIVESERVICE);
  2615. ZwSetValueKey(
  2616. controlHandle,
  2617. &unicodeName,
  2618. TITLE_INDEX_VALUE,
  2619. REG_SZ,
  2620. ServiceKeyName->Buffer,
  2621. ServiceKeyName->Length + sizeof(UNICODE_NULL)
  2622. );
  2623. ZwClose(controlHandle);
  2624. }
  2625. enabled = TRUE;
  2626. }
  2627. }
  2628. ZwClose(handle);
  2629. }
  2630. if (closeHandle) {
  2631. ZwClose(ServiceHandle);
  2632. }
  2633. return enabled;
  2634. }
  2635. BOOLEAN
  2636. IopIsDeviceInstanceEnabled(
  2637. IN HANDLE DeviceInstanceHandle OPTIONAL,
  2638. IN PUNICODE_STRING DeviceInstance,
  2639. IN BOOLEAN DisableIfEnabled
  2640. )
  2641. /*++
  2642. Routine Description:
  2643. This routine checks if the specified devices instances is enabled.
  2644. Arguments:
  2645. DeviceInstanceHandle - Optionally supplies a handle to the device instance
  2646. key to be checked.
  2647. DeviceInstance - Specifies the device instance key unicode name. Caller
  2648. must at least specified DeviceInstanceHandle or DeviceInstance.
  2649. DisableIfEnabled - If this flag is set, and the device should be disabled
  2650. but is currently disabled, then the device is disabled.
  2651. Returns:
  2652. A BOOLEAN value.
  2653. --*/
  2654. {
  2655. NTSTATUS status;
  2656. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  2657. HANDLE handle, handle1;
  2658. ULONG deviceFlags;
  2659. BOOLEAN enabled, closeHandle = FALSE;
  2660. UNICODE_STRING unicodeString;
  2661. PDEVICE_OBJECT deviceObject = NULL;
  2662. PDEVICE_NODE deviceNode = NULL;
  2663. //
  2664. // Open registry ServiceKeyName\Enum branch
  2665. //
  2666. if (!ARGUMENT_PRESENT(DeviceInstanceHandle)) {
  2667. status = IopOpenRegistryKeyEx( &handle,
  2668. NULL,
  2669. &CmRegistryMachineSystemCurrentControlSetEnumName,
  2670. KEY_READ
  2671. );
  2672. if (NT_SUCCESS( status )) {
  2673. status = IopOpenRegistryKeyEx( &DeviceInstanceHandle,
  2674. handle,
  2675. DeviceInstance,
  2676. KEY_READ
  2677. );
  2678. ZwClose(handle);
  2679. }
  2680. if (!NT_SUCCESS( status )) {
  2681. return FALSE;
  2682. }
  2683. closeHandle = TRUE;
  2684. }
  2685. enabled = TRUE;
  2686. //
  2687. // First check the device node
  2688. //
  2689. deviceObject = IopDeviceObjectFromDeviceInstance(DeviceInstance);
  2690. if (deviceObject) {
  2691. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  2692. if (deviceNode && (PipIsDevNodeProblem(deviceNode, CM_PROB_DISABLED) || PipIsDevNodeProblem(deviceNode, CM_PROB_HARDWARE_DISABLED))) {
  2693. enabled = FALSE;
  2694. goto exit;
  2695. }
  2696. }
  2697. //
  2698. // Check if the device instance has been disabled.
  2699. // First check global flag: CONFIGFLAG and then CSCONFIGFLAG.
  2700. //
  2701. deviceFlags = 0;
  2702. status = IopGetRegistryValue(DeviceInstanceHandle,
  2703. REGSTR_VALUE_CONFIG_FLAGS,
  2704. &keyValueInformation);
  2705. if (NT_SUCCESS(status)) {
  2706. if ((keyValueInformation->Type == REG_DWORD) &&
  2707. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  2708. deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  2709. }
  2710. ExFreePool(keyValueInformation);
  2711. }
  2712. if (!(deviceFlags & CONFIGFLAG_DISABLED)) {
  2713. enabled = TRUE;
  2714. //
  2715. // See if we can open current hardware profile
  2716. //
  2717. status = IopOpenRegistryKeyEx( &handle1,
  2718. NULL,
  2719. &CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent,
  2720. KEY_READ
  2721. );
  2722. if (NT_SUCCESS(status) && DeviceInstance != NULL) {
  2723. //
  2724. // Now, we must open the System\CCS\Enum key under this.
  2725. //
  2726. //
  2727. // Open system\CurrentControlSet under current hardware profile key
  2728. //
  2729. PiWstrToUnicodeString(&unicodeString, REGSTR_PATH_CURRENTCONTROLSET);
  2730. status = IopOpenRegistryKeyEx( &handle,
  2731. handle1,
  2732. &unicodeString,
  2733. KEY_READ
  2734. );
  2735. ZwClose(handle1);
  2736. if (NT_SUCCESS(status)) {
  2737. PiWstrToUnicodeString(&unicodeString, REGSTR_KEY_ENUM);
  2738. status = IopOpenRegistryKeyEx( &handle1,
  2739. handle,
  2740. &unicodeString,
  2741. KEY_READ
  2742. );
  2743. ZwClose(handle);
  2744. if (NT_SUCCESS(status)) {
  2745. status = IopOpenRegistryKeyEx( &handle,
  2746. handle1,
  2747. DeviceInstance,
  2748. KEY_READ
  2749. );
  2750. ZwClose(handle1);
  2751. if (NT_SUCCESS(status)) {
  2752. status = IopGetRegistryValue(
  2753. handle,
  2754. REGSTR_VALUE_CSCONFIG_FLAGS,
  2755. &keyValueInformation
  2756. );
  2757. if (NT_SUCCESS(status)) {
  2758. if((keyValueInformation->Type == REG_DWORD) &&
  2759. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  2760. deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  2761. }
  2762. ExFreePool(keyValueInformation);
  2763. }
  2764. ZwClose(handle);
  2765. if (NT_SUCCESS(status)) {
  2766. if ((deviceFlags & CSCONFIGFLAG_DISABLED) ||
  2767. (deviceFlags & CSCONFIGFLAG_DO_NOT_CREATE) ||
  2768. (deviceFlags & CSCONFIGFLAG_DO_NOT_START)) {
  2769. enabled = FALSE;
  2770. }
  2771. }
  2772. }
  2773. }
  2774. }
  2775. }
  2776. } else {
  2777. enabled = FALSE;
  2778. }
  2779. //
  2780. // If the device is disabled and has device node associated with it.
  2781. // disable the device.
  2782. //
  2783. if (enabled == FALSE && deviceNode && DisableIfEnabled) {
  2784. IopDisableDevice(deviceNode);
  2785. }
  2786. exit:
  2787. if (deviceObject) {
  2788. ObDereferenceObject(deviceObject);
  2789. }
  2790. if (closeHandle) {
  2791. ZwClose(DeviceInstanceHandle);
  2792. }
  2793. return enabled;
  2794. }
  2795. ULONG
  2796. IopDetermineResourceListSize(
  2797. IN PCM_RESOURCE_LIST ResourceList
  2798. )
  2799. /*++
  2800. Routine Description:
  2801. This routine determines size of the passed in ResourceList
  2802. structure.
  2803. Arguments:
  2804. Configuration1 - Supplies a pointer to the resource list.
  2805. Return Value:
  2806. size of the resource list structure.
  2807. --*/
  2808. {
  2809. ULONG totalSize, listSize, descriptorSize, i, j;
  2810. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  2811. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  2812. if (!ResourceList) {
  2813. totalSize = 0;
  2814. } else {
  2815. totalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
  2816. fullResourceDesc = &ResourceList->List[0];
  2817. for (i = 0; i < ResourceList->Count; i++) {
  2818. listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  2819. PartialResourceList) +
  2820. FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
  2821. PartialDescriptors);
  2822. partialDescriptor = &fullResourceDesc->PartialResourceList.PartialDescriptors[0];
  2823. for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) {
  2824. descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  2825. if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) {
  2826. descriptorSize += partialDescriptor->u.DeviceSpecificData.DataSize;
  2827. }
  2828. listSize += descriptorSize;
  2829. partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  2830. ((PUCHAR)partialDescriptor + descriptorSize);
  2831. }
  2832. totalSize += listSize;
  2833. fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
  2834. ((PUCHAR)fullResourceDesc + listSize);
  2835. }
  2836. }
  2837. return totalSize;
  2838. }
  2839. VOID
  2840. PpInitializeDeviceReferenceTable(
  2841. VOID
  2842. )
  2843. /*++
  2844. Routine Description:
  2845. This routine initializes data structures associated with the device
  2846. reference table.
  2847. Arguments:
  2848. None.
  2849. Return Value:
  2850. None.
  2851. --*/
  2852. {
  2853. ExInitializeFastMutex(&PpDeviceReferenceTableLock);
  2854. RtlInitializeGenericTable( &PpDeviceReferenceTable,
  2855. PiCompareInstancePath,
  2856. PiAllocateGenericTableEntry,
  2857. PiFreeGenericTableEntry,
  2858. NULL);
  2859. }
  2860. RTL_GENERIC_COMPARE_RESULTS
  2861. NTAPI
  2862. PiCompareInstancePath(
  2863. IN PRTL_GENERIC_TABLE Table,
  2864. IN PVOID FirstStruct,
  2865. IN PVOID SecondStruct
  2866. )
  2867. /*++
  2868. Routine Description:
  2869. This routine is the callback for the generic table routines.
  2870. Arguments:
  2871. Table - Table for which this is invoked.
  2872. FirstStruct - An element in the table to compare.
  2873. SecondStruct - Another element in the table to compare.
  2874. Return Value:
  2875. RTL_GENERIC_COMPARE_RESULTS.
  2876. --*/
  2877. {
  2878. PUNICODE_STRING lhs = ((PDEVICE_REFERENCE)FirstStruct)->DeviceInstance;
  2879. PUNICODE_STRING rhs = ((PDEVICE_REFERENCE)SecondStruct)->DeviceInstance;
  2880. LONG result;
  2881. PAGED_CODE();
  2882. result = RtlCompareUnicodeString(lhs, rhs, TRUE);
  2883. if (result < 0) {
  2884. return GenericLessThan;
  2885. } else if (result > 0) {
  2886. return GenericGreaterThan;
  2887. }
  2888. return GenericEqual;
  2889. }
  2890. PVOID
  2891. NTAPI
  2892. PiAllocateGenericTableEntry(
  2893. IN PRTL_GENERIC_TABLE Table,
  2894. IN CLONG ByteSize
  2895. )
  2896. /*++
  2897. Routine Description:
  2898. This routine is the callback for allocation for entries in the generic table.
  2899. Arguments:
  2900. Table - Table for which this is invoked.
  2901. ByteSize - Amount of memory to allocate.
  2902. Return Value:
  2903. Pointer to allocated memory if successful, else NULL.
  2904. --*/
  2905. {
  2906. PAGED_CODE();
  2907. return ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, ByteSize);
  2908. }
  2909. VOID
  2910. NTAPI
  2911. PiFreeGenericTableEntry(
  2912. IN PRTL_GENERIC_TABLE Table,
  2913. IN PVOID Buffer
  2914. )
  2915. /*++
  2916. Routine Description:
  2917. This routine is the callback for releasing memory for entries in the generic
  2918. table.
  2919. Arguments:
  2920. Table - Table for which this is invoked.
  2921. Buffer - Buffer to free.
  2922. Return Value:
  2923. None.
  2924. --*/
  2925. {
  2926. PAGED_CODE();
  2927. ExFreePool(Buffer);
  2928. }
  2929. NTSTATUS
  2930. IopMapDeviceObjectToDeviceInstance(
  2931. IN PDEVICE_OBJECT DeviceObject,
  2932. IN PUNICODE_STRING DeviceInstance
  2933. )
  2934. /*++
  2935. Routine Description:
  2936. This routine adds a reference for the specified device to the
  2937. PpDeviceReferenceTable lookup table.
  2938. Note, caller must own the PpRegistryDeviceResource before calling the
  2939. function.
  2940. Arguments:
  2941. DeviceObject - supplies a pointer to a physical device object.
  2942. DeviceInstance - supplies a UNICODE_STRING to specify the device instance path.
  2943. Return Value:
  2944. Status code that indicates whether or not the function was successful.
  2945. --*/
  2946. {
  2947. NTSTATUS status;
  2948. HANDLE hEnum, hInstance, hControl;
  2949. UNICODE_STRING unicodeKeyName;
  2950. DEVICE_REFERENCE deviceReference;
  2951. #if DBG
  2952. PDEVICE_OBJECT oldDeviceObject;
  2953. #endif
  2954. #if DBG
  2955. oldDeviceObject = IopDeviceObjectFromDeviceInstance(DeviceInstance);
  2956. ASSERT(!oldDeviceObject);
  2957. if (oldDeviceObject) {
  2958. ObDereferenceObject(oldDeviceObject);
  2959. }
  2960. #endif
  2961. deviceReference.DeviceObject = DeviceObject;
  2962. deviceReference.DeviceInstance = DeviceInstance;
  2963. ExAcquireFastMutex(&PpDeviceReferenceTableLock);
  2964. if (RtlInsertElementGenericTable(&PpDeviceReferenceTable,
  2965. (PVOID)&deviceReference,
  2966. (CLONG)sizeof(DEVICE_REFERENCE),
  2967. NULL)) {
  2968. status = STATUS_SUCCESS;
  2969. } else {
  2970. status = STATUS_UNSUCCESSFUL;
  2971. }
  2972. ExReleaseFastMutex(&PpDeviceReferenceTableLock);
  2973. if (NT_SUCCESS(status)) {
  2974. //
  2975. // Create the volatile Control subkey for this device instance,
  2976. // since user-mode depends on it to be present for non-phantom
  2977. // devices.
  2978. //
  2979. // NTRAID #174944-2000/08/30-jamesca:
  2980. // Remove dependence on the presence of volatile Control subkey
  2981. // for present devices.
  2982. //
  2983. status = IopOpenRegistryKeyEx(&hEnum,
  2984. NULL,
  2985. &CmRegistryMachineSystemCurrentControlSetEnumName,
  2986. KEY_READ);
  2987. if (NT_SUCCESS(status)) {
  2988. status = IopOpenRegistryKeyEx(&hInstance,
  2989. hEnum,
  2990. DeviceInstance,
  2991. KEY_ALL_ACCESS);
  2992. if (NT_SUCCESS(status)) {
  2993. PiWstrToUnicodeString(&unicodeKeyName, REGSTR_KEY_CONTROL);
  2994. status = IopCreateRegistryKeyEx(&hControl,
  2995. hInstance,
  2996. &unicodeKeyName,
  2997. KEY_ALL_ACCESS,
  2998. REG_OPTION_VOLATILE,
  2999. NULL);
  3000. if (NT_SUCCESS(status)) {
  3001. ZwClose(hControl);
  3002. }
  3003. ZwClose(hInstance);
  3004. }
  3005. ZwClose(hEnum);
  3006. }
  3007. //
  3008. // The attempt to create the volatile Control subkey should always
  3009. // succeed, but just in case it didn't, make sure to always return
  3010. // STATUS_SUCCESS when the device reference is successfully added to
  3011. // the table.
  3012. //
  3013. ASSERT(NT_SUCCESS(status));
  3014. status = STATUS_SUCCESS;
  3015. }
  3016. return status;
  3017. }
  3018. PDEVICE_OBJECT
  3019. IopDeviceObjectFromDeviceInstance(
  3020. IN PUNICODE_STRING DeviceInstance
  3021. )
  3022. /*++
  3023. Routine Description:
  3024. This routine receives a DeviceInstance path (or DeviceInstance handle) and
  3025. returns a reference to a bus device object for the DeviceInstance.
  3026. Note, caller must owner the PpRegistryDeviceResource before calling the function,
  3027. Arguments:
  3028. DeviceInstance - supplies a UNICODE_STRING to specify the device instance path.
  3029. Returns:
  3030. A reference to the desired bus device object.
  3031. --*/
  3032. {
  3033. DEVICE_REFERENCE key;
  3034. PDEVICE_REFERENCE deviceReference;
  3035. PDEVICE_OBJECT deviceObject;
  3036. PDEVICE_NODE deviceNode;
  3037. PAGED_CODE();
  3038. //
  3039. // Look-up the DO in our table.
  3040. //
  3041. deviceObject = NULL;
  3042. key.DeviceObject = NULL;
  3043. key.DeviceInstance = DeviceInstance;
  3044. ExAcquireFastMutex(&PpDeviceReferenceTableLock);
  3045. deviceReference = RtlLookupElementGenericTable(&PpDeviceReferenceTable, (PVOID)&key);
  3046. if (deviceReference) {
  3047. deviceObject = deviceReference->DeviceObject;
  3048. ASSERT(deviceObject);
  3049. if (deviceObject) {
  3050. ASSERT(deviceObject->Type == IO_TYPE_DEVICE);
  3051. if (deviceObject->Type != IO_TYPE_DEVICE) {
  3052. deviceObject = NULL;
  3053. } else {
  3054. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  3055. ASSERT(deviceNode && (deviceNode->PhysicalDeviceObject == deviceObject));
  3056. if (!deviceNode || deviceNode->PhysicalDeviceObject != deviceObject) {
  3057. deviceObject = NULL;
  3058. }
  3059. }
  3060. }
  3061. }
  3062. //
  3063. // Take a reference if we found the device object.
  3064. //
  3065. if (deviceObject) {
  3066. ObReferenceObject(deviceObject);
  3067. }
  3068. ExReleaseFastMutex(&PpDeviceReferenceTableLock);
  3069. return deviceObject;
  3070. }
  3071. NTSTATUS
  3072. IopDeviceObjectToDeviceInstance (
  3073. IN PDEVICE_OBJECT DeviceObject,
  3074. IN PHANDLE DeviceInstanceHandle,
  3075. IN ACCESS_MASK DesiredAccess
  3076. )
  3077. /*++
  3078. Routine Description:
  3079. This routine receives a DeviceObject pointer and returns a handle to the device
  3080. instance path under registry System\ENUM key.
  3081. Note, caller must owner the PpRegistryDeviceResource before calling the function,
  3082. Arguments:
  3083. DeviceObject - supplies a pointer to a physical device object.
  3084. DeviceInstanceHandle - Supplies a variable to receive the handle to the registry
  3085. device instance key.
  3086. DesiredAccess - specifies the access that is needed to this key.
  3087. Returns:
  3088. NTSTATUS code to indicate success or failure.
  3089. --*/
  3090. {
  3091. NTSTATUS status;
  3092. HANDLE handle;
  3093. PDEVICE_NODE deviceNode;
  3094. PAGED_CODE();
  3095. status = IopOpenRegistryKeyEx( &handle,
  3096. NULL,
  3097. &CmRegistryMachineSystemCurrentControlSetEnumName,
  3098. KEY_READ
  3099. );
  3100. if (!NT_SUCCESS( status )) {
  3101. return status;
  3102. }
  3103. deviceNode = (PDEVICE_NODE) DeviceObject->DeviceObjectExtension->DeviceNode;
  3104. if (deviceNode && (deviceNode->InstancePath.Length != 0)) {
  3105. status = IopOpenRegistryKeyEx( DeviceInstanceHandle,
  3106. handle,
  3107. &deviceNode->InstancePath,
  3108. DesiredAccess
  3109. );
  3110. } else {
  3111. status = STATUS_INVALID_DEVICE_REQUEST;
  3112. }
  3113. ZwClose(handle);
  3114. return status;
  3115. }
  3116. NTSTATUS
  3117. IopCleanupDeviceRegistryValues (
  3118. IN PUNICODE_STRING InstancePath
  3119. )
  3120. /*++
  3121. Routine Description:
  3122. This routine cleans up a device instance key when the device is no
  3123. longer present/enumerated. If the device is registered to a Service
  3124. the Service's enum key will also been cleaned up.
  3125. Note the caller must lock the RegistryDeviceResource
  3126. Arguments:
  3127. InstancePath - supplies a pointer to the name of the device instance key.
  3128. Return Value:
  3129. status
  3130. --*/
  3131. {
  3132. DEVICE_REFERENCE key;
  3133. NTSTATUS status;
  3134. #if DBG
  3135. PDEVICE_OBJECT deviceObject;
  3136. #endif
  3137. PAGED_CODE();
  3138. //
  3139. // Delete the mapping between this instance path and corresponding DO.
  3140. //
  3141. key.DeviceObject = NULL;
  3142. key.DeviceInstance = InstancePath;
  3143. ExAcquireFastMutex(&PpDeviceReferenceTableLock);
  3144. RtlDeleteElementGenericTable(&PpDeviceReferenceTable, (PVOID)&key);
  3145. ExReleaseFastMutex(&PpDeviceReferenceTableLock);
  3146. #if DBG
  3147. deviceObject = IopDeviceObjectFromDeviceInstance(InstancePath);
  3148. ASSERT(!deviceObject);
  3149. if (deviceObject) {
  3150. ObDereferenceObject(deviceObject);
  3151. }
  3152. #endif
  3153. //
  3154. // Deregister the device from its controlling service's service enum key
  3155. //
  3156. status = PiDeviceRegistration( InstancePath, FALSE, NULL );
  3157. return status;
  3158. }
  3159. NTSTATUS
  3160. IopGetDeviceResourcesFromRegistry (
  3161. IN PDEVICE_OBJECT DeviceObject,
  3162. IN ULONG ResourceType,
  3163. IN ULONG Preference,
  3164. OUT PVOID *Resource,
  3165. OUT PULONG Length
  3166. )
  3167. /*++
  3168. Routine Description:
  3169. This routine determines the resources decoded by the device specified.
  3170. If the device object is a madeup device, we will try to read the resources
  3171. from registry. Otherwise, we need to traverse the internal assigned resource
  3172. list to compose the resource list.
  3173. Arguments:
  3174. DeviceObject - supplies a pointer to a device object whose registry
  3175. values are to be cleaned up.
  3176. ResourceType - 0 for CM_RESOURCE_LIST and 1 for IO_RESOURCE_REQUIREMENTS_LIS
  3177. Flags - specify the preference.
  3178. Resource - Specified a variable to receive the required resources.
  3179. Length - Specified a variable to receive the length of the resource structure.
  3180. Return Value:
  3181. status
  3182. --*/
  3183. {
  3184. HANDLE handle, handlex;
  3185. NTSTATUS status;
  3186. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  3187. UNICODE_STRING unicodeName;
  3188. PWCHAR valueName = NULL;
  3189. *Resource = NULL;
  3190. *Length = 0;
  3191. //
  3192. // Open the LogConfig key of the device instance.
  3193. //
  3194. status = IopDeviceObjectToDeviceInstance(DeviceObject, &handlex, KEY_READ);
  3195. if (!NT_SUCCESS(status)) {
  3196. return status;
  3197. }
  3198. if (ResourceType == QUERY_RESOURCE_LIST) {
  3199. //
  3200. // Caller is asking for CM_RESOURCE_LIST
  3201. //
  3202. if (Preference & REGISTRY_ALLOC_CONFIG) {
  3203. //
  3204. // Try alloc config first
  3205. //
  3206. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  3207. status = IopOpenRegistryKeyEx( &handle,
  3208. handlex,
  3209. &unicodeName,
  3210. KEY_READ
  3211. );
  3212. if (NT_SUCCESS(status)) {
  3213. status = PipReadDeviceConfiguration (handle, REGISTRY_ALLOC_CONFIG, (PCM_RESOURCE_LIST *)Resource, Length);
  3214. ZwClose(handle);
  3215. if (NT_SUCCESS(status)) {
  3216. ZwClose(handlex);
  3217. return status;
  3218. }
  3219. }
  3220. }
  3221. handle = NULL;
  3222. if (Preference & REGISTRY_FORCED_CONFIG) {
  3223. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  3224. status = IopOpenRegistryKeyEx( &handle,
  3225. handlex,
  3226. &unicodeName,
  3227. KEY_READ
  3228. );
  3229. if (NT_SUCCESS(status)) {
  3230. status = PipReadDeviceConfiguration (handle, REGISTRY_FORCED_CONFIG, (PCM_RESOURCE_LIST *)Resource, Length);
  3231. if (NT_SUCCESS(status)) {
  3232. ZwClose(handle);
  3233. ZwClose(handlex);
  3234. return status;
  3235. }
  3236. } else {
  3237. ZwClose(handlex);
  3238. return status;
  3239. }
  3240. }
  3241. if (Preference & REGISTRY_BOOT_CONFIG) {
  3242. //
  3243. // Try alloc config first
  3244. //
  3245. if (handle == NULL) {
  3246. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  3247. status = IopOpenRegistryKeyEx( &handle,
  3248. handlex,
  3249. &unicodeName,
  3250. KEY_READ
  3251. );
  3252. if (!NT_SUCCESS(status)) {
  3253. ZwClose(handlex);
  3254. return status;
  3255. }
  3256. }
  3257. status = PipReadDeviceConfiguration( handle,
  3258. REGISTRY_BOOT_CONFIG,
  3259. (PCM_RESOURCE_LIST *)Resource,
  3260. Length);
  3261. }
  3262. if (handle) {
  3263. ZwClose(handle);
  3264. }
  3265. } else {
  3266. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  3267. status = IopOpenRegistryKeyEx( &handle,
  3268. handlex,
  3269. &unicodeName,
  3270. KEY_READ
  3271. );
  3272. if (NT_SUCCESS(status)) {
  3273. if (Preference & REGISTRY_OVERRIDE_CONFIGVECTOR) {
  3274. valueName = REGSTR_VALUE_OVERRIDE_CONFIG_VECTOR;
  3275. } else if (Preference & REGISTRY_BASIC_CONFIGVECTOR) {
  3276. valueName = REGSTR_VALUE_BASIC_CONFIG_VECTOR;
  3277. }
  3278. if (valueName) {
  3279. //
  3280. // Try to read device's configuration vector
  3281. //
  3282. status = IopGetRegistryValue (handle,
  3283. valueName,
  3284. &keyValueInformation);
  3285. if (NT_SUCCESS(status)) {
  3286. //
  3287. // Try to read what caller wants.
  3288. //
  3289. if ((keyValueInformation->Type == REG_RESOURCE_REQUIREMENTS_LIST) &&
  3290. (keyValueInformation->DataLength != 0)) {
  3291. *Resource = ExAllocatePool(PagedPool,
  3292. keyValueInformation->DataLength);
  3293. if (*Resource) {
  3294. PIO_RESOURCE_REQUIREMENTS_LIST ioResource;
  3295. *Length = keyValueInformation->DataLength;
  3296. RtlCopyMemory(*Resource,
  3297. KEY_VALUE_DATA(keyValueInformation),
  3298. keyValueInformation->DataLength);
  3299. //
  3300. // Process the io resource requirements list to change undefined
  3301. // interface type to our default type.
  3302. //
  3303. ioResource = *Resource;
  3304. if (ioResource->InterfaceType == InterfaceTypeUndefined) {
  3305. ioResource->BusNumber = 0;
  3306. ioResource->InterfaceType = PnpDefaultInterfaceType;
  3307. }
  3308. } else {
  3309. status = STATUS_INVALID_PARAMETER_2;
  3310. }
  3311. }
  3312. ExFreePool(keyValueInformation);
  3313. }
  3314. }
  3315. ZwClose(handle);
  3316. }
  3317. }
  3318. ZwClose(handlex);
  3319. return status;
  3320. }
  3321. NTSTATUS
  3322. PipReadDeviceConfiguration (
  3323. IN HANDLE Handle,
  3324. IN ULONG Flags,
  3325. OUT PCM_RESOURCE_LIST *CmResource,
  3326. OUT PULONG Length
  3327. )
  3328. /*++
  3329. Routine Description:
  3330. This routine read the specified ALLOC config or ForcedConfig or Boot config.
  3331. Arguments:
  3332. Hanle - supplies a handle to the registry key to read resources.
  3333. Return Value:
  3334. status
  3335. --*/
  3336. {
  3337. NTSTATUS status;
  3338. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  3339. PWCHAR valueName;
  3340. *CmResource = NULL;
  3341. *Length = 0;
  3342. if (Flags == REGISTRY_ALLOC_CONFIG) {
  3343. valueName = REGSTR_VALUE_ALLOC_CONFIG;
  3344. } else if (Flags == REGISTRY_FORCED_CONFIG) {
  3345. valueName = REGSTR_VALUE_FORCED_CONFIG;
  3346. } else if (Flags == REGISTRY_BOOT_CONFIG) {
  3347. valueName = REGSTR_VALUE_BOOT_CONFIG;
  3348. } else {
  3349. return STATUS_INVALID_PARAMETER_2;
  3350. }
  3351. //
  3352. // Read the registry value of the desired value name
  3353. //
  3354. status = IopGetRegistryValue (Handle,
  3355. valueName,
  3356. &keyValueInformation);
  3357. if (NT_SUCCESS(status)) {
  3358. //
  3359. // Try to read what caller wants.
  3360. //
  3361. if ((keyValueInformation->Type == REG_RESOURCE_LIST) &&
  3362. (keyValueInformation->DataLength != 0)) {
  3363. *CmResource = ExAllocatePool(PagedPool,
  3364. keyValueInformation->DataLength);
  3365. if (*CmResource) {
  3366. if (*CmResource) {
  3367. *Length = keyValueInformation->DataLength;
  3368. RtlCopyMemory(*CmResource,
  3369. KEY_VALUE_DATA(keyValueInformation),
  3370. keyValueInformation->DataLength);
  3371. } else {
  3372. status = STATUS_INSUFFICIENT_RESOURCES;
  3373. }
  3374. }
  3375. ExFreePool(keyValueInformation);
  3376. if (*CmResource) {
  3377. PCM_RESOURCE_LIST resourceList;
  3378. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  3379. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
  3380. ULONG j, k, size;
  3381. //
  3382. // Process the resource list read from Registry to change undefined
  3383. // interface type to our default interface type.
  3384. //
  3385. resourceList = *CmResource;
  3386. cmFullDesc = &resourceList->List[0];
  3387. for (j = 0; j < resourceList->Count; j++) {
  3388. if (cmFullDesc->InterfaceType == InterfaceTypeUndefined) {
  3389. cmFullDesc->BusNumber = 0;
  3390. cmFullDesc->InterfaceType = PnpDefaultInterfaceType;
  3391. }
  3392. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  3393. for (k = 0; k < cmFullDesc->PartialResourceList.Count; k++) {
  3394. size = 0;
  3395. switch (cmPartDesc->Type) {
  3396. case CmResourceTypeDeviceSpecific:
  3397. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  3398. break;
  3399. }
  3400. cmPartDesc++;
  3401. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  3402. }
  3403. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  3404. }
  3405. }
  3406. } else if (keyValueInformation->Type != REG_RESOURCE_LIST) {
  3407. status = STATUS_UNSUCCESSFUL;
  3408. }
  3409. }
  3410. return status;
  3411. }
  3412. PIO_RESOURCE_REQUIREMENTS_LIST
  3413. IopCmResourcesToIoResources(
  3414. IN ULONG SlotNumber,
  3415. IN PCM_RESOURCE_LIST CmResourceList,
  3416. IN ULONG Priority
  3417. )
  3418. /*++
  3419. Routine Description:
  3420. This routines converts the input CmResourceList to IO_RESOURCE_REQUIREMENTS_LIST.
  3421. Arguments:
  3422. SlotNumber - supplies the SlotNumber the resources refer to.
  3423. CmResourceList - the cm resource list to convert.
  3424. Priority - specifies the priority of the logconfig
  3425. Return Value:
  3426. returns a IO_RESOURCE_REQUIREMENTS_LISTST if succeeds. Otherwise a NULL value is
  3427. returned.
  3428. --*/
  3429. {
  3430. PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList;
  3431. ULONG count = 0, size, i, j;
  3432. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  3433. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
  3434. PIO_RESOURCE_DESCRIPTOR ioDesc;
  3435. //
  3436. // First determine number of descriptors required.
  3437. //
  3438. cmFullDesc = &CmResourceList->List[0];
  3439. for (i = 0; i < CmResourceList->Count; i++) {
  3440. count += cmFullDesc->PartialResourceList.Count;
  3441. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  3442. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  3443. size = 0;
  3444. switch (cmPartDesc->Type) {
  3445. case CmResourceTypeDeviceSpecific:
  3446. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  3447. count--;
  3448. break;
  3449. }
  3450. cmPartDesc++;
  3451. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  3452. }
  3453. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  3454. }
  3455. if (count == 0) {
  3456. return NULL;
  3457. }
  3458. //
  3459. // Count the extra descriptors for InterfaceType and BusNumber information.
  3460. //
  3461. count += CmResourceList->Count - 1;
  3462. //
  3463. // Allocate heap space for IO RESOURCE REQUIREMENTS LIST
  3464. //
  3465. count++; // add one for CmResourceTypeConfigData
  3466. ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool(
  3467. PagedPool,
  3468. sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  3469. count * sizeof(IO_RESOURCE_DESCRIPTOR)
  3470. );
  3471. if (!ioResReqList) {
  3472. return NULL;
  3473. }
  3474. //
  3475. // Parse the cm resource descriptor and build its corresponding IO resource descriptor
  3476. //
  3477. ioResReqList->InterfaceType = CmResourceList->List[0].InterfaceType;
  3478. ioResReqList->BusNumber = CmResourceList->List[0].BusNumber;
  3479. ioResReqList->SlotNumber = SlotNumber;
  3480. ioResReqList->Reserved[0] = 0;
  3481. ioResReqList->Reserved[1] = 0;
  3482. ioResReqList->Reserved[2] = 0;
  3483. ioResReqList->AlternativeLists = 1;
  3484. ioResReqList->List[0].Version = 1;
  3485. ioResReqList->List[0].Revision = 1;
  3486. ioResReqList->List[0].Count = count;
  3487. //
  3488. // Generate a CmResourceTypeConfigData descriptor
  3489. //
  3490. ioDesc = &ioResReqList->List[0].Descriptors[0];
  3491. ioDesc->Option = IO_RESOURCE_PREFERRED;
  3492. ioDesc->Type = CmResourceTypeConfigData;
  3493. ioDesc->ShareDisposition = CmResourceShareShared;
  3494. ioDesc->Flags = 0;
  3495. ioDesc->Spare1 = 0;
  3496. ioDesc->Spare2 = 0;
  3497. ioDesc->u.ConfigData.Priority = Priority;
  3498. ioDesc++;
  3499. cmFullDesc = &CmResourceList->List[0];
  3500. for (i = 0; i < CmResourceList->Count; i++) {
  3501. if (i != 0) {
  3502. //
  3503. // Set up descriptor to remember the InterfaceType and BusNumber.
  3504. //
  3505. ioDesc->Option = IO_RESOURCE_PREFERRED;
  3506. ioDesc->Type = CmResourceTypeReserved;
  3507. ioDesc->ShareDisposition = CmResourceShareUndetermined;
  3508. ioDesc->Flags = 0;
  3509. ioDesc->Spare1 = 0;
  3510. ioDesc->Spare2 = 0;
  3511. if (cmFullDesc->InterfaceType == InterfaceTypeUndefined) {
  3512. ioDesc->u.DevicePrivate.Data[0] = PnpDefaultInterfaceType;
  3513. } else {
  3514. ioDesc->u.DevicePrivate.Data[0] = cmFullDesc->InterfaceType;
  3515. }
  3516. ioDesc->u.DevicePrivate.Data[1] = cmFullDesc->BusNumber;
  3517. ioDesc->u.DevicePrivate.Data[2] = 0;
  3518. ioDesc++;
  3519. }
  3520. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  3521. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  3522. ioDesc->Option = IO_RESOURCE_PREFERRED;
  3523. ioDesc->Type = cmPartDesc->Type;
  3524. ioDesc->ShareDisposition = cmPartDesc->ShareDisposition;
  3525. ioDesc->Flags = cmPartDesc->Flags;
  3526. ioDesc->Spare1 = 0;
  3527. ioDesc->Spare2 = 0;
  3528. size = 0;
  3529. switch (cmPartDesc->Type) {
  3530. case CmResourceTypePort:
  3531. ioDesc->u.Port.MinimumAddress = cmPartDesc->u.Port.Start;
  3532. ioDesc->u.Port.MaximumAddress.QuadPart = cmPartDesc->u.Port.Start.QuadPart +
  3533. cmPartDesc->u.Port.Length - 1;
  3534. ioDesc->u.Port.Alignment = 1;
  3535. ioDesc->u.Port.Length = cmPartDesc->u.Port.Length;
  3536. ioDesc++;
  3537. break;
  3538. case CmResourceTypeInterrupt:
  3539. #if defined(_X86_)
  3540. ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector =
  3541. cmPartDesc->u.Interrupt.Level;
  3542. #else
  3543. ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector =
  3544. cmPartDesc->u.Interrupt.Vector;
  3545. #endif
  3546. ioDesc++;
  3547. break;
  3548. case CmResourceTypeMemory:
  3549. ioDesc->u.Memory.MinimumAddress = cmPartDesc->u.Memory.Start;
  3550. ioDesc->u.Memory.MaximumAddress.QuadPart = cmPartDesc->u.Memory.Start.QuadPart +
  3551. cmPartDesc->u.Memory.Length - 1;
  3552. ioDesc->u.Memory.Alignment = 1;
  3553. ioDesc->u.Memory.Length = cmPartDesc->u.Memory.Length;
  3554. ioDesc++;
  3555. break;
  3556. case CmResourceTypeDma:
  3557. ioDesc->u.Dma.MinimumChannel = cmPartDesc->u.Dma.Channel;
  3558. ioDesc->u.Dma.MaximumChannel = cmPartDesc->u.Dma.Channel;
  3559. ioDesc++;
  3560. break;
  3561. case CmResourceTypeDeviceSpecific:
  3562. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  3563. break;
  3564. case CmResourceTypeBusNumber:
  3565. ioDesc->u.BusNumber.MinBusNumber = cmPartDesc->u.BusNumber.Start;
  3566. ioDesc->u.BusNumber.MaxBusNumber = cmPartDesc->u.BusNumber.Start +
  3567. cmPartDesc->u.BusNumber.Length - 1;
  3568. ioDesc->u.BusNumber.Length = cmPartDesc->u.BusNumber.Length;
  3569. ioDesc++;
  3570. break;
  3571. default:
  3572. ioDesc->u.DevicePrivate.Data[0] = cmPartDesc->u.DevicePrivate.Data[0];
  3573. ioDesc->u.DevicePrivate.Data[1] = cmPartDesc->u.DevicePrivate.Data[1];
  3574. ioDesc->u.DevicePrivate.Data[2] = cmPartDesc->u.DevicePrivate.Data[2];
  3575. ioDesc++;
  3576. break;
  3577. }
  3578. cmPartDesc++;
  3579. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  3580. }
  3581. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  3582. }
  3583. ioResReqList->ListSize = (ULONG)((ULONG_PTR)ioDesc - (ULONG_PTR)ioResReqList);
  3584. return ioResReqList;
  3585. }
  3586. NTSTATUS
  3587. IopFilterResourceRequirementsList(
  3588. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList,
  3589. IN PCM_RESOURCE_LIST CmList,
  3590. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *FilteredList,
  3591. OUT PBOOLEAN ExactMatch
  3592. )
  3593. /*++
  3594. Routine Description:
  3595. This routines adjusts the input IoList based on input BootConfig.
  3596. Arguments:
  3597. IoList - supplies the pointer to an IoResourceRequirementsList
  3598. CmList - supplies the pointer to a BootConfig.
  3599. FilteredList - Supplies a variable to receive the filtered resource
  3600. requirements list.
  3601. Return Value:
  3602. A NTSTATUS code to indicate the result of the function.
  3603. --*/
  3604. {
  3605. PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList;
  3606. PIO_RESOURCE_LIST ioResourceList, newIoResourceList, selectedResourceList = NULL;
  3607. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor, ioResourceDescriptorEnd;
  3608. PIO_RESOURCE_DESCRIPTOR newIoResourceDescriptor, configDataDescriptor;
  3609. LONG ioResourceDescriptorCount = 0;
  3610. USHORT version;
  3611. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  3612. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor;
  3613. ULONG cmDescriptorCount = 0;
  3614. ULONG size, i, j, oldCount, phase;
  3615. LONG k, alternativeLists;
  3616. BOOLEAN exactMatch;
  3617. PAGED_CODE();
  3618. *FilteredList = NULL;
  3619. *ExactMatch = FALSE;
  3620. //
  3621. // Make sure there is some resource requirements to be filtered.
  3622. // If no, we will convert CmList/BootConfig to an IoResourceRequirementsList
  3623. //
  3624. if (IoList == NULL || IoList->AlternativeLists == 0) {
  3625. if (CmList && CmList->Count != 0) {
  3626. *FilteredList = IopCmResourcesToIoResources (0, CmList, LCPRI_BOOTCONFIG);
  3627. }
  3628. return STATUS_SUCCESS;
  3629. }
  3630. //
  3631. // Make a copy of the Io Resource Requirements List
  3632. //
  3633. ioList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, IoList->ListSize);
  3634. if (ioList == NULL) {
  3635. return STATUS_INSUFFICIENT_RESOURCES;
  3636. }
  3637. RtlCopyMemory(ioList, IoList, IoList->ListSize);
  3638. //
  3639. // If there is no BootConfig, simply return the copy of the input Io list.
  3640. //
  3641. if (CmList == NULL || CmList->Count == 0) {
  3642. *FilteredList = ioList;
  3643. return STATUS_SUCCESS;
  3644. }
  3645. //
  3646. // First determine minimum number of descriptors required.
  3647. //
  3648. cmFullDesc = &CmList->List[0];
  3649. for (i = 0; i < CmList->Count; i++) {
  3650. cmDescriptorCount += cmFullDesc->PartialResourceList.Count;
  3651. cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  3652. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  3653. size = 0;
  3654. switch (cmDescriptor->Type) {
  3655. case CmResourceTypeConfigData:
  3656. case CmResourceTypeDevicePrivate:
  3657. cmDescriptorCount--;
  3658. break;
  3659. case CmResourceTypeDeviceSpecific:
  3660. size = cmDescriptor->u.DeviceSpecificData.DataSize;
  3661. cmDescriptorCount--;
  3662. break;
  3663. default:
  3664. //
  3665. // Invalid cmresource list. Ignore it and use io resources
  3666. //
  3667. if (cmDescriptor->Type == CmResourceTypeNull ||
  3668. cmDescriptor->Type >= CmResourceTypeMaximum) {
  3669. cmDescriptorCount--;
  3670. }
  3671. }
  3672. cmDescriptor++;
  3673. cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size);
  3674. }
  3675. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor;
  3676. }
  3677. if (cmDescriptorCount == 0) {
  3678. *FilteredList = ioList;
  3679. return STATUS_SUCCESS;
  3680. }
  3681. //
  3682. // cmDescriptorCount is the number of BootConfig Descriptors needs.
  3683. //
  3684. // For each IO list Alternative ...
  3685. //
  3686. ioResourceList = ioList->List;
  3687. k = ioList->AlternativeLists;
  3688. while (--k >= 0) {
  3689. ioResourceDescriptor = ioResourceList->Descriptors;
  3690. ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
  3691. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  3692. ioResourceDescriptor->Spare1 = 0;
  3693. ioResourceDescriptor++;
  3694. }
  3695. ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd;
  3696. }
  3697. ioResourceList = ioList->List;
  3698. k = alternativeLists = ioList->AlternativeLists;
  3699. while (--k >= 0) {
  3700. version = ioResourceList->Version;
  3701. if (version == 0xffff) { // Convert bogus version to valid number
  3702. version = 1;
  3703. }
  3704. //
  3705. // We use Version field to store number of BootConfig found.
  3706. // Count field to store new number of descriptor in the alternative list.
  3707. //
  3708. ioResourceList->Version = 0;
  3709. oldCount = ioResourceList->Count;
  3710. ioResourceDescriptor = ioResourceList->Descriptors;
  3711. ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
  3712. if (ioResourceDescriptor == ioResourceDescriptorEnd) {
  3713. //
  3714. // An alternative list with zero descriptor count
  3715. //
  3716. ioResourceList->Version = 0xffff; // Mark it as invalid
  3717. ioList->AlternativeLists--;
  3718. continue;
  3719. }
  3720. exactMatch = TRUE;
  3721. //
  3722. // For each Cm Resource descriptor ... except DevicePrivate and
  3723. // DeviceSpecific...
  3724. //
  3725. cmFullDesc = &CmList->List[0];
  3726. for (i = 0; i < CmList->Count; i++) {
  3727. cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  3728. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  3729. size = 0;
  3730. switch (cmDescriptor->Type) {
  3731. case CmResourceTypeDevicePrivate:
  3732. break;
  3733. case CmResourceTypeDeviceSpecific:
  3734. size = cmDescriptor->u.DeviceSpecificData.DataSize;
  3735. break;
  3736. default:
  3737. if (cmDescriptor->Type == CmResourceTypeNull ||
  3738. cmDescriptor->Type >= CmResourceTypeMaximum) {
  3739. break;
  3740. }
  3741. //
  3742. // Check CmDescriptor against current Io Alternative list
  3743. //
  3744. for (phase = 0; phase < 2; phase++) {
  3745. ioResourceDescriptor = ioResourceList->Descriptors;
  3746. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  3747. if ((ioResourceDescriptor->Type == cmDescriptor->Type) &&
  3748. (ioResourceDescriptor->Spare1 == 0)) {
  3749. ULONGLONG min1, max1, min2, max2;
  3750. ULONG len1 = 1, len2 = 1, align1, align2;
  3751. UCHAR share1, share2;
  3752. share2 = ioResourceDescriptor->ShareDisposition;
  3753. share1 = cmDescriptor->ShareDisposition;
  3754. if ((share1 == CmResourceShareUndetermined) ||
  3755. (share1 > CmResourceShareShared)) {
  3756. share1 = share2;
  3757. }
  3758. if ((share2 == CmResourceShareUndetermined) ||
  3759. (share2 > CmResourceShareShared)) {
  3760. share2 = share1;
  3761. }
  3762. align1 = align2 = 1;
  3763. switch (cmDescriptor->Type) {
  3764. case CmResourceTypePort:
  3765. case CmResourceTypeMemory:
  3766. min1 = cmDescriptor->u.Port.Start.QuadPart;
  3767. max1 = cmDescriptor->u.Port.Start.QuadPart + cmDescriptor->u.Port.Length - 1;
  3768. len1 = cmDescriptor->u.Port.Length;
  3769. min2 = ioResourceDescriptor->u.Port.MinimumAddress.QuadPart;
  3770. max2 = ioResourceDescriptor->u.Port.MaximumAddress.QuadPart;
  3771. len2 = ioResourceDescriptor->u.Port.Length;
  3772. align2 = ioResourceDescriptor->u.Port.Alignment;
  3773. break;
  3774. case CmResourceTypeInterrupt:
  3775. max1 = min1 = cmDescriptor->u.Interrupt.Vector;
  3776. min2 = ioResourceDescriptor->u.Interrupt.MinimumVector;
  3777. max2 = ioResourceDescriptor->u.Interrupt.MaximumVector;
  3778. break;
  3779. case CmResourceTypeDma:
  3780. min1 = max1 =cmDescriptor->u.Dma.Channel;
  3781. min2 = ioResourceDescriptor->u.Dma.MinimumChannel;
  3782. max2 = ioResourceDescriptor->u.Dma.MaximumChannel;
  3783. break;
  3784. case CmResourceTypeBusNumber:
  3785. min1 = cmDescriptor->u.BusNumber.Start;
  3786. max1 = cmDescriptor->u.BusNumber.Start + cmDescriptor->u.BusNumber.Length - 1;
  3787. len1 = cmDescriptor->u.BusNumber.Length;
  3788. min2 = ioResourceDescriptor->u.BusNumber.MinBusNumber;
  3789. max2 = ioResourceDescriptor->u.BusNumber.MaxBusNumber;
  3790. len2 = ioResourceDescriptor->u.BusNumber.Length;
  3791. break;
  3792. default:
  3793. ASSERT(0);
  3794. break;
  3795. }
  3796. if (phase == 0) {
  3797. if (share1 == share2 && min2 == min1 && max2 >= max1 && len2 >= len1) {
  3798. //
  3799. // For phase 0 match, we want near exact match...
  3800. //
  3801. if (max2 != max1) {
  3802. exactMatch = FALSE;
  3803. }
  3804. ioResourceList->Version++;
  3805. ioResourceDescriptor->Spare1 = 0x80;
  3806. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  3807. PIO_RESOURCE_DESCRIPTOR ioDesc;
  3808. ioDesc = ioResourceDescriptor;
  3809. ioDesc--;
  3810. while (ioDesc >= ioResourceList->Descriptors) {
  3811. ioDesc->Type = CmResourceTypeNull;
  3812. ioResourceList->Count--;
  3813. if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) {
  3814. ioDesc--;
  3815. } else {
  3816. break;
  3817. }
  3818. }
  3819. }
  3820. ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
  3821. ioResourceDescriptor->Flags = cmDescriptor->Flags;
  3822. if (ioResourceDescriptor->Type == CmResourceTypePort ||
  3823. ioResourceDescriptor->Type == CmResourceTypeMemory) {
  3824. ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1;
  3825. ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1;
  3826. ioResourceDescriptor->u.Port.Alignment = 1;
  3827. } else if (ioResourceDescriptor->Type == CmResourceTypeBusNumber) {
  3828. ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1;
  3829. ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1);
  3830. }
  3831. ioResourceDescriptor++;
  3832. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  3833. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  3834. ioResourceDescriptor->Type = CmResourceTypeNull;
  3835. ioResourceDescriptor++;
  3836. ioResourceList->Count--;
  3837. } else {
  3838. break;
  3839. }
  3840. }
  3841. phase = 1; // skip phase 1
  3842. break;
  3843. } else {
  3844. ioResourceDescriptor++;
  3845. }
  3846. } else {
  3847. exactMatch = FALSE;
  3848. if (share1 == share2 && min2 <= min1 && max2 >= max1 && len2 >= len1 &&
  3849. (min1 & (align2 - 1)) == 0) {
  3850. //
  3851. // Io range covers Cm range ... Change the Io range to what is specified
  3852. // in BootConfig.
  3853. //
  3854. //
  3855. switch (cmDescriptor->Type) {
  3856. case CmResourceTypePort:
  3857. case CmResourceTypeMemory:
  3858. ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1;
  3859. ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1;
  3860. break;
  3861. case CmResourceTypeInterrupt:
  3862. case CmResourceTypeDma:
  3863. ioResourceDescriptor->u.Interrupt.MinimumVector = (ULONG)min1;
  3864. ioResourceDescriptor->u.Interrupt.MaximumVector = (ULONG)max1;
  3865. break;
  3866. case CmResourceTypeBusNumber:
  3867. ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1;
  3868. ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1);
  3869. break;
  3870. }
  3871. ioResourceList->Version++;
  3872. ioResourceDescriptor->Spare1 = 0x80;
  3873. ioResourceDescriptor->Flags = cmDescriptor->Flags;
  3874. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  3875. PIO_RESOURCE_DESCRIPTOR ioDesc;
  3876. ioDesc = ioResourceDescriptor;
  3877. ioDesc--;
  3878. while (ioDesc >= ioResourceList->Descriptors) {
  3879. ioDesc->Type = CmResourceTypeNull;
  3880. ioResourceList->Count--;
  3881. if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) {
  3882. ioDesc--;
  3883. } else {
  3884. break;
  3885. }
  3886. }
  3887. }
  3888. ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
  3889. ioResourceDescriptor++;
  3890. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  3891. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  3892. ioResourceDescriptor->Type = CmResourceTypeNull;
  3893. ioResourceList->Count--;
  3894. ioResourceDescriptor++;
  3895. } else {
  3896. break;
  3897. }
  3898. }
  3899. break;
  3900. } else {
  3901. ioResourceDescriptor++;
  3902. }
  3903. }
  3904. } else {
  3905. ioResourceDescriptor++;
  3906. }
  3907. } // Don't add any instruction after this ...
  3908. } // phase
  3909. } // switch
  3910. //
  3911. // Move to next Cm Descriptor
  3912. //
  3913. cmDescriptor++;
  3914. cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size);
  3915. }
  3916. //
  3917. // Move to next Cm List
  3918. //
  3919. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor;
  3920. }
  3921. if (ioResourceList->Version != (USHORT)cmDescriptorCount) {
  3922. //
  3923. // If the current alternative list does not cover all the boot config
  3924. // descriptors, make it as invalid.
  3925. //
  3926. ioResourceList->Version = 0xffff;
  3927. ioList->AlternativeLists--;
  3928. } else {
  3929. if ((ioResourceList->Count == cmDescriptorCount) ||
  3930. (ioResourceList->Count == (cmDescriptorCount + 1) &&
  3931. ioResourceList->Descriptors[0].Type == CmResourceTypeConfigData)) {
  3932. if (selectedResourceList) {
  3933. ioResourceList->Version = 0xffff;
  3934. ioList->AlternativeLists--;
  3935. } else {
  3936. selectedResourceList = ioResourceList;
  3937. ioResourceDescriptorCount += ioResourceList->Count;
  3938. ioResourceList->Version = version;
  3939. if (exactMatch) {
  3940. *ExactMatch = TRUE;
  3941. }
  3942. }
  3943. } else {
  3944. ioResourceDescriptorCount += ioResourceList->Count;
  3945. ioResourceList->Version = version;
  3946. }
  3947. }
  3948. ioResourceList->Count = oldCount;
  3949. //
  3950. // Move to next Io alternative list.
  3951. //
  3952. ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd;
  3953. }
  3954. //
  3955. // If there is not any valid alternative, convert CmList to Io list.
  3956. //
  3957. if (ioList->AlternativeLists == 0) {
  3958. *FilteredList = IopCmResourcesToIoResources (0, CmList, LCPRI_BOOTCONFIG);
  3959. ExFreePool(ioList);
  3960. return STATUS_SUCCESS;
  3961. }
  3962. //
  3963. // we have finished filtering the resource requirements list. Now allocate memory
  3964. // and rebuild a new list.
  3965. //
  3966. size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  3967. sizeof(IO_RESOURCE_LIST) * (ioList->AlternativeLists - 1) +
  3968. sizeof(IO_RESOURCE_DESCRIPTOR) * (ioResourceDescriptorCount);
  3969. newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
  3970. if (newList == NULL) {
  3971. ExFreePool(ioList);
  3972. return STATUS_INSUFFICIENT_RESOURCES;
  3973. }
  3974. //
  3975. // Walk through the io resource requirements list and pick up any valid descriptor.
  3976. //
  3977. newList->ListSize = size;
  3978. newList->InterfaceType = CmList->List->InterfaceType;
  3979. newList->BusNumber = CmList->List->BusNumber;
  3980. newList->SlotNumber = ioList->SlotNumber;
  3981. if (ioList->AlternativeLists > 1) {
  3982. *ExactMatch = FALSE;
  3983. }
  3984. newList->AlternativeLists = ioList->AlternativeLists;
  3985. ioResourceList = ioList->List;
  3986. newIoResourceList = newList->List;
  3987. while (--alternativeLists >= 0) {
  3988. ioResourceDescriptor = ioResourceList->Descriptors;
  3989. ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
  3990. if (ioResourceList->Version == 0xffff) {
  3991. ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd;
  3992. continue;
  3993. }
  3994. newIoResourceList->Version = ioResourceList->Version;
  3995. newIoResourceList->Revision = ioResourceList->Revision;
  3996. newIoResourceDescriptor = newIoResourceList->Descriptors;
  3997. if (ioResourceDescriptor->Type != CmResourceTypeConfigData) {
  3998. newIoResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
  3999. newIoResourceDescriptor->Type = CmResourceTypeConfigData;
  4000. newIoResourceDescriptor->ShareDisposition = CmResourceShareShared;
  4001. newIoResourceDescriptor->Flags = 0;
  4002. newIoResourceDescriptor->Spare1 = 0;
  4003. newIoResourceDescriptor->Spare2 = 0;
  4004. newIoResourceDescriptor->u.ConfigData.Priority = LCPRI_BOOTCONFIG;
  4005. configDataDescriptor = newIoResourceDescriptor;
  4006. newIoResourceDescriptor++;
  4007. } else {
  4008. newList->ListSize -= sizeof(IO_RESOURCE_DESCRIPTOR);
  4009. configDataDescriptor = newIoResourceDescriptor;
  4010. }
  4011. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  4012. if (ioResourceDescriptor->Type != CmResourceTypeNull) {
  4013. *newIoResourceDescriptor = *ioResourceDescriptor;
  4014. newIoResourceDescriptor++;
  4015. }
  4016. ioResourceDescriptor++;
  4017. }
  4018. newIoResourceList->Count = (ULONG)(newIoResourceDescriptor - newIoResourceList->Descriptors);
  4019. //if (newIoResourceList->Count == (cmDescriptorCount + 1)) {
  4020. configDataDescriptor->u.ConfigData.Priority = LCPRI_BOOTCONFIG;
  4021. //}
  4022. //
  4023. // Move to next Io alternative list.
  4024. //
  4025. newIoResourceList = (PIO_RESOURCE_LIST) newIoResourceDescriptor;
  4026. ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd;
  4027. }
  4028. ASSERT((PUCHAR)newIoResourceList == ((PUCHAR)newList + newList->ListSize));
  4029. *FilteredList = newList;
  4030. ExFreePool(ioList);
  4031. return STATUS_SUCCESS;
  4032. }
  4033. NTSTATUS
  4034. IopMergeFilteredResourceRequirementsList (
  4035. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList1,
  4036. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList2,
  4037. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *MergedList
  4038. )
  4039. /*++
  4040. Routine Description:
  4041. This routines merges two IoLists into one.
  4042. Arguments:
  4043. IoList1 - supplies the pointer to the first IoResourceRequirementsList
  4044. IoList2 - supplies the pointer to the second IoResourceRequirementsList
  4045. MergedList - Supplies a variable to receive the merged resource
  4046. requirements list.
  4047. Return Value:
  4048. A NTSTATUS code to indicate the result of the function.
  4049. --*/
  4050. {
  4051. NTSTATUS status = STATUS_SUCCESS;
  4052. PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList;
  4053. ULONG size;
  4054. PUCHAR p;
  4055. PAGED_CODE();
  4056. *MergedList = NULL;
  4057. //
  4058. // First handle the easy cases that both IO Lists are empty or any one of
  4059. // them is empty.
  4060. //
  4061. if ((IoList1 == NULL || IoList1->AlternativeLists == 0) &&
  4062. (IoList2 == NULL || IoList2->AlternativeLists == 0)) {
  4063. return status;
  4064. }
  4065. ioList = NULL;
  4066. if (IoList1 == NULL || IoList1->AlternativeLists == 0) {
  4067. ioList = IoList2;
  4068. } else if (IoList2 == NULL || IoList2->AlternativeLists == 0) {
  4069. ioList = IoList1;
  4070. }
  4071. if (ioList) {
  4072. newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, ioList->ListSize);
  4073. if (newList == NULL) {
  4074. return STATUS_INSUFFICIENT_RESOURCES;
  4075. }
  4076. RtlCopyMemory(newList, ioList, ioList->ListSize);
  4077. *MergedList = newList;
  4078. return status;
  4079. }
  4080. //
  4081. // Do real work...
  4082. //
  4083. size = IoList1->ListSize + IoList2->ListSize - FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List);
  4084. newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(
  4085. PagedPool,
  4086. size
  4087. );
  4088. if (newList == NULL) {
  4089. return STATUS_INSUFFICIENT_RESOURCES;
  4090. }
  4091. p = (PUCHAR)newList;
  4092. RtlCopyMemory(p, IoList1, IoList1->ListSize);
  4093. p += IoList1->ListSize;
  4094. RtlCopyMemory(p,
  4095. &IoList2->List[0],
  4096. size - IoList1->ListSize
  4097. );
  4098. newList->ListSize = size;
  4099. newList->AlternativeLists += IoList2->AlternativeLists;
  4100. *MergedList = newList;
  4101. return status;
  4102. }
  4103. NTSTATUS
  4104. IopMergeCmResourceLists (
  4105. IN PCM_RESOURCE_LIST List1,
  4106. IN PCM_RESOURCE_LIST List2,
  4107. IN OUT PCM_RESOURCE_LIST *MergedList
  4108. )
  4109. /*++
  4110. Routine Description:
  4111. This routines merges two IoLists into one.
  4112. Arguments:
  4113. IoList1 - supplies the pointer to the first CmResourceList
  4114. IoList2 - supplies the pointer to the second CmResourceList
  4115. MergedList - Supplies a variable to receive the merged resource
  4116. list.
  4117. Return Value:
  4118. A NTSTATUS code to indicate the result of the function.
  4119. --*/
  4120. {
  4121. NTSTATUS status = STATUS_SUCCESS;
  4122. PCM_RESOURCE_LIST cmList, newList;
  4123. ULONG size, size1, size2;
  4124. PUCHAR p;
  4125. PAGED_CODE();
  4126. *MergedList = NULL;
  4127. //
  4128. // First handle the easy cases that both IO Lists are empty or any one of
  4129. // them is empty.
  4130. //
  4131. if ((List1 == NULL || List1->Count == 0) &&
  4132. (List2 == NULL || List2->Count == 0)) {
  4133. return status;
  4134. }
  4135. cmList = NULL;
  4136. if (List1 == NULL || List1->Count == 0) {
  4137. cmList = List2;
  4138. } else if (List2 == NULL || List2->Count == 0) {
  4139. cmList = List1;
  4140. }
  4141. if (cmList) {
  4142. size = IopDetermineResourceListSize(cmList);
  4143. newList = (PCM_RESOURCE_LIST) ExAllocatePool(PagedPool, size);
  4144. if (newList == NULL) {
  4145. return STATUS_INSUFFICIENT_RESOURCES;
  4146. }
  4147. RtlCopyMemory(newList, cmList, size);
  4148. *MergedList = newList;
  4149. return status;
  4150. }
  4151. //
  4152. // Do real work...
  4153. //
  4154. size1 = IopDetermineResourceListSize(List1);
  4155. size2 = IopDetermineResourceListSize(List2);
  4156. size = size1 + size2;
  4157. newList = (PCM_RESOURCE_LIST) ExAllocatePool(
  4158. PagedPool,
  4159. size
  4160. );
  4161. if (newList == NULL) {
  4162. return STATUS_INSUFFICIENT_RESOURCES;
  4163. }
  4164. p = (PUCHAR)newList;
  4165. RtlCopyMemory(p, List1, size1);
  4166. p += size1;
  4167. RtlCopyMemory(p,
  4168. &List2->List[0],
  4169. size2 - FIELD_OFFSET(CM_RESOURCE_LIST, List)
  4170. );
  4171. newList->Count = List1->Count + List2->Count;
  4172. *MergedList = newList;
  4173. return status;
  4174. }
  4175. BOOLEAN
  4176. IopIsLegacyDriver (
  4177. IN PDRIVER_OBJECT DriverObject
  4178. )
  4179. /*++
  4180. Routine Description:
  4181. This routine checks if the driver object specifies a legacy driver.
  4182. Arguments:
  4183. DriverObject - supplies a pointer to the driver object to be checked.
  4184. Return Value:
  4185. BOOLEAN
  4186. --*/
  4187. {
  4188. PAGED_CODE();
  4189. //
  4190. // If AddDevice entry is not empty it is a wdm driver
  4191. //
  4192. if (DriverObject->DriverExtension->AddDevice) {
  4193. return FALSE;
  4194. }
  4195. //
  4196. // Else if LEGACY flag is set in the driver object, it's a legacy driver.
  4197. //
  4198. if (DriverObject->Flags & DRVO_LEGACY_DRIVER) {
  4199. return TRUE;
  4200. } else {
  4201. return FALSE;
  4202. }
  4203. }
  4204. VOID
  4205. IopDeleteLegacyKey(
  4206. IN PDRIVER_OBJECT DriverObject
  4207. )
  4208. /*++
  4209. Routine Description:
  4210. This routine checks if the Legacy= value of the driver's legacy_xxx key
  4211. is one. If yes, it deletes the Legacy key.
  4212. Parameters:
  4213. DriverObject - supplies a pointer to the driver object.
  4214. Return Value:
  4215. None. If anything fails in this routine, the legacy key stays.
  4216. --*/
  4217. {
  4218. WCHAR buffer[MAX_DEVICE_ID_LEN];
  4219. NTSTATUS status;
  4220. UNICODE_STRING deviceName, instanceName, unicodeName, *serviceName;
  4221. ULONG length;
  4222. HANDLE handle, handle1, handlex, enumHandle;
  4223. ULONG legacy;
  4224. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  4225. PDEVICE_OBJECT deviceObject;
  4226. PDEVICE_NODE deviceNode;
  4227. BOOLEAN deletedPDO;
  4228. serviceName = &DriverObject->DriverExtension->ServiceKeyName;
  4229. PiLockPnpRegistry(FALSE);
  4230. status = IopOpenRegistryKeyEx( &enumHandle,
  4231. NULL,
  4232. &CmRegistryMachineSystemCurrentControlSetEnumName,
  4233. KEY_ALL_ACCESS
  4234. );
  4235. if (!NT_SUCCESS(status)) {
  4236. goto exit;
  4237. }
  4238. status = PipGenerateMadeupNodeName( serviceName,
  4239. &deviceName
  4240. );
  4241. if (!NT_SUCCESS(status)) {
  4242. goto exit;
  4243. }
  4244. length = _snwprintf(buffer,
  4245. sizeof(buffer) / sizeof(WCHAR),
  4246. L"%s\\%s",
  4247. REGSTR_KEY_ROOTENUM,
  4248. deviceName.Buffer);
  4249. RtlFreeUnicodeString(&deviceName);
  4250. deviceName.MaximumLength = sizeof(buffer);
  4251. ASSERT(length <= sizeof(buffer) - 10);
  4252. deviceName.Length = (USHORT)(length * sizeof(WCHAR));
  4253. deviceName.Buffer = buffer;
  4254. RtlUpcaseUnicodeString(&deviceName, &deviceName, FALSE);
  4255. status = IopOpenRegistryKeyEx( &handle1,
  4256. enumHandle,
  4257. &deviceName,
  4258. KEY_ALL_ACCESS
  4259. );
  4260. if (NT_SUCCESS(status)) {
  4261. deviceName.Buffer[deviceName.Length / sizeof(WCHAR)] =
  4262. OBJ_NAME_PATH_SEPARATOR;
  4263. deviceName.Length += sizeof(WCHAR);
  4264. PiUlongToInstanceKeyUnicodeString(
  4265. &instanceName,
  4266. buffer + deviceName.Length / sizeof(WCHAR),
  4267. sizeof(buffer) - deviceName.Length,
  4268. 0
  4269. );
  4270. deviceName.Length += instanceName.Length;
  4271. //
  4272. // deviceName is now the full InstancePath (ROOT\LEGACY_service\0000)
  4273. // and instancePath points to the instance ID (0000)
  4274. //
  4275. status = IopOpenRegistryKeyEx( &handle,
  4276. handle1,
  4277. &instanceName,
  4278. KEY_ALL_ACCESS
  4279. );
  4280. if (NT_SUCCESS(status)) {
  4281. legacy = 1;
  4282. status = IopGetRegistryValue (handle,
  4283. REGSTR_VALUE_LEGACY,
  4284. &keyValueInformation);
  4285. if (NT_SUCCESS(status)) {
  4286. if ((keyValueInformation->Type == REG_DWORD) &&
  4287. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  4288. legacy = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  4289. }
  4290. ExFreePool(keyValueInformation);
  4291. }
  4292. if (legacy != 0) {
  4293. //
  4294. // We also want to delete the madeup device node
  4295. //
  4296. deletedPDO = FALSE;
  4297. deviceObject = IopDeviceObjectFromDeviceInstance(&deviceName);
  4298. if (deviceObject) {
  4299. PDEVICE_NODE devNodex, devNodey;
  4300. deviceNode = (PDEVICE_NODE)deviceObject->DeviceObjectExtension->DeviceNode;
  4301. if (deviceNode != NULL && (deviceNode->Flags & DNF_MADEUP)) {
  4302. //
  4303. // Now mark this one deleted.
  4304. //
  4305. if (!PipDoesDevNodeHaveProblem(deviceNode)) {
  4306. PipSetDevNodeState(deviceNode, DeviceNodeRemoved, NULL);
  4307. PipSetDevNodeProblem(deviceNode, CM_PROB_DEVICE_NOT_THERE);
  4308. }
  4309. //
  4310. // This is actually doing nothing because DeviceNode->ResourceList is NULL.
  4311. //
  4312. IopReleaseDeviceResources(deviceNode, FALSE);
  4313. devNodex = deviceNode;
  4314. while (devNodex) {
  4315. devNodey = devNodex;
  4316. devNodex = (PDEVICE_NODE)devNodey->OverUsed2.NextResourceDeviceNode;
  4317. devNodey->OverUsed2.NextResourceDeviceNode = NULL;
  4318. devNodey->OverUsed1.LegacyDeviceNode = NULL;
  4319. }
  4320. deviceNode->Flags &= ~DNF_MADEUP; // remove its boot config if any
  4321. IoDeleteDevice(deviceObject);
  4322. deletedPDO = TRUE;
  4323. }
  4324. ObDereferenceObject(deviceObject); // added via IopDeviceObjectFromDeviceInstance
  4325. }
  4326. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  4327. status = IopOpenRegistryKeyEx( &handlex,
  4328. handle,
  4329. &unicodeName,
  4330. KEY_ALL_ACCESS
  4331. );
  4332. if (NT_SUCCESS(status)) {
  4333. ZwDeleteKey(handlex);
  4334. }
  4335. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  4336. status = IopOpenRegistryKeyEx( &handlex,
  4337. handle,
  4338. &unicodeName,
  4339. KEY_ALL_ACCESS
  4340. );
  4341. if (NT_SUCCESS(status)) {
  4342. ZwDeleteKey(handlex);
  4343. }
  4344. ZwClose(enumHandle);
  4345. //
  4346. // We need to call IopCleanupDeviceRegistryValue even we are going to
  4347. // delete it. Because, it also cleans up related value names in other
  4348. // keys.
  4349. //
  4350. if (deletedPDO) {
  4351. IopCleanupDeviceRegistryValues(&deviceName);
  4352. }
  4353. ZwDeleteKey(handle);
  4354. ZwDeleteKey(handle1);
  4355. } else {
  4356. ZwClose(handle);
  4357. ZwClose(handle1);
  4358. ZwClose(enumHandle);
  4359. }
  4360. } else {
  4361. ZwClose(handle1);
  4362. ZwClose(enumHandle);
  4363. }
  4364. } else {
  4365. ZwClose(enumHandle);
  4366. }
  4367. exit:
  4368. PiUnlockPnpRegistry();
  4369. return;
  4370. }
  4371. NTSTATUS
  4372. IopQueryAndSaveDeviceNodeCapabilities (
  4373. IN PDEVICE_NODE DeviceNode
  4374. )
  4375. /*++
  4376. Routine Description:
  4377. Called after start to refresh Capability flags
  4378. Arguments:
  4379. DeviceObject - supplies a pointer to a device object whose registry
  4380. values are to be updated.
  4381. Return Value:
  4382. status
  4383. --*/
  4384. {
  4385. NTSTATUS status;
  4386. DEVICE_CAPABILITIES capabilities;
  4387. PAGED_CODE();
  4388. ASSERT(DeviceNode != NULL);
  4389. //
  4390. // Open the device instance key
  4391. //
  4392. status = PipQueryDeviceCapabilities(DeviceNode, &capabilities);
  4393. if (!NT_SUCCESS(status)) {
  4394. return status;
  4395. }
  4396. return IopSaveDeviceCapabilities(DeviceNode,&capabilities);
  4397. }
  4398. NTSTATUS
  4399. IopSaveDeviceCapabilities (
  4400. IN PDEVICE_NODE DeviceNode,
  4401. IN PDEVICE_CAPABILITIES Capabilities
  4402. )
  4403. /*++
  4404. Routine Description:
  4405. This routine updates device capabilities, must be called after a valid device instance key has been created
  4406. Called directly from IopProcessNewDeviceNode, and indirecly via IopQueryAndSaveDeviceNodeCapabilities
  4407. after device is started.
  4408. Arguments:
  4409. DeviceObject - supplies a pointer to a device object whose registry
  4410. values are to be updated.
  4411. Return Value:
  4412. status
  4413. --*/
  4414. {
  4415. NTSTATUS status;
  4416. UNICODE_STRING unicodeName;
  4417. ULONG value;
  4418. HANDLE handle;
  4419. PAGED_CODE();
  4420. ASSERT(DeviceNode != NULL);
  4421. ASSERT(Capabilities != NULL);
  4422. //
  4423. // Open the device instance key
  4424. //
  4425. status = IopDeviceObjectToDeviceInstance(DeviceNode->PhysicalDeviceObject, &handle, KEY_ALL_ACCESS);
  4426. if (!NT_SUCCESS(status)) {
  4427. return status;
  4428. }
  4429. if (DeviceNode->Flags & DNF_HAS_BOOT_CONFIG) {
  4430. Capabilities->SurpriseRemovalOK = 0;
  4431. }
  4432. //
  4433. // Assert the bit fields are completely contained in a ULONG. This is a
  4434. // public structure, so it shouldn't ever change, but paranoia is a good
  4435. // thing...
  4436. //
  4437. ASSERT((FIELD_OFFSET(DEVICE_CAPABILITIES, Address) -
  4438. FIELD_OFFSET(DEVICE_CAPABILITIES, Version) -
  4439. FIELD_SIZE (DEVICE_CAPABILITIES, Version)) == sizeof(ULONG));
  4440. DeviceNode->CapabilityFlags =
  4441. *((PULONG) (((PUCHAR) Capabilities) +
  4442. FIELD_OFFSET(DEVICE_CAPABILITIES, Version) +
  4443. FIELD_SIZE(DEVICE_CAPABILITIES, Version)));
  4444. value = (Capabilities->LockSupported) |
  4445. (Capabilities->EjectSupported << 1) |
  4446. (Capabilities->WarmEjectSupported<< 1) |
  4447. (Capabilities->Removable << 2) |
  4448. (Capabilities->DockDevice << 3) |
  4449. (Capabilities->UniqueID << 4) |
  4450. (Capabilities->SilentInstall << 5) |
  4451. (Capabilities->RawDeviceOK << 6) |
  4452. (Capabilities->SurpriseRemovalOK << 7) |
  4453. (Capabilities->HardwareDisabled << 8) |
  4454. (Capabilities->NonDynamic << 9);
  4455. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CAPABILITIES);
  4456. status = ZwSetValueKey(
  4457. handle,
  4458. &unicodeName,
  4459. TITLE_INDEX_VALUE,
  4460. REG_DWORD,
  4461. &value,
  4462. sizeof(value)
  4463. );
  4464. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_UI_NUMBER);
  4465. value = Capabilities->UINumber;
  4466. if(value != (ULONG)-1) {
  4467. ZwSetValueKey(handle,
  4468. &unicodeName,
  4469. TITLE_INDEX_VALUE,
  4470. REG_DWORD,
  4471. &value,
  4472. sizeof(value)
  4473. );
  4474. } else {
  4475. ZwDeleteValueKey(handle, &unicodeName);
  4476. }
  4477. ZwClose(handle);
  4478. return STATUS_SUCCESS;
  4479. }
  4480. NTSTATUS
  4481. IopRestartDeviceNode(
  4482. IN PDEVICE_NODE DeviceNode
  4483. )
  4484. {
  4485. PAGED_CODE();
  4486. PpDevNodeLockTree(PPL_TREEOP_BLOCK_READS_FROM_ALLOW);
  4487. ASSERT(DeviceNode->State == DeviceNodeRemoved ||
  4488. DeviceNode->State == DeviceNodeInitialized );
  4489. ASSERT(!PipDoesDevNodeHaveProblem(DeviceNode));
  4490. ASSERT(DeviceNode->Flags & DNF_ENUMERATED);
  4491. if (!(DeviceNode->Flags & DNF_ENUMERATED)) {
  4492. PpDevNodeUnlockTree(PPL_TREEOP_BLOCK_READS_FROM_ALLOW);
  4493. return STATUS_UNSUCCESSFUL;
  4494. }
  4495. DeviceNode->UserFlags &= ~DNUF_NEED_RESTART;
  4496. DeviceNode->Flags &= ~(DNF_DRIVER_BLOCKED | DNF_HARDWARE_VERIFICATION);
  4497. #if DBG_SCOPE
  4498. DeviceNode->FailureStatus = 0;
  4499. if (DeviceNode->PreviousResourceList) {
  4500. ExFreePool(DeviceNode->PreviousResourceList);
  4501. DeviceNode->PreviousResourceList = NULL;
  4502. }
  4503. if (DeviceNode->PreviousResourceRequirements) {
  4504. ExFreePool(DeviceNode->PreviousResourceRequirements);
  4505. DeviceNode->PreviousResourceRequirements = NULL;
  4506. }
  4507. #endif
  4508. //
  4509. // Prepare to set the device state back to DeviceNodeUninitialized. To
  4510. // do this we free any existing devnode strings so we can recreate them
  4511. // during enumeration.
  4512. //
  4513. // ADRIAO N.B. 8/19/2000 -
  4514. // We don't restore the state to DeviceNodeInitialized to maintain Win2K
  4515. // behavior. We have no idea if anyone actually depends on this. In theory
  4516. // this would let a bus driver get away with changing a child's IDs after a
  4517. // remove.
  4518. //
  4519. if (DeviceNode->State != DeviceNodeUninitialized) {
  4520. DeviceNode->Flags &= ~(DNF_NO_RESOURCE_REQUIRED |
  4521. DNF_RESOURCE_REQUIREMENTS_CHANGED);
  4522. if (DeviceNode->ServiceName.Length != 0) {
  4523. ExFreePool(DeviceNode->ServiceName.Buffer);
  4524. PiWstrToUnicodeString(&DeviceNode->ServiceName, NULL);
  4525. }
  4526. if (DeviceNode->ResourceRequirements != NULL) {
  4527. ExFreePool(DeviceNode->ResourceRequirements);
  4528. DeviceNode->ResourceRequirements = NULL;
  4529. DeviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED;
  4530. }
  4531. }
  4532. ASSERT(DeviceNode->ServiceName.Length == 0 &&
  4533. DeviceNode->ServiceName.MaximumLength == 0 &&
  4534. DeviceNode->ServiceName.Buffer == NULL);
  4535. ASSERT(!(DeviceNode->Flags &
  4536. ~(DNF_MADEUP | DNF_ENUMERATED | DNF_HAS_BOOT_CONFIG | DNF_IDS_QUERIED |
  4537. DNF_BOOT_CONFIG_RESERVED | DNF_NO_RESOURCE_REQUIRED)));
  4538. PipSetDevNodeState(DeviceNode, DeviceNodeUninitialized, NULL);
  4539. PpDevNodeUnlockTree(PPL_TREEOP_BLOCK_READS_FROM_ALLOW);
  4540. return STATUS_SUCCESS;
  4541. }
  4542. BOOLEAN
  4543. IopDeleteKeyRecursiveCallback(
  4544. IN HANDLE KeyHandle,
  4545. IN PUNICODE_STRING KeyName,
  4546. IN OUT PVOID Context
  4547. )
  4548. /*++
  4549. Routine Description:
  4550. This is a callback routine to PipApplyFunctionToSubKeys, that gets called
  4551. through IopDeleteKeyRecursive. This routine prepares a given key for
  4552. deletion by deleting all of its subkeys. This is done, using
  4553. PipApplyFunctionToSubKeys, with instructions to delete all enumerated
  4554. subkeys, and calling this routine as a callback routine, if necessary, until
  4555. no subkeys remain. KeyHandle can then be successfully deleted by the
  4556. caller.
  4557. Arguments:
  4558. KeyHandle - Handle to a subkey that has been enumerated by
  4559. PipApplyFunctionToSubKeys.
  4560. KeyName - Name of the subkey whose handle is specified by KeyHandle.
  4561. Context - Supplies a pointer to user-defined data that will be passed
  4562. in to the callback routine at each subkey invocation.
  4563. Return Value:
  4564. BOOLEAN that returns whether or not the given key can be safely deleted.
  4565. --*/
  4566. {
  4567. NTSTATUS status = STATUS_SUCCESS;
  4568. PAGED_CODE();
  4569. UNREFERENCED_PARAMETER(KeyName);
  4570. //
  4571. // delete any subkeys, recursively if necessary
  4572. //
  4573. status = PipApplyFunctionToSubKeys(
  4574. KeyHandle,
  4575. NULL,
  4576. KEY_ALL_ACCESS,
  4577. FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS |
  4578. FUNCTIONSUBKEY_FLAG_DELETE_SUBKEYS,
  4579. IopDeleteKeyRecursiveCallback,
  4580. Context);
  4581. *((NTSTATUS *)Context) = status;
  4582. return (BOOLEAN)NT_SUCCESS(status);
  4583. }
  4584. NTSTATUS
  4585. IopDeleteKeyRecursive(
  4586. IN HANDLE ParentKey OPTIONAL,
  4587. IN PWCHAR KeyName
  4588. )
  4589. /*++
  4590. Routine Description:
  4591. Recursively deletes all subkeys of KeyName, then deletes KeyName.
  4592. Arguments:
  4593. ParentKey - Handle to the parent key of KeyName. If NULL then KeyName is
  4594. expected to start with \Registry.
  4595. KeyName - Name of subkey to delete, as a NULL terminated UNICODE string.
  4596. Return Value:
  4597. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  4598. --*/
  4599. {
  4600. NTSTATUS status = STATUS_SUCCESS;
  4601. BOOLEAN result;
  4602. HANDLE hKey;
  4603. UNICODE_STRING unicodeKeyName;
  4604. PAGED_CODE();
  4605. //
  4606. // Attempt to open the key name we were given
  4607. //
  4608. RtlInitUnicodeString(&unicodeKeyName, KeyName);
  4609. status = IopOpenRegistryKeyEx( &hKey,
  4610. ParentKey,
  4611. &unicodeKeyName,
  4612. KEY_ALL_ACCESS
  4613. );
  4614. if (NT_SUCCESS(status)) {
  4615. //
  4616. // Recusively delete all subkeys
  4617. //
  4618. result = IopDeleteKeyRecursiveCallback(hKey,
  4619. &unicodeKeyName,
  4620. (PVOID)&status);
  4621. if (result) {
  4622. //
  4623. // It is safe to delete this key
  4624. //
  4625. status = ZwDeleteKey(hKey);
  4626. }
  4627. ZwClose(hKey);
  4628. }
  4629. return status;
  4630. }
  4631. BOOLEAN
  4632. PiRegSzToString(
  4633. IN PWCHAR RegSzData,
  4634. IN ULONG RegSzLength,
  4635. OUT PULONG StringLength OPTIONAL,
  4636. OUT PWSTR *CopiedString OPTIONAL
  4637. )
  4638. /*++
  4639. Routine Description:
  4640. This routine takes as input a REG_SZ data buffer (as returned in the DataOffset area
  4641. of the buffer in a KEY_VALUE_FULL_INFORMATION structure), as well as the length
  4642. of the buffer, in bytes (as specified by the DataLength field in the above mentioned
  4643. struct). It optionally returns the length of the contained string (in bytes), not
  4644. including the terminating NULL, as well as an optional copy of the string itself
  4645. (properly NULL-terminated).
  4646. It is the responsibility of the caller to free the (PagedPool) buffer allocated
  4647. for the string copy.
  4648. Arguments:
  4649. RegSzData - Supplies a pointer to the REG_SZ data buffer.
  4650. RegSzLength - Supplies the length of the RegSzData buffer, in bytes.
  4651. StringLength - Optionally supplies a pointer to a variable that will receive
  4652. the length, in bytes, of the string (excluding terminating NULL).
  4653. CopiedString - Optionally supplies a pointer to a wide character pointer that
  4654. will recieve a (properly NULL-terminated) copy of the specified
  4655. string. If this paramater is NULL, no copy will be made.
  4656. Return Value:
  4657. If success, returns TRUE
  4658. If failure (not able to allocate memory for string copy), returns FALSE
  4659. --*/
  4660. {
  4661. PWCHAR curPos, endOfRegSzData;
  4662. ULONG actualStringLength;
  4663. //
  4664. // Since we're converting a byte count to a wide-character count (and the
  4665. // compiler is converting it back when adding it to a PWCHAR), we are
  4666. // ensuring that endOfRegSzData is not on an odd-byte boundary, even if
  4667. // the RegSzLength passed in was odd. This takes care of the case where
  4668. // the REG_SZ buffer retrieved from the registry is bogus (e.g., you have
  4669. // a 5-byte buffer, the 1st unicode character of which is a UNICODE_NULL).
  4670. //
  4671. endOfRegSzData = (curPos = RegSzData) + CB_TO_CWC(RegSzLength);
  4672. while ((curPos < endOfRegSzData) && *curPos) {
  4673. curPos++;
  4674. }
  4675. actualStringLength = (ULONG)((PUCHAR)curPos - (PUCHAR)RegSzData);
  4676. if (ARGUMENT_PRESENT(StringLength)) {
  4677. *StringLength = (ULONG)((PUCHAR)curPos - (PUCHAR)RegSzData);
  4678. }
  4679. if (ARGUMENT_PRESENT(CopiedString)) {
  4680. //
  4681. // Allocate memory for the string (+ terminating NULL)
  4682. //
  4683. *CopiedString = (PWSTR)ExAllocatePool(PagedPool, actualStringLength + sizeof(UNICODE_NULL));
  4684. if (*CopiedString == NULL) {
  4685. return FALSE;
  4686. }
  4687. //
  4688. // Copy the string and NULL-terminate it.
  4689. //
  4690. if (actualStringLength) {
  4691. RtlCopyMemory(*CopiedString, RegSzData, actualStringLength);
  4692. }
  4693. *(PWCHAR)((PUCHAR)(*CopiedString) + actualStringLength) = UNICODE_NULL;
  4694. }
  4695. return TRUE;
  4696. }
  4697. ULONG
  4698. IopDebugPrint (
  4699. IN ULONG Level,
  4700. IN PCHAR Format,
  4701. ...
  4702. )
  4703. {
  4704. va_list ap;
  4705. va_start(ap, Format);
  4706. vDbgPrintExWithPrefix("", DPFLTR_NTOSPNP_ID, Level, Format, ap);
  4707. va_end(ap);
  4708. return Level;
  4709. }
  4710. PCHAR
  4711. PpConvertMultiSzWstrToStr(
  4712. IN PWCHAR Source,
  4713. IN ULONG Length
  4714. )
  4715. {
  4716. NTSTATUS status;
  4717. PWCHAR s, sourceEnd;
  4718. PCHAR dest, d;
  4719. ANSI_STRING ansiString;
  4720. UNICODE_STRING unicodeString;
  4721. PAGED_CODE();
  4722. if (Length <= 2) {
  4723. return NULL;
  4724. }
  4725. #if DBG
  4726. for (s = Source; *s != UNICODE_NULL; s += wcslen(s) + 1) {
  4727. }
  4728. ASSERT(Length == (ULONG)(s - Source) + 1);
  4729. #endif
  4730. dest = ExAllocatePool(PagedPool, Length * sizeof(CHAR));
  4731. if (dest) {
  4732. s = Source;
  4733. for (sourceEnd = s + Length, d = dest;
  4734. s < sourceEnd && *s != UNICODE_NULL;
  4735. s += wcslen(s) + 1) {
  4736. RtlInitUnicodeString(&unicodeString, s);
  4737. status = RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
  4738. if (!NT_SUCCESS(status)) {
  4739. ExFreePool(dest);
  4740. return NULL;
  4741. }
  4742. RtlCopyMemory(d, ansiString.Buffer, ansiString.Length + 1);
  4743. d += ansiString.Length + 1;
  4744. RtlFreeAnsiString(&ansiString);
  4745. }
  4746. if (s < sourceEnd) {
  4747. *d = '\0';
  4748. }
  4749. }
  4750. return dest;
  4751. }
  4752. PWCHAR
  4753. PpConvertMultiSzStrToWstr(
  4754. IN PCHAR Source,
  4755. IN ULONG Length
  4756. )
  4757. {
  4758. NTSTATUS status;
  4759. PCHAR s, sourceEnd;
  4760. PWCHAR dest, d;
  4761. ANSI_STRING ansiString;
  4762. UNICODE_STRING unicodeString;
  4763. PAGED_CODE();
  4764. if (Length <= 2) {
  4765. return NULL;
  4766. }
  4767. #if DBG
  4768. for (s = Source; *s != '\0'; s += strlen(s) + 1) {
  4769. }
  4770. ASSERT(Length == (ULONG)(s - Source) + 1);
  4771. #endif
  4772. dest = ExAllocatePool(PagedPool, Length * sizeof(WCHAR));
  4773. if (dest) {
  4774. s = Source;
  4775. for (sourceEnd = s + Length, d = dest;
  4776. s < sourceEnd && *s != '\0';
  4777. s += strlen(s) + 1) {
  4778. RtlInitAnsiString(&ansiString, s);
  4779. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  4780. if (!NT_SUCCESS(status)) {
  4781. ExFreePool(dest);
  4782. return NULL;
  4783. }
  4784. RtlCopyMemory(d, unicodeString.Buffer, unicodeString.Length + sizeof(UNICODE_NULL));
  4785. d += (unicodeString.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
  4786. RtlFreeUnicodeString(&unicodeString);
  4787. }
  4788. if (s < sourceEnd) {
  4789. *d = UNICODE_NULL;
  4790. }
  4791. }
  4792. return dest;
  4793. }
  4794. VOID
  4795. PpSystemHiveLimitCallback(
  4796. PSYSTEM_HIVE_LIMITS HiveLimits,
  4797. ULONG Level
  4798. )
  4799. {
  4800. PAGED_CODE();
  4801. if (Level >= HiveLimits->High) {
  4802. PpSystemHiveTooLarge = TRUE;
  4803. } else {
  4804. ASSERT(Level <= HiveLimits->Low);
  4805. PpSystemHiveTooLarge = FALSE;
  4806. PpResetProblemDevices(IopRootDeviceNode, CM_PROB_REGISTRY_TOO_LARGE);
  4807. PipRequestDeviceAction(
  4808. IopRootDeviceNode->PhysicalDeviceObject,
  4809. RestartEnumeration,
  4810. FALSE,
  4811. 0,
  4812. NULL,
  4813. NULL
  4814. );
  4815. }
  4816. }
  4817. NTSTATUS
  4818. PpBusTypeGuidInitialize(
  4819. VOID
  4820. )
  4821. /*++
  4822. Routine Description:
  4823. This routine opens the specified subkey.
  4824. Arguments:
  4825. None
  4826. Return Value:
  4827. STATUS_SUCCESS.
  4828. --*/
  4829. {
  4830. PAGED_CODE();
  4831. PpBusTypeGuidCountMax = 16;
  4832. PpBusTypeGuidArray = ExAllocatePool(PagedPool, sizeof(GUID) * PpBusTypeGuidCountMax);
  4833. if (PpBusTypeGuidArray == NULL) {
  4834. PpBusTypeGuidCountMax = 0;
  4835. return STATUS_INSUFFICIENT_RESOURCES;
  4836. }
  4837. PpBusTypeGuidCount = 0;
  4838. ExInitializeFastMutex(&PpBusTypeGuidLock);
  4839. return STATUS_SUCCESS;
  4840. }
  4841. USHORT
  4842. PpBusTypeGuidGetIndex(
  4843. IN LPGUID BusTypeGuid
  4844. )
  4845. /*++
  4846. Routine Description:
  4847. This routine looks up the BusTypeGuid and returns its index into the table.
  4848. Arguments:
  4849. BusTypeGuid - GUID to lookup.
  4850. Return Value:
  4851. Index into the table iff successful, else 0xFFFF.
  4852. --*/
  4853. {
  4854. LPGUID p;
  4855. ULONG i;
  4856. PAGED_CODE();
  4857. ExAcquireFastMutex(&PpBusTypeGuidLock);
  4858. //
  4859. // First look it up.
  4860. //
  4861. for (i = 0; i < PpBusTypeGuidCount; i++) {
  4862. if (IopCompareGuid(BusTypeGuid, &PpBusTypeGuidArray[i])) {
  4863. break;
  4864. }
  4865. }
  4866. //
  4867. // If the GUID is not in the table, add it.
  4868. //
  4869. if (i == PpBusTypeGuidCount) {
  4870. //
  4871. // Grow the table if needed.
  4872. //
  4873. if (i == PpBusTypeGuidCountMax) {
  4874. //
  4875. // We grow the table one entry at a time. This should not be a
  4876. // problem since this should not happen often.
  4877. //
  4878. p = ExAllocatePool(PagedPool, (i + 1) * sizeof(GUID));
  4879. if (p) {
  4880. //
  4881. // Copy the old table.
  4882. //
  4883. RtlCopyMemory(p, PpBusTypeGuidArray, PpBusTypeGuidCount * sizeof(GUID));
  4884. //
  4885. // Update global data.
  4886. //
  4887. PpBusTypeGuidCountMax++;
  4888. if (PpBusTypeGuidArray) {
  4889. ExFreePool(PpBusTypeGuidArray);
  4890. }
  4891. PpBusTypeGuidArray = p;
  4892. } else {
  4893. //
  4894. // Return invalid index on failure.
  4895. //
  4896. i = (ULONG)-1;
  4897. }
  4898. }
  4899. //
  4900. // Copy the new entry on success.
  4901. //
  4902. if (i != (ULONG)-1) {
  4903. //
  4904. // Copy the new entry.
  4905. //
  4906. RtlCopyMemory(&PpBusTypeGuidArray[PpBusTypeGuidCount], BusTypeGuid, sizeof(GUID));
  4907. //
  4908. // Update global data.
  4909. //
  4910. PpBusTypeGuidCount++;
  4911. }
  4912. }
  4913. ExReleaseFastMutex(&PpBusTypeGuidLock);
  4914. return (USHORT)i;
  4915. }
  4916. NTSTATUS
  4917. PpBusTypeGuidGet(
  4918. IN USHORT Index,
  4919. IN OUT LPGUID BusTypeGuid
  4920. )
  4921. /*++
  4922. Routine Description:
  4923. This routine return the BusTypeGuid in the table at the specified index.
  4924. Arguments:
  4925. Index - BusTypeGuid index.
  4926. BusTypeGuid - Recieves the GUID.
  4927. Return Value:
  4928. NTSTATUS.
  4929. --*/
  4930. {
  4931. NTSTATUS status;
  4932. PAGED_CODE();
  4933. ExAcquireFastMutex(&PpBusTypeGuidLock);
  4934. if (Index < PpBusTypeGuidCount) {
  4935. RtlCopyMemory(BusTypeGuid, &PpBusTypeGuidArray[Index], sizeof(GUID));
  4936. status = STATUS_SUCCESS;
  4937. } else {
  4938. status = STATUS_OBJECT_NAME_NOT_FOUND;
  4939. }
  4940. ExReleaseFastMutex(&PpBusTypeGuidLock);
  4941. return status;
  4942. }
  4943. ULONG
  4944. PiFixupID(
  4945. IN PWCHAR ID,
  4946. IN ULONG MaxIDLength,
  4947. IN BOOLEAN Multi,
  4948. IN ULONG AllowedSeparators,
  4949. IN PUNICODE_STRING LogString OPTIONAL
  4950. )
  4951. /*++
  4952. Routine Description:
  4953. This routine parses the device instance string and replaces any invalid
  4954. characters (not allowed in a "device instance") with an underscore
  4955. character.
  4956. Invalid characters are:
  4957. c <= 0x20 (' ')
  4958. c > 0x7F
  4959. c == 0x2C (',')
  4960. Arguments:
  4961. ID - ID to be fixed up.
  4962. MaxIDLength - Maximum allowed size of ID.
  4963. Multi - Specifies if the ID is MULTI_SZ or not.
  4964. AllowedSeparators - Number of separators allowed in the ID.
  4965. Return Value:
  4966. ID length in number of characters.
  4967. --*/
  4968. {
  4969. PWCHAR p, pMax, lastNull;
  4970. ULONG separators;
  4971. UNICODE_STRING reason;
  4972. PAGED_CODE();
  4973. //
  4974. // BUGBUG - do we need to uppercase these!?
  4975. //
  4976. separators = 0;
  4977. lastNull = NULL;
  4978. for(p = ID, pMax = p + MaxIDLength; p < pMax; p++) {
  4979. if(*p == UNICODE_NULL) {
  4980. if(Multi == FALSE || (lastNull && p == lastNull + 1)) {
  4981. break;
  4982. }
  4983. pMax += MaxIDLength;
  4984. lastNull = p;
  4985. continue;
  4986. }
  4987. if (*p == L' ') {
  4988. *p = L'_';
  4989. } else if ((*p < L' ') || (*p > (WCHAR)0x7F) || (*p == L',')) {
  4990. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  4991. "PiFixupID: ID at %p has invalid character %02X\n",
  4992. ID,
  4993. *p));
  4994. if(LogString) {
  4995. PiWstrToUnicodeString(&reason, L"invalid character");
  4996. PpLogEvent(LogString, &reason, STATUS_PNP_INVALID_ID, p, sizeof(WCHAR));
  4997. }
  4998. return 0;
  4999. } else if ((*p == OBJ_NAME_PATH_SEPARATOR && ++separators > AllowedSeparators)) {
  5000. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  5001. "PiFixupID: ID at %p has too many (%d) separators\n",
  5002. ID,
  5003. separators));
  5004. if(LogString) {
  5005. PiWstrToUnicodeString(&reason, L"too many separators");
  5006. PpLogEvent(LogString, &reason, STATUS_PNP_INVALID_ID, &separators, sizeof(ULONG));
  5007. }
  5008. return 0;
  5009. }
  5010. }
  5011. if(p >= pMax || (AllowedSeparators != (ULONG)-1 && separators != AllowedSeparators)) {
  5012. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  5013. "PiFixupID: ID at %p not terminated, or too long or has invalid number (%d) of separators\n",
  5014. ID,
  5015. separators));
  5016. if(LogString) {
  5017. PiWstrToUnicodeString(&reason, L"not terminated, too long or invalid number of separators");
  5018. PpLogEvent(LogString, &reason, STATUS_PNP_INVALID_ID, NULL, 0);
  5019. }
  5020. return 0;
  5021. }
  5022. return (ULONG)(ULONG_PTR)(p - ID) + 1;
  5023. }
  5024. NTSTATUS
  5025. PpQueryDeviceID(
  5026. IN PDEVICE_NODE DeviceNode,
  5027. OUT PWCHAR *BusID,
  5028. OUT PWCHAR *DeviceID
  5029. )
  5030. /*++
  5031. Routine Description:
  5032. This routine queries the Device ID and fixes it up. It also parses the DeviceID
  5033. and returns the pointers to BusID and DeviceID parts. If this routine fails,
  5034. BusID and DeviceID will be set to NULL.
  5035. Arguments:
  5036. DeviceNode - The devnode whose DeviceID needs to be queried.
  5037. BusID - Recieves the pointer to the bus part of DeviceID.
  5038. DeviceID - Recieves the pointer to the device part of DeviceID.
  5039. Return Value:
  5040. NTSTATUS.
  5041. --*/
  5042. {
  5043. NTSTATUS status;
  5044. PWCHAR id, separator;
  5045. ULONG idLength;
  5046. PAGED_CODE();
  5047. *BusID = NULL;
  5048. *DeviceID= NULL;
  5049. status = PpQueryID(DeviceNode, BusQueryDeviceID, &id, &idLength);
  5050. if(NT_SUCCESS(status)) {
  5051. ASSERT(id && idLength);
  5052. *BusID = id;
  5053. separator = wcschr(id, OBJ_NAME_PATH_SEPARATOR);
  5054. ASSERT(separator);
  5055. *separator = UNICODE_NULL;
  5056. *DeviceID = separator + 1;
  5057. } else {
  5058. ASSERT(id == NULL && idLength == 0);
  5059. }
  5060. return status;
  5061. }
  5062. NTSTATUS
  5063. PpQueryID(
  5064. IN PDEVICE_NODE DeviceNode,
  5065. IN BUS_QUERY_ID_TYPE IDType,
  5066. OUT PWCHAR *ID,
  5067. OUT PULONG IDLength
  5068. )
  5069. /*++
  5070. Routine Description:
  5071. This routine queries the specified ID and fixes it up. If this
  5072. routine fails, ID will be set to NULL.
  5073. Arguments:
  5074. DeviceNode - The devnode whose IDs need to be queried.
  5075. IDType - Type of ID to be queried.
  5076. ID - Receives the ID returned by the driver if any. The caller
  5077. is expected to free the storage for ID on success.
  5078. IDLength - Receives the length of the ID (including terminating NULL) in bytes.
  5079. Return Value:
  5080. NTSTATUS.
  5081. --*/
  5082. {
  5083. NTSTATUS status;
  5084. UNICODE_STRING reason;
  5085. PAGED_CODE();
  5086. ASSERT(IDType == BusQueryDeviceID || IDType == BusQueryInstanceID ||
  5087. IDType == BusQueryHardwareIDs || IDType == BusQueryCompatibleIDs);
  5088. *IDLength = 0;
  5089. status = PpIrpQueryID(DeviceNode->PhysicalDeviceObject, IDType, ID);
  5090. if(NT_SUCCESS(status)) {
  5091. switch(IDType) {
  5092. case BusQueryDeviceID:
  5093. *IDLength = PiFixupID(*ID, MAX_DEVICE_ID_LEN, FALSE, 1, &DeviceNode->Parent->ServiceName);
  5094. break;
  5095. case BusQueryInstanceID:
  5096. *IDLength = PiFixupID(*ID, MAX_DEVICE_ID_LEN, FALSE, 0, &DeviceNode->Parent->ServiceName);
  5097. break;
  5098. case BusQueryHardwareIDs:
  5099. case BusQueryCompatibleIDs:
  5100. *IDLength = PiFixupID(*ID, MAX_DEVICE_ID_LEN, TRUE, (ULONG)-1, &DeviceNode->Parent->ServiceName);
  5101. break;
  5102. default:
  5103. *IDLength = 0;
  5104. break;
  5105. }
  5106. (*IDLength) *= sizeof(WCHAR);
  5107. if(*IDLength == 0) {
  5108. status = STATUS_PNP_INVALID_ID;
  5109. }
  5110. }
  5111. if(!NT_SUCCESS(status)) {
  5112. if (status == STATUS_PNP_INVALID_ID || IDType == BusQueryDeviceID) {
  5113. PipSetDevNodeProblem(DeviceNode, CM_PROB_INVALID_DATA);
  5114. if ((DeviceNode->Parent->Flags & DNF_CHILD_WITH_INVALID_ID) == 0) {
  5115. DeviceNode->Parent->Flags |= DNF_CHILD_WITH_INVALID_ID;
  5116. PpSetInvalidIDEvent(&DeviceNode->Parent->InstancePath);
  5117. }
  5118. }
  5119. if (status == STATUS_PNP_INVALID_ID) {
  5120. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  5121. "PpQueryID: Bogus ID returned by %wZ\n",
  5122. &DeviceNode->Parent->ServiceName));
  5123. ASSERT(status != STATUS_PNP_INVALID_ID);
  5124. } else if (IDType == BusQueryDeviceID) {
  5125. //
  5126. // DeviceID is not optional.
  5127. //
  5128. PiWstrToUnicodeString(&reason, L"failed IRP_MN_QUERY_ID-BusQueryDeviceID");
  5129. PpLogEvent(&DeviceNode->Parent->ServiceName, &reason, status, NULL, 0);
  5130. IopDbgPrint((IOP_ENUMERATION_ERROR_LEVEL,
  5131. "PpIrpQueryID: Failed by %wZ, status = %x\n",
  5132. &DeviceNode->Parent->ServiceName, status));
  5133. ASSERT(IDType != BusQueryDeviceID);
  5134. }
  5135. if(*ID) {
  5136. ExFreePool(*ID);
  5137. *ID = NULL;
  5138. *IDLength = 0;
  5139. }
  5140. }
  5141. return status;
  5142. }