Linux内核的基本组成模型是,linux内核之设备驱动模型

linux内核之设备驱动模型

前言

一、设备模型的基石---kobject子系统

二、设备模型的总框架---总线、设备和驱动模型

三、有关驱动的虚拟内存文件系统---Sysfs系统

前言

七七八八,磨磨蹭蹭,终于大体上是把LDD3弄完了(大的方面),这里还剩一部分设备驱动部分,喝杯枸杞茶,拍拍我这略显懒散的脸,把这部分记录完。

这篇博客打算写一下几个部分

设备模型的基石—kobject子系统

设备模型的总框架—总线、设备和驱动模型

有关驱动的虚拟内存文件系统—Sysfs系统

ok,let’s begin…

一、设备模型的基石—kobject子系统

在面向对象的大型框架或者软件系统中,为了代码的复用性,大多数系统都会创造一个Object对象,以这个对象作为其他对象的祖先。作为开天辟地的老大,它一般对软件系统中所需要的对象做出了最高的抽象。 对于它的子孙们,大都需要继承Object,从而淋漓极致的发挥面向对象中继承和多态的功效。

用C语言开发的linux在设备驱动这个模块中也或多或少的用到了这中做法。

kobject是组成设备模型的基本结构,而内核中很多平台、总线或者框架的实现大都以kobject为基础(比如说后面说到的总线、设备和驱动模型)。由于linux使用C语言完成的,面向对象的那种纯纯的继承关系是体现不出来的,所以kobject的子孙们“继承”这个祖先的方式是包含一个object的结构体。如设备驱动中的字符设备cdev,其成员如下。

struct cdev {

struct kobject kobj; //内嵌的内核对象.

struct module *owner; //该字符设备所在的内核模块的对象指针.

const struct file_operations *ops; //该结构描述了字符设备所能实现的方法,是极为关键的一个结构体.

struct list_head list; //用来将已经向内核注册的所有字符设备形成链表.

dev_t dev; //字符设备的设备号,由主设备号和次设备号构成.

unsigned int count; //隶属于同一主设备号的次设备号的个数.

这里再简单多说一点,以上所说的这种"继承"方式,有的C++教材中叫做组合的方式。同时,利用这种内嵌的组合方式,linux在实现多态的时候用到了一个叫做 container of()的方式(用结构体成员找结构体),感兴趣的可以问问度娘。

咱再回来接着说kobject,在2.6的内核中,它的基本结构为:

struct kobject {

const char*name;

struct list_headentry;

struct kobject*parent;

struct kset*kset;

struct kobj_type*ktype;

struct sysfs_dirent*sd;

struct krefkref;

unsigned int state_initialized:1;

unsigned int state_in_sysfs:1;

unsigned int state_add_uevent_sent:1;

unsigned int state_remove_uevent_sent:1;

unsigned int uevent_suppress:1;

};

LDD3中,Kobject的作用有以下几点:

(1)、对象的引用计数。结构体中kref主要实现的就是这个作用,控制对象的生命周期,即当内核中没有代码持有对象的引用时,对象就可以删除了。

(2)、数据结构的相互关联。object把大量的数据结构联系成了层次化的体系结构。(有点类似于对象的子类父类家族树)

(3)、sysfs表述。在sysfs中显示的每一个对象,都对应这一个kobject,它被用来于内核交互。

(4)、热插拔事件处理。当系统中的硬件被热插拔时,在kobject子系统的控制下,将产生事件通知用户空间。(本文不涉及这点)

由kobject所引申出来的几个结构体还有kset、kobj_type等等,它们的作用和object差不多(或者说它们是和kobject一起配合组成以上说明的作用)。网上有很多博客说的很好,目前我也想不出什么好的创新点,在此就不赘述了。给推荐一个博客。

linux设备驱动模型

二、设备模型的总框架—总线、设备和驱动模型

在linux驱动中应该有很多框架,但最主要的应该要数这个总线、设备和驱动模型框架了。

来,先来弄张图。

82e3732f9961e405cc6e43bd7bbde5e5.png

为了应对日益复杂的硬件设备,原先的linux内核有点吃不消,在全世界热爱linux的热血青年的共同努力下,应该在2.6版本之后就出现了上图所示的总线、设备驱动模型。

在这个模型中,有三个概念:

(1)、总线(Bus)。这里所说的总线并不是真正CPU内部的硬件总线,而是一个虚拟的概念。(之所以叫做总线,我想是因为设备、和驱动能“挂”在上面吧),从某种程度上来说,它是这个模型的控制者、总览大局的。模型中的设备和驱动需要挂在它下面才能使用。在linux内核中用bus_type来描述一个总线。

struct bus_type {

const char*name;

struct bus_attribute*bus_attrs;

struct device_attribute*dev_attrs;

struct driver_attribute*drv_attrs;

int (*match)(struct device *dev, struct device_driver *drv);

int (*uevent)(struct device *dev, struct kobj_uevent_env *env);

int (*probe)(struct device *dev);

int (*remove)(struct device *dev);

void (*shutdown)(struct device *dev);

int (*suspend)(struct device *dev, pm_message_t state);

int (*resume)(struct device *dev);

const struct dev_pm_ops *pm;

struct bus_type_private *p;

};

(2)设备(device)。在linux内核中用device结构体来描述。如下所示。

struct device {

struct device*parent;

struct device_private*p;

struct kobject kobj;

const char*init_name; /* initial name of the device */

struct device_type*type;

struct mutexmutex;/* mutex to synchronize calls to

* its driver.

*/

struct bus_type*bus;/* type of bus device is on */

struct device_driver *driver;/* which driver has allocated this

device */

void*platform_data;/* Platform specific data, device

core doesn't touch it */

struct dev_pm_infopower;

#ifdef CONFIG_NUMA

intnuma_node;/* NUMA node this device is close to */

#endif

u64*dma_mask;/* dma mask (if dma'able device) */

u64coherent_dma_mask;/* Like dma_mask, but for

alloc_coherent mappings as

not all hardware supports

64 bit addresses for consistent

allocations such descriptors. */

struct device_dma_parameters *dma_parms;

struct list_headdma_pools;/* dma pools (if dma'ble) */

struct dma_coherent_mem*dma_mem; /* internal for coherent mem

override */

/* arch specific additions */

struct dev_archdataarchdata;

#ifdef CONFIG_OF

struct device_node*of_node;

#endif

dev_tdevt;/* dev_t, creates the sysfs "dev" */

spinlock_tdevres_lock;

struct list_headdevres_head;

struct klist_nodeknode_class;

struct class*class;

const struct attribute_group **groups;/* optional groups */

void(*release)(struct device *dev);

};

(3)驱动(driver)。在linux内核中用device_driver来描述。如下所示。

struct device_driver {

const char*name;

struct bus_type*bus;

struct module*owner;

const char*mod_name;/* used for built-in modules */

bool suppress_bind_attrs;/* disables bind/unbind via sysfs */

#if defined(CONFIG_OF)

const struct of_device_id*of_match_table;

#endif

int (*probe) (struct device *dev);

int (*remove) (struct device *dev);

void (*shutdown) (struct device *dev);

int (*suspend) (struct device *dev, pm_message_t state);

int (*resume) (struct device *dev);

const struct attribute_group **groups;

const struct dev_pm_ops *pm;

struct driver_private *p;

};

linux内核把设备驱动分开了,一个管设备,一个管驱动。它们在使用的时候都需要“挂”到对应的bus总线上(bus_type里有对应的kset,device和device_driver中也有指明哪条bus的bus_type类型), 它们就像一对小情侣,而bus就相当于红娘。这对小情侣的配对都需要红娘来牵线,当一个device来到红娘bus注册的时候,bus红娘就从已注册的device_driver中遍历,找到能和device匹配的(用bus_type里的match函数)。当device_driver来注册时也是一样。 需要说明一点的是,一般来说,一个设备只能匹配一个driver,而一个driver能够匹配多个device。(这么说的话,这里的小情侣应该是古时候的小情侣,嘿嘿)

这里我基本只说一些大的方面,具体的细节方面,有很多博客、资料说的已经很好了。这里也给一些资料。

1、从需求的角度去理解Linux系列:总线、设备和驱动

2、Linux设备驱动中的软件架构思想

3、linux设备驱动模型

4、linux驱动中probe函数是怎么调用的

这里在多说一点,这个总线(Bus)、设备(device)、驱动(device_driver)几个结构体也算是比较底层的结构体了,linux内核中比较成熟的总线都在这底层的结构体上进行了相应的封装(成员变量和对应的操作方法上)。如bus总线、pci总线和platform总线。如果大家想深入了解这个模型的话,可以自己模拟写一个属于自己的总线、创建自己的设备和驱动。这里也给大家几个资料。

1、从零开始写个platform平台总线

2、字符驱动移植–bus(平台总线), device, driver

3、总线设备驱动模型

三、有关驱动的虚拟内存文件系统—Sysfs系统

在linux系统中除了一些真正存储在介质上的文件系统(如ext2、ext3等)外,还有一种叫做虚拟内存的文件系统,这种文件系统只存在于内存中,断电了,文件系统也就消失了。这种文件系统的作用大多是导出内核的信息,使内核空间和用户空间进行交互。如proc、tmpfs、sysfs等。

对于sysfs文件系统,它最主要的作用就是管理统一的设备、驱动。所以这个文件系统里大都是和驱动相关的。

嗯。。对,这部分还有一些class等,udev等知识点,我还没有搞的太透彻, 先是这些吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值