在驱动中创建sysfs接口、procfs接口、debugfs接口

前言

在一些linux开发板中,经常可以看到通过echo的方式来直接控制硬件或者修改驱动,例如:

//灯灭
echo 0 >/sys/class/leds/firefly:blue:power/brightness 
//灯亮
echo 1 >/sys/class/leds/firefly:blue:power/brightness 

这是怎么做到呢?

实际上,这是因为在驱动中提供了sysfs接口给用户使用,使得用户可以通过cat或者echo命令来查看和修改驱动中某些变量的值。

下面介绍驱动中创建sysfs接口的方法

sysfs接口创建

基本步骤:

1、使用DEVICE_ATTR声明一个sys节点

static DEVICE_ATTR(led_status, 0600, led_status_show, led_status_store);

led_status:在sys接口中显示的节点名字

0600:表示操作这个led_status节点的权限

led_status_show:使用cat命令查看sys接口时调用的函数

led_status_store:使用echo命令往sys接口写入内容时调用的函数

2、完成sys节点的读写函数

static unsigned int led = 0;
/*
*  sys节点的读函数
*  执行 cat /sys/devices/platform/leds/led_status时会调用
*/
static ssize_t led_status_show(struct device *dev, struct device_attribute *attr, char *buf)
{//buf是通过cat命令显示到终端的内容,这里显示led变量return sprintf(buf, "%s:%d.\n", "led", led);
}/**
*  sys节点的写函数
*  用echo命令往sys节点写入内容时,会调用该函数
*/
static ssize_t led_status_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{//写入的内容会存放到buf中,这里将buf内容赋值给led变量sscanf(buf, "%d", &led);return count;
}

示例中,led_status_show()函数和led_status_store()函数的作用分为打印led变量的值修改led变量的值.

3、定义struct attributestruct attribute_group数组

static struct attribute *led_attributes[]={/*上述使用了DEVICE_ATTR声明节点名字为led_status,* 则struct attribute名字应为:*  dev_attr_ + (节点名) + .attr* 所以名字为dev_attr_led_status.attr*/&dev_attr_led_status.attr,NULL,
};static const struct attribute_group led_attrs={.attrs = led_attributes,//引用上述struct attribute数组
};

上述使用了DEVICE_ATTR声明节点名字为led_status, 则struct attribute名字应为:dev_attr_ + (节点名) + .attr。所以名字为dev_attr_led_status.attr

4、在probe函数中调用sysfs_create_group()函数注册sysfs接口

完整例子

设备树:

 leds:leds{compatible = "xx,xx-led";};

驱动:

static unsigned int led = 0;static ssize_t led_status_show(struct device *dev, struct device_attribute *attr, char *buf)
{return sprintf(buf, "%s:%d.\n", "led", led);
}static ssize_t led_status_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{sscanf(buf, "%d", &led);return count;
}static DEVICE_ATTR(led_status, 0600, led_status_show, led_status_store);static struct attribute *led_attributes[]={&dev_attr_led_status.attr,NULL,
};static const struct attribute_group led_attrs={.attrs = led_attributes,
};static int xx_led_probe(struct platform_device *pdev)
{sysfs_create_group(&pdev->dev.kobj, &led_attrs);return 0;
}static int xx_led_remove(struct platform_device *pdev)
{sysfs_remove_group(&pdev->dev.kobj, &led_attrs);return 0;
}static const struct of_device_id xx_led_of_match[] = {{.compatible = "xx,xx-led"},
};static struct platform_driver xx_led_driver = {.probe = xx_led_probe,.remove = xx_led_remove,.driver = {.name = "xx-led",.owner = THIS_MODULE,.of_match_table = xx_led_of_match,},
};static int __init xx_led_init(void)
{return platform_driver_register(&xx_led_driver );
}static void __exit xx_led_exit(void)
{platform_driver_unregister(&xx_led_driver);
}module_init(xx_led_init);
module_exit(xx_led_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("xx led driver");
MODULE_AUTHOR("Vincent");
MODULE_VERSION("V1.0.00");

驱动加载后,就可以在linux终端中,使用catecho命令来查看和修改驱动中led变量的值。例如:

at /sys/devices/platform/leds/led_status
led:0.//修改led变量的值为9
echo 9 > /sys/devices/platform/leds/led_status
//查看
cat /sys/devices/platform/leds/led_status
led:9.

上面介绍了Linux驱动中sysfs接口的创建,今天介绍procfs接口的创建。

procfs:可实现类似cat /proc/cpuinfo的操作

procfs接口创建

实现效果:

例如, 在/proc下创建一个clk节点,通过cat /proc/clk可查看内容:

图片

代码实现:

系统内核版本
Linux4.9.88

在驱动中添加以下代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>struct proc_dir_entry *my_proc_entry;static int proc_clk_show(struct seq_file *m, void *v)
{//cat显示的内容seq_printf(m,"pll0: %u Mhz\n""pll1: %u Mhz\n""pll2: %u Mhz\n",100, 200, 300);return 0;
}static int clk_info_open(struct inode *inode, struct file *filp)
{return single_open(filp, proc_clk_show, NULL);
}static struct file_operations myops = 
{.owner = THIS_MODULE,.open = clk_info_open,.read = seq_read,.llseek = seq_lseek,.release = seq_release,
};static int __init my_module_init(void)
{//注册proc接口my_proc_entry = proc_create("clk", 0644, NULL, &myops);return 0;
}static void __exit my_module_exit(void)
{//注销proc接口proc_remove(my_proc_entry);
}module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");

procfs接口的创建,主要是实现struct file_operations结构体,然后通过proc_create函数进行注册,通过proc_remove函数进行注销。

procfs通常是用来获取CPU、内存、进程等各种信息,例如cat /proc/cpuinfocat /proc/meminfo,所以我们只需要实现.open成员函数。当使用cat命令查看/proc下的信息时,会调用到.open对应的实现函数。

这里我们使用了seq_file接口,需要记住的是,procfs通常会和seq_file接口一起使用。seq_file是一个序列文件接口,当我们创建的proc数据内容由一系列数据顺序组合而成或者是比较大的proc文件系统时,都建议使用seq_file接口,例如cat /proc/meminfo就会显示很多内容。

seq_file接口主要就是解决proc接口编程存在的问题,推荐在proc接口编程时使用seq_file接口,另外.read、.llseek、.release成员函数也可以直接用seq_readseq_lseekseq_release

proc新接口

注意,在较新版本的内核中,procfs的函数接口有所变化。

系统内核版本
Linux5.10.111

在驱动中添加以下代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>struct proc_dir_entry *my_proc_entry;static int proc_clk_show(struct seq_file *m, void *v)
{seq_printf(m,"pll0: %lu Mhz\n""pll1: %lu Mhz\n""pll2: %lu Mhz\n",100, 200, 300);return 0;
}static int clk_info_open(struct inode *inode, struct file *filp)
{return single_open(filp, proc_clk_show, NULL);
}static const struct proc_ops clk_stat_proc_fops = {.proc_open = clk_info_open,.proc_read =  seq_read,.proc_lseek = seq_lseek,.proc_release = seq_release,
};static int __init my_module_init(void)
{my_proc_entry = proc_create("clk", 0, NULL, &clk_stat_proc_fops);return 0;
}static void __exit my_module_exit(void)
{proc_remove(my_proc_entry);
}module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");

新的proc接口中,将原来的struct file_operations换成了struct proc_ops,其中成员函数也添加了对应的前缀proc,但本质还是一样的,只是换了名字,更加规范了一些。

 debugfs接口创建

上面介绍了procfs接口的创建,今天再介绍一种debugfs接口的创建。

实现效果

/sys/kernel/debug/目录下创建一个ion/test文件,通过catecho的方式进行读写操作:

图片

图片

前期准备

内核配置打开debugfs:

CONFIG_DEBUG_FS=y

挂载debugfs文件系统:

mount -t debugfs none /sys/kernel/debug

代码实现

读写变量:

#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/types.h>static struct dentry *ion_dir;
static u64 test_u64 = 0;static int __init debugfs_init(void)
{//创建一个/sys/kernel/debug/ion目录ion_dir = debugfs_create_dir("ion", NULL);if (!ion_dir) {printk("ion_dir is null\n");return -1;}/* 创建/sys/kernel/debug/ion/test_u64文件 */debugfs_create_u64("test_u64", 0644,ion_dir, &test_u64);return 0;
}static void __exit debugfs_exit(void)
{debugfs_remove_recursive(ion_dir);
}module_init(debugfs_init);
module_exit(debugfs_exit);
MODULE_LICENSE("GPL");

运行结果:

图片

读写字符串:

#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/dcache.h>
#include <linux/types.h>static char ion_buf[512] = "hello\n";
static struct dentry *ion_dir;static int ion_open(struct inode *inode, struct file *filp)
{//printk("ion open\n");return 0;
}ssize_t ion_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
{int retval = 0;if ((*offp + count) > 512)count = 512 - *offp;if (copy_to_user(buf, ion_buf+*offp, count)) {printk("copy to user failed, count:%ld\n", count);retval = -EFAULT;goto out;}*offp += count;retval = count;
out:return retval;
}ssize_t ion_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{int retval;if (*offp > 512)return 0;if (*offp + count > 512)count = 512 - *offp;if (copy_from_user(ion_buf+*offp, buff, count)) {printk("copy from user failed, count:%ld\n", count);retval = -EFAULT;goto out;}*offp += count;retval = count;
out:return retval;
}struct file_operations my_fops = {.owner = THIS_MODULE,.read = ion_read,.write = ion_write,.open = ion_open,
};static int __init debugfs_init(void)
{printk("INIT MODULE\n");//创建一个/sys/kernel/debug/ion目录ion_dir = debugfs_create_dir("ion", NULL);if (!ion_dir) {printk("ion_dir is null\n");return -1;}/* 创建/sys/kernel/debug/ion/test文件 */struct dentry *filent = debugfs_create_file("test", 0644, ion_dir, NULL, &my_fops);if (!filent) {printk("test file is null\n");return -1;}return 0;
}static void __exit debugfs_exit(void)
{debugfs_remove_recursive(ion_dir);
}module_init(debugfs_init);
module_exit(debugfs_exit);
MODULE_LICENSE("GPL");

运行结果:

图片

函数接口说明

创建目录、文件函数:

/* 创建目录 */
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);/*创建节点 */
struct dentry *debugfs_create_file(const char *name, umode_t mode,struct dentry *parent, void *data,const struct file_operations *fops);

name:要创建的/sys/kernel/debug下的目录名

parent:父目录,用struct dentry结构体表示。如果直接在/sys/kernel/debug/下创建文件,则为NULL

创建不同大小的文件:

//创建十进制的无符号文件
void debugfs_create_u8(const char *name, umode_t mode,struct dentry *parent, u8 *value);
void debugfs_create_u16(const char *name, umode_t mode,struct dentry *parent, u16 *value);
void debugfs_create_u32(const char *name, umode_t mode,struct dentry *parent, u32 *value);
void debugfs_create_u64(const char *name, umode_t mode,struct dentry *parent, u64 *value);
//创建十六进制的无符号文件
void debugfs_create_x8(const char *name, umode_t mode,struct dentry *parent, u8 *value);
void debugfs_create_x16(const char *name, umode_t mode,struct dentry *parent, u16 *value);
void debugfs_create_x32(const char *name, umode_t mode,struct dentry *parent, u32 *value);
void debugfs_create_x64(const char *name, umode_t mode,struct dentry *parent, u64 *value);

更详细的debugfs用法请参考官方文档:Documentation/filesystems/debugfs.txt

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/53833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云原生之使用Docker部署SSCMS内容管理系统

云原生之使用Docker部署SSCMS内容管理系统 一、SSCMS介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载SSCMS镜像五、部署SSCMS内容管理系统5.1 创建SSCMS容器5.2 检查SSC…

