windows-nt/Source/XPSP1/NT/drivers/input/neckbadd/neckbadd.c

1037 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*--
Copyright (c) 1997 Microsoft Corporation
Module Name:
neckbadd.c
Abstract:
Environment:
Kernel mode only.
Notes:
Revision History:
--*/
#include "neckbadd.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, NecKbdCreateClose)
#pragma alloc_text (PAGE, NecKbdInternIoCtl)
#pragma alloc_text (PAGE, NecKbdUnload)
#endif
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Initialize the entry points of the driver.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
ULONG i;
UNREFERENCED_PARAMETER (RegistryPath);
//
// Fill in all the dispatch entry points with the pass through function
// and the explicitly fill in the functions we are going to intercept
//
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = NecKbdDispatchPassThrough;
}
DriverObject->MajorFunction [IRP_MJ_CREATE] =
DriverObject->MajorFunction [IRP_MJ_CLOSE] = NecKbdCreateClose;
DriverObject->MajorFunction [IRP_MJ_PNP] = NecKbdPnP;
DriverObject->MajorFunction [IRP_MJ_POWER] = NecKbdPower;
DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NecKbdInternIoCtl;
DriverObject->DriverUnload = NecKbdUnload;
DriverObject->DriverExtension->AddDevice = NecKbdAddDevice;
NecKbdServiceParameters(RegistryPath);
return STATUS_SUCCESS;
}
NTSTATUS
NecKbdAddDevice(
IN PDRIVER_OBJECT Driver,
IN PDEVICE_OBJECT PDO
)
{
PDEVICE_EXTENSION devExt;
IO_ERROR_LOG_PACKET errorLogEntry;
PDEVICE_OBJECT device;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
status = IoCreateDevice(Driver, // driver
sizeof(DEVICE_EXTENSION), // size of extension
NULL, // device name
FILE_DEVICE_8042_PORT, // device type
0, // device characteristics
FALSE, // exclusive
&device // new device
);
if (!NT_SUCCESS(status)) {
return (status);
}
RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION));
devExt = (PDEVICE_EXTENSION) device->DeviceExtension;
devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);
if (devExt->TopOfStack == NULL) {
IoDeleteDevice(device);
return STATUS_DEVICE_NOT_CONNECTED;
}
ASSERT(devExt->TopOfStack);
devExt->Self = device;
devExt->PDO = PDO;
devExt->DeviceState = PowerDeviceD0;
devExt->Removed = FALSE;
devExt->Started = FALSE;
device->Flags |= DO_BUFFERED_IO;
device->Flags |= DO_POWER_PAGABLE;
device->Flags &= ~DO_DEVICE_INITIALIZING;
return status;
}
NTSTATUS
NecKbdComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PKEVENT event;
PIO_STACK_LOCATION irpStack;
NTSTATUS status = STATUS_SUCCESS;
event = (PKEVENT) Context;
UNREFERENCED_PARAMETER(DeviceObject);
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
//
// We could switch on the major and minor functions of the IRP to perform
// different functions, but we know that Context is an event that needs
// to be set.
//
KeSetEvent(event, 0, FALSE);
//
// Allows the caller to use the IRP after it is completed
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
NecKbdCreateClose (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Maintain a simple count of the creates and closes sent against this device
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION devExt;
PAGED_CODE();
irpStack = IoGetCurrentIrpStackLocation(Irp);
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
if (NULL == devExt->UpperConnectData.ClassService) {
//
// No Connection yet. How can we be enabled?
//
status = STATUS_INVALID_DEVICE_STATE;
}
break;
case IRP_MJ_CLOSE:
break;
}
Irp->IoStatus.Status = status;
//
// Pass on the create and the close
//
return NecKbdDispatchPassThrough(DeviceObject, Irp);
}
NTSTATUS
NecKbdDispatchPassThrough(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Passes a request on to the lower driver.
--*/
{
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Pass the IRP to the target
//
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(
((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->TopOfStack,
Irp);
}
NTSTATUS
NecKbdInternIoCtl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch routine for internal device control requests.
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION devExt;
KEVENT event;
PCONNECT_DATA connectData;
PKEYBOARD_TYPEMATIC_PARAMETERS TypematicParameters;
NTSTATUS status = STATUS_SUCCESS;
//
// Get a pointer to the device extension.
//
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//
// Initialize the returned Information field.
//
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current parameters for this request. The
// information is contained in the current stack location.
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Case on the device control subfunction that is being performed by the
// requestor.
//
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
//
// Connect a keyboard class device driver to the port driver.
//
case IOCTL_INTERNAL_KEYBOARD_CONNECT:
//
// Only allow a connection if the keyboard hardware is present.
// Also, only allow one connection.
//
if (devExt->UpperConnectData.ClassService != NULL) {
status = STATUS_SHARING_VIOLATION;
break;
}
else if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(CONNECT_DATA)) {
//
// invalid buffer
//
status = STATUS_INVALID_PARAMETER;
break;
}
//
// Copy the connection parameters to the device extension.
//
connectData = ((PCONNECT_DATA)
(irpStack->Parameters.DeviceIoControl.Type3InputBuffer));
devExt->UpperConnectData = *connectData;
connectData->ClassDeviceObject = devExt->Self;
connectData->ClassService = NecKbdServiceCallback;
break;
//
// Disconnect a keyboard class device driver from the port driver.
//
case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
//
// Clear the connection parameters in the device extension.
//
// devExt->UpperConnectData.ClassDeviceObject = NULL;
// devExt->UpperConnectData.ClassService = NULL;
status = STATUS_NOT_IMPLEMENTED;
break;
case IOCTL_KEYBOARD_SET_TYPEMATIC:
//
// Might want to capture these in the future
//
case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
case IOCTL_KEYBOARD_QUERY_INDICATORS:
case IOCTL_KEYBOARD_SET_INDICATORS:
case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
default:
break;
}
if (!NT_SUCCESS(status)) {
return status;
}
return NecKbdDispatchPassThrough(DeviceObject, Irp);
}
NTSTATUS
NecKbdPnP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch routine for plug and play irps
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PDEVICE_EXTENSION devExt;
PIO_STACK_LOCATION irpStack;
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldIrql;
KEVENT event;
PAGED_CODE();
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->MinorFunction) {
case IRP_MN_START_DEVICE: {
//
// The device is starting.
//
// We cannot touch the device (send it any non pnp irps) until a
// start device has been passed down to the lower drivers.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
KeInitializeEvent(&event,
NotificationEvent,
FALSE
);
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE) NecKbdComplete,
&event,
TRUE,
TRUE,
TRUE); // No need for Cancel
status = IoCallDriver(devExt->TopOfStack, Irp);
if (STATUS_PENDING == status) {
KeWaitForSingleObject(
&event,
Executive, // Waiting for reason of a driver
KernelMode, // Waiting in kernel mode
FALSE, // No allert
NULL); // No timeout
}
if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) {
//
// As we are successfully now back from our start device
// we can do work.
//
devExt->Started = TRUE;
devExt->Removed = FALSE;
}
//
// We must now complete the IRP, since we stopped it in the
// completetion routine with MORE_PROCESSING_REQUIRED.
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
}
case IRP_MN_REMOVE_DEVICE:
IoSkipCurrentIrpStackLocation(Irp);
IoCallDriver(devExt->TopOfStack, Irp);
devExt->Removed = TRUE;
IoDetachDevice(devExt->TopOfStack);
IoDeleteDevice(DeviceObject);
status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
case IRP_MN_STOP_DEVICE:
case IRP_MN_QUERY_DEVICE_RELATIONS:
case IRP_MN_QUERY_INTERFACE:
case IRP_MN_QUERY_CAPABILITIES:
case IRP_MN_QUERY_DEVICE_TEXT:
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_QUERY_ID:
case IRP_MN_QUERY_PNP_DEVICE_STATE:
default:
//
// Here the filter driver might modify the behavior of these IRPS
// Please see PlugPlay documentation for use of these IRPs.
//
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(devExt->TopOfStack, Irp);
break;
}
return status;
}
NTSTATUS
NecKbdPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch routine for power irps Does nothing except
record the state of the device.
Arguments:
DeviceObject - Pointer to the device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PDEVICE_EXTENSION devExt;
POWER_STATE powerState;
POWER_STATE_TYPE powerType;
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
powerType = irpStack->Parameters.Power.Type;
powerState = irpStack->Parameters.Power.State;
switch (irpStack->MinorFunction) {
case IRP_MN_SET_POWER:
Print(("NecKbdPower:Power Setting %s state to %d\n",
((powerType == SystemPowerState) ? "System"
: "Device"),
powerState.SystemState));
if (powerType == DevicePowerState) {
devExt->DeviceState = powerState.DeviceState;
}
break;
case IRP_MN_QUERY_POWER:
Print(("NecKbdPower:Power query %s status to %d\n",
((powerType == SystemPowerState) ? "System"
: "Device"),
powerState.SystemState));
break;
default:
Print(("NecKbdPower:Power minor (0x%x) no known\n",
irpStack->MinorFunction));
break;
}
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
PoCallDriver(devExt->TopOfStack, Irp);
return STATUS_SUCCESS;
}
VOID
NecKbdServiceCallback(
IN PDEVICE_OBJECT DeviceObject,
IN PKEYBOARD_INPUT_DATA InputDataStart,
IN PKEYBOARD_INPUT_DATA InputDataEnd,
IN OUT PULONG InputDataConsumed
)
{
PDEVICE_EXTENSION devExt;
PKEYBOARD_INPUT_DATA CurrentInputData,
CurrentInputDataStart;
KEYBOARD_INPUT_DATA TempInputData[2];
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
RtlZeroMemory(TempInputData, sizeof(KEYBOARD_INPUT_DATA) * 2);
CurrentInputData = CurrentInputDataStart = InputDataStart;
while (CurrentInputData < InputDataEnd) {
// Print(("NecKbdServiceCallBack: captured scancode: 0x%2x(%2x)\n",
// CurrentInputData->MakeCode,
// CurrentInputData->Flags
// ));
if (devExt->KeyStatusFlags & STOP_PREFIX) {
if (((CurrentInputData->MakeCode != NUMLOCK_KEY) ||
((CurrentInputData->Flags & (KEY_E0|KEY_E1)) != 0) ||
((CurrentInputData->Flags & KEY_BREAK) != (devExt->CachedInputData.Flags & KEY_BREAK)))) {
Print(("NecKbdServiceCallBack: clearing prefix of STOP(%s)\n",
(CurrentInputData->Flags & KEY_BREAK) ? "Break" : "Make"
));
//
// send cached input data
//
CLASSSERVICE_CALLBACK(
&(devExt->CachedInputData),
&(devExt->CachedInputData) + 1);
devExt->KeyStatusFlags &= ~STOP_PREFIX;
}
}
switch (CurrentInputData->MakeCode) {
case CAPS_KEY:
case KANA_KEY:
if (CurrentInputData->Flags & (KEY_E0|KEY_E1)) {
break;
}
if (!(CurrentInputData->Flags & KEY_BREAK)) {
Print(("NecKbdServiceCallBack: Captured %s (Make)\n",
((CurrentInputData->MakeCode == CAPS_KEY) ? "CAPS" : "KANA")
));
if (((CurrentInputData->MakeCode == CAPS_KEY)&&(devExt->KeyStatusFlags & CAPS_PRESSING))||
((CurrentInputData->MakeCode == KANA_KEY)&&(devExt->KeyStatusFlags & KANA_PRESSING))) {
//
// ignore repeated make code
//
Print(("NecKbdServiceCallBack: ignoring repeated %s(Break)\n",
((CurrentInputData->MakeCode == CAPS_KEY) ? "CAPS" : "KANA")
));
} else {
if (CurrentInputDataStart <= CurrentInputData) {
CLASSSERVICE_CALLBACK(
CurrentInputDataStart,
CurrentInputData + 1);
}
//
// Send break code
//
RtlCopyMemory(
(PCHAR)&(TempInputData[0]),
(PCHAR)CurrentInputData,
sizeof(KEYBOARD_INPUT_DATA)
);
TempInputData[0].Flags |= KEY_BREAK;
Print(("NecKbdServiceCallBack: Sending %s(Break)\n",
((CurrentInputData->MakeCode == CAPS_KEY) ? "CAPS" : "KANA")
));
CLASSSERVICE_CALLBACK(
&(TempInputData[0]),
&(TempInputData[1]));
}
if (CurrentInputData->MakeCode == CAPS_KEY) {
devExt->KeyStatusFlags |= CAPS_PRESSING;
} else {
devExt->KeyStatusFlags |= KANA_PRESSING;
}
} else {
//
// Break generates no scancode.
//
Print(("NecKbdServiceCallBack: ignoring %s(Break)\n",
((CurrentInputData->MakeCode == CAPS_KEY) ? "CAPS" : "KANA")
));
if (CurrentInputDataStart < CurrentInputData) {
CLASSSERVICE_CALLBACK(
CurrentInputDataStart,
CurrentInputData);
}
if (CurrentInputData->MakeCode == CAPS_KEY) {
devExt->KeyStatusFlags &= ~CAPS_PRESSING;
} else {
devExt->KeyStatusFlags &= ~KANA_PRESSING;
}
}
CurrentInputDataStart = CurrentInputData + 1;
break;
case CTRL_KEY:
if ((CurrentInputData->Flags & (KEY_E0|KEY_E1)) == KEY_E1) {
Print(("NecKbdServiceCallBack: prefix of STOP(%s)\n",
(CurrentInputData->Flags & KEY_BREAK) ? "Break" : "Make"
));
if (CurrentInputDataStart < CurrentInputData) {
CLASSSERVICE_CALLBACK(
CurrentInputDataStart,
CurrentInputData);
}
RtlCopyMemory(
(PCHAR)&(devExt->CachedInputData),
(PCHAR)CurrentInputData,
sizeof(KEYBOARD_INPUT_DATA)
);
devExt->KeyStatusFlags |= STOP_PREFIX;
CurrentInputDataStart = CurrentInputData + 1;
}
break;
case NUMLOCK_KEY:
if ((CurrentInputData->Flags & (KEY_E0|KEY_E1)) == 0) {
if (devExt->KeyStatusFlags & STOP_PREFIX) {
if ((CurrentInputData->Flags & KEY_BREAK) == (devExt->CachedInputData.Flags & KEY_BREAK)) {
//
// it is STOP key
//
Print(("NecKbdServiceCallBack: Captured STOP(%s)\n",
((CurrentInputData->Flags & KEY_BREAK) ? "Break" : "Make")
));
devExt->KeyStatusFlags &= ~STOP_PREFIX;
//
// make packets for 0x1d
//
RtlCopyMemory(
(PCHAR)&(TempInputData[0]),
(PCHAR)CurrentInputData,
sizeof(KEYBOARD_INPUT_DATA)
);
TempInputData[0].MakeCode = CTRL_KEY;
TempInputData[0].Flags &= ~(KEY_E0|KEY_E1);
//
// make packet for 0x46+E0
//
RtlCopyMemory(
(PCHAR)&(TempInputData[1]),
(PCHAR)CurrentInputData,
sizeof(KEYBOARD_INPUT_DATA)
);
TempInputData[1].MakeCode = STOP_KEY;
TempInputData[1].Flags |= KEY_E0;
TempInputData[1].Flags &= ~KEY_E1;
//
// send packets 0x1d, 0x46+E0
//
CLASSSERVICE_CALLBACK(
&(TempInputData[0]),
&(TempInputData[2]));
CurrentInputDataStart = CurrentInputData + 1;
} else {
//
// invalid prefix. send it as is.
//
Print(("NecKbdServiceCallBack: invalid prefix for STOP(%s)\n",
((CurrentInputData->Flags & KEY_BREAK) ? "Break" : "Make")
));
}
} else {
//
// it is vf3 key. it behaves as F13 or NumLock
//
Print(("NecKbdServiceCallBack: Captured vf3(VfKeyEmulation is %s)\n",
((VfKeyEmulation) ? "On" : "Off")
));
if (!(VfKeyEmulation)) {
CurrentInputData->MakeCode = VF3_KEY;
CurrentInputData->Flags &= ~(KEY_E0|KEY_E1);
}
}
}
break;
//
// ScrollLock can emulate VF4
//
case SCROLL_LOCK_KEY:
if ((CurrentInputData->Flags & (KEY_E0|KEY_E1)) == 0) {
Print(("NecKbdServiceCallBack: Captured vf4(VfKeyEmulation is %s)\n",
((VfKeyEmulation) ? "On" : "Off")
));
if (!(VfKeyEmulation)) {
CurrentInputData->MakeCode = VF4_KEY;
CurrentInputData->Flags &= ~(KEY_E0|KEY_E1);
}
}
break;
//
// hankaku/zenkaku can emulate VF5
//
case HANKAKU_ZENKAKU_KEY:
if ((CurrentInputData->Flags & (KEY_E0|KEY_E1)) == 0) {
Print(("NecKbdServiceCallBack: Captured vf5(VfKeyEmulation is %s)\n",
((VfKeyEmulation) ? "On" : "Off")
));
if (!(VfKeyEmulation)) {
CurrentInputData->MakeCode = VF5_KEY;
CurrentInputData->Flags &= ~(KEY_E0|KEY_E1);
}
}
break;
//
// the others(sent as is)
//
default:
break;
}
CurrentInputData++;
}
//
// flush InputData
//
if (CurrentInputDataStart < InputDataEnd) {
if (devExt->KeyStatusFlags & STOP_PREFIX) {
CLASSSERVICE_CALLBACK(
CurrentInputDataStart,
InputDataEnd - 1);
} else {
CLASSSERVICE_CALLBACK(
CurrentInputDataStart,
InputDataEnd);
}
}
}
VOID
NecKbdUnload(
IN PDRIVER_OBJECT Driver
)
/*++
Routine Description:
Free all the allocated resources associated with this driver.
Arguments:
DriverObject - Pointer to the driver object.
Return Value:
None.
--*/
{
PAGED_CODE();
ASSERT(NULL == Driver->DeviceObject);
return;
}
VOID
NecKbdServiceParameters(
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine retrieves this driver's service parameters information
from the registry.
Arguments:
RegistryPath - Pointer to the null-terminated Unicode name of the
registry path for this driver.
Return Value:
None.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PRTL_QUERY_REGISTRY_TABLE Parameters = NULL;
PWSTR Path = NULL;
UNICODE_STRING ParametersPath;
ULONG QueriedVfKeyEmulation = 0;
ULONG DefaultVfKeyEmulation = 0;
USHORT queries = 1;
PAGED_CODE();
ParametersPath.Buffer = NULL;
//
// Registry path is already null-terminated, so just use it.
//
Path = RegistryPath->Buffer;
if (NT_SUCCESS(Status)) {
//
// Allocate the Rtl query table.
//
Parameters = ExAllocatePool(
PagedPool,
sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
);
if (!Parameters) {
Print(("NecKbdServiceParameters: couldn't allocate table for Rtl query to %ws for %ws\n",
pwParameters,
Path
));
Status = STATUS_UNSUCCESSFUL;
} else {
RtlZeroMemory(
Parameters,
sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
);
//
// Form a path to this driver's Parameters subkey.
//
RtlInitUnicodeString( &ParametersPath, NULL );
ParametersPath.MaximumLength = RegistryPath->Length +
(wcslen(pwParameters) * sizeof(WCHAR) ) + sizeof(UNICODE_NULL);
ParametersPath.Buffer = ExAllocatePool(
PagedPool,
ParametersPath.MaximumLength
);
if (!ParametersPath.Buffer) {
Print(("NecKbdServiceParameters: Couldn't allocate string for path to %ws for %ws\n",
pwParameters,
Path
));
Status = STATUS_UNSUCCESSFUL;
}
}
}
if (NT_SUCCESS(Status)) {
//
// Form the parameters path.
//
RtlZeroMemory(
ParametersPath.Buffer,
ParametersPath.MaximumLength
);
RtlAppendUnicodeToString(
&ParametersPath,
Path
);
RtlAppendUnicodeToString(
&ParametersPath,
pwParameters
);
//
// Gather all of the "user specified" information from
// the registry.
//
Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
Parameters[0].Name = pwVfKeyEmulation;
Parameters[0].EntryContext = &QueriedVfKeyEmulation;
Parameters[0].DefaultType = REG_DWORD;
Parameters[0].DefaultData = &DefaultVfKeyEmulation;
Parameters[0].DefaultLength = sizeof(ULONG);
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
ParametersPath.Buffer,
Parameters,
NULL,
NULL
);
if (!NT_SUCCESS(Status)) {
Print(("NecKbdServiceParameters: RtlQueryRegistryValues failed (0x%x)\n", Status));
}
}
if (!NT_SUCCESS(Status)) {
//
// assign driver defaults.
//
VfKeyEmulation = (DefaultVfKeyEmulation == 0) ? FALSE : TRUE;
} else {
VfKeyEmulation = (QueriedVfKeyEmulation == 0) ? FALSE : TRUE;
}
Print(("NecKbdServiceParameters: VfKeyEmulation is %s\n",
VfKeyEmulation ? "Enable" : "Disable"));
//
// Free the allocated memory before returning.
//
if (ParametersPath.Buffer)
ExFreePool(ParametersPath.Buffer);
if (Parameters)
ExFreePool(Parameters);
}