算是进入了HCD的片儿区,这里的老大不是帮派头目也不是巡逻片儿警,而是几个结构。在HCD这个片儿区,这个山头儿,王中之王就是include/linux/usb/hcd.h里定义的struct usb_hcd。

struct usb_hcd {/** housekeeping*/struct usb_bus     self;       /* hcd is-a bus */struct kref       kref;       /* reference counter */const char       *product_desc;  /* product/vendor string */int          speed;      /* Speed for this roothub.* May be different from* hcd->driver->flags & HCD_MASK*/char            irq_descr[24];  /* driver + bus # */struct timer_list  rh_timer;   /* drives root-hub polling */struct urb     *status_urb;    /* the current status urb */
#ifdef CONFIG_PM_RUNTIMEstruct work_struct  wakeup_work;    /* for remote wakeup */
#endif/** hardware info/state*/const struct hc_driver   *driver;    /* hw-specific hooks *//** OTG and some Host controllers need software interaction with phys;* other external phys should be software-transparent*/struct usb_phy       *usb_phy;struct phy     *phy;/* Flags that need to be manipulated atomically because they can* change while the host controller is running.  Always use* set_bit() or clear_bit() to change their values.*/unsigned long        flags;
#define HCD_FLAG_HW_ACCESSIBLE      0   /* at full power */
#define HCD_FLAG_POLL_RH        2   /* poll for rh status? */
#define HCD_FLAG_POLL_PENDING       3   /* status has changed? */
#define HCD_FLAG_WAKEUP_PENDING     4   /* root hub is resuming? */
#define HCD_FLAG_RH_RUNNING     5   /* root hub is running? */
#define HCD_FLAG_DEAD           6   /* controller has died? *//* The flags can be tested using these macros; they are likely to* be slightly faster than test_bit().*/
#define HCD_HW_ACCESSIBLE(hcd)  ((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE))
#define HCD_POLL_RH(hcd)    ((hcd)->flags & (1U << HCD_FLAG_POLL_RH))
#define HCD_POLL_PENDING(hcd)   ((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING))
#define HCD_WAKEUP_PENDING(hcd) ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
#define HCD_RH_RUNNING(hcd) ((hcd)->flags & (1U << HCD_FLAG_RH_RUNNING))
#define HCD_DEAD(hcd)       ((hcd)->flags & (1U << HCD_FLAG_DEAD))/* Flags that get set only during HCD registration or removal. */unsigned        rh_registered:1;/* is root hub registered? */unsigned       rh_pollable:1;  /* may we poll the root hub? */unsigned     msix_enabled:1; /* driver has MSI-X enabled? */unsigned     remove_phy:1;   /* auto-remove USB phy *//* The next flag is a stopgap, to be removed when all the HCDs* support the new root-hub polling mechanism. */unsigned     uses_new_polling:1;unsigned     wireless:1; /* Wireless USB HCD */unsigned      authorized_default:1;unsigned       has_tt:1;   /* Integrated TT in root hub */unsigned     amd_resume_bug:1; /* AMD remote wakeup quirk */unsigned     can_do_streams:1; /* HC supports streams */unsigned     tpl_support:1; /* OTG & EH TPL support */unsigned int       irq;        /* irq allocated */void __iomem     *regs;      /* device memory/io */resource_size_t       rsrc_start; /* memory/io resource start */resource_size_t       rsrc_len;   /* memory/io resource length */unsigned     power_budget;   /* in mA, 0 = no limit */struct giveback_urb_bh  high_prio_bh;struct giveback_urb_bh  low_prio_bh;/* bandwidth_mutex should be taken before adding or removing* any new bus bandwidth constraints:*   1. Before adding a configuration for a new device.*   2. Before removing the configuration to put the device into*      the addressed state.*   3. Before selecting a different configuration.*   4. Before selecting an alternate interface setting.** bandwidth_mutex should be dropped after a successful control message* to the device, or resetting the bandwidth after a failed attempt.*/struct mutex        *bandwidth_mutex;struct usb_hcd     *shared_hcd;struct usb_hcd      *primary_hcd;#define HCD_BUFFER_POOLS   4struct dma_pool        *pool[HCD_BUFFER_POOLS];int         state;
#   define  __ACTIVE        0x01
#   define  __SUSPEND       0x04
#   define  __TRANSIENT     0x80#   define  HC_STATE_HALT       0
#   define  HC_STATE_RUNNING    (__ACTIVE)
#   define  HC_STATE_QUIESCING  (__SUSPEND|__TRANSIENT|__ACTIVE)
#   define  HC_STATE_RESUMING   (__SUSPEND|__TRANSIENT)
#   define  HC_STATE_SUSPENDED  (__SUSPEND)#define  HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)/* more shared queuing code would be good; it should support* smarter scheduling, handle transaction translators, etc;* input size of periodic table to an interrupt scheduler.* (ohci 32, uhci 1024, ehci 256/512/1024).*//* The HC driver's private data is stored at the end of* this structure.*/unsigned long hcd_priv[0]__attribute__ ((aligned(sizeof(s64))));
};

