Linux用户与内核空间交互—sysfs

Posted 为了维护世界和平_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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_level
	prev_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;
    //检查系统有没有配置SYSFS
	if (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_level
	stat = 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;
	

    //创建文件gpressure
	gpressure = 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

 


参考:

https://course.0voice.com/v1/course/intro?courseId=2&agentId=0

以上是关于Linux用户与内核空间交互—sysfs的主要内容,如果未能解决你的问题,请参考以下文章

Linux用户与内核空间交互—netlink

Linux用户与内核空间交互—netlink

Linux用户与内核空间交互—ioctl

Linux用户与内核空间交互—ioctl

Linux用户与内核空间交互—debugfs

Linux用户与内核空间交互—debugfs