灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2372回复:0

linux设备模型详解

楼主#
更多 发布于:2012-08-27 15:08


linux设备模型详解



Linux 2.6内核的一个重要特色是提供了统一的内核设备模型。随着技术的不断进步,系统的拓扑结构越来越复杂,对智能电源管理、热插拔以及plug and play的支持要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,2.6内核开发了全新的设备模型。

1. Sysfs文件系统

Sysfs文件系统是一个类似于proc文件系统的特殊文件系统,用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息。其顶层目录主要有:

Block目录:包含所有的块设备

Devices目录:包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构

Bus目录:包含系统中所有的总线类型

Drivers目录:包括内核中所有已注册的设备驱动程序

Class目录:系统中的设备类型(如网卡设备,声卡设备等)

2. 内核对象机制关键数据结构  

2.1 kobject内核对象

Kobject 是Linux 2.6引入的新的设备管理机制,在内核中由struct kobject表示。通过这个数据结构使所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux 2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。

Kobject结构定义为:

struct kobject {

char * k_name;    指向设备名称的指针

char name[KOBJ_NAME_LEN];   设备名称

struct kref kref;    对象计数

struct list_head entry;   挂接到所在kset中去的单元

struct kobject * parent; 指向父对象的指针

struct kset * kset;    所属kset的指针

struct kobj_type * ktype;   指向其对象类型描述符的指针

struct dentry * dentry; sysfs文件系统中与该对象对应的文件节点路径指针

};

其中的kref域表示该对象的计数,内核通过kref实现对象计数管理,内核提供两个函数kobject_get()、kobject_put()分别用于增加和减少计数,当计数为0时,所有该对象使用的资源将被释放。

Ktype 域是一个指向kobj_type结构的指针,表示该对象的类型。Kobj_type数据结构包含三个域:一个release方法用于释放kobject占 用的资源;一个sysfs_ops指针指向sysfs操作表和一个sysfs文件系统缺省属性列表。Sysfs操作表包括两个函数store()和 show()。当用户态读取属性时,show()函数被调用,该函数编码指定属性值存入buffer中返回给用户态;而store()函数用于存储用户态传入的属性值。

2.2 kset内核对象集合

Kobject通常通过kset组织成层次化的结构,kset是具有相同类型的kobject的集合,在内核中用kset数据结构表示,定义为:

struct kset {

struct subsystem * subsys;   所在的subsystem的指针

struct kobj_type * ktype;   指向该kset对象类型描述符的指针

struct list_head list;      用于连接该kset中所有kobject的链表头

struct kobject kobj;     嵌入的kobject

struct kset_hotplug_ops * hotplug_ops; 指向热插拔操作表的指针

};

包含在kset中的所有kobject被组织成一个双向循环链表,list域正是该链表的头。Ktype域指向一个kobj_type结构,被该 kset中的所有kobject共享,表示这些对象的类型。Kset数据结构还内嵌了一个kobject对象(由kobj域表示),所有属于这个kset 的kobject对象的parent域均指向这个内嵌的对象。此外,kset还依赖于kobj维护计数:kset的计数实际上就是内嵌的 kobject对象的计数。

2.3 subsystem内核对象子系统

Subsystem是一系列kset的集合,描述系统中某一类设备子系统,如block_subsys表示所有的块设备,对应于sysfs文件系统中的block目录。类似的,devices_subsys对应于 sysfs中的devices目录,描述系统中所有的设备。Subsystem由struct subsystem数据结构描述,定义为:

struct subsystem {

struct kset kset;       内嵌的kset对象

struct rw_semaphore rwsem; 互斥访问信号量

};

每 个kset必须属于某个subsystem,通过设置kset结构中的subsys域指向指定的subsystem可以将一个kset加入到该 subsystem。所有挂接到同一subsystem的kset共享同一个rwsem信号量,用于同步访问kset中的链表。



3. 内核对象机制主要相关函数

针对内核对象不同层次的数据结构,linux 2.6内核定义了一系列操作函数,定义于lib/kobject.c文件中。  
3.1 kobject相关函数

void kobject_init(struct kobject * kobj);

kobject初始化函数。设置kobject计数为1,entry域指向自身,其所属kset计数加1。

int kobject_set_name(struct kobject *kobj, const char *format, ...);

设置指定kobject的名称。

void kobject_cleanup(struct kobject * kobj)和void kobject_release(struct kref *kref);

kobject清除函数。当其计数为0时,释放对象占用的资源。

struct kobject *kobject_get(struct kobject *kobj);

将kobj 对象的计数加1,同时返回该对象的指针。

void kobject_put(struct kobject * kobj);

将kobj对象的计数减1,如果计数降为0,则调用kobject_release()释放该kobject对象。

int kobject_add(struct kobject * kobj);

