Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1020 lines
33 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
internal.c
Abstract:
This module contains the internal subroutines used by the kernel-mode
Plug and Play Manager.
Author:
Lonny McMichael (lonnym) 02/15/95
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Not included in normal builds for now
//
#ifdef _PNP_POWER_
//
// Define the context structure for the PiFindServiceInstance
// callback routine.
//
typedef struct _PI_FIND_SERVICE_INSTANCE_CONTEXT {
PUNICODE_STRING DeviceInstancePath;
BOOLEAN DeviceFound;
} PI_FIND_SERVICE_INSTANCE_CONTEXT, *PPI_FIND_SERVICE_INSTANCE_CONTEXT;
//
// Define utility functions internal to this file.
//
BOOLEAN
PiFindServiceInstance(
IN HANDLE DeviceInstanceHandle,
IN PUNICODE_STRING DeviceInstancePath,
IN OUT PVOID Context
);
#endif // _PNP_POWER_
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, PiRegSzToString)
#if _PNP_POWER_
#pragma alloc_text(PAGE, PiBusEnumeratorFromRegistryPath)
#pragma alloc_text(PAGE, PiGetInstalledBusInformation)
#pragma alloc_text(PAGE, PiGenerateDeviceInstanceIdentifier)
#pragma alloc_text(PAGE, PiGetDeviceObjectFilePointer)
#pragma alloc_text(PAGE, PiGetOrSetDeviceInstanceStatus)
#pragma alloc_text(PAGE, PiFindServiceInstance)
#pragma alloc_text(PAGE, PiFindBusInstanceNode)
#if 0 // obsolete API
#pragma alloc_text(PAGE, PiGetDeviceInstanceIdentifier)
#endif // obsolete API
#endif // _PNP_POWER_
#endif
BOOLEAN
PiRegSzToString(
IN PWCHAR RegSzData,
IN ULONG RegSzLength,
OUT PULONG StringLength OPTIONAL,
OUT PWSTR *CopiedString OPTIONAL
)
/*++
Routine Description:
This routine takes as input a REG_SZ data buffer (as returned in the DataOffset area
of the buffer in a KEY_VALUE_FULL_INFORMATION structure), as well as the length
of the buffer, in bytes (as specified by the DataLength field in the above mentioned
struct). It optionally returns the length of the contained string (in bytes), not
including the terminating NULL, as well as an optional copy of the string itself
(properly NULL-terminated).
It is the responsibility of the caller to free the (PagedPool) buffer allocated
for the string copy.
Arguments:
RegSzData - Supplies a pointer to the REG_SZ data buffer.
RegSzLength - Supplies the length of the RegSzData buffer, in bytes.
StringLength - Optionally supplies a pointer to a variable that will receive
the length, in bytes, of the string (excluding terminating NULL).
CopiedString - Optionally supplies a pointer to a wide character pointer that
will recieve a (properly NULL-terminated) copy of the specified
string. If this paramater is NULL, no copy will be made.
Return Value:
If success, returns TRUE
If failure (not able to allocate memory for string copy), returns FALSE
--*/
{
ULONG i, RegSzNumChars = CB_TO_CWC(RegSzLength);
//
// Find the end of the string.
//
for(i = 0; ((i < RegSzNumChars) && RegSzData[i]); i++);
if(ARGUMENT_PRESENT(StringLength)) {
*StringLength = CWC_TO_CB(i);
}
if(ARGUMENT_PRESENT(CopiedString)) {
//
// Allocate memory for the string (+ terminating NULL)
//
if(!(*CopiedString = (PWSTR)ExAllocatePool(PagedPool, CWC_TO_CB(i + 1)))) {
return FALSE;
}
//
// Copy the string and NULL-terminate it.
//
if(i) {
RtlMoveMemory(*CopiedString, RegSzData, CWC_TO_CB(i));
}
(*CopiedString)[i] = UNICODE_NULL;
}
return TRUE;
}
#if _PNP_POWER_
PPLUGPLAY_BUS_ENUMERATOR
PiBusEnumeratorFromRegistryPath(
IN PUNICODE_STRING ServiceRegistryPath
)
/*++
Routine Description:
This routine takes as input a unicode string representing a registry
path to a service entry. Alternately, this string may simply include
the service key name by itself. In the former case, the last
component of the path is extracted from the string, and is assumed
to be a service key name.
The bus enumerator list is searched for a node matching this service
key. If found, a pointer to that node is returned.
NOTE: The caller of this routine must have acquired the PnP bus
enumerator list resource for shared (read) access.
Arguments:
ServiceRegistryPath - Supplies either the full registry path to a
service key, or the service key by itself. If
a full path is supplied, the last component
of the path is extracted, and assumed to be
the service key name.
Return Value:
If success, returns a pointer to the matching bus enumerator node.
If failure, returns NULL.
--*/
{
ULONG ServiceNameLength = 0;
PWCHAR ServiceNameStart;
UNICODE_STRING TempUnicodeString;
PLIST_ENTRY CurrentListEntry;
PPLUGPLAY_BUS_ENUMERATOR CurrentNode;
//
// Extract last component from the path
//
ServiceNameStart = ServiceRegistryPath->Buffer +
CB_TO_CWC(ServiceRegistryPath->Length) - 1;
if(*ServiceNameStart == OBJ_NAME_PATH_SEPARATOR) {
ServiceNameStart--;
}
while(ServiceNameStart >= ServiceRegistryPath->Buffer) {
if(*ServiceNameStart == OBJ_NAME_PATH_SEPARATOR) {
ServiceNameStart++;
break;
} else {
ServiceNameLength += sizeof(WCHAR);
ServiceNameStart--;
}
}
if(ServiceNameStart < ServiceRegistryPath->Buffer) {
ServiceNameStart++;
}
TempUnicodeString.Length = TempUnicodeString.MaximumLength
= (USHORT)ServiceNameLength;
TempUnicodeString.Buffer = ServiceNameStart;
//
// Now traverse the bus enumerator list, looking for a matching service name.
//
for(CurrentListEntry = PpBusListHead.Flink;
CurrentListEntry != &PpBusListHead;
CurrentListEntry = CurrentListEntry->Flink) {
CurrentNode = CONTAINING_RECORD(CurrentListEntry,
PLUGPLAY_BUS_ENUMERATOR,
BusEnumeratorListEntry
);
if(RtlEqualUnicodeString(&TempUnicodeString,
&(CurrentNode->ServiceName),
TRUE
)) {
//
// Found a match.
//
return CurrentNode;
}
}
return NULL;
}
NTSTATUS
PiGetInstalledBusInformation(
OUT PHAL_BUS_INFORMATION *BusInformation,
OUT PULONG BusCount
)
/*++
Routine Description:
This routine returns an array of all bus instances for which a bus handler
has been registered (as retrieved by calling HalQuerySystemInformation for
information class HalInstalledBusInformation). The routine allocates the
necessary buffer to contain this array, and returns it, along with a count
of the number of buses installed.
It is the caller's responsibility to free the (PagedPool) buffer allocated
by this routine.
Arguments:
BusInformation - Receives the list of bus instances.
BusCount - Receives the number of installed buses returned in the BusInformation
buffer.
Return Value:
NT status code indicating whether the function was successful.
--*/
{
NTSTATUS Status;
PHAL_BUS_INFORMATION BusInfoBuffer = NULL;
ULONG BufferLength = 0, RequiredLength;
do {
if(BufferLength) {
if(!(BusInfoBuffer = ExAllocatePool(PagedPool, BufferLength))) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
Status = HalQuerySystemInformation(HalInstalledBusInformation,
BufferLength,
BusInfoBuffer,
&RequiredLength
);
if(!NT_SUCCESS(Status)) {
if(BufferLength) {
ExFreePool(BusInfoBuffer);
}
if(Status == STATUS_BUFFER_TOO_SMALL) {
BufferLength = RequiredLength;
} else {
return Status;
}
}
} while(Status == STATUS_BUFFER_TOO_SMALL);
if(BufferLength) {
*BusInformation = BusInfoBuffer;
} else {
*BusInformation = NULL;
}
*BusCount = RequiredLength / sizeof(HAL_BUS_INFORMATION);
return STATUS_SUCCESS;
}
#if 0 // obsolete API
NTSTATUS
PiGetDeviceInstanceIdentifier(
IN PUNICODE_STRING ServiceKeyName,
IN ULONG InstanceNumber,
IN ULONG HwProfileId,
OUT PWCHAR InstanceIdString,
IN ULONG InstanceIdStringLength,
OUT PULONG ResultLength
)
/*++
Routine Description:
This routine takes as input a service name, and an instance ordinal
indicating a particular device in the service's volatile Enum list. It
returns a unique string identifying this device instance for the
specified hardware profile that is guaranteed to not change.
This string may be used by the driver to segregate instance-specific
configuration information under it's service entry's Parameters subkey.
NOTE: The driver should not try to interpret this string as anything other
than a unique 'cookie' it can use to identify a device instance.
Since this call may have the side-effect of writing out a newly-generated
instance identifier value entry to the registry, the caller of this routine
must have acquired the Plug & Play device registry resource for exclusive
(write) access before calling this routine.
Parameters:
ServiceKeyName - Supplies the name of the subkey in the system service
list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services) that caused
the driver to load. This is the RegistryPath parameter to the
DriverEntry routine.
InstanceNumber - Supplies an ordinal value indicating the device instance
to retrieve the unique identifier for.
HwProfileId - Supplies the hardware profile configuration ID for which
the unique identifier should be retrieved. The identifier string
is hardware profile-specific, because a driver must be able to
configure its device differently depending on the hardware profile
currently in use. (E.g., a netcard configured for thick-ethernet
in one hardware profile, and thin-ethernet in another)
InstanceIdString - Supplies a pointer to a character buffer that will receive
the string uniquely identifying the device instance associated with this
instance ordinal (for the specified hardware profile).
InstanceIdStringLength - Supplies the length, in bytes, of the InstanceIdString
buffer.
ResultLength - Receives the length of the identifying string, in bytes, not
including the NULL terminator.
Return Value:
Status code that indicates whether or not the function was successful.
--*/
{
NTSTATUS Status;
HANDLE EnumDevInstHandle;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
UNICODE_STRING DevInstUnicodeString, InstanceIdentifier, TempUnicodeString;
BOOLEAN GenerateID;
//
// Retrieve the device instance path associated with the specified service
// instance ordinal, as well as an opened handle to the device instance
// registry key.
//
Status = IopServiceInstanceToDeviceInstance(NULL,
ServiceKeyName,
InstanceNumber,
&DevInstUnicodeString,
&EnumDevInstHandle,
KEY_ALL_ACCESS
);
if(!NT_SUCCESS(Status)) {
return Status;
}
//
// See if there is already an identifier string recorded for this
// device instance, and if so, use it.
//
GenerateID = TRUE;
Status = IopGetRegistryValue(EnumDevInstHandle,
REGSTR_VALUE_INSTANCEIDENTIFIER,
&KeyValueInformation
);
if(NT_SUCCESS(Status)) {
if(KeyValueInformation->Type == REG_SZ) {
IopRegistryDataToUnicodeString(&InstanceIdentifier,
(PWCHAR)KEY_VALUE_DATA(KeyValueInformation),
KeyValueInformation->DataLength
);
} else {
InstanceIdentifier.Length = 0;
}
if(InstanceIdentifier.Length) {
GenerateID = FALSE;
} else {
ExFreePool(KeyValueInformation);
}
}
if(GenerateID) {
Status = PiGenerateDeviceInstanceIdentifier(&DevInstUnicodeString,
&InstanceIdentifier
);
if(!NT_SUCCESS(Status)) {
goto PrepareForReturn0;
}
//
// Store the generated instance identifier in the device instance subkey.
// (Ignore return status--we have what we want.)
//
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_VALUE_INSTANCEIDENTIFIER);
ZwSetValueKey(EnumDevInstHandle,
&TempUnicodeString,
TITLE_INDEX_VALUE,
REG_SZ,
InstanceIdentifier.Buffer,
InstanceIdentifier.MaximumLength
);
}
//
// We now have the unique device instance identifier. To make it specific
// to the specified hardware profile, we will now prepend the hardware
// profile configuration ID (base-10, 4 digits).
//
*ResultLength = InstanceIdentifier.Length + (4 * sizeof(WCHAR));
if(InstanceIdStringLength < *ResultLength + sizeof(UNICODE_NULL)) {
Status = STATUS_BUFFER_TOO_SMALL;
goto PrepareForReturn1;
}
swprintf(InstanceIdString, REGSTR_KEY_INSTANCE_KEY_FORMAT, HwProfileId);
RtlMoveMemory(&(InstanceIdString[4]),
InstanceIdentifier.Buffer,
InstanceIdentifier.Length
);
InstanceIdString[CB_TO_CWC(*ResultLength)] = UNICODE_NULL;
PrepareForReturn1:
if(GenerateID) {
ExFreePool(InstanceIdentifier.Buffer);
} else {
ExFreePool(KeyValueInformation);
}
PrepareForReturn0:
ZwClose(EnumDevInstHandle);
ExFreePool(DevInstUnicodeString.Buffer);
return Status;
}
#endif // obsolete API
NTSTATUS
PiGenerateDeviceInstanceIdentifier(
IN PUNICODE_STRING DeviceInstanceRegistryPath,
OUT PUNICODE_STRING DeviceInstanceIdString
)
/*++
Routine Description:
This routine takes as input a registry path to a device instance
(relative to HKLM\System\Enum), and returns a string that uniquely
identifies this device instance. The current algorithm simply replaces
every occurrence of a backslash ('\') with an ampersand ('&'), however,
this may change in the future, therefore the resulting string should not
be interpreted as anything but a unique 'cookie'.
It is the caller's responsibility to free the (PagedPool) memory allocated
for the unicode string buffer.
Parameters:
DeviceInstanceRegistryPath - Supplies the path in the registry (relative to
HKLM\System\Enum) to the device instance for which to generate the
identifier.
DeviceInstanceIdString - Receives a unicode string that uniquely identifies
the specified device instance. The unicode string is guaranteed to be
NULL-terminated. Note that this string is not specific to a particular
hardware profile, and must be combined with a hardware profile configuration
ID before it may be used by a driver to store hardware-profile-specific
configuration parameters for a device instance.
Return Value:
Status code that indicates whether or not the function was successful.
--*/
{
NTSTATUS Status;
ULONG StringLength = DeviceInstanceRegistryPath->Length, i;
WCHAR CurrentChar;
if(DeviceInstanceIdString->Buffer = ExAllocatePool(PagedPool,
StringLength + sizeof(WCHAR))) {
DeviceInstanceIdString->Length = (USHORT)StringLength;
DeviceInstanceIdString->MaximumLength = (USHORT)StringLength + sizeof(WCHAR);
StringLength = CB_TO_CWC(StringLength); // need count of chars now.
for(i = 0; i < StringLength; i++) {
if((CurrentChar = DeviceInstanceRegistryPath->Buffer[i]) != OBJ_NAME_PATH_SEPARATOR) {
DeviceInstanceIdString->Buffer[i] = CurrentChar;
} else {
DeviceInstanceIdString->Buffer[i] = L'&';
}
}
DeviceInstanceIdString->Buffer[i] = UNICODE_NULL;
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
NTSTATUS
PiGetDeviceObjectFilePointer(
IN PUNICODE_STRING ObjectName,
OUT PFILE_OBJECT *DeviceFileObject
)
/*++
Routine Description:
This routine returns a pointer to a referenced file object that has been
opened to the specified device.
To close access to the device, the caller should dereference the file
object pointer.
Arguments:
ObjectName - Name of the device object for which a file object pointer is
to be returned.
DeviceFileObject - Supplies the address of a variable to receive a pointer
to the file object for the device.
Return Value:
NT status code indicating whether the function was successful.
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE FileHandle;
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
//
// Open the device. (We specify the IO_ATTACH_DEVICE_API create option
// flag so that we can open devices that are already opened for exclusive
// access.)
//
InitializeObjectAttributes(&ObjectAttributes,
ObjectName,
0,
NULL,
NULL
);
Status = ZwCreateFile(&FileHandle,
FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatus,
NULL,
0,
0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | IO_ATTACH_DEVICE_API,
NULL,
0
);
if(NT_SUCCESS(Status)) {
//
// We successfully got a file handle to the device, now
// reference the file object.
//
Status = ObReferenceObjectByHandle(FileHandle,
0,
IoFileObjectType,
KernelMode,
DeviceFileObject,
NULL
);
ZwClose(FileHandle);
}
return Status;
}
NTSTATUS
PiGetOrSetDeviceInstanceStatus(
IN PUNICODE_STRING DeviceInstancePath,
IN OUT PDEVICE_STATUS DeviceStatus,
IN BOOLEAN SetRequested
)
/*++
Routine Description:
This routine will either get or set the current device status for the
specified device instance.
Arguments:
DeviceInstancePath - Supplies a pointer to a unicode string specifying the
registry path for the device instance (relative to HKLM\System\Enum).
DeviceStatus - If the status is not to be set (i.e., SetRequested = FALSE),
this variable receives the current status of the device (if no device status
is given in the controlling service's volatile Enum subkey, then
DeviceStatusOK is returned). If the caller specified that the status should
be set, then this variable contains that value that the status will be set to.
SetRequested - Specifies whether the status value is to be set (TRUE), or simply
retrieved (FALSE).
Return Value:
NT status code indicating whether the function was successful. Common return
codes include:
STATUS_PLUGPLAY_NO_DEVICE - the device has not yet been installed, hence
has no status (it isn't yet linked to a service entry)
--*/
{
NTSTATUS Status;
HANDLE EnumHandle, DeviceInstanceHandle, ServiceKeyHandle;
PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
UNICODE_STRING TempUnicodeString;
PI_FIND_SERVICE_INSTANCE_CONTEXT FindServiceInstanceContext;
ULONG ServiceInstanceOrdinal, DwordValue;
WCHAR UnicodeBuffer[20];
//
// First, open HKLM\System\CurrentControlSet\Enum
//
Status = IopOpenRegistryKey(&EnumHandle,
NULL,
&CmRegistryMachineSystemCurrentControlSetEnumName,
KEY_READ,
FALSE
);
if(!NT_SUCCESS(Status)) {
return Status;
}
//
// Now open up the device instance key under HKLM\System\Enum.
//
Status = IopOpenRegistryKey(&DeviceInstanceHandle,
EnumHandle,
DeviceInstancePath,
KEY_READ,
FALSE
);
ZwClose(EnumHandle);
if(!NT_SUCCESS(Status)) {
return Status;
}
//
// Now, retrieve the controlling service for this device instance.
//
Status = IopGetRegistryValue(DeviceInstanceHandle,
REGSTR_VALUE_SERVICE,
&KeyValueInformation
);
ZwClose(DeviceInstanceHandle);
if(NT_SUCCESS(Status)) {
//
// Verify that we really have a service name here.
//
if(KeyValueInformation->Type == REG_SZ) {
IopRegistryDataToUnicodeString(&TempUnicodeString,
(PWCHAR)KEY_VALUE_DATA(KeyValueInformation),
KeyValueInformation->DataLength
);
} else {
TempUnicodeString.Length = 0;
}
if(!TempUnicodeString.Length) {
ExFreePool(KeyValueInformation);
Status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
if(!NT_SUCCESS(Status)) {
return (Status == STATUS_OBJECT_NAME_NOT_FOUND) ? STATUS_PLUGPLAY_NO_DEVICE
: Status;
}
//
// Open the controlling service entry key under HKLM\System\CurrentControlSet\Services.
//
Status = IopOpenServiceEnumKeys(&TempUnicodeString,
KEY_READ,
&ServiceKeyHandle,
NULL,
FALSE
);
ExFreePool(KeyValueInformation);
if(!NT_SUCCESS(Status)) {
return Status;
}
//
// Now, find the specified device instance under the controlling service's volatile
// Enum list.
//
FindServiceInstanceContext.DeviceInstancePath = DeviceInstancePath;
FindServiceInstanceContext.DeviceFound = FALSE;
Status = IopApplyFunctionToServiceInstances(ServiceKeyHandle,
NULL,
0, // no need to open the device instance keys
TRUE,
PiFindServiceInstance,
&FindServiceInstanceContext,
&ServiceInstanceOrdinal
);
if(NT_SUCCESS(Status) && !FindServiceInstanceContext.DeviceFound) {
Status = STATUS_PLUGPLAY_NO_DEVICE;
}
if(NT_SUCCESS(Status)) {
//
// The device instance was found, now open the service's volatile Enum subkey
// and see if there is a status value entry of the form "DeviceStatus<x>", where
// <x> is the device's service instance ordinal.
//
PiWstrToUnicodeString(&TempUnicodeString, REGSTR_KEY_ENUM);
Status = IopOpenRegistryKey(&EnumHandle,
ServiceKeyHandle,
&TempUnicodeString,
(SetRequested ? KEY_ALL_ACCESS : KEY_READ),
FALSE
);
if(NT_SUCCESS(Status)) {
swprintf(UnicodeBuffer, REGSTR_VALUE_DEVICE_STATUS_FORMAT, ServiceInstanceOrdinal);
if(SetRequested) {
RtlInitUnicodeString(&TempUnicodeString, UnicodeBuffer);
DwordValue = (ULONG)(*DeviceStatus);
Status = ZwSetValueKey(EnumHandle,
&TempUnicodeString,
TITLE_INDEX_VALUE,
REG_DWORD,
&DwordValue,
sizeof(DwordValue)
);
} else {
//
// Just retrieve the current device status (if unable to get, use default of
// DeviceStatusOK.
//
Status = IopGetRegistryValue(EnumHandle,
UnicodeBuffer,
&KeyValueInformation
);
if(NT_SUCCESS(Status)) {
if((KeyValueInformation->Type == REG_DWORD) &&
(KeyValueInformation->DataLength >= sizeof(ULONG))) {
*DeviceStatus = *(PDEVICE_STATUS)KEY_VALUE_DATA(KeyValueInformation);
} else {
*DeviceStatus = DeviceStatusOK;
}
ExFreePool(KeyValueInformation);
} else if(Status == STATUS_OBJECT_NAME_NOT_FOUND){
*DeviceStatus = DeviceStatusOK;
Status = STATUS_SUCCESS;
}
}
ZwClose(EnumHandle);
}
}
ZwClose(ServiceKeyHandle);
return Status;
}
BOOLEAN
PiFindServiceInstance(
IN HANDLE DeviceInstanceHandle,
IN PUNICODE_STRING DeviceInstancePath,
IN OUT PVOID Context
)
/*++
Routine Description:
This routine is a callback function for IopApplyFunctionToServiceInstances.
It is called for each device instance key referenced by a service instance
value under the specified service's volatile Enum subkey. The purpose of this
routine is to determine whether the current device instance path matches the
device instance being searched for (as specified in the context structure),
and if so, to set the 'DeviceFound' flag in the context structure, and abort
enumeration.
NOTE: The PnP device-specific registry resource must be acquired for shared
(read) access before invoking this routine.
Arguments:
DeviceInstanceHandle - Unused
DeviceInstancePath - Supplies the registry path (relative to HKLM\System\Enum)
to this device instance.
Context - Supplies a pointer to a PI_FIND_SERVICE_INSTANCE_CONTEXT structure with
the following fields:
PUNICODE_STRING DeviceInstancePath - Supplies a pointer to a unicode string
specifying the device instance being searched for.
BOOLEAN DeviceFound - If the current device instance matches the one being
searched for, then this flag is set to TRUE, and enumeration is aborted
(by returning FALSE).
Return Value:
TRUE to continue the enumeration.
FALSE to abort it. Enumeration should be aborted when the matching device instance
is encountered.
--*/
{
UNREFERENCED_PARAMETER(DeviceInstanceHandle);
//
// See if this device instance is the one we're looking for.
//
if(RtlEqualUnicodeString(DeviceInstancePath,
((PPI_FIND_SERVICE_INSTANCE_CONTEXT)Context)->DeviceInstancePath,
TRUE)) {
((PPI_FIND_SERVICE_INSTANCE_CONTEXT)Context)->DeviceFound = TRUE;
return FALSE;
} else {
return TRUE;
}
}
NTSTATUS
PiFindBusInstanceNode(
IN PPLUGPLAY_BUS_INSTANCE BusInstance OPTIONAL,
IN PUNICODE_STRING BusDeviceInstanceName OPTIONAL,
OUT PPLUGPLAY_BUS_ENUMERATOR *BusEnumeratorNode OPTIONAL,
OUT PPLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR *BusInstanceNode OPTIONAL
)
/*++
Routine Description:
This routine finds the bus instance node in our global bus list that
matches either the BusInstance structure, or the BusDeviceInstanceName
string, whichever was specified. (If both parameters are specified, the
BusInstance parameter is used, and BusDeviceInstanceName is ignored.)
The caller must have acquired the Plug & Play bus list resource for
(at least) shared (read) access.
Arguments:
BusInstance - Optionally, supplies a pointer to a bus instance structure for
which the corresponding bus instance node is to be retrieved. If this parameter
is not specified, then BusDeviceInstanceName will be used instead. (NOTE: the
BusName parameter in this structure is ignoring for the purposes of finding a
match.)
BusDeviceInstanceName - Optionally, supplies the device instance name for which the
corresponding bus instance node is to be retrieved. This provides an alternate
means of identifying the desired bus instance node (used only if BusInstance
is not specified).
BusEnumeratorNode - Optionally, receives a pointer to the bus enumerator node for this
bus instance, if found.
BusInstanceNode - Optionally, receives a pointer to the matching bus instance node,
if found.
Return Value:
NT status indicating whether or not the function succeeded.
If the specified bus instance is not found, then STATUS_NO_SUCH_DEVICE
is returned.
--*/
{
PLIST_ENTRY CurrentPnPBusListEntry, CurrentPnPBusInstance;
PPLUGPLAY_BUS_ENUMERATOR CurBusEnumerator;
PPLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR CurBusInstNode;
BOOLEAN Found;
//
// Make sure at least one of the search parameters is specified.
//
if(!(ARGUMENT_PRESENT(BusInstance) || ARGUMENT_PRESENT(BusDeviceInstanceName))) {
return STATUS_INVALID_PARAMETER;
}
Found = FALSE;
for(CurrentPnPBusListEntry = PpBusListHead.Flink;
CurrentPnPBusListEntry != &PpBusListHead;
CurrentPnPBusListEntry = CurrentPnPBusListEntry->Flink) {
CurBusEnumerator = CONTAINING_RECORD(CurrentPnPBusListEntry,
PLUGPLAY_BUS_ENUMERATOR,
BusEnumeratorListEntry
);
for(CurrentPnPBusInstance = CurBusEnumerator->BusInstanceListEntry.Flink;
CurrentPnPBusInstance != &(CurBusEnumerator->BusInstanceListEntry);
CurrentPnPBusInstance = CurrentPnPBusInstance->Flink ) {
CurBusInstNode = CONTAINING_RECORD(CurrentPnPBusInstance,
PLUGPLAY_BUS_INSTANCE_FULL_DESCRIPTOR,
BusInstanceListEntry
);
if(ARGUMENT_PRESENT(BusInstance)) {
//
// Compare based on the supplied BusInstance structure.
//
if((CurBusInstNode->BusInstanceInformation.BusNumber == BusInstance->BusNumber) &&
(sizeof(PLUGPLAY_BUS_TYPE) == RtlCompareMemory(
&(CurBusInstNode->BusInstanceInformation.BusType),
&(BusInstance->BusType),
sizeof(PLUGPLAY_BUS_TYPE)
))) {
Found = TRUE;
}
} else {
//
// Compare based on the supplied device instance name
//
if(RtlEqualUnicodeString(BusDeviceInstanceName,
&(CurBusInstNode->DeviceInstancePath),
TRUE)) {
Found = TRUE;
}
}
if(Found) {
if(ARGUMENT_PRESENT(BusEnumeratorNode)) {
*BusEnumeratorNode = CurBusEnumerator;
}
if(ARGUMENT_PRESENT(BusInstanceNode)) {
*BusInstanceNode = CurBusInstNode;
}
return STATUS_SUCCESS;
}
}
}
return STATUS_NO_SUCH_DEVICE;
}
#endif // _PNP_POWER_