诙谐幽默的 bus/driver/device关系

news/2024/7/8 3:42:50 标签: struct, semaphore, module, migration, list, linux

这里让我们聚焦Linux的设备模型! 顾名思义,设备模型是关于设备的模型,对咱们写驱动的和不写驱动的人来说,设备的概念就是总线和与其相连的各种设备了。电脑城的IT工作者都会知道设备是通过总线连到计算机上的,而且还需要对应的驱动才能用,可是总线是如何发现设备的?设备又是如何和驱动对应起来的?它们经过怎样的艰辛才找到命里注定的那个它?它们的关系如何?白头偕老型的还是朝三暮四型的?这些问题就不是他们关心的了,而是咱们需要关心的。我们惊喜地发现,这些疑问的中心思想中心词汇就是总线、设备和驱动,没错,它们都是咱们这里要聊的Linux设备模型的“名角”。 总线、设备、驱动,也就是bus、device、driver,既然是“名角”,在内核中都会有它们自己专属的结构,在include/linux/device.h中定义: 

  1. struct bus_type { 
  2.         const char              * name; 
  3.         struct module           * owner; 
  4.    
  5.         struct kset             subsys; 
  6.         struct kset             drivers; 
  7.         struct kset             devices; 
  8.         struct klist            klist_devices; 
  9.         struct klist            klist_drivers; 
  10.    
  11.         struct blocking_notifier_head bus_notifier; 
  12.    
  13.         struct bus_attribute    * bus_attrs; 
  14.         struct device_attribute * dev_attrs; 
  15.         struct driver_attribute * drv_attrs; 
  16. struct bus_attribute drivers_autoprobe_attr;
  17.         struct bus_attribute drivers_probe_attr; 
  18.    
  19.         int (*match)(struct device * dev, struct device_driver * drv); 
  20.         int (*uevent)(struct device *dev, char **envp, 
  21.         int num_envp, char *buffer, int buffer_size); 
  22.         int             (*probe)(struct device * dev); 
  23.         int             (*remove)(struct device * dev); 
  24.         void            (*shutdown)(struct device * dev); 
  25.    
  26.         int (*suspend)(struct device * dev, pm_message_t state); 
  27.         int (*suspend_late)(struct device * dev, pm_message_t state); 
  28.         int (*resume_early)(struct device * dev); 
  29.         int (*resume)(struct device * dev); 
  30.    
  31.         unsigned int drivers_autoprobe:1
  32.   }; 
  33.   struct device_driver { 
  34.         const char              * name; 
  35.         struct bus_type         * bus; 
  36.   
  37.         struct kobject          kobj; 
  38.         struct klist            klist_devices; 
  39.         struct klist_node       knode_bus; 
  40.    
  41.         struct module           * owner; 
  42.         const char              * mod_name;  /* used for built-in modules */
  43.         struct module_kobject   * mkobj; 
  44.    
  45.         int     (*probe)        (struct device * dev); 
  46.         int     (*remove)       (struct device * dev); 
  47.         void    (*shutdown)     (struct device * dev); 
  48.         int     (*suspend)      (struct device * dev, pm_message_t state); 
  49.         int     (*resume)       (struct device * dev); 
  50.   }; 
  51.   struct device { 
  52.         struct klist            klist_children; 
  53.         struct klist_node       knode_parent;    /* node in sibling list */
  54.         struct klist_node       knode_driver; 
  55.         struct klist_node       knode_bus; 
  56.         struct device           *parent; 
  57.   
  58.         struct kobject kobj; 
  59.         char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
  60.         struct device_type      *type; 
  61.         unsigned                is_registered:1
  62.         unsigned                uevent_suppress:1
  63.         struct device_attribute uevent_attr; 
  64.         struct device_attribute *devt_attr; 
  65.    
  66.         struct semaphore        sem; /* semaphore to synchronize calls to
  67.                                          * its driver.
  68.                                          */
  69.    
  70.         struct bus_type * bus;          /* type of bus device is on */
  71.         struct device_driver *driver;   /* which driver has allocated this
  72.                                              device */
  73.         void            *driver_data;   /* data private to the driver */
  74.         void            *platform_data; /* Platform specific data, device
  75.                                              core doesn't touch it */
  76.        struct dev_pm_info      power; 
  77.    
  78.   #ifdef CONFIG_NUMA 
  79.         int             numa_node;   /* NUMA node this device is close to */
  80.   #endif 
  81.         u64             *dma_mask;      /* dma mask (if dma'able device) */
  82.         u64             coherent_dma_mask;/* Like dma_mask, but for
  83.                                                alloc_coherent mappings as
  84.                                               not all hardware supports
  85.                                             64 bit addresses for consistent
  86.                                             allocations such descriptors. */
  87.   
  88.         struct list_head        dma_pools;     /* dma pools (if dma'ble) */
  89.   
  90.         struct dma_coherent_mem *dma_mem; /* internal for coherent mem
  91.                                               override */
  92.         /* arch specific additions */
  93.         struct dev_archdata     archdata; 
  94.    
  95.         spinlock_t              devres_lock; 
  96.         struct list_head        devres_head; 
  97.   
  98.         /* class_device migration path */
  99.         struct list_head        node; 
  100.         struct class            *class
  101.         dev_t                   devt;    /* dev_t, creates the sysfs "dev" */
  102.         struct attribute_group  **groups;       /* optional groups */
  103.   
  104.         void    (*release)(struct device * dev); 
  105.   };

 

 有没有发现它们的共性是什么?对,它们很长,很复杂。不过不妨把它们看成艺术品,既然是艺术品,当然不会让你那么容易就看懂了。 让我们平心静气地看一下上面代码的结构,我们会发现,struct bus_type中有成员struct kset drivers 和struct kset devices,同时struct device中有两个成员struct bus_type * bus和struct device_driver *driver,struct device_driver中有两个成员struct bus_type * bus和struct klist klist_devices。先不说什么是klist、kset,光从成员的名字看,它们就是一个完美的三角关系。我们每个人心中是不是都有两个她?一个梦中的她,一个现实中的她。 我们可以知道struct device中的bus表示这个设备连到哪个总线上,driver表示这个设备的驱动是什么。struct device_driver中的bus表示这个驱动属于哪个总线,klist_devices表示这个驱动都支持哪些设备,因为这里device是复数,又是list,更因为一个驱动可以支持多个设备,而一个设备只能绑定一个驱动。当然,struct bus_type中的drivers和devices分别表示了这个总线拥有哪些设备和哪些驱动。 我们还需要看一看什么是klist和kset。还有上面device和driver结构中出现的kobject结构是什么?我可以肯定地告诉你,kobject和kset都是Linux设备模型中最基本的元素,总线、设备、驱动是西瓜,kobjcet、klist是种瓜的人,没有幕后种瓜人的汗水不会有清爽解渴的西瓜。我们不能光知道西瓜是多么的甜,还要知道种瓜人的辛苦。kobject和kset不会在意自己的得失,它们存在的意义在于把总线、设备和驱动这样的对象连接到设备模型上。种瓜的人也不会在意自己的汗水,在意的只是能不能种出甜蜜的西瓜。 一般来说应该这么理解,整个Linux的设备模型是一个OO的体系结构,总线、设备和驱动都是其中鲜活存在的对象,kobject是它们的基类,所实现的只是一些公共的接口,kset是同种类型kobject对象的集合,也可以说是对象的容器。只是因为C语言里不可能会有C++语言里类的class继承、组合等的概念,只有通过kobject嵌入到对象结构中来实现。这样,内核使用kobject将各个对象连接起来组成了一个分层的结构体系。kobject结构中包含了parent成员,指向了另一个kobject结构,也就是这个分层结构的上一层结点。而kset是通过链表来实现的,这样就可以明白,struct bus_type结构中的成员drivers和devices表示了一条总线拥有两条链表,一条是设备链表,一条是驱动链表。我们知道了总线对应的数据结构,就可以找到这条总线关联了多少设备,又有哪些驱动来支持这类设备。 那么klist呢?其实它就包含了一个链表和一个自旋锁,我们暂且把它看成链表也无妨。本来在2.6.11内核中,struct device_driver结构的devices成员就是一个链表类型。 那么总线、设备和驱动之间是如何和谐共处的呢?先说一说总线中的那两条链表是怎么形成的。内核要求每次出现一个设备就要向总线汇报,或者说注册,每次出现一个驱动,也要向总线汇报,或者说注册。比如系统初始化时,会扫描连接了哪些设备,并为每一个设备建立起一个struct device的变量,每一次有一个驱动程序,就要准备一个struct device_driver结构的变量。把这些变量统统加入相应的链表,device插入devices 链表,driver插入drivers链表。这样通过总线就能找到每一个设备,每一个驱动。然而,假如计算机里只有设备却没有对应的驱动,那么设备无法工作。反过来,倘若只有驱动却没有设备,驱动也起不了任何作用。在它们遇见彼此之前,双方都如同路埂里的野草,一个飘啊飘,一个摇啊摇,谁也不知道未来在哪里,只能在生命的风里飘摇。于是总线上的两张表里就慢慢地就挂上了许多孤单的灵魂。devices开始多了,drivers开始多了,它们像是来自两个不同的世界,devices们彼此取暖,drivers们一起狂欢,但它们有一点是相同的,都只是在等待属于自己的另一半。 现在,总线上的两条链表已经有了,剩下的那个呢?链表里的设备和驱动又是如何联系的?先有设备还是先有驱动?很久很久以前,先有的是设备,每一个要用的设备在计算机启动之前就已经插好了,插放在它应该在的位置上,然后计算机启动,操作系统开始初始化,总线开始扫描设备,每找到一个设备,就为其申请一个struct device结构,并且挂入总线中的devices链表中来。然后每一个驱动程序开始初始化,开始注册其struct device_driver结构,然后去总线的devices链表中去寻找(遍历),去寻找每一个还没有绑定驱动的设备,即struct device中的struct device_driver指针仍为空的设备,然后它会去观察这种设备的特征,看是否是它所支持的设备,如果是,那么调用一个叫做device_bind_driver的函数,然后它们就结为了“秦晋之好”。换句话说,把struct device中的struct device_driver driver指向这个驱动,而struct device_driver driver把struct device加入它的那张struct klist klist_devices链表中来。就这样,bus、device和driver,这三者之间或者说他们中的两两之间,就给联系上了。知道其中之一,就能找到另外两个。一荣俱荣,一损俱损。 但现在情况变了,出现了一种新的名词,叫热插拔。此时设备可以在计算机启动以后再插入或者拔出计算机了。因此,很难再说是先有设备还是先有驱动了,因为都有可能。设备可以在任何时刻出现,而驱动也可以在任何时刻被加载,所以,现在的情况就是,每当一个struct device诞生,它就会去bus的drivers链表中寻找自己的另一半。反之,每当一个一个struct device_driver诞生,它就去bus的devices链表中寻找它的那些设备。如果找到了合适的,那么和之前那种情况一样,调用device_bind_driver绑定好。如果找不到,没有关系,就等待吧。

