Hi all,

I am new to device driver development and am currently writing an upper
filter driver for a USB keyboard. My first step I am trying is to
obtain the LED information from the keyboard from a user-mode
application. I have followed the Windows example (toaster filter)
regarding creating a control device object in the upper filter driver
and am able to obtain a handle to this control device object in the
user-mode application. However, I then attempt to obtain the LED
information as follows in the application:


USBHandle = CreateFile("\\\\.\\KeyboardUSB", GENERIC_READ |
GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (USBHandle != INVALID_HANDLE_VALUE) {
status = DeviceIoControl(USBHandle,
IOCTL_KEYBOARD_QUERY_INDICATORS, NULL, 0, &kbdParam, sizeof(kbdParam),
&outLength, NULL);
}


In the filter driver, I receive the correct IRP (as below in my
DispatchIO routine), but am unsure how to obtain and return the correct
data. Below shows what I am currently attempting to do.


irpStack = IoGetCurrentIrpStackLocation(Irp);

switch (irpStack->MajorFunction) {
case IRP_MJ_DEVICE_CONTROL:
#ifdef DEBUG
WriteLogFile("DispatchIo: IRP_MJ_DEVICE_CONTROL\r\n", 35);
#endif
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_KEYBOARD_QUERY_INDICATORS:
#ifdef DEBUG
WriteLogFile("DispatchIo:
IOCTL_KEYBOARD_QUERY_INDICATORS\r\n", 45);
#endif
return FilterPass(MainDeviceObject, Irp);
break;

default:
break;
}
default:
break;
}


Therefore, my main question is how to execute the IRPs correctly that
are created from my application using DeviceIoControl. Do I need to
use completion routines and if so, how should these be used?

Thanks in advance,
Kyzer

Re: Keyboard filter driver - obtaining keyboard indicator status by Maxim

Maxim
Mon Nov 21 01:27:36 CST 2005

Keyboard is monopolistically opened by USER32, use the USER32 APIs to get
the LED state.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
maxim@storagecraft.com
http://www.storagecraft.com

"Kyzer" <kyzer626@hotmail.com> wrote in message
news:1132551080.636816.285750@f14g2000cwb.googlegroups.com...
> Hi all,
>
> I am new to device driver development and am currently writing an upper
> filter driver for a USB keyboard. My first step I am trying is to
> obtain the LED information from the keyboard from a user-mode
> application. I have followed the Windows example (toaster filter)
> regarding creating a control device object in the upper filter driver
> and am able to obtain a handle to this control device object in the
> user-mode application. However, I then attempt to obtain the LED
> information as follows in the application:
>
>
> USBHandle = CreateFile("\\\\.\\KeyboardUSB", GENERIC_READ |
> GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
>
> if (USBHandle != INVALID_HANDLE_VALUE) {
> status = DeviceIoControl(USBHandle,
> IOCTL_KEYBOARD_QUERY_INDICATORS, NULL, 0, &kbdParam, sizeof(kbdParam),
> &outLength, NULL);
> }
>
>
> In the filter driver, I receive the correct IRP (as below in my
> DispatchIO routine), but am unsure how to obtain and return the correct
> data. Below shows what I am currently attempting to do.
>
>
> irpStack = IoGetCurrentIrpStackLocation(Irp);
>
> switch (irpStack->MajorFunction) {
> case IRP_MJ_DEVICE_CONTROL:
> #ifdef DEBUG
> WriteLogFile("DispatchIo: IRP_MJ_DEVICE_CONTROL\r\n", 35);
> #endif
> switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
> case IOCTL_KEYBOARD_QUERY_INDICATORS:
> #ifdef DEBUG
> WriteLogFile("DispatchIo:
> IOCTL_KEYBOARD_QUERY_INDICATORS\r\n", 45);
> #endif
> return FilterPass(MainDeviceObject, Irp);
> break;
>
> default:
> break;
> }
> default:
> break;
> }
>
>
> Therefore, my main question is how to execute the IRPs correctly that
> are created from my application using DeviceIoControl. Do I need to
> use completion routines and if so, how should these be used?
>
> Thanks in advance,
> Kyzer
>


Re: Keyboard filter driver - obtaining keyboard indicator status by Robert

Robert
Mon Nov 21 07:35:08 CST 2005

Maxim S. Shatskih wrote:
> Keyboard is monopolistically opened by USER32, use the USER32 APIs to get
> the LED state.
>

He could catch and strore the LED report written in the filter driver
and implement a DeviceIoControl to read back the report.

Still it is much simpler to ask Windows for the keyboard states
associated with the LEDs.

Re: Keyboard filter driver - obtaining keyboard indicator status by Kyzer

Kyzer
Mon Nov 21 17:28:41 CST 2005

Thanks for your responses. Even though using the USER32 APIs would
seem easier, I would like to know how to implement your method Robert,
as I will have to use handle different IRPs after obtaining the LED
status (such as setting the LED indicators and changing input/output),
Therefore, I think that obtaining the LED status is the first step to
implementing the other features that I wish to do, and the other
functions will follow a similar process to this.

Let me know if you wish to look at any other code from my filter
driver.

Thanks,
Kyzer


Re: Keyboard filter driver - obtaining keyboard indicator status by Robert

Robert
Tue Nov 22 00:46:54 CST 2005

Kyzer wrote:

> Let me know if you wish to look at any other code from my filter
> driver.

Sorry, i am no driver specialist. You will have to find someone else to
help you with that.

Re: Keyboard filter driver - obtaining keyboard indicator status by Maxim

Maxim
Tue Nov 22 13:00:49 CST 2005

> He could catch and strore the LED report written in the filter driver
> and implement a DeviceIoControl to read back the report.

He will need the second device object to open in this case.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
maxim@storagecraft.com
http://www.storagecraft.com


Re: Keyboard filter driver - obtaining keyboard indicator status by Kyzer

Kyzer
Tue Nov 22 22:21:14 CST 2005

Thanks for your response. In my user-mode application I am able to
obtain a handle to the control device object that I am creating in the
filter driver. The filter driver's dispatch routine is also receiving
the IRP created from the DeviceIoControl function call, but I am unsure
how to correctly pass this IRP to the lower drivers (if this is
required) and return the correct data.

Is the use of a service callback function required in my filter
driver's dispatch routine, and if yes, how should this be done?

Thanks,
Kyzer


Re: Keyboard filter driver - obtaining keyboard indicator status by Kyzer

Kyzer
Thu Nov 24 00:06:30 CST 2005

Hi all,

As I'm currently more than a little confused as to how to solve my
problem, I have decided to include my driver code (below), and explain
exactly what I am attempting to do.

I am trying to send requests to a USB keyboard from an application (eg.
querying/setting LED indicators, sending characters to the keyboard,
etc). I understand that to do this, I need to create a control device
object in an upper filter driver so that the application may has access
to the keyboard. Then obviously via this control device object, I
would like to handle the requests. (A sample of the code from the
application is located in the first post on this thread).

>From the filter driver code below, here are a few questions that I
would like to pose - the answers of which may help me in getting a
solution to this problem:
1. Currently the control device object is of type FILE_DEVICE_KEYBOARD,
but should I be creating this as a different device type (and possibly
creating a new device interface) (ie. calling
IoRegisterDeviceInterface)?
2. Is the control device object created correctly, or should it be
created in a different location?
3. Should the control device object be attached to the device stack
differently (eg. in a similar way to the device object created in
AddDevice) so that I may pass the requests from the application lower
down the stack and receive the correct result?
4. Should I be using completion routines when receiving requests from
the application?

Below is the current filter driver code:


//******************************************************************************
//
//! @file filter.c
//
//******************************************************************************
// Include Files

#include "filter.h"

#include "ntstrsafe.h"

//******************************************************************************
// Definitions

#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, KeybdAddDevice)
#pragma alloc_text (PAGE, KeybdDispatchPnp)
#pragma alloc_text (PAGE, KeybdUnload)

#pragma alloc_text (PAGE, KeybdCreateControlObject)
#pragma alloc_text (PAGE, KeybdDeleteControlObject)
#pragma alloc_text (PAGE, KeybdDispatchIo)
#endif

PDEVICE_OBJECT MainDeviceObject = NULL;

FAST_MUTEX ControlMutex;
ULONG InstanceCount = 0;
PDEVICE_OBJECT ControlDeviceObject;

#define SYMBOLIC_NAME_STRING L"\\DosDevices\\KeybdUSB"
#define NTDEVICE_NAME_STRING L"\\Device\\KeybdUSB"

//******************************************************************************
// DriverEntry
//! @brief Installable driver initialisation entry point - called
directly by
//! the I/O system
//!
//! @param DriverObject - pointer to the driver object
//! @param RegistryPath - pointer to a string representing the path
to the
//! the driver-specific key in the registry
//! @return STATUS_SUCCESS if successful, or STATUS_UNSUCCESSFUL
otherwise
//! @warning -
//! @note -

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING
RegistryPath) {

NTSTATUS status = STATUS_SUCCESS;
ULONG ulIndex;
PDRIVER_DISPATCH *dispatch;

UNREFERENCED_PARAMETER(RegistryPath);

//
// Create dispatch points
//
for (ulIndex = 0, dispatch = DriverObject->MajorFunction;ulIndex <=
IRP_MJ_MAXIMUM_FUNCTION;ulIndex++, dispatch++) {
*dispatch = KeybdPass;
}

DriverObject->MajorFunction[IRP_MJ_PNP] = KeybdDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = KeybdDispatchPower;
DriverObject->DriverExtension->AddDevice = KeybdAddDevice;
DriverObject->DriverUnload = KeybdUnload;

//
// Set the following dispatch points as we will be doing
// something useful to these requests instead of just
// passing them down.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = KeybdDispatchIo;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KeybdDispatchIo;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = KeybdDispatchIo;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
KeybdDispatchIo;

//
// Mutex is to synchronize multiple threads creating & deleting
// control deviceobjects.
//
ExInitializeFastMutex(&ControlMutex);

return status;

}

//******************************************************************************
// KeybdAddDevice
//! @brief Creates a function device object to attach to the stack
//!
//! @param DriverObject - pointer to a device object
//! @param PhysicalDeviceObject - pointer to a device object created
by the
//! underlying bus driver
//! @return Status of success
//! @warning -
//! @note -

NTSTATUS KeybdAddDevice(IN PDRIVER_OBJECT DriverObject, IN
PDEVICE_OBJECT PhysicalDeviceObject) {

NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
ULONG deviceType = FILE_DEVICE_UNKNOWN;

PAGED_CODE();

//
// Create a filter device object.
//
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
NULL, FILE_DEVICE_KEYBOARD, FILE_DEVICE_SECURE_OPEN, FALSE,
&MainDeviceObject);

if (!NT_SUCCESS(status)) {
//
// Returning failure here prevents the entire stack from
functioning,
// but most likely the rest of the stack will not be able to
create
// device objects either, so it is still OK.
//
return status;
}

deviceExtension =
(PDEVICE_EXTENSION)MainDeviceObject->DeviceExtension;
deviceExtension->NextLowerDriver =
IoAttachDeviceToDeviceStack(MainDeviceObject, PhysicalDeviceObject);

//
// Failure for attachment is an indication of a broken plug & play
system.
//
if (NULL == deviceExtension->NextLowerDriver) {
IoDeleteDevice(MainDeviceObject);
MainDeviceObject = NULL;
return STATUS_UNSUCCESSFUL;
}

MainDeviceObject->Flags |= deviceExtension->NextLowerDriver->Flags &
(DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
MainDeviceObject->DeviceType =
deviceExtension->NextLowerDriver->DeviceType;
MainDeviceObject->Characteristics =
deviceExtension->NextLowerDriver->Characteristics;
deviceExtension->Self = MainDeviceObject;

//
// Set the initial state of the Filter DO
//
INITIALIZE_PNP_STATE(deviceExtension);

MainDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

return STATUS_SUCCESS;

}

//******************************************************************************
// KeybdPass
//! @brief Default dispatch routing
//!
//! @param DeviceObject - pointer to a device object
//! @param Irp - pointer to an I/O request packet
//! @return Status of success or otherwise
//! @warning -
//! @note -

NTSTATUS KeybdPass(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

PDEVICE_EXTENSION deviceExtension;
NTSTATUS status;

deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);

return status;

}

