Linux2.6内核以后引入新的设备驱动模型,设备驱动模型的基础数据结构主要有KObject和KSet,Kset顾名思义应该是一个集合(比如说总线集、设备驱动集合、设备集合),KObject顾名思义应该是具体的一个事物(比如说总线、驱动、设备),KSet就是KObject的集合,通过这两个结构体来表征总线、设备、设备驱动之间的层次关系。而完成设备驱动具体功能主要由总线、设备驱动、设备三个结构体以及其中的功能函数。
在实际的驱动编写中,主要是针对总线、设备驱动、设备这个部件进行编程,通过这三个标准部件,完成Linux下驱动编写的标准化。
我们编写一个设备驱动,首先需要考虑的这个设备驱动是属于那个总线的,是USB总线、PCI总线还是I2C总线或者是其他设备总线。一个设备不管是手动或者自动安装到系统时,会首先向系统注册,系统会根据设备驱动的总线类型(设备驱动结构体中已经定义好)找到对应的设备总线,然后将设备驱动加到对应总线的驱动KSet中去,即将当前设备驱动KObject加入到对应总线的KSet中去,当新的设备插入系统时,系统也会根据硬件连接判断设备属于那个总线,然后遍历总线下驱动KSet,通过驱动探测函数匹配设备驱动(匹配条件如设备的ID),如果找到设备驱动程序,就将该设备加入总线的设备KSet中,并修改设备结构体中设备驱动程序指针,将设备和设备驱动程序关联起来,如果没有找到匹配设备驱动,就仅仅将设备加入到总线的设备KSet中,没有关联的设备驱动程序。由此可见总线KObject包含设备KSet和设备驱动KSet。
综上所述每个设备或者设备驱动程序都是属于总线,不管是新的设备插入还是新的设备驱动注册安装,都会通过遍历总线下设备KSet和设备驱动KSet来完成设备和驱动的匹配,实现设备与驱动的关联。
那么,总线、设备、设备驱动在Linux中是如何具体关联的呢?
在Linux设备驱动模型中,总线有bus_type结构体描述,定义在<linux/device.h>文件中
总线驱动也属于内核模块,因此在编写具体总线驱动时,也需要完成module_init和module_exit接口。在Linux驱动模型中,总线也被看做设备,因此在编写总线的驱动时,需要同时实现总线接口和设备接口。
下面是总线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,用于管理其挂载其总线下的设备和驱动
};
总线中有一个匹配接口,实现挂载在总线上设备与设备驱动的匹配。在模块初始化过程中,注册总线和注册设备。(比较重要的是match接口)
bus_attrs:总线默认属性
struct bus_attribute { struct attribute attr;<br> ssize_t (*show)(struct bus_type *bus, char *buf); ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count); }; |
@dev_attrs:所有挂载设备默认属性?
struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); }; |
@drv_attrs:所有挂载驱动默认属性?
struct driver_attribute { struct attribute attr; ssize_t (*show)(struct device_driver *driver, char *buf); ssize_t (*store)(struct device_driver *driver, const char *buf, size_t count); }; |
struct subsys_private {
structkset subsys;
structkset *devices_kset;
structkset *drivers_kset;
structklist klist_devices;
structklist klist_drivers;
structblocking_notifier_head bus_notifier;
unsignedint drivers_autoprobe:1;
structbus_type *bus;
structlist_head class_interfaces;
structkset glue_dirs;
structmutex class_mutex;
structclass *class;
};
下面是设备驱动和设备的接口
struct device_driver {
constchar *name;
structbus_type *bus;
structmodule *owner;
constchar *mod_name; /* used for built-in modules */
boolsuppress_bind_attrs; /* disablesbind/unbind via sysfs */
conststruct of_device_id *of_match_table;
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);
conststruct attribute_group **groups;
conststruct dev_pm_ops *pm;
structdriver_private *p;
};
设备?
struct device { struct device *parent;
struct device_private *p;
struct kobject kobj; const char *init_name; /* initial name of the device */ const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to * its driver. */
struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ struct dev_pm_info power; struct dev_power_domain *pwr_domain;
#ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif u64 *dma_mask; /* dma mask (if dma'able device) */ u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ /* arch specific additions */ struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
dev_t devt; /* dev_t, creates the sysfs "dev" */ spinlock_t devres_lock; struct list_head devres_head;
struct klist_node knode_class; struct class *class; const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev); }; |
设备和设备驱动是如何联系起来的呢?前面已经介绍过了,每个设备和设备驱动都是属于某个总线的,设备和设备驱动都是挂载在总线上,当新设备插入时或者新的设备驱动向系统注册时,系统会遍历相应总线上的设备和设备驱动,并通过bus_type结构体中的match函数实现设备与设备驱动的匹配,那么匹配函数时如何匹配设备设备驱动呢?在设备结构体有个init_name 的成员,在设备驱动结构体中有一个name的成员。