[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;
 
}

四、注册以致用(probe)

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周末不下雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值