Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。
这个属于分离的思想,将设备和驱动分开管理。
1、bus 总线
总线是处理器和设备之间的通道。总线有多种类型,每种总线可以挂载多个设备。
在设备模型中,所有的设备都通过总线相连,以总线来管理设备和驱动函数。总线有bus_type结构表示。
/*linux/device.h*/
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);
总线属性添加和删除:
设置总线的属性后,会在对应的总线目录下增加了一个新的文件,通过对该文件的读写访问,触发相应的函数操作,从而实现/sys/的文件接口与内核设备模型的数据交互。
struct attribute {
const char *name; //设定该文件的名字
struct module *owner; //设定该文件的属主
mode_t mode; //设定该文件的文件操作权限
};
/*linux/device.h*/
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *bus, char *buf);
ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
};
bus_attribute中有两个函数指针,show和store。
设置总线属性有两个步骤:
1、创建并初始化bus_attribute结构
使用宏BUS_ATTR
BUS_ATTR(_name, _mode, _show, _store)
该宏会定义一个名叫bus_attr__name的bus_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人show和store。
2、将bus_attibute添加到指定的总线上
使用以下调用:
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
该函数失败时返回错误号。
一旦调用该函数,会就在指定bus总线的目录下新建一个名叫_name的文件
2、driver
驱动程序是在CPU运行时,提供操作的软件接口。所有的设备必须有与之配套驱动程序才能正常工作。一个驱动程序可以驱动多个类似或者完全不同的设备。
/*linux/device.h*/
struct device_driver {
const char *name; //驱动函数的名字,在对应总线的driver目录下显示
struct bus_type *bus; //指定该驱动程序所操作的总线类型,必须设置,不然会注册失败
struct module *owner;
const char *mod_name; /* used for built-in modules */
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 attribute_group **groups;
struct dev_pm_ops *pm;
struct driver_private *p;
};
和设备不一样的是,在注册驱动函数是必须指定该驱动函数对应的总线,因为驱动函数注册成功后,会存放在对应总线的driver目录下,如果没有总线,注册当然会失败。
注册驱动
1、定义结构体device_driver。
2、调用注册函数:
int driver_register(struct device_driver *drv)
函数失败返回非零,需要判断返回值来检查注册是否成功。
驱动函数属性:
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *drive