940 lines
27 KiB
C
940 lines
27 KiB
C
/*++
|
|
|
|
Copyright (c) 1989-1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
query.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the subroutines to Query Device Descriptions from
|
|
the Hardware tree in the registry
|
|
|
|
Author:
|
|
|
|
Andre Vachon (andreva) 20-Jun-1994
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "iop.h"
|
|
|
|
typedef struct _IO_QUERY_DESC {
|
|
PINTERFACE_TYPE BusType;
|
|
PULONG BusNumber;
|
|
PCONFIGURATION_TYPE ControllerType;
|
|
PULONG ControllerNumber;
|
|
PCONFIGURATION_TYPE PeripheralType;
|
|
PULONG PeripheralNumber;
|
|
PIO_QUERY_DEVICE_ROUTINE CalloutRoutine;
|
|
PVOID Context;
|
|
} IO_QUERY_DESC, *PIO_QUERY_DESC;
|
|
|
|
|
|
NTSTATUS
|
|
pIoQueryBusDescription(
|
|
PIO_QUERY_DESC QueryDescription,
|
|
UNICODE_STRING PathName,
|
|
HANDLE RootHandle,
|
|
PULONG BusNum,
|
|
BOOLEAN HighKey
|
|
);
|
|
|
|
NTSTATUS
|
|
pIoQueryDeviceDescription(
|
|
PIO_QUERY_DESC QueryDescription,
|
|
UNICODE_STRING PathName,
|
|
HANDLE RootHandle,
|
|
ULONG BusNum,
|
|
PKEY_VALUE_FULL_INFORMATION *BusValueInfo
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, IoQueryDeviceDescription)
|
|
#pragma alloc_text(PAGE, pIoQueryBusDescription)
|
|
#pragma alloc_text(PAGE, pIoQueryDeviceDescription)
|
|
#endif
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
IoQueryDeviceDescription(
|
|
IN PINTERFACE_TYPE BusType OPTIONAL,
|
|
IN PULONG BusNumber OPTIONAL,
|
|
IN PCONFIGURATION_TYPE ControllerType OPTIONAL,
|
|
IN PULONG ControllerNumber OPTIONAL,
|
|
IN PCONFIGURATION_TYPE PeripheralType OPTIONAL,
|
|
IN PULONG PeripheralNumber OPTIONAL,
|
|
IN PIO_QUERY_DEVICE_ROUTINE CalloutRoutine,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
BusType - Supplies an optional bus type being searched for in the
|
|
description tree. Valid types are Mca, Isa, Eisa ... If no bus type
|
|
is specified, the system information (i.e. machine BIOS) is returned.
|
|
|
|
BusNumber - Supplies an optional value determining which bus should be
|
|
queried.
|
|
|
|
ControllerType - Supplies an optional controller type being searched for.
|
|
If no Controller type is specified, only the Bus information is
|
|
returned.
|
|
|
|
ControllerNumber - Supplies an optional value determining which
|
|
controller should be queried.
|
|
|
|
PeripheralType - Supplies an optional peripheral type being searched for.
|
|
If no Controller type is specified, only the Bus information and the
|
|
controller information are returned.
|
|
|
|
PeripheralNumber - Supplies an optional value determining which
|
|
peripheral should be queried.
|
|
|
|
CalloutRoutine - Supplies a pointer to a routine that gets called
|
|
for each successful match of PeripheralType.
|
|
|
|
Context - Supplies a context value that is passed back to the callback
|
|
routine.
|
|
|
|
Return Value:
|
|
|
|
The status returned is the final completion status of the operation.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#define UNICODE_NUM_LENGTH 14
|
|
#define UNICODE_REGISTRY_PATH_LENGTH 1024
|
|
|
|
IO_QUERY_DESC queryDesc;
|
|
|
|
NTSTATUS status;
|
|
UNICODE_STRING registryPathName;
|
|
HANDLE rootHandle;
|
|
ULONG busNumber = (ULONG) -1;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( CalloutRoutine != NULL );
|
|
|
|
|
|
// Check if we need to return the machine information
|
|
|
|
|
|
if (!ARGUMENT_PRESENT( BusType )) {
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
queryDesc.BusType = BusType;
|
|
queryDesc.BusNumber = BusNumber;
|
|
queryDesc.ControllerType = ControllerType;
|
|
queryDesc.ControllerNumber = ControllerNumber;
|
|
queryDesc.PeripheralType = PeripheralType;
|
|
queryDesc.PeripheralNumber = PeripheralNumber;
|
|
queryDesc.CalloutRoutine = CalloutRoutine;
|
|
queryDesc.Context = Context;
|
|
|
|
|
|
|
|
// Set up a string with the pathname to the hardware description portion of the registry.
|
|
registryPathName.Length = 0;
|
|
registryPathName.MaximumLength = UNICODE_REGISTRY_PATH_LENGTH * sizeof(WCHAR);
|
|
registryPathName.Buffer = ExAllocatePoolWithTag( PagedPool, UNICODE_REGISTRY_PATH_LENGTH, 'mNoI' );
|
|
if (!registryPathName.Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlAppendUnicodeStringToString( ®istryPathName, &CmRegistryMachineHardwareDescriptionSystemName );
|
|
|
|
// Open a handle to the root path we have.
|
|
status = IopOpenRegistryKey( &rootHandle, (HANDLE) NULL, ®istryPathName, KEY_READ, FALSE );
|
|
if (NT_SUCCESS( status )) {
|
|
status = pIoQueryBusDescription(&queryDesc, registryPathName, rootHandle, &busNumber, TRUE );
|
|
ZwClose( rootHandle );
|
|
}
|
|
|
|
ExFreePool( registryPathName.Buffer );
|
|
|
|
// For compatibility with old version of the function.
|
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
} else {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
pIoQueryBusDescription(
|
|
PIO_QUERY_DESC QueryDescription,
|
|
UNICODE_STRING PathName,
|
|
HANDLE RootHandle,
|
|
PULONG BusNum,
|
|
BOOLEAN HighKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
QueryDescription - Buffer containing all the query information requested
|
|
by the driver.
|
|
|
|
PathName - Registry path name of the key we are dealing with. This is
|
|
a unicode strig so that we don't have to bother with resetting NULLs
|
|
at the end of the string - the length determines how much of the
|
|
string is valid.
|
|
|
|
RootHandle - Handle equivalent to the registry path.
|
|
|
|
BusNum - Pointer to a variable that keeps track of the bus number we are
|
|
searching for (buses have to be accumulated.
|
|
|
|
HighKey - Determines is this is a high key (a root key with a list of
|
|
bus types) or a low level key (under which the number of the various
|
|
buses will be little).
|
|
|
|
Return Value:
|
|
|
|
The status returned is the final completion status of the operation.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
ULONG i;
|
|
UNICODE_STRING unicodeString;
|
|
|
|
UNICODE_STRING registryPathName;
|
|
|
|
ULONG keyBasicInformationSize;
|
|
PKEY_BASIC_INFORMATION keyBasicInformation = NULL;
|
|
HANDLE handle;
|
|
|
|
PKEY_FULL_INFORMATION keyInformation;
|
|
ULONG size;
|
|
|
|
PKEY_VALUE_FULL_INFORMATION busValueInfo[IoQueryDeviceMaxData];
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
status = IopGetRegistryKeyInformation( RootHandle, &keyInformation );
|
|
if (NT_SUCCESS( status )) {
|
|
// With the keyInformation, allocate a buffer that will be large enough for all the subkeys
|
|
keyBasicInformationSize = keyInformation->MaxNameLen + sizeof(KEY_NODE_INFORMATION);
|
|
keyBasicInformation = ExAllocatePoolWithTag( PagedPool, keyBasicInformationSize, 'mNoI' );
|
|
ExFreePool(keyInformation);
|
|
if (keyBasicInformation == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
// Now we need to enumerate the keys and see if one of them is a bus
|
|
for (i = 0; NT_SUCCESS( status ); i++) {
|
|
// If we have found the Bus we are looking for, break
|
|
if ((ARGUMENT_PRESENT( QueryDescription->BusNumber )) && (*(QueryDescription->BusNumber) == *BusNum)) {
|
|
break;
|
|
}
|
|
|
|
status = ZwEnumerateKey( RootHandle,
|
|
i,
|
|
KeyBasicInformation,
|
|
keyBasicInformation,
|
|
keyBasicInformationSize,
|
|
&size );
|
|
|
|
// If the sub function enumerated all the buses till the end, then
|
|
// treat that as success.
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
|
|
// Only if this is a high key (otherwise we are in the callback
|
|
// pass which we will process later on).
|
|
|
|
// If the string is any valid bus string, then we have to go down
|
|
// the tree recursively.
|
|
// Otherwise, go on to the next key.
|
|
|
|
|
|
if (HighKey) {
|
|
if (wcsncmp( keyBasicInformation->Name, CmTypeString[MultiFunctionAdapter], keyBasicInformation->NameLength / sizeof(WCHAR) ) &&
|
|
wcsncmp( keyBasicInformation->Name, CmTypeString[EisaAdapter], keyBasicInformation->NameLength / sizeof(WCHAR) ) &&
|
|
wcsncmp( keyBasicInformation->Name, CmTypeString[TcAdapter], keyBasicInformation->NameLength / sizeof(WCHAR) )) {
|
|
// All the comparisons returned 1 (which means they all were unsuccessful) so we do not have a bus.
|
|
// Go on to the next key.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
// We have a bus. Open that key and enumerate it's clidren
|
|
// (which should be numbers)
|
|
|
|
|
|
unicodeString.Buffer = keyBasicInformation->Name;
|
|
unicodeString.Length = (USHORT) keyBasicInformation->NameLength;
|
|
unicodeString.MaximumLength = (USHORT) keyBasicInformation->NameLength;
|
|
|
|
if (!NT_SUCCESS( IopOpenRegistryKey( &handle,
|
|
RootHandle,
|
|
&unicodeString,
|
|
KEY_READ,
|
|
FALSE ) )) {
|
|
|
|
|
|
// The key could not be opened. Go to the next key
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
// We have the key. now build the name for this path.
|
|
|
|
// Reset the string to its original value
|
|
|
|
|
|
registryPathName = PathName;
|
|
|
|
RtlAppendUnicodeToString( ®istryPathName,
|
|
L"\\" );
|
|
|
|
RtlAppendUnicodeStringToString( ®istryPathName,
|
|
&unicodeString );
|
|
|
|
|
|
if (!HighKey) {
|
|
|
|
|
|
// We have a Key. Get the information for that key
|
|
|
|
|
|
status = IopGetRegistryValues( handle,
|
|
&busValueInfo[0] );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
|
|
// Verify that the identifier value for this bus
|
|
// sub-key matches the user-specified bus type.
|
|
// If not, do not increment the number of *found*
|
|
// buses.
|
|
|
|
|
|
if (( busValueInfo[IoQueryDeviceConfigurationData] != NULL ) &&
|
|
( busValueInfo[IoQueryDeviceConfigurationData]->DataLength != 0 ) &&
|
|
( ((PCM_FULL_RESOURCE_DESCRIPTOR)
|
|
((PCCHAR) busValueInfo[IoQueryDeviceConfigurationData] +
|
|
busValueInfo[IoQueryDeviceConfigurationData]->DataOffset))
|
|
->InterfaceType == *(QueryDescription->BusType) )) {
|
|
|
|
|
|
// Increment the number of buses of desired type we
|
|
// have found.
|
|
|
|
|
|
(*BusNum)++;
|
|
|
|
|
|
// If we are looking for a specific bus number,
|
|
// check to see if we are at the right number.
|
|
// If we are not goto the next bus. Otherwise
|
|
// (i.e we have the right bus number, or we
|
|
// specified all buses), then go on so the
|
|
// information can be reported.
|
|
|
|
|
|
if ( (QueryDescription->BusNumber == NULL) ||
|
|
(*(QueryDescription->BusNumber) == *BusNum) ) {
|
|
|
|
|
|
|
|
// If we want controller information, call
|
|
// the controller function.
|
|
// Otherwise just return the bus information.
|
|
|
|
|
|
if (QueryDescription->ControllerType != NULL) {
|
|
|
|
status = pIoQueryDeviceDescription(
|
|
QueryDescription,
|
|
registryPathName,
|
|
handle,
|
|
*BusNum,
|
|
(PKEY_VALUE_FULL_INFORMATION *) busValueInfo );
|
|
|
|
} else {
|
|
|
|
status = QueryDescription->CalloutRoutine(
|
|
QueryDescription->Context,
|
|
®istryPathName,
|
|
*(QueryDescription->BusType),
|
|
*BusNum,
|
|
(PKEY_VALUE_FULL_INFORMATION *) busValueInfo,
|
|
0,
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Free the pool allocated for the controller value data.
|
|
|
|
|
|
if (busValueInfo[0]) {
|
|
ExFreePool( busValueInfo[0] );
|
|
busValueInfo[0] = NULL;
|
|
}
|
|
if (busValueInfo[1]) {
|
|
ExFreePool( busValueInfo[1] );
|
|
busValueInfo[1] = NULL;
|
|
}
|
|
if (busValueInfo[2]) {
|
|
ExFreePool( busValueInfo[2] );
|
|
busValueInfo[2] = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shortcurt exit to avoid the recursive call.
|
|
|
|
|
|
if ((QueryDescription->BusNumber !=NULL ) &&
|
|
(*(QueryDescription->BusNumber) == *BusNum)) {
|
|
ZwClose( handle );
|
|
handle = NULL;
|
|
continue;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// If we have the key handle, do recursive enumeration.
|
|
// enumaration (for both high and low keys)
|
|
|
|
|
|
status = pIoQueryBusDescription(
|
|
QueryDescription,
|
|
registryPathName,
|
|
handle,
|
|
BusNum,
|
|
(BOOLEAN)!HighKey );
|
|
|
|
|
|
// If the sub function enumerated all the buses till the end, then
|
|
// treat that as success.
|
|
|
|
|
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
ZwClose( handle );
|
|
handle = NULL;
|
|
|
|
}
|
|
|
|
if (keyBasicInformation) {
|
|
ExFreePool( keyBasicInformation );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
pIoQueryDeviceDescription(
|
|
PIO_QUERY_DESC QueryDescription,
|
|
UNICODE_STRING PathName,
|
|
HANDLE RootHandle,
|
|
ULONG BusNum,
|
|
PKEY_VALUE_FULL_INFORMATION *BusValueInfo
|
|
)
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
UNICODE_STRING registryPathName = PathName;
|
|
UNICODE_STRING controllerBackupRegistryPathName;
|
|
UNICODE_STRING peripheralBackupRegistryPathName;
|
|
HANDLE controllerHandle = NULL;
|
|
HANDLE peripheralHandle = NULL;
|
|
PKEY_FULL_INFORMATION controllerTypeInfo = NULL;
|
|
PKEY_FULL_INFORMATION peripheralTypeInfo = NULL;
|
|
ULONG maxControllerNum;
|
|
ULONG maxPeripheralNum;
|
|
ULONG controllerNum;
|
|
ULONG peripheralNum;
|
|
WCHAR numBuffer[UNICODE_NUM_LENGTH];
|
|
UNICODE_STRING bufferUnicodeString;
|
|
PKEY_VALUE_FULL_INFORMATION controllerValueInfo[IoQueryDeviceMaxData];
|
|
PKEY_VALUE_FULL_INFORMATION peripheralValueInfo[IoQueryDeviceMaxData];
|
|
|
|
|
|
|
|
// Set up a string for the number translation.
|
|
|
|
|
|
bufferUnicodeString.MaximumLength = UNICODE_NUM_LENGTH * sizeof(WCHAR);
|
|
bufferUnicodeString.Buffer = &numBuffer[0];
|
|
|
|
|
|
// For each controller of the specified type (subkeys 0..M)
|
|
// if we are looking for controller information
|
|
// call the specified callout routine
|
|
// else
|
|
// For each peripheral of the specified type (subkeys 0..N)
|
|
// call the specified callout routine
|
|
|
|
|
|
// Add the controller name to the registry path name.
|
|
|
|
|
|
status = RtlAppendUnicodeToString( ®istryPathName,
|
|
L"\\" );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = RtlAppendUnicodeToString( ®istryPathName,
|
|
CmTypeString[*(QueryDescription->ControllerType)] );
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
return status;
|
|
}
|
|
|
|
|
|
// If a Contoller number was specified by the caller, use that
|
|
// controller number. Otherwise, find out how many buses are present
|
|
// by querying the key.
|
|
|
|
|
|
if (ARGUMENT_PRESENT( QueryDescription->ControllerNumber )) {
|
|
|
|
controllerNum = *(QueryDescription->ControllerNumber);
|
|
maxControllerNum = controllerNum + 1;
|
|
|
|
} else {
|
|
|
|
|
|
// Open the registry key for the controller and
|
|
// Get the full key information for the controller key to
|
|
// determine the number of sub-keys (controller numbers).
|
|
// And we fail, then go on to the next bus.
|
|
// Note the memory allocated by the query must be freed.
|
|
|
|
|
|
status = IopOpenRegistryKey( &controllerHandle,
|
|
(HANDLE) NULL,
|
|
®istryPathName,
|
|
KEY_READ,
|
|
FALSE );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = IopGetRegistryKeyInformation( controllerHandle,
|
|
&controllerTypeInfo );
|
|
|
|
ZwClose( controllerHandle );
|
|
controllerHandle = NULL;
|
|
}
|
|
|
|
|
|
// If no controller of this type was found on the bus, go on to
|
|
// the next bus; goto the end of the loop with a successful status
|
|
// so that the memory gets freed, but we continue looping.
|
|
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
// Get the number of controller sub-keys for this controller
|
|
// type and free the pool.
|
|
|
|
|
|
maxControllerNum = controllerTypeInfo->SubKeys;
|
|
controllerNum = 0;
|
|
|
|
ExFreePool( controllerTypeInfo );
|
|
controllerTypeInfo = NULL;
|
|
}
|
|
|
|
|
|
// Make a backup of the string since we want to start where we were
|
|
// on the next loop iteration.
|
|
|
|
|
|
controllerBackupRegistryPathName = registryPathName;
|
|
|
|
|
|
// For each controller of the specified type (subkeys 0..M).
|
|
// We use BusNumber as the initial value since it is zero if we want
|
|
// all buses, and we only want the bus specified if the value is not
|
|
// zero.
|
|
|
|
|
|
for ( ; controllerNum < maxControllerNum; controllerNum++) {
|
|
|
|
|
|
// Reset the string to its original value
|
|
|
|
|
|
registryPathName = controllerBackupRegistryPathName;
|
|
|
|
|
|
// Convert the controller number to a unicode string and append
|
|
// it to the registry path name.
|
|
|
|
|
|
bufferUnicodeString.Length = (UNICODE_NUM_LENGTH-1) * sizeof(WCHAR);
|
|
status = RtlIntegerToUnicodeString( controllerNum,
|
|
10,
|
|
&bufferUnicodeString );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = RtlAppendUnicodeToString( ®istryPathName,
|
|
L"\\" );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = RtlAppendUnicodeStringToString(
|
|
®istryPathName,
|
|
&bufferUnicodeString );
|
|
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
|
|
// Open the registry key for the controller number and
|
|
// Get the value data for this controller and save it for later.
|
|
|
|
|
|
|
|
status = IopOpenRegistryKey( &controllerHandle,
|
|
(HANDLE) NULL,
|
|
®istryPathName,
|
|
KEY_READ,
|
|
FALSE );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = IopGetRegistryValues( controllerHandle,
|
|
&controllerValueInfo[0] );
|
|
|
|
ZwClose( controllerHandle );
|
|
controllerHandle = NULL;
|
|
}
|
|
|
|
|
|
// If we could not open the key and get the info, just continue
|
|
// since there is no memory to free and we are using the for
|
|
// loop to determine when we get to the last controller.
|
|
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
continue;
|
|
}
|
|
|
|
|
|
// Check if we want the controller and bus information only. If
|
|
// it is the case, invoque the callout routine and go on to the
|
|
// next loop (unless an error occurs in the callout).
|
|
|
|
|
|
if (!ARGUMENT_PRESENT( (QueryDescription->PeripheralType) )) {
|
|
|
|
status = QueryDescription->CalloutRoutine(
|
|
QueryDescription->Context,
|
|
®istryPathName,
|
|
*(QueryDescription->BusType),
|
|
BusNum,
|
|
BusValueInfo,
|
|
*(QueryDescription->ControllerType),
|
|
controllerNum,
|
|
(PKEY_VALUE_FULL_INFORMATION *) controllerValueInfo,
|
|
0,
|
|
0,
|
|
NULL );
|
|
|
|
goto IoQueryDeviceControllerLoop;
|
|
}
|
|
|
|
|
|
// Add the peripheral name to the registry path name.
|
|
|
|
|
|
status = RtlAppendUnicodeToString( ®istryPathName,
|
|
L"\\" );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = RtlAppendUnicodeToString(
|
|
®istryPathName,
|
|
CmTypeString[*(QueryDescription->PeripheralType)] );
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
goto IoQueryDeviceControllerLoop;
|
|
}
|
|
|
|
|
|
// If a Peripheralnumber was specified by the caller, use that
|
|
// peripheral number. Otherwise, find out how many buses are
|
|
// present by querying the key.
|
|
|
|
|
|
if (ARGUMENT_PRESENT( (QueryDescription->PeripheralNumber) )) {
|
|
|
|
peripheralNum = *(QueryDescription->PeripheralNumber);
|
|
maxPeripheralNum = peripheralNum + 1;
|
|
|
|
} else {
|
|
|
|
|
|
// Open the registry key for the peripheral and
|
|
// Get the full key information for the peripheral key to
|
|
// determine the number of sub-keys (peripheral numbers).
|
|
// And we fail, then go on to the next controller.
|
|
// Note the memory allocated by the query must be freed.
|
|
|
|
|
|
status = IopOpenRegistryKey( &peripheralHandle,
|
|
(HANDLE) NULL,
|
|
®istryPathName,
|
|
KEY_READ,
|
|
FALSE );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = IopGetRegistryKeyInformation( peripheralHandle,
|
|
&peripheralTypeInfo );
|
|
|
|
ZwClose( peripheralHandle );
|
|
peripheralHandle = NULL;
|
|
}
|
|
|
|
|
|
// If no controller of this type was found on the bus, go on to
|
|
// the next bus; goto the end of the loop with a successful
|
|
// status so that the memory gets freed, but we continue looping.
|
|
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
status = STATUS_SUCCESS;
|
|
goto IoQueryDeviceControllerLoop;
|
|
}
|
|
|
|
|
|
// Get the number of peripheral sub-keys for this peripheral
|
|
// type and free the pool.
|
|
|
|
|
|
maxPeripheralNum = peripheralTypeInfo->SubKeys;
|
|
peripheralNum = 0;
|
|
|
|
ExFreePool( peripheralTypeInfo );
|
|
peripheralTypeInfo = NULL;
|
|
}
|
|
|
|
|
|
// Make a backup of the string since we want to start where we
|
|
// were on the next loop iteration.
|
|
|
|
|
|
peripheralBackupRegistryPathName = registryPathName;
|
|
|
|
|
|
// For each peripheral of the specified type (subkeys 0..N).
|
|
// We use BusNumber as the initial value since it is zero if we
|
|
// want all buses, and we only want the bus specified if the
|
|
// value is not zero.
|
|
|
|
|
|
for ( ; peripheralNum < maxPeripheralNum; peripheralNum++) {
|
|
|
|
|
|
// Reset the string to its original value.
|
|
|
|
|
|
registryPathName = peripheralBackupRegistryPathName;
|
|
|
|
|
|
// Convert the peripheral number to a unicode string and append
|
|
// it to the registry path name.
|
|
|
|
|
|
bufferUnicodeString.Length =
|
|
(UNICODE_NUM_LENGTH-1) * sizeof(WCHAR);
|
|
status = RtlIntegerToUnicodeString( peripheralNum,
|
|
10,
|
|
&bufferUnicodeString );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = RtlAppendUnicodeToString( ®istryPathName,
|
|
L"\\" );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = RtlAppendUnicodeStringToString(
|
|
®istryPathName,
|
|
&bufferUnicodeString );
|
|
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
|
|
// Open the registry key for the peripheral number and
|
|
// Get the value data for this peripheral and save it for
|
|
// later.
|
|
|
|
|
|
status = IopOpenRegistryKey( &peripheralHandle,
|
|
(HANDLE) NULL,
|
|
®istryPathName,
|
|
KEY_READ,
|
|
FALSE );
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = IopGetRegistryValues( peripheralHandle,
|
|
&peripheralValueInfo[0] );
|
|
|
|
ZwClose( peripheralHandle );
|
|
peripheralHandle = NULL;
|
|
}
|
|
|
|
|
|
// If getting the peripheral information worked properly,
|
|
// call the user-specified callout routine.
|
|
|
|
|
|
if (NT_SUCCESS( status )) {
|
|
|
|
status = QueryDescription->CalloutRoutine(
|
|
QueryDescription->Context,
|
|
®istryPathName,
|
|
*(QueryDescription->BusType),
|
|
BusNum,
|
|
BusValueInfo,
|
|
*(QueryDescription->ControllerType),
|
|
controllerNum,
|
|
(PKEY_VALUE_FULL_INFORMATION *) controllerValueInfo,
|
|
*(QueryDescription->PeripheralType),
|
|
peripheralNum,
|
|
(PKEY_VALUE_FULL_INFORMATION *) peripheralValueInfo );
|
|
|
|
|
|
// Free the pool allocated for the peripheral value data.
|
|
|
|
|
|
if (peripheralValueInfo[0]) {
|
|
ExFreePool( peripheralValueInfo[0] );
|
|
peripheralValueInfo[0] = NULL;
|
|
}
|
|
if (peripheralValueInfo[1]) {
|
|
ExFreePool( peripheralValueInfo[1] );
|
|
peripheralValueInfo[1] = NULL;
|
|
}
|
|
if (peripheralValueInfo[2]) {
|
|
ExFreePool( peripheralValueInfo[2] );
|
|
peripheralValueInfo[2] = NULL;
|
|
}
|
|
|
|
|
|
// If the user-specified callout routine returned with
|
|
// an unsuccessful status, quit.
|
|
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // for ( ; peripheralNum < maxPeripheralNum ...
|
|
|
|
IoQueryDeviceControllerLoop:
|
|
|
|
|
|
// Free the pool allocated for the controller value data.
|
|
|
|
|
|
if (controllerValueInfo[0]) {
|
|
ExFreePool( controllerValueInfo[0] );
|
|
controllerValueInfo[0] = NULL;
|
|
}
|
|
if (controllerValueInfo[1]) {
|
|
ExFreePool( controllerValueInfo[1] );
|
|
controllerValueInfo[1] = NULL;
|
|
}
|
|
if (controllerValueInfo[2]) {
|
|
ExFreePool( controllerValueInfo[2] );
|
|
controllerValueInfo[2] = NULL;
|
|
}
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
} // for ( ; controllerNum < maxControllerNum...
|
|
|
|
|
|
return( status );
|
|
}
|
|
|