//******************************************************************************
// KeybdDispatchPnp
//! @brief Plug and play dispatch routines
//!
//! @param DeviceObject - pointer to the device object
//! @param Irp - pointer to an I/O request packet
//! @return Status depending on the success of the dispatch
//! @warning -
//! @note -

NTSTATUS KeybdDispatchPnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{

PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
NTSTATUS status;

PAGED_CODE();

deviceExtension = (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);
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)KeybdStartCompletionRoutine, NULL, TRUE, TRUE,
TRUE);

status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);
return status;

case IRP_MN_REMOVE_DEVICE:
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(deviceExtension->NextLowerDriver, Irp);

SET_NEW_PNP_STATE(deviceExtension, Deleted);

KeybdDeleteControlObject();

IoDetachDevice(deviceExtension->NextLowerDriver);
IoDeleteDevice(DeviceObject);
return status;

case IRP_MN_QUERY_STOP_DEVICE:
SET_NEW_PNP_STATE(deviceExtension, StopPending);
status = STATUS_SUCCESS;
break;

case IRP_MN_CANCEL_STOP_DEVICE:
//
// Check to see whether you have received cancel-stop
// without first receiving a query-stop. This could happen if
someone
// above us fails a query-stop and passes down the subsequent
// cancel-stop.
//