汽车电子笔记之:AUTOSAR方法论及基础概念

目录 1、AUTOSAR方法论 2、AUTOSAR的BSW 2.1、MCAL 2.2、ECU抽象层 2.3、服务层 2.4、复杂驱动 3、AUTOSAR的RTE 4、AUTOSAR的应用层 4.1、SWC 4.2、AUTOSAR的通信 4.3、AUTOSAR软件接口 1、AUTOSAR方法论 AUTOSAR为汽车电子软件系统开发过程定义了一套通用的技术方法…

在 macOS 中安装 TensorFlow 1g

tensorflow 需要多大空间 pip install tensorflow pip install tensorflow Looking in indexes: https://pypi.douban.com/simple/ Collecting tensorflowDownloading https://pypi.doubanio.com/packages/1a/c1/9c14df0625836af8ba6628585c6d3c3bf8f1e1101cafa2435eb28a7764…

基于ROS2的消除重力加速度对IMU加速度影响,动态获取当前重力加速度。

IMU的全称是惯性测量单元&#xff0c;包括一个三轴的加速度计以及一个三轴的陀螺仪&#xff0c;分别测量出物体的加速度和角速度信息&#xff0c;不受周围环境结构、光照等外界因素影响。通常IMU的输出频率在100-1000hz之间&#xff0c;远高于相机或者激光雷达的输出频率 消除…

容灾设备系统组成,容灾备份系统组成包括哪些

随着信息技术的快速发展&#xff0c;企业对数据的需求越来越大&#xff0c;数据已经成为企业的核心财产。但是&#xff0c;数据安全性和完整性面临巨大挑战。在这种环境下&#xff0c;容灾备份系统应运而生&#xff0c;成为保证企业数据安全的关键因素。下面我们就详细介绍容灾…

关于JAVA程序的内存分布

目录 1.Java程序运行时内存说明 2.JVM内存划分 3.Java中数据类型 4.Java中的String 5.结合HelloWorld分析java程序内存分布 1.Java程序运行时内存说明 编写的.java程序文件需要java编译器javac转成.class文件&#xff0c;然后通过jvm&#xff08;名为java的可执行程序&…

STM32F103 USB OTA升级BootLoader (一)

1.配置外部高速晶振 2.勾选USB功能 3.将USB模式配置Virtual Port Com 4.将系统主频配置为72M,USB频率配置为48M. 5.配置好项目名称&#xff0c;开发环境&#xff0c;最后获取代码。 6.修改Flash大小和勾选Use Micro LIB 7.修改main.c代码 #include "main.h" #includ…

浏览器安装selenium驱动,以Microsoft Edge安装驱动为例

Selenium是一个用于Web应用程序测试的自动化工具。它可以直接在浏览器中运行&#xff0c;模拟真实用户对浏览器进行操作。利用selenium&#xff0c;可以驱动浏览器执行特定的动作&#xff0c;比如&#xff1a;点击、下拉等等&#xff0c;还可以获取浏览器当前呈现的页面的源代码…

8/26 回溯法 周总结 记录个人的想法

DAY1 77. 组合 这道题是经典的回溯题&#xff0c; 递归函数参数和返回值显而易见 终止条件是path.size()k 递归逻辑&#xff0c;需要理解每次调用回溯的startIndex的含义&#xff0c;图解&#xff1a; DAY2 216. 组合总和 III:这道题与77题作类比&#xff1a; 77&#xff1…

自定义loadbalance实现feignclient的自定义路由

自定义loadbalance实现feignclient的自定义路由 项目背景 服务A有多个同事同时开发&#xff0c;每个同事都在dev或者test环境发布自己的代码&#xff0c;注册到注册中心有好几个(本文nacos为例)&#xff0c;这时候调用feign可能会导致请求到不同分支的服务上面&#xff0c;会…

