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

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