Linux usb core阅读
OHCI和UHCI支持的是usb1.1的控制器,支持的硬件范围不一样;EHCI支持的是usb2.0控制器的高速模式,它本身并不支持全速或者低速模式,硬件上通过TT电路来兼容
CPU不会直接和usb设备通信,而是通过主机控制器HC去控制所有usb设备的通信
usb总线是一种轮询方式的总线,所有的数据传输都必须由主机发起,HC初始化所有的数据传输,各种设备围绕再主机周围
usb通信是通过endpoint,主机和endpoint之间数据传输是通过pipe;usb主机到设备是OUT端点,设备到主机是IN端点;一个usb逻辑设备就是一群端点集合,它与主机之间的通信发生在主机上的一个缓冲区和设备上的一个端点之间,通过管道来传输数据;意思就是管道的一端是主机上的一个缓冲区,一端是设备上的端点; 一个设备可以包括多个接口,一个接口可以有多个端点
pipe通信方式有两种:stream、message;message要求数据有一定格式,stream没有特定格式要求
端点四种类型:
控制传输:配置设备、获取设备信息、发送命令到设备、发送控制信息的,每个usb设备都有EP0控制端点
中断传输:固定速率传输少量数据
批量传输:传输大量数据,保证数据没有丢失
等时传输:传输大量数据,不能保证数据是否送达,以稳定速率发送和接收实时的信息,对传输延迟比较敏感
从usb_init开始
ubsys_initcall(usb_init):
函数开头__init标记,表明这个函数仅在初始化期间使用,在模块装载之后它占用的资源就会释放
#define __init attribute ((section (“.init.text”)))
__arrtibute__标记,它被用来声明一些特殊的属性,这些属性主要用来指示编译器进行特定方面的优化和更仔细的代码检查
__section属性标记,可以让编译器将函数或变量放在指定的节中;通常编译器将函数放在.txt节中,变量放在.data或者.bss节中
那init是如何被调用的:
#define subsys_initcall(fn) __define_initcall(“4”,fn,4) :将指定的函数指针fn放在 .initcall4.init 节中
在vmlinux.lds文件中,搜索initcall.init :
__inicall_start = .;
.initcall.init : AT(ADDR(.initcall.init) – 0xC0000000) {
*(.initcall1.init)27
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
subsys_initcall宏便是将指定的函数指针放在了 .initcall4.init 子节,其他比如core_initcall 将函数指针放在 .initcall1.init 子节等等;调用时是顺序调用的,
最初实际的执行函数调用地方是在init/main.c文件中,内核初始化,do_initcalls函数会直接用到 __initcall_start、__initcall_end
nousb:
一个标志,在启动内核时通过内核参数cmdline去掉usb子系统的
设备模型:
总线、设备、驱动、kset、kobject:
总线、设备、驱动是一个个的对象; kobject是它们的基类,实现一些公共接口;kset是同类型的kobject对象的集合,对象的容器;
bus总线有两条链表:devices设备链表和drivers驱动链表
有新设备或者新驱动注册加载时,就把它们分别加入到链表中,这样就可以通过bus总线找到device和driver
新加一个设备或者驱动,就会去驱动或者设备链表中寻找自己合适的另一半,找到了就device_bind_driver绑定
struct usb_bus_type:
const struct bus_type usb_bus_type = {
.name = “usb”,
.m