4.1.1 USB Core的初始化 USB驱动从USB子系统的初始化开始,USB子系统的初始化在文件driver/usb/core/usb.c
[cpp] view plaincopy
- subsys_initcall(usb_init);
- module_exit(usb_exit);
subsys_initcall()是一个宏,可以理解为module_init()。由于此部分代码非常重要,开发者把它看作一个子系统,而不仅仅是一个模块。USB Core这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块。在Linux中,像这样一个类别的设备驱动被归结为一个子系统。subsys_initcall(usb_init)告诉我们,usb_init才是真正的初始化函数,而usb_exit将是整个USB子系统结束时的清理函数。
4.1.2 主机控制器的初始化及驱动执行(以EHCI为例) module_init(otg_init); 模块注册
static init __init otg_init(void);
platform_driver_register(); 平台注册
static int __init otg_probe(struct platform_device *pdev); 探测处理函数
reg = platform_get_resource(pdev, IORESOURCE_MEM, 0); 获取寄存器信息
data = platform_get_resource(pdev,IORESOURCE_MEM, 1); 获取内存信息
irq = platform_get_irq(pdev,0); 获取中断号
usb_create_hcd(&otg_hc_driver, &pdev->dev, pdev->dev.bus_id);
分配和初始化HCD结构体。对设备数据空间进行分配,初始化计数器、总线、定时器、hcd结构体各成员值。
ret = usb_add_hcd(hcd,irq,SA_INTERRUPT);
完成HCD结构体的初始化和注册。申请buffer,注册总线、分配设备端内存空间,向中断向量表中申请中断,注册根集线器,对根集线器状态进行轮询。
4.1.3 注册集线器 register_root_hub(hcd);
在USB系统驱动加载的过程中,创建了集线器的线程(khubd),并且一直查询相应的线程事务。HCD驱动中,将集线器作为一个设备添加到主机控制器驱动中,然后进行集线器端口的初始化。在USB主机看来,根集线器本身也是USB主机的设备。USB主机驱动加载完成之后,即开始注册根集线器,并且作为一个设备加载到主机驱动之中。
USB主机和USB设备之间进行数据交互,USB设备本身并没有总线控制权,U盘被动地接收USB主机发送过来的信息并做出响应。USB主机控制器与根集线器构成了主机系统,然后外接其它的USB设备。
为了更好地探测到根集线器的状态变化,USB主机控制器驱动增加了状态轮询函数,以一定的时间间隔轮询根集线器状态是否发生变化。一旦根集线器状态发生变化,主机控制器就会产生相应的响应。
USB主机和USB设备之间的数据传输以URB(USB Request Block)的形式进行。
4.2 URB传输过程 USB初始化过程中,无论是主机控制器驱动还是根集线器驱动,都是通过URB传输获取设备信息。
4.2.1 申请URB struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
为urb分配内存并执行初始化。
4.2.2 初始化URB 初始化具体的urb包
[cpp] view plaincopy
- static
inline
void usb_fill_bulk_urb(struct urb *urb, - struct usb_device *dev,
- unsigned int pipe,
- void *transfer_buffer,
- int buffer_length,
- usb_complete_t complete_fn,
- void *context)
- static
inline
void usb_fill_control_urb(struct urb *urb, - struct usb_device *dev,
- unsigned int pipe,
- unsigned char *setup_packet,
- void *transfer_buffer,
- int buffer_length,
- usb_complete_t complete_fn,
- void *context)
- static
inline
void usb_fill_int_urb(struct urb *urb, - struct usb_device *dev,
- unsigned int pipe,
- void *transfer_buffer,
- int buffer_length,
- usb_complete_t complete_fn,
- void *context,
- int interval)
不同的传输模式下,驱动为之申请不同的URB。其中,Linux内核只支持同步传输外的三种传输事件,ISO事务需要手工进行初始化工作。控制传输事务、批量传输事务、中断传输事务API如上所示。
三种事务传输模式下的URB初始化函数有很多相似之处,主要参数含义如下:
• urb: 事务传输中的urb
• dev: 事务传输的目的设备
• pipe: USB主机与USB设备之间数据传输的通道
• transfer_buffer: 发送数据所申请的内存缓冲区首地址
• length: 发送数据缓冲区的长度
• context: complete函数的上下文
• complete_fn: 调用完成函数
• usb_fill_control_urb()的setup_packet: 即将被发送的设备数据包
• usb_fill_int_urb()的interval: 中断传输中两个URB调度的时间间隔
4.2.3 提交URB URB初始化完成之后,USBD开始通过usb_start_wait_urb()提交urb请求(它调用usb_submit_urb来真正的发送URB请求),添加completition函数。
接下来,从message.c传到主机控制器(hcd.c),开始真正的usb_hcd_submit_urb()。此时,根据是否为根集线器,进入不同的工作队列。
usb_start_wait_urb->
usb_submit_urb->
usb_hcd_submit_urb
a) root_hub传输
若为root hub,将调用rh_urb_enqueue(),共有两种传输事务(控制传输和中断传输)
[cpp] view plaincopy
- static
int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) - {
- if (usb_endpoint_xfer_int(&urb->ep->desc)) // 中断传输
- return rh_queue_status (hcd, urb);
- if (usb_endpoint_xfer_control(&urb->ep->desc)) // 控制传输
- return rh_call_control (hcd, urb);
- return -EINVAL;
- }
b) 非root_hub传输
对于非常root_hub传输,它调用:
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
c) 批量传输
root_hub本身没有批量传输流程,按照控制传输流程,控制传输最终要通过switch语句跳转到Bulk-Only传输流程中。 |