Keyboard filter driver - obtaining keyboard indicator status

Discussion in 'Windows Vista Drivers' started by Kyzer, Nov 21, 2005.

  1. Kyzer

    Kyzer Guest

    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
     
    Kyzer, Nov 21, 2005
    #1
    1. Advertisements

  2. Keyboard is monopolistically opened by USER32, use the USER32 APIs to get
    the LED state.
     
    Maxim S. Shatskih, Nov 21, 2005
    #2
    1. Advertisements

  3. 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.
     
    Robert Marquardt, Nov 21, 2005
    #3
  4. Kyzer

    Kyzer Guest

    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
     
    Kyzer, Nov 21, 2005
    #4
  5. Sorry, i am no driver specialist. You will have to find someone else to
    help you with that.
     
    Robert Marquardt, Nov 22, 2005
    #5
  6. He could catch and strore the LED report written in the filter driver
    He will need the second device object to open in this case.
     
    Maxim S. Shatskih, Nov 22, 2005
    #6
  7. Kyzer

    Kyzer Guest

    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
     
    Kyzer, Nov 23, 2005
    #7
  8. Kyzer

    Kyzer Guest

    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).
    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
     
    Kyzer, Nov 24, 2005
    #8
  9. Kyzer

    Kyzer Guest

    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).
    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
     
    Kyzer, Nov 24, 2005
    #9
  10. Please go thru the toaster filter sample in the DDK. It shows how to create
    a control-device and interact from application.

    You can also use WMI to talk to your filter driver. The firefly sample in
    the DDK demonstrate how to do that.

    http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q262305

    --
    --
    -Eliyas
    This posting is provided "AS IS" with no warranties, and confers no rights.
    http://www.microsoft.com/whdc/driver/default.mspx
    http://www.microsoft.com/whdc/driver/kernel/KB-drv.mspx



     
    Eliyas Yakub [MSFT], Nov 24, 2005
    #10
  11. Kyzer

    Kyzer Guest

    Thanks for your response. The filter driver that I've created is based
    on the content in the toaster filter driver sample, and the control
    device object is created in the same way as that shown in the link from
    the Microsoft website posted previously.

    Currently my control device object has a device type of
    FILE_DEVICE_KEYBOARD - is this correct or should it be something
    different? Related to this, should I be registering a device
    interface? (I assume I shouldn't be because the device type of the
    control device is a keyboard and subseuqently already exists).

    Secondly, the DeviceIoControl function calls from the application are
    received by the filter driver's control object correctly, but are not
    being executed properly in the driver as I believe that they are not
    being passed down the stack correctly. How should this be done
    properly?....with completion routines?....or does something extra have
    to be done when creating the control object to what I have done and
    what is displayed in the toaster filter sample?
     
    Kyzer, Nov 25, 2005
    #11
  12. Currently my control device object has a device type of
    FILE_DEVICE_KEYBOARD is fine. It's doesn't really matter what you use as the
    device-type for non-storage related devices.
    You can't register device-interface on control-device. You could do that on
    the filter-device object - you create in the AddDevice - but it's not useful
    because the class driver already registers an interface for the stack.
    As far as the system is concerned, control-device and pnp-device are
    independnt devices. As a result, irps received on the control-device cannot
    be forwarded down to pnp-device, because 1) they don't have enough stack
    locations 2) in general, it's not appropriate to forward an IRP sent to a
    control-device to a pnp-stack because you could run into synchronization
    issues when the pnp stack is undergoing state changes.
    You could fix the DeviceObject->StackSize to make sure the deviceobject has
    enough stack location to forward the IRP down. Dealing with pnp
    synchronization is little tricky. You have to pay attention to pnp-state of
    the filter-device before you forward the IRP down.
     
    Eliyas Yakub [MSFT], Nov 25, 2005
    #12
  13. Kyzer

    Kyzer Guest

    Thanks for your response - it has given me a bit more understanding on
    the problem. I have had one thought regarding the problem and am
    wondering if it is viable. Is it possible that if an IRP is received
    on the control device, it can then create a new IRP for the PnP device
    that can then be passed down the stack and return a valid result? If
    this is viable, how would it be done?

    Thanks.
     
    Kyzer, Nov 28, 2005
    #13
  14. It's possible but then how is it going to be different from forwarding the
    one you got on control-device. With this approach, you are 1) creating more
    overhead in terms of allocating another IRP (proxy request) everytime 2)
    another point of failure in your code 3) you have to pend the original
    request in a cancelable state and deal with synchronization between the
    completion routine of the proxy request and cancel-routine of the pended
    request 4) cancel and wait for the proxy request to complete when the pnp
    stack is removed. All this is tricky. You could eliminate 1 and 2 by
    preallocating IRPs.

    However, if you would like to still create proxy IRPs, there are plenty of
    examples in http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q326315
    and Walter Oney's WDM book.

    --
     
    Eliyas Yakub [MSFT], Nov 28, 2005
    #14
  15. Yes you can.
     
    Maxim S. Shatskih, Nov 28, 2005
    #15
  16. Kyzer

    Kyzer Guest

    Thanks for your thoughts - and sorry about the delay with this
    response. I have looked at the examples and have had small successes
    with querying and setting the keyboard LED indicators (ie. QUERY - I
    receive data but it doesn't appear to be correct, SET - occasionally it
    works properly but it often also crashes the computer). I assume these
    problems are related to synchronisation as explained previously, which
    I am still looking into.

    However, I have another question: I am attempting to write characters
    to the keyboard (by creating a new IRP_MJ_WRITE request from within the
    filter driver and passing it to the lower driver). But when I pass
    this request down the stack, I receive an error of
    ERROR_INVALID_FUNCTION. From what I understand of this error, the
    drivers in the stack don't support this request, so how is it possible
    to read and write data to the keyboard? Is there a different request
    that is sent to emulate a keypress on a keyboard?

    I look forward to reading the responses.

    Kyzer
     
    Kyzer, Dec 6, 2005
    #16
  17. you do not write characters to the keyboard. if you want to emulate/inject
    a keypresses independent of keyboard, i suggest a virtual keyboard. if you
    want to write data to the 8042 controller, see the IOCTLs in ntdd8042.h and
    then look them up in the DDK. the keyboard stack does not support
    IRP_MJ_WRITE.

    d
     
    Doron Holan [MS], Dec 6, 2005
    #17
  18. Use SendInput instead, this is a correct way.
     
    Maxim S. Shatskih, Dec 6, 2005
    #18
  19. Kyzer

    Kyzer Guest

    Thanks for your response. Because the keyboard is USB, writing data to
    the 8042 controller isn't an option for me. To explain briefly, my
    keyboard originally was PS2 but is connected with a PS2 to USB
    converter - thereby making it a 'USB' keyboard. I need to send data
    directly to the keyboard from an application, and depending on the data
    sent to the keyboard, it may send data back. Therefore how can I send
    data to the keyboard and intercept the response?

    An example is if I send the bytes 0xED then 0x07, the three LED
    indicators should turn on, but I don't think that sending the
    keypresses of 0xED then 0x07 is equivalent to sending the bytes
    directly to the keyboard.

    At the moment I have an upper filter driver for the keyboard stack with
    a control device object that I can access from my user-mode application
    - if that is of any use. Help on this would be greatly appreciated as
    at the moment it feels as though I am going around in circles trying to
    work out how I have to do this.

    Thanks.
     
    Kyzer, Dec 6, 2005
    #19
  20. Filter driver can be a solution. Filter driver with a separate second
    device object which will be the target of IOCTLs from user mode.
     
    Maxim S. Shatskih, Dec 6, 2005
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.