if (StopPending == deviceExtension->DevicePnPState) {
//
// We did receive a query-stop, so restore.
//
RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
}
status = STATUS_SUCCESS; // We must not fail this IRP.
break;

case IRP_MN_STOP_DEVICE:
SET_NEW_PNP_STATE(deviceExtension, Stopped);
status = STATUS_SUCCESS;
break;

case IRP_MN_QUERY_REMOVE_DEVICE:
SET_NEW_PNP_STATE(deviceExtension, RemovePending);
status = STATUS_SUCCESS;
break;

case IRP_MN_SURPRISE_REMOVAL:
SET_NEW_PNP_STATE(deviceExtension, SurpriseRemovePending);
status = STATUS_SUCCESS;
break;

case IRP_MN_CANCEL_REMOVE_DEVICE:
//
// Check to see whether you have received cancel-remove
// without first receiving a query-remove. This could happen
if
// someone above us fails a query-remove and passes down the
// subsequent cancel-remove.
//
if (RemovePending == deviceExtension->DevicePnPState) {
//
// We did receive a query-remove, so restore.
//
RESTORE_PREVIOUS_PNP_STATE(deviceExtension);
}

status = STATUS_SUCCESS; // We must not fail this IRP.
break;

case IRP_MN_DEVICE_USAGE_NOTIFICATION:
//
// On the way down, pagable might become set. Mimic the driver
// above us. If no one is above us, just set pagable.
//
if ((DeviceObject->AttachedDevice == NULL) ||
(DeviceObject->AttachedDevice->Flags & DO_POWER_PAGABLE)) {
DeviceObject->Flags |= DO_POWER_PAGABLE;
}

IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
KeybdDeviceUsageNotificationCompletionRoutine, NULL, TRUE, TRUE, TRUE);
return IoCallDriver(deviceExtension->NextLowerDriver, Irp);

default:
//
// If you don't handle any IRP you must leave the
// status as is.
//
status = Irp->IoStatus.Status;
break;
}

//
// Pass the IRP down and forget it.
//
Irp->IoStatus.Status = status;
return KeybdPass(DeviceObject, Irp);

}

//******************************************************************************
// KeybdStartCompletionRoutine
//! @brief Completion routine used when calling the lower device
objects to
//! which the filter device object is attached
//!
//! @param DeviceObject - pointer to the device object
//! @param Irp - pointer to a plug and play IRP
//! @param Context - NULL
//! @return Status of successful completion routine
//! @warning -
//! @note -

NTSTATUS KeybdStartCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN
PIRP Irp, IN PVOID Context) {

PDEVICE_EXTENSION deviceExtension;

UNREFERENCED_PARAMETER(Context);

deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}

if (NT_SUCCESS (Irp->IoStatus.Status)) {
//
// As we are successfully now back, we will
// first set our state to Started.
//

SET_NEW_PNP_STATE(deviceExtension, Started);

//
// On the way up inherit FILE_REMOVABLE_MEDIA during Start.
// This characteristic is available only after the driver stack
is started!.
//
if (deviceExtension->NextLowerDriver->Characteristics &
FILE_REMOVABLE_MEDIA) {
DeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
}

//
// If the PreviousPnPState is stopped then we are being stopped
temporarily
// and restarted for resource rebalance.
//
if (Stopped != deviceExtension->PreviousPnPState) {
//
// Device is started for the first time.
//
KeybdCreateControlObject(DeviceObject);
}

}

