• Linux驱动开发7---设备驱动模型的三大组件


    一 设备驱动模型三个重要组件

    总线 设备 驱动

    1.1 总线

    1.总线是物理总线和的抽象,虚拟总线的描述
    2.设备驱动模型中驱动程序依附在总线上

    1.2 三者之间的联系

    在上一节说到sys下每一个目录都由kobject映射
    sys目录下有一个bus目录,所有总线都保存在bus下,一般一个总线目录下都会有一些设备目录和驱动目录(kobject)以及一些总线属性文件(ktype)

    设备目录中包含挂接在该总线上的设备
    驱动目录包含挂接在该总线上的驱动程序,都是使用链表去组织
    设备和驱动程序之间通过指针相互联系
    在这里插入图片描述

    1.3 描述总线的数据结构bus_type

    在设备驱动模型中 总线使用bus_type描述。只要有一条新总线,就需要由bus_type结构实例化出一个对象出来:

    源码地址:/include/linux/device/bus.h

    name对应总线的名称
    bus_attrs, dev_attrs drv_attrs对应则上一节中的attribute类型的变量,与他类似,但是包含了更定制化的信息。
    probe ---- 探测设备函数
    match ----匹配函数,检验参数 2 中的驱动是否支持参数 1 中的设备
    uevent,remove,suspend,resume都是电源管理相关的函数

    在linux系统中电源管理一直都是非常重要的部分 省电模式模式下系统的设备以一定的先后顺序挂起
    全速工作模式下系统中的设备以一定的先后顺序恢复运行 一条总线上所有设备都挂起时总线才会挂起 一条总线上有任意一个设备要恢复之前总线必须恢复
    由于这个管理功能对于大多模块都是必须的,所以将他抽象到更深的层次上

    dev_pm_ops *pm是关于电源管理的操作符
    bus_type_private表示总线私有数据

    struct bus_type {
    	const char		*name;
    	const char		*dev_name;
    	struct device		*dev_root;
    	const struct attribute_group **bus_groups;
    	const struct attribute_group **dev_groups;
    	const struct attribute_group **drv_groups;
    
    	int (*match)(struct device *dev, struct device_driver *drv);
    	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    	int (*probe)(struct device *dev);
    	void (*sync_state)(struct device *dev);
    	void (*remove)(struct device *dev);
    	void (*shutdown)(struct device *dev);
    
    	int (*online)(struct device *dev);
    	int (*offline)(struct device *dev);
    
    	int (*suspend)(struct device *dev, pm_message_t state);
    	int (*resume)(struct device *dev);
    
    	int (*num_vf)(struct device *dev);
    
    	int (*dma_configure)(struct device *dev);
    
    	const struct dev_pm_ops *pm;
    
    	const struct iommu_ops *iommu_ops;
    
    	struct subsys_private *p;
    	struct lock_class_key lock_key;
    
    	bool need_parent_lock;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    使用bus_type实例化对象时,就是对物理总线进行抽象,也是对虚拟总线进行描述的过程
    (大名鼎鼎的platform平台设备总线就是虚拟总线,往后会介绍)
    bus_type的实例化十分简单,因为有很多成员使用不到,ac97声卡的总线定义:

    struct bus_type ac97_bus_type = {
    .name = "ac97",
    .match = ac97_bus_match,
    #ifdef CONFIG_PM
    .suspend = ac97_bus_suspend,
    .resume = ac97_bus_resume,
    #endif /* CONFIG_PM */
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用bus_type_private实例化对象时,最主要的是填写前三个kset变量的信息:
    subsys代表该 bus 子系统,里面的 kobj 是该 bus 的主kobj,也就是最顶层
    drivers_kset指向挂接到该总线上的所有驱动集合
    devices_kset;挂接到该总线上的所有设备集合

    经过对上面两个重要结构体的填写,已经基本具备了总线驱动设备模型的框架
    此时只需要对总线进行注册:bus_register()
    bus_register()函数对 bus_type 进行注册,当从系统中删除一条总线时,应该使用
    bus_unregister()函数。

    int bus_register(struct bus_type *bus)
    {
    int retval; /*返回值*/
    struct bus_type_private *priv; /*总线私有数据*/
    priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
    /*申请一个总线私有数据结构*/
    if (!priv) /*内存不足,返回*/
    return -ENOMEM;
    priv->bus = bus; /*总线私有数据结构回指的总线*/
    bus->p = priv; /*总线的私有数据*/
    BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);/*初始化通知链表*/
    retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
    /*设置总线的名字,例如 PCI*/
    if (retval) /*失败则返回*/
    goto out;
    priv->subsys.kobj.kset = bus_kset;
    /*指向其父 kset,bus_kset 在 buses_init()例程中添加*/
    priv->subsys.kobj.ktype = &bus_ktype; /*设置读取总线属性文件的默认方法*/
    priv->drivers_autoprobe = 1; /*驱动程序注册时,可以探测(probe)设备*/
    retval = kset_register(&priv->subsys); /*注册总线容器 priv->subsys*/
    if (retval) /*失败返回*/
    goto out;
    retval = bus_create_file(bus, &bus_attr_uevent);
    /*建立 uevent 属性文件*/
    if (retval) /**/
    goto bus_uevent_fail;
    /*创建一个 devices_kset 容器。也就是在新的总线目录下创建一个 devices 的目录,其
    父目录就是 priv->subsys.kobj 对应的总线目录*/
    priv->devices_kset = kset_create_and_add("devices", NULL,
    &priv->subsys.kobj);
    if (!priv->devices_kset) { /*创建失败则返回*/
    retval = -ENOMEM;
    goto bus_devices_fail;
    }
    /*创建一个 drivers_kset 容器。也就是在新的总线目录下创建一个 drivers 的目录,其
    父目录就是 priv->subsys.kobj 对应的总线目录*/
    priv->drivers_kset = kset_create_and_add("drivers", NULL,
    &priv->subsys.kobj);
    if (!priv->drivers_kset) { /*创建失败则返回*/
    retval = -ENOMEM;
    goto bus_drivers_fail;
    }
    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_
    put); /*初始化设备链表*/
    klist_init(&priv->klist_drivers, NULL, NULL); /*初始化驱动程序链表*/
    retval = add_probe_files(bus); /*与热插拔相关的探测文件*/
    if (retval)
    goto bus_probe_files_fail;
    retval = bus_add_attrs(bus); /*为总线创建一些属性文件*/
    if (retval)
    goto bus_attrs_fail;
    pr_debug("bus: '%s': registered\n", bus->name);
    return 0;
    /*错误处理*/
    bus_attrs_fail:
    remove_probe_files(bus);
    bus_probe_files_fail:
    kset_unregister(bus->p->drivers_kset);
    bus_drivers_fail:
    kset_unregister(bus->p->devices_kset);
    bus_devices_fail:
    bus_remove_file(bus, &bus_attr_uevent);
    bus_uevent_fail:
    kset_unregister(&bus->p->subsys);
    kfree(bus->p);
    out:
    return retval;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
  • 相关阅读:
    JavaScript基础 JavaScript第二天 1. 运算符
    Nevron Vision for .NET 2023.1 Crack
    一类综合的模糊化自适应滑模控制
    品牌平面设计如何让自己有脑洞大开的创意 优漫动游
    python迭代器
    Python自学知识点
    【蓝桥杯Web】第十三届蓝桥杯(Web 应用开发)省赛真题
    API测试简介
    GAN实战笔记——第三章第一个GAN模型:生成手写数字
    【Java】学习日记 Day22
  • 原文地址:https://blog.csdn.net/weixin_43604927/article/details/125923244