isochronous transfer on USB 2.0

Hi,
I’m working on a WDM function driver for some special piece of audio
hardware connected via USB to the PC. For reasons of latency, performance
and planned regularity we decided to use isochronous transfer. While it
just starts to work fine with fullspeed on USB 1, we were stuck with a
strange behaviour on the highspeed USB 2 bus. When starting our streaming
process (in kernelmode allocating and configuring IRP, URB, MDL an then
IoCallDriver, on a periodic basis) only the first 2, 3, 4 or 5 IRP’s will
reach our device. After this usbd.sys seems to ignore everything I send
down the driver stack. My completion routine finds both status values set
to SUCCESS (=0x00000000) but in fact the busdriver has done nothing at
all. By monitoring the device’s hardware ports, no further transfer could
be observed. This behaves identical on Win2000 and WinXP.
Any idea, what may be going wrong here ?

When looking around I found a message, published on a support forum from
Cypress, which states that Microsoft has not fully developed (and so does
not support) isochronous transfers with USB 2 (highspeed).
Could this really be true ? (I can’t believe …)

-Dietmar Jagonak

We were having problems with high-speed isochronous transfers as well, however,
with the latest MS drivers, we’ve gotten it to work (almost) perfectly.

First of all, you need to make sure you’re using the MS drivers. Neither the
Adaptec nor the OrangeMicro drivers worked for us.

Secondly, we’ve found that you cannot pass down to USBD more than 8 URBs
simulatenously, because if you do, the 9th, 17th, … come back wrong.
You say that you are periodically passing USBD your URBs. Does this mean you’re
allocating new URBs every time and free them in your completion routine or do
you recycle them? Because with ther former, you may end up having more than 8
URBs pending with USBD, which doesn’t seem to work. With the latter, you can
make sure that there are never more than 8 URBs outstanding.

Also, we piggyback exactly one URB per IRP, and we don’t use the URB.link field.

Are you using high-bandwidth high-speed isochronous transfers? If so, you must
set the packet size for the isochronous pipe to n * 1024, n being the number of
packets per microframe. USBD apparently interprets high-bandwidth transfers
as being larger in size.

Hope this helps a little,

Burk.

Dietmar Jagonak wrote:

Hi,
I’m working on a WDM function driver for some special piece of audio
hardware connected via USB to the PC. For reasons of latency, performance
and planned regularity we decided to use isochronous transfer. While it
just starts to work fine with fullspeed on USB 1, we were stuck with a
strange behaviour on the highspeed USB 2 bus. When starting our streaming
process (in kernelmode allocating and configuring IRP, URB, MDL an then
IoCallDriver, on a periodic basis) only the first 2, 3, 4 or 5 IRP’s will
reach our device. After this usbd.sys seems to ignore everything I send
down the driver stack. My completion routine finds both status values set
to SUCCESS (=0x00000000) but in fact the busdriver has done nothing at
all. By monitoring the device’s hardware ports, no further transfer could
be observed. This behaves identical on Win2000 and WinXP.
Any idea, what may be going wrong here ?

When looking around I found a message, published on a support forum from
Cypress, which states that Microsoft has not fully developed (and so does
not support) isochronous transfers with USB 2 (highspeed).
Could this really be true ? (I can’t believe …)

-Dietmar Jagonak


You are currently subscribed to ntdev as: xxxxx@stg.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Burkhard Daniel wrote:

Secondly, we’ve found that you cannot pass down to USBD more than 8 URBs
simulatenously, because if you do, the 9th, 17th, … come back wrong.

I’m curious if you’re transferring 8 packets per URB? There is a known
bug associated with queuing a request that’s 256 or more packets away
from something that’s already in the queue, and I’m wondering if your
problem was the packet count rather than the number of URB’s.

Also, we piggyback exactly one URB per IRP, and we don’t use the URB.link field.

Linked URBs used to cause system crashes. Did you once try to link some
URBs under XP and find that it worked, or are you just being cautious
because of aforementioned crashes?

Are you using high-bandwidth high-speed isochronous transfers? If so, you must
set the packet size for the isochronous pipe to n * 1024, n being the number of
packets per microframe. USBD apparently interprets high-bandwidth transfers
as being larger in size.

Which field of which structure are you talking about here? There is a
wMaxPacketSize field in the endpoint descriptor and a MaxTransferSize
field in the USBD pipe descriptor. So, setting a “packet” size for a
“pipe” is a bit ambiguous.


Walter Oney, Consulting and Training
Basic and Advanced Driver Programming Seminars
Now teaming with John Hyde for USB Device Engineering Seminars
Check out our schedule at http://www.oneysoft.com

Walter Oney wrote:

