UMDF Short Completion Info

Hi all,

I have a 64bit user mode driver created using UMDF based on the examples that ship with the SDK. Communication between app and device works fine for the most part with a combination of device io requests and bulk i/o.

Most commands occur via bulk i/o with a short 8 byte packet coming in via OnWrite and been passed onto the appropriate usb endpoint. This is followed a short time later by an OnRead request to obtain the result of the command.

Most of the write/read requests are completing correctly with the bytes requested in the OnRead matching the bytes transfered as shown in the OnCompletion callback. However, those read requests are for small amounts of 2, 4, 8 or 17 bytes at a time.

The problem begins when a read request comes in for 10,202,400 bytes (which is following a OnWrite request for a full field readout of the camera of 10,202,400 bytes). The OnRead request has 10,202,400 bytes in the BytesToRead parameter and the output buffer in the request parameter is 10,202,400 in size.

When the OnCompletion callback fires however, it reports 10,202,112 bytes were actually transferred.

I’ve read a few posts on here about the buffer needing to be a multiple of the endpoint packet size. As the output buffer is not a multiple of 512 but the returned 10,202,112 is, could that be a cause of the problem?

It does look like the remainder of the data is coming in during subsequent reads, which then throws things out of sync.

If the buffer used in the OnRead callback needs to be a multiple of 512, how can I reformat it during the OnRead callback before it’s passed on to the endpoint with a send?

Or could something else be the cause?

Here’s my current OnRead callback for the Queue.

  
STDMETHODIMP_ (void)  
CMyQueue::OnRead(  
 /\* [in] \*/ IWDFIoQueue \*pWdfQueue,  
 /\* [in] \*/ IWDFIoRequest \*pWdfRequest,  
 /\* [in] \*/ SIZE_T BytesToRead  
 )  
{  
 UNREFERENCED_PARAMETER(pWdfQueue);  
  
TraceEvents(TRACE_LEVEL_INFORMATION,  
 TEST_TRACE_QUEUE,  
 "%!FUNC!: Queue %p Request %p BytesToTransfer %d\n",  
 this,  
 pWdfRequest,  
 (ULONG)(ULONG_PTR)BytesToRead  
 );  
  
HRESULT hr = S_OK;  
 IWDFMemory \* pOutputMemory = NULL;  
 pWdfRequest-\>GetOutputMemory(&pOutputMemory);  
  
hr = m_Parent-\>GetInputPipe()-\>FormatRequestForRead(  
 pWdfRequest,  
 NULL, //pFile  
 pOutputMemory,  
 NULL, //Memory offset  
 NULL //DeviceOffset  
 );  
  
if (FAILED(hr))  
 {  
 TraceEvents(TRACE_LEVEL_INFORMATION, TEST_TRACE_QUEUE, "Format request failed");  
 pWdfRequest-\>Complete(hr);  
 }  
 else  
 {  
 ForwardFormattedRequest(pWdfRequest, m_Parent-\>GetInputPipe());  
 }  
  
SAFE_RELEASE(pOutputMemory);  
  
return;  
}  
  

I’ve tried creating a new memory object in the OnRead callback and using that in the format call to no avail.

Any suggestions appreciated.

xxxxx@figmentgames.com wrote:


The problem begins when a read request comes in for 10,202,400 bytes (which is following a OnWrite request for a full field readout of the camera of 10,202,400 bytes). The OnRead request has 10,202,400 bytes in the BytesToRead parameter and the output buffer in the request parameter is 10,202,400 in size.

When the OnCompletion callback fires however, it reports 10,202,112 bytes were actually transferred.

I’ve read a few posts on here about the buffer needing to be a multiple of the endpoint packet size. As the output buffer is not a multiple of 512 but the returned 10,202,112 is, could that be a cause of the problem?

It does look like the remainder of the data is coming in during subsequent reads, which then throws things out of sync.

This depends on how your device is implemented. Remember that a USB
device is never told how much data to transfer. It simply receives a
signal that says “GO!” It is up to the device to decide how much data
to send. If your data only sends full packets (512 bytes), then you
would see this kind of behavior. The end of the frame would remain in
the device until it gets enough data to make 512 bytes.

In order to get that partial packet, your device needs to be modified to
send a short packet when it sees “end of frame” signal. It is entirely
up to your device.


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

Hi Tim,

If that were the case, wouldn’t the device hold back the short read packets of 2,4,8 or 17 bytes in length that are received earlier in the communication sequence? Or would an exception be made for the first returned packet?