return STATUS_SUCCESS;

}

//******************************************************************************
// KeybdDeviceUsageNotificationCompletionRoutine
//! @brief Completion routine used when calling the lower device
objects to
//! which the filter device object is attached
//!
//! @param DeviceObject - pointer to the device object
//! @param Irp - pointer to a plug and play IRP
//! @param Context - NULL
//! @return Status of successful completion routine
//! @warning -
//! @note -

NTSTATUS KeybdDeviceUsageNotificationCompletionRoutine(IN
PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {

PDEVICE_EXTENSION deviceExtension;

UNREFERENCED_PARAMETER(Context);

deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}

//
// On the way up, pagable might become clear. Mimic the driver below
us.
//
if (!(deviceExtension->NextLowerDriver->Flags & DO_POWER_PAGABLE)) {
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
}

return STATUS_SUCCESS;

}

//******************************************************************************
// KeybdDispatchPower
//! @brief Dispatch routine for power IRPs
//!
//! @param DeviceObject - pointer to the device object
//! @param Irp - pointer to the request packet
//! @return Status of success
//! @warning -
//! @note -

NTSTATUS KeybdDispatchPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP
Irp) {

PDEVICE_EXTENSION deviceExtension;

deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(deviceExtension->NextLowerDriver, Irp);

}

//******************************************************************************
// KeybdUnload
//! @brief Frees all of the allocated resources from DriverEntry
//!
//! @param DriverObject - pointer to driver object
//! @return -
//! @warning -
//! @note -

VOID KeybdUnload(IN PDRIVER_OBJECT DriverObject) {

PAGED_CODE();

//
// The device object(s) should be NULL now
// (since we unload, all the devices objects associated with this
// driver must be deleted.
//
ASSERT(DriverObject->DeviceObject == NULL);
return;

}

//******************************************************************************
// KeybdCreateControlObject
//! @brief Creates the control object
//!
//! @param DeviceObject - pointer to device object
//! @return Status of success
//! @warning -
//! @note -

NTSTATUS KeybdCreateControlObject(IN PDEVICE_OBJECT DeviceObject) {

UNICODE_STRING ntDeviceName;
UNICODE_STRING symbolicLinkName;
PCONTROL_DEVICE_EXTENSION deviceExtension;
NTSTATUS status;

PDEVICE_EXTENSION mainDeviceExtension;

ExAcquireFastMutexUnsafe(&ControlMutex);

//
// If this is a first instance of the device, then create a
controlobject
// and register dispatch points to handle ioctls.
//
if (1 == ++InstanceCount) {
//
// Initialize the unicode strings
//
RtlInitUnicodeString(&ntDeviceName, NTDEVICE_NAME_STRING);
RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING);

//
// Create a named deviceobject so that applications or drivers
// can directly talk to us without going through the entire
stack.
// This call could fail if there are not enough resources or
// another deviceobject of same name exists (name collision).
//
status = IoCreateDevice(DeviceObject->DriverObject,
sizeof(CONTROL_DEVICE_EXTENSION), &ntDeviceName, FILE_DEVICE_KEYBOARD,
FILE_DEVICE_SECURE_OPEN, FALSE, &ControlDeviceObject);

if (NT_SUCCESS(status)) {
ControlDeviceObject->Flags |= DO_BUFFERED_IO;

status = IoCreateSymbolicLink(&symbolicLinkName,
&ntDeviceName);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(ControlDeviceObject);
goto End;
}

deviceExtension = ControlDeviceObject->DeviceExtension;
deviceExtension->ControlData = NULL;

mainDeviceExtension = MainDeviceObject->DeviceExtension;
deviceExtension->NextLowerDriver =
mainDeviceExtension->NextLowerDriver;

ControlDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
}

End:

ExReleaseFastMutexUnsafe(&ControlMutex);
return status;

}

