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

1018 lines
29 KiB

  1. /*++
  2. Copyright (c) 1989-1994 Microsoft Corporation
  3. Module Name:
  4. query.c
  5. Abstract:
  6. This module contains the subroutines to Query Device Descriptions from
  7. the Hardware tree in the registry
  8. Author:
  9. Andre Vachon (andreva) 20-Jun-1994
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. typedef struct _IO_QUERY_DESC {
  16. PINTERFACE_TYPE BusType;
  17. PULONG BusNumber;
  18. PCONFIGURATION_TYPE ControllerType;
  19. PULONG ControllerNumber;
  20. PCONFIGURATION_TYPE PeripheralType;
  21. PULONG PeripheralNumber;
  22. PIO_QUERY_DEVICE_ROUTINE CalloutRoutine;
  23. PVOID Context;
  24. } IO_QUERY_DESC, *PIO_QUERY_DESC;
  25. NTSTATUS
  26. pIoQueryBusDescription(
  27. PIO_QUERY_DESC QueryDescription,
  28. UNICODE_STRING PathName,
  29. HANDLE RootHandle,
  30. PULONG BusNum,
  31. BOOLEAN HighKey
  32. );
  33. NTSTATUS
  34. pIoQueryDeviceDescription(
  35. PIO_QUERY_DESC QueryDescription,
  36. UNICODE_STRING PathName,
  37. HANDLE RootHandle,
  38. ULONG BusNum,
  39. PKEY_VALUE_FULL_INFORMATION *BusValueInfo
  40. );
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text(PAGE, IoQueryDeviceDescription)
  43. #pragma alloc_text(PAGE, pIoQueryBusDescription)
  44. #pragma alloc_text(PAGE, pIoQueryDeviceDescription)
  45. #endif
  46. NTSTATUS
  47. IoQueryDeviceDescription(
  48. IN PINTERFACE_TYPE BusType OPTIONAL,
  49. IN PULONG BusNumber OPTIONAL,
  50. IN PCONFIGURATION_TYPE ControllerType OPTIONAL,
  51. IN PULONG ControllerNumber OPTIONAL,
  52. IN PCONFIGURATION_TYPE PeripheralType OPTIONAL,
  53. IN PULONG PeripheralNumber OPTIONAL,
  54. IN PIO_QUERY_DEVICE_ROUTINE CalloutRoutine,
  55. IN PVOID Context
  56. )
  57. /*++
  58. Routine Description:
  59. Arguments:
  60. BusType - Supplies an optional bus type being searched for in the
  61. description tree. Valid types are Mca, Isa, Eisa ... If no bus type
  62. is specified, the system information (i.e. machine BIOS) is returned.
  63. BusNumber - Supplies an optional value determining which bus should be
  64. queried.
  65. ControllerType - Supplies an optional controller type being searched for.
  66. If no Controller type is specified, only the Bus information is
  67. returned.
  68. ControllerNumber - Supplies an optional value determining which
  69. controller should be queried.
  70. PeripheralType - Supplies an optional peripheral type being searched for.
  71. If no Controller type is specified, only the Bus information and the
  72. controller information are returned.
  73. PeripheralNumber - Supplies an optional value determining which
  74. peripheral should be queried.
  75. CalloutRoutine - Supplies a pointer to a routine that gets called
  76. for each successful match of PeripheralType.
  77. Context - Supplies a context value that is passed back to the callback
  78. routine.
  79. Return Value:
  80. The status returned is the final completion status of the operation.
  81. Notes:
  82. --*/
  83. {
  84. #define UNICODE_NUM_LENGTH 14
  85. #define UNICODE_REGISTRY_PATH_LENGTH 1024
  86. IO_QUERY_DESC queryDesc;
  87. NTSTATUS status;
  88. UNICODE_STRING registryPathName;
  89. HANDLE rootHandle;
  90. ULONG busNumber = (ULONG) -1;
  91. PAGED_CODE();
  92. ASSERT( CalloutRoutine != NULL );
  93. //
  94. // Check if we need to return the machine information
  95. //
  96. if (!ARGUMENT_PRESENT( BusType )) {
  97. return STATUS_NOT_IMPLEMENTED;
  98. }
  99. queryDesc.BusType = BusType;
  100. queryDesc.BusNumber = BusNumber;
  101. queryDesc.ControllerType = ControllerType;
  102. queryDesc.ControllerNumber = ControllerNumber;
  103. queryDesc.PeripheralType = PeripheralType;
  104. queryDesc.PeripheralNumber = PeripheralNumber;
  105. queryDesc.CalloutRoutine = CalloutRoutine;
  106. queryDesc.Context = Context;
  107. //
  108. // Set up a string with the pathname to the hardware description
  109. // portion of the registry.
  110. //
  111. registryPathName.Length = 0;
  112. registryPathName.MaximumLength = UNICODE_REGISTRY_PATH_LENGTH *
  113. sizeof(WCHAR);
  114. registryPathName.Buffer = ExAllocatePoolWithTag( PagedPool,
  115. UNICODE_REGISTRY_PATH_LENGTH,
  116. 'NRoI' );
  117. if (!registryPathName.Buffer) {
  118. return STATUS_INSUFFICIENT_RESOURCES;
  119. }
  120. RtlAppendUnicodeStringToString( &registryPathName,
  121. &CmRegistryMachineHardwareDescriptionSystemName );
  122. //
  123. // Open a handle to the root path we have.
  124. //
  125. status = IopOpenRegistryKey( &rootHandle,
  126. (HANDLE) NULL,
  127. &registryPathName,
  128. KEY_READ,
  129. FALSE );
  130. if (NT_SUCCESS( status )) {
  131. status = pIoQueryBusDescription(&queryDesc,
  132. registryPathName,
  133. rootHandle,
  134. &busNumber,
  135. TRUE );
  136. ZwClose( rootHandle );
  137. }
  138. ExFreePool( registryPathName.Buffer );
  139. //
  140. // For compatibility with old version of the function.
  141. //
  142. if (status == STATUS_NO_MORE_ENTRIES) {
  143. return STATUS_OBJECT_NAME_NOT_FOUND;
  144. } else {
  145. return status;
  146. }
  147. }
  148. NTSTATUS
  149. pIoQueryBusDescription(
  150. PIO_QUERY_DESC QueryDescription,
  151. UNICODE_STRING PathName,
  152. HANDLE RootHandle,
  153. PULONG BusNum,
  154. BOOLEAN HighKey
  155. )
  156. /*++
  157. Routine Description:
  158. Arguments:
  159. QueryDescription - Buffer containing all the query information requested
  160. by the driver.
  161. PathName - Registry path name of the key we are dealing with. This is
  162. a unicode strig so that we don't have to bother with resetting NULLs
  163. at the end of the string - the length determines how much of the
  164. string is valid.
  165. RootHandle - Handle equivalent to the registry path.
  166. BusNum - Pointer to a variable that keeps track of the bus number we are
  167. searching for (buses have to be accumulated.
  168. HighKey - Determines is this is a high key (a root key with a list of
  169. bus types) or a low level key (under which the number of the various
  170. buses will be little).
  171. Return Value:
  172. The status returned is the final completion status of the operation.
  173. Notes:
  174. --*/
  175. {
  176. NTSTATUS status;
  177. ULONG i;
  178. UNICODE_STRING unicodeString;
  179. UNICODE_STRING registryPathName;
  180. ULONG keyBasicInformationSize;
  181. PKEY_BASIC_INFORMATION keyBasicInformation = NULL;
  182. HANDLE handle;
  183. PKEY_FULL_INFORMATION keyInformation;
  184. ULONG size;
  185. PKEY_VALUE_FULL_INFORMATION busValueInfo[IoQueryDeviceMaxData];
  186. PAGED_CODE();
  187. status = IopGetRegistryKeyInformation( RootHandle,
  188. &keyInformation );
  189. if (NT_SUCCESS( status )) {
  190. //
  191. // With the keyInformation, allocate a buffer that will be large
  192. // enough for all the subkeys
  193. //
  194. keyBasicInformationSize = keyInformation->MaxNameLen +
  195. sizeof(KEY_NODE_INFORMATION);
  196. keyBasicInformation = ExAllocatePoolWithTag( PagedPool,
  197. keyBasicInformationSize,
  198. 'BKoI' );
  199. ExFreePool(keyInformation);
  200. if (keyBasicInformation == NULL) {
  201. return STATUS_INSUFFICIENT_RESOURCES;
  202. }
  203. }
  204. //
  205. // Now we need to enumerate the keys and see if one of them is a bus
  206. //
  207. for (i = 0; NT_SUCCESS( status ); i++) {
  208. //
  209. // If we have found the Bus we are looking for, break
  210. //
  211. if ((ARGUMENT_PRESENT( QueryDescription->BusNumber )) &&
  212. (*(QueryDescription->BusNumber) == *BusNum)) {
  213. break;
  214. }
  215. status = ZwEnumerateKey( RootHandle,
  216. i,
  217. KeyBasicInformation,
  218. keyBasicInformation,
  219. keyBasicInformationSize,
  220. &size );
  221. //
  222. // If the sub function enumerated all the buses till the end, then
  223. // treat that as success.
  224. //
  225. if (!NT_SUCCESS( status )) {
  226. break;
  227. }
  228. //
  229. // Only if this is a high key (otherwise we are in the callback
  230. // pass which we will process later on).
  231. //
  232. // If the string is any valid bus string, then we have to go down
  233. // the tree recursively.
  234. // Otherwise, go on to the next key.
  235. //
  236. if (HighKey) {
  237. if (wcsncmp( keyBasicInformation->Name,
  238. CmTypeString[MultiFunctionAdapter],
  239. keyBasicInformation->NameLength / sizeof(WCHAR) ) &&
  240. wcsncmp( keyBasicInformation->Name,
  241. CmTypeString[EisaAdapter],
  242. keyBasicInformation->NameLength / sizeof(WCHAR) ) &&
  243. wcsncmp( keyBasicInformation->Name,
  244. CmTypeString[TcAdapter],
  245. keyBasicInformation->NameLength / sizeof(WCHAR) )) {
  246. //
  247. // All the comparisons returned 1 (which means they all were
  248. // unsuccessful) so we do not have a bus.
  249. //
  250. // Go on to the next key.
  251. //
  252. continue;
  253. }
  254. }
  255. //
  256. // We have a bus. Open that key and enumerate it's clidren
  257. // (which should be numbers)
  258. //
  259. unicodeString.Buffer = keyBasicInformation->Name;
  260. unicodeString.Length = (USHORT) keyBasicInformation->NameLength;
  261. unicodeString.MaximumLength = (USHORT) keyBasicInformation->NameLength;
  262. if (!NT_SUCCESS( IopOpenRegistryKey( &handle,
  263. RootHandle,
  264. &unicodeString,
  265. KEY_READ,
  266. FALSE ) )) {
  267. //
  268. // The key could not be opened. Go to the next key
  269. //
  270. continue;
  271. }
  272. //
  273. // We have the key. now build the name for this path.
  274. //
  275. // Reset the string to its original value
  276. //
  277. registryPathName = PathName;
  278. RtlAppendUnicodeToString( &registryPathName,
  279. L"\\" );
  280. RtlAppendUnicodeStringToString( &registryPathName,
  281. &unicodeString );
  282. if (!HighKey) {
  283. //
  284. // We have a Key. Get the information for that key
  285. //
  286. status = IopGetRegistryValues( handle,
  287. &busValueInfo[0] );
  288. if (NT_SUCCESS( status )) {
  289. //
  290. // Verify that the identifier value for this bus
  291. // sub-key matches the user-specified bus type.
  292. // If not, do not increment the number of *found*
  293. // buses.
  294. //
  295. if (( busValueInfo[IoQueryDeviceConfigurationData] != NULL ) &&
  296. ( busValueInfo[IoQueryDeviceConfigurationData]->DataLength != 0 ) &&
  297. ( ((PCM_FULL_RESOURCE_DESCRIPTOR)
  298. ((PCCHAR) busValueInfo[IoQueryDeviceConfigurationData] +
  299. busValueInfo[IoQueryDeviceConfigurationData]->DataOffset))
  300. ->InterfaceType == *(QueryDescription->BusType) )) {
  301. //
  302. // Increment the number of buses of desired type we
  303. // have found.
  304. //
  305. (*BusNum)++;
  306. //
  307. // If we are looking for a specific bus number,
  308. // check to see if we are at the right number.
  309. // If we are not goto the next bus. Otherwise
  310. // (i.e we have the right bus number, or we
  311. // specified all buses), then go on so the
  312. // information can be reported.
  313. //
  314. if ( (QueryDescription->BusNumber == NULL) ||
  315. (*(QueryDescription->BusNumber) == *BusNum) ) {
  316. //
  317. // If we want controller information, call
  318. // the controller function.
  319. // Otherwise just return the bus information.
  320. //
  321. if (QueryDescription->ControllerType != NULL) {
  322. status = pIoQueryDeviceDescription(
  323. QueryDescription,
  324. registryPathName,
  325. handle,
  326. *BusNum,
  327. (PKEY_VALUE_FULL_INFORMATION *) busValueInfo );
  328. } else {
  329. status = QueryDescription->CalloutRoutine(
  330. QueryDescription->Context,
  331. &registryPathName,
  332. *(QueryDescription->BusType),
  333. *BusNum,
  334. (PKEY_VALUE_FULL_INFORMATION *) busValueInfo,
  335. 0,
  336. 0,
  337. NULL,
  338. 0,
  339. 0,
  340. NULL );
  341. }
  342. }
  343. }
  344. //
  345. // Free the pool allocated for the controller value data.
  346. //
  347. if (busValueInfo[0]) {
  348. ExFreePool( busValueInfo[0] );
  349. busValueInfo[0] = NULL;
  350. }
  351. if (busValueInfo[1]) {
  352. ExFreePool( busValueInfo[1] );
  353. busValueInfo[1] = NULL;
  354. }
  355. if (busValueInfo[2]) {
  356. ExFreePool( busValueInfo[2] );
  357. busValueInfo[2] = NULL;
  358. }
  359. }
  360. //
  361. // Shortcurt exit to avoid the recursive call.
  362. //
  363. if ((QueryDescription->BusNumber !=NULL ) &&
  364. (*(QueryDescription->BusNumber) == *BusNum)) {
  365. ZwClose( handle );
  366. handle = NULL;
  367. continue;
  368. }
  369. }
  370. //
  371. // If we have the key handle, do recursive enumeration.
  372. // enumaration (for both high and low keys)
  373. //
  374. status = pIoQueryBusDescription(
  375. QueryDescription,
  376. registryPathName,
  377. handle,
  378. BusNum,
  379. (BOOLEAN)!HighKey );
  380. //
  381. // If the sub function enumerated all the buses till the end, then
  382. // treat that as success.
  383. //
  384. if (status == STATUS_NO_MORE_ENTRIES) {
  385. status = STATUS_SUCCESS;
  386. }
  387. ZwClose( handle );
  388. handle = NULL;
  389. }
  390. if (keyBasicInformation) {
  391. ExFreePool( keyBasicInformation );
  392. }
  393. return status;
  394. }
  395. NTSTATUS
  396. pIoQueryDeviceDescription(
  397. PIO_QUERY_DESC QueryDescription,
  398. UNICODE_STRING PathName,
  399. HANDLE RootHandle,
  400. ULONG BusNum,
  401. PKEY_VALUE_FULL_INFORMATION *BusValueInfo
  402. )
  403. {
  404. NTSTATUS status;
  405. UNICODE_STRING registryPathName = PathName;
  406. UNICODE_STRING controllerBackupRegistryPathName;
  407. UNICODE_STRING peripheralBackupRegistryPathName;
  408. HANDLE controllerHandle = NULL;
  409. HANDLE peripheralHandle = NULL;
  410. PKEY_FULL_INFORMATION controllerTypeInfo = NULL;
  411. PKEY_FULL_INFORMATION peripheralTypeInfo = NULL;
  412. ULONG maxControllerNum;
  413. ULONG maxPeripheralNum;
  414. ULONG controllerNum;
  415. ULONG peripheralNum;
  416. WCHAR numBuffer[UNICODE_NUM_LENGTH];
  417. UNICODE_STRING bufferUnicodeString;
  418. PKEY_VALUE_FULL_INFORMATION controllerValueInfo[IoQueryDeviceMaxData];
  419. PKEY_VALUE_FULL_INFORMATION peripheralValueInfo[IoQueryDeviceMaxData];
  420. //
  421. // Set up a string for the number translation.
  422. //
  423. bufferUnicodeString.MaximumLength = UNICODE_NUM_LENGTH * sizeof(WCHAR);
  424. bufferUnicodeString.Buffer = &numBuffer[0];
  425. // For each controller of the specified type (subkeys 0..M)
  426. // if we are looking for controller information
  427. // call the specified callout routine
  428. // else
  429. // For each peripheral of the specified type (subkeys 0..N)
  430. // call the specified callout routine
  431. //
  432. // Add the controller name to the registry path name.
  433. //
  434. status = RtlAppendUnicodeToString( &registryPathName,
  435. L"\\" );
  436. if (NT_SUCCESS( status )) {
  437. status = RtlAppendUnicodeToString( &registryPathName,
  438. CmTypeString[*(QueryDescription->ControllerType)] );
  439. }
  440. if (!NT_SUCCESS( status )) {
  441. return status;
  442. }
  443. //
  444. // If a Contoller number was specified by the caller, use that
  445. // controller number. Otherwise, find out how many buses are present
  446. // by querying the key.
  447. //
  448. if (ARGUMENT_PRESENT( QueryDescription->ControllerNumber )) {
  449. controllerNum = *(QueryDescription->ControllerNumber);
  450. maxControllerNum = controllerNum + 1;
  451. } else {
  452. //
  453. // Open the registry key for the controller and
  454. // Get the full key information for the controller key to
  455. // determine the number of sub-keys (controller numbers).
  456. // And we fail, then go on to the next bus.
  457. // Note the memory allocated by the query must be freed.
  458. //
  459. status = IopOpenRegistryKey( &controllerHandle,
  460. (HANDLE) NULL,
  461. &registryPathName,
  462. KEY_READ,
  463. FALSE );
  464. if (NT_SUCCESS( status )) {
  465. status = IopGetRegistryKeyInformation( controllerHandle,
  466. &controllerTypeInfo );
  467. ZwClose( controllerHandle );
  468. controllerHandle = NULL;
  469. }
  470. //
  471. // If no controller of this type was found on the bus, go on to
  472. // the next bus; goto the end of the loop with a successful status
  473. // so that the memory gets freed, but we continue looping.
  474. //
  475. if (!NT_SUCCESS( status )) {
  476. return status;
  477. }
  478. //
  479. // Get the number of controller sub-keys for this controller
  480. // type and free the pool.
  481. //
  482. maxControllerNum = controllerTypeInfo->SubKeys;
  483. controllerNum = 0;
  484. ExFreePool( controllerTypeInfo );
  485. controllerTypeInfo = NULL;
  486. }
  487. //
  488. // Make a backup of the string since we want to start where we were
  489. // on the next loop iteration.
  490. //
  491. controllerBackupRegistryPathName = registryPathName;
  492. //
  493. // For each controller of the specified type (subkeys 0..M).
  494. // We use BusNumber as the initial value since it is zero if we want
  495. // all buses, and we only want the bus specified if the value is not
  496. // zero.
  497. //
  498. for ( ; controllerNum < maxControllerNum; controllerNum++) {
  499. //
  500. // Reset the string to its original value
  501. //
  502. registryPathName = controllerBackupRegistryPathName;
  503. //
  504. // Convert the controller number to a unicode string and append
  505. // it to the registry path name.
  506. //
  507. bufferUnicodeString.Length = (UNICODE_NUM_LENGTH-1) * sizeof(WCHAR);
  508. status = RtlIntegerToUnicodeString( controllerNum,
  509. 10,
  510. &bufferUnicodeString );
  511. if (NT_SUCCESS( status )) {
  512. status = RtlAppendUnicodeToString( &registryPathName,
  513. L"\\" );
  514. if (NT_SUCCESS( status )) {
  515. status = RtlAppendUnicodeStringToString(
  516. &registryPathName,
  517. &bufferUnicodeString );
  518. }
  519. }
  520. if (!NT_SUCCESS( status )) {
  521. break;
  522. }
  523. //
  524. // Open the registry key for the controller number and
  525. // Get the value data for this controller and save it for later.
  526. //
  527. status = IopOpenRegistryKey( &controllerHandle,
  528. (HANDLE) NULL,
  529. &registryPathName,
  530. KEY_READ,
  531. FALSE );
  532. if (NT_SUCCESS( status )) {
  533. status = IopGetRegistryValues( controllerHandle,
  534. &controllerValueInfo[0] );
  535. ZwClose( controllerHandle );
  536. controllerHandle = NULL;
  537. }
  538. //
  539. // If we could not open the key and get the info, just continue
  540. // since there is no memory to free and we are using the for
  541. // loop to determine when we get to the last controller.
  542. //
  543. if (!NT_SUCCESS( status )) {
  544. continue;
  545. }
  546. //
  547. // Check if we want the controller and bus information only. If
  548. // it is the case, invoque the callout routine and go on to the
  549. // next loop (unless an error occurs in the callout).
  550. //
  551. if (!ARGUMENT_PRESENT( (QueryDescription->PeripheralType) )) {
  552. status = QueryDescription->CalloutRoutine(
  553. QueryDescription->Context,
  554. &registryPathName,
  555. *(QueryDescription->BusType),
  556. BusNum,
  557. BusValueInfo,
  558. *(QueryDescription->ControllerType),
  559. controllerNum,
  560. (PKEY_VALUE_FULL_INFORMATION *) controllerValueInfo,
  561. 0,
  562. 0,
  563. NULL );
  564. goto IoQueryDeviceControllerLoop;
  565. }
  566. //
  567. // Add the peripheral name to the registry path name.
  568. //
  569. status = RtlAppendUnicodeToString( &registryPathName,
  570. L"\\" );
  571. if (NT_SUCCESS( status )) {
  572. status = RtlAppendUnicodeToString(
  573. &registryPathName,
  574. CmTypeString[*(QueryDescription->PeripheralType)] );
  575. }
  576. if (!NT_SUCCESS( status )) {
  577. goto IoQueryDeviceControllerLoop;
  578. }
  579. //
  580. // If a Peripheralnumber was specified by the caller, use that
  581. // peripheral number. Otherwise, find out how many buses are
  582. // present by querying the key.
  583. //
  584. if (ARGUMENT_PRESENT( (QueryDescription->PeripheralNumber) )) {
  585. peripheralNum = *(QueryDescription->PeripheralNumber);
  586. maxPeripheralNum = peripheralNum + 1;
  587. } else {
  588. //
  589. // Open the registry key for the peripheral and
  590. // Get the full key information for the peripheral key to
  591. // determine the number of sub-keys (peripheral numbers).
  592. // And we fail, then go on to the next controller.
  593. // Note the memory allocated by the query must be freed.
  594. //
  595. status = IopOpenRegistryKey( &peripheralHandle,
  596. (HANDLE) NULL,
  597. &registryPathName,
  598. KEY_READ,
  599. FALSE );
  600. if (NT_SUCCESS( status )) {
  601. status = IopGetRegistryKeyInformation( peripheralHandle,
  602. &peripheralTypeInfo );
  603. ZwClose( peripheralHandle );
  604. peripheralHandle = NULL;
  605. }
  606. //
  607. // If no controller of this type was found on the bus, go on to
  608. // the next bus; goto the end of the loop with a successful
  609. // status so that the memory gets freed, but we continue looping.
  610. //
  611. if (!NT_SUCCESS( status )) {
  612. status = STATUS_SUCCESS;
  613. goto IoQueryDeviceControllerLoop;
  614. }
  615. //
  616. // Get the number of peripheral sub-keys for this peripheral
  617. // type and free the pool.
  618. //
  619. maxPeripheralNum = peripheralTypeInfo->SubKeys;
  620. peripheralNum = 0;
  621. ExFreePool( peripheralTypeInfo );
  622. peripheralTypeInfo = NULL;
  623. }
  624. //
  625. // Make a backup of the string since we want to start where we
  626. // were on the next loop iteration.
  627. //
  628. peripheralBackupRegistryPathName = registryPathName;
  629. //
  630. // For each peripheral of the specified type (subkeys 0..N).
  631. // We use BusNumber as the initial value since it is zero if we
  632. // want all buses, and we only want the bus specified if the
  633. // value is not zero.
  634. //
  635. for ( ; peripheralNum < maxPeripheralNum; peripheralNum++) {
  636. //
  637. // Reset the string to its original value.
  638. //
  639. registryPathName = peripheralBackupRegistryPathName;
  640. //
  641. // Convert the peripheral number to a unicode string and append
  642. // it to the registry path name.
  643. //
  644. bufferUnicodeString.Length =
  645. (UNICODE_NUM_LENGTH-1) * sizeof(WCHAR);
  646. status = RtlIntegerToUnicodeString( peripheralNum,
  647. 10,
  648. &bufferUnicodeString );
  649. if (NT_SUCCESS( status )) {
  650. status = RtlAppendUnicodeToString( &registryPathName,
  651. L"\\" );
  652. if (NT_SUCCESS( status )) {
  653. status = RtlAppendUnicodeStringToString(
  654. &registryPathName,
  655. &bufferUnicodeString );
  656. }
  657. }
  658. if (!NT_SUCCESS( status )) {
  659. break;
  660. }
  661. //
  662. // Open the registry key for the peripheral number and
  663. // Get the value data for this peripheral and save it for
  664. // later.
  665. //
  666. status = IopOpenRegistryKey( &peripheralHandle,
  667. (HANDLE) NULL,
  668. &registryPathName,
  669. KEY_READ,
  670. FALSE );
  671. if (NT_SUCCESS( status )) {
  672. status = IopGetRegistryValues( peripheralHandle,
  673. &peripheralValueInfo[0] );
  674. ZwClose( peripheralHandle );
  675. peripheralHandle = NULL;
  676. }
  677. //
  678. // If getting the peripheral information worked properly,
  679. // call the user-specified callout routine.
  680. //
  681. if (NT_SUCCESS( status )) {
  682. status = QueryDescription->CalloutRoutine(
  683. QueryDescription->Context,
  684. &registryPathName,
  685. *(QueryDescription->BusType),
  686. BusNum,
  687. BusValueInfo,
  688. *(QueryDescription->ControllerType),
  689. controllerNum,
  690. (PKEY_VALUE_FULL_INFORMATION *) controllerValueInfo,
  691. *(QueryDescription->PeripheralType),
  692. peripheralNum,
  693. (PKEY_VALUE_FULL_INFORMATION *) peripheralValueInfo );
  694. //
  695. // Free the pool allocated for the peripheral value data.
  696. //
  697. if (peripheralValueInfo[0]) {
  698. ExFreePool( peripheralValueInfo[0] );
  699. peripheralValueInfo[0] = NULL;
  700. }
  701. if (peripheralValueInfo[1]) {
  702. ExFreePool( peripheralValueInfo[1] );
  703. peripheralValueInfo[1] = NULL;
  704. }
  705. if (peripheralValueInfo[2]) {
  706. ExFreePool( peripheralValueInfo[2] );
  707. peripheralValueInfo[2] = NULL;
  708. }
  709. //
  710. // If the user-specified callout routine returned with
  711. // an unsuccessful status, quit.
  712. //
  713. if (!NT_SUCCESS( status )) {
  714. break;
  715. }
  716. }
  717. } // for ( ; peripheralNum < maxPeripheralNum ...
  718. IoQueryDeviceControllerLoop:
  719. //
  720. // Free the pool allocated for the controller value data.
  721. //
  722. if (controllerValueInfo[0]) {
  723. ExFreePool( controllerValueInfo[0] );
  724. controllerValueInfo[0] = NULL;
  725. }
  726. if (controllerValueInfo[1]) {
  727. ExFreePool( controllerValueInfo[1] );
  728. controllerValueInfo[1] = NULL;
  729. }
  730. if (controllerValueInfo[2]) {
  731. ExFreePool( controllerValueInfo[2] );
  732. controllerValueInfo[2] = NULL;
  733. }
  734. if (!NT_SUCCESS( status )) {
  735. break;
  736. }
  737. } // for ( ; controllerNum < maxControllerNum...
  738. return( status );
  739. }
  740.