Modifying the hardware is not an option as the device is outside my control and has been on sale for some time now. There is a 32 bit driver out for it that works, so I’ve been working on the assumption that the device opperates correctly and that I’m doing something wrong.

If the device is holding back on sending the final small packet, can you hazard a guess as to why it works with the 32bit driver? (I don’t have access to the driver source to check)

xxxxx@figmentgames.com wrote:

If that were the case, wouldn’t the device hold back the short read packets of 2,4,8 or 17 bytes in length that are received earlier in the communication sequence? Or would an exception be made for the first returned packet?

It is ENTIRELY up to the device. Are those short packets going through
the bulk pipe? Such transfers would commonly be done with vendor
requests over the control pipe.

Modifying the hardware is not an option as the device is outside my control and has been on sale for some time now. There is a 32 bit driver out for it that works, so I’ve been working on the assumption that the device opperates correctly and that I’m doing something wrong.

If the device is holding back on sending the final small packet, can you hazard a guess as to why it works with the 32bit driver? (I don’t have access to the driver source to check)

Don’t know. Sometimes there a separate command to tell the device to
flush its FIFO. Does the USB part of device know how large the image
is? Is there a byte count? Someone has to tell the device, otherwise
it won’t know it’s supposed to flush the partial packet.


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

> It is ENTIRELY up to the device. Are those short packets going through the

bulk pipe? Such transfers would commonly be done with vendor requests over
the control pipe.

Yes those packets are done via bulk i/o. The device uses bulk transfers for most commands.

Don’t know. Sometimes there a separate command to tell the device to
flush its FIFO. Does the USB part of device know how large the image is?
Is there a byte count? Someone has to tell the device, otherwise it won’t
know it’s supposed to flush the partial packet.

Prior to the app issuing a read request it does a write with a command that instructs the device to read out its pixels. Part of the params to that command specify the number of pixels to read out. I’ve dumped the incoming buffer data in the onwrite method and verified it’s requesting the correct number of pixels.

The app then issues a read request for that number of pixels, which is the 10,202,400 value I’m seeing in the OnRead method.

So the device will know how much it’s expected to be sending out. Also it looks like the device does send out the full data, only it’s been split for some reason by the time it reaches the driver.

Is there anything I could run to view the data sent from the USB device to work out if it’s something in the UMDF framework that’s causing the split or the device only sending 10,202,112 then later sending the remaining data?

The only reason I don’t want to blame the device atm for not sending the final packet is this all works fine with the 32bit driver. If there’s a way to view the data sent by the device prior to it hitting the driver that might help, but I’m so new to this I don’t have a clue if that’s possible :slight_smile:

Cheers for the suggestions Tim. In light of what you’ve said, I’ve installed a USB data logger and analysed the communication between driver and device which has turned up the following.

The request to read 10,202,400 bytes is sent to the device. The device then sends 5 packets back

4 times 0x200000 = 2,097,152 bytes
1 times 0x1bac00 = 1,813,504

Which is the short packet that is completing the request at 10,202,112 bytes despite the driver/app expecting 10,202,400.

The app gets this data and issues the next 8 byte command to the device and expects 3 bytes back. The device then returns a packet of 0x200 = 288 bytes which is the missing bytes expected in the previous transfer.

Why the device or usb hw is not including those 288 bytes in the previous transfer is a mystery.

Unless anyone can think of any way I could have incorrectly configured the driver to result in such an exchange, I think I’m going to need to get access to the devices firmware to get the root of the issue.

How the 32bit driver is working around this, I’m unsure.

xxxxx@figmentgames.com wrote:

Cheers for the suggestions Tim. In light of what you’ve said, I’ve installed a USB data logger and analysed the communication between driver and device which has turned up the following.

The request to read 10,202,400 bytes is sent to the device. The device then sends 5 packets back

4 times 0x200000 = 2,097,152 bytes
1 times 0x1bac00 = 1,813,504

Well, what you’re seeing here is that UMDF is chopping your request up
into 5 requests for 2MB, because the USB stack in XP is limited to
requests of about 3MB. The packets on the wire are only 512 bytes at a
time.

Which is the short packet that is completing the request at 10,202,112 bytes despite the driver/app expecting 10,202,400.

That’s not a short packet. The final transfer is a multiple of 512
bytes. Those are fulll packets.

The app gets this data and issues the next 8 byte command to the device and expects 3 bytes back. The device then returns a packet of 0x200 = 288 bytes which is the missing bytes expected in the previous transfer.

0x200 is 512 bytes, not 288.

Why the device or usb hw is not including those 288 bytes in the previous transfer is a mystery.

