How to send requests to HID USB device from WDF UMDF 2.15 hid minidriver?

I have a HID-USB device that shows up in Device Manager under “Human
Interface Devices” as both a HID compliant vendor defined service and a USB
input device. I have written a WDF UMDF 2.15 virtual hidmini driver, based
on the vhidmini2 sample driver, that masquerades as both the device and the
system that the device connects to. The driver successfully interacts with
the user application, written for the device, such that the software thinks
it is attached to the device and communicating with the system to which the
device would be attached. I now want to have the virtual hidmini driver act
as a filter driver for the device default driver stack (no vendor supplied
driver is required) so that request commands not native to the device
(intended for an alternate device) can be translated into a compatible
format and responses from the device translated into the format that the
user app is expecting. This is necessary because the user app supports two
different devices and uses the alternate device for what it considers to be
“enhanced” commands. However, the device that I have can support at least a
subset of these “enhanced” commands.

I install my driver to the HID component of the device, leaving the USB
component intact. I/O from the user app is sent to my driver as it should
be. I now want to send new translated write requests to the device and
retrieve the responses with Read requests. Can this be done using
WdfDeviceGetIoTarget, WdfRequestCreate,
WdfUsbTargetPipeFormatRequestForWrite(Read) and WdfRequestSend and does the
UMDF 2.15 directive UmdfDispatcher = NativeUSB need to be set in the INF
file for this to work?

If the WdfRequestCreate method can be used, will setting the IoTarget to
NULL automatically obtain the drivers default IoTarget and thereby make
WdfDeviceGetIoTarget unnecessary?

Any help would be greatly appreciated.

If you are filtering the HID component (the child enumerated by hidclass/hidusb) you do not use any USB constructs. The usb constructs stop at the usb hid miniport one layer above in the parent. You cannot just use GetIoTarget either as this part of the HID stack requires you have a valid file handle for IO (WdfIoTargetOpen), not just the pointer to the attached device object (which is what GetIoTarget boils down to). Once you have a valid file handle you can send generic reads and writes.

If you require USB constructs you need to put your device lower filter below hidusb. When you do that you will see URBs flow through the stack and you can access USB’isms. Your filter must be KMDF at this point as you can’t have UMDF sitting below a KM driver.

d

From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Randy Lewis
Sent: Monday, February 22, 2016 6:38 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] How to send requests to HID USB device from WDF UMDF 2.15 hid minidriver?

I have a HID-USB device that shows up in Device Manager under “Human Interface Devices” as both a HID compliant vendor defined service and a USB input device. I have written a WDF UMDF 2.15 virtual hidmini driver, based on the vhidmini2 sample driver, that masquerades as both the device and the system that the device connects to. The driver successfully interacts with the user application, written for the device, such that the software thinks it is attached to the device and communicating with the system to which the device would be attached. I now want to have the virtual hidmini driver act as a filter driver for the device default driver stack (no vendor supplied driver is required) so that request commands not native to the device (intended for an alternate device) can be translated into a compatible format and responses from the device translated into the format that the user app is expecting. This is necessary because the user app supports two different devices and uses the alternate device for what it considers to be “enhanced” commands. However, the device that I have can support at least a subset of these “enhanced” commands.

I install my driver to the HID component of the device, leaving the USB component intact. I/O from the user app is sent to my driver as it should be. I now want to send new translated write requests to the device and retrieve the responses with Read requests. Can this be done using WdfDeviceGetIoTarget, WdfRequestCreate, WdfUsbTargetPipeFormatRequestForWrite(Read) and WdfRequestSend and does the UMDF 2.15 directive UmdfDispatcher = NativeUSB need to be set in the INF file for this to work?

If the WdfRequestCreate method can be used, will setting the IoTarget to NULL automatically obtain the drivers default IoTarget and thereby make WdfDeviceGetIoTarget unnecessary?

Any help would be greatly appreciated.


NTDEV is sponsored by OSR

Visit the list online at: http:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

Wow, a reply from Doron Holan, I feel blessed!

