- Implementation of IoQueryDeviceDescription. Patch by Alex Ionescu.

svn path=/trunk/; revision=9563
This commit is contained in:
Filip Navara 2004-05-30 18:30:03 +00:00
parent 9c2056bb25
commit c5cd2328e8

View file

@ -16,12 +16,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: resource.c,v 1.14 2003/12/14 17:44:02 hbirr Exp $
/* $Id: resource.c,v 1.15 2004/05/30 18:30:03 navaraf Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/io/resource.c
* PURPOSE: Hardware resource managment
* PROGRAMMER: David Welch (welch@mcmail.com)
* Alex Ionescu (alex@relsoft.net)
* UPDATE HISTORY:
* Created 22/05/98
*/
@ -30,8 +31,6 @@
#include <ddk/ntddk.h>
#include <rosrtl/string.h>
#include <internal/debug.h>
/* GLOBALS *******************************************************************/
@ -39,7 +38,633 @@
static CONFIGURATION_INFORMATION
SystemConfigurationInformation = {0, 0, 0, 0, 0, 0, 0, FALSE, FALSE};
/* FUNCTIONS *****************************************************************/
/* API Parameters to Pass in IopQueryBusDescription */
typedef struct IO_QUERY {
PINTERFACE_TYPE BusType;
PULONG BusNumber;
PCONFIGURATION_TYPE ControllerType;
PULONG ControllerNumber;
PCONFIGURATION_TYPE PeripheralType;
PULONG PeripheralNumber;
PIO_QUERY_DEVICE_ROUTINE CalloutRoutine;
PVOID Context;
} IO_QUERY, *PIO_QUERY;
PWSTR ArcTypes[42] = {
L"System",
L"CentralProcessor",
L"FloatingPointProcessor",
L"PrimaryICache",
L"PrimaryDCache",
L"SecondaryICache",
L"SecondaryDCache",
L"SecondaryCache",
L"EisaAdapter",
L"TcAdapter",
L"ScsiAdapter",
L"DtiAdapter",
L"MultifunctionAdapter",
L"DiskController",
L"TapeController",
L"CdRomController",
L"WormController",
L"SerialController",
L"NetworkController",
L"DisplayController",
L"ParallelController",
L"PointerController",
L"KeyboardController",
L"AudioController",
L"OtherController",
L"DiskPeripheral",
L"FloppyDiskPeripheral",
L"TapePeripheral",
L"ModemPeripheral",
L"MonitorPeripheral",
L"PrinterPeripheral",
L"PointerPeripheral",
L"KeyboardPeripheral",
L"TerminalPeripheral",
L"OtherPeripheral",
L"LinePeripheral",
L"NetworkPeripheral",
L"SystemMemory",
L"DockingInformation",
L"RealModeIrqRoutingTable",
L"RealModePCIEnumeration",
L"Undefined"
};
#define TAG_IO_RESOURCE TAG('R', 'S', 'R', 'C')
/* PRIVATE FUNCTIONS **********************************************************/
/*
* IopQueryDeviceDescription
*
* FUNCTION:
* Reads and returns Hardware information from the appropriate hardware
* registry key. Helper sub of IopQueryBusDescription.
*
* ARGUMENTS:
* Query - What the parent function wants.
* RootKey - Which key to look in
* RootKeyHandle - Handle to the key
* Bus - Bus Number.
* BusInformation - The Configuration Information Sent
*
* RETURNS:
* Status
*/
NTSTATUS STDCALL
IopQueryDeviceDescription(
PIO_QUERY Query,
UNICODE_STRING RootKey,
HANDLE RootKeyHandle,
ULONG Bus,
PKEY_VALUE_FULL_INFORMATION *BusInformation)
{
NTSTATUS Status;
/* Controller Stuff */
UNICODE_STRING ControllerString;
UNICODE_STRING ControllerRootRegName = RootKey;
UNICODE_STRING ControllerRegName;
HANDLE ControllerKeyHandle;
PKEY_FULL_INFORMATION ControllerFullInformation;
PKEY_VALUE_FULL_INFORMATION ControllerInformation[3] = {NULL, NULL, NULL};
ULONG ControllerNumber;
ULONG ControllerLoop;
ULONG MaximumControllerNumber;
/* Peripheral Stuff */
UNICODE_STRING PeripheralString;
HANDLE PeripheralKeyHandle;
PKEY_FULL_INFORMATION PeripheralFullInformation;
PKEY_VALUE_FULL_INFORMATION PeripheralInformation[3] = {NULL, NULL, NULL};
ULONG PeripheralNumber;
ULONG PeripheralLoop;
ULONG MaximumPeripheralNumber;
/* Global Registry Stuff */
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG LenFullInformation;
ULONG LenKeyFullInformation;
UNICODE_STRING TempString;
WCHAR TempBuffer[14];
PWSTR Strings[3] = {
L"Identifier",
L"Configuration Data",
L"Component Information"
};
/* Temporary String */
TempString.MaximumLength = sizeof(TempBuffer);
TempString.Length = 0;
TempString.Buffer = TempBuffer;
/* Add Controller Name to String */
RtlAppendUnicodeToString(&ControllerRootRegName, L"\\");
RtlAppendUnicodeToString(&ControllerRootRegName, ArcTypes[*Query->ControllerType]);
/* Set the Controller Number if specified */
if (Query->ControllerNumber && *(Query->ControllerNumber))
{
ControllerNumber = *Query->ControllerNumber;
MaximumControllerNumber = ControllerNumber + 1;
} else {
/* Find out how many Controller Numbers there are */
InitializeObjectAttributes(
&ObjectAttributes,
&ControllerRootRegName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&ControllerKeyHandle, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
/* How much buffer space */
ZwQueryKey(ControllerKeyHandle, KeyFullInformation, NULL, 0, &LenFullInformation);
/* Allocate it */
ControllerFullInformation = ExAllocatePoolWithTag(PagedPool, LenFullInformation, TAG_IO_RESOURCE);
/* Get the Information */
Status = ZwQueryKey(ControllerKeyHandle, KeyFullInformation, ControllerFullInformation, LenFullInformation, &LenFullInformation);
ZwClose(ControllerKeyHandle);
ControllerKeyHandle = NULL;
}
/* No controller was found, go back to function. */
if (!NT_SUCCESS(Status))
{
if (ControllerFullInformation != NULL)
ExFreePool(ControllerFullInformation);
return Status;
}
/* Find out Controller Numbers */
ControllerNumber = 0;
MaximumControllerNumber = ControllerFullInformation->SubKeys;
/* Free Memory */
ExFreePool(ControllerFullInformation);
ControllerFullInformation = NULL;
}
/* Save String */
ControllerRegName = ControllerRootRegName;
/* Loop through controllers */
for (; ControllerNumber < MaximumControllerNumber; ControllerNumber++)
{
/* Load String */
ControllerRootRegName = ControllerRegName;
/* Controller Number to Registry String */
Status = RtlIntegerToUnicodeString(ControllerNumber, 10, &TempString);
/* Create String */
Status |= RtlAppendUnicodeToString(&ControllerRootRegName, L"\\");
Status |= RtlAppendUnicodeStringToString(&ControllerRootRegName, &TempString);
/* Something messed up */
if (!NT_SUCCESS(Status)) break;
/* Open the Registry Key */
InitializeObjectAttributes(
&ObjectAttributes,
&ControllerRootRegName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&ControllerKeyHandle, KEY_READ, &ObjectAttributes);
/* Read the Configuration Data... */
if (NT_SUCCESS(Status))
{
for (ControllerLoop = 0; ControllerLoop < 3; ControllerLoop++)
{
/* Identifier String First */
RtlInitUnicodeString(&ControllerString, Strings[ControllerLoop]);
/* How much buffer space */
ZwQueryValueKey(ControllerKeyHandle, &ControllerString, KeyValueFullInformation, NULL, 0, &LenKeyFullInformation);
/* Allocate it */
ControllerInformation[ControllerLoop] = ExAllocatePoolWithTag(PagedPool, LenKeyFullInformation, TAG_IO_RESOURCE);
/* Get the Information */
Status = ZwQueryValueKey(ControllerKeyHandle, &ControllerString, KeyValueFullInformation, ControllerInformation[ControllerLoop], LenKeyFullInformation, &LenKeyFullInformation);
}
/* Clean Up */
ZwClose(ControllerKeyHandle);
ControllerKeyHandle = NULL;
}
/* Something messed up */
if (!NT_SUCCESS(Status))
goto EndLoop;
/* We now have Bus *AND* Controller Information.. is it enough? */
if (!(*Query->PeripheralType))
{
Status = Query->CalloutRoutine(
Query->Context,
&ControllerRootRegName,
*Query->BusType,
Bus,
BusInformation,
*Query->ControllerType,
ControllerNumber,
ControllerInformation,
0,
0,
NULL);
goto EndLoop;
}
/* Not enough...caller also wants peripheral name */
Status = RtlAppendUnicodeToString(&ControllerRootRegName, L"\\");
Status |= RtlAppendUnicodeToString(&ControllerRootRegName, ArcTypes[*Query->PeripheralType]);
/* Something messed up */
if (!NT_SUCCESS(Status)) goto EndLoop;
/* Set the Peripheral Number if specified */
if (Query->PeripheralNumber && *Query->PeripheralNumber)
{
PeripheralNumber = *Query->PeripheralNumber;
MaximumPeripheralNumber = PeripheralNumber + 1;
} else {
/* Find out how many Peripheral Numbers there are */
InitializeObjectAttributes(
&ObjectAttributes,
&ControllerRootRegName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&PeripheralKeyHandle, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
/* How much buffer space */
ZwQueryKey(PeripheralKeyHandle, KeyFullInformation, NULL, 0, &LenFullInformation);
/* Allocate it */
PeripheralFullInformation = ExAllocatePoolWithTag(PagedPool, LenFullInformation, TAG_IO_RESOURCE);
/* Get the Information */
Status = ZwQueryKey(PeripheralKeyHandle, KeyFullInformation, PeripheralFullInformation, LenFullInformation, &LenFullInformation);
ZwClose(PeripheralKeyHandle);
PeripheralKeyHandle = NULL;
}
/* No controller was found, go back to function but clean up first */
if (!NT_SUCCESS(Status))
{
Status = STATUS_SUCCESS;
goto EndLoop;
}
/* Find out Peripheral Number */
PeripheralNumber = 0;
MaximumPeripheralNumber = PeripheralFullInformation->SubKeys;
/* Free Memory */
ExFreePool(PeripheralFullInformation);
PeripheralFullInformation = NULL;
}
/* Save Name */
ControllerRegName = ControllerRootRegName;
/* Loop through Peripherals */
for (; PeripheralNumber < MaximumPeripheralNumber; PeripheralNumber++)
{
/* Restore Name */
ControllerRootRegName = ControllerRegName;
/* Peripheral Number to Registry String */
Status = RtlIntegerToUnicodeString(PeripheralNumber, 10, &TempString);
/* Create String */
Status |= RtlAppendUnicodeToString(&ControllerRootRegName, L"\\");
Status |= RtlAppendUnicodeStringToString(&ControllerRootRegName, &TempString);
/* Something messed up */
if (!NT_SUCCESS(Status)) break;
/* Open the Registry Key */
InitializeObjectAttributes(
&ObjectAttributes,
&ControllerRootRegName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&PeripheralKeyHandle, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
for (PeripheralLoop = 0; PeripheralLoop < 3; PeripheralLoop++)
{
/* Identifier String First */
RtlInitUnicodeString(&PeripheralString, Strings[PeripheralLoop]);
/* How much buffer space */
ZwQueryValueKey(PeripheralKeyHandle, &PeripheralString, KeyValueFullInformation, NULL, 0, &LenKeyFullInformation);
/* Allocate it */
PeripheralInformation[PeripheralLoop] = ExAllocatePoolWithTag(PagedPool, LenKeyFullInformation, TAG_IO_RESOURCE);
/* Get the Information */
Status = ZwQueryValueKey(PeripheralKeyHandle, &PeripheralString, KeyValueFullInformation, PeripheralInformation[PeripheralLoop], LenKeyFullInformation, &LenKeyFullInformation);
}
/* Clean Up */
ZwClose(PeripheralKeyHandle);
PeripheralKeyHandle = NULL;
/* We now have everything the caller could possibly want */
if (NT_SUCCESS(Status))
{
#if 0
Status = Query->CalloutRoutine(
Query->Context,
&ControllerRootRegName,
*Query->BusType,
Bus,
BusInformation,
*Query->ControllerType,
ControllerNumber,
ControllerInformation,
*Query->PeripheralType,
PeripheralNumber,
PeripheralInformation);
#else
Status = STATUS_SUCCESS;
#endif
}
/* Free the allocated memory */
for (PeripheralLoop = 0; PeripheralLoop < 3; PeripheralLoop++)
{
if (PeripheralInformation[PeripheralLoop])
{
ExFreePool(PeripheralInformation[PeripheralLoop]);
PeripheralInformation[PeripheralLoop] = NULL;
}
}
/* Something Messed up */
if (!NT_SUCCESS(Status)) break;
}
}
EndLoop:
/* Free the allocated memory */
for (ControllerLoop = 0; ControllerLoop < 3; ControllerLoop++)
{
if (ControllerInformation[ControllerLoop])
{
ExFreePool(ControllerInformation[ControllerLoop]);
ControllerInformation[ControllerLoop] = NULL;
}
}
/* Something Messed up */
if (!NT_SUCCESS(Status)) break;
}
return Status;
}
/*
* IopQueryBusDescription
*
* FUNCTION:
* Reads and returns Hardware information from the appropriate hardware
* registry key. Helper sub of IoQueryDeviceDescription. Has two modes
* of operation, either looking for Root Bus Types or for sub-Bus
* information.
*
* ARGUMENTS:
* Query - What the parent function wants.
* RootKey - Which key to look in
* RootKeyHandle - Handle to the key
* Bus - Bus Number.
* KeyIsRoot - Whether we are looking for Root Bus Types or
* information under them.
*
* RETURNS:
* Status
*/
NTSTATUS STDCALL
IopQueryBusDescription(
PIO_QUERY Query,
UNICODE_STRING RootKey,
HANDLE RootKeyHandle,
PULONG Bus,
BOOLEAN KeyIsRoot)
{
NTSTATUS Status;
ULONG BusLoop;
UNICODE_STRING SubRootRegName;
UNICODE_STRING BusString;
UNICODE_STRING SubBusString;
ULONG LenBasicInformation;
ULONG LenFullInformation;
ULONG LenKeyFullInformation;
ULONG LenKey;
HANDLE SubRootKeyHandle;
PKEY_FULL_INFORMATION FullInformation;
PKEY_BASIC_INFORMATION BasicInformation;
OBJECT_ATTRIBUTES ObjectAttributes;
PKEY_VALUE_FULL_INFORMATION BusInformation[3] = {NULL, NULL, NULL};
/* How much buffer space */
Status = ZwQueryKey(RootKeyHandle, KeyFullInformation, NULL, 0, &LenFullInformation);
if (!NT_SUCCESS(Status))
return Status;
/* Allocate it */
FullInformation = ExAllocatePoolWithTag(PagedPool, LenFullInformation, TAG_IO_RESOURCE);
/* Get the Information */
Status = ZwQueryKey(RootKeyHandle, KeyFullInformation, FullInformation, LenFullInformation, &LenFullInformation);
/* Everything was fine */
if (NT_SUCCESS(Status))
{
/* Buffer needed for all the keys under this one */
LenBasicInformation = FullInformation->MaxNameLen + sizeof(KEY_BASIC_INFORMATION);
/* Allocate it */
BasicInformation = ExAllocatePoolWithTag(PagedPool, LenBasicInformation, TAG_IO_RESOURCE);
}
/* Deallocate the old Buffer */
ExFreePool(FullInformation);
/* Try to find a Bus */
for (BusLoop = 0; NT_SUCCESS(Status); BusLoop++)
{
/* Bus parameter was passed and number was matched */
if ((Query->BusNumber) && (*(Query->BusNumber)) == *Bus) break;
/* Enumerate the Key */
Status = ZwEnumerateKey(
RootKeyHandle,
BusLoop,
KeyBasicInformation,
BasicInformation,
LenBasicInformation,
&LenKey);
/* Everything enumerated */
if (!NT_SUCCESS(Status)) break;
/* What Bus are we going to go down? (only check if this is a Root Key) */
if (KeyIsRoot)
{
if (wcsncmp(BasicInformation->Name, L"MultifunctionAdapter", BasicInformation->NameLength / 2) &&
wcsncmp(BasicInformation->Name, L"EisaAdapter", BasicInformation->NameLength / 2) &&
wcsncmp(BasicInformation->Name, L"TcAdapter", BasicInformation->NameLength / 2))
{
/* Nothing found, check next */
continue;
}
}
/* Enumerate the Bus. */
BusString.Buffer = BasicInformation->Name;
BusString.Length = BasicInformation->NameLength;
BusString.MaximumLength = BasicInformation->NameLength;
/* Open a handle to the Root Registry Key */
InitializeObjectAttributes(
&ObjectAttributes,
&BusString,
OBJ_CASE_INSENSITIVE,
RootKeyHandle,
NULL);
Status = ZwOpenKey(&SubRootKeyHandle, KEY_READ, &ObjectAttributes);
/* Go on if we can't */
if (!NT_SUCCESS(Status)) continue;
/* Key opened. Create the path */
SubRootRegName = RootKey;
RtlAppendUnicodeToString(&SubRootRegName, L"\\");
RtlAppendUnicodeStringToString(&SubRootRegName, &BusString);
if (!KeyIsRoot)
{
/* Parsing a SubBus-key */
int SubBusLoop;
PWSTR Strings[3] = {
L"Identifier",
L"Configuration Data",
L"Component Information"};
for (SubBusLoop = 0; SubBusLoop < 3; SubBusLoop++)
{
/* Identifier String First */
RtlInitUnicodeString(&SubBusString, Strings[SubBusLoop]);
/* How much buffer space */
ZwQueryValueKey(SubRootKeyHandle, &SubBusString, KeyValueFullInformation, NULL, 0, &LenKeyFullInformation);
/* Allocate it */
BusInformation[SubBusLoop] = ExAllocatePoolWithTag(PagedPool, LenKeyFullInformation, TAG_IO_RESOURCE);
/* Get the Information */
Status = ZwQueryValueKey(SubRootKeyHandle, &SubBusString, KeyValueFullInformation, BusInformation[SubBusLoop], LenKeyFullInformation, &LenKeyFullInformation);
}
if (NT_SUCCESS(Status))
{
/* Do we have something */
if (BusInformation[1] != NULL &&
BusInformation[1]->DataLength != 0 &&
/* Does it match what we want? */
(((PCM_FULL_RESOURCE_DESCRIPTOR)((ULONG_PTR)BusInformation[1] + BusInformation[1]->DataOffset))->InterfaceType == *(Query->BusType)))
{
/* Found a bus */
(*Bus)++;
/* Is it the bus we wanted */
if (Query->BusNumber == NULL || *(Query->BusNumber) == *Bus)
{
/* If we don't want Controller Information, we're done... call the callback */
if (Query->ControllerType == NULL)
{
Status = Query->CalloutRoutine(
Query->Context,
&SubRootRegName,
*(Query->BusType),
*Bus,
BusInformation,
0,
0,
NULL,
0,
0,
NULL);
} else {
/* We want Controller Info...get it */
Status = IopQueryDeviceDescription(Query, SubRootRegName, RootKeyHandle, *Bus, (PKEY_VALUE_FULL_INFORMATION*)BusInformation);
}
}
}
}
/* Free the allocated memory */
for (SubBusLoop = 0; SubBusLoop < 3; SubBusLoop++)
{
if (BusInformation[SubBusLoop])
{
ExFreePool(BusInformation[SubBusLoop]);
BusInformation[SubBusLoop] = NULL;
}
}
/* Exit the Loop if we found the bus */
if (Query->BusNumber != NULL && *(Query->BusNumber) == *Bus)
{
ZwClose(SubRootKeyHandle);
SubRootKeyHandle = NULL;
continue;
}
}
/* Enumerate the buses below us recursively if we haven't found the bus yet */
Status = IopQueryBusDescription(Query, SubRootRegName, SubRootKeyHandle, Bus, !KeyIsRoot);
/* Everything enumerated */
if (Status == STATUS_NO_MORE_ENTRIES) Status = STATUS_SUCCESS;
ZwClose(SubRootKeyHandle);
SubRootKeyHandle = NULL;
}
/* Free the last remaining Allocated Memory */
if (BasicInformation)
ExFreePool(BasicInformation);
return Status;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
@ -106,9 +731,25 @@ IoAssignResources(PUNICODE_STRING RegistryPath,
}
/*
* @unimplemented
* FUNCTION:
* Reads and returns Hardware information from the appropriate hardware registry key.
*
* ARGUMENTS:
* BusType - MCA, ISA, EISA...specifies the Bus Type
* BusNumber - Which bus of above should be queried
* ControllerType - Specifices the Controller Type
* ControllerNumber - Which of the controllers to query.
* CalloutRoutine - Which function to call for each valid query.
* Context - Value to pass to the callback.
*
* RETURNS:
* Status
*
* STATUS:
* @implemented
*/
NTSTATUS STDCALL
NTSTATUS NTAPI
IoQueryDeviceDescription(PINTERFACE_TYPE BusType,
PULONG BusNumber,
PCONFIGURATION_TYPE ControllerType,
@ -118,51 +759,51 @@ IoQueryDeviceDescription(PINTERFACE_TYPE BusType,
PIO_QUERY_DEVICE_ROUTINE CalloutRoutine,
PVOID Context)
{
#if 0
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
PWCH BaseKeyName[] =
L"\\Registry\\Machine\\Hardware\\MultifunctionAdapter\\0";
HANDLE BaseKeyHandle;
ULONG i;
struct
{
KEY_BASIC_INFORMATION BasicInfo;
WCH Name[255];
} BasicInfo;
NTSTATUS Status;
ULONG BusLoopNumber = -1; /* Root Bus */
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING RootRegKey;
HANDLE RootRegHandle;
WCHAR RootRegString[] = L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM\\";
IO_QUERY Query;
BaseKeyName = L"\\Registry\\Machine\\Hardware\\MultifunctionAdapter";
InitializeObjectAttributes(&ObjectAttributes,
BaseKeyName,
0,
NULL,
NULL);
Status = ZwOpenKey(&BaseKeyHandle,
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEY,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* Set up the String */
RootRegKey.Length = 0;
RootRegKey.MaximumLength = 2048;
RootRegKey.Buffer = ExAllocatePoolWithTag(PagedPool, RootRegKey.MaximumLength, TAG_IO_RESOURCE);
RtlAppendUnicodeToString(&RootRegKey, RootRegString);
/* Open a handle to the Root Registry Key */
InitializeObjectAttributes(
&ObjectAttributes,
&RootRegKey,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
i = 0;
for (;;)
{
Status = ZwEnumerateKey(BaseKeyHandle,
i,
KeyBasicInformation,
&BasicInfo,
sizeof(BasicInfo),
&ResultLength);
if (!NT_SUCCESS(Status))
{
break;
}
Status = ZwOpenKey(&RootRegHandle, KEY_READ, &ObjectAttributes);
}
#endif
return(STATUS_NOT_IMPLEMENTED);
if (NT_SUCCESS(Status))
{
/* Use a helper function to loop though this key and get the info */
Query.BusType = BusType;
Query.BusNumber = BusNumber;
Query.ControllerType = ControllerType;
Query.ControllerNumber = ControllerNumber;
Query.PeripheralType = PeripheralType;
Query.PeripheralNumber = PeripheralNumber;
Query.CalloutRoutine = CalloutRoutine;
Query.Context = Context;
Status = IopQueryBusDescription(&Query, RootRegKey, RootRegHandle, &BusLoopNumber, TRUE);
/* Close registry */
ZwClose(RootRegHandle);
}
/* Free Memory */
ExFreePool(RootRegKey.Buffer);
return Status;
}
/*