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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

为了维护世界和平_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值