作者: zjujoe 转载请注明出处
Email:[email protected]
BLOG:http://blog.csdn.net/zjujoe
USB 协议的特性之一就是把复杂性留给软件。USB 驱动纷繁复杂,不管主机端还是设备端,不管是底层控制器驱动还是上层各种 CLASS 驱动。对于这么复杂的软件族,在测试方面付出一些努力是很有价值的。Linux usb 社团开发了一些测试用例。大概是因为开发控制器驱动的人比较多(因为每个硬件平台都不同),这些测试用例主要用于测试底层控制器驱动。
测试的大体原理是这样的,在主机端有 usbtest 内核模块,它是一个专用于测试的 usb 客户驱动, 该某块通过 ioctl 接口提供了各种测试类型, 比如 Simple non-queued bulk I/O tests ,Queued bulk I/O tests ,等等 (如果您不是很理解,建议您去阅读 fudan_abc 写的Linux 那点事儿系列, 或者您没空,读一下内核相关文档)。在应用层则有一个程序及脚本 (testusb.c and test.sh),用于触发各种测试。对应的,在设备端,有各种gadget 驱动配合测试,比如,g_zero 便是其中之一。这一套流程可以用来测试主机端及外设端的控制器驱动。我们这里并不打算翻译http://www.linux-usb.org/usbtest/index.html(这里提供了测试代码,流程等),我们主要是结合 PXA 平台的测试要求提供一个测试实例 (把自己的实践经验记录下来)。 PXA 平台支持 otg 功能,我们首先测试设备端控制器驱动。
1. 首先是准备一台 Linux 主机。 在一台笔记本上安装了 ubuntu 7.10, 并重新编译了内核(如何编? Google 一下),替换掉系统标准内核以及 initramfs。 这样, 编译出的模块就可以安装到内核了。
2. 主机端,编译出内核模块 usbtest。并安装到内核。大体查看一下, 该模块提供了10几个 testcase:
0) 空操作
1) Simple non-queued Bulk out
2) Simple non-queued Bulk in
3) Simple non-queued Bulk out, vary size
4) Simple non-queued Bulk in, vary size
5) 等等。
从 id_table 可以看到, 它支持各种 usb device, 我们在 device 端使用 g_zero, 也包含在这里面。
3. 主机端,安装内核模块: modprobe usbtest
4. 主机端,安装 usbfs: mount -t usbfs none /proc/bus/usb,这样 /proc/bus/usb 下就会列出 usb 的设备信息,我们的测试程序依赖这些信息。
5. 主机端,编译出 testusb: gcc -Wall -g -lpthread -o testusb testusb.c
6. 设备端, 安装 g_zero 驱动: insmod g_zero.ko
7. 主机端,开始测试, testusb –a
8. 发现执行出错,设备端报错:
bad OUT byte, buf [0] = 22
使用 KFT 及 Graphviz 工具,得到函数调用关系图:
原来zero_setup 中在 set interface 时会先调用 zero_reset_config 而该函数会间接调用到complete 函数: source_sink_complete。该函数本来是在从主机端传来数据时调用,其中会检查数据有效性。 现在调用,buffer 里只有无效数据, 所以出错。
将 zero_setup 中对 zero_reset_config 函数的调用注释掉。
9. 继续测试,发现到 test case 10 时出错. 跟踪 usbtest.c, 发现函数 ctrl_out 中有如下语句:
1251 if (length < 1 || length > 0xffff || vary >= length)
而testusb 中,length和 very 缺省值均为512. 于是直接出错返回。
10. 不再使用缺省值测试, 发现:
./testusb -a -c10 -t10 -s512 -g16 -v32
可以正常通过。.
11. 现在usbtest 可以基本跑起来, 不过比较脆弱。每个 test case 都能跑,不过换一下参数,或者多跑几趟,就失败了。
#以下可以正常运行(当然,可能多跑几次,就失败)
./testusb -a -c10 -t1 -s4096 -g32 -v32
./testusb -a -c10 -t2 -s4096 -g32 -v32
./testusb -a -c10 -t3 -s4096 -g32 -v32
./testusb -a -c10 -t4 -s4096 -g32 -v512
./testusb -a -c10 -t5 -s512 -g32 -v512
./testusb -a -c10 -t6 -s512 -g32 -v512
./testusb -a -c10 -t7 -s512 -g32 -v512
./testusb -a -c10 -t8 -s512 -g32 -v512
./testusb -a -c10 -t9 -s512 -g32 -v256
./testusb -a -c10 -t10 -s512 -g16 -v32
./testusb -a -c10 -t11 -s512 -g32 -v256
./testusb -a -c10 -t12 -s512 -g32 -v256
./testusb -a -c10 -t13 -s512 -g32 -v256
./testusb -a -c10 -t14 -s256 -g32 -v1
#以下一般会出错
#./testusb -a -c10 -t4 -s4096 -g32 -v32 # error
#./testusb -a -c10 -t4 -s4096 -g32 -v256 # error
#./testusb -a -c10 -t7 -s512 -g32 -v32 #error
#./testusb -a -c10 -t7 -s512 -g32 -v256 #error
#./testusb -a -c10 -t8 -s512 -g32 -v32 #error
#./testusb -a -c10 -t8 -s512 -g32 -v256 #error
#./testusb -a -c10 -t10 -s512 -g32 -v256 #error
#./testusb -a -c10 -t14 -s512 -g32 -v256 #error
在系统比较稳定后,可以使用 test.sh 进行耐力测试。 test.sh 的主要代码是一个没有退出条件的主循环,用户可以选择要测试的类型:
control: any device can do this
out, in: out needs 'bulk sink' firmware, in needs 'bulk src'
iso-out, iso-in: out needs 'iso sink' firmware, in needs 'iso src'
halt: needs bulk sink+src, tests halt set/clear from host
unlink: needs bulk sink and/or src, test HCD unlink processing
loop: needs firmware that will buffer N transfers
这样,我们就可以进行了各种单项测试。
比如: ./test.sh in | tee test_in.log
等等。
根据要求,这些测试项应该运行 24 小时以上,由于目前某些基本测试就没有通过,还需要继续优化代码,再进行耐力测试。
USB Testing on Linux
http://www.linux-usb.org/usbtest/index.html