Linux设备驱动模型介绍
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
文库资料 ©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.
第1章 Linux 设备驱动模型介绍
设备驱动模型,对系统的所有设备和驱动进行了抽象,形成了复杂的设备树型结构,采用面向对象的方法,抽象出了device 设备、driver 驱动、bus 总线和class 类等概念,所有已经注册的设备和驱动都挂在总线上,总线来完成设备和驱动之间的匹配。
总线、设备、驱动以及类之间的关系错综复杂,在Linux 内核中通过kobject 、kset 和subsys 来进行管理,驱动编写可以忽略这些管理机制的具体实现。
设备驱动模型的内部结构还在不停的发生改变,如device 、driver 、bus 等数据结构在不同版本都有差异,但是基于设备驱动模型编程的结构基本还是统一的。
Linux 设备驱动模型是Linux 驱动编程的高级内容,这一节只对device 、driver 等这些基本概念作介绍,便于阅读和理解内核中的代码。
实际上,具体驱动也不会孤立的使用这些概念,这些概念都融合在更高层的驱动子系统中。
对于大多数读者可以忽略这一节内容。
1.1.1 设备
在Linux 设备驱动模型中,底层用device 结构来描述所管理的设备。
device 结构在文件<linux/device.h>中定义,如程序清单1.1所示。
程序清单1.1 device 数据结构定义
struct device {
struct device *parent; /* 父设备
*/ struct device_private *p; /* 设备的私有数据 */ struct kobject
kobj; /* 设备的kobject 对象 */ const char *init_name; /*设备的初始名字 */ struct device_type *type;
/* 设备类型
*/ struct mutex mutex; /*同步驱动的互斥信号量 */ struct bus_type *bus; /*设备所在的总线类型 */ struct device_driver *driver; /*管理该设备的驱动程序
*/ void
*platform_data;
/*平台相关的数据 */ struct dev_pm_info
power;
/* 电源管理
*/
#ifdef CONFIG_NUMA int numa_node; /*设备接近的非一致性存储结构
*/ #endif
u64 *dma_mask; /* DMA 掩码
*/ u64 coherent_dma_mask; /*设备一致性的DMA 掩码
*/
struct device_dma_parameters *dma_parms; /* DMA 参数
*/ struct list_head
dma_pools; /* DMA 缓冲池
*/ struct dma_coherent_mem
*dma_mem; /* DMA 一致性内存 */ /*体系结构相关的附加项*/ struct dev_archdata archdata;
/* 体系结构相关的数据
*/ #ifdef CONFIG_OF
struct device_node
*of_node;
文库资料 ©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.
注册和注销device 的函数分别是device_register()和device_unregister(),函数原型如下:
int __must_check device_register(struct device *dev); void device_unregister(struct device *dev);
大多数不会在驱动中单独使用device 结构,而是将device 结构嵌入到更高层的描述结构中。
例如,内核中用spi_device 来描述SPI 设备,spi_device 结构在<linux/spi/spi.h>文件中定义,是一个嵌入了device 结构的更高层的结构体,如程序清单1.2所示。
程序清单1.2 spi_device 数据结构
struct spi_device {
struct device dev;
/* device 数据结构
*/
struct spi_master *master; u32 max_speed_hz; u8 chip_select; u8 mode; u8 bits_per_word; int irq;
void *controller_state; void *controller_data; char modalias[SPI_NAME_SIZE];
};
系统提供了device_create()函数用于在sysfs/classs 中创建dev 文件,以供用户空间使用。
device_create()函数定义如下:
struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
说明:
● cls 是指向将要被注册的class 结构; ● parent 是设备的父指针; ● devt 是设备的设备编号;
● drvdata 是被添加到设备回调的数据; ● fmt 是设备的名字。
与device_create()函数相反的是device_destroy()函数,用于销毁sysfs/class 目录中的dev 文件。
device_destroy()函数原型如下:
文库资料 ©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.
1.1.2 驱动
与设备相对应,Linux 设备驱动模型中,对管理的驱动也用device_driver 结构来描述,在<linux/device.h>中定义,如程序清单1.3所示。
程序清单1.3 device_driver 结构定义
struct device_driver {
const char *name; /* 驱动的名称
*/ struct bus_type *bus; /* 驱动所在的总线 */ struct module
*owner;
/* 驱动的所属模块
*/ const char *mod_name; /*模块名称(静态编译的时候使用) */ bool suppress_bind_attrs;
/*通过sysfs 禁止bind 或者unbind */ #if defined(CONFIG_OF)
const struct of_device_id *of_match_table; /* 匹配设备的表 */ #endif
int (*probe) (struct device *dev);
/* probe 探测方法 */ int (*remove) (struct device *dev); /* remove 方法 */ void (*shutdown) (struct device *dev); /* shutdown 方法 */ int (*suspend) (struct device *dev, pm_message_t state);
/* suspend 方法 */ int (*resume) (struct device *dev);
/* resume 方法
*/
const struct attribute_group **groups; const struct dev_pm_ops *pm; /* 电源管理 */ struct driver_private *p;
/* 驱动的私有数据
*/
};
系统提供了driver_register()和driver_ungister()分别用于注册和注销device_driver ,函数原型分别如下:
int __must_check driver_register(struct device_driver *drv); void driver_unregister(struct device_driver *drv);
与device 结构类似,在驱动中一般也不会单独使用device_driver 结构,通常也是嵌入在更高层的描述结构中。
还是以SPI 为例,SPI 设备的驱动结构为spi_driver ,在<linux/spi/spi.h>文件中定义,是一个内嵌了device_driver 结构的更高层的结构体,原型如程序清单1.4所示。
程序清单1.4 spi_driver 数据结构
struct spi_driver {
const struct spi_device_id *id_table;
int (*probe)(struct spi_device *spi); int
(*remove)(struct spi_device *spi);
void (*shutdown)(struct spi_device *spi);
int (*suspend)(struct spi_device *spi, pm_message_t mesg); int (*resume)(struct spi_device *spi);
文库资料 ©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.
1.1.3 总线
在设备驱动模型中,所有的设备都通过总线相连,总线既可以是实际的物理总线,也可以是内核虚拟的platform 总线。
驱动也挂在总线上,总线是设备和驱动之间的媒介,为它们提供服务。
当设备插入系统,总线将在所注册的驱动中寻找匹配的驱动,当驱动插入系统中,总线也会在所注册的设备中寻找匹配的设备。
在Linux 设备驱动模型中,总线用bus_type 结构来描述。
bus_type 结构在<linux/device.h>中定义,如程序清单1.5所示。
程序清单1.5 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); /* match 方法:匹配设备和驱动 */
int (*uevent)(struct device *dev, struct kobj_uevent_env *env); /* uevent 方法,支持热插拔
*/ int (*probe)(struct device *dev);
/* probe 方法
*/ int (*remove)(struct device *dev); /* remove 方法 */ void (*shutdown)(struct device *dev); /* shutdown 方法 * int (*suspend)(struct device *dev, pm_message_t state);
/* suspend 方法 */ int (*resume)(struct device *dev); /* resume 方法
*/
const struct dev_pm_ops *pm; /* 电源管理
*/ struct bus_type_private *p;
/* 总线的私有数据结构
*/
};
说明一下bus 总线的match 方法。
当往总线添加一个新设备或者新驱动的时候,match 方法会被调用,为设备或者驱动寻找匹配的驱动程序或者设备。
注册和注销bus 总线的函数分别是bus_register()和bus_unregister(),函数原型分别如下:
int __must_check bus_register(struct bus_type *bus); void bus_unregister(struct bus_type *bus);
一般情况下,无需用户再往系统注册一个总线,因为目前Linux 的设备驱动模型已经比较完善,几乎任何设备都可以套用既有的总线。
1.1.4 类
类是Linux 设备驱动模型中的一个高层抽象,为用户空间提供设备的高层视图。
如在驱动中SCSI 磁盘和ATA 磁盘,它们是不同的设备,但是从类的角度来看,它们都是磁盘,在用户用户空间无需关心底层设备和驱动的具体实现。
文库资料 ©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.
在sysfs 中,类一般都放在/sys/class/目录下,例外的是块设备放在/sys/block 目录下。
在类子系统中,可以向用户空间导出信息,用户空间可以通过这些信息与内核交互。
最典型就是已经接触过的udev ,udev 是用户空间的程序,根据/sys/class 目录下的dev 文件来创建设备节点。
在Linux 设备驱动模型中,类用class 结构来描述,在<linux/device.h>中定义,如程序清单1.6所示。
程序清单1.6 class 结构定义
struct class {
const char *name; /* 类的名称 */ struct module
*owner;
/* 类的所属模块
*/ struct class_attribute *class_attrs; /* 类的属性 */ struct device_attribute *dev_attrs;
/* 设备属性
*/ struct kobject *dev_kobj;
/* 类的kobject 对象
*/
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); char *(*devnode)(struct device *dev, mode_t *mode); void (*class_release)(struct class *class); void (*dev_release)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev);
const struct kobj_ns_type_operations *ns_type; const void *(*namespace)(struct device *dev); const struct dev_pm_ops *pm; struct class_private *p; };
注册或者注销一个类的函数分别是class_register()和class_unregister(),函数原型分别如下:
int __must_check __class_register(struct class *class,struct lock_class_key *key); #define class_register(class) \ ({ \ static struct lock_class_key __key; \
__class_register(class, &__key); \
})
void class_unregister(struct class *class);
调用class_create()可以在sysfs/class 目录下创建自定义的类,调用class_destroy()函数则以销毁自定义类,函数原型分别如下:
extern struct class * __must_check __class_create(struct module *owner, const char *name,
struct lock_class_key *key); #define class_create(owner, name) \
文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.。