Linux内核(7) - 设备模型(上)

对于驱动开发来说,设备模型的理解是根本,毫不夸张得说,理解了设备模型,再去看那些五花八门的驱动程序,你会发现自己站在了另一个高度,从而有了一种俯视的感觉,就像凤姐俯视知音和故事会,韩峰同志俯视女下属。

顾名而思义就知道设备模型是关于设备的模型,既不是任小强们的房模,也不是张导的炮模。对咱们写驱动的和不写驱动的人来说,设备的概念就是总线和与其相连的各种设备了。电脑城的IT工作者都会知道设备是通过总线连到计算机上的,而且还需要对应的驱动才能用,可是总线是如何发现设备的,设备又是如何和驱动对应起来的,它们经过怎样的艰辛才找到命里注定的那个他,它们的关系如何,白头偕老型的还是朝三暮四型的,这些问题就不是他们关心的了,而是咱们需要关心的。在房市股市千锤百炼的咱们还能够惊喜的发现,这些疑问的中心思想中心词汇就是总线、设备和驱动,没错,它们就是咱们这里要聊的Linux设备模型的名角。

总线、设备、驱动,也就是bus、device、driver,既然是名角,在内核里都会有它们自己专属的结构,在include/linux/device.h里定义。

52 struct bus_type {
53   const char              * name;
54     struct module           * owner;
55
56      struct kset             subsys;
57      struct kset             drivers;
58       struct kset             devices;
59      struct klist            klist_devices;
60      struct klist            klist_drivers;
61
62       struct blocking_notifier_head bus_notifier;
63
64      struct bus_attribute    * bus_attrs;
65       struct device_attribute * dev_attrs;
66      struct driver_attribute * drv_attrs;
67      struct bus_attribute drivers_autoprobe_attr;
68      struct bus_attribute drivers_probe_attr;
69
70      int (*match)(struct device * dev, struct device_driver * drv);
71       int (*uevent)(struct device *dev, char **envp,
72      int num_envp, char *buffer, int buffer_size);
73      int             (*probe)(struct device * dev);
74      int             (*remove)(struct device * dev);
75       void            (*shutdown)(struct device * dev);
76
77      int (*suspend)(struct device * dev, pm_message_t state);
78      int (*suspend_late)(struct device * dev, pm_message_t state);
79      int (*resume_early)(struct device * dev);
80       int (*resume)(struct device * dev);
81
82      unsigned int drivers_autoprobe:1;
83 };

124 struct device_driver {
125     const char              * name;
126      struct bus_type         * bus;
127
128      struct kobject          kobj;
129      struct klist            klist_devices;
130      struct klist_node       knode_bus;
131
132      struct module           * owner;
133      const char              * mod_name;  /* used for built-in modules */
134      struct module_kobject   * mkobj;
135
136     int     (*probe)        (struct device * dev);
137     int     (*remove)       (struct device * dev);
138      void    (*shutdown)     (struct device * dev);
139     int     (*suspend)      (struct device * dev, pm_message_t state);
140      int     (*resume)       (struct device * dev);
141 };

407 struct device {
408   struct klist  klist_children;
409   struct klist_node knode_parent;  /* node in sibling list */
410   struct klist_node knode_driver;
411   struct klist_node knode_bus;
412   struct device  *parent;
413
414   struct kobject kobj;
415   char bus_id[BUS_ID_SIZE]; /* position on parent bus */
416   struct device_type *type;
417   unsigned  is_registered:1;
418   unsigned  uevent_suppress:1;
419
420      struct semaphore sem; /* semaphore to synchronize calls to
421         * its driver.
422         */
423
424   struct bus_type * bus;  /* type of bus device is on */
425   struct device_driver *driver; /* which driver has allocated this
426          device */
427   void  *driver_data; /* data private to the driver */
428   void  *platform_data; /* Platform specific data, device
429          core doesn‘t touch it */
430   struct dev_pm_info power;
431
432 #ifdef CONFIG_NUMA
433   int  numa_node; /* NUMA node this device is close to */
434 #endif
435   u64  *dma_mask; /* dma mask (if dma‘able device) */
436   u64  coherent_dma_mask;/* Like dma_mask, but for
437            alloc_coherent mappings as
438            not all hardware supports
439            64 bit addresses for consistent
440            allocations such descriptors. */
441
442   struct list_head dma_pools; /* dma pools (if dma‘ble) */
443
444   struct dma_coherent_mem *dma_mem; /* internal for coherent mem
445            override */
446   /* arch specific additions */
447   struct dev_archdata archdata;
448
449   spinlock_t  devres_lock;
450   struct list_head devres_head;
451
452   /* class_device migration path */
453   struct list_head node;
454   struct class  *class;
455   dev_t   devt;  /* dev_t, creates the sysfs "dev" */
456   struct attribute_group **groups; /* optional groups */
457
458   void (*release)(struct device * dev);
459 };

有没有发现它们的共性是什么?对,不是很傻很天真,而是很长很复杂。不过不妨把它们看成艺术品,既然是艺术,当然不会让你那么容易的就看懂了,不然怎么称大师称名家。这么想想咱们就会比较的宽慰了,阿Q是鲁迅对咱们80后最大的贡献。

我知道进入了21世纪,最缺的就是耐性,房价股价都让咱们没有耐性,内核的代码也让人没有耐性。不过做为最没有耐性的一代人,还是要平心静气的扫一下上面的结构,我们会发现,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将各个对象连接起来组成了一个分层的结构体系,就好像马列主义将我们13亿人也连接成了一个分层的社会体系一样。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链表中寻找它的那些设备。如果找到了合适的,那么OK,和之前那种情况一下,调用device_bind_driver绑定好。如果找不到,没有关系,等待吧,等到昙花再开,等到风景看透,心中相信,这世界上总有一个人是你所等的,只是还没有遇到而已。

原文地址:https://www.cnblogs.com/alantu2018/p/8448804.html

时间: 2024-10-11 22:01:30

Linux内核(7) - 设备模型(上)的相关文章

Linux内核(8) - 设备模型(下)

设备模型拍得再玄幻,它也只是个模型,必须得落实在具体的子系统,否则就只能抱着个最佳技术奖空遗恨.既然前面已经以USB子系统的实现分析示例了分析内核源码应该如何入手,那么这里就仍然以USB子系统为例,看看设备模型是如何软着陆的. 内核中USB子系统的结构 我们已经知道了USB子系统的代码都位于drivers/usb目录下面,也认识了一个很重要的目录--core子目录.现在,我们再来看一个很重要的模块--usbcore.你可以使用"lsmod"命令看一下,在显示的结果里能够找到有一个模块叫

Linux内核系列设备模型(一) Kobject与Kset

1.Kobject Kobject是设备驱动模型的核心结构,它使所有设备在底层都有统一的接口.在内核注册的kobject对象都会对应sysfs文件系统中的一个目录(目录名称有Kobject结构中k_name指定) struct kobject {     const char        * k_name; // 指向设备名称的指针     char            name[KOBJ_NAME_LEN]; // 设备名称     struct kref        kref; //引

基于tiny4412的Linux内核移植 -- 设备树的展开

作者信息 作者: 彭东林 邮箱:[email protected] QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本:Linux-4.4.0 (支持device tree) u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动) busybox版本:busybox 1.25 交叉编译工具链: arm-none-linux-gnueabi-gcc (gcc version 4

浅谈Linux驱动到设备模型再到设备树(总结)

1.最初Linux驱动架构 Linux驱动会在初始化函数中向内核注册file_operations结构体,结构体里面就包含一些基本的open,close函数.Linux驱动中也会去实现这些open函数.并且相对应的硬件信息也在这个驱动中.以LED为例,驱动程序中会将LED的引脚地址映射成虚拟地址,然后在open函数里面进行写操作. 当APP调用open函数的时候,就会通过一系列转换,最后调用到驱动中的open函数.(这边就不具体描述APP怎么调用到驱动中的open函数) 原文地址:https:/

linux内核交互,设备驱动控制管理接口

1,ioctl preface--starting point ,format,mount volume,in addition to the above file system -- allows users to store and retrive data; organized in a hierarchical directory tree,behaviorial semantics as spelled ou; ASM   shared disk cluster file system

Linux设备模型——设备驱动模型和sysfs文件系统解读

本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的.在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解.其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解. 内核版本:2.6.30 1. What is sysfs? 个人理解:sysfs向用户空间展示了驱动设备的层次结构.我们都知道设备和对应的驱动都是由内

Linux 设备模型之 (kobject、kset 和 Subsystem)(二)

问题描写叙述:前文我们知道了/sys是包括内核和驱动的实施信息的,用户能够通过 /sys 这个接口.用户通过这个接口能够一览内核设备的全貌.本文将从Linux内核的角度来看一看这个设备模型是怎样构建的. 1.kobject 结构 在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject相应sysfs里的一个文件夹. 从面向对象的角度来说.kobject能够看作是全部设备对象的基类,由于C语言并没有面向对象的语法,所以通常是把kobject内嵌到其它结构体里来实现类似的

《Linux Device Drivers》第十四章 Linux 设备模型

简介 2.6内核的设备模型提供一个对系统结构的一般性抽象描述,用以支持多种不同的任务 电源管理和系统关机 与用户空间通信 热插拔设备 设备类型 对象生命周期 kobject.kset和子系统 kobject是组成设备模型的基本结构 对象的引用计数 sysfs表述 数据结构关联 热插拔事件处理 kobject基础知识 <linux/kobject.h> 嵌入的kobject 内核代码很少去创建一个单独的kobject对象,kobject用于控制对大型域相关对象的访问 kobject的初始化 首先

20150517 Linux文件系统与设备文件系统

20150517 Linux文件系统与设备文件系统 2015-05-17 Lover雪儿 注:本文参考书籍:华清远见-<Linux 设备驱动开发详解>第五章,大概内容如下,具体内容还请观看原书. 一.devfs(设备文件系统) devfs(设备文件系统)是由linux2.4内核引入的,具有如下优点: ①可以通过程序在设备初始化时在/dev目录下创建设备文件,卸载时把它删除. ②设备驱动程序可以指定设备名.所有者和权限位,用户空间中人可以修改. ③不需要为设备驱动程序分配主设备号以及处理次设备号