HID miniport driver feature request handling

Hi,

I have a few questions on the HidUsbFx2 HID miniport driver sample in the WDK. The driver sets up its IO queue type as WdfIoQueueDispatchParallel.

For dispatch type parallel, I see this in MSDN documentation:

“If the driver forwards the request to a general I/O target, it typically calls one of the I/O target object’s asynchronous methods”

However, when the sample driver receives IOCTL_HID_GET_FEATURE, it is calling the USB I/O target’s sychronous method “WdfUsbTargetDeviceSendControlTransferSynchronously”. Few questions:

  1. Is the sample implementation correct? In other words, shouldn’t it be calling async method on the I/O target? Is it OK to call a synchronous method as well?
  2. In my HID miniport driver’s case, the request gets sent down to a PCI device after registering for a completion routine. Within the IOCTL_HID_GET_FEATURE call, can I wait on a synchronization object until the device responds back? From the completion routine, I can signal the synchronization object and return control back to the HID client.
  3. Is it possible that a HID miniport driver can receive more than one get/set feature requests?

Thanks in advance!
-Sai

xxxxx@intel.com wrote:

I have a few questions on the HidUsbFx2 HID miniport driver sample in the WDK. The driver sets up its IO queue type as WdfIoQueueDispatchParallel.

For dispatch type parallel, I see this in MSDN documentation:

“If the driver forwards the request to a general I/O target, it typically calls one of the I/O target object’s asynchronous methods”

However, when the sample driver receives IOCTL_HID_GET_FEATURE, it is calling the USB I/O target’s sychronous method “WdfUsbTargetDeviceSendControlTransferSynchronously”. Few questions:

  1. Is the sample implementation correct? In other words, shouldn’t it be calling async method on the I/O target? Is it OK to call a synchronous method as well?

Sure, it’s OK. The fact that it’s in a parallel queue just means that
other requests can arrive while we’re processing this one.

  1. In my HID miniport driver’s case, the request gets sent down to a PCI device after registering for a completion routine. Within the IOCTL_HID_GET_FEATURE call, can I wait on a synchronization object until the device responds back? From the completion routine, I can signal the synchronization object and return control back to the HID client.

You can wait. You do need to be be aware that the request cannot be
canceled while you are holding it. However, from a coding perspective,
it’s usually not any more difficult to move your client completion code
into your IRP completion routine. It’s the difference between:

RequestHandler() {
WdfRequestSetCompletionRoutine( NewRequest );
WdfRequestSend( NewRequest );
…Wait…
WdfRequestComplete( Request );
}
CompletionHandler() {
…Signal synchronization primitive …
}

and

RequestHandler() {
WdfRequestForwardToIoQueue( Request, some_manual_queue );
WdfRequestSetCompletionRoutine( NewRequest );
WdfRequestSend( NewRequest );
}
CompletionHandler() {
WdfIoQueueRetrieveNextRequest( some_manual_queue, OriginalRequest );
WdfRequestComplete( OriginalRequest );
}

  1. Is it possible that a HID miniport driver can receive more than one get/set feature requests?

Yes, they aren’t serialized.


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

Thanks Tim, appreciate your response.

Let’s say I have a Top Level collection with 2 or more feature reports.

If choose the approach of forwarding to a manual queue, can you please look at this scenario and let me know your suggestion?

  1. Driver receives the first get_report request. Driver forwards the request to a manual queue, sets completion routine, sends the request down and returns status_pending.
  2. Driver gets a second get_report request (the report id and report size could be different for this one). Driver also forwards this request (to the same manual queue as above), sets completion routine, sends the request down and returns status_pending.
  3. At this point, driver has 2 requests in the manual queue. Now, when the completion routine gets called, I wouldn’t know if the completion was for the first get_report request or the second one that was sent down. Sample code shows how to call WdfIoQueueRetrieveNextRequest to retrieve the request from the queue. However, the queue element that I retrieve is expected to be for the first request but the completion can happen for either one. How do I make sure I am completing the correct get_feature request? I can possibly look at report id in completion routine. But then, is there a way to iterate through the manual queue and retrieve the appropriate request?

Thanks,
-Sai

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Friday, February 21, 2014 3:46 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] HID miniport driver feature request handling

xxxxx@intel.com wrote:

I have a few questions on the HidUsbFx2 HID miniport driver sample in the WDK. The driver sets up its IO queue type as WdfIoQueueDispatchParallel.

For dispatch type parallel, I see this in MSDN documentation:

“If the driver forwards the request to a general I/O target, it typically calls one of the I/O target object’s asynchronous methods”

However, when the sample driver receives IOCTL_HID_GET_FEATURE, it is calling the USB I/O target’s sychronous method “WdfUsbTargetDeviceSendControlTransferSynchronously”. Few questions:

  1. Is the sample implementation correct? In other words, shouldn’t it be calling async method on the I/O target? Is it OK to call a synchronous method as well?

Sure, it’s OK. The fact that it’s in a parallel queue just means that other requests can arrive while we’re processing this one.

  1. In my HID miniport driver’s case, the request gets sent down to a PCI device after registering for a completion routine. Within the IOCTL_HID_GET_FEATURE call, can I wait on a synchronization object until the device responds back? From the completion routine, I can signal the synchronization object and return control back to the HID client.

You can wait. You do need to be be aware that the request cannot be canceled while you are holding it. However, from a coding perspective, it’s usually not any more difficult to move your client completion code into your IRP completion routine. It’s the difference between:

