第3节 USB主机实例
现在通过查看可用的 USB 主机软件获得数据结构的使用实例。该部分讨论了 Freescale’s ColdFire 网站 (http://www.freescale.com/coldfire)上提供的MCF532XSC.Zip文件中“m5329evb_usb_host_mouse_test”演示代码。该代码:
(1)设置USB模块为主机模式。
(2)枚举一个USB鼠标。
(3)从鼠标中读取偏移和按键信息。
本文使用MCF532XSC.zip作为一个具体实例,但该实例中的代码可以容易地移植到其他包含兼容EHCI的主机控制器或双模式USB控制器的ColdFire设备。
3.1 控制队列首部
一旦主机控制器检测到接入了新的USB设备,首先就是建立一个QH处理枚举设备的控制通信量。图7是简化的QH,横线下的值是实例中将QH初始化为端点0QH的值。因为在创建QH时它们不需要软件初始化,QTD覆盖区在实例中已删除。实例软件中总是在覆盖区清零以使得方便读取QH的值。QH初始后,该 QH 成为异步列表中 的第一也是唯一的 QH,因此寄存器ASYNCLISTADDR中为该QH的地址。

图7 端点0控制队列头部实例
3.1.1 队列首部水平链接指针实例(偏移:0x00)
3.1.2 端点特性(偏移:0x04)
3.1.3端点性能(偏移:0x8)
3.1.4 当前qTD指针(偏移:0xC)
当前qTD指针不需要软件初始化,但在该例中已被写0。为了调试这样可以较为容易地读取QH。
3.1.5下一qTD指针(偏移:0x10)
下一 qTD 指针写 0x0000_0001,这样表明该 QH 当前没有指向一个有效的qTD。一旦该端点的qTDs初始化,那么该值应更新指向链表中第一个qTD。
3.2 获取设备描述符qTDs
此时异步列表已建立并使能,但主机控制器还未申请任何总线周期。为了申请USB通行量需要创建一些qTDs。USB枚举过程中第一步是读取连接设备的设备描述符,以此为例初始化 qTDs。设备描述符提供接入设备的基本信息,这些信息包括设备端点 0 所支持的最大包长度。读入最大包长度后,QH[Maximum Packet Length]字段被改写以与设备性能向适应。
为了读入设备描述符,需要三次不同的传输:
(1)与setup包一起发送获取设备描述符命令
(2)主机发送IN包以允许设备发送描述符
(3)主机发送一个0长度的OUT包以响应描述符的接收
3.2.1获取描述符SETUP包
图8是简化的qTD,以及软件实例中用来发送获取描述符命令的实际值。因为qTD 的最后四个长字在实例中没有使用,所以已删除。实例中总是清零qTD的最后4个长字以使得读取qTD的值简便。

图8 获取描述符SETUP包的qTD的实例
3.2.1.2 qTD令牌(偏移:0x08)
(1)设置USB模块为主机模式。
(2)枚举一个USB鼠标。
(3)从鼠标中读取偏移和按键信息。
本文使用MCF532XSC.zip作为一个具体实例,但该实例中的代码可以容易地移植到其他包含兼容EHCI的主机控制器或双模式USB控制器的ColdFire设备。
3.1 控制队列首部
一旦主机控制器检测到接入了新的USB设备,首先就是建立一个QH处理枚举设备的控制通信量。图7是简化的QH,横线下的值是实例中将QH初始化为端点0QH的值。因为在创建QH时它们不需要软件初始化,QTD覆盖区在实例中已删除。实例软件中总是在覆盖区清零以使得方便读取QH的值。QH初始后,该 QH 成为异步列表中 的第一也是唯一的 QH,因此寄存器ASYNCLISTADDR中为该QH的地址。

图7 端点0控制队列头部实例
3.1.1 队列首部水平链接指针实例(偏移:0x00)
表3-7 队列首部水平链接指针


3.1.2 端点特性(偏移:0x04)
表3-8 端点特性


3.1.3端点性能(偏移:0x8)
表3-9 端点性能


3.1.4 当前qTD指针(偏移:0xC)
当前qTD指针不需要软件初始化,但在该例中已被写0。为了调试这样可以较为容易地读取QH。
3.1.5下一qTD指针(偏移:0x10)
下一 qTD 指针写 0x0000_0001,这样表明该 QH 当前没有指向一个有效的qTD。一旦该端点的qTDs初始化,那么该值应更新指向链表中第一个qTD。
3.2 获取设备描述符qTDs
此时异步列表已建立并使能,但主机控制器还未申请任何总线周期。为了申请USB通行量需要创建一些qTDs。USB枚举过程中第一步是读取连接设备的设备描述符,以此为例初始化 qTDs。设备描述符提供接入设备的基本信息,这些信息包括设备端点 0 所支持的最大包长度。读入最大包长度后,QH[Maximum Packet Length]字段被改写以与设备性能向适应。
为了读入设备描述符,需要三次不同的传输:
(1)与setup包一起发送获取设备描述符命令
(2)主机发送IN包以允许设备发送描述符
(3)主机发送一个0长度的OUT包以响应描述符的接收
3.2.1获取描述符SETUP包
图8是简化的qTD,以及软件实例中用来发送获取描述符命令的实际值。因为qTD 的最后四个长字在实例中没有使用,所以已删除。实例中总是清零qTD的最后4个长字以使得读取qTD的值简便。

图8 获取描述符SETUP包的qTD的实例
3.2.1.1 下一qTD指针(偏移:0x00)
表3-10 qTD下一元素传输指针(长字0)


3.2.1.2 qTD令牌(偏移:0x08)
表3-11 qTD令牌(长字2)


3.2.1.3 qTD缓冲区页指针(偏移:0x0C)
3.2.2 IN包
图9是简化的qTD图,以及软件实例中的用于发送IN命令读取设备描述符的实际值。

图9 获取描述符IN包的qTD的实例
3.2.2.1 下一qTD指针(偏移:0x00)
3.2.2.2 qTD令牌(偏移:0x08)
表3-12 qTD缓冲区指针


3.2.2 IN包
图9是简化的qTD图,以及软件实例中的用于发送IN命令读取设备描述符的实际值。

图9 获取描述符IN包的qTD的实例
3.2.2.1 下一qTD指针(偏移:0x00)
表3-13 qTD下一元素传输指针(长字0)


3.2.2.2 qTD令牌(偏移:0x08)
表3-14 qTD令牌(长字2)

3.2.2.3 qTD缓冲区指针(偏移:0x0C)
3.2.3 OUT包
图10是简化的qTD图,以及软件实例中的用于发送OUT命令响应接收到设备描述符的实际值。

图10 获取描述符OUT包的qTD的实例
3.2.3.1 下一qTD指针(偏移:0x00)
表3-16 qTD下一元素传输指针(长字0)


3.3 中断队列首部
从鼠标读入描述符后,例程配置一QH与一中断端点通信。鼠标使用中断端点返回 x-和 y-偏移信息、按键数据和滚动信息(返回数据的格式随鼠标不同变化)。
图11是简化的QH图,以及例程中用来初始化QH为端点1的中断QH的值。

图11 中断队列头部实例

3.3.4 当前qTD指针(偏移:0xC)
当前qTD指针不需要软件初始化,但在本例中写0,出于调试目的这样做可以更为简单的读取QH。
3.3.5 下一qTD指针(偏移:0x10)
下一qTD指针写0x0000_0001。这表明该QH指向一无效qTD。在为该端点创建一qTD后,该字段应写入指向第一个qTD的值。
3.4 周期帧列表初始化
此时,例程配置周期帧列表。函数periodic_schedule_init实现以下功能:
3.5 中断qTD
周期表此时已经运行,但是需要一个qTD移动数据。例程使用一个qTD来中断通信。该qTD配置为可以容纳20个USB鼠标的包。一旦接收到20个包,传输总字节数和缓冲区指针字段重新初始化为原来值,这样该 qTD 就可以在连续环中再次使用。
图12是在例程中使用的中断qTD的实际值。

图12 中断qTD实例
3.5.1 下一qTD指针(偏移:0x00)

3.2.2.3 qTD缓冲区指针(偏移:0x0C)
表3-15 qTD缓冲区指针


3.2.3 OUT包
图10是简化的qTD图,以及软件实例中的用于发送OUT命令响应接收到设备描述符的实际值。

图10 获取描述符OUT包的qTD的实例
3.2.3.1 下一qTD指针(偏移:0x00)

3.2.3.2 qTD令牌(偏移:0x08)
表3-17 qTD令牌(长字2)
3.2.3.3 qTD缓冲区页指针(偏移:0x0C)
表3-18 qTD缓冲区指针 
3.3 中断队列首部
从鼠标读入描述符后,例程配置一QH与一中断端点通信。鼠标使用中断端点返回 x-和 y-偏移信息、按键数据和滚动信息(返回数据的格式随鼠标不同变化)。
图11是简化的QH图,以及例程中用来初始化QH为端点1的中断QH的值。

图11 中断队列头部实例
3.3.1 队列首部水平链接指针实例(偏移:0x00)
表3-19 队列首部水平链接指针
3.3.2 端点特性(偏移:0x04)
表3-20 端点特性



3.3.3 端点性能(偏移:0x8)
表3-21 端点性能
当前qTD指针不需要软件初始化,但在本例中写0,出于调试目的这样做可以更为简单的读取QH。
3.3.5 下一qTD指针(偏移:0x10)
下一qTD指针写0x0000_0001。这表明该QH指向一无效qTD。在为该端点创建一qTD后,该字段应写入指向第一个qTD的值。
3.4 周期帧列表初始化
此时,例程配置周期帧列表。函数periodic_schedule_init实现以下功能:
- ● 初始化USBCMD[FS]字段,该字段定义周期帧列表的大小
- ● 为周期帧列表分配内存空间
- ● 用长字0x0000_0001填充帧列表,表示当前帧列表指针无效
- ● 寄存器PERIODICLISTBASE用来设置指向帧列表
- ● 周期表使能
3.5 中断qTD
周期表此时已经运行,但是需要一个qTD移动数据。例程使用一个qTD来中断通信。该qTD配置为可以容纳20个USB鼠标的包。一旦接收到20个包,传输总字节数和缓冲区指针字段重新初始化为原来值,这样该 qTD 就可以在连续环中再次使用。
图12是在例程中使用的中断qTD的实际值。

图12 中断qTD实例
表3-22 qTD下一元素传输指针(长字0)




3.5.2 qTD令牌(偏移:0x08)
表3-23 qTD令牌(长字2)
3.5.3 qTD缓冲区指针(偏移:0x0C)
表3-24 qTD缓冲区指针