来源: http://blog.csdn.net/zyhorse2010/article/details/6456408

http://www.niftyadmin.cn/n/1736497.html

相关文章

linux下UART的应用层编程及测试小程序

//串口相关的头文件 #include<stdio.h> /*标准输入输出定义*/ #include<stdlib.h> /*标准函数库定义*/ #include<unistd.h> /*Unix 标准函数定义*/ #include<sys/types.h> #include<sys/stat.h> #incl…

我理解的逻辑地址、线性地址、物理地址和虚拟地址(补充完整了)

本贴涉及的硬件平台是X86&#xff0c;如果是其它平台&#xff0c;嘻嘻&#xff0c;不保证能一一对号入座&#xff0c;但是举一反三&#xff0c;我想是完全可行的。 一、概念 物理地址(physical address) 用于内存芯片级的单元寻址&#xff0c;与处理器和CPU连接的地址总线相对…

dmesg命令

dmesg命令-->用来显示开机信息, kernel会将开机信息存储在ring buffer中。开机时来不及查看信息&#xff0c;可利用dmesg来查看。开机信息亦保存在/var/log/dmesg 【dmesg命令作用】: 有时候屏幕上的启动信息一闪而过&#xff0c;我们无法查看到具体信息&#xff0c;又或者…

c面试考点

