当前位置:文档之家› 如何实现Linux设备驱动模型

如何实现Linux设备驱动模型

文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.如何实现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 device 数据结构定义struct device {struct device *parent; /* 父设备*/ struct device_private *p; /* 设备的私有数据 */ struct kobjectkobj; /* 设备的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_infopower;/* 电源管理*/#ifdef CONFIG_NUMA int numa_node; /*设备接近的非一致性存储结构*/ #endifu64 *dma_mask; /* DMA 掩码*/ u64 coherent_dma_mask; /*设备一致性的DMA 掩码*/struct device_dma_parameters *dma_parms; /* DMA 参数*/ struct list_headdma_pools; /* DMA 缓冲池*/ struct dma_coherent_mem*dma_mem; /* DMA 一致性内存 */ /*体系结构相关的附加项*/ struct dev_archdata archdata;/* 体系结构相关的数据*/ #ifdef CONFIG_OF文库资料©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 结构的更高层的结构体,如程序清单错误!文档中没有指定样式的文字。

.2所示。

程序清单错误!文档中没有指定样式的文字。

.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 是设备的名字。

文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.与device_create()函数相反的是device_destroy()函数,用于销毁sysfs/class 目录中的dev 文件。

device_destroy()函数原型如下:void device_destroy(struct class *cls, dev_t devt);1.1.2 驱动与设备相对应,Linux 设备驱动模型中,对管理的驱动也用device_driver 结构来描述,在<linux/device.h>中定义,如程序清单错误!文档中没有指定样式的文字。

.3所示。

程序清单错误!文档中没有指定样式的文字。

.3device_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; /* 匹配设备的表 */ #endifint (*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 结构的更高层的结构体,原型如程序清单错误!文档中没有指定样式的文字。

.4所示。

程序清单错误!文档中没有指定样式的文字。

.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);文库资料©2017 Guangzhou ZHIYUAN Electronics Stock Co., Ltd.1.1.3 总线在设备驱动模型中,所有的设备都通过总线相连,总线既可以是实际的物理总线,也可以是内核虚拟的platform 总线。

驱动也挂在总线上,总线是设备和驱动之间的媒介,为它们提供服务。

当设备插入系统,总线将在所注册的驱动中寻找匹配的驱动,当驱动插入系统中,总线也会在所注册的设备中寻找匹配的设备。

在Linux 设备驱动模型中,总线用bus_type 结构来描述。

bus_type 结构在<linux/device.h>中定义,如程序清单错误!文档中没有指定样式的文字。

.5所示。

程序清单错误!文档中没有指定样式的文字。

.5bus_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 方法。

相关主题