UHCI的数据结构和数据流控制
一、数据结构
主要涉及到三个数据结构:Frame list 、Transfer Descriptors(TD)、Queue Head(QH)。Frame list必须要4K字节对齐;而TD和QH需要16字节对齐,一般情况本身的结构大小要超过16字节。
三者之间的关系如下图所示:
其中Frame list base address从UHCI的IO Register中读到的,uhcispec中有介绍。Frame counter也是在IO register中读到,也base address共同得到当前UHCI需要处理的Frame list中的Frame pointer。
剩下的问题就是如何控制Frame pointer中TD、QH的数据流。
关于TD和QH的数据结构问题:
1、Frame list pointer:
Frame list pointer指第一个需要调度的结构体的地址。
Q:表示Link pointer指向的是TD(0)还是QH(1)。
T:表示告知HC,该Frame是否有有效的数据流入口。1、表示空的frame;0表示有效入口。
2、Transfer Descriptor
针对同步、中断、控制、bulk传输,有四种不同的TD,当然结构大同小异,只是部分控制bit不一样而已。按理说会有8个Dword,实际使用前4个Dword,最后4个Dword是留给software使用的。
Link pointer指指向另外一个TD或者QH。
Vf:告知HC,该深度遍历还是广度遍历。深度遍历就是跑向Link pointer的指向的TD;广度遍历跑向Link pointer指向的另外一个QH。1=depth first;0=breadth first。
Q:表示Link pointer指向的是TD(0)还是QH(1)。
T:1=Link pointer无效;0=Link pointer是有效的。该bit告知HC本TD中link pointer是否指向另外一个数据流入口。如果TD在一个队列里中,该bit代表告知HC,队列中已经没有另外的有效数据流入口了。也就是说本TD是最后一个TD。
另外的字段说明请看spec。
在status字段中,bit23是active bit。也就是说,Software将所有的QH或者TD设置好,Frame list base address也设置好之后,在将该bit置位,则HC马上开始USB的数据传输。在等待若干time之后判断是否得到ACK。
Buffer Pointer指本TD中需要传输的数据内容。大小必须不小于MAX Length中定义的size。
3、Queue Head
QH是特别针对控制、bulk和中断传输定义的结构。而同步传输中不会使用QH。必须16字节对齐。
QHLP:此字段指向下一个横向数据表的地址,可以是QH或者TD。一般情况是QH(多个队列)。
Q:表示Link pointer指向的是TD(0)还是QH(1)。
T:告知HC,本QH已经是本次调度序列中最后一个QH了。1=last QH;0=pointer有效,指向TD或者QH。
二、如何控制数据流
HCD设定HC的register:Frame list baseaddress和frame list index,并通过hc的run、stop控制HC执行调度序列。
HC首先从Frame list中读取一个入口,判断bit0 是否是pointer address有效;判断bit1 是指定TD还是QH;另外一个字段即pointer address。
如果针对isochronous传输,Frame list则指向TD,如果没有isochronous传输,则指向QH。如果指向TD,则HC获取到入口地址开始在USB总线上传输数据,每个TD包含的link pointer指向下一个入口,TD或者QH;如果是指向QH的,HC就会按照QH中的结构来相应处理。
1、 处理同步传输的描述符
同步传输的描述符是link到frame list中,每1ms发生一次数据的传送。所以同步传输的控制也要保证host端到端点之间的固定频率的数据传送。同步TD的处理如下:
1)、HC获取对应的Isochronous TD;
2)、HC decode TD的各个字段,来做相应的传输控制。
3)、HC产生USB token,开始传送 usb数据。
4)、当传输过程完成,HC将更新状态,标志TD非活跃状态。
5)、HC获取当前TD中link pointer指向的TD或者QH。
6)、类似的同样处理TD或者QH。
2、 处理bulk、control和interrupt的传输描述符
像bulk、control和interrupt TD传输数据是通过QH队列来实现的。步骤如下:
1)、HC从Frame list中获得QH,并确认是否有有效的入口。
2)、如果数据(TD or QH)入口有效,HC从QH的元素指针中获取TD或者QH,如果是TD,则跳转到3);如果QH则跳转到1);如果是无效的入口,直接跳转到10)。
3)、HC解析TD字段,觉得采取何种方式传输。
4)、HC产生USB token,并开始执行传输,setup阶段。
5)、等传输过程结束,HC更新状态。
6)、如果传输结束并成功,TD被标志位非活跃状态,并跳转到9)。
7)、如果此次传输没有成功,但是error次数没有达到门限值,那么TD将依旧重新开始活跃。跳转到10)。
8)、如果此次传输失败,而且error也达到了门限值,那么TD将被标志成非活跃态,跳转到10)。
9)、HC将当前TD的link pointer写入到当前QH结构中的元素指针中(也就是将QH中之前处理完的TD从链表中移除),如果link pointer的Vf bit置位了(depth),(将当前QH传递过去)跳转到2);否则直接进入10)。
10)、HC从当前QH的QH linkpointer中获取到QH或者TD的指向。如果该QH link pointer的T位置位的话,HC进入idle转跳等待1ms 帧时间的消耗完。
11)、UHCI的处理过程继续以此流程进行下去。
数据流控制的结构图如下:
下图是一个队列的实例: