聊完了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状态,这桩心愿已了,该继续看设备的那条生命线了。
分享到:
相关推荐
2.6.22内核的usb core源码分析。原文为blog.csdn.net/fudan_abc上的《linux那些事儿之戏说USB》。
我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核
然后是usb core(也就是戏说USB),这一阶段是个承上启下的角色,承的是U盘/HUB,启的是UHCI/EHCI,主要描述一个usb设备连接到hub上之后,在HUB和UHCI/EHCI之间也就是usb core里发生的故事. 再然后可以开始看UHCI/EHCI.这...
第九章会修电脑不会修收音机?——聊设计模式原则 第十章三层架构,分层开发 第十一章无熟人难办事?——聊设计模式迪米特法则 第十二章有了门面,程序员的程序会更加体面 第十三章设计模式不能戏说!设计模式怎就不...
兄弟连Linux基础知识与系统管理课件
大班音乐:戏说脸谱.ppt
戏说指针 如何分析指针类型 细说指针 指针的类型 指针所指向的类型 指针的值 指针本身所占据的内存区
C# 面向对象设计 让你了解C#的面向对象的设计原理 更好的掌握C#的学习 真正的成为C#高手
一本很不错的讲面向对象的书,给大家分享下 !
指针的本质、指针的三要素、类型与变量名
幼儿园大班歌唱教案:戏说脸谱.doc
简单明了的解释 很实用
1.使用轻松的方式解释23种设计模式,很容易理解
戏说国学.doc
戏说面向对象程序设计(C#版)面向对象程序设计(C#版)
戏说绩效工资.doc
幼儿园教案2021-幼儿园大班歌唱教案:戏说脸谱.doc
戏说面向对象程序设计之C#版,适合初学者的再进一步学习,里面包含了一些设计模式,如工厂模式等,内容轻松幽默,适合初学者和有一定面向对象基础的对象,推荐阅读。
戏说信号与系统,大家可以参考一下,很浅显易懂