前言:
本文主要介绍入门USB的推荐书籍,硬件, 以及其学习流程, 并不会花大量篇幅阐述usb协议。但也会对一些USB不易理解的知识点进行解析。
本文依旧不停地更新中。有任何对内容的疑惑不解,或指正建议, 请一定要给我留言,我会尽快更新。希望每个希望学习USB的人, 都能学会USB!
1. USB入门推荐书籍
a. 《USB2.0与OTG规范及开发指南》 北京航空航天大学出版社出版的图书,作者是周立功等。
推荐理由: 是usb2.0规范的中文翻译本。各种描述符,usb请求的描述极尽详细。建议人手一本!
b. 《USB技术及应用设计》 2003年清华大学出版社出版的图书,作者是肖踞雄。
推荐理由: 包含ohci,uhci,ehci的寄存器的中文翻译;标准usb描述符及请求的中文描述。
c. ohci规范,ehci规范。
推荐理由:虽然《USB技术及应用设计》一书已有ehci和ohci寄存器的中文说明,但不是太详细,仍需要看看官方文档。
d. 《Linux内核源代码情景分析(下册)》 作者: 毛德操 / 胡希明
推荐理由: 第8章 “设备驱动”的8.9节 “通用串行外部总线USB”,基于linux2.4对uhci的初始化,数据传输进行详细描述。
e. 《Linux那些事儿之我是USB》
推荐理由:本书主要介绍usb的框架,底层寄存器操作的介绍是没有的。随着学习的深入,此书也应该会用到。
f. 《圈圈教你玩usb》
推荐理由: 有USB标准描述符,标准请求和四种数据传输的描述,可以作为参考书。
2. USB入门推荐硬件
a. mini2440
推荐理由: 包含OHCI。
b. orangepi3
推荐理由: 包含OHCI,EHCI,XHCI 以及 OTG。 差不到买了这块板子,mini2440就不用买了。。。
c. usb packet viewer
推荐理由:usb分析仪,能够分析高速,全速,低速传输。学习过程中,我所遇到的那些,在代码层面无法解决的问题,都经由它的帮助而解决! 十分推荐。
3. USB入门推荐学习方法
USB的学习方法,我推荐从精简USB控制器代码开始。根据以下的精简方式,剥离USB框架,去掉各种传参, 使得usb控制器获取设备描述符的硬件操作流程一览无遗,获得一次纯粹的USB控制器的控制传输。
模仿此次的控制传输,我们可以继续地设置设备的地址,获取设备的配置描述符。再而是批量传输或周期传输。
这里将使用到Orangepi3的uboot,这里给出我已修改dts和config,以开启EHCI的uboot的下载地址。
sunxi_h6_uboot: 原全志H6的uboot代码, 仅修改dts和config, 以开启ehci。
https://gitee.com/suiren/uboot_camera
uboot_sunxiH6_udisk_read: 基于uboot的u盘读写。简化usb代码, 只保留需要的硬件操作代码,非常适合阅读和学习ehci及usb。
a. 基于UBOOT进行USB控制器代码的精简
通过对UBOOT的usb控制器代码的精简,仅保留其硬件操作代码,这样便能够自主地对usb控制器编程,体验usb的四种传输,让usb协议的学习不再纸上谈兵!
那么,如何对usb控制器代码进行精简呢?
我推荐以下步骤:
步骤0: 定位usb相关代码位置,使用sed批量添加函数名打印,以了解usb控制器驱动程序的执行流程。
uboot上的usb相关代码:common/usb*.c ; drivers/usb/host;
sed使用方法跳转至此链接:SED代码调试大法_天下虽人的博客-CSDN博客
步骤1: 找到第一次获取设备描述符的代码段,以此作为程序运行的终点。注意,获取根集线器的描述符是不经过usb总线的,必须是对外部设备获取设备描述符。
步骤2: 进入获取设备描述符的函数内,找到最终传输数据的代码,从这里开始精简。即由底层至上层的精简方式。
ehci的最终的批量和控制传输的函数为:ehci_submit_async(), 位于drivers/usb/host/ehci-hcd.c文件。
ohci的最终的数据传输函数为:td_submit_job(),位于drivers/usb/host/ohci-hcd.c文件。
详细待补充。
步骤3: 可以与步骤2并行。 精简获取根集线器各种描述符的相关函数,以及和根集线器相关的各种请求函数。譬如,在_ehci_submit_control_msg()函数,此函数位于drivers/usb/host/ehci-hcd.c文件。这个函数里的ehci_submit_root()函数,就是专提供于根集线器的,不经由USB总线的,获取根集线器数据的函数。
static int _ehci_submit_control_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int length,
struct devrequest *setup)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
if (usb_pipetype(pipe) != PIPE_CONTROL) {
debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
return -1;
}
if (usb_pipedevice(pipe) == ctrl->rootdev) {
if (!ctrl->rootdev)
dev->speed = USB_SPEED_HIGH;
return ehci_submit_root(dev, pipe, buffer, length, setup);
}
return ehci_submit_async(dev, pipe, buffer, length, setup);
}
b. 基于s3c2440_usb_host_rw代码进行USB控制器代码的精简
s3c2440_usb_host_rw代码可以在CSDN找到,是MINI2440的专用代码,实现ochi读取u盘数据。
相比于精简UBOOT的USB控制器代码, 精简此代码要简单一些。精简步骤和a相同。