Linux那些事儿 之 戏说USB(28)设备的生命线(七)

      今年过节不收礼啊,不收礼,收礼只收结构体。

从尖沙咀儿辛辛苦苦赶到铜锣湾,算是进入了HCD的片儿区,这里的老大不是帮派头目也不是巡逻片儿警,而是几个结构。C里边是以结构为王的,随便到一个新地方,新环境,新山头儿,首先要去结识的就是几个占山为王,雄据一方的结构。在HCD这个片儿区,这个山头儿,王中之王就是drivers/usb/core/hcd.h里定义的struct usb_hcd。
49 /*
50 * USB Host Controller Driver (usb_hcd) framework
51 *
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.
54 */
55
56 /*------------------------------------------------------------------------*/
57
58 struct usb_hcd {
59
60         /*
61          * housekeeping
62          */
63         struct usb_bus          self;           /* hcd is-a bus */
64         struct kref             kref;           /* reference counter */
65
66         const char              *product_desc; /* product/vendor string */
67         char                    irq_descr[24]; /* driver + bus # */
68
69         struct timer_list       rh_timer;       /* drives root-hub polling */
70         struct urb              *status_urb;    /* the current status urb */
71 #ifdef CONFIG_PM
72         struct work_struct      wakeup_work;    /* for remote wakeup */
73 #endif
74
75         /*
76          * hardware info/state
77          */
78         const struct hc_driver *driver;        /* hw-specific hooks */
79
80         /* Flags that need to be manipulated atomically */
81         unsigned long           flags;
82 #define HCD_FLAG_HW_ACCESSIBLE 0x00000001
83 #define HCD_FLAG_SAW_IRQ        0x00000002
84
85         unsigned                rh_registered:1;/* is root hub registered? */
86
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? */
91         unsigned                poll_pending:1; /* status has changed? */
92         unsigned                wireless:1;     /* Wireless USB HCD */
93
94         int                     irq;            /* irq allocated */
95         void __iomem            *regs;          /* device memory/io */
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 */
99
100 #define HCD_BUFFER_POOLS        4
101         struct dma_pool         *pool [HCD_BUFFER_POOLS];
102
103         int                     state;
104 #       define __ACTIVE                0x01
105 #       define __SUSPEND               0x04
106 #       define __TRANSIENT             0x80
107
108 #       define HC_STATE_HALT           0
109 #       define HC_STATE_RUNNING        (__ACTIVE)
110 #       define HC_STATE_QUIESCING      (__SUSPEND|__TRANSIENT|__ACTIVE)
111 #       define HC_STATE_RESUMING       (__SUSPEND|__TRANSIENT)
112 #       define HC_STATE_SUSPENDED      (__SUSPEND)
113
116
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).
121          */
122
123         /* The HC driver's private data is stored at the end of
124          * this structure.
125          */
126         unsigned long hcd_priv[0]
127                         __attribute__ ((aligned (sizeof(unsigned long))));
128 };
经过了血与火,熊市与牛市的洗礼,我们都应该对这种变态结构习以为常了,男人么,图不了房子图不了车子图不了美女,能图的还有啥?不就是一颗平常心么。那就用一颗平常心去想想,换作你,会怎么用一个结构去描述主机控制器?毫无头绪吧,这就对了,要真是思如泉涌的话就和写代码的哥们儿一样变态了。
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里定义
273 /*
274 * Allocated per bus (tree of devices) we have:
275 */
276 struct usb_bus {
277         struct device *controller;      /* host/master side hardware */
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? */
284
285         int devnum_next;                /* Next open device number in
286                                          * round-robin allocation */
287
288         struct usb_devmap devmap;       /* device address allocation map */
289         struct usb_device *root_hub;    /* Root hub */
290         struct list_head bus_list;      /* list of busses */
291
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%.
298                                          */
299         int bandwidth_int_reqs;         /* number of Interrupt requests */
300         int bandwidth_isoc_reqs;        /* number of Isoc. requests */
301
302 #ifdef CONFIG_USB_DEVICEFS
303         struct dentry *usbfs_dentry;    /* usbfs dentry entry for the bus */
304 #endif
305         struct class_device *class_dev; /* class device for this bus */
306
307 #if defined(CONFIG_USB_MON)
308         struct mon_bus *mon_bus;        /* non-null when associated */
309         int monitored;                  /* non-zero when monitored */
310 #endif
311 };
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 */
89 #define USB_MAXBUS              64
90 struct usb_busmap {
91         unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];
92 };
93 static struct usb_busmap busmap;
讲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,它里面有这么一段
877         retval = usb_host_init();
878         if (retval)
879                 goto host_init_failed;
当时只是简单说这是用来初始化host controller的,现在鼓气勇气进去看看,在hcd.c里
671 static struct class *usb_host_class;
672
673 int usb_host_init(void)
674 {
675          int retval = 0;
676
677          usb_host_class = class_create(THIS_MODULE, "usb_host");
678          if (IS_ERR(usb_host_class))
679                  retval = PTR_ERR(usb_host_class);
680          return retval;
681 }
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函数有这么几行
736                                     bus->controller, "usb_host%d", busnum);
这两行就是使用 class_device_create 在/sys/class/usb_host下面为每条总线创建了一个目录,目录名里的数字代表的就是每条总线的编号,usb_register_bus函数是每个主机控制器驱动在probe里调用的,向usb core注册一条总线,也可以说是注册一个主机控制器。
307~310行,CONFIG_USB_MON是干吗用的?这要看看drivers/usb/mon目录下的Kconfig
1 #
2 # USB Monitor configuration
3 #
4
5 config USB_MON
6         bool "USB Monitor"
7         depends on USB!=n
8         default y
9         help
10          If 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>.
13
14           This is somewhat experimental at this time, but it should be safe.
15
16           If unsure, say Y.

文件里就这么多内容,从里面咱们可以知道,如果定义了CONFIG_USB_MON,一个所谓的usb Monitor,也就是usb监视器的东东就会编进内核。这个Monitor是用来监视usb总线上的底层通信流的,相关的文件都在drivers/usb/mon下面。2005年的阳春三月,Greg大侠春心思动,于是就孕育出了这个usb Monitor

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值