文章目录
该系列文章阅读顺序:
- linux驱动-设备驱动模型(属性文件 kobject )
- linux驱动-设备驱动模型(kset)
- linux驱动-设备驱动模型(bus总线)
- linux驱动-设备驱动模型(device设备)
- linux驱动-设备驱动模型(driver驱动)
- linux驱动-设备驱动模型(class类)
- linux驱动-设备驱动模型(platform设备)
Linux设备模型用 Driver 抽象硬件设备的驱动程序,它包含设备初始化、电源管理相关的接口实现。而Linux内核中的驱动开发,基本都围绕该抽象进行(实现所规定的接口函数)。
作者: baron
1、数据结构
1) device_driver
struct device_driver {
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 */
enum probe_type probe_type;
const struct of_device_id *of_match_table; //用设备树匹配时,用于匹配设备
const struct acpi_device_id *acpi_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);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p; //保存相关链表,也保存了kobj
};
2) driver_private
struct driver_private {
struct kobject kobj; // 用于创建 driver 所在目录
struct klist klist_devices; // 用于链接匹配到的设备
struct klist_node knode_bus; // 链接到bus->p->klist_drivers
struct module_kobject *mkobj;
struct device_driver *driver; // 指向该结构的拥有者
};
2、driver的注册
相较于device的注册,driver的注册就比较简单
- 在总线上查找drv,判断drv是否已经注册进bus,防止重复注册
- 调用bus_add_driver将drv注册进入bus
- 创建属性文件 drv->groups
- 向上层发送uevent事件,KOBJ_ADD
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
//在总线上查找drv,判断drv是否已经注册进bus,防止重复注册
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
//调用bus_add_driver将drv注册进入bus
ret = bus_add_driver(drv);
if (ret)
return ret;
//创建属性文件 drv->groups
ret = driver_add_groups(drv, drv->groups);
if (ret) {
bus_remove_driver(drv);
return ret;
}
//向上层发送uevent事件,KOBJ_ADD
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
return ret;
}
bus_add_driver
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
//初始化klist_devices
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset; //初始化kest
// 由于没有设置 parent 因此使用 bus->p->drivers_kset 做父节点,并在这里创建drv目录,
// 从这里可以知道drv的根目录为 /sys/bus/drv->bus/drivers/
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
//将priv->knode_bus 链接进入priv->bus->p->klist_drivers
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
//判断是否可以自动probe,如果可以,则遍历klist_devices,对其中的每一个dev都调用drv->bus->match(dev, drv)函数
if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else
error = driver_attach(drv);
if (error)
goto out_unregister;
}
}
module_add_driver(drv->owner, drv);
//在drv所在目录创建属性文件 uevent
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
//在drv所在目录创建属性文件 drv_groups
error = driver_add_groups(drv, bus->drv_groups);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
__func__, drv->name);
}
//如果支持 bind 则在 drv 所在目录创建属性文件 bind 和 unbind
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
return 0;
out_unregister:
kobject_put(&priv->kobj);
/* drv->p is freed in driver_release() */
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
3、driver_register 总结
1) 在sys/创建对应节点
bus_add_driver 会创建下面节点
/sys/bus/xxx/drivers/drv->name
/sys/bus/xxx/drivers/drv->name/uevent
/* 支持 suppress_bind_attrs */
/sys/bus/xxx/drivers/drv->name/unbind
/sys/bus/xxx/drivers/drv->name/bind
2) 匹配 bus 总线上的设备
除了创建节点之外,如果可以自动 probe ,如果可以,则遍历 klist_devices,对其中的每一个 dev 都调用 drv->bus->match(dev, drv)
函数,如果匹配成功则调用 really_probe(drv) ,在这个函数中默认先调用函数 dev->bus->probe(dev)
,如果没有设置 dev->bus->probe
函数,则调用该函数,调用流程如下
bus_add_driver---->
driver_attach----> 无论如何最终都会调用这个函数
bus_for_each_dev---->
__driver_attach---->
driver_match_device---->
drv->bus->match(dev, drv) //如果匹配成功则调用 really_probe
really_probe---->
dev->bus->probe(dev) //默认调用这个
drv->probe(dev) //如果没有设置 dev->bus->probe 函数,则调用这个
4、注册我们自己的驱动
在我们创建的 bus 上注册我们自己的驱动
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
MODULE_AUTHOR("baron");
MODULE_LICENSE("GPL");
extern struct bus_type my_bus;
int my_drv_probe(struct device *dev)
{
printk("my_drv_probe\n");
return 0;
}
int my_drv_remove(struct device *dev)
{
printk("my_drv_remove\n");
return 0;
}
struct device_driver my_drv = {
.name = "my_drv",
.bus = &my_bus,
.probe = my_drv_probe,
.remove = my_drv_remove,
};
static int my_drv_init(void)
{
driver_register(&my_drv);
return 0;
}
static void my_drv_exit(void)
{
driver_unregister(&my_drv);
}
module_init(my_drv_init);
module_exit(my_drv_exit);
验证结果
XF-X2:/sys/bus/my_bus/drivers # ls
XF-X2:/sys/bus/my_bus/drivers #
XF-X2:/sys/bus/my_bus/drivers # insmod /cache/my
my_bus.ko my_device.ko my_driver.ko
XF-X2:/sys/bus/my_bus/drivers # insmod /cache/my_driver.ko
XF-X2:/sys/bus/my_bus/drivers # ls
my_drv
XF-X2:/sys/bus/my_bus/drivers #
XF-X2:/sys/bus/my_bus/drivers # cd my_drv/
XF-X2:/sys/bus/my_bus/drivers/my_drv # ls
bind uevent unbind
5、在driver目录下创建属性文件
和前面的 device 下创建属性文件相同,这里只给接口不再赘述
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);
};
#define DRIVER_ATTR(_name, _mode, _show, _store) \
struct driver_attribute driver_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define DRIVER_ATTR_RW(_name) \
struct driver_attribute driver_attr_##_name = __ATTR_RW(_name)
#define DRIVER_ATTR_RO(_name) \
struct driver_attribute driver_attr_##_name = __ATTR_RO(_name)
#define DRIVER_ATTR_WO(_name) \
struct driver_attribute driver_attr_##_name = __ATTR_WO(_name)
//用于在当前 driver 下创建属性文件
extern int __must_check driver_create_file(struct device_driver *driver, const struct driver_attribute *attr);
//删除属性文件
extern void driver_remove_file(struct device_driver *driver, const struct driver_attribute *attr);