Thanks for the reply. Am I understanding correctly that I should use WdfIoTargetOpen to get a handle to the device and then use WdfRequestCreate and WdfRequestSend to communicate with the device and should I remove the directive UmdfDispatcher=NativeUSB from the INF file? The data packet that my device expects to receive and returns is simply 17 bytes with the first byte being the devices HID Report ID and the rest are a device specific command format. The data packet that I obtain from the user app could in fact be passed on to the device without any changes when it’s in the correct command format. And the data packet that I should receive from the device could then be passed back to the app without changes. However, some of the packets from the user app are not in the correct command format (they are intended for a different device) and need to be translated into the device’s format and the response from the device will not be in the format that the app is expecting for those commands. The translation of those cases is what my driver will do.

Randy

Yes, remove UmdfDispatcher=NativeUSB. I can’t remember exactly, but I think the hid miniport is driver that writes out the report id to the first byte of the payload. If that is correct, it doesn’t matter what you change in your hid filter as it would be overwritten by the miniport. This should be easily proven one way or the other

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@cox.net
Sent: Monday, February 22, 2016 10:20 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] How to send requests to HID USB device from WDF UMDF 2.15 hid minidriver?

Wow, a reply from Doron Holan, I feel blessed!

Thanks for the reply. Am I understanding correctly that I should use WdfIoTargetOpen to get a handle to the device and then use WdfRequestCreate and WdfRequestSend to communicate with the device and should I remove the directive UmdfDispatcher=NativeUSB from the INF file? The data packet that my device expects to receive and returns is simply 17 bytes with the first byte being the devices HID Report ID and the rest are a device specific command format. The data packet that I obtain from the user app could in fact be passed on to the device without any changes when it’s in the correct command format. And the data packet that I should receive from the device could then be passed back to the app without changes. However, some of the packets from the user app are not in the correct command format (they are intended for a different device) and need to be translated into the device’s format and the response from the device will not be in the format that the app is expecting for those commands. The translation of those cases is what my driver will do.

Randy


NTDEV is sponsored by OSR

Visit the list online at: https:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:></https:>

Thanks. I thought I had a clear path to victory but now I’m hung up with the TargetDeviceName needed as an input to the WDF_IO_TARGET_OPEN_PARAMS structure used by the WdfIoTargetOpen method. I assume this would be the system assigned PDO Object Name that I can find in Device Manager for the USB component, which is \Device\USBPDO-9. I’m guessing this is not a constant, however, and I have no idea how to retrieve it at load time. I’ve tried to use it anyway and ran into a problem with the Unicode string functions such as RtlUnicodeStringInit, which are defined in Ntstrsafe.h. Apparently, this header file has some of the same macros as other header files already included and Visual Studio throws up hundreds of error messages when I include it. I’ve spent months getting to this point researching Wdf documents and resolving driver related issues and I don’t want to fight with the compiler too!

Is there a straightforward way to obtain the TargetDeviceName and convert it to a Unicode string?

You can enable your own custom device interface and open it

Sent from my Windows 10 phone

From: xxxxx@cox.netmailto:xxxxx
Sent: Monday, February 22, 2016 5:35 PM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: RE:[ntdev] How to send requests to HID USB device from WDF UMDF 2.15 hid minidriver?

Thanks. I thought I had a clear path to victory but now I’m hung up with the TargetDeviceName needed as an input to the WDF_IO_TARGET_OPEN_PARAMS structure used by the WdfIoTargetOpen method. I assume this would be the system assigned PDO Object Name that I can find in Device Manager for the USB component, which is \Device\USBPDO-9. I’m guessing this is not a constant, however, and I have no idea how to retrieve it at load time. I’ve tried to use it anyway and ran into a problem with the Unicode string functions such as RtlUnicodeStringInit, which are defined in Ntstrsafe.h. Apparently, this header file has some of the same macros as other header files already included and Visual Studio throws up hundreds of error messages when I include it. I’ve spent months getting to this point researching Wdf documents and resolving driver related issues and I don’t want to fight with the compiler too!

Is there a straightforward way to obtain the TargetDeviceName and convert it to a Unicode string?


NTDEV is sponsored by OSR

Visit the list online at: https:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:></https:></mailto:xxxxx></mailto:xxxxx>

