Chinaunix首页 | 论坛 | 博客
  • 博客访问: 315093
  • 博文数量: 172
  • 博客积分: 25
  • 博客等级: 民兵
  • 技术积分: 895
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-09 16:57
文章分类

全部博文(172)

文章存档

2012年(86)

2011年(86)

分类:

2011-12-26 00:24:39

原文地址:Linux设备驱动模型 作者:tq08g2z

Linux2.6提供了一些数据结构和辅助函数,他们为系统中所有的总线、设备以及设备驱动程序提供了一个统一的视图;这个框架被称为设备驱动模型。

 

Sysfs文件系统是一种特殊的文件系统,同样被设计成允许用户态应用程序访问内核数据结构的一种文件系统。它还提供关于内核数据结构的附加信息。Sysfs文件系统的目标是要展现设备驱动程序模型组件的层次关系。来看一下这个sysfs

该文件系统的相应高层目录是:

block: 块设备,他们独立于所有连接的总线。

devices:所有被内核识别的硬件设备,依照连接他们的总线对其进行组织。

bus:系统中用于连接设备的总线。

drivers:在内核中注册的设备驱动程序。

class:系统中设备的类型(声卡、网卡、显卡等等),同一类可能包含有不同总线连接的设备,于是由不同的驱动程序驱动。

power:处理一些硬件设备电源状态的文件。

firmware:处理一些硬件设备的固件的文件。

 

Sysfs文件系统中所表示的设备驱动程序模型组件之间的关系就像目录和文件、符号链接之间的关系一样。Sysfs文件系统中普通文件的主要作用是表示驱动程序和设备的属性。

 

 

kobject

设备驱动程序模型的核心数据结构是一个普通的数据结构,叫做kobject,他与sysfs文件系统自然的绑定在一起:每个kobject对应于sysfs文件系统中的一个目录。

 

通常情况下,kobject不会被单独的使用,而是被嵌入一个叫做“容器”的更大的对象中,这就像是Linux内核里在许多数据结构中都能见到的list_head结构一样,而容器描述设备驱动程序模型中的组件。容器(通常为一个内核对象)的典型例子有总线、设备以及驱动程序的描述符。

 

将一个kobject嵌入容器中允许内核:

1、为容器保持一个引用计数。

2、维持容器的层次列表或组。

3、为容器的属性提供一中用户态查看的视图。

 

kobjectksetkobj_type

每个kobjectkobject数据结构描述,其定义如下:

---------------------------------------------------------------------

include/linux/kobject.h

59 struct kobject {

 60         const char              *name;

 61         struct list_head        entry;

 62         struct kobject          *parent;

 63         struct kset             *kset;

 64         struct kobj_type        *ktype;

 65         struct sysfs_dirent     *sd;

 66         struct kref             kref;

 67         unsigned int state_initialized:1;

 68         unsigned int state_in_sysfs:1;

 69         unsigned int state_add_uevent_sent:1;

 70         unsigned int state_remove_uevent_sent:1;

 71         unsigned int uevent_suppress:1;

 72 };

---------------------------------------------------------------------

name:指向包含容器名称的字符串。

entry:用于kobject所插入的链表的指针,比如同一个ksetkobject会被连接起来。

parent:指向父kobject对象。

kset:指向包含的kset

ktype:指向kobject的类型描述符。

sd:指向与kobject对应的sysfs目录项对象

kref:容器的引用计数。

 

ktype字段指向kobj_type对象,该对象描述了kobject的“类型”——本质上它描述的是包括kobject的容器的类型。其定义如下:

---------------------------------------------------------------------

include/linux/kobject.h

107 struct kobj_type {

108         void (*release)(struct kobject *kobj);

109         const struct sysfs_ops *sysfs_ops;

110         struct attribute **default_attrs;

111 };

---------------------------------------------------------------------

kobject对象的生存周期通常是难以预测的,创建者并不知道kobject的引用计数什么时候会变为0。为了异步的通知创建者,于是便产生了release方法,它在kobject对象的引用计数变为0时调用,通常release方法都是做一些清理工作。每一个kobject都需要一个kobj_type和它关联起来。

另外两个字段sysfs_opsdefault_attrs控制如何在sysfs文件系统中来呈现这一类型的对象。