RequestHandler() {
WdfRequestSetCompletionRoutine( NewRequest );
WdfRequestSend( NewRequest );
…Wait…
WdfRequestComplete( Request );
}
CompletionHandler() {
…Signal synchronization primitive …
}

and

RequestHandler() {
WdfRequestForwardToIoQueue( Request, some_manual_queue );
WdfRequestSetCompletionRoutine( NewRequest );
WdfRequestSend( NewRequest );
}
CompletionHandler() {
WdfIoQueueRetrieveNextRequest( some_manual_queue, OriginalRequest );
WdfRequestComplete( OriginalRequest );
}

  1. Is it possible that a HID miniport driver can receive more than one get/set feature requests?

Yes, they aren’t serialized.


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


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Paithara Balagangadhara, Sai Prasad wrote:

  1. At this point, driver has 2 requests in the manual queue. Now, when the completion routine gets called, I wouldn’t know if the completion was for the first get_report request or the second one that was sent down. Sample code shows how to call WdfIoQueueRetrieveNextRequest to retrieve the request from the queue. However, the queue element that I retrieve is expected to be for the first request but the completion can happen for either one. How do I make sure I am completing the correct get_feature request?

The way you do that is to define a context structure for the request
you’re going to queue that contains, for example, the WDFREQUEST handle
of the newly created request. Then, in the completion routine, you use
WdfIoQueueFindRequest (which leaves the request in the queue) to search
through the manual queue to find the one that has a match in the
context, and WdfIoQueueRetrieveFoundRequest to remove it.

In my humble opinion, one of the few shortcomings in KMDF is that there
is no WdfIoQueueRetrieveExactlyThisRequest function. I end up having to
use this workaround more often than I would have expected.


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

Hi Tim,

Can you elaborate on this: “request cannot be cancelled while you are holding it”? How is this different in either option (with or without forwarding to a manual queue)?

Thanks,
-Sai

On Feb 21, 2014, at 3:46 PM, “Tim Roberts” wrote:

> xxxxx@intel.com wrote:
>> I have a few questions on the HidUsbFx2 HID miniport driver sample in the WDK. The driver sets up its IO queue type as WdfIoQueueDispatchParallel.
>>
>> For dispatch type parallel, I see this in MSDN documentation:
>>
>> “If the driver forwards the request to a general I/O target, it typically calls one of the I/O target object’s asynchronous methods”
>>
>> However, when the sample driver receives IOCTL_HID_GET_FEATURE, it is calling the USB I/O target’s sychronous method “WdfUsbTargetDeviceSendControlTransferSynchronously”. Few questions:
>>
>> 1. Is the sample implementation correct? In other words, shouldn’t it be calling async method on the I/O target? Is it OK to call a synchronous method as well?
>
> Sure, it’s OK. The fact that it’s in a parallel queue just means that
> other requests can arrive while we’re processing this one.
>
>
>> 2. In my HID miniport driver’s case, the request gets sent down to a PCI device after registering for a completion routine. Within the IOCTL_HID_GET_FEATURE call, can I wait on a synchronization object until the device responds back? From the completion routine, I can signal the synchronization object and return control back to the HID client.
>
> You can wait. You do need to be be aware that the request cannot be
> canceled while you are holding it. However, from a coding perspective,
> it’s usually not any more difficult to move your client completion code
> into your IRP completion routine. It’s the difference between:
>
> RequestHandler() {
> WdfRequestSetCompletionRoutine( NewRequest );
> WdfRequestSend( NewRequest );
> …Wait…
> WdfRequestComplete( Request );
> }
> CompletionHandler() {
> …Signal synchronization primitive …
> }
>
> and
>
> RequestHandler() {
> WdfRequestForwardToIoQueue( Request, some_manual_queue );
> WdfRequestSetCompletionRoutine( NewRequest );
> WdfRequestSend( NewRequest );
> }
> CompletionHandler() {
> WdfIoQueueRetrieveNextRequest( some_manual_queue, OriginalRequest );
> WdfRequestComplete( OriginalRequest );
> }
>
>
>> 3. Is it possible that a HID miniport driver can receive more than one get/set feature requests?
>
> Yes, they aren’t serialized.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Paithara Balagangadhara, Sai Prasad wrote:

Can you elaborate on this: “request cannot be cancelled while you are holding it”? How is this different in either option (with or without forwarding to a manual queue)?

Cancellation may be the single most complicated topic in driver
programming. The KMDF team has gone to great lengths to make sure their
code does it correctly.

One of the key issues is that cancellation is merely a suggestion –
IoCancelIrp politely sets a bit and exits. It is entirely up to the
owner of the IRP to decide whether to even look at – much less honor –
that request. A request that is held in a manual queue is owned by
KMDF, and while it is so owned, KMDF will make sure that the request can
be cancelled. What you see (as the driver) is that the request
disappears from the queue. Everything else is done for you.

When KMDF delivers a request to you, that request is no longer
cancellable. You can MAKE the request cancellable again (using
WdfRequestMarkCancelable), as long as you provide a mechanism to handle
the cancel request. In general, any time I need to hold on to a request
for a while, I create a manual queue and let KMDF keep track of it.
KMDF queues are simple and lightweight, and the added benefit of proper
cancellation handling is a HUGE win.

The other enormous controversy revolves over the question of whether the
word “canceled” contains one L or two.


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