前言:
本篇blog主要是整理了一下总线,驱动,设备之间的关系概述。
一、总线、驱动、设备
1.1 设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构
1.2 在2.4内核中,设备的信息放在/proc中,在2.6内核以后,把设备相关的信息归类在新增加sysfs文件系统,并将它挂载到/sys目录中,把设备信息归类的同时,让用户可以通过用户空间访问。
简单介绍一些sys中的目录:
block:用于管理块设备,系统中的每一个块设备会在该目录下对应一个子目录。bus:用于管理总线,每注册一条总线,在该目录下有一个对应的子目录。
其中,每个总线子目录下会有两个子目录:devices和drivers。
devices包含系统中所有属于该总线的的设备。
class:将系统中的设备按功能分类。dev:该目录包含已注册的设备号(设备节点)的视图,包括char和block
kernel:内核中的相关参数。module:内核中的模块信息。
fireware:内核中的固件信息。
Fs:描述内核中的文件系统。
sys中的其他目录都是将devvice目录下的数据加以转换加工而得,通过/sys中信息,内核就能方便对设备进行管理
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); // 匹配方法int (*uevent)(struct device *dev, struct kobj_uevent_env *env);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);
const struct dev_pm_ops *pm;
struct subsys_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;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;
/* 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); //当设备的最后一个引用被删除时,调用该函数};
const char *name; // 驱动名字struct bus_type *bus; // 所属总线
struct module *owner;const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;// 设备id表,表示该驱动支持哪些型号的设备
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);const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;};
设备的成功注册后会在/sys/device目录下创建相应的目录,如果指定总线,会在指定总线目录/sys/bus/xx/device下创建一个指向/sys/device目录的软连接。
驱动函数的注册会在/sys/bus/xx/driver目录下创建相应的目录。
二、配对函数(match)、探测函数(probe)和卸载函数(remove)
1. int (*match)(struct device *dev, struct device_driver *drv);--总线bus
当总线上添加了新设备或者新驱动函数的时候,内核会调用一次或者多次这个函数。
如果现在添加了一个新的驱动(driver),内核就会调用所属总线(bus)的match函数,配对总线上所有的设备(device),如果驱动能够对应处理其中一个设备,函数返回1,告诉内核配对成功。
一般的,match函数是判断设备的结构体成员device->bus_id和驱动函数的结构体成员device_driver->name是否一致,如果一致,那就表明配对成功。
2,int (*probe)(struct device *dev);---- 驱动driver
当配对(match)成功后,内核就会调用指定驱动中的probe函数来查询设备能否被该驱动操作,如果可以,驱动就会对该设备进行相应的操作,如初始化。所以说,真正的驱动函数入口是在probe函数中。
3, int (*remove) (struct device *dev); ---驱动driver
当设备从总线中移除时,内核会调用驱动函数中的remove函数调用,进行一些设备卸载相应的操作