default_attrs指向一个任何注册为该类型的kobject都会自动拥有的默认属性的表。属性在sysfs中用一个文件表示。

 

kref字段是一个kref类型的结构,它仅包括一个refcount字段。这个字段就是kobject的引用计数器,但它也可以作为kobject的容器的引用计数器。为了安全,不能手动的释放kobject对象,系统专门提供了两个函数用于管理管理引用计数器:

struct kobject *kobject_get(struct kobject *kobj);

void kobject_put(struct kobject *kobj);

 

 

通过kset数据结构,可以将kobjects组织成一棵层次树。kset仅仅是一个相关的kobjects的集合。同一个kset中的kobject没有限制要求他们必须具有相同的ktype,但若他们不是则必须要小心。kset定义为:

---------------------------------------------------------------------

include/linux/kobject.h

137 /**

138  * struct kset - a set of kobjects of a specific type, belonging to

139  * a specific subsystem.

140  * A kset defines a group of kobjects.  They can be individually

141  * different "types" but overall these kobjects all want to be grouped

142  * together and operated on in the same manner.  ksets are used to

143  * define the attribute callbacks and other common events that happen

144  * to a kobject.

145  *

146  * @list: the list of all kobjects for this kset

147  * @list_lock: a lock for iterating over the kobjects

148  * @kobj: the embedded kobject for this kset (recursion, isn't it

 fun...)

149  * @uevent_ops: the set of uevent operations for this kset.  These

150  * are called whenever a kobject has something happen to it so that

151  * the kset can add new environment variables, or filter out the

152  * uevents if so desired.

153  */

154 struct kset {

155         struct list_head list;

156         spinlock_t list_lock;

157         struct kobject kobj;

158         const struct kset_uevent_ops *uevent_ops;

159 };

---------------------------------------------------------------------

ksetsysfs中的一个子目录,可以展示与kset相关的kobjectskobj字段是嵌入在kset数据结构中的kobject。它可以被设置为属于该ksetkobject的父kobject,即由kobjectparent指向它。如果属于一个ksetkobject在注册时没有指定父kobject,那么它将被添加进kset的目录。并不是一个kset的所有的成员都必须位于kset目录。如果在注册的时候明确的指定了父kobject的换,则注册到ksetkobject将会被添加在父kobject下。

 

注册kobjectkset

一般来说,如果想让kobjectkset出现在sysfs子树中,就必须首先注册它们。与kobject对应的目录总是出现在其父kobject的目录中。因此,sysfs子树的结构就描述了各种已注册的kobject之间以及各种容器对象之间的层次关系。

创建kobject的代码必须初始化它。通过强制调用kobject_init()函数 kobject的一些内部字段会被适当的设置:

void kobject_init(struct kobject *kobj, struct kobj_type *ktype);

 

调用了kobject_init()之后则可以向sysfs注册kobject,这必须调用kobject_add()函数:

int __must_check kobject_add(struct kobject *kobj,

                struct kobject *parent,

                const char *fmt, ...);

 

也可以通过调用kobject_init_and_add()在同一时刻完成kobject的初始化和添加进系统:

int __must_check kobject_init_and_add(struct kobject *kobj,

                     struct kobj_type *ktype,

                     struct kobject *parent,

                     const char *fmt, ...);

 

kobject_del()用于将kobject的目录从sysfs文件系统移走:

void kobject_del(struct kobject *kobj);

 

为了更易于内核开发者进行开发,Linux也提供了另外一些函数:

int kset_register(struct kset *kset);

void kset_unregister(struct kset *kset);

struct kset * kset_create_and_add(const char *name,

                   const struct kset_uevent_ops *u,

                   struct kobject *parent_kobj);

但他们本质上是围绕kobject的封装。

 

许多kobject目录都包括称作属性(attribute)的普通文件。sysfs_create_file()函数接受kobject的地址和属性描述符作为它的参数,并在合适的目录中创建特殊文件:

int sysfs_create_file(struct kobject *kobj,

const struct attribute *attr);

 

sysfs文件系统中所描述的对象间的其他关系可以通过符号链接的方式来建立,sysfs_create_link()函数为目录中其他kobject相关联的特定kobject创建一个符号链接:

int sysfs_create_link(struct kobject *kobj, struct kobject *target,

               const char *name);

 

 