Burkhard Daniel wrote:

>Secondly, we’ve found that you cannot pass down to USBD more than 8 URBs
>simulatenously, because if you do, the 9th, 17th, … come back wrong.

I’m curious if you’re transferring 8 packets per URB? There is a known
bug associated with queuing a request that’s 256 or more packets away
from something that’s already in the queue, and I’m wondering if your
problem was the packet count rather than the number of URB’s.

We’re transferring 248 packets per URB. This is the largest number that worked
for us for high-bandwidth high-speed isochronous transfers. 255 doesn’t work
because the number must be divisble by 8, because there are 8 microframes to
each frame and an URB only allows us to start at a certain frame. If we want to
specify an uninterrrupted flow of data, each URB must contain 8 or more packets
(in high-speed isochronous transfers).

So, it is possible to have pending 8 * 248 = 1984 packets with up to 3072 bytes
(=3 packets per microframe) each, which amounts to close to 6 MB (or 248 ms).

I don’t know how that relates to the bug you’re referring to though.

>Also, we piggyback exactly one URB per IRP, and we don’t use the URB.link field.

Linked URBs used to cause system crashes. Did you once try to link some
URBs under XP and find that it worked, or are you just being cautious
because of aforementioned crashes?

I followed your advice :slight_smile: You’re book says don’t touch it so we didn’t touch
it. No, I haven’t tried it on XP, because my driver has to be able to run on 2k.

>Are you using high-bandwidth high-speed isochronous transfers? If so, you must
>set the packet size for the isochronous pipe to n * 1024, n being the number of
> packets per microframe. USBD apparently interprets high-bandwidth transfers
>as being larger in size.

Which field of which structure are you talking about here? There is a
wMaxPacketSize field in the endpoint descriptor and a MaxTransferSize
field in the USBD pipe descriptor. So, setting a “packet” size for a
“pipe” is a bit ambiguous.

Sorry. I was referring to the wMaxPacketSize field in the endpoint descriptor.
You need to set it to 1024 if you want to transfer 1 packet per microframe,
2048 for 2 pkts/µframe, and 3072 for 3 pkts/µframe.

Burk.

Burkhard Daniel
Software Technologies Group, Inc.
xxxxx@stg.com * http://www.stg.com
fon: +49-179-5319489 fax: +49-179-335319489

“Burkhard Daniel” wrote:

?We were having problems with high-speed isochronous transfers as well, however,
?with the latest MS drivers, we’ve gotten it to work (almost) perfectly.

Sounds like there is a new version out with Microsoft ?? Where to find it ?
I use the version ( 5.0.2195.5652 in usbehci.sys ) which originally was offered additionally for Win2K because there is no service pack conaining these drivers.

?First of all, you need to make sure you’re using the MS drivers. Neither the
?Adaptec nor the OrangeMicro drivers worked for us.

?Secondly, we’ve found that you cannot pass down to USBD more than 8 URBs
?simulatenously, because if you do, the 9th, 17th, … come back wrong.
?You say that you are periodically passing USBD your URBs. Does this mean you’re
?allocating new URBs every time and free them in your completion routine or do
?you recycle them? Because with ther former, you may end up having more than 8
?URBs pending with USBD, which doesn’t seem to work. With the latter, you can
?make sure that there are never more than 8 URBs outstanding.

?Also, we piggyback exactly one URB per IRP, and we don’t use the URB.link field.

Me too has been studying the WDM driver books from Walter Oney. So, naturally I left the URB.link field untouched, and also I’m adjusting the packet count per URB to a multiple of 8.
The IRP-URB pairs once I have allocated them, are stored (via pointers) in a (limited) array of some kind of context structure and later reused again after being marked as unused through my completion routine. This limit is adjustable from usermode at runtime because I have to deal with the lack of free IRP-URB which I can use.
According to your advice I tested lowering this limit down to 8 but I couldn’t observe any change in the mentioned behaviour.

There is one thing in the chain which I’M a littel confused about. How does the USBD make use of the MDL pointer I give to him in my URB. I allocated the MDL with a virtual address and a length value. Additionally I have to fill the URB field “TransferBufferLength” with a reasonable value. And least, I have to give every “IsoPacket” its offset and length value. Now, how tight must these values correlate with one another ? I don’t think the “IsoPacket.Offset” values are allowed to point
to anywhere within my MDL. But have they really to be continuous without any gap ? What if the “TransferBufferLength” differs somewhat from the allocated size of my MDL ?
Its this kind of difficulty because my driver has to transfer very different sized datablocks provided by the usermode app. This may extremly change from 10 Bytes in one actual block to 2800 Bytes in the next block, the distance between two blocks perfectly has to be 1,45 ms which means 2 blocks within 3ms. With USB 1 the max size will only be about 544 Bytes in a block.

