Linux用户与内核空间交互—sysfs
目录
简介
一、sysfs
1、/sys 目录
2、API
3、platform API
4、创建platform总线设备文件
二、程序源码
简介
用户空间与内核的交互方式,使用copy_from_user(), copy_to_user().
除了这两种交互方式,内核还提供了其他高级的方式,对于写驱动来说很重要。有proc、sysfs、debugfs、netlink、ioctl。
本文学习sysfs
一、sysfs
2.6内核版本有个关键的特性叫 现代设备模型,所有的设备以类似与树形的数据结构呈现。
1、/sys 目录
在ubuntu系统上的/sys目录
root@ubuntu:/sys# ls
block bus class dev devices firmware fs hypervisor kernel module power
sysfs树包括以下内容:
- 每个总线都在系统中体现(也可以是虚拟或伪总线)
- 每个设备在每条总线上体现
- 在总线上,每个设备驱动绑定到一个设备
可以通过它支持的各种总线(PCI、USB、platform、I2C、SPI等)、各种设备、设备本身、块设备视口等来查看系统
2、API
device_create_file()
struct device 存在数据结构 platform_device, pci_device, net_device, usb_device, i2c_client, serial_port 中
有的驱动中没有struct device,则使用platform bus
接着看一下platform设备
platform设备在Soc嵌入式板子中经常用于表示各种各样的设备
# ls /sys/devices/platform/
alarmtimer 'Fixed MDIO bus.0' intel_pmc_core.0 platform-framebuffer.0
reg-dummy
serial8250 eisa.0 i8042 pcspkr power rtc_cmos uevent
3、platform API
platform_device_register_simple()
platform_device_unregister(sysfs_demo_platdev)
4、创建platform总线设备文件
int device_create_file(struct device *dev, const struct device_attribute *attr);
第二个参数
// interface for exporting device attributes
struct device_attribute {struct attribute attr;ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);ssize_t (*store)(struct device *dev, struct device_attribute *attr,const char *buf, size_t count);
};
导出设备属性的接口,不要再使用copy_[from/to]_user,参数buf是内核空间的buf
show是读回调,store是写回调
初始化device_attribute 结构体,内核提供了几个宏
DEVICE_ATTR(),__ATTR(),DEVICE_ATTR_RW
#define DEVICE_ATTR_RW(_name) \struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)#define __ATTR(_name, _mode, _show, _store) { \.attr = {.name = __stringify(_name), \.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \.show = _show, \.store = _store, \
}
通过上述代码,可以创建read-write (RW), read-only (RO), or write-only (WO) sysfs文件
如 static DEVICE_ATTR_RW(sysfs_debug_level); 初始化后的回调函数是 dev_attr_sysfs_debug_level
5、sysfs总结
设置、显示内核特定的值,每个sysfs文件一个值,不太适合debug大量的输出文件。调试输出需要使用debugfs。
二、程序源码
1、创建platform 总线
2、创建两个sysfs文件,sysfs_debug_level可以读写,sysfs_pressure只读
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>// copy_[to|from]_user()
#include <linux/version.h>
#include <linux/uaccess.h>MODULE_AUTHOR("wy");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_VERSION("0.1");//创建的sysfs文件夹
#define OURMODNAME "sysfs_simple_intf"
//文件夹下的文件
#define SYSFS_FILE1 sysfs_debug_level
#define SYSFS_FILE3 sysfs_pressure//互斥体
static DEFINE_MUTEX(mtx);//全局的静态参数
static int debug_level;
static u32 gpressure;static struct platform_device *sysfs_demo_platdev;//回调函数 pressure
static ssize_t sysfs_pressure_show(struct device *dev,struct device_attribute *attr, char *buf)
{int n;//互斥体if (mutex_lock_interruptible(&mtx))return -ERESTARTSYS;pr_debug("In the 'show' method: pressure=%u\n", gpressure);//将gpressure的值存到buf中n = snprintf(buf, 25, "%u", gpressure);mutex_unlock(&mtx);return n;
}
//属性生命sysfs_process
static DEVICE_ATTR_RO(sysfs_pressure);
//debug_level的参数范围
#define DEBUG_LEVEL_MIN 0
#define DEBUG_LEVEL_MAX 2//读取debug_level
static ssize_t sysfs_debug_level_show(struct device *dev,struct device_attribute *attr,char *buf)
{int n;if (mutex_lock_interruptible(&mtx))return -ERESTARTSYS;//debug_level值n = snprintf(buf, 25, "%d\n", debug_level);mutex_unlock(&mtx);return n;
}
//写debug_level
static ssize_t sysfs_debug_level_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{int ret = (int)count, prev_dbglevel;if (mutex_lock_interruptible(&mtx))return -ERESTARTSYS;//保存debug_levelprev_dbglevel = debug_level;if (count == 0 || count > 12) {ret = -EINVAL;goto out;}//将字符串的值 转化为int类型ret = kstrtoint(buf, 0, &debug_level); if (ret)goto out;//验证if (debug_level < DEBUG_LEVEL_MIN || debug_level > DEBUG_LEVEL_MAX) {debug_level = prev_dbglevel;ret = -EFAULT;goto out;}ret = count;out:mutex_unlock(&mtx);return ret;
}static DEVICE_ATTR_RW(sysfs_debug_level); //初始化
static int __init sysfs_simple_intf_init(void)
{int stat = 0;//检查系统有没有配置SYSFSif (unlikely(!IS_ENABLED(CONFIG_SYSFS))) {pr_warn("sysfs unsupported! Aborting ...\n");return -EINVAL;}#define PLAT_NAME "sysfs_simple_intf_device"//创建platform总线下的文件sysfs_demo_platdev = platform_device_register_simple(PLAT_NAME, -1, NULL, 0);//错误验证if (IS_ERR(sysfs_demo_platdev)) {stat = PTR_ERR(sysfs_demo_platdev);pr_info("error (%d) registering our platform device, aborting\n", stat);goto out1;}//创建文件debug_levelstat = device_create_file(&sysfs_demo_platdev->dev, &dev_attr_sysfs_debug_level);if (stat) {pr_info("device_create_file [1] failed (%d), aborting now\n", stat);goto out2;}//创建文件gpressuregpressure = 25; stat = device_create_file(&sysfs_demo_platdev->dev, &dev_attr_sysfs_pressure);if (stat) {pr_info("device_create_file [3] failed (%d), aborting now\n", stat);goto out3;}return 0;out3:device_remove_file(&sysfs_demo_platdev->dev,&dev_attr_sysfs_pressure);device_remove_file(&sysfs_demo_platdev->dev, &dev_attr_sysfs_debug_level);out2:platform_device_unregister(sysfs_demo_platdev);out1:return stat;
}//删除
static void __exit sysfs_simple_intf_cleanup(void)
{device_remove_file(&sysfs_demo_platdev->dev, &dev_attr_sysfs_pressure);device_remove_file(&sysfs_demo_platdev->dev, &dev_attr_sysfs_debug_level);platform_device_unregister(sysfs_demo_platdev);
}module_init(sysfs_simple_intf_init);
module_exit(sysfs_simple_intf_cleanup);
程序输出
#:/sys/devices/platform/sysfs_simple_intf_device# cat sysfs_pressure
25#:/sys/devices/platform/sysfs_simple_intf_device# cat sysfs_debug_level
0
#:/sys/devices/platform/sysfs_simple_intf_device# echo 2 > sysfs_debug_level
#:/sys/devices/platform/sysfs_simple_intf_device# cat sysfs_debug_level
2
Linux用户与内核空间交互—sysfs相关推荐
- Linux用户与内核空间交互—netlink
目录 简介 一.netlink soket 优点 二.用户空间 1.API 2.编程流程 3.源码 三.内核编程 1.API 2.内核空间编程流程 3.内核源码 简介 用户空间与内核的交互方式,使用c ...
- 跟踪 linux 内核调用_Linux用户和内核空间中的动态跟踪
跟踪 linux 内核调用 您是否曾经遇到过这样的情况,即您意识到没有在代码中的某些点插入调试打印 ,所以现在您将不知道您的CPU是否命中了特定的代码行来执行,直到您重新编译该代码为止.调试语句? 不 ...
- linux 用户态 内核态 通信,procfs(从0开始,内核态和用户态通信charpter2)
这篇博文将针对linux内核态与用户态通信方式中的procfs进行详细的学习. /proc主要存放内核的一些控制信息,所以这些信息大部分的逻辑位置位于内核控制的内存,在/proc下使用ls -l你会发 ...
- linux内核dma内存分配,Linux 4.x 内核空间 DMA 虚拟内存地址
Architecture: i386 32bit Machine Ubuntu 16.04 Linux version: 4.15.0-39-generic 目录 DMA 虚拟内存区 在 IA32 体 ...
- Linux 用户进程内存空间详解
经常使用top命令了解进程信息,其中包括内存方面的信息.命令top帮助文档是这么解释各个字段的. VIRT , Virtual Image (kb) RES, Resident size (kb) S ...
- linux内存非线性映射到文件,Linux 4.x 内核空间 FIXUP 固定映射和临时映射虚拟内存...
Architecture: i386 32bit Machine Ubuntu 16.04 Linux version: 4.15.0-39-generic 目录 FIXUP 虚拟内存区 在 IA32 ...
- 用户空间和内核空间通讯之【proc文件系统】
今天我们介绍另一种用户内核空间通信的方法:proc文件系统. proc文件系统作为linux提供的一种虚拟文件系统并不占用实际外围存储空间,它仅存在于内存中,系统断电即消失.proc文件系统最开始的设 ...
- linux内核空间和用户空间的是怎样区别的,如何交互,如何从用户空间进入内核空间
linux驱动程序一般工作在内核空间,但也可以工作在用户空间.下面我们将详细解析,什么是内核空间,什么是用户空间,以及如何判断他们. Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,L ...
- linux 内核空间 sy,在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysf...
级别: 初级 燚 杨 (), 计算机科学硕士 2006 年 2 月 16 日 本系列文章包括两篇,它们文详细地介绍了 Linux 系统下用户空间与内核空间数据交换的九种方式,包括内核启动参数.模块参数 ...
最新文章
- onkeyup,onkeydown和onkeypress的区别介绍
- JAVA项目中出现部分中文乱码问题
- java gc时会暂停运行吗,java gc 项目终止运行
- Java同步数据结构之Collection-Queue
- c32-野指针和内存操作分析
- odoo16 Windows绿色版 下载就能尝试了
- wⅰndows ISO文件备份,5 款 Windows 最佳备份软件
- 计算机英特尔显卡在哪找,Win10英特尔显卡设置在哪里 英特尔核芯显卡控制面板六大功能详解...
- Java开发设计——七大原则
- Jetson Xavier NX学习笔记(三)系统烧录+开机教程+YOLOv7环境搭建+错误总结(详细版)
- Android 存储相册,Android 相册图片存储
- input输入的时候统计字数的代码
- 程序员自学理财8~理财必读《富人思维》精典笔记
- 02-Linux 网络基础(Network Namespase、veth pair、bridge、Iptables)
- ​贝叶斯神经网络最新综述
- [设计模式]单例模式的几种不同写法比较
- 在MindSpore1.1.1下训练模型,利用converter进行mindir转换时出现错误的解决方案
- 笔记:《深入浅出统计学》第六章:排列与组合(Python实现)
- 基于Python Tkinter的多线程局域网扫描器
- AreYouReady?