//******************************************************************************
// KeybdDeleteControlObject
//! @brief Deletes a control object
//!
//! @param -
//! @return -
//! @warning -
//! @note -

VOID KeybdDeleteControlObject() {

UNICODE_STRING symbolicLinkName;

ExAcquireFastMutexUnsafe(&ControlMutex);

//
// If this is the last instance of the device then delete the
controlobject
// and symbolic link to enable the pnp manager to unload the driver.
//
if (!(--InstanceCount) && ControlDeviceObject) {
RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING);

IoDeleteSymbolicLink(&symbolicLinkName);
IoDeleteDevice(ControlDeviceObject);
ControlDeviceObject = NULL;
}

ExReleaseFastMutexUnsafe(&ControlMutex);

}

//******************************************************************************
// KeybdDispatchIo
//! @brief Handles the I/O requests (and just passes the request on
if it
//! doesn't come from a control object
//!
//! @param DeviceObject - pointer to device object
//! @param Irp - pointer to the request packet
//! @return Status of success
//! @warning -
//! @note -

NTSTATUS KeybdDispatchIo(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {

PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
KIRQL currentIrql;

PAGED_CODE();

//
// Please note that this is a common dispatch point for
controlobject and
// filter deviceobject attached to the pnp stack.
//
if (DeviceObject != ControlDeviceObject) {
//
// We will just pass the request down as we are not interested in
handling
// requests that come on the PnP stack.
//
return KeybdPass(DeviceObject, Irp);
}

//
// Else this is targeted at our control deviceobject so let's handle
it.
// Here we will handle the IOCTl requests that come from the app.
//
status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);

switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
// User-mode application is attempting to obtain a handle to
the control object
break;

case IRP_MJ_CLOSE:
break;

case IRP_MJ_CLEANUP:
break;

case IRP_MJ_DEVICE_CONTROL:
deviceExtension = DeviceObject->DeviceExtension;
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_KEYBOARD_QUERY_INDICATORS:
return KeybdPass(DeviceObject, Irp);
break;

case IOCTL_KEYBOARD_SET_INDICATORS:
return KeybdPass(DeviceObject, Irp);
break;

default:
status = STATUS_INVALID_PARAMETER;
break;
}
break;

default:
break;
}

Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);

return status;

}

//******************************************************************************


Any thoughts on the code or questions above would be greatly
appreciated, as I have been stuck at this point of the driver for a
while now, and feel that once I get this problem fixed, the rest of my
development required should be comparatively straight forward
hopefully.

Thanks,
Kyzer


Re: Keyboard filter driver - obtaining keyboard indicator status by Kyzer

Kyzer
Thu Nov 24 00:06:35 CST 2005

Hi all,

As I'm currently more than a little confused as to how to solve my
problem, I have decided to include my driver code (below), and explain
exactly what I am attempting to do.

I am trying to send requests to a USB keyboard from an application (eg.
querying/setting LED indicators, sending characters to the keyboard,
etc). I understand that to do this, I need to create a control device
object in an upper filter driver so that the application may has access
to the keyboard. Then obviously via this control device object, I
would like to handle the requests. (A sample of the code from the
application is located in the first post on this thread).

>From the filter driver code below, here are a few questions that I
would like to pose - the answers of which may help me in getting a
solution to this problem:
1. Currently the control device object is of type FILE_DEVICE_KEYBOARD,
but should I be creating this as a different device type (and possibly
creating a new device interface) (ie. calling
IoRegisterDeviceInterface)?
2. Is the control device object created correctly, or should it be
created in a different location?
3. Should the control device object be attached to the device stack
differently (eg. in a similar way to the device object created in
AddDevice) so that I may pass the requests from the application lower
down the stack and receive the correct result?
4. Should I be using completion routines when receiving requests from
the application?

Below is the current filter driver code:


//******************************************************************************
//
//! @file filter.c
//
//******************************************************************************
// Include Files

#include "filter.h"

#include "ntstrsafe.h"

//******************************************************************************
// Definitions

#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, KeybdAddDevice)
#pragma alloc_text (PAGE, KeybdDispatchPnp)
#pragma alloc_text (PAGE, KeybdUnload)