一、 想说一说关于集中数据类型的sizeof问题&#xff0c;这题出现率40%sizeof就是求在内存总占多少字节的问题&#xff0c;最基本的char 1字节 short 2字节 int 4字节任何的指针都是4字节 sizeof&#xff08;数组名&#xff09;数组占的大小&#xff08;这里必须注意虽然数组…

C语言陷阱和缺陷

原著&#xff1a;Andrew Koenig - AT&T Bell Laboratories Murray Hill, New Jersey 07094 翻译&#xff1a;lover_P 修订&#xff1a;CQBOY 来自&#xff1a;http://blog.csdn.net/loverp/archive/2004/08/16/75725.aspx [修订说明] 改正了文中的大部分错别字和格式错误&…

关于mmap()函数的用户和驱动的一点总结

前言&#xff1a;内存映射&#xff0c;简而言之就是将用户空间的一段内存区域映射到内核空间&#xff0c;映射成功后&#xff0c;用户对这段内存区域的修改可以直接反映到内核空间&#xff0c;同样&#xff0c;内核空间对这段区域的修改也直接反映用户空间。那么对于内核空间&l…

I2C总线的EEPROM(24C08)Linux驱动

基于Linux 2.6.30内核 符合Linux驱动架构模型 针对24C08的Page读写做了优化。 完全模拟文件读写方式&#xff0c;支持lseek操作。 这个代码中&#xff0c;包含了设备的地址&#xff0c;在i2c_add_driver时会去探测该地址上是否有设备。 但通常&#xff0c;做板级开发时&…

【人工智能与深度学习】图卷积网络 I

【人工智能与深度学习】图卷积网络 I 传统卷积神经网络什么是维度诅咒?有关卷积神经网络的主要假设::图域数据域图域图域的启发性示例图的定义和特征传统卷积网络中的卷积卷积我们如何定义卷积?我们可以把模板匹配延伸到图吗?图卷积光谱图卷积网络步骤 1 : 图拉普拉斯步骤2…