将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录各级kobject的计数,在其parent指向的目录下创建文件节点,并启动该类型内核对象的hotplug函数。

int kobject_register(struct kobject * kobj);

kobject注册函数。通过调用kobject_init()初始化kobj,再调用kobject_add()完成该内核对象的注册。

void kobject_del(struct kobject * kobj);

从Linux设备层次(hierarchy)中删除kobj对象。

void kobject_unregister(struct kobject * kobj);

kobject注销函数。与kobject_register()相反,它首先调用kobject_del从设备层次中删除该对象,再调用kobject_put()减少该对象的计数,如果计数降为0,则释放该kobject对象。

3.2 kset相关函数

与kobject 相似,kset_init()完成指定kset的初始化,kset_get()和kset_put()分别增加和减少kset对象的计数。 Kset_add()和kset_del()函数分别实现将指定keset对象加入设备层次和从其中删除;kset_register()函数完成 kset的注册而kset_unregister()函数则完成kset的注销。

3.3 subsystem相关函数

subsystem有一组完成类似的函数,分别是:

void subsystem_init(struct subsystem *subsys);

int subsystem_register(struct subsystem *subsys);

void subsystem_unregister(struct subsystem *subsys);

struct subsystem *subsys_get(struct subsystem *subsys)

void subsys_put(struct subsystem *subsys);

4. 设备模型组件

在上述内核对象机制的基础上,Linux的设备模型建立在几个关键组件的基础上,下面我们详细阐述这些组件。

4.1 devices

系统中的任一设备在设备模型中都由一个device对象描述,其对应的数据结构struct device定义为:

struct device {

struct list_head g_list;

struct list_head node;

    struct list_head bus_list;

    struct list_head driver_list;

    struct list_head children;

    struct device *parent;

    struct kobject kobj;

    char bus_id[BUS_ID_SIZE];

    struct bus_type *bus;

    struct device_driver *driver;

    void *driver_data;

    /* Several fields omitted */

};

g_list 将该device对象挂接到全局设备链表中,所有的device对象都包含在devices_subsys中,并组织成层次结构。Node域将该对象挂接 到其兄弟对象的链表中,而bus_list则用于将连接到相同总线上的设备组织成链表,driver_list则将同一驱动程序管理的所有设备组织为链 表。此外,children域指向该device对象子对象链表头,parent域则指向父对象。Device对象还内嵌一个kobject对象,用于引 用计数管理并通过它实现设备层次结构。Driver域指向管理该设备的驱动程序对象,而driver_data则是提供给驱动程序的数据。Bus域描述设 备所连接的总线类型。

内核提供了相应的函数用于操作device对象。其中Device_register()函数将一个新的device对象插 入设备模型,并自动在/sys/devices下创建一个对应的目录。Device_unregister()完成相反的操作,注销设备对象。 Get_device()和put_device()分别增加与减少设备对象的计数。通常device结构不单独使用,而是包含在更大的结构中作为一 个子结构使用,比如描述PCI设备的struct pci_dev,其中的dev域就是一个device对象。
4.2 drivers

系统中的每个驱动程序由一个device_driver对象描述,对应的数据结构定义为:

struct device_driver {

    char *name;   设备驱动程序的名称

    struct bus_type *bus; 该驱动所管理的设备挂接的总线类型

    struct kobject kobj;    内嵌kobject对象

    struct list_head devices;   该驱动所管理的设备链表头

    int (*probe)(struct device *dev); 指向设备探测函数,用于探测设备是否可以被该驱动程序管理

int (*remove)(struct device *dev); 用于删除设备的函数

/* some fields omitted*/

};

与device 结构类似,device_driver对象依靠内嵌的kobject对象实现计数管理和层次结构组织。内核提供类似的函数用于操作 device_driver对象,如get_driver()增加计数,driver_register()用于向设备模型插入新的driver对 象,同时在sysfs文件系统中创建对应的目录。Device_driver()结构还包括几个函数,用于处理热拔插、即插即用和电源管理事件。

4.3   buses

系统中总线由struct bus_type描述,定义为:

struct bus_type {

char   * name; 总线类型的名称

struct subsystem subsys; 与该总线相关的subsystem

struct kset drivers; 所有与该总线相关的驱动程序集合

struct kset devices; 所有挂接在该总线上的设备集合

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 (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);

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

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

};

每个bus_type对象都内嵌一个subsystem对象,bus_subsys对象管理系统中所有总线类型的subsystem对象。每个 bus_type对象都对应/sys/bus目录下的一个子目录,如PCI总线类型对应于/sys/bus/pci。在每个这样的目录下都存在两个子目 录:devices和drivers(分别对应于bus_type结构中的devices和drivers域)。其中devices子目录描述连接在该总 线上的所有设备,而drivers目录则描述与该总线关联的所有驱动程序。与device_driver对象类似,bus_type结构还包含几个函数 (match()、hotplug()等)处理相应的热插拔、即插即拔和电源管理事件。