Am I at least getting close to communicating with the device with the following:

WDFIOTARGET myDevice;
NTSTATUS myStatus;
WDFREQUEST myRequest;
WDF_IO_TARGET_OPEN_PARAMS myParams;
UNICODE_STRING myDeviceName;
BOOL requestSent = FALSE;

myDeviceName.Buffer = L"\Device\USBPDO-9";
myDeviceName.Length = sizeof(myDeviceName.Buffer);
myDeviceName.MaximumLength = myDeviceName.Length + sizeof(WCHAR);

// RtlUnicodeStringInit(&myDeviceName, “\Device\USBPDO-9”); // can’t use because required header file Wdm.h conflicts with other headers

WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME(
&myParams,
&myDeviceName,
GENERIC_READ | GENERIC_WRITE);

// myParams.Type = WdfIoTargetOpenByName; // initialized with above
myParams.EvtIoTargetQueryRemove = NULL;
myParams.EvtIoTargetRemoveCanceled = NULL;
myParams.EvtIoTargetRemoveComplete = NULL;
// myParams.DesiredAccess = GENERIC_READ | GENERIC_WRITE; // initialized with above
// myParams.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE; // ditto
// myParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; // ditto
// myParams.FileName = NULL; // ditto

// myDevice = WdfDeviceGetIoTarget(QueueContext->DeviceContext->Device); // can’t use this
myStatus = WdfIoTargetCreate(QueueContext->DeviceContext->Device, WDF_NO_OBJECT_ATTRIBUTES, &myDevice);
KdPrint((“IoTargetCreate returned: status = %x, IoTarget handle = %x\n”, myStatus, myDevice));
if (NT_SUCCESS(myStatus))
myStatus = WdfIoTargetOpen(myDevice, &myParams);
KdPrint((“IoTargetOpen returned: %x\n”, myStatus));
if (myDevice != NULL)
{
myStatus = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, myDevice, &myRequest);

if (NT_SUCCESS(myStatus))
{
requestSent = WdfRequestSend(myRequest, myDevice, NULL);
KdPrint((“WriteReport request for IO Target returned: %x, %x, %x\n”, myDevice, myStatus, requestSent));
WdfObjectDelete(myRequest);
}
}

In the above, I get a handle to the device (or something) but WdfIoTargetOpen(myDevice, &myParams) fails with 0xc000000d (invalid parameters). Why is any of this necessary? It seems to me that I should be able to just modify the WriteFile Request that I receive from the user app and pass it back to the framework (without completion) to continue on down the driver stack to the device as it would if my driver was not present. I tried modifying the associated event handler to have it do nothing but this did not result in anything being passed to the device.

Yes, you can modify the writes as they oasd through your driver if you want to use the file handle opened by the app

Sent from my Windows 10 phone

From: xxxxx@cox.netmailto:xxxxx
Sent: Tuesday, February 23, 2016 6:37 AM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: RE:[ntdev] How to send requests to HID USB device from WDF UMDF 2.15 hid minidriver?

Am I at least getting close to communicating with the device with the following:

WDFIOTARGET myDevice;
NTSTATUS myStatus;
WDFREQUEST myRequest;
WDF_IO_TARGET_OPEN_PARAMS myParams;
UNICODE_STRING myDeviceName;
BOOL requestSent = FALSE;

myDeviceName.Buffer = L"\Device\USBPDO-9<file:>";
myDeviceName.Length = sizeof(myDeviceName.Buffer);
myDeviceName.MaximumLength = myDeviceName.Length + sizeof(WCHAR);

// RtlUnicodeStringInit(&myDeviceName, “\Device\USBPDO-9”); // can’t use because required header file Wdm.h conflicts with other headers

WDF_IO_TARGET_OPEN_PARAMS_INIT_CREATE_BY_NAME(
&myParams,
&myDeviceName,
GENERIC_READ | GENERIC_WRITE);

