聊完了struct usb_hcd和struct usb_bus,算是已经向HCD片儿区的老大们拜过山头了,接下来就该看看usb_submit_urb()最后的那个遗留问题usb_hcd_submit_urb()了,要有心理准备,也是个一百多行的狠角色。现在内核里有个很不好的现象,设计结构比复杂,写函数比长。像一个中介语重心长的说:我承认的确房屋中介有不好的现象,收看房费,收差价,很是让人生气,作为业内人士我感到很心酸,但是还是有好的啊。不管怎地苦的都是我们,如果你缺少动力往下看,就去看一遍福布斯美国富翁排行榜,如果上面没有你的名字,你就继续往下看,这是勉励俺的,也拿来与你共勉。
916 /* may be called in any context with a valid urb->dev usecount
917
* caller surrenders "ownership" of urb
918
* expects usb_submit_urb() to have sanity checked and conditioned all
934
* Atomically queue the urb,first to our records, then to the HCD.
935
* Access to urb->status is controlled by urb->lock ... changes on
936
* i/o completion (normal or fault) or unlinking.
939 // FIXME:verify that quiescing hc works right (RH cleans up)
956 /* HC upstream links (register access, wakeup signaling) can work
957 * even when the downstream links (and DMA etc) are quiesced; let
958
* usbcore talk to the root hub.
975 /* increment urb's reference count as part of giving it to the HCD
976 * (which now controls it).HCD guarantees that it either returns
977 * an error or calls giveback(), but not both.
983 /* NOTE:requirement on hub callers (usbfs and the hub
984 * driver, for now) that URBs' urb->transfer_buffer be
985 * valid and usb_buffer_{sync,unmap}() not be needed, since
986 * they could clobber root hub response data.
992 /* lower level hcd code should use *_dma exclusively,
993 * unless it uses pio or talks to another transport.
1003 if (urb->transfer_buffer_length != 0
usb_hcd_submit_urb是hcd.c里的,目标也很明确,就是将提交过来的urb指派给合适的主机控制器驱动程序。core目录下面以hcd打头的几个文件严格来说不能算是HCD,只能算HCDI,即主机控制器驱动的接口层,用来衔接具体的主机控制器驱动和usb core的。
924行,bus_to_hcd在哪里提到过一下,是用来获得struct usb_bus结构体对应的struct usb_hcd结构体,urb要去的那个设备所在的总线是在设备生命线的开头儿就初始化好了的,忘了可以再蓦然回首一下。bus_to_hcd还有个兄弟hcd_to_bus,都在hcd.h里定义
这俩函数傻强都能看懂,继续看928行,也是大多数函数开头儿必备的常规检验,如果usb_hcd都还是空的,那就别开国际玩笑了,返回吧。
931行,usbmon_urb_submit就是与前面Greg孕育出来的usb Monitor有关的,如果你编译内核的时候没有配置上CONFIG_USB_MON,它就啥也不是,一个空函数,一具空壳。
941行,去获得一把锁,这把锁在hcd.c的开头儿就已经初始化好了,所以说是把全局锁
102 /* used when updating hcd data */
前边儿多次遇到过自旋锁,不过一直没功夫说它,现在就简单介绍一下。它和信号量,还有前面提到的completion一样都是linux里用来进行代码同步的,为什么要进行同步?你要知道在linux这个庞大负责的世界里,不是只有你一个人在战斗,可能同时有多个线程,多杆枪在战斗,那么只要他们互相之间有一定的共享,就必须要保证一个人操作这个共享的时候让其它人知道,这么说吧,你和另外一个人带领两只队伍去打土匪窝,结果你方武力值,智力值比较高,先占领了山头儿,你得插把旗子表示你已经占领了,让友军不要再打了,过来享受胜利果实吧,里边土匪太太,美酒美食一堆一堆的,如果你什么都不说,没插旗子也没其它什么暗号表示一下,只顾自个儿享受了,那边儿正打着过瘾谁知道在匪窝儿里的是你还是土匪啊。所以说同步是多重要啊,保持共享代码的状态一致是多么重要啊。
自旋锁身为同步机制的一种,自然也有它独特的本事,它可以用在中断上下文或者说原子上下文使用。上下文就是你代码运行的环境,linux的这个环境使用二分法可以分成两种,能睡觉的环境和不能睡觉的环境。像信号量和completion就只能用在可以睡觉的环境,而自旋锁就用在不能睡觉的环境里。而咱们的usb_submit_urb还有usb_hcd_submit_urb必须得在两种环境里都能够使用,所以使用的是自旋锁,那在什么时候都不能睡觉了还有心情去调用它们那?想想urb的那个结束处理函数,它就是不能睡觉的,但它里面必须得能够重新提交urb。
那再说说hcd_data_lock这把锁都是用来保护些什么的,为什么要使用它?主机控制器的struct usb_hcd结构体在它的驱动里早就初始化好了,就那么一个,但同一时刻是可能有多个urb向同一主机控制器申请进行传输,可能有多个地方都希望访问它里面的内容的,比如948行的state元素,显然就要同步了,hcd_data_lock这把锁就是专门用来保护主机控制器的这个结构体的。
942行,遇到多次也说过多次了,知道了pipe,就可以从struct usb_device里的两个数组ep_in和ep_out里拿出对应端点的struct usb_host_endpoint结构体。写代码的哥们儿也知道咱们说过多次了,就直接把这一堆搞一行里了。
944~973这些行都是做检验的,写个代码真费劲儿,到处都是地雷暗礁,到处都要检验。就好像去年以前还处于公粮时代的时候,那些验粮的,要一关又一关的,发生了多少可歌可泣的故事啊。验粮的都要牙好,写代码看代码的当然都要耐心好了。
944行,显然都走到这一步了,目的端点为空的可能性太小了,所以加上了unlikely。
946行,前面还费了点口舌说过,urb里的这个reject,只有
usb_kill_urb有特权修改它,如果走到这里发现它的值大于0了,那就说明哪里调用了
usb_kill_urb要终止这次传输,所以就还是返回吧,不过这种可能性比较小,没人无聊到那种地步,总是刚提交就终止,吊主机控制器胃口,所以仍然加上unlikely。
948行,如果上面那两个检验都通过了,现在就case一下主机控制器的状态,如果为HC_STATE_RUNNING或HC_STATE_RESUMING就说明主机控制器这边儿没问题,尽管将这个urb往端点的那个urb队列里塞好了,952行就是完成这个的,struct urb那么变态的结构都熬过来了,这行是小case了。如果主机控制器的状态为HC_STATE_SUSPENDED,但它的上行链路能够工作,且这个urb是送往root hub的,则将其塞到root hub的urb队列里。
然后判断上面几次检验的结果,如果一切正常,则继续往下走,否则就黯然回头吧。
979行,检验都通过了,可以放心的增加urb的引用计数了。
980行,将urb的use_count也增加1,表示urb已经被HCD接受了,正在被处理着。你如果对这两个引用计数什么差别还有疑问,再蓦然回首一下看看说struct urb时讲的。
982行,判断这个urb是不是流向root hub的,如果是,它就走向了root hub的生命线。不过,毕竟你更关注的是你的usb设备,应该很少有机会和欲望直接和root hub交流些什么。
995行,如果这个主机控制器支持DMA,可你却没有告诉它URB_NO_SETUP_DMA_MAP或URB_NO_TRANSFER_DMA_MAP这两个标志,它就会认为你在urb里没有提供DMA的缓冲区,就会调用dma_map_single将setup_packet或transfer_buffer映射为DMA缓冲区。
1014行,终于可以将urb扔给具体的主机控制器驱动程序了,urb可以欢快的尽情呼喊,UHCI,OHCI,EHCI,我来了!
下面的路就让urb去走吧,咱们说到这里也该回头了,经过了这么多事,遇到了这么多人,我始终都不能忘怀自己是从设置设备地址,发送SET_ADDRESS请求给主机控制器开始,这么一路走过来的,到现在,设备已经可以进入Address状态,这桩心愿已了,该继续看设备的那条生命线了。