聊完了struct usb_hcd和struct usb_bus,算是已经向HCD片儿区的老大们拜过山头了,接下来就该看看usb_submit_urb()最后的那个遗留问题usb_hcd_submit_urb()了,要有心理准备,也是个一百多行的狠角色。现在内核里有个很不好的现象,设计结构比复杂,写函数比长。如果你缺少动力往下看,就去看一遍福布斯美国富翁排行榜,如果上面没有你的名字,你就继续往下看,这是勉励俺的,也拿来与你共勉。
drivers/usb/core/hcd.c
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
/* increment urb's reference count as part of giving it to the HCD
* (which will control it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
usb_get_urb(urb);
atomic_inc(&urb->use_count);
atomic_inc(&urb->dev->urbnum);
usbmon_urb_submit(&hcd->self, urb);
/* NOTE requirements on root-hub callers (usbfs and the hub
* driver, for now): URBs' urb->transfer_buffer must be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data. Also, control
* URBs must be submitted in process context with interrupts
* enabled.
*/
if (is_root_hub(urb->dev)) {
status = rh_urb_enqueue(hcd, urb);
} else {
status = map_urb_for_dma(hcd, urb, mem_flags);
if (likely(status == 0)) {
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
if (unlikely(status))
unmap_urb_for_dma(hcd, urb);
}
}
if (unlikely(status)) {
usbmon_urb_submit_error(&hcd->self, urb, status);
urb->hcpriv = NULL;
INIT_LIST_HEAD(&urb->urb_list);
atomic_dec(&urb->use_count);
atomic_dec(&urb->dev->urbnum);
if (atomic_read(&urb->reject))
wake_up(&usb_kill_urb_queue);
usb_put_urb(urb);
}
return status;
}
usb_hcd_submit_urb是hcd.c里的,目标也很明确,就是将提交过来的urb指派给合适的主机控制器驱动程序。core目录下面以hcd打头的几个文件严格来说不能算是HCD,只能算HCDI,即主机控制器驱动的接口层,用来衔接具体的主机控制器驱动和usb core的。
4行,bus_to_hcd在哪里提到过一下,是用来获得struct usb_bus结构体对应的struct usb_hcd结构体,urb要去的那个设备所在的总线是在设备生命线的开头儿就初始化好了的,忘了可以再蓦然回首一下。bus_to_hcd还有个兄弟hcd_to_bus,都在include/linux/usb/hcd.h里定义
static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
{
return &hcd->self;
}
static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus)
{
return container_of(bus, struct usb_hcd, self);
}
13行,usbmon_urb_submit就是与前面Greg孕育出来的usb Monitor有关的,如果你编译内核的时候没有配置上CONFIG_USB_MON,它就啥也不是,一个空函数,一具空壳。
23行,判断这个urb是不是流向root hub的,如果是,它就走向了root hub的生命线。不过,毕竟你更关注的是你的usb设备,应该很少有机会和欲望直接和root hub交流些什么。
26行,如果这个主机控制器支持DMA
28行,终于可以将urb扔给具体的主机控制器驱动程序了,urb可以欢快的尽情呼喊,UHCI,OHCI,EHCI,我来了!
下面的路就让urb去走吧,咱们说到这里也该回头了,经过了这么多事,遇到了这么多人,我始终都不能忘怀自己是从设置设备地址,发送SET_ADDRESS请求给主机控制器开始,这么一路走过来的,到现在,设备已经可以进入Address状态,这桩心愿已了,该继续看设备的那条生命线了。