WDK 7600.16385.1中关于USB ISO传输的驱动例子, 是针对于USB2.0与USB1.1的, 即HS与FS.
这个例子没有非常特别之处, 但对于USB2.0的ISO传输的数据分割算法, 还是挺有意思的.
根据MSDN参考文章:
Interval | Polling period (2Interval-1) |
---|---|
1 | 1; Data is transferred every bus interval. |
2 | 2; Data is transferred every second bus interval. |
3 | 4; Data is transferred every fourth bus interval. |
4 | 8; Data is transferred every eighth bus interval. |
Polling period | Number of Packets for high speed/SuperSpeed |
---|---|
1 | Multiple of 8 |
2 | Multiple of 4 |
3 | Multiple of 2 |
4 | Any |
最后, 说一下这个算法的问题:
实际运行过程中, 会导致 babble error, 所以, 最后, 笔者将USBSamp的算法改成另外一种.
比如, 如果一个ISO IN EP的MAX PACKET SIZE = 768, 且其extra transaction 是2, 刚其MaximumPacketSize为768*3 = 2304.
为了符合interval =1, 包的个数为8的倍数的要求, 刚以18432为读写请求:
结果如下:
1. request 18432, actual read 18432
8 packets, each 2304 bytes, 每个ISO PAKCET的OFFSET也均为2304的整数倍
2. request 18431, actual read 17664
最后一个transaction的767 bytes没有收到, 最后一个PACKET收到1536 bytes
7 packets 2304, one packet 2303,每个ISO PAKCET的OFFSET也均为2304的整数倍
最后一个iso packet USBD_STATUS = USBD_STATUS_BABBLE_DETECTED 0xC0000012
这里的BABBLE ERROR, 应该就是buffer只有767 bytes, 但DEVICE回了768 bytes所导致的.
IsoPacket[0].offset = 0 IsoPacket[0].Length = 2304 IsoPacket[0].Status = 0
UsbSamp:
IsoPacket[1].offset = 2304 IsoPacket[1].Length = 2304 IsoPacket[1].Status = 0
UsbSamp:
IsoPacket[2].offset = 4608 IsoPacket[2].Length = 2304 IsoPacket[2].Status = 0
UsbSamp:
IsoPacket[3].offset = 6912 IsoPacket[3].Length = 2304 IsoPacket[3].Status = 0
UsbSamp:
IsoPacket[4].offset = 9216 IsoPacket[4].Length = 2304 IsoPacket[4].Status = 0
UsbSamp:
IsoPacket[5].offset = 11520 IsoPacket[5].Length = 2304 IsoPacket[5].Status = 0
UsbSamp:
IsoPacket[6].offset = 13824 IsoPacket[6].Length = 2304 IsoPacket[6].Status = 0
UsbSamp:
IsoPacket[7].offset = 16128 IsoPacket[7].Length = 1536 IsoPacket[7].Status = c0000012
3. request 18433, actual read 0
16个PACKETS
一个1153 BYTES, 15个1152 BYTES
OFFSET为:
urb header status C0000B00
UsbSamp:
subReqContext
UsbSamp:
IsoPacket[0].offset = 0 IsoPacket[0].Length = 768 IsoPacket[0].Status = c0000011
UsbSamp:
IsoPacket[1].offset = 1153 IsoPacket[1].Length = 768 IsoPacket[1].Status = c0000011
UsbSamp:
IsoPacket[2].offset = 2305 IsoPacket[2].Length = 768 IsoPacket[2].Status = c0000011
UsbSamp:
IsoPacket[3].offset = 3457 IsoPacket[3].Length = 768 IsoPacket[3].Status = c0000011
UsbSamp:
IsoPacket[4].offset = 4609 IsoPacket[4].Length = 768 IsoPacket[4].Status = c0000011
UsbSamp:
IsoPacket[5].offset = 5761 IsoPacket[5].Length = 768 IsoPacket[5].Status = c0000011
UsbSamp:
IsoPacket[6].offset = 6913 IsoPacket[6].Length = 768 IsoPacket[6].Status = c0000011
UsbSamp:
IsoPacket[7].offset = 8065 IsoPacket[7].Length = 768 IsoPacket[7].Status = c0000011
UsbSamp:
IsoPacket[8].offset = 9217 IsoPacket[8].Length = 768 IsoPacket[8].Status = c0000011
UsbSamp:
IsoPacket[9].offset = 10369 IsoPacket[9].Length = 768 IsoPacket[9].Status = c0000011
UsbSamp:
IsoPacket[10].offset = 11521 IsoPacket[10].Length = 768 IsoPacket[10].Status = c0000011
UsbSamp:
IsoPacket[11].offset = 12673 IsoPacket[11].Length = 768 IsoPacket[11].Status = c0000011
UsbSamp:
IsoPacket[12].offset = 13825 IsoPacket[12].Length = 768 IsoPacket[12].Status = c0000011
UsbSamp:
IsoPacket[13].offset = 14977 IsoPacket[13].Length = 768 IsoPacket[13].Status = c0000011
UsbSamp:
IsoPacket[14].offset = 16129 IsoPacket[14].Length = 768 IsoPacket[14].Status = c0000011
UsbSamp:
IsoPacket[15].offset = 17281 IsoPacket[15].Length = 768 IsoPacket[15].Status = c0000011
其中c0000011为USBD_STATUS_XACT_ERRO, C0000B00为USBD_STATUS_ISOCH_REQUEST_FAILED
如果, 再改变一下APP的请求长度, 比如7*2304 = 16128
结果如下:
1. request 16128, read 0 bytes
8 packets, each 2016 bytes
urb header status C0000B00
IsoPacket[0].offset = 0 IsoPacket[0].Length = 1536 IsoPacket[0].Status = c0000012
UsbSamp:
IsoPacket[1].offset = 2016 IsoPacket[1].Length = 1536 IsoPacket[1].Status = c0000012
UsbSamp:
IsoPacket[2].offset = 4032 IsoPacket[2].Length = 1536 IsoPacket[2].Status = c0000012
UsbSamp:
IsoPacket[3].offset = 6048 IsoPacket[3].Length = 1536 IsoPacket[3].Status = c0000012
UsbSamp:
IsoPacket[4].offset = 8064 IsoPacket[4].Length = 1536 IsoPacket[4].Status = c0000012
UsbSamp:
IsoPacket[5].offset = 10080 IsoPacket[5].Length = 1536 IsoPacket[5].Status = c0000012
UsbSamp:
IsoPacket[6].offset = 12096 IsoPacket[6].Length = 1536 IsoPacket[6].Status = c0000012
UsbSamp:
IsoPacket[7].offset = 14112 IsoPacket[7].Length = 1536 IsoPacket[7].Status = c0000012
2. request 16129, read 0 bytes
1 packet 2017, 7 packet 2016
urb header status C0000B00
UsbSamp:
subReqContext
UsbSamp:
IsoPacket[0].offset = 0 IsoPacket[0].Length = 1536 IsoPacket[0].Status = c0000012
UsbSamp:
IsoPacket[1].offset = 2017 IsoPacket[1].Length = 1536 IsoPacket[1].Status = c0000012
UsbSamp:
IsoPacket[2].offset = 4033 IsoPacket[2].Length = 1536 IsoPacket[2].Status = c0000012
UsbSamp:
IsoPacket[3].offset = 6049 IsoPacket[3].Length = 1536 IsoPacket[3].Status = c0000012
UsbSamp:
IsoPacket[4].offset = 8065 IsoPacket[4].Length = 1536 IsoPacket[4].Status = c0000012
UsbSamp:
IsoPacket[5].offset = 10081 IsoPacket[5].Length = 1536 IsoPacket[5].Status = c0000012
UsbSamp:
IsoPacket[6].offset = 12097 IsoPacket[6].Length = 1536 IsoPacket[6].Status = c0000012
UsbSamp:
IsoPacket[7].offset = 14113 IsoPacket[7].Length = 1536 IsoPacket[7].Status = c0000012
3.
request 16127, read 0 bytes
1 packet 2022, 7 packet 2015
urb header status C0000B00
UsbSamp:
subReqContext
UsbSamp:
IsoPacket[0].offset = 0 IsoPacket[0].Length = 1536 IsoPacket[0].Status = c0000012
UsbSamp:
IsoPacket[1].offset = 2022 IsoPacket[1].Length = 1536 IsoPacket[1].Status = c0000012
UsbSamp:
IsoPacket[2].offset = 4037 IsoPacket[2].Length = 1536 IsoPacket[2].Status = c0000012
UsbSamp:
IsoPacket[3].offset = 6052 IsoPacket[3].Length = 1536 IsoPacket[3].Status = c0000012
UsbSamp:
IsoPacket[4].offset = 8067 IsoPacket[4].Length = 1536 IsoPacket[4].Status = c0000012
UsbSamp:
IsoPacket[5].offset = 10082 IsoPacket[5].Length = 1536 IsoPacket[5].Status = c0000012
UsbSamp:
IsoPacket[6].offset = 12097 IsoPacket[6].Length = 1536 IsoPacket[6].Status = c0000012
UsbSamp:
IsoPacket[7].offset = 14112 IsoPacket[7].Length = 1536 IsoPacket[7].Status = c0000012
综上实验所示, 只要一个iso packet的buffer size小于ep 的MaximumPacketSize, 则ISO就会产生BABBLE ERROR.
但该结论只适用于ISO IN, 对于ISO OUT, 该规则不适用.
似乎, 从3 TRANSACTIONS的EP来讲, 如果数据达到了2个 TRANSACTIONS, 则为BABBLE, 如果只达到了一个,甚至更少, 则为XACT. 当然, 这只是笔者根据这几个情况得出的结论, 正确性有待考证.
最后, 笔者将该算法去除, 在符合polling period = 1, 2, 4, 8对packets(1, 2, 4, 8)的要求的情况下, 能够接受任意长度的ISO IN传输.
具体实现为:
所有的OFFSET设置为MaximumPacketSize的整数倍, 在SYS空间中申请一块NON PAGED POOL, 这块BUFFER的长度, 向上圆整到MaximumPacketSize的整数倍(如8*n, 4*n, 2*n, 1*n倍), ISO IN 的数据先存放在SYS空间的这块BUFFER中, 安排一个WORK ITEM, 在WORK ITEM中, 最后将数据COPY到用户空间的BUFFER中, COPY长度为用户请求的长度, 这样解决了BABBLE ERROR的问题(事实上, 也同时解决了XACT ERROR的问题).