KMDF USB Funny Problem

I’m writing a very simple KMDF driver for an FX2 board, in KMDF 1.5 for
XP SP2. It implements most of the ioctls from the old Cypress EZUSB
driver. All of the descriptor and control requests work perfectly.
However, I can’t get bulk operations to work.

There is one ioctl for bulk read, and one for bulk write. The input
buffer gives the pipe number, and the output buffer gives the data
buffer itself (read is METHOD_OUT_DIRECT, write is METHOD_IN_DIRECT).
So, I call

WdfRequestRetrieveInputBuffer to get the pipe number
WdfRequestRetrieveOutputMemory to get an object for the buffer
WdfUsbTargetPipeSetNoMaximumPacketSizeCheck
WdfUsbTargetPipeFormatRequestForRead (or Write)
WDF_REQUEST_SEND_OPTIONS options;
WDF_REQUEST_SEND_OPTIONS_INIT(
&options,
WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET
);

WdfRequestSend( Request, WdfUsbTargetPipeGetIoTarget( Pipe ),
&options );

I then return without completing the request.

What the application sees is that the ioctls return successfully, but
with no bytes processed. Further, a USB sniffer shows no activity on
the bulk pipe. The in-flight recorder shows this for the write request:

182: FxPkgIo::Dispatch - WDFDEVICE 0x76C8AC48 !devobj 0x89746C98
0x0000000e(IRP_MJ_DEVICE_CONTROL), IRP_MN 0, IRP 0x8B446ED8
183: FxDevice::AllocateRequestMemory - Allocating FxRequest* 8976F010,
WDFREQUEST 76890FE8
184: FxIoQueue::QueueRequest - Queuing WDFREQUEST 0x76890FE8 on WDFQUEUE
0x76C9C7D8
185: FxIoQueue::DispatchEvents - Thread 89E38020 is processing WDFQUEUE
0x76C9C7D8
186: FxIoQueue::DispatchRequestToDriver - Calling driver
EvtIoDeviceControl for WDFREQUEST 0x76890FE8
187: imp_WdfRequestRetrieveInputBuffer - Enter: WDFREQUEST 0x76890FE8
188: imp_WdfRequestRetrieveOutputMemory - Enter: WDFREQUEST 0x76890FE8
189: imp_WdfUsbTargetPipeSetNoMaximumPacketSizeCheck - WDFUSBPIPE 75F27C90
190: imp_WdfUsbTargetPipeFormatRequestForWrite - WDFUSBPIPE 75F27C90,
WDFREQUEST 76890FE8, WDFMEMORY 76890F79
191: FxUsbPipe::_FormatTransfer - WDFUSBPIPE 75F27C90, WDFREQUEST
76890FE8, WDFMEMORY 76890F79, STATUS_SUCCESS
192: FxIoQueue::RequestCompletedCallback - Enter: WDFQUEUE 0x76C9C7D8,
WDFREQUEST 0x76890FE8
193: FxDevice::FreeRequestMemory - Free FxRequest* 8976F010 memory
194: FxIoQueue::DispatchRequestToDriver - WDFREQUEST 0x76890FE8
dispatched to driver
195: FxIoQueue::DispatchEvents - No requests on WDFQUEUE 0x76C9C7D8

Notice that it goes straight from FormatTransfer to
RequestCompletedCallback. I was surprised not to see a line for
WdfRequestSend. I was also surprised to see that the WDFMEMORY handle
was an odd number. I thought all WDF objects used the same algorithm to
map address to handle. However, I can fetch the buffer address and
length from this handle, so it must be OK.

The WDFUSBPIPE, WDFUSBINTERFACE, and WDFUSBDEVICE structures all look
correct. I’ve triple-checked that I’m writing to the OUT pipe and
reading from the IN pipe. The pipe IO targets show “started”.

As an experiment, I replaces the SEND_AND_FORGET sequence with one that
sets a completion routine. In that case, the request hangs forever, or
until I Ctrl-C the test app, at which point my completion routine gets
called. Again, however, the USB Sniffer shows no activity on the bulk
pipes.

Am I missing something? I could write this kind of thing in my sleep
for WDM, but I thought this would be a great opportunity to find out
about the USB parts of KMDF.


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

Send and forget is the equivalent of IoSkipCurrentIrpStackLocation which means your formatting is lost. You cannot use send and forget on a formatted request. The 2 exceptions are formatting by calling WdfRequestWdmFormatUsingStackLocation and WdfRequestFormatRequestUsingCurrentType.

Send the request normally and then complete it in the completion routine (did you forget to complete it in your current investigation?)

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Thursday, September 20, 2007 1:03 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] KMDF USB Funny Problem

I’m writing a very simple KMDF driver for an FX2 board, in KMDF 1.5 for
XP SP2. It implements most of the ioctls from the old Cypress EZUSB
driver. All of the descriptor and control requests work perfectly.
However, I can’t get bulk operations to work.

There is one ioctl for bulk read, and one for bulk write. The input
buffer gives the pipe number, and the output buffer gives the data
buffer itself (read is METHOD_OUT_DIRECT, write is METHOD_IN_DIRECT).
So, I call

