0723 linux中设备与驱动关联
2012-07-23 15:05
204 查看
1、对于Linux驱动开发来说,设备模型的理解是根本,顾名思义设备模型是关于设备的模型,设备的概念就是总线和与其相连的各种设备了。
总线、设备、驱动,也就是bus、device、driver,在内核里都会有它们自己专属的结构,在include/linux/device.h 里定义。
首先是总线,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); --实现设备与驱动的匹配。不同的总线实现匹配的方法不同,如platform总线采用name匹配,而usb_bus采用id匹配
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device*dev); --在2.6的内核中实现一个设备与驱动的探测。主要是因为热插拔的设备的增多。
int (*remove)(struct device*dev); --移除设备
void (*shutdown)(struct device*dev); --关闭设备
int (*suspend)(struct device *dev,pm_message_t state);
int (*suspend_late)(struct device *dev, pm_message_t state);
int (*resume_early)(struct device*dev);
int (*resume)(struct device *dev);
struct dev_pm_ops*pm; --电源管理
struct bus_type_private *p; --bus_type私有成员,这个结构体中主要包括了kset以及klist,用于管理其挂载其总线下的设备和驱动
};
下面是设备device的定义:
struct device {
struct device * parent; //父设备,一般一个bus也对应一个设备。
struct kobject kobj;//代表自身
char bus_id[BUS_ID_SIZE];
struct bus_type * bus; /* 所属的总线 */
struct device_driver *driver; /* 匹配的驱动*/
void *driver_data; /* data private to the driver 指向驱动 */
void *platform_data; /* Platform specific data,由驱动定义并使用*/
///更多字段忽略了
};
下面是设备驱动定义:
struct device_driver {
const char * name;
struct bus_type * bus;//所属总线
struct completion unloaded;
struct kobject kobj;//代表自身
struct klist klist_devices;//设备列表
struct klist_node knode_bus;
struct module * owner;
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);
};
我们会发现,struct bus_type中有成员struct ksetdrivers 和struct ksetdevices,同时struct
device中有两个成员struct bus_type * bus和struct device_driver *driver , struct device_driver中有两个成员struct bus_type*bus和structk listklist_devices。struct device中的bus表示这个设备连到哪个总线上,driver表示这个设备的驱动是什么,struct device_driver中的bus表示这个驱动属于哪个总线,klist_devices表示这个驱动都支持哪些设备,因为这里device是复数,又是list,更因为一个驱动可以支持多个设备,而一个设备只能绑定一个驱动。当然,struct
bus_type中的drivers和devices分别表示了这个总线拥有哪些设备和哪些驱动。
还有上面device 和driver结构里出现的kobject 结构是什么?kobject 和kset 都是Linux 设备模型中最基本的元素。一般来说应该这么理解,整个Linux 的设备模型是一个OO 的体系结构,总线、设备和驱动都是其中鲜活存在的对象,kobject 是它们的基类,所实现的只是一些公共的接口,kset 是同种类型kobject 对象的集合,也可以说是对象的容器。
(ps:Linux2.6内核以后引入新的设备驱动模型,设备驱动模型的基础数据结构主要有KObject和KSet,Kset顾名思义应该是一个集合(比如说总线集、设备驱动集合、设备集合),KObject顾名思义应该是具体的一个事物(比如说总线、驱动、设备),KSet就是KObject的集合,通过这两个结构体来表征总线、设备、设备驱动之间的层次关系。而完成设备驱动具体功能主要由总线、设备驱动、设备三个结构体以及其中的功能函数。)
那么总线、设备和驱动之间是如何关联的呢?
先说说总线中的那两条链表是怎么形成的。内核要求每次出现一个设备就要向总线汇报,或者说注册,每次出现一个驱动,也要向总线汇报,或者说注册。比如系统初始化的时候,会扫描连接了哪些设备,并为每一个设备建立起一个struct device 的变量,每一次有一个驱动程序,就要准备一个struct device_driver 结构的变量。把这些变量统统加入相应的链表,device 插入devices
链表,driver 插入drivers 链表。这样通过总线就能找到每一个设备,每一个驱动。
设备和驱动又是如何联系?
原来是把每一个要用的设备在计算机启动之前就已经插好了,插放在它应该在的位置上,然后计算机启动,然后操作系统开始初始化,总线开始扫描设备,每找到一个设备,就为其申请一个struct device 结构,并且挂入总线中的devices 链表中来,然后每一个驱动程序开始初始化,开始注册其struct device_driver 结构,然后它去总线的devices 链表中去寻找(遍历),去寻找每一个还没有绑定驱动的设备,struct
device 中的struct device_driver 指针仍为空的设备,然后它会去观察这种设备的特征,看是否是他所支持的设备,如果是,那么调用一个叫做device_bind_driver 的函数,然后他们就结为了秦晋之好。换句话说,把struct device 中的struct device_driver driver 指向这个驱动,而struct device_driver driver 把struct device 加入他的那struct klist klist_devices链表中来。就这样,bus、device
和driver,这三者之间或者说他们中的两两之间,就给联系上了。知道其中之一,就能找到另外两个。
但现在情况变了,出现了一种新的名词,叫热插拔。设备可以在计算机启动以后在插入或者拔出计算机了。设备可以在任何时刻出现,而驱动也可以在任何时刻被加载,所以,出现的情况就是,每当一个struct device 诞生,它就会去bus 的drivers链表中寻找自己的另一半,反之,每当一个struct device_driver 诞生,它就去bus的devices 链表中寻找它的那些设备。如果找到了合适的,那么OK,和之前那种情况一下,调device_bind_driver
绑定好。如果找不到,没有关系,等待吧!
我们编写一个设备驱动,首先需要考虑的这个设备驱动是属于那个总线的,是USB总线、PCI总线还是I2C总线或者是其他设备总线。一个设备不管是手动或者自动安装到系统时,会首先向系统注册,系统会根据设备驱动的总线类型(设备驱动结构体中已经定义好)找到对应的设备总线,然后将设备驱动加到对应总线的驱动KSet中去,即将当前设备驱动KObject加入到对应总线的KSet中去,当新的设备插入系统时,系统也会根据硬件连接判断设备属于那个总线,然后遍历总线下驱动KSet,通过驱动探测函数匹配设备驱动(匹配条件如设备的ID),如果找到设备驱动程序,就将该设备加入总线的设备KSet中,并修改设备结构体中设备驱动程序指针,将设备和设备驱动程序关联起来,如果没有找到匹配设备驱动,就仅仅将设备加入到总线的设备KSet中,没有关联的设备驱动程序。由此可见总线KObject包含设备KSet和设备驱动KSet。
总线驱动也属于内核模块,因此在编写具体总线驱动时,也需要完成module_init和module_exit接口。在Linux驱动模型中,总线也被看做设备,因此在编写总线的驱动时,需要同时实现总线接口和设备接口。
总线、设备、驱动,也就是bus、device、driver,在内核里都会有它们自己专属的结构,在include/linux/device.h 里定义。
首先是总线,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); --实现设备与驱动的匹配。不同的总线实现匹配的方法不同,如platform总线采用name匹配,而usb_bus采用id匹配
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device*dev); --在2.6的内核中实现一个设备与驱动的探测。主要是因为热插拔的设备的增多。
int (*remove)(struct device*dev); --移除设备
void (*shutdown)(struct device*dev); --关闭设备
int (*suspend)(struct device *dev,pm_message_t state);
int (*suspend_late)(struct device *dev, pm_message_t state);
int (*resume_early)(struct device*dev);
int (*resume)(struct device *dev);
struct dev_pm_ops*pm; --电源管理
struct bus_type_private *p; --bus_type私有成员,这个结构体中主要包括了kset以及klist,用于管理其挂载其总线下的设备和驱动
};
下面是设备device的定义:
struct device {
struct device * parent; //父设备,一般一个bus也对应一个设备。
struct kobject kobj;//代表自身
char bus_id[BUS_ID_SIZE];
struct bus_type * bus; /* 所属的总线 */
struct device_driver *driver; /* 匹配的驱动*/
void *driver_data; /* data private to the driver 指向驱动 */
void *platform_data; /* Platform specific data,由驱动定义并使用*/
///更多字段忽略了
};
下面是设备驱动定义:
struct device_driver {
const char * name;
struct bus_type * bus;//所属总线
struct completion unloaded;
struct kobject kobj;//代表自身
struct klist klist_devices;//设备列表
struct klist_node knode_bus;
struct module * owner;
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);
};
我们会发现,struct bus_type中有成员struct ksetdrivers 和struct ksetdevices,同时struct
device中有两个成员struct bus_type * bus和struct device_driver *driver , struct device_driver中有两个成员struct bus_type*bus和structk listklist_devices。struct device中的bus表示这个设备连到哪个总线上,driver表示这个设备的驱动是什么,struct device_driver中的bus表示这个驱动属于哪个总线,klist_devices表示这个驱动都支持哪些设备,因为这里device是复数,又是list,更因为一个驱动可以支持多个设备,而一个设备只能绑定一个驱动。当然,struct
bus_type中的drivers和devices分别表示了这个总线拥有哪些设备和哪些驱动。
还有上面device 和driver结构里出现的kobject 结构是什么?kobject 和kset 都是Linux 设备模型中最基本的元素。一般来说应该这么理解,整个Linux 的设备模型是一个OO 的体系结构,总线、设备和驱动都是其中鲜活存在的对象,kobject 是它们的基类,所实现的只是一些公共的接口,kset 是同种类型kobject 对象的集合,也可以说是对象的容器。
(ps:Linux2.6内核以后引入新的设备驱动模型,设备驱动模型的基础数据结构主要有KObject和KSet,Kset顾名思义应该是一个集合(比如说总线集、设备驱动集合、设备集合),KObject顾名思义应该是具体的一个事物(比如说总线、驱动、设备),KSet就是KObject的集合,通过这两个结构体来表征总线、设备、设备驱动之间的层次关系。而完成设备驱动具体功能主要由总线、设备驱动、设备三个结构体以及其中的功能函数。)
那么总线、设备和驱动之间是如何关联的呢?
先说说总线中的那两条链表是怎么形成的。内核要求每次出现一个设备就要向总线汇报,或者说注册,每次出现一个驱动,也要向总线汇报,或者说注册。比如系统初始化的时候,会扫描连接了哪些设备,并为每一个设备建立起一个struct device 的变量,每一次有一个驱动程序,就要准备一个struct device_driver 结构的变量。把这些变量统统加入相应的链表,device 插入devices
链表,driver 插入drivers 链表。这样通过总线就能找到每一个设备,每一个驱动。
设备和驱动又是如何联系?
原来是把每一个要用的设备在计算机启动之前就已经插好了,插放在它应该在的位置上,然后计算机启动,然后操作系统开始初始化,总线开始扫描设备,每找到一个设备,就为其申请一个struct device 结构,并且挂入总线中的devices 链表中来,然后每一个驱动程序开始初始化,开始注册其struct device_driver 结构,然后它去总线的devices 链表中去寻找(遍历),去寻找每一个还没有绑定驱动的设备,struct
device 中的struct device_driver 指针仍为空的设备,然后它会去观察这种设备的特征,看是否是他所支持的设备,如果是,那么调用一个叫做device_bind_driver 的函数,然后他们就结为了秦晋之好。换句话说,把struct device 中的struct device_driver driver 指向这个驱动,而struct device_driver driver 把struct device 加入他的那struct klist klist_devices链表中来。就这样,bus、device
和driver,这三者之间或者说他们中的两两之间,就给联系上了。知道其中之一,就能找到另外两个。
但现在情况变了,出现了一种新的名词,叫热插拔。设备可以在计算机启动以后在插入或者拔出计算机了。设备可以在任何时刻出现,而驱动也可以在任何时刻被加载,所以,出现的情况就是,每当一个struct device 诞生,它就会去bus 的drivers链表中寻找自己的另一半,反之,每当一个struct device_driver 诞生,它就去bus的devices 链表中寻找它的那些设备。如果找到了合适的,那么OK,和之前那种情况一下,调device_bind_driver
绑定好。如果找不到,没有关系,等待吧!
我们编写一个设备驱动,首先需要考虑的这个设备驱动是属于那个总线的,是USB总线、PCI总线还是I2C总线或者是其他设备总线。一个设备不管是手动或者自动安装到系统时,会首先向系统注册,系统会根据设备驱动的总线类型(设备驱动结构体中已经定义好)找到对应的设备总线,然后将设备驱动加到对应总线的驱动KSet中去,即将当前设备驱动KObject加入到对应总线的KSet中去,当新的设备插入系统时,系统也会根据硬件连接判断设备属于那个总线,然后遍历总线下驱动KSet,通过驱动探测函数匹配设备驱动(匹配条件如设备的ID),如果找到设备驱动程序,就将该设备加入总线的设备KSet中,并修改设备结构体中设备驱动程序指针,将设备和设备驱动程序关联起来,如果没有找到匹配设备驱动,就仅仅将设备加入到总线的设备KSet中,没有关联的设备驱动程序。由此可见总线KObject包含设备KSet和设备驱动KSet。
总线驱动也属于内核模块,因此在编写具体总线驱动时,也需要完成module_init和module_exit接口。在Linux驱动模型中,总线也被看做设备,因此在编写总线的驱动时,需要同时实现总线接口和设备接口。
相关文章推荐
- 关于设备模型、设备与驱动关联的过程分析 - linux设备/驱动
- 设备驱动----Linux中总线、设备、驱动是如何关联的?
- Linux中总线、设备、驱动是如何关联的?
- linux设备与驱动关联的全过程分析
- 转:Linux I2C核心、总线与设备驱动
- Linux 设备 设备驱动 设备结点 (设备号) 关系
- Linux字符设备驱动和杂项设备驱动对比
- Linux字符驱动中动态分配设备号与动态生成设备节点
- linux驱动修炼之道-混杂设备
- linux设备驱动makefile入门解析
- linux驱动学习--第二十三天:第十二章:Linux 字符设备驱动综合实例(三)NVRAM 设备驱动 和 看门狗设备驱动
- linux驱动开发之自动创建设备节点的方法
- 设备模型、设备与驱动关联的全过程分析 platform_device platform_driver driver bus关系
- linux设备和驱动加载的先后顺序
- 浅谈 Linux 内核开发之网络设备驱动
- Linux设备驱动开发详解-第4章(三)-导出符号
- linux驱动编写之十三(设备模型之sysfs,bus,device,driver源代码分析)
- linux 总线 设备 驱动
- Linux混杂设备驱动模型
- linux设备驱动之平台总线实践环节(三)