#pragma alloc_text (PAGE, KeybdCreateControlObject)
#pragma alloc_text (PAGE, KeybdDeleteControlObject)
#pragma alloc_text (PAGE, KeybdDispatchIo)
#endif

PDEVICE_OBJECT MainDeviceObject = NULL;

FAST_MUTEX ControlMutex;
ULONG InstanceCount = 0;
PDEVICE_OBJECT ControlDeviceObject;

#define SYMBOLIC_NAME_STRING L"\\DosDevices\\KeybdUSB"
#define NTDEVICE_NAME_STRING L"\\Device\\KeybdUSB"

//******************************************************************************
// DriverEntry
//! @brief Installable driver initialisation entry point - called
directly by
//! the I/O system
//!
//! @param DriverObject - pointer to the driver object
//! @param RegistryPath - pointer to a string representing the path
to the
//! the driver-specific key in the registry
//! @return STATUS_SUCCESS if successful, or STATUS_UNSUCCESSFUL
otherwise
//! @warning -
//! @note -

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING
RegistryPath) {

NTSTATUS status = STATUS_SUCCESS;
ULONG ulIndex;
PDRIVER_DISPATCH *dispatch;

UNREFERENCED_PARAMETER(RegistryPath);

//
// Create dispatch points
//
for (ulIndex = 0, dispatch = DriverObject->MajorFunction;ulIndex <=
IRP_MJ_MAXIMUM_FUNCTION;ulIndex++, dispatch++) {
*dispatch = KeybdPass;
}

DriverObject->MajorFunction[IRP_MJ_PNP] = KeybdDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = KeybdDispatchPower;
DriverObject->DriverExtension->AddDevice = KeybdAddDevice;
DriverObject->DriverUnload = KeybdUnload;

//
// Set the following dispatch points as we will be doing
// something useful to these requests instead of just
// passing them down.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = KeybdDispatchIo;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KeybdDispatchIo;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = KeybdDispatchIo;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
KeybdDispatchIo;

//
// Mutex is to synchronize multiple threads creating & deleting
// control deviceobjects.
//
ExInitializeFastMutex(&ControlMutex);

return status;

}

//******************************************************************************
// KeybdAddDevice
//! @brief Creates a function device object to attach to the stack
//!
//! @param DriverObject - pointer to a device object
//! @param PhysicalDeviceObject - pointer to a device object created
by the
//! underlying bus driver
//! @return Status of success
//! @warning -
//! @note -

NTSTATUS KeybdAddDevice(IN PDRIVER_OBJECT DriverObject, IN
PDEVICE_OBJECT PhysicalDeviceObject) {

NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
ULONG deviceType = FILE_DEVICE_UNKNOWN;

PAGED_CODE();

//
// Create a filter device object.
//
status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
NULL, FILE_DEVICE_KEYBOARD, FILE_DEVICE_SECURE_OPEN, FALSE,
&MainDeviceObject);

if (!NT_SUCCESS(status)) {
//
// Returning failure here prevents the entire stack from
functioning,
// but most likely the rest of the stack will not be able to
create
// device objects either, so it is still OK.
//
return status;
}

deviceExtension =
(PDEVICE_EXTENSION)MainDeviceObject->DeviceExtension;
deviceExtension->NextLowerDriver =
IoAttachDeviceToDeviceStack(MainDeviceObject, PhysicalDeviceObject);

//
// Failure for attachment is an indication of a broken plug & play
system.
//
if (NULL == deviceExtension->NextLowerDriver) {
IoDeleteDevice(MainDeviceObject);
MainDeviceObject = NULL;
return STATUS_UNSUCCESSFUL;
}

MainDeviceObject->Flags |= deviceExtension->NextLowerDriver->Flags &
(DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
MainDeviceObject->DeviceType =
deviceExtension->NextLowerDriver->DeviceType;
MainDeviceObject->Characteristics =
deviceExtension->NextLowerDriver->Characteristics;
deviceExtension->Self = MainDeviceObject;

//
// Set the initial state of the Filter DO
//
INITIALIZE_PNP_STATE(deviceExtension);

MainDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

return STATUS_SUCCESS;

}

//******************************************************************************
// KeybdPass
//! @brief Default dispatch routing
//!
//! @param DeviceObject - pointer to a device o