好的,我们来深入讲解 sysfs 文件系统。它与 proc文件系统密切相关,但在设计目的和使用方式上有显著区别。
简单来说,sysfs是一个基于内存的虚拟文件系统,它在用户空间和内核空间之间提供了一个结构化的、清晰的接口,主要用于导出内核设备模型的各个部分——即系统中的总线、设备、驱动以及它们的相互关系。
如果说 proc是内核的“杂乱的控制面板”,那么 sysfs就是一份“井然有序的设备清单和关系图”。
导出内核设备模型,展示总线、设备、驱动的层次结构和关系。
1、导出内核设备模型
sysfs将设备模型以一种人类可读的层次化目录结构呈现出来。
sysfs清晰地展示了“哪个驱动绑定到了哪个设备”、“设备挂在了哪条总线上”这样的关系。
2、提供统一的设备属性接口
3、与 udev协同工作,实现动态设备管理
sysfs的布局与关键目录 (/sys)
sysfs通常挂载在 /sys目录下。其主要子目录有:
/sys/block/:包含所有块设备(如硬盘、分区)的符号链接。
/sys/bus/:按总线类型组织的目录。这是理解设备关系的关键。
pci/, usb/, i2c/, spi/等。
进入 pci0000:00/(一个PCI总线实例),你会看到 devices/和 drivers/两个目录。
devices/下的目录名是内核内部的设备名(如 0000:00:02.0),它是一个符号链接,指向 /sys/devices/...下的实际设备目录。
drivers/下是每个已加载的PCI驱动程序的目录(如 i915显卡驱动)。
/sys/class/:按设备功能组织的目录。这是用户最常与之交互的部分,它跨越了总线的界限。
input/:所有输入设备(鼠标、键盘、触摸屏),你可以在这里找到 mouseX, eventY。
net/:所有网络设备(eth0, wlan0)。
tty/:所有终端和伪终端设备。
leds/:所有LED指示灯。
power_supply/:所有电源设备(电池、交流适配器)。
进入 net/下的某个网卡目录,你会发现 address(MAC地址)、operstate(运行状态)等属性文件。
/sys/devices/:所有设备在系统全局设备树中的物理位置。这里的目录结构是内核看到的真实硬件拓扑结构,非常复杂。其他目录(如 /sys/bus/pci/devices/)下的符号链接最终都指向这里。
/sys/firmware/:包含系统固件相关的信息,如 ACPI 表、设备树(Device Tree)等。
/sys/module/:包含已加载的内核模块的信息。
/sys/power/:用于控制系统的电源状态,如休眠和唤醒。你可以向 state文件写入 mem(挂起到内存)或 disk(挂起到磁盘)来触发休眠。
作用:
建立系统中总线、驱动、设备三者之间的联系
向用户空间展示内核中各种设备的拓扑图
提供给用户空间对设备获取信息和操作的接口,取代 ioctl 的部分功能
(99+ 封私信 / 51 条消息) linux设备驱动程序--sysfs用户接口的使用 - 知乎
sysfs 虚拟文件系统,。
sys
block:
bus:
platform
class:
dev:
sysfs文件系统
四个基本结构
目录组织结构
Linux统一设备模型:/sys/bus、/sys/class、
class_create
函数功能:在/sys/class生成一个目录,目录名由name指定
函数原型:struct class *class_create(struct module *owner, const char *name);
函数参数:
- *owner:THIS_MODULE
- *name:目录名
函数返回值:
- 成功:class指针
- 失败:NULL对于class是否创建成功,可以使用IS_ERR宏来判断
辅助接口:可以定义一个struct class 的指针变量cls来接受返回值,然后通过IS_ERR(cls)判断是否失败;
IS_ERR(cls);成功----------------->0
IS_ERR(cls);失败----------------->非0
PTR_ERR(cls);来获得失败的返回错误码;
*/class_destroy
函数功能:删除class_create生成目录
函数原型:void class_destroy(struct class *cls)
函数参数:
- cls:class指针
返回值:device_create
函数功能:在/sys/class目录下class_create生成目录再生成一个子目录与该设备相对应,发uevent让应用程序udevd创建设备文件
函数原型:struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)
函数参数:
- *class:class指针
- parent:父对象,一般NULL
- devt:设备号
- *drvdata:驱动私有数据,一般NULL
- *fmt:字符串的格式(这里重新看下视频)
- ...:不定参数
函数返回值:
- 成功:device指针
- 失败:NULLdevice_destroy
函数功能:删除device_create生成目录
函数原型:void device_destroy(struct class *class, dev_t devt)
函数参数:
- *class:class指针
- devt:设备号
函数返回值:
- struct class *class_create(struct module *owner, const char *name);
/*
* 功能:在/sys/class生成一个目录,目录名由name指定
* 参数:
struct module *owner - THIS_MODULE
const char *name - 目录名
* 返回值 成功:class指针 失败:NULL
*/
/*
辅助接口:可以定义一个struct class 的指针变量cls来接受返回值,然后通过IS_ERR(cls)判断是否失败;
IS_ERR(cls);成功----------------->0
IS_ERR(cls);失败----------------->非0
PTR_ERR(cls);来获得失败的返回错误码;
*/void class_destroy(struct class *cls)
/*
* 功能:删除class_create生成目录
* 参数:
struct class *cls - class指针
* 返回值
*/struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
/*
* 功能:在/sys/class目录下class_create生成目录再生成一个子目录与该设备相对应,发uevent让应用程序udevd创建设备文件
* 参数:
struct class *class - class指针
struct device *parent - 父对象,一般NULL
dev_t devt - 设备号
void *drvdata - 驱动私有数据,一般NULL
const char *fmt - 字符串的格式
... - 不定参数
* 返回值
成功:device指针
失败:NULL
*/void device_destroy(struct class *class, dev_t devt)
/*
* 功能:删除device_create生成目录
* 参数:
struct class *class - class指针
dev_t devt - 设备号
* 返回值
*/#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
int major = 12;
int minor = 0;
int dev_num = 1;
struct mychar_dev
{
struct cdev mydev;
struct class *pcls;
struct device *pdev;
};
struct mychar_dev gmydev;
int __init mychar_init(void)
{
int ret = 0;
dev_t devno = MKDEV(major, minor);
/* 获取设备号 */
ret = register_chrdev_region(devno, dev_num, "mychardev");
if (ret)
{
ret = alloc_chrdev_region(&devno, minor, dev_num, "mychardev");
if (ret)
{
printk("get devno failed\n");
return -1;
}
major = MAJOR(devno);
}
/* 注册驱动 */
cdev_init(&gmydev.mydev, &myops);
gmydev.mydev.owner = THIS_MODULE;
cdev_add(&gmydev.mydev, devno, dev_num);
/* 在/sys/class下创建类目录,目录名为第二个参数 */
gmydev.pcls = class_create(THIS_MODULE, "mychar");
if (IS_ERR(gmydev.pcls))
{
cdev_del(&gmydev.mydev);
unregister_chrdev_region(devno, dev_num);
return -1;
}
/* 在上面的类目录下创建设备 */
gmydev.pdev = device_create(gmydev.pcls, NULL, devno, NULL, "mychar");
if (NULL == gmydev.pdev)
{
class_destroy(gmydev.pcls);
cdev_del(&gmydev.mydev);
unregister_chrdev_region(devno, dev_num);
return -1;
}
return 0;
}
void __exit mychar_exit(void)
{
dev_t devno = MKDEV(major, minor);
device_destroy(gmydev.pcls, devno);
class_destroy(gmydev.pcls);
cdev_del(&gmydev.mydev);
unregister_chrdev_region(devno, dev_num);
}