>?Are you using high-bandwidth high-speed isochronous transfers? If so, you must
>?set the packet size for the isochronous pipe to n * 1024, n being the number of
>??packets per microframe. USBD apparently interprets high-bandwidth transfers
>?as being larger in size.

Up till now we use one packet per microframe. I think we’ll try to tune it up to 3 per microframe when it’s basically running well.

>?Hope this helps a little,

Thanks for every kind of input …

>?Burk.
>
>?Dietmar Jagonak wrote:
>?>?Hi,
>?>?I’m working on a WDM function driver for some special piece of audio
>?>?hardware connected via USB to the PC. For reasons of latency, performance
>?>?and planned regularity we decided to use isochronous transfer. While it
>?>?just starts to work fine with fullspeed on USB 1, we were stuck with a
>?>?strange behaviour on the highspeed USB 2 bus. When starting our streaming
>?>?process (in kernelmode allocating and configuring IRP, URB, MDL an then
>?>?IoCallDriver, on a periodic basis) only the first 2, 3, 4 or 5 IRP’s will
>?>?reach our device. After this usbd.sys seems to ignore everything I send
>?>?down the driver stack. My completion routine finds both status values set
>?>?to SUCCESS (=0x00000000) but in fact the busdriver has done nothing at
>?>?all. By monitoring the device’s hardware ports, no further transfer could
>?>?be observed. This behaves identical on Win2000 and WinXP.
>?>?Any idea, what may be going wrong here ?
>?>
>?>?When looking around I found a message, published on a support forum from
>?>?Cypress, which states that Microsoft has not fully developed (and so does
>?>?not support) isochronous transfers with USB 2 (highspeed).
>?>?Could this really be true ? (I can’t believe …)
>?>
>?>?-Dietmar Jagonak
>?>
>?>?—
>?>?You are currently subscribed to ntdev as: xxxxx@stg.com
>?>?To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
>
>?—
>?You are currently subscribed to ntdev as: xxxxx@equisoft.de
>?To unsubscribe send a blank email to xxxxx@lists.osr.com

EquiSoft DDev wrote:
> “Burkhard Daniel” wrote:
>
>> We were having problems with high-speed isochronous transfers as well,
>> however, with the latest MS drivers, we’ve gotten it to work (almost)
>> perfectly.
>
>
> Sounds like there is a new version out with Microsoft ?? Where to find it
> ? I use the version ( 5.0.2195.5652 in usbehci.sys ) which originally was
> offered additionally for Win2K because there is no service pack conaining
> these drivers.

That is what I’m using, too.

There is one thing in the chain which I’M a littel confused about. How
> does the USBD make use of the MDL pointer I give to him in my URB. I
> allocated the MDL with a virtual address and a length value. Additionally
> I have to fill the URB field “TransferBufferLength” with a reasonable
> value. And least, I have to give every “IsoPacket” its offset and length
> value. Now, how tight must these values correlate with one another ? I
> don’t think the “IsoPacket.Offset” values are allowed to point to
> anywhere within my MDL. But have they really to be continuous without any
> gap ? What if the “TransferBufferLength” differs somewhat from the
> allocated size of my MDL ? Its this kind of difficulty because my driver
> has to transfer very different sized datablocks provided by the usermode
> app. This may extremly change from 10 Bytes in one actual block to 2800
> Bytes in the next block, the distance between two blocks perfectly has to
> be 1,45 ms which means 2 blocks within 3ms. With USB 1 the max size will
> only be about 544 Bytes in a block.

Are you doing IN or OUT transfers?

You must make sure that the URB.TransferBufferLength is less or equal to the
MDL size; i.e. the MDL must be large enough to hold at least
TransferBufferLength bytes. Then you initialize the IsoPacket.Offset field
to where within the buffer that particular packet should start. For IN
transfers, leave the IsoPacket.Length field alone, USBD will set this when
it has stored data in the packet. For OUT transfers you must set this field
as well.

Essentially, the idea is that you give USBD a virtually contiguous block of
memory described by an MDL, and USBD then fills that buffer with the number
of packets you specified in _URB_ISOCH_TRANSFER.NumberOfPackets. Since you
specify where in the buffer the packet will be stored (using the Offset
field), you can later find out what data belonged to which frame.

From how I understand it, the Offset fields may point to anywhere in your
MDL. But why, exactly, would you not want the iso packets be consecutive in
memory?

Burk.

Burkhard Daniel
Software Technologies Group, Inc.
xxxxx@stg.com * http://www.stg.com
fon: +49-179-5319489 fax: +49-179-335319489