经过了血与火,熊市与牛市的洗礼,我们都应该对这种变态结构习以为常了,男人么,图不了房子图不了车子图不了美女,能图的还有啥?不就是一颗平常心么。

6行,又一个结构体,struct usb_bus,还名曰self,struct usb_hcd里还有self,看来这家伙是双子座的,以为能再分裂出一个自己。
为什么这里会用这么一个戏剧性的词汇self?俺在前面的某处提到过那么一下,一个主机控制器就会连出一条usb总线,主机控制器驱动用struct usb_hcd结构表示,一条总线用struct usb_bus结构表示,它们是相生相依的关系。struct usb_bus在include/linux/usb.h里定义

struct usb_bus {struct device *controller;   /* host/master side hardware */int busnum;          /* Bus number (in order of reg) */const char *bus_name;     /* stable id (PCI slot_name etc) */u8 uses_dma;         /* Does the host controller use DMA? */u8 uses_pio_for_control; /** Does the host controller use PIO* for control transfers?*/u8 otg_port;          /* 0, or number of OTG/HNP port */unsigned is_b_host:1;     /* true during some HNP roleswitches */unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */unsigned no_stop_on_short:1;    /** Quirk: some controllers don't stop* the ep queue on a short transfer* with the URB_SHORT_NOT_OK flag set.*/unsigned no_sg_constraint:1;   /* no sg constraint */unsigned sg_tablesize;        /* 0 or largest number of sg list entries */int devnum_next;        /* Next open device number in* round-robin allocation */struct usb_devmap devmap;   /* device address allocation map */struct usb_device *root_hub; /* Root hub */struct usb_bus *hs_companion; /* Companion EHCI bus, if any */struct list_head bus_list;  /* list of busses */struct mutex usb_address0_mutex; /* unaddressed device mutex */int bandwidth_allocated; /* on this bus: how much of the time* reserved for periodic (intr/iso)* requests is used, on average?* Units: microseconds/frame.* Limits: Full/low speed reserve 90%,* while high speed reserves 80%.*/int bandwidth_int_reqs;     /* number of Interrupt requests */int bandwidth_isoc_reqs;  /* number of Isoc. requests */unsigned resuming_ports;  /* bit array: resuming root-hub ports */#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)struct mon_bus *mon_bus;   /* non-null when associated */int monitored;            /* non-zero when monitored */
#endif
};

2行,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越来越走向幕后。就好像我们一开始是天地混沌,然后是女娲造人,有了社会有了阶级,再然后才有了新中国一样。
3行,busnum,总线编号,你的机子里总可以有多个主机控制器吧,自然也就可以有多条usb总线了,既然可以有多条,就要编个号方便确认了。有关总线编号,可以看看定义在drivesr/usb/core/hcd.c里的这几行

/* used when allocating bus numbers */
#define USB_MAXBUS      64
static DECLARE_BITMAP(busmap, USB_MAXBUS);

include/linux/types.h

#define DECLARE_BITMAP(name,bits) \unsigned long name[BITS_TO_LONGS(bits)]

讲struct usb_device的devnum时候,说到过一个devicemap,这里又有个busmap,当时分析说devicemap一共有128位,同理可知,这里的busmap一共有64位,也就是说最多可以有64条usb总线,如果你还觉得不够,言一声,我可以躲你远远的。
4行,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。
5行,uses_dma,表明这个主机控制器支持不支持DMA。主机控制器的一项重要工作就是在内存和USB总线之间传输数据,这个过程可以使用DMA或者不使用DMA,不使用DMA的方式即所谓的PIO方式。DMA代表着Direct Memory Access,即直接内存访问,不需要CPU去干预。具体的去看看PCI DMA的东东吧,因为一般来说主机控制器都是PCI设备,uses_dma都在它们自己的probe函数里设置了。
10~12行,有关otg的,飘过。
21行,devnum_next,24行,devmap,早就说过devmap这张表了,devnum_next中记录的就是这张表里下一个为0的位,里面为1的位都是已经被这条总线上的usb设备占据了的,名花有主的。
25行,root_hub,就好像端点0在所有设备的端点里面那么的鹤立鸡群一样,root hub在所有的hub里面也是那么的特殊,还记得usb的那颗树么,它就是那颗树的根,和usb主机控制器绑定在一起,其它的hub和设备都必须从它这儿延伸出去。正是因为这种特殊的关系,写代码的哥们儿也素有成人之心,就直接将它放在了struct usb_bus结构里,让他们永不分离。usb主机控制器,usb总线,root hub,1比1比1。
27行,bus_list,在drivers/usb/core/hcd.c中定义有一个全局队列usb_bus_list

/* host controllers we manage */
LIST_HEAD (usb_bus_list);
EXPORT_SYMBOL_GPL (usb_bus_list);