// myParams.Type = WdfIoTargetOpenByName; // initialized with above
myParams.EvtIoTargetQueryRemove = NULL;
myParams.EvtIoTargetRemoveCanceled = NULL;
myParams.EvtIoTargetRemoveComplete = NULL;
// myParams.DesiredAccess = GENERIC_READ | GENERIC_WRITE; // initialized with above
// myParams.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE; // ditto
// myParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; // ditto
// myParams.FileName = NULL; // ditto

// myDevice = WdfDeviceGetIoTarget(QueueContext->DeviceContext->Device); // can’t use this
myStatus = WdfIoTargetCreate(QueueContext->DeviceContext->Device, WDF_NO_OBJECT_ATTRIBUTES, &myDevice);
KdPrint((“IoTargetCreate returned: status = %x, IoTarget handle = %x\n”, myStatus, myDevice));
if (NT_SUCCESS(myStatus))
myStatus = WdfIoTargetOpen(myDevice, &myParams);
KdPrint((“IoTargetOpen returned: %x\n”, myStatus));
if (myDevice != NULL)
{
myStatus = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, myDevice, &myRequest);

if (NT_SUCCESS(myStatus))
{
requestSent = WdfRequestSend(myRequest, myDevice, NULL);
KdPrint((“WriteReport request for IO Target returned: %x, %x, %x\n”, myDevice, myStatus, requestSent));
WdfObjectDelete(myRequest);
}
}

In the above, I get a handle to the device (or something) but WdfIoTargetOpen(myDevice, &myParams) fails with 0xc000000d (invalid parameters). Why is any of this necessary? It seems to me that I should be able to just modify the WriteFile Request that I receive from the user app and pass it back to the framework (without completion) to continue on down the driver stack to the device as it would if my driver was not present. I tried modifying the associated event handler to have it do nothing but this did not result in anything being passed to the device.


NTDEV is sponsored by OSR

Visit the list online at: https:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:></https:></file:></mailto:xxxxx></mailto:xxxxx>

I inserted a WdfIoTargetGetState command before and after the WdfIoTargetOpen command and to my surprise it returned a value of 1 (WdfIoTargetStarted) before the attempt to Open and a value of 4 (WdfIoTargetClosed) after the attempt to Open (which fails). Does the value of 1 mean that the device was ready to receive I/O even before trying to open it?

A newly created iotarget is in the started state

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@cox.net
Sent: Tuesday, February 23, 2016 9:57 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] How to send requests to HID USB device from WDF UMDF 2.15 hid minidriver?

I inserted a WdfIoTargetGetState command before and after the WdfIoTargetOpen command and to my surprise it returned a value of 1 (WdfIoTargetStarted) before the attempt to Open and a value of 4 (WdfIoTargetClosed) after the attempt to Open (which fails). Does the value of 1 mean that the device was ready to receive I/O even before trying to open it?


NTDEV is sponsored by OSR

Visit the list online at: https:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:></https:>

I got to thinking that the “virtual device” that my driver creates when the actual device in not connected is still being created even when I insert the driver into the actual device’s driver stack. Is that what my QueueContext->DeviceContext->Device points to even when the actual device is installed? Is this why I have to use remote IO target methods to get a handle to the actual device?

I can’t answer, it is your code. You only need the remote io target in the HID filter if you want to talk with the device “on your own” outside of the context of IO sent on someone else’s (ie the app) handle.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@cox.net
Sent: Tuesday, February 23, 2016 12:24 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] How to send requests to HID USB device from WDF UMDF 2.15 hid minidriver?

I got to thinking that the “virtual device” that my driver creates when the actual device in not connected is still being created even when I insert the driver into the actual device’s driver stack. Is that what my QueueContext->DeviceContext->Device points to even when the actual device is installed? Is this why I have to use remote IO target methods to get a handle to the actual device?


NTDEV is sponsored by OSR

Visit the list online at: https:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:></https:>

I added the following code to my driver hoping to pass an unmodified Request to the device, and succeeded in getting “something” to the device (based on snooping the USB traffic for the device) but the device was apparently unable to interpret this information (nor could I) and did not respond as desired. I suspect that the framework’s repackaging of the Request prior to sending it to my driver has made it useless for sending on to the device. It seems like this should be a simple thing for a driver to do for the device that it was intended for. I suspect all these problems have to do with the mshidumdf.sys minidriver that sits between my driver and hidclass.sys. Would it make things any easier if I replace the system supplied mshidumdf.sys with the user supplied version hidumdf.sys, which I could then modify as needed to make this work? If not, I’m thinking of giving up on the UMDF hidmini driver approach (after months of working on it) and writing a UMDF filter driver. What would be a good sample model from which to start if I go this route?