设备驱动程序模型的组件

设备驱动程序模型建立在几个基本数据结构之上,这些结构描述了总线、设备、设备驱动等等。让我们来看一下他们。

 

设备

设备驱动模型中的每个设备是由一个device对象来描述的。其定义如下:

---------------------------------------------------------------------

include/linux/device.h

398 struct device {

399     struct device           *parent;/* 指向父设备的指针 */

400

401     struct device_private   *p;

402

403     struct kobject kobj; /* 内嵌的kobject结构 */

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

405     struct device_type      *type;

406

407     struct semaphore  sem;  /* semaphore to synchronize calls to

408                                          * its driver.

409                                          */

410

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

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

413                                            device */

414     void       *platform_data; /* Platform specific data, device

415                                            core doesn't touch it */

416     struct dev_pm_info      power;

417

418 #ifdef CONFIG_NUMA

419     int    numa_node;     /* NUMA node this device is close to */

420 #endif

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

422     u64             coherent_dma_mask;/* Like dma_mask, but for

423                              alloc_coherent mappings as

424                              not all hardware supports

425                              64 bit addresses for consistent

426                              allocations such descriptors. */

427

428     struct device_dma_parameters *dma_parms;

429

430     struct list_head     dma_pools;  /* dma pools (if dma'ble) */

431

432     struct dma_coherent_mem *dma_mem; /* internal for coherent mem

433                                              override */

434     /* arch specific additions */

435     struct dev_archdata     archdata;

436

437     dev_t         devt;   /* dev_t, creates the sysfs "dev" */

438

439     spinlock_t              devres_lock;

440     struct list_head        devres_head;

441

442     struct klist_node       knode_class;

443     struct class            *class;

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

445

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

447 };

---------------------------------------------------------------------

 

驱动程序

设备驱动程序模型中的每个驱动程序都可由device_driver对象描述。其定义为:

---------------------------------------------------------------------

include/linux/device.h

122 struct device_driver {

123     const char              *name;

124     struct bus_type         *bus;

125

126     struct module           *owner;

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

128

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

130

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

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

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

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

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

136     const struct attribute_group **groups;

137

138     const struct dev_pm_ops *pm;

139

140     struct driver_private *p;

141 };

---------------------------------------------------------------------

 

总线

内核所支持的每一种总线类型都由一个bus_type对象描述。其定义为:

---------------------------------------------------------------------

include/linux/device.h

51 struct bus_type {

 52     const char              *name;

 53     struct bus_attribute    *bus_attrs;

 54     struct device_attribute *dev_attrs;

 55     struct driver_attribute *drv_attrs;

 56

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

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

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

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

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

 62

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

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

 65

 66     const struct dev_pm_ops *pm;

 67

 68     struct bus_type_private *p;

 69 };

---------------------------------------------------------------------

 

每个类是由一个class对象描述的。其定义为:

---------------------------------------------------------------------

include/linux/device.h

189 struct class {

190  const char              *name;

191  struct module           *owner;

192

193  struct class_attribute          *class_attrs;

194  struct device_attribute         *dev_attrs;

195  struct kobject                  *dev_kobj;

196

197  int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

198  char *(*devnode)(struct device *dev, mode_t *mode);

199

200  void (*class_release)(struct class *class);

201  void (*dev_release)(struct device *dev);

202

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

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

205

206  const struct dev_pm_ops *pm;

207

208  struct class_private *p;

209 };

---------------------------------------------------------------------

 

动态创建设备文件

Linux的设备模型子系统实在是一个非常复杂的系统。除了内核中各种复杂的对象之外,为了实现目标,比如热插拔,动态插入,设备文件的动态建立等特性的,在用户空间也需要有程序来配合,这就是udev工具集,用户态应用程序。当系统启动时,/dev目录是清空的,这是udev程序将扫描/sys/class子目录来寻找dev文件。对每一个这样的文件(主设备号和次设备号的组合表示一个内核所支持的逻辑设备文件),udev程序都会在/dev目录下为它创建一个相应的设备文件。udev也会根据配置文件分配一个文件名并创建一个符号链接。最后,/dev目录里只有存放了系统中内核所支持的所有设备的设备文件,而没有任何其他的文件。

阅读(635) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~