Not really. It’s the “short packet” issue. Perhaps your should try
rounding your request up to a multiple of 512 – try reading 10,202,624
bytes.


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

> When the OnCompletion callback fires however, it reports 10,202,112 bytes were actually

transferred.

Why is this the problem?

Any read in Windows and UNIX OSes can return lesser data then requested, you must be prepared for this. Well, maybe the only exception is Windows serial port in some exotic mode.

As the output buffer is not a multiple of 512 but the returned 10,202,112 is

Correct.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

> 0x200 is 512 bytes, not 288.

Apologies. The last packet returned is 288 bytes, I should have written 0x120 and not 0x200. I must have still been thinking of the 0x200000 packets when I wrote 0x200, my mistake :slight_smile:

That’s not a short packet. The final transfer is a multiple of 512
bytes. Those are fulll packets.

Ok, so what I’m seeing is the stack splitting the transfers into 5 requests, but all those packets during the transfer are 512 bytes. Understood.

Not really. It’s the “short packet” issue. Perhaps your should try rounding
your request up to a multiple of 512 – try reading 10,202,624 bytes.

Is it possible to modify a request in the OnRead callback to increase the amount to be read? Or, would I need to create a new request and send that to the device with the new amount in place of the original request passed into OnRead?

What should happen with the original request?

Any read in Windows and UNIX OSes can return lesser data
then requested, you must be prepared for this. Well, maybe the
only exception is Windows serial port in some exotic mode.

The problem is that the applications currently work with the existing 32bit driver but not the 64bit driver I’ve created. With the 64bit driver the app requests the full pixel data and when the driver returns a short amount, it then goes on to performing the next command.

I agree that the app should be able to deal with transfers returning less than requested. However, it’s unlikely I’ll be able to get any app changes made as they’re totally outside my control and created by a different company. Although if that does prove to be the issue, I’ll at least submit a request :slight_smile:

I’ve been sent a copy of the devices firmware, which I’m going to review in the morning, so hopefully this is something I can resolve at either the driver or device level.

>unlikely I’ll be able to get any app changes made as they’re totally outside my control

Then maybe you will need full buffering in your driver. Read from USB stack to some buffer, then respond to app’s reads from this buffer.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

On 11/04/2010 01:46 AM, xxxxx@figmentgames.com wrote:

The problem is that the applications currently work with the existing
32bit driver but not the 64bit driver I’ve created.

You stated before you have a USB data logger. Use it:
Look at what the 32bit driver does.
This might give you an idea what’s different.

That occurred to me last night, I ran the test on a spare XP machine. It looks like XP breaks the transfer into 9 blocks of 0x105000 bytes and one block of 0x8dd20. All the pixels arrive unlike with the 64bit driver where the last 288 are delayed until another read request occurs.

Anyone know why the final partial packet is included on XP 32bit but not on Win7 64bit? The device firmware is the same in both cases as is the app. I don’t see any extra usb data flows to suggest the 32bit driver is doing anything special.

Thanks everyone for your advice. I’ve got the driver working now by creating a new request with a memory buffer that’s a multiple of 512 bytes and storing the applications request in a manual queue until the device returns the data.

I do have a couple of final questions though. The completion callback for the request I created does not have a valid OutputMemory, I’ve had to pass in the created memory via the custom params option of the callback. Is this correct or should formatting the request for read have linked up the memory I passed in to the request?

Also the GetType() returned by the custom request is undefined. I assume that’s because I created it rather than it coming in from an external source?

In the completion callback you need to look at completion params (which represent the next stack location) and not the request parameters. You receive IWDFRequestCompletionParams in the request completion callback and you need to QI IWDFUsbRequestCompletionParams from it.

Please look at CMyDevice::SendControlTransferSynchronously in the fx2 sample for an example. This function uses sync send, but the handling of completion params is same for async send (but you will be doing it in the completion callback).

As you noted this request has no type and memory associated since there was none at this driver’s layer.

HTH,
Praveen

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@figmentgames.com
Sent: Friday, November 05, 2010 9:48 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] UMDF Short Completion Info

Thanks everyone for your advice. I’ve got the driver working now by creating a new request with a memory buffer that’s a multiple of 512 bytes and storing the applications request in a manual queue until the device returns the data.

I do have a couple of final questions though. The completion callback for the request I created does not have a valid OutputMemory, I’ve had to pass in the created memory via the custom params option of the callback. Is this correct or should formatting the request for read have linked up the memory I passed in to the request?

Also the GetType() returned by the custom request is undefined. I assume that’s because I created it rather than it coming in from an external source?


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

Thanks Praveen, that’s done the trick.