mirror of https://github.com/lianthony/NT4.0
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.
1146 lines
37 KiB
1146 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pnpsubs.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the plug-and-play IO system APIs.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) 3-Jan-1995
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "iop.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, IoQueryDeviceEnumInfo)
|
|
#pragma alloc_text(PAGE, IoOpenDeviceInstanceKey)
|
|
#pragma alloc_text(PAGE, IopQueryDeviceConfiguration)
|
|
#if _PNP_POWER_STUB_ENABLED_
|
|
#pragma alloc_text(PAGE, IoQuerySystemInformation)
|
|
#pragma alloc_text(PAGE, IoGetDeviceProperty)
|
|
#pragma alloc_text(PAGE, IoSetDeviceProperty)
|
|
#pragma alloc_text(PAGE, IoRegisterPlugPlayNotification)
|
|
#pragma alloc_text(PAGE, IoUnregisterPlugPlayNotification)
|
|
#pragma alloc_text(PAGE, IoReportDeviceStatus)
|
|
#endif // _PNP_POWER_STUB_ENABLED_
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
NTSTATUS
|
|
IoQueryDeviceEnumInfo(
|
|
IN PUNICODE_STRING ServiceKeyName,
|
|
OUT PULONG Count
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens ServiceKeyName key and returns the number of device
|
|
instances found at enumeration time to variable Count.
|
|
|
|
Note the device count returned from this function may include disabled
|
|
devices. It is the device driver's responsibility to check each device
|
|
before creating it to ensure that it is not disabled.= (vai the
|
|
DeviceStatus value returned from IoQueryConfiguration and
|
|
IoQueryDeviceConfigurationVector). Disabled devices must be ignored.
|
|
|
|
Parameters:
|
|
|
|
ServiceKeyName - Supplies the name of the subkey in the system service
|
|
list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
|
|
that caused the driver to load.
|
|
|
|
Count - Receives the number of device instances found at enumeration whose
|
|
Enum data indicate that ServiceKeyName is for their device driver.
|
|
A driver can use this as the limit for a loop around calls to
|
|
IoQueryDeviceConfiguration.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE enumHandle;
|
|
ULONG instanceCount = 0;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE);
|
|
|
|
//
|
|
// Open System\CurrentControlSet\Services
|
|
//
|
|
|
|
status = IopOpenServiceEnumKeys (
|
|
ServiceKeyName,
|
|
KEY_READ,
|
|
NULL,
|
|
&enumHandle,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit1;
|
|
}
|
|
|
|
//
|
|
// Read value of Count if present. If it is not present, a value of
|
|
// zero will be returned.
|
|
//
|
|
|
|
status = IopGetRegistryValue(enumHandle, REGSTR_VALUE_COUNT, &keyValueInformation);
|
|
if (NT_SUCCESS(status)) {
|
|
if (keyValueInformation->DataLength != 0) {
|
|
instanceCount = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
} else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
ZwClose(enumHandle);
|
|
|
|
exit1:
|
|
ExReleaseResource(&PpRegistryDeviceResource);
|
|
KeLeaveCriticalRegion();
|
|
*Count = instanceCount;
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
IoOpenDeviceInstanceKey(
|
|
IN PUNICODE_STRING ServiceKeyName,
|
|
IN ULONG InstanceNumber,
|
|
IN ULONG DevInstKeyType,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
OUT PHANDLE DevInstRegKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
THis routine returns a handle to an opened registry key that the driver
|
|
may use to store/retrieve configuration information specific to a particular
|
|
device instance.
|
|
|
|
The driver must call ZwClose to close the handle returned from this api
|
|
when access is no longer required.
|
|
|
|
BUGBUG (lonnym): For SUR, we inform a driver calling IoQueryEnumDeviceInfo of
|
|
_all_ device instances associated with its service entry, not just those devices
|
|
that are currently present and enabled. To keep the driver from creating device
|
|
objects for these 'non-live' devices, we will fail the driver's subsequent call to
|
|
IoOpenDeviceInstanceKey with STATUS_PLUGPLAY_NO_DEVICE for such devices.
|
|
|
|
Parameters:
|
|
|
|
ServiceKeyName - Supplies the name of the subkey in the system service
|
|
list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
|
|
that caused the driver to load.
|
|
|
|
InstanceNumber - Supplies an ordinal value indicating the device instance
|
|
to open a registry storage key for. For enumerated devices,
|
|
this value may be from 0 to n-1, where n is the Count value
|
|
returned from the original call to IoQueryDeviceEnumInfo.
|
|
|
|
DevInstKeyType - Supplies flags specifying which storage key associated with
|
|
the device instance is to be opened. May be a combination of
|
|
the following value:
|
|
|
|
PLUGPLAY_REGKEY_DEVICE - Open a key for storing device specific
|
|
(driver-independent) information relating to the device instance.
|
|
The flag may not be specified with PLUGPLAY_REGKEY_DRIVER.
|
|
|
|
PLUGPLAY_REGKEY_DRIVER - Open a key for storing driver-specific
|
|
information relating to the device instance, This flag may
|
|
not be specified with PLUGPLAY_REGKEY_DEVICE.
|
|
|
|
PLUGPLAY_REGKEY_CURRENT_HWPROFILE - If this flag is specified,
|
|
then a key in the current hardware profile branch will be
|
|
opened for the specified storage type. This allows the driver
|
|
to access configuration information that is hardware profile
|
|
specific.
|
|
|
|
DesiredAccess - Specifies the access mask for the key to be opened.
|
|
|
|
DevInstRegKey - Supplies the address of a variable that receives a handle to the
|
|
opened key for the specified registry storage location.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE classHandle, instanceHandle, handle;
|
|
UNICODE_STRING unicodeKeyName, unicodeString;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
ULONG csConfigFlags;
|
|
|
|
//
|
|
// Make sure the DevInstKeyType argument is valid.
|
|
//
|
|
|
|
if (((DevInstKeyType & PLUGPLAY_REGKEY_DEVICE) &&
|
|
(DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)) ||
|
|
!(DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE + PLUGPLAY_REGKEY_DRIVER)) ) {
|
|
return STATUS_INVALID_PARAMETER_3;
|
|
}
|
|
|
|
unicodeKeyName.Buffer = NULL;
|
|
classHandle = NULL;
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE);
|
|
|
|
//
|
|
// First determine whether this device is present and enabled (otherwise, fail
|
|
// the call now with STATUS_PLUGPLAY_NO_DEVICE).
|
|
//
|
|
status = IopGetDeviceInstanceCsConfigFlags(ServiceKeyName, InstanceNumber, &csConfigFlags);
|
|
|
|
if(NT_SUCCESS(status) &&
|
|
(csConfigFlags & (CSCONFIGFLAG_DISABLED | CSCONFIGFLAG_DO_NOT_CREATE | CSCONFIGFLAG_DO_NOT_START))) {
|
|
//
|
|
// This device is disabled or not present.
|
|
//
|
|
status = STATUS_PLUGPLAY_NO_DEVICE;
|
|
goto exit_Local0;
|
|
}
|
|
|
|
status = IopOpenServiceEnumKeys (
|
|
ServiceKeyName,
|
|
KEY_READ,
|
|
&handle,
|
|
NULL,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local0;
|
|
}
|
|
|
|
//
|
|
// Check if caller wants the global device/driver key or the one specific
|
|
// to hardware profile.
|
|
//
|
|
|
|
if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) {
|
|
|
|
//
|
|
// Get the device instance path form instance number of ServiceName\Enum.
|
|
//
|
|
|
|
status = IopServiceInstanceToDeviceInstance (handle,
|
|
NULL,
|
|
InstanceNumber,
|
|
&unicodeKeyName,
|
|
NULL,
|
|
KEY_READ
|
|
);
|
|
ZwClose(handle);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local0;
|
|
}
|
|
|
|
//
|
|
// Open current hardware profile key
|
|
//
|
|
|
|
status = IopOpenRegistryKey(&classHandle,
|
|
NULL,
|
|
&CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent,
|
|
DesiredAccess,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local1;
|
|
}
|
|
|
|
//
|
|
// Open system\CurrentControlSet under current hardware profile key
|
|
//
|
|
|
|
PiWstrToUnicodeString(&unicodeString, REGSTR_PATH_CURRENTCONTROLSET);
|
|
status = IopOpenRegistryKey(&handle,
|
|
classHandle,
|
|
&unicodeString,
|
|
DesiredAccess,
|
|
FALSE
|
|
);
|
|
ZwClose(classHandle);
|
|
classHandle = NULL;
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local1;
|
|
}
|
|
|
|
//
|
|
// Open the Control\Class key if regkey-driver is specified
|
|
//
|
|
|
|
if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) {
|
|
PiWstrToUnicodeString(&unicodeString, REGSTR_PATH_CONTROL_CLASS);
|
|
status = IopOpenRegistryKey(&classHandle,
|
|
handle,
|
|
&unicodeString,
|
|
DesiredAccess,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
ZwClose(handle);
|
|
goto exit_Local1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open Enum subkey
|
|
//
|
|
|
|
PiWstrToUnicodeString(&unicodeString, REGSTR_KEY_ENUM);
|
|
status = IopOpenRegistryKey(&instanceHandle,
|
|
handle,
|
|
&unicodeString,
|
|
KEY_READ,
|
|
FALSE
|
|
);
|
|
ZwClose(handle);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local2;
|
|
}
|
|
|
|
handle = instanceHandle;
|
|
|
|
//
|
|
// open the device instance path under current hardware profile's Enum key
|
|
//
|
|
|
|
status = IopOpenRegistryKey(&instanceHandle,
|
|
handle,
|
|
&unicodeKeyName,
|
|
DesiredAccess,
|
|
FALSE
|
|
);
|
|
ZwClose(handle);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local2;
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// Open the subkey specified by ServiceName\Enum instance number under
|
|
// System\CurrentControlSet\Enum subtree.
|
|
//
|
|
|
|
status = IopServiceInstanceToDeviceInstance (handle,
|
|
NULL,
|
|
InstanceNumber,
|
|
NULL,
|
|
&instanceHandle,
|
|
KEY_READ
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
ZwClose(handle);
|
|
goto exit_Local0;
|
|
}
|
|
|
|
if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) {
|
|
|
|
//
|
|
// Open global control\class key
|
|
//
|
|
|
|
status = IopOpenRegistryKey(&classHandle,
|
|
NULL,
|
|
&CmRegistryMachineSystemCurrentControlSetControlClass,
|
|
DesiredAccess,
|
|
FALSE
|
|
);
|
|
ZwClose(handle);
|
|
if (!NT_SUCCESS(status)) {
|
|
ZwClose(instanceHandle);
|
|
goto exit_Local0;
|
|
}
|
|
} else {
|
|
ZwClose(handle);
|
|
}
|
|
}
|
|
|
|
if (DevInstKeyType & PLUGPLAY_REGKEY_DEVICE) {
|
|
|
|
//
|
|
// Open the "Device Parameters" subkey under the device instance key.
|
|
//
|
|
|
|
PiWstrToUnicodeString(&unicodeString, REGSTR_KEY_DEVICEPARAMETERS);
|
|
status = IopOpenRegistryKeyPersist(&handle,
|
|
instanceHandle,
|
|
&unicodeString,
|
|
DesiredAccess,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
*DevInstRegKey = handle;
|
|
}
|
|
}
|
|
|
|
if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) {
|
|
|
|
//
|
|
// Open the class GUID key under control\class\
|
|
//
|
|
|
|
status = IopGetRegistryValue(instanceHandle,
|
|
REGSTR_VALUE_DRIVER,
|
|
&keyValueInformation
|
|
);
|
|
if ((status == STATUS_OBJECT_NAME_NOT_FOUND) ||
|
|
(status == STATUS_OBJECT_PATH_NOT_FOUND)) {
|
|
|
|
UNICODE_STRING unicodeName, unicodeInstanceName, unicodeValue;
|
|
HANDLE guidHandle;
|
|
ULONG instance;
|
|
UCHAR unicodeBuffer[20];
|
|
|
|
//
|
|
// The "Driver=" value name and its key have not been created yet. We need
|
|
// to create them before returning the handle to the key.
|
|
//
|
|
|
|
//
|
|
// Create a device instance under CCS\Control\Class\Guid Unknown
|
|
//
|
|
|
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_UNKNOWN_CLASS_GUID);
|
|
status = IopOpenRegistryKeyPersist(&guidHandle,
|
|
classHandle,
|
|
&unicodeName,
|
|
KEY_ALL_ACCESS,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Find the instance number to represent the key name
|
|
//
|
|
|
|
instance = 0;
|
|
while (TRUE) {
|
|
PiUlongToInstanceKeyUnicodeString(&unicodeInstanceName,
|
|
unicodeBuffer + sizeof(WCHAR),
|
|
20 - sizeof(WCHAR),
|
|
instance
|
|
);
|
|
status = IopOpenRegistryKey(&handle,
|
|
guidHandle,
|
|
&unicodeInstanceName,
|
|
KEY_READ,
|
|
FALSE
|
|
);
|
|
if ((status == STATUS_OBJECT_PATH_NOT_FOUND) ||
|
|
(status == STATUS_OBJECT_NAME_NOT_FOUND)) {
|
|
break;
|
|
} else {
|
|
if (NT_SUCCESS(status)) {
|
|
ZwClose(handle);
|
|
}
|
|
instance++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Next open/create the key and initialize "Driver=" value name under
|
|
// current device instance key.
|
|
//
|
|
|
|
status = IopOpenRegistryKeyPersist(&handle,
|
|
guidHandle,
|
|
&unicodeInstanceName,
|
|
KEY_ALL_ACCESS,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
ZwClose(guidHandle);
|
|
if (NT_SUCCESS(status)) {
|
|
*(PWSTR)unicodeBuffer = OBJ_NAME_PATH_SEPARATOR;
|
|
unicodeInstanceName.Buffer = (PWSTR)unicodeBuffer;
|
|
unicodeInstanceName.Length += sizeof(WCHAR);
|
|
unicodeInstanceName.MaximumLength += sizeof(WCHAR);
|
|
IopConcatenateUnicodeStrings(&unicodeValue, &unicodeName, &unicodeInstanceName);
|
|
|
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_DRIVER);
|
|
ZwSetValueKey(instanceHandle,
|
|
&unicodeName,
|
|
TITLE_INDEX_VALUE,
|
|
REG_SZ,
|
|
unicodeValue.Buffer,
|
|
unicodeValue.Length + sizeof(UNICODE_NULL)
|
|
);
|
|
RtlFreeUnicodeString(&unicodeValue);
|
|
*DevInstRegKey = handle;
|
|
}
|
|
}
|
|
} else if (NT_SUCCESS(status)) {
|
|
status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|
if (keyValueInformation->DataLength != 0) {
|
|
if (keyValueInformation->Type == REG_SZ) {
|
|
IopRegistryDataToUnicodeString(&unicodeString,
|
|
(PWSTR)KEY_VALUE_DATA(keyValueInformation),
|
|
keyValueInformation->DataLength
|
|
);
|
|
|
|
//
|
|
// Open the desired registry key
|
|
//
|
|
|
|
status = IopOpenRegistryKey(&handle,
|
|
classHandle,
|
|
&unicodeString,
|
|
DesiredAccess,
|
|
FALSE
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
*DevInstRegKey = handle;
|
|
}
|
|
}
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
}
|
|
|
|
ZwClose(instanceHandle);
|
|
exit_Local2:
|
|
if (classHandle) {
|
|
ZwClose(classHandle);
|
|
}
|
|
exit_Local1:
|
|
if (unicodeKeyName.Buffer) {
|
|
RtlFreeUnicodeString(&unicodeKeyName);
|
|
}
|
|
exit_Local0:
|
|
ExReleaseResource(&PpRegistryDeviceResource);
|
|
KeLeaveCriticalRegion();
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
IopQueryDeviceConfiguration(
|
|
IN PUNICODE_STRING ServiceKeyName,
|
|
IN ULONG InstanceOrdinal,
|
|
OUT PHAL_BUS_INFORMATION BusInfo,
|
|
OUT PULONG DeviceInstanceFlags,
|
|
OUT PCM_RESOURCE_LIST Configuration,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG ActualBufferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads and returns the device hardware information
|
|
specified by ServiceKeyName and InstanceOrdinal.
|
|
|
|
Parameters:
|
|
|
|
|
|
ServiceKeyName - Supplies the name of the subkey in the system service
|
|
list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services) that caused
|
|
the driver to load.
|
|
|
|
InstanceOrdinal - Supplies an ordinal that uniquely identifies the device
|
|
instance.
|
|
|
|
BusInfo - Receives bus information about the bus on which the device
|
|
is located.
|
|
|
|
DeviceInstanceFlags- Receives a ULONG containing status flags pertaining
|
|
to this device instance. The possible returned flags are:
|
|
DEVINSTANCE_FLAG_HWPROFILE_DISABLED
|
|
DEVINSTANCE_FLAG_PNP_ENUMERATED
|
|
|
|
Configuration - Receives the last known configuration. This will be
|
|
the configuration assigned to the device by the PnP BIOS (PnP
|
|
devices), ARC firmware, or the last known configuration (non-PnP
|
|
devices).
|
|
|
|
BufferSize - Supplies the size in bytes of the buffer pointed to by
|
|
Configuration.
|
|
|
|
ActualBufferSize - Supplies a variable to receive the size of data written
|
|
to Configuration buffer. In case of output buffer too small error,
|
|
it will contain the minimum required buffer size.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE serviceHandle, handle, sysEnumHandle = NULL;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
UNICODE_STRING unicodeKeyName;
|
|
ULONG foundAtEnum = 0, instanceFlags = 0;
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireResourceShared(&PpRegistryDeviceResource, TRUE);
|
|
|
|
status = IopOpenServiceEnumKeys (
|
|
ServiceKeyName,
|
|
KEY_READ,
|
|
&serviceHandle,
|
|
NULL,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local0;
|
|
}
|
|
|
|
//
|
|
// Open the subkey specified by ServiceName\Enum instance number under
|
|
// System\Enum subtree.
|
|
//
|
|
|
|
status = IopServiceInstanceToDeviceInstance (serviceHandle,
|
|
NULL,
|
|
InstanceOrdinal,
|
|
NULL,
|
|
&handle,
|
|
KEY_READ
|
|
);
|
|
ZwClose(serviceHandle);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local0;
|
|
}
|
|
|
|
//
|
|
// Now determine DeviceInstance flags and return the data
|
|
//
|
|
|
|
IopGetDeviceInstanceCsConfigFlags(
|
|
ServiceKeyName,
|
|
InstanceOrdinal,
|
|
&instanceFlags
|
|
);
|
|
|
|
if (instanceFlags & CSCONFIGFLAG_DO_NOT_CREATE ||
|
|
instanceFlags & CSCONFIGFLAG_DISABLED) {
|
|
instanceFlags = DEVINSTANCE_FLAG_HWPROFILE_DISABLED;
|
|
}
|
|
status = IopGetRegistryValue (handle,
|
|
REGSTR_VALUE_FOUNDATENUM,
|
|
&keyValueInformation
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
if (keyValueInformation->DataLength != 0) {
|
|
foundAtEnum = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
} else if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
goto exit_Local;
|
|
}
|
|
|
|
if (foundAtEnum) {
|
|
instanceFlags |= DEVINSTANCE_FLAG_PNP_ENUMERATED;
|
|
}
|
|
*DeviceInstanceFlags = instanceFlags;
|
|
|
|
//
|
|
// Read Configuration = value and return the data
|
|
//
|
|
|
|
status = IopGetRegistryValue (handle,
|
|
REGSTR_VALUE_CONFIGURATION,
|
|
&keyValueInformation);
|
|
if (NT_SUCCESS(status)) {
|
|
*ActualBufferSize = keyValueInformation->DataLength;
|
|
if (keyValueInformation->DataLength > BufferSize) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
RtlMoveMemory((PUCHAR)Configuration,
|
|
KEY_VALUE_DATA(keyValueInformation),
|
|
keyValueInformation->DataLength
|
|
);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
} else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// If no "Configuration=" value entry, we next check
|
|
// "DetectSignature".
|
|
//
|
|
|
|
status = IopGetRegistryValue (handle,
|
|
REGSTR_VALUE_DETECTSIGNATURE,
|
|
&keyValueInformation);
|
|
if (NT_SUCCESS(status)) {
|
|
*ActualBufferSize = keyValueInformation->DataLength;
|
|
if (keyValueInformation->DataLength > BufferSize) {
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
RtlMoveMemory((PUCHAR)Configuration,
|
|
KEY_VALUE_DATA(keyValueInformation),
|
|
keyValueInformation->DataLength
|
|
);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
} else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
|
|
//
|
|
// If no "Configuration=" or "DetectSignature" value entries,
|
|
// we return success with output buffer filled with zero.
|
|
//
|
|
|
|
*ActualBufferSize = 0;
|
|
RtlFillMemory((PUCHAR)Configuration, BufferSize, 0);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now read Bus information and return the installed bus information.
|
|
//
|
|
|
|
BusInfo->BusNumber = 0xffffffff;
|
|
BusInfo->BusType = MaximumInterfaceType;
|
|
BusInfo->ConfigurationType = MaximumBusDataType;
|
|
|
|
//
|
|
// Try to find the bus device current device is attached to.
|
|
// Traverse the BaseDevicePath to the bus node to get the information.
|
|
// (In fact, the device handler contains the hidden information.)
|
|
//
|
|
|
|
while (1) {
|
|
status = IopGetRegistryValue (handle,
|
|
REGSTR_VALUE_BASEDEVICEPATH,
|
|
&keyValueInformation
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
if (keyValueInformation->Type == REG_SZ) {
|
|
IopRegistryDataToUnicodeString(&unicodeKeyName,
|
|
(PWSTR)KEY_VALUE_DATA(keyValueInformation),
|
|
keyValueInformation->DataLength
|
|
);
|
|
ExFreePool(keyValueInformation);
|
|
|
|
//
|
|
// Open the device path pointed by BaseDevicePath
|
|
//
|
|
|
|
ZwClose(handle);
|
|
if (sysEnumHandle == NULL) {
|
|
status = IopOpenRegistryKey(
|
|
&sysEnumHandle,
|
|
NULL,
|
|
&CmRegistryMachineSystemCurrentControlSetEnumName,
|
|
KEY_READ,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto exit_Local0;
|
|
}
|
|
}
|
|
|
|
status = IopOpenRegistryKey (
|
|
&handle,
|
|
sysEnumHandle,
|
|
&unicodeKeyName,
|
|
KEY_READ,
|
|
FALSE
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
ZwClose(sysEnumHandle);
|
|
goto exit_Local0;
|
|
} else {
|
|
continue;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// The registry data is bogus. Fail the call.
|
|
//
|
|
|
|
ExFreePool(keyValueInformation);
|
|
goto exit_Local;
|
|
}
|
|
} else if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
break;
|
|
} else {
|
|
goto exit_Local;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now reach the bus node (the node without BaseDevicePath value key),
|
|
// retrieve its bus information.
|
|
//
|
|
|
|
status = IopGetRegistryValue (handle,
|
|
REGSTR_VALUE_INTERFACETYPE,
|
|
&keyValueInformation
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
if (keyValueInformation->DataLength != 0) {
|
|
BusInfo->BusType = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
|
|
status = IopGetRegistryValue (handle,
|
|
REGSTR_VALUE_SYSTEMBUSNUMBER,
|
|
&keyValueInformation
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
if (keyValueInformation->DataLength != 0) {
|
|
BusInfo->BusNumber = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
|
|
status = IopGetRegistryValue (handle,
|
|
REGSTR_VALUE_BUSDATATYPE,
|
|
&keyValueInformation
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
if (keyValueInformation->DataLength != 0) {
|
|
BusInfo->ConfigurationType = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
|
|
exit_Local:
|
|
ZwClose(handle);
|
|
exit_Local0:
|
|
ExReleaseResource(&PpRegistryDeviceResource);
|
|
KeLeaveCriticalRegion();
|
|
return status;
|
|
}
|
|
#if _PNP_POWER_STUB_ENABLED_
|
|
|
|
NTSTATUS
|
|
IoQuerySystemInformation(
|
|
IN OUT PIO_SYSTEM_INFORMATION SystemInformation
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
SystemInformation - Supplies the a pointer to the SYSTEM_INFORMATION
|
|
structure which receives the information about the
|
|
system. Note, the Size field of the SYSTEM_INFORMATION
|
|
structure must be initialized by caller.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
--*/
|
|
|
|
{
|
|
|
|
SystemInformation->OS = OS_WINDOWS_NT;
|
|
SystemInformation->OSVersion = 0x0400;
|
|
SystemInformation->NumberProcessors = KeNumberProcessors;
|
|
SystemInformation->ProcessorArchitecture = KeProcessorArchitecture;
|
|
SystemInformation->ProcessorLevel = KeProcessorLevel;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
IoReportDeviceStatus(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG DeviceStatus
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
PnP device drivers call this API to report any changes in status that
|
|
they detect for a device (e.g., a driver discovers that an adapter has
|
|
been removed when it tries to power it back up after having previously
|
|
powered down the device for power management). When the device status
|
|
is changed, the user mode PnP manager will be notified to take action.
|
|
|
|
Parameters:
|
|
DeviceObject - Supplies the device object whoes device status is to be
|
|
reported. This device object should be the one directly
|
|
associated with the physical device instance. Normally,
|
|
it is the device object created by the HAL bus extender.
|
|
|
|
DeviceStatus - Supplies an ordinala device status code indicating the new
|
|
status of the device. The DeviceStatus code from 0 to
|
|
0x7FFFFFFF are reserved for the system and the code from
|
|
0x80000000 to 0xFFFFFFFF are for private use and will not
|
|
be interpreted by PnP manager.
|
|
|
|
Device Status Codes:
|
|
|
|
#define DEVICE_STATUS_OK 0x00000000
|
|
#define DEVICE_STATUS_MALFUNCTIONED 0x00000001
|
|
#define DEVICE_STATUS_REMOVED 0x00000002
|
|
#define DEVICE_STATUS_DISABLED 0x00000003
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#if _PNP_POWER_
|
|
|
|
// Add code here
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#else
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
#endif // _PNP_POWER_
|
|
}
|
|
|
|
NTSTATUS
|
|
IoGetDeviceProperty(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
|
|
IN ULONG BufferLength,
|
|
IN PVOID PropertyBuffer,
|
|
OUT PULONG ResultLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine lets drivers query the registry properties associated with the
|
|
specified device.
|
|
|
|
Parameters:
|
|
|
|
DeviceObject - Supplies the device object whoes registry property is to be
|
|
returned. This device object should be the one created by
|
|
a bus driver.
|
|
|
|
DeviceProperty - Specifies what device property to get.
|
|
|
|
BufferLength - Specifies the length, in byte, of the PropertyBuffer.
|
|
|
|
PropertyBuffer - Supplies a pointer to a buffer to receive property data.
|
|
|
|
ResultLength - Supplies a pointer to a variable to receive the size of the
|
|
property data returned.
|
|
|
|
ReturnValue:
|
|
|
|
Status code that indicates whether or not the function was successful. If
|
|
PropertyBuffer is not big enough to hold requested data, STATUS_BUFFER_OVERFLOW
|
|
will be returned and ResultLength will be set to the number of bytes actually
|
|
required.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if _PNP_POWER_
|
|
|
|
// Add code here
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#else
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#endif // _PNP_POWER_
|
|
}
|
|
|
|
NTSTATUS
|
|
IoSetDeviceProperty(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
|
|
IN PVOID PropertyBuffer,
|
|
IN ULONG BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine lets drivers change the registry properties associated with the
|
|
specified device.
|
|
|
|
Parameters:
|
|
|
|
DeviceObject - Supplies the device object whoes registry property is to be
|
|
returned. This device object should be the one created by
|
|
a bus driver.
|
|
|
|
DeviceProperty - Specifies what device property to set (see below).
|
|
|
|
BufferLength - Specifies the length, in byte, of the PropertyBuffer.
|
|
|
|
PropertyBuffer - Supplies a pointer to a property data buffer.
|
|
|
|
ReturnValue:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
This routine returns STATUS_ACCESS_DENIED if it is requested to set a
|
|
read-only property.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if _PNP_POWER_
|
|
|
|
// Add code here
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#else
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#endif // _PNP_POWER_
|
|
}
|
|
|
|
NTSTATUS
|
|
IoRegisterPlugPlayNotification(
|
|
IN IO_NOTIFICATION_EVENT_CATEGORY Event,
|
|
IN LPGUID ResourceType, OPTIONAL
|
|
IN PVOID ResourceDescription, OPTIONAL
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PDRIVER_NOTIFICATION_ENTRY NotificationEntry,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API registers a driver's callback function for a specified pnp event.
|
|
The registered notification record stays registered even after the registered
|
|
event occurred. To remove a registered notification record, the caller must
|
|
call IoUnRegisterPlugPlayNotification.
|
|
|
|
Parameters:
|
|
|
|
Event - Specifies the hardware event catagory that the driver is to be registered.
|
|
|
|
ResourceType - a pointer to a 128 bit GUID specifying the type of resource. If
|
|
HardwareProfileChange is specified for Event, this parameter
|
|
is not used and should be NULL.
|
|
|
|
ResourceDescription - Supplies a pointer to a buffer containing the resource.
|
|
If HardwareProfileChange is specified for Event, this parameter
|
|
is not used and should be NULL.
|
|
|
|
DeviceObject - Specifies a pointer to a device object. This device object
|
|
prevents the driver from being unloaded while it is registered to
|
|
be notified.
|
|
|
|
NotificationEntry - Supplies a pointer to a function which is to be executed
|
|
when the notification occurs.
|
|
|
|
Context - Supplies a pointer to a data structure that is passed to the driver's
|
|
notification entry.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if _PNP_POWER_
|
|
|
|
// Add code here
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#else
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#endif // _PNP_POWER_
|
|
}
|
|
|
|
NTSTATUS
|
|
IoUnregisterPlugPlayNotification(
|
|
IN IO_NOTIFICATION_EVENT_CATEGORY Event,
|
|
IN LPGUID ResourceType, OPTIONAL
|
|
IN PVOID ResourceDescription, OPTIONAL
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PDRIVER_NOTIFICATION_ENTRY NotificationEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API removes the event notification registration established via
|
|
IoRegisterPlugPlayNotification API.
|
|
|
|
Parameters:
|
|
|
|
Event - Specifies the hardware event that the driver is to be registered.
|
|
|
|
ResourceType - a 128 bit GUID specifying the type of resource. If
|
|
HardwareProfileChange is specified for Event, this parameter
|
|
is not used and should be NULL.
|
|
|
|
ResourceDescription - Supplies a pointer to a buffer containing the resource.
|
|
If HardwareProfileChange is specified for Event, this parameter
|
|
is not used and should be NULL.
|
|
|
|
DeviceObject - Specifies a pointer to the a device object which passed to the
|
|
IoRegisterPlugPlayNotification.
|
|
|
|
NotificationEntry - Supplies a pointer to a function which is to be executed
|
|
when the notification occurs.
|
|
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
--*/
|
|
|
|
{
|
|
#if _PNP_POWER_
|
|
|
|
// Add code here
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#else
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
#endif // _PNP_POWER_
|
|
}
|
|
#endif // _PNP_POWER_STUB_ENABLED_
|