• [21天学习挑战赛——内核笔记](九)——sysfs相关API



    活动地址:CSDN21天学习挑战赛

    学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
    想系统/深入学习某技术知识点…
    一个人摸索学习很难坚持,想组团高效学习…
    想写博客但无从下手,急需写作干货注入能量…
    热爱写作,愿意让自己成为更好的人…

    一、什么是sysfs?

    Sysfs 是Linux 2.6所提供的一种虚拟文件系统。这个文件系统不仅可以把设备(devices)驱动程序(drivers)的信息从内核输出到用户空间,也可以用来对设备和驱动程序做设置。
    简单的说,sysfs是一个基于内存的
    文件系统
    ,它的作用是将内核信息以文件的方式提供给用户程序使用。

    sysfs 给应用程序提供了统一访问设备的接口,但可以看到, sysfs 仅仅是提供了一个可以统一访问设备的框架,但究竟是否支持 sysfs 还需要各设备驱动程序的编程支持;在 2.6 内核 诞 生 5年以来的发展中,很多子系统、设备驱动程序逐渐转向了 sysfs 作为与用户空间友好的接口,但仍然也存在大量的代码还在使用旧的 proc 或虚拟字符设备的 ioctl 方式;如果仅从最终用户的角度来说, sysfs 与 proc 都是在提供相同或类似的功能,对于旧的 proc 代码,没有绝对的必要去做 proc 至 sysfs 的升级;

    二、注册流程

    /sys/bus:该目录包含linux下的总线设备,每个子目录下主要包含两个目录:device和driver.

    Linux 设备总线驱动模型

    在这里插入图片描述
    简单来说,bus 负责维护 注册进来的devcie 与 driver ,每注册进来一个device 或者 driver 都会调用 Bus->match 函数 将device 与 driver 进行配对,并将它们加入链表,如果配对成功,调用Bus->probe或者driver->probe函数, 调用 kobject_uevent 函数设置环境变量,mdev进行创建设备节点等操作。后面,我们从 Bus driver 到 device三个部分进行详细的分析。
    在这里插入图片描述
    这张图也可以直观看出,系统启动到再到驱动的注册,也很直观

    三、bus_register

    kzalloc ----> subsys. private空间
    kobjetset name ----> 设置bus名到kobjet
    kset register ----> 在/5y/bus下创建kobjet目录及ttribute文件
    bus_ create. file ----> 创建ueven文件
    kset reate. and add ----> 创建5y/s/ox/device8录
    kset _create and add ----> 创建5/s/0o/driver目录
    add probe files ----> 创建drivers. probe及drivers _autoprobe文件
    bus. add groups ----> 创建bus->bus. group属性文件
    那么bus_register 函数处理的工作有哪些呢,博主在网上找了一下解释,写的挺好,如下:

    1、将 Bus 与 priv 相互建立联系
    2、BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
    3、设置 bus->priv->subsys(kset).kobj 的名字为 bus->name
    4、设置 bus->priv->subsys(kset).kobj.kset 指向 bus_kset
    5、设置 bus->priv->subsys(kset).kobj.ktype 为 bus_ktype ,提供 show store 函数
    6、设置 bus->priv->drivers_autoprobe = 1;
    7、注册 bus->priv->subsys(kset) 对应于图中④与⑥的关系
    由于4,且没有指定bus->priv->subsys(kset).kobj.Parent,会将 bus_kest.kobj 设置为 bus->priv->subsys(kset).kobj.Parent 因此,会将bus->priv->subsys(kset).kobj.entry 加入 bus_kest 链表,且会在/sys/bus目录下创建相应的总线目录/sys/bus/ ( b u s − > n a m e ) ,例如 / s y s / b u s / p l a t f o r m 8 、创建 b u s a t t r u e v e n t − > a t t r 属性文件 9 、创建并注册 d e v i c e s k s e t , d e v i c e s k s e t . k o b j . p a r e n t = b u s − > p r i v − > s u b s y s . k o b j , 名字为 d e v i c e ,因此会创建 / s y s / b u s / (bus->name),例如 /sys/bus/platform 8、创建 bus_attr_uevent->attr 属性文件 9、创建并注册 devices_kset ,devices_kset.kobj.parent = bus->priv->subsys.kobj ,名字为 device ,因此会创建 /sys/bus/ (bus>name),例如/sys/bus/platform8、创建busattruevent>attr属性文件9、创建并注册devicesksetdeviceskset.kobj.parent=bus>priv>subsys.kobj,名字为device,因此会创建/sys/bus/(bus->name)/devices
    10、创建并注册 drivers_kset ,drivers_kset.kobj.parent = bus->priv->subsys.kobj ,名字为 drivers ,因此会创建 /sys/bus/$(bus->name)/drivers
    11、初始化 bus->priv->klist_devices 链表
    12、初始化 bus->priv->klist_drivers 链表
    13、创建 bus->bus_attrs 属性文件

    原码如下

    int bus_register(struct bus_type *bus)
    {
    	int retval;
    	struct bus_type_private *priv;
     
    	priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
    /* 1. bus 与 prv 相互建立联系 */
    	// 私有数据 .bus ->  bus 本身
    	priv->bus = bus;
    	// bus->p 指向 priv
    	bus->p = priv;
    	// 内核通知链
    	BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
     
    /* 设置 bus->prv->subsys->kobj */
    	// 设置 priv->subsys.kobj.name = bus->name  对应于/sys/ 目录下的目录名
    	retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
    	// 所有的 priv->subsys.kobj.kset 指向 bus_kse 对应于图中④与六的关系
    	priv->subsys.kobj.kset = bus_kset;
    	// 所有的priv->subsys.kobj.ktype 等于 bus_ktype
    	priv->subsys.kobj.ktype = &bus_ktype;
    	
    	priv->drivers_autoprobe = 1;
    	
    /* 注册 kset (bus->prv->subsys priv->devices_kset priv->drivers_kset) */	
    	// 注册 priv->subsys ,由于 priv->subsys.kobj.kset = bus_kset,所以会在 /sys/bus/目录下创建 目录 如/sys/bus/plateform
    	retval = kset_register(&priv->subsys);
    	// sysfs_create_file(&bus->p->subsys.kobj, &bus_attr_uevent->attr);
    	retval = bus_create_file(bus, &bus_attr_uevent);
     
    	// 由于 priv->subsys.kobj.kset = bus_kset ,因此会创建 /sys/bus/XXX/devices 目录 如 /sys/bus/plateform/devices
    	priv->devices_kset = kset_create_and_add("devices", NULL,
    						 &priv->subsys.kobj);
    	// 同理 创建 /sys/bus/XXX/devices 目录 如 /sys/bus/plateform/drivers
    	priv->drivers_kset = kset_create_and_add("drivers", NULL,
    						 &priv->subsys.kobj);
    	// 初始化 klist_devices 并设置get put 函数  初始化 klist_drivers 不知为何没有get put ?
    	klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
    	klist_init(&priv->klist_drivers, NULL, NULL);
     
    	retval = add_probe_files(bus);  // static inline int add_probe_files(struct bus_type *bus) { return 0; }
    	// 添加 bus->attrs 属性文件
    	retval = bus_add_attrs(bus);
     
    	return 0;
     
    }
    
    • 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

    四、注册以致用(probe)

    通过上文的注册
    在这里插入图片描述
    通过这张图可以看出,驱动和设备需要进行match进行匹配,如果没有成功匹配到,则适用所有设备

    参考文章
    RK3399平台开发系列讲解(设备管理篇)sysfs相关API详解 - 视频介绍
    sysfs 文件系统
    Linux 设备总线驱动模型

  • 相关阅读:
    FPGA与单片机有什么区别?
    Windows环境Redis使用AOF持久化,无法生成AOF文件,生成后无法加载AOF文件内容
    【FPGA】正确处理设计优先级--或许能帮你节省50%的资源
    1688API接口,获取商品详情,按关键词搜索,拍立淘,商品评论商品类目,店铺接口等
    【解决方案】共享打印机连接报错0x0000011b解决方法
    【算法leetcode】1837. K 进制表示下的各位数字总和(rust和go是真的好用)
    Framework之旅 -- 后台Recent基础扫盲篇
    MySQl索引
    ESP32下的ble数据notify收发(支持ESP-IDF4.4\ESPIDF5.1)
    安卓备份分区----手动查询安卓系统分区信息 导出系统分区的一些基本操作
  • 原文地址:https://blog.csdn.net/m0_52592798/article/details/126433352