4.4 classes

系统中的设备类由 struct class描述,表示某一类设备。所有的class对象都属于class_subsys子系统,对应于sysfs文件系统中的/sys/class目录。 每个class对象包括一个class_device链表,每个class_device对象表示一个逻辑设备,并通过struct class_device中的dev域(一个指向struct device的指针)关联一个物理设备。这样,一个逻辑设备总是对应于一个物理设备,但是一个物理设备却可能对应于多个逻辑设备。此外,class结构中 还包括用于处理热插拔、即插即拔和电源管理事件的函数,这与device对象和driver对象相似。



device model

device model主要的数据结构有三个: kobject, kset 和 subsystem.



相关数据结构:

struct kobject {

char   * k_name;

char   name[KOBJ_NAME_LEN];

struct kref  kref;

struct list_head entry;

struct kobject  * parent;

struct kset  * kset;

struct kobj_type * ktype;

struct dentry  * dentry;

};



struct kset {

struct subsystem * subsys;

struct kobj_type * ktype;

struct list_head list;

spinlock_t  list_lock;

struct kobject  kobj;

struct kset_hotplug_ops * hotplug_ops;

};

  

struct subsystem {

struct kset  kset;

struct rw_semaphore rwsem;

};



他们是整个device model的骨架(用面向对象的口气说:这叫基类(不是鸡肋^_`))。

其他所有的结构,比如cdev,bus等等,都是在这些骨架上搭建起来的。

kobject是最最基础的。很多结构都会有一个内嵌的kobject.

kobject的计数功能是最重要的。



kset可以看作是一类kojbect的集合,而subsystem可以看作是若干kset的集合。



多个kset可以通过subsys指针指向一个subsystem。但subsystem仅包含一个内嵌的kset。

这种单向关系意味着不可能仅仅通过一个subsystem结构体就找到该subsystem所有的ksets。

他们的联系示意图如下:

                                                        

                                                        

  /----------------------------->     kset     <----------------------------/

  |                              +------------+                             |

  |                              |   subsys   |                             |

  |                              +------------+                             |

  |                              |   ktype    |                             |

  |                              +------------+                             |

  |   /------------------------->|   list     |<------------------------/   |

  |   |                          +------------+                         |   |

  |   |                    /---->|   kobj     |<---/                    |   |

  |   |                    |     +------------+    |                    |   |

  |   |                    |     | hotplug_ops|    |                    |   |

  |   |                    |     +------------+    |                    |   |

  |   |                    |                       |                    |   |

  |   |                    |                       |                    |   |

  |   |                    |                       |                    |   |

  |   |                    |                       |                    |   |

  |   |                    |                       |                    |   |

  |   |                    |                       |                    |   |

  |   |                    |                       |                    |   |

  |   |       kobject      |                       |       kobject      |   |

  |   |     +--------+     |                       |     +--------+     |   |

  |   |     |        |     |                       |     |        |     |   |

  |   |     +--------+     |                       |     +--------+     |   |

  |   |     | parent |-----/                       /-----| parent |     |   |

  |   |     +--------+                                   +--------+     |   |

  |   /---->| entry  |<--------------------------------->| entry  |-----/   |

  |         +--------+                                   +--------+         |

  |         |        |                                   |        |         |

  |         +--------+                                   +--------+         |

  /---------| kset   |                                   | kset   |---------/

            +--------+                                   +--------+  

            |        |                                   |        |  

            +--------+                                   +--------+  

          



另外需要说明的是,kset中的list是贯穿所有kobject的双向链表,但是并不一定是通过kobject的entry字段穿在一起的。

所有的kobject并不简单的是一个独立的kobject,而可能是内嵌在其他数据结构中的kobject(例如kset,subsystem 等等)

          

          

                                subsystem       <-----/  

                       +------------------------+     |

                       |             kset       |     |

                       |        +-------------+ |     |

                       |        |   subsys    |-------/

                       |        +-------------+ |      

                       |        |   ktype     | |

                       |  kset  +-------------+ |

                       |        |   list      | |

                       |        +-------------+ |

                       |        |   kobj      | |

                       |        +-------------+ |

                       |        | hotplug_ops | |  

                       |        +-------------+ |  

                       |------------------------|  

                       |                        |  

                       |      rwsem             |  

                       |                        |  

                       +------------------------+  

                

                

所有的kset一定属于一个subsystem中(kset的subsys指向某一个subsystem)

对于subsystem内嵌的kset,如果没有设定它的subsys, 则是指向自身的subsystem。(见subsystem_register()函数)




喜欢0 评分0
游客

返回顶部