今年过节不收礼啊,不收礼,收礼只收结构体。
从尖沙咀儿辛辛苦苦赶到铜锣湾,算是进入了HCD的片儿区,这里的老大不是帮派头目也不是巡逻片儿警,而是几个结构。C里边是以结构为王的,随便到一个新地方,新环境,新山头儿,首先要去结识的就是几个占山为王,雄据一方的结构。在HCD这个片儿区,这个山头儿,王中之王就是drivers/usb/core/hcd.h里定义的struct usb_hcd。
50* USB Host Controller Driver (usb_hcd) framework
52* Since "struct usb_bus" is so thin, you can't share much code in it.
53* This framework is a layer over that, and should be more sharable.
56 /*------------------------------------------------------------------------*/
67 char irq_descr[24];/* driver + bus # */
69 struct timer_list rh_timer; /* drives root-hub polling */
70 struct urb *status_urb; /* the current status urb */
80 /* Flags that need to be manipulated atomically */
85 unsigned rh_registered:1;/* is root hub registered? */
87 /* The next flag is a stopgap, to be removed when all the HCDs
88 * support the new root-hub polling mechanism. */
89 unsigned uses_new_polling:1;
90 unsigned poll_rh:1; /* poll for rh status? */
92 unsigned wireless:1; /* Wireless USB HCD */
94 int irq; /* irq allocated */
96 u64 rsrc_start; /* memory/io resource start */
97 u64 rsrc_len; /* memory/io resource length */
98 unsigned power_budget; /* in mA, 0 = no limit */
117 /* more shared queuing code would be good; it should support
118 * smarter scheduling, handle transaction translators, etc;
119 * input size of periodic table to an interrupt scheduler.
120 * (ohci 32, uhci 1024, ehci 256/512/1024).
123 /* The HC driver's private data is stored at the end of
126 unsigned long hcd_priv[0]
经过了血与火,熊市与牛市的洗礼,我们都应该对这种变态结构习以为常了,男人么,图不了房子图不了车子图不了美女,能图的还有啥?不就是一颗平常心么。那就用一颗平常心去想想,换作你,会怎么用一个结构去描述主机控制器?毫无头绪吧,这就对了,要真是思如泉涌的话就和写代码的哥们儿一样变态了。
63行,又一个结构体,struct usb_bus,还名曰self,struct usb_hcd里还有self,看来这家伙是双子座的,以为能再分裂出一个自己,和黄金十二宫里的双子一样。俺也是双子的,不过俺从来没想再分裂出一个,现在世道艰难,一个就已经存活不易了。
为什么这里会用这么一个戏剧性的词汇self?难道Greg他们都是具有乐观主义精神的无产阶级革命者?当然不是,他们都是资产阶级,咱们才是无产阶级。俺在前面的某处提到过那么一下,一个主机控制器就会连出一条usb总线,主机控制器驱动用struct usb_hcd结构表示,一条总线用struct usb_bus结构表示,它们是白天与黑夜般相生相依的关系,一个白天只能连着一个黑夜,一个黑夜只能引出一个白天,没听说过谁过了两个白天才到夜里的,如果谁说了,他不是疯子就是哲学家或经济学家。struct usb_bus在include/linux/usb.h里定义
274* Allocated per bus (tree of devices) we have:
278 int busnum; /* Bus number (in order of reg) */
279 char *bus_name; /* stable id (PCI slot_name etc) */
280 u8 uses_dma; /* Does the host controller use DMA? */
281 u8 otg_port; /* 0, or number of OTG/HNP port */
282 unsigned is_b_host:1; /* true during some HNP roleswitches */
283 unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
285 int devnum_next; /* Next open device number in
286 * round-robin allocation */
288 struct usb_devmap devmap; /* device address allocation map */
292 int bandwidth_allocated; /* on this bus: how much of the time
293 * reserved for periodic (intr/iso)
294 * requests is used, on average?
295 * Units: microseconds/frame.
296 * Limits: Full/low speed reserve 90%,
297 * while high speed reserves 80%.
299 int bandwidth_int_reqs; /* number of Interrupt requests */
300 int bandwidth_isoc_reqs; /* number of Isoc. requests */
302 #ifdef CONFIG_USB_DEVICEFS
303 struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
307 #if defined(CONFIG_USB_MON)
309 int monitored; /* non-zero when monitored */
277行,controller,struct usb_hcd那里含了个usb_bus,这里就回应了个controller,你山西来个黑砖窑,我唐山就回应个黑军车,黑对黑,遥相呼应。那现在通过struct usb_hcd里的self和struct usb_bus里的controller这两个很有乐观主义精神的词儿,你能不能说下它们到底是什么关系?你当然可以说是一个对应主机控制器,一个描述一条总线,但其实对于写代码的来说一个主机控制器和一条总线差不多是一码事,不用分的那么清,可以简单的说它们都是用来描述主机控制器的,那为什么又分成了两个结构,难道Greg他们现在又不信奉简约主义了?
这个问题的答案我也很想知道,但知道了又能怎么样?知道了你就能明白为什么美女都不喜欢你,为什么她们身上衣服件数越多反而露得越多?你不能明白,所以也不用去知道了。不过思索了一杯茶的时间,还是有那么点儿线索。不要小看这杯茶,按日里万鸡来换算,这点儿时间都能理多少鸡了?
前面说过linux里和小李飞刀齐名的就是设备模型了,usb主机控制器当然也是一个设备,而且更多的时候它还是一个PCI设备,那它就应该纳入这个设备模型范畴之内,struct usb_hcd结构里就得嵌入类似struct device或struct pci_dev这样的一个结构体,但是你仔细瞅瞅,能不能在它里面发现这么一个成员?不能,对于一个设备来说,这可是大逆不道的。但是你再瞅瞅struct usb_bus,第一个就是一个struct device结构体。好,第一条线索就先到这儿。
再利用这杯茶的时间挑个具体的主机控制器驱动程序快速的走一下,就UHCI吧,都在host目录下的uhci-族文件里,首先它是个pci设备,要使用pci_register_driver注册一个struct pci_driver结构体uhci_pci_driver,uhci_pci_driver里又有个熟悉的probe,在这个probe里,它调用usb_create_hcd来创建一个usb_hcd,初始化里面的self,还将这个self里的controller设定为描述主机控制器的那个pci_dev里的struct device结构体,从而将usb_hcd、usb_bus和pci_dev,甚至设备模型都连接起来了。
这杯茶应该还没有这么快就喝的完,那就再接着巡视一下uhci-文件里定义的那些函数,只用看它们的参数,你会发现参数里不是struct usb_hcd就是struct uhci_hcd,如果你和我一样无聊愿意多看点的话,你会看到那些函数的前面几行常常会有hcd_to_uhci或者uhci_to_hcd这样的函数在struct usb_hcd和struct uhci_hcd之间做着转换。struct uhci_hcd是什么?它是uhci自己私有的一个结构体,就像每个成功的男人背后都有一个女人一样,每个具体的主机控制器都有这么一个类似的结构体。如果你再无聊一下,顺便瞧了下hcd_to_uhci或者uhci_to_hcd的定义,你就会明白,每个主机控制器的这个私有结构体都藏在struct usb_hcd结构最后的那个hcd_priv变长数组里。
通过这杯茶,你能悟出什么?如果说镜头闪的太快,让你看的不太明白,那就只管听俺说好了。对于具体的主机控制器驱动来说,它们的眼里只有struct usb_hcd,struct usb_hcd结构之于主机控制器驱动,就如同struct usb_device或struct usb_interface之于usb驱动。没有usb_create_hcd去创建usb_hcd,就不会有usb_bus的存在。而对于linux设备模型来说,struct usb_bus无疑要更亲切一些。总之,你可以把struct usb_bus当作只是嵌入到struct usb_hcd里面的一个结构体,它将struct usb_hcd要完成的一部分工作进行了封装,因为要描述一个主机控制器太复杂太难,于是就开了struct usb_bus这么一个窗户去专门面对设备模型、sysfs等等。这也就是俺开头儿就说这个片儿区,struct usb_hcd才是王中之王的原因。
你知道Greg他们是怎么描述这种奇妙的关系么?他们把这个叫作HCD bus-glue layer,并致力于flatten out it. 这个关系早先是比较混沌的,现在要清晰些,以后只会更清晰,struct usb_hcd越来越走上台前,struct usb_bus越来越走向幕后。就好像我们一开始是天地混沌,然后是女娲造人,有了社会有了阶级,再然后才有了新中国一样。
278行,busnum,总线编号,你的机子里总可以有多个主机控制器吧,自然也就可以有多条usb总线了,既然可以有多条,就要编个号方便确认了。有关总线编号,可以看看定义在drivesr/usb/core/hcd.c里的这几行
88 /* used when allocating bus numbers */
讲struct usb_device的devnum时候,说到过一个devicemap,这里又有个busmap,当时分析说devicemap一共有128位,同理可知,这里的busmap一共有64位,也就是说最多可以有64条usb总线,如果你还觉得不够,言一声,我可以躲你远远的。
279行,bus_name,bus总线,name名字,bus_name总线的名字,什么样的名字?要知道大多数情况下主机控制器都是一个PCI设备,那么bus_name应该就是用来在PCI总线上标识usb主机控制器的名字,PCI总线使用标准的PCI ID来标识PCI设备,所以bus_name里保存的应该就是主机控制器对应的PCI ID。UHCI等调用usb_create_hcd创建usb_hcd的时候确实是将它们对应PCI ID赋给了bus_name。
现在简单说说这个PCI ID。PCI spec允许单个系统可以最多有256条PCI总线,对咱们当然是太多了,但是对于一些极变态,需求极为旺盛的系统,它可能还觉得这满足不了要求,于是所有的PCI总线又被划分为domain,每个PCI domain又可以最多拥有256条总线,这下总该够了吧,而每条总线上又可以支持32个设备,这些设备里边儿还都可以是多功能板,它们还都可以最多支持8种功能。那系统怎么来区分每种功能?总要知道它在哪个domain,哪条总线,哪个设备板上吧。这么说还是太笼统了,你可以用lspci命令看一下
00:00.0 Host bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX Host bridge (rev 01)
00:01.0 PCI bridge: Intel Corporation 440BX/ZX/DX - 82443BX/ZX/DX AGP bridge (rev 01)
00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08)
00:07.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)
00:07.2 USB Controller: Intel Corporation 82371AB/EB/MB PIIX4 USB
00:07.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08)
00:0f.0 VGA compatible controller: VMware Inc [VMware SVGA II] PCI Display Adapter
00:10.0 SCSI storage controller: LSI Logic / Symbios Logic 53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI (rev 01)
00:11.0 Ethernet controller: Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE] (rev 10)
00:12.0 Multimedia audio controller: Ensoniq ES1371 [AudioPCI-97] (rev 02)
每行前面的数字就是所谓的PCI ID,每个PCI ID由domain号(16位),总线编号(8位),设备号(5位),功能号(3位)组成,不过这里lspci没有标明domain号,但对于一台普通PC而言,一般也就只有一个domain,0x0000。
280行,uses_dma,表明这个主机控制器支持不支持DMA。主机控制器的一项重要工作就是在内存和USB总线之间传输数据,这个过程可以使用DMA或者不使用DMA,不使用DMA的方式即所谓的PIO方式。DMA代表着Direct Memory Access,即直接内存访问,不需要CPU去干预。具体的去看看PCI DMA的东东吧,因为一般来说主机控制器都是PCI设备,uses_dma都在它们自己的probe函数里设置了。
281~283行,有关otg的,飘过。
285行,devnum_next,288行,devmap,早就说过devmap这张表了,devnum_next中记录的就是这张表里下一个为0的位,里面为1的位都是已经被这条总线上的usb设备占据了的,名花有主的。
289行,root_hub,就好像端点0在所有设备的端点里面那么的鹤立鸡群一样,root hub在所有的hub里面也是那么的特殊,还记得usb的那颗树么,它就是那颗树的根,和usb主机控制器绑定在一起,其它的hub和设备都必须从它这儿延伸出去。正是因为这种特殊的关系,写代码的哥们儿也素有成人之心,就直接将它放在了struct usb_bus结构里,让他们永不分离。usb主机控制器,usb总线,root hub,1比1比1。
290行,bus_list,在drivers/usb/core/hcd.c中定义有一个全局队列usb_bus_list
84 /* host controllers we manage */
它就是所有usb总线的组织。每次一条总线新添加进来,都要向这个组织靠拢,都要使用bus_list字段链接在这个队列上。
292行,bandwidth_allocated,表明总线为中断传输和等时传输预留了多少带宽,协议里说了,对于高速来说,最多可以有80%,对于低速和全速要多点儿,可以达到90%。它的单位是微妙,表示一帧或微帧内有多少微妙可以留给中断/等时传输用。
299行,bandwidth_int_reqs,300行,bandwidth_isoc_reqs,分别表示当前中断传输和等时传输的数量。
302~304行,是usbfs的,每条总线都对应于/proc/bus/usb下的一个目录。你无聊的话可以去瞅瞅。
305行,class_dev,这里又牵涉到设备模型中的一个概念,设备的class,即设备的类。像前面提到的设备模型里的总线、设备、驱动三个核心概念,纯粹是从写驱动的角度看的,而这里的类则是面向于linux的广大用户的,它不管你是用什么接口,怎么去连接,它只管你对用户来说提供了什么功能,一个SCSI硬盘和一个ATA硬盘对驱动来说是八杆子打不着的两个东西,但是对于用户来说,它们都是硬盘,都是用来备份文件,备份各种小电影的,这也就是所谓的物以类聚人以群分。
设备模型与sysfs是分不开的,class在sysfs里的体现就在/sys/class下面,可以去看看
atm dma graphics hwmon i2c-adapter input
mem misc net pci_bus scsi_device scsi_disk
scsi_host sound spi_host spi_master spi_transport tty
usb_device usb_endpoint usb_host vc vtconsole
看到里面的usb_host了吧,它就是所有usb主机控制器的类,这些目录都是怎么来的那?咱们还要追溯一下usb子系统的初始化函数usb_init,它里面有这么一段
879 goto host_init_failed;
当时只是简单说这是用来初始化host controller的,现在鼓气勇气进去看看,在hcd.c里
usb_host_init所作的一切就是调用class_create创建了一个usb_host这样的类,你只要加载了usbcore模块就能在/sys/class下面看到有usb_host目录出现。既然usb_host目录表示的是usb主机控制器的类,那么它下面应该就对应各个具体的主机控制器了,你用ls 命令look一下就能看到usb_host1、usb_host2等等这样的目录,它们每个都对应一个在你系统里实际存在的主机控制器,实际上在hcd.c里的usb_register_bus函数有这么几行
这两行就是使用class_device_create在/sys/class/usb_host下面为每条总线创建了一个目录,目录名里的数字代表的就是每条总线的编号,usb_register_bus函数是每个主机控制器驱动在probe里调用的,向usb core注册一条总线,也可以说是注册一个主机控制器。
307~310行,CONFIG_USB_MON是干吗用的?这要看看drivers/usb/mon目录下的Kconfig
2 # USB Monitor configuration
10If you say Y here, a component which captures the USB traffic
11 between peripheral-specific drivers and HC drivers will be built.
12 For more information, see <file:Documentation/usb/usbmon.txt>.
14 This is somewhat experimental at this time, but it should be safe.
文件里就这么多内容,从里面咱们可以知道,如果定义了CONFIG_USB_MON,一个所谓的usb Monitor,也就是usb监视器的东东就会编进内核。这个Monitor是用来监视usb总线上的底层通信流的,相关的文件都在drivers/usb/mon下面。2005年的阳春三月,Greg大侠春心思动,于是就孕育出了这个usb Monitor。
分享到:
相关推荐
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#版,适合初学者的再进一步学习,里面包含了一些设计模式,如工厂模式等,内容轻松幽默,适合初学者和有一定面向对象基础的对象,推荐阅读。
戏说信号与系统,大家可以参考一下,很浅显易懂