WdfRequestRetrieveInputBuffer to get the pipe number
WdfRequestRetrieveOutputMemory to get an object for the buffer
WdfUsbTargetPipeSetNoMaximumPacketSizeCheck
WdfUsbTargetPipeFormatRequestForRead (or Write)
WDF_REQUEST_SEND_OPTIONS options;
WDF_REQUEST_SEND_OPTIONS_INIT(
&options,
WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET
);

WdfRequestSend( Request, WdfUsbTargetPipeGetIoTarget( Pipe ),
&options );

I then return without completing the request.

What the application sees is that the ioctls return successfully, but
with no bytes processed. Further, a USB sniffer shows no activity on
the bulk pipe. The in-flight recorder shows this for the write request:

182: FxPkgIo::Dispatch - WDFDEVICE 0x76C8AC48 !devobj 0x89746C98
0x0000000e(IRP_MJ_DEVICE_CONTROL), IRP_MN 0, IRP 0x8B446ED8
183: FxDevice::AllocateRequestMemory - Allocating FxRequest* 8976F010,
WDFREQUEST 76890FE8
184: FxIoQueue::QueueRequest - Queuing WDFREQUEST 0x76890FE8 on WDFQUEUE
0x76C9C7D8
185: FxIoQueue::DispatchEvents - Thread 89E38020 is processing WDFQUEUE
0x76C9C7D8
186: FxIoQueue::DispatchRequestToDriver - Calling driver
EvtIoDeviceControl for WDFREQUEST 0x76890FE8
187: imp_WdfRequestRetrieveInputBuffer - Enter: WDFREQUEST 0x76890FE8
188: imp_WdfRequestRetrieveOutputMemory - Enter: WDFREQUEST 0x76890FE8
189: imp_WdfUsbTargetPipeSetNoMaximumPacketSizeCheck - WDFUSBPIPE 75F27C90
190: imp_WdfUsbTargetPipeFormatRequestForWrite - WDFUSBPIPE 75F27C90,
WDFREQUEST 76890FE8, WDFMEMORY 76890F79
191: FxUsbPipe::_FormatTransfer - WDFUSBPIPE 75F27C90, WDFREQUEST
76890FE8, WDFMEMORY 76890F79, STATUS_SUCCESS
192: FxIoQueue::RequestCompletedCallback - Enter: WDFQUEUE 0x76C9C7D8,
WDFREQUEST 0x76890FE8
193: FxDevice::FreeRequestMemory - Free FxRequest* 8976F010 memory
194: FxIoQueue::DispatchRequestToDriver - WDFREQUEST 0x76890FE8
dispatched to driver
195: FxIoQueue::DispatchEvents - No requests on WDFQUEUE 0x76C9C7D8

Notice that it goes straight from FormatTransfer to
RequestCompletedCallback. I was surprised not to see a line for
WdfRequestSend. I was also surprised to see that the WDFMEMORY handle
was an odd number. I thought all WDF objects used the same algorithm to
map address to handle. However, I can fetch the buffer address and
length from this handle, so it must be OK.

The WDFUSBPIPE, WDFUSBINTERFACE, and WDFUSBDEVICE structures all look
correct. I’ve triple-checked that I’m writing to the OUT pipe and
reading from the IN pipe. The pipe IO targets show “started”.

As an experiment, I replaces the SEND_AND_FORGET sequence with one that
sets a completion routine. In that case, the request hangs forever, or
until I Ctrl-C the test app, at which point my completion routine gets
called. Again, however, the USB Sniffer shows no activity on the bulk
pipes.

Am I missing something? I could write this kind of thing in my sleep
for WDM, but I thought this would be a great opportunity to find out
about the USB parts of KMDF.


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


NTDEV is sponsored by OSR

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

You cannot use WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET flag for the requests that you format.

Without this flag application request will not complete until you call WdfRequestComplete as discussed in previous posts.

In my earlier post I had included info about send and forget for completeness - but I did not mention the restrictions with this flag. I apologize for the confusion that might have caused. Doron had subsequently clarified that send_and_forget cannot be used for formatted requests and to the functions other than WdfRequestSend.

Without send_and_forget flag if your completion routine does not get called or the request doesn’t even go to USB, that should not happen and we will need to understand what’s going wrong. Please send the trace for that case.

Praveen

Doron Holan wrote:

Send and forget is the equivalent of IoSkipCurrentIrpStackLocation which means your formatting is lost. You cannot use send and forget on a formatted request.

Hmm, that’s a tidbit that I never would have figured out on my own. Nor
do I believe that anything like this is stated or implied in the
documentation. I certainly had a very different mental model of what
the “send and forget” option did.

Actually, I was probably on the verge of guessing this. I finally
hooked up the kernel debugger, and I had traced far enough in to get to
IofCallDriver, where I noticed that the IRP stack location did not
contain my URB pointer, but was instead just a duplicate of what had
been given to me.

Send the request normally and then complete it in the completion routine (did you forget to complete it in your current investigation?)

Somewhere in the many iterations and combinations I went through, I must
have dialed the proper combination. It seems to be working as expected
now. Thanks for the hint.


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