React(7)

1.React Hooks 使用hooks理由 1. 高阶组件为了复用&#xff0c;导致代码层级复杂 2. 生命周期的复杂 3. 写成functional组件,无状态组件 &#xff0c;因为需要状态&#xff0c;又改成了class,成本高 1.1 useState useState();括号里面处的是初始值&#xff1b;返回的是一个…

【算法系列 | 7】深入解析查找算法之—布隆过滤器

序言 心若有阳光&#xff0c;你便会看见这个世界有那么多美好值得期待和向往。 决定开一个算法专栏&#xff0c;希望能帮助大家很好的了解算法。主要深入解析每个算法&#xff0c;从概念到示例。 我们一起努力&#xff0c;成为更好的自己&#xff01; 今天第3讲&#xff0c;讲一…

stm32之8.中断

&#xff08;Exceptions&#xff09;异常是导致程序流更改的事件&#xff0c;发生这种情况&#xff0c;处理器将挂起当前执行的任务&#xff0c;并执行程序的一部分&#xff0c;称之为异常处理函数。在完成异常处理程序的执行之后&#xff0c;处理器将恢复正常的程序执行&#…

python+TensorFlow实现人脸识别智能小程序的项目(包含TensorFlow版本与Pytorch版本)

pythonTensorFlow实现人脸识别智能小程序的项目&#xff08;包含TensorFlow版本与Pytorch版本&#xff09; 一&#xff1a;TensorFlow基础知识内容部分&#xff08;简明扼要&#xff0c;快速适应&#xff09;1、下载Cifar10数据集&#xff0c;并进行解压缩处理2、将Cifar10数据…

WebSocket详解以及应用

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;websocket、网络、长连接、前端☀️每日 一言&#xff1a;任何一个你不喜欢而又离不开的地方&#xff0c;任何一种你不喜欢而又无法摆脱的生活&#xff0c;都是监狱&#xff01; 一、前言 我们在…

C#-集合小例子

目录 背景&#xff1a; 过程: 1.添加1-100数: 2.求和: 3.平均值: 4.代码:​ 总结: 背景&#xff1a; 往集合里面添加100个数&#xff0c;首先得有ArrayList导入命名空间&#xff0c;这个例子分为3步&#xff0c;1.添加1-100个数2.进行1-100之间的总和3.求总和的平均值&…

如何把本地项目上传github

一、在gitHub上创建新项目 【1】点击添加&#xff08;&#xff09;-->New repository 【2】填写新项目的配置项 Repository name&#xff1a;项目名称 Description &#xff1a;项目的描述 Choose a license&#xff1a;license 【3】点击确定&#xff0c;项目已在githu…

数据结构数组栈的实现

Hello&#xff0c;今天我们来实现一下数组栈&#xff0c;学完这个我们又更进一步了。 一、栈 栈的概念 栈是一种特殊的线性表&#xff0c;它只允许在固定的一端进行插入和删除元素的操作。 进行数据的插入和删除只在栈顶实现&#xff0c;另一端就是栈底。 栈的元素是后进先出。…

四川玖璨电商:2023怎样运营短视频?

​短视频的兴起和流行让越来越多的人关注和运营短视频号。如何运营短视频号&#xff0c;吸引更多的观众和粉丝&#xff1f;下面四川玖璨电商小编将介绍几个关键点。 首先&#xff0c;确定短视频的定位和主题非常重要。根据自己的兴趣和特长&#xff0c;确定一个独特的主题&…

Diffusion Models for Image Restoration and Enhancement – A Comprehensive Survey

图像恢复与增强的扩散模型综述 论文链接&#xff1a;https://arxiv.org/abs/2308.09388 项目地址&#xff1a;https://github.com/lixinustc/Awesome-diffusion-model-for-image-processing/ Abstract 图像恢复(IR)一直是低水平视觉领域不可或缺的一项具有挑战性的任务&…