它就是所有usb总线的组织。每次一条总线新添加进来,都要向这个组织靠拢,都要使用bus_list字段链接在这个队列上。
31行,bandwidth_allocated,表明总线为中断传输和等时传输预留了多少带宽,协议里说了,对于高速来说,最多可以有80%,对于低速和全速要多点儿,可以达到90%。它的单位是微秒,表示一帧或微帧内有多少微秒可以留给中断/等时传输用。
38行,bandwidth_int_reqs,39行,bandwidth_isoc_reqs,分别表示当前中断传输和等时传输的数量。
43行,CONFIG_USB_MON是干吗用的?这要看看drivers/usb/mon目录下的Kconfig

#
# USB Monitor configuration
#config USB_MONtristate "USB Monitor"helpIf you select this option, a component which captures the USB trafficbetween peripheral-specific drivers and HC drivers will be built.For more information, see <file:Documentation/usb/usbmon.txt>.If unsure, say Y, if allowed, otherwise M.

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

Linux那些事儿 之 戏说USB(24)设备的生命线(七)相关推荐

  1. Linux那些事儿 之 戏说USB(27)设备的生命线(十)

    跟着设备的生命线走到现在,我算是明白了,什么东西的发展都是越往后越高级越复杂.再给张小表,看看现在和上次那张表出现的时候有什么变化. state        USB_STATE_ADDRESS sp ...

  2. Linux那些事儿 之 戏说USB(19)设备的生命线(二)

    现在设备的struct usb_device结构体已经准备好了,只是还不怎么饱满,hub接下来就会给它做做整容手术,往里边儿塞点什么,充实一些内容,比如:将设备的状态设置为Powered,也就是加电状 ...

  3. Linux那些事儿 之 戏说USB(23)设备的生命线(二)

    转载地址:http://blog.csdn.net/fudan_abc/article/details/1814938 现在设备的struct usb_device结构体已经准备好了,只是还不怎么饱满 ...

  4. 【转】Linux那些事儿 之 戏说USB(23)设备的生命线(二)

    现在设备的struct usb_device结构体已经准备好了,只是还不怎么饱满,hub接下来就会给它做做整容手术,往里边儿塞点什么,充实一些内容,比如:将设备的状态设置为Powered,也就是加电状 ...

  5. Linux那些事儿 之 戏说USB(22)设备的生命线(一)

    转载地址:http://blog.csdn.net/fudan_abc/article/details/1814891 李安告诉我们,每个人的心中都有一座断背山,每个人的手里都有一条生命线. Goog ...

  6. Linux那些事儿 之 戏说USB(25)设备的生命线(八)

    回到struct usb_hcd,继续努力的往下看. 7行,又见kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看drivers/usb/core/hcd ...

  7. Linux那些事儿 之 戏说USB(28)设备的生命线(十一)

    现在已经使用GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符.接口描述符还是端点描述符都彼此的挤在一起,所以得想 ...

  8. Linux那些事儿 之 戏说USB(22)设备的生命线(五)

    下面接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义. struct ur ...

  9. Linux那些事儿 之 戏说USB(18)设备的生命线(一)

    首先当然是你将usb设备连接在hub的某个端口上,hub检测到有设备连接了进来,它会为设备分配一个struct usb_device结构的对象并初始化,并调用设备模型提供的接口将设备添加到usb总线的 ...

最新文章

  1. HBase存储剖析与数据迁移
  2. 利用python实现简易版的贪吃蛇游戏(面向python小白)
  3. 调试内存_C/C++程序调试和内存检测
  4. Hadoop应用实战100讲(三)-Hadoop分布式文件系统
  5. netbean下搭建mariadb数据库
  6. gd动态曲线 php_PHP 高级编程之多线程
  7. kbhit linux windows通用,linux模拟windows的kbhit
  8. powershell编程_对Power BI PowerShell Commandlet的编程访问
  9. 【阙值分割】基于matlab粒子群算法自适应多阈值图像分割【含Matlab源码 1459期】
  10. aix java 版本_AIX系统安装JDK
  11. html+div+动画效果,CSS3效果:animate实现点点点loading动画效果(一)
  12. 手工制作使用WinXShell的PE(不是直接生成) #1
  13. 怎么把png格式图片转换成jpg格式?
  14. 电子签约存证及印章管理整体化解决方案
  15. win7安装python3.7_win7无法安装python3
  16. Python 爬取妹子图02
  17. poi读取doc文档
  18. can收发器 rx_CANOpen系列教程03_CAN收发器功能、原理及作用
  19. 使用Tensorflow训练LSTM+Attention中文标题党分类
  20. Xmind8无法启动的问题

热门文章

  1. python 字符串拼接
  2. RecyclerView 点击Item 改变文字颜色以及所在的背景色
  3. 牛客~~打篮球~~~模拟水题
  4. C++ 笔记(06)— 变量作用域(局部变量、全局变量、静态局部变量)
  5. Windows Phone开发(16):样式和控件模板
  6. poj1226 Substrings
  7. 递归删除目录下的所有文件
  8. TMS320F28335项目开发记录2_CCS与JTAG仿真器连接问题汇总
  9. (原创)c#学习笔记10--定义类成员03--接口的实现01--显示实现接口成员
  10. WPF初探--RichTextBox