My KMDF USB driver is not as healthy as I thought. Here’s one specific
question. The docs for WdfUsbTargetPipeFormatRequestForWrite say:

To forward an I/O request that your driver received in an I/O queue:

  1. Specify the received request’s handle for the
    *WdfUsbTargetPipeFormatRequestForWrite* method’s /Request/ parameter.
  2. Use the received request’s input buffer for the
    *WdfUsbTargetPipeFormatRequestForWrite* method’s /WriteMemory
    /parameter.

The driver must call *WdfRequestRetrieveInputMemory*
<dfrequestobjectref_180dea64-0a3a-4b59-89e8-37705a674e77.xml.htm>
to obtain a handle to a framework memory object that represents
the request’s input buffer and use that handle as the value for
/WriteMemory/.

Note that very last sentence. I have a case here where I’m getting a
METHOD_OUT_DIRECT ioctl that I’d like to forward on as a write request.
In that case, my write buffer is in WdfRequestRetrieveOutputMemory, not
…InputMemory.

Is that not supported? In the debugger, the URB that gets built has a
TransferBufferLength of 0. The TransferBufferMDL seems to be correct.
Is this WDFREQUEST wrapping simply not as generalized as I keep assuming?

Is the handle for a WDFMEMORY object somehow related to its use? Is it
(address ^ 0xfffffff8) + 1 for an output buffer and (address ^
0xfffffff8) - 1 for an input buffer?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.</dfrequestobjectref_180dea64-0a3a-4b59-89e8-37705a674e77.xml.htm>

> Is the handle for a WDFMEMORY object somehow related to its use? Is it
(address ^ 0xfffffff8) + 1 for an output buffer and (address ^
0xfffffff8) - 1 for an input buffer?

Not exactly, but the WDFMEMORYs that come from a WDFREQUEST are pseudo handles that refer back to the wdfrequest. That is completely unimportant to this problem though.

Remember that input/output refer to the action on the buffer itself. So you read the contents from write buffer and put them somewhere else. That makes a write buffer an input. You write to the contexts of a read buffer which makes it an output. You want to retrieve the input memory and things should work.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Friday, September 21, 2007 12:21 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] KMDF USB Funny Problem

My KMDF USB driver is not as healthy as I thought. Here’s one specific
question. The docs for WdfUsbTargetPipeFormatRequestForWrite say:

To forward an I/O request that your driver received in an I/O queue:

  1. Specify the received request’s handle for the
    *WdfUsbTargetPipeFormatRequestForWrite* method’s /Request/ parameter.
  2. Use the received request’s input buffer for the
    *WdfUsbTargetPipeFormatRequestForWrite* method’s /WriteMemory
    /parameter.

The driver must call *WdfRequestRetrieveInputMemory*
<dfrequestobjectref_180dea64-0a3a-4b59-89e8-37705a674e77.xml.htm>
to obtain a handle to a framework memory object that represents
the request’s input buffer and use that handle as the value for
/WriteMemory/.

Note that very last sentence. I have a case here where I’m getting a
METHOD_OUT_DIRECT ioctl that I’d like to forward on as a write request.
In that case, my write buffer is in WdfRequestRetrieveOutputMemory, not
…InputMemory.

Is that not supported? In the debugger, the URB that gets built has a
TransferBufferLength of 0. The TransferBufferMDL seems to be correct.
Is this WDFREQUEST wrapping simply not as generalized as I keep assuming?

Is the handle for a WDFMEMORY object somehow related to its use? Is it
(address ^ 0xfffffff8) + 1 for an output buffer and (address ^
0xfffffff8) - 1 for an input buffer?


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


NTDEV is sponsored by OSR

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</dfrequestobjectref_180dea64-0a3a-4b59-89e8-37705a674e77.xml.htm>

Doron Holan wrote:

Remember that input/output refer to the action on the buffer itself. So you read the contents from write buffer and put them somewhere else. That makes a write buffer an input. You write to the contexts of a read buffer which makes it an output. You want to retrieve the input memory and things should work.

That makes sense for METHOD_BUFFERED, where the input and output buffers
are the same piece of kernel memory, but for a METHOD_OUT_DIRECT ioctl,
that’s not the case; SystemBuffer and MdlAddress are not the same
thing. I need to be able to grab the “output buffer” of the ioctl, and
feed it as input to a USB write operation.


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

Tim Roberts wrote:

Doron Holan wrote:

> Remember that input/output refer to the action on the buffer itself. So you read the contents from write buffer and put them somewhere else. That makes a write buffer an input. You write to the contexts of a read buffer which makes it an output. You want to retrieve the input memory and things should work.
>
>

That makes sense for METHOD_BUFFERED, where the input and output buffers
are the same piece of kernel memory, but for a METHOD_OUT_DIRECT ioctl,
that’s not the case; SystemBuffer and MdlAddress are not the same
thing. I need to be able to grab the “output buffer” of the ioctl, and
feed it as input to a USB write operation.

Forget it; it was a firmware problem. The KMDF interfaces do work as I
expect.


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