UCHAR myBuffer[128];
ULONG myBufferLen = 128;
ULONG numBytesReturned = 0;
WDF_REQUEST_SEND_OPTIONS options;
WDF_REQUEST_PARAMETERS params;

WDF_REQUEST_PARAMETERS_INIT(&params);
WdfRequestGetParameters(Request, &params);
WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
options.Timeout = 10000; // nano sec

localIoTarget = WdfDeviceGetIoTarget(QueueContext->DeviceContext->Device); // obtain handle to local I/O Target
if (localIoTarget)
{
WdfRequestFormatRequestUsingCurrentType(Request);
requestSent = WdfRequestSend(Request, localIoTarget, &options);
if(requestSent == TRUE)
KdPrint((“Forward request to local IO Target returned: Handle: %x, Sent: %s\n”, localIoTarget, “TRUE”));
else
KdPrint((“Forward request to local IO Target returned: Handle: %x, Sent: %s\n”, localIoTarget, “FALSE”));
}

xxxxx@cox.net wrote:

I added the following code to my driver hoping to pass an unmodified Request to the device, and succeeded in getting “something” to the device (based on snooping the USB traffic for the device) but the device was apparently unable to interpret this information (nor could I) and did not respond as desired.

Depending on where you are in the HID stack, you see very different
things. What are you processing here? Ioctls? Reads and writes?

By the way, your timeout value here is way off:

WDF_REQUEST_SEND_OPTIONS_INIT(&options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
options.Timeout = 10000; // nano sec

The Timeout value has the traditional non-intuitive Windows kernel
meaning. A positive value indicates absolute time. What you have
specified here actually sets a timeout on January 1, 1601, which of
course will immediately expire. To get a time relative to now, you need
to use a negative value, in units of 100 nanoseconds.

The best way to specify this is to use the macros. If you want 100ms
timeout:

options.Timeout = WDF_REL_TIMEOUT_IN_MSEC(100);

I suspect that the framework’s repackaging of the Request prior to sending it to my driver has made it useless for sending on to the device.

Doubtful. It’s just not that complicated to pass a request on to the
next driver.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim, thanks for your comments on this. With regards to the timeout value, I’m glad you pointed that out even though it’s not currently being used. As for what I’m processing, my driver is a WDF UMDF 2.15 hid minidriver created from the virtual vhiidmini2 sample model. All requests are repackaged by the framework into IOCTLs with the events of interest (to me) defined by IOCTL_HID_READ_REPORT and IOCTL_HID_WRITE_REPORT. A user app WriteFile request will generate a IOCTL_HID_WRITE_REPORT which is passed to the default queue and immediately handled by the driver. User app ReadFile requests never get passed directly to my driver (this conclusion is based on hours of trial and error experimenting). I’ve concluded that the framework periodically sends a IOCTL_HID_READ_REPORT requests (this happens even when the user app is not running), which get forwarded into a manual queue that is controlled by a periodic timer. The timer initiates retrieval of requests, which when completed by the driver somehow end up being passed to the user app if it has made a ReadFile request. How this happens is a mystery to me. What I want to do with this driver is to translate some of the commands sent by the user app (which are intended for a different device) into those that the device I am using can process. Then when my device responds I need to translate the response into a format that the user app is expecting from the other device. What I have accomplished so far is to get the driver to successfully interact with the user app by masquerading as the other device with no actual device installed. When data from a WriteFile is received I compose an appropriate response, copy the data to and complete one of the queued IOCTL_HID_READ_REPORT requests (it doesn’t seem to matter which one I respond to, the user app ends up getting the response data). What still needs to be accomplished is to communicate with the device I have when it is installed. I am overwhelmed by all the WDF function choices and can’t figure out how to do this.