linux sys节点属性

本文详细介绍了如何使用sysfs接口在驱动层与应用层之间建立桥梁,实现设备驱动与应用程序之间的数据交换。通过定义DEVICE_ATTR宏和自定义show和store函数,可以实现对设备属性的读取和写入操作。以具体实例展示了如何在sysfs目录下创建设备属性文件,并通过echo和cat命令进行数据交互。同时,通过平台设备注册和驱动注册,实现了硬件设备与内核模块的连接。最后,通过应用层的代码示例展示了如何读取和写入设备属性,以及内核如何响应这些操作。

从底层把值传给上层有很多种方法,sysfs就是很简单的一个:

提到sysfs,就不得不提函数宏 DEVICE_ATTR

DEVICE_ATTR的原型:

#define DEVICE_ATTR(_name,_mode,_show,_store)\

struct device_atttribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) //名称,权限位,读函数,写函数

其中_show表示读方法 --- 对应于adb的cat

_store表示写方法 --- 对应于adb的echo.

 

_ATTR宏有很多,例如设备使用的是DEVICE_ATTR,总线使用的是BUS_ATTR,驱动使用的是DRIVER_ATTR,类别(class)使用的是CLASS_ATTR, 这四个宏定义在<inlude/linux/device.h>中.

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>

struct att_dev{
	struct platform_device *pdev;
	struct kobject *kobj;
};

static ssize_t att_store(struct device *dev, 
					struct device_attribute *attr, 
					const char *buf, size_t count) 
{
	printk("echo debug buf\n");

	return count;
}

static ssize_t att_show(struct device *dev,
                 struct device_attribute *attr,
                 char *buf)
{
	printk("cat debug buf\n");
	return 0;
}
static DEVICE_ATTR(test,0777,att_show,att_store);

static struct att_dev *dev = NULL;

static __devinit int att_probe(struct platform_device *ppdev){
	int ret;
	
	dev->kobj = kobject_create_and_add("attkobj", NULL); 
	if(dev->kobj == NULL){
		ret = -ENOMEM;
		goto kobj_err;
	}

	ret = sysfs_create_file(&dev->pdev->dev.kobj,&dev_attr_test.attr);
	if(ret < 0){
		goto file_err;
	}
	return 0;

file_err:
	 kobject_del(dev->kobj);  
kobj_err:
	return ret;
}

static struct platform_driver att_driver = {
	.probe = att_probe,
	.driver = {
		.owner = THIS_MODULE,
		.name = "att_test",
	},
};

static int __init att_init(void)
{
	int ret;

	dev = kzalloc(sizeof(struct att_dev),GFP_KERNEL);
	if(dev == NULL){
		printk("%s get dev memory error\n",__func__);
		return -ENOMEM;
	}
	
	dev->pdev = platform_device_register_simple("att_test", -1, NULL, 0);  
	if(IS_ERR(dev->pdev)){
		PTR_ERR(dev->pdev); 
		printk("%s pdev error\n",__func__);
		return -1;
	}

    ret = platform_driver_register(&att_driver);
    if(ret < 0){
        printk("%s register driver error\n",__func__);
        return ret;
    }

	return 0;
}

static void __exit att_exit(void)
{
    sysfs_remove_file(&dev->pdev->dev.kobj,&dev_attr_test.attr);
    kobject_del(dev->kobj);
    platform_device_unregister(dev->pdev);
    platform_driver_unregister(&att_driver);
    if(dev != NULL)
        kfree(dev);
}

module_init(att_init);
module_exit(att_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("driverSir");

安装之后/sys/devices/platform/att_test/test

echo 1 > test 

cat test

dmesg之后会看到内核打印出

[  424.793357] echo debug buf
[  427.122139] cat debug buf

说明在echo 1 > test 时调用了att_store,cat test 的时候调用了att_show

 

具体例子:

 

static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP, sensor_delay_show, sensor_delay_store);
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, sensor_enable_show, sensor_enable_store);
static DEVICE_ATTR(data, S_IRUGO, sensor_data_show, NULL);
static DEVICE_ATTR(status, S_IRUGO, sensor_status_show, NULL);

 

 static struct attribute *sensor_attributes[] = {
 &dev_attr_delay.attr,
 &dev_attr_enable.attr,
 &dev_attr_data.attr,
 &dev_attr_status.attr,
 NULL
};

 

如果你想实现的接口名字是data的时候,需要实现static struct attribute *sensor_attribute[] = { &dev_attr_data.attr}

 

将sensor_attribute封装为:static struct attribute_group sensor_attribute_group = {
 .attrs = sensor_attributes
};

 

只要利用sysfs_create_group(&input_data->dev.kobj, &sensor_attribute_group);创建接口.

通过以上三个步骤,就可以在adb shell终端查看到接口了.

当我们在shell中输入:echo "1" > enable时,在上层实际上完成了一次写操作,对应到kernel,就会调用驱动中的sensor_enable_store.

当我们在shell中输入:cat enable时,在上层实际上完成了一次读操作,对应到kernel,就会调用驱动中的sensor_enable_show.

 

这样android和kernel就建立起了桥梁,可以根据不同的操作,在store和show函数中完成对应的硬件操作


driver例子:

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/kthread.h>
#include <linux/semaphore.h>

struct v_dev{
	struct platform_device *p_dev;	
	struct input_dev *input;
	int x;
	int y;
	struct task_struct *run_thread;
	struct semaphore sem;
};

struct v_dev *vmouse_dev = NULL;

static ssize_t write_pos(struct device *dev, struct device_attribute *attr,
             const char *buf, size_t count)
{
	int x,y;
	sscanf(buf,"%d%d",&x,&y);
	vmouse_dev->x = x;
	vmouse_dev->y =y;

	//post 信号量
	up(&vmouse_dev->sem);	

	return count;
}

static ssize_t show_pos(struct device *dev, struct device_attribute *attr,
            char *buf){
	return sprintf(buf,"(%d,%d)\n",vmouse_dev->x,vmouse_dev->y);
}

DEVICE_ATTR(pos,0644,show_pos,write_pos);

static int vmouse_thread(void *data)
{
	int x,y;
	struct v_dev *vmouse_dev = (struct v_dev*)data;
	struct semaphore *sema = &(vmouse_dev->sem);
	
	printk(KERN_INFO "vmouse thread running\n");
	
	while(1){
		//等待信号量
		while((down_interruptible(sema)) == -EINTR){} ;
			
		x = vmouse_dev->x;
		y = vmouse_dev->y;
		input_report_abs(vmouse_dev->input,ABS_X,x);
		input_report_abs(vmouse_dev->input,ABS_Y,y);
		input_sync(vmouse_dev->input);

		printk("vmouse thread report\n");
	}

	return 0;
}	

static int vmouse_probe(struct platform_device *pdev)
{
	int ret = -1;
	printk("%s debug \n",__func__);
	
	if(vmouse_dev->p_dev == pdev){
		printk("platform device is same\n");
	}
	
	vmouse_dev->input = input_allocate_device();
	if(!(vmouse_dev->input)){
		printk("%s request input deivce error\n",__func__);
		goto alloc_input;
	}
	
	vmouse_dev->input->name = "vmouse";
	set_bit(EV_ABS,vmouse_dev->input->evbit);
	input_set_abs_params(vmouse_dev->input, ABS_X, -1024, 1024, 0, 0);
	input_set_abs_params(vmouse_dev->input, ABS_Y, -1024, 1024, 0, 0);

	ret = input_register_device(vmouse_dev->input);
	if(ret < 0){
		printk("%s register input device error\n",__func__);
		goto input_register;
	}
	
	device_create_file(&pdev->dev,&dev_attr_pos);
//初始化信号量,在线程中要用到
	sema_init(&(vmouse_dev->sem),0);	

	vmouse_dev->run_thread = kthread_run(vmouse_thread,vmouse_dev,"vmouse_thread");
	
	return 0;

input_register:
	input_free_device(vmouse_dev->input);
alloc_input:
	kfree(vmouse_dev);
	return ret;
}

static struct platform_driver vmouse_driver = {
	.probe = vmouse_probe,
	.driver = {
		.owner = THIS_MODULE,
		.name = "v_mouse",
	},
};

static int __init vmouse_init(void)
{
	int ret =-1;
	
	printk("%s\n", __func__);
	
	vmouse_dev = kzalloc(sizeof(struct v_dev),GFP_KERNEL);
	if(vmouse_dev == NULL){
		printk("%s alloc memory  error\n",__func__);
		return -ENOMEM;
	}

	vmouse_dev->p_dev= platform_device_register_simple("v_mouse",-1,NULL,0);	
	if(!(vmouse_dev->p_dev)){
		printk("%s register platform device error\n",__func__);
		return ret;
	}
	
	ret = platform_driver_register(&vmouse_driver);
	if(ret < 0){
		printk("%s register driver error\n",__func__);
		return ret;
	}

	return 0;
}

static void __exit vmouse_exit(void)
{
	printk("%s\n", __func__);
	if(vmouse_dev->input != NULL){
		input_unregister_device(vmouse_dev->input);
	}
	printk("%s debug__1\n",__func__);
	
	if(vmouse_dev != NULL){
	platform_device_unregister(vmouse_dev->p_dev);
	}
	printk("%s debug__2\n",__func__);
	
	platform_driver_unregister(&vmouse_driver);
	printk("%s debug__3\n",__func__);
	
	kfree(vmouse_dev);
	printk("%s debug__4\n",__func__);
}

module_init(vmouse_init);
module_exit(vmouse_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("WEED<weed_hz@126.com>");

应用层例子:

#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
//要看自己的节点了
#define EVENT_DEV "/dev/input/event5"

int main(void)
{
	struct input_event ev;
	int count,x,y;

	int fd = open(EVENT_DEV, O_RDWR);
	if(fd < 0){
		printf("open %s failed\n",EVENT_DEV);
		return 0;
	}

	while(1){
		count = read(fd, &ev,sizeof(struct input_event));
		if(EV_ABS == ev.type){
			if(ev.code == ABS_X){
				x = ev.value;
			}else if(ev.code == ABS_Y){
				y = ev.value;
			}
			printf("position: x=%d, y=%d\n",x,y);
		}else if(EV_SYN == ev.type){
				puts("sync!");
		}
	}

	return 0;	
}

先运行应用程序:./test_sys  
在另一个终端执行:echo "90 90" >/sys/devices/platform/v_mouse/pos

你就会看到你input设备上报的坐标,打印信息如下:

position: x=90, y=0
position: x=90, y=90
sync!
内容概要:本文介绍了一种基于多目标粒子群算法(MOPSO)的微电网优化调度模型,综合考虑风能、光伏、储能系统、柴油发电机、燃气轮机以及与主电网之间的能量交互等多种分布式能源的协同运行。通过构建以运行成本最小化、碳排放最低化和系统可靠性最优化为目标的多目标优化模型,利用Matlab平台实现MOPSO算法求解,完成对微电网在不同运行场景下的能量管理与调度方案优化。该模型能够有效平衡经济性与环保性之间的关系,适用于含多类型分布式电源的复杂微电网系统,具有较强的工程应用价值和科研参考意义; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及工程技术人员,尤其适合从事微电网、智能电网、综合能源系统、可再生能源集成与优化调度等领域研究的专业人士; 使用场景及目标:①用于多能源耦合微电网系统的协同优化调度研究;②支持多目标智能优化算法在能源系统中的建模与求解实践,帮助用户掌握MOPSO在实际工程问题中的应用方法;③为学术论文复现、毕业设计、科研项目开发提供完整的代码实例与技术支撑; 阅读建议:建议读者结合Matlab代码与理论文档,深入理解目标函数构建、约束条件处理及Pareto最优解集生成机制,重点关注算法参数设置、多目标权衡分析与结果可视化,并可通过调整能源配置或引入新约束进行二次开发与创新研究。
内容概要:本文系统研究了基于模型预测控制(MPC)的滚动优化方法在微电网多时间尺度能量管理调度中的应用。通过构建包含风能、光伏、储能等多种分布式能源的微电网综合系统模型,充分利用MPC的前瞻性预测与滚动优化机制,实现对系统内部能量流的精细化、动态化调控。研究重点解决了新能源出力强不确定性带来的调度挑战,兼顾系统运行的经济性、稳定性与可靠性,在日前、日内及实时等多个时间尺度上实现了优化决策的协同。文中配套提供了完整的Python代码实现,涵盖模型构建、约束处理、目标函数设定与求解全过程,具有较强的可复现性与工程参考价值。; 适合人群:具备一定电力系统、优化理论基础和Python编程能力的研究生、科研人员及从事微电网、综合能源系统、能源互联网等领域研究的工程技术人员。; 使用场景及目标:①深入理解MPC在复杂能源系统调度中的核心原理与技术优势;②学习并复现多时间尺度滚动优化的完整建模与求解流程;③为微电网能量管理系统(EMS)的开发、相关学术研究或工程项目提供直接的算法实现参考与技术支撑; 阅读建议:建议读者结合所提供的Python代码进行逐行研读与调试,亲自动手修改系统参数、负荷曲线或新能源出力数据,以深刻体会MPC算法的动态响应特性与优化效果,进而在此基础上开展二次开发与创新性研究。
智能安防是依托人工智能、大数据、物联网等前沿技术构建的新一代安全防护体系,彻底打破了传统安防“被动监控、事后追溯”的局限。它不再是孤立的摄像头、门禁和报警器的简单组合,而是通过全域感知设备的互联互通,实现对人员、车辆、环境等多维度数据的实时采集与智能分析。从社区出入口的人脸无感通行、异常行为识别,到道路上的违章智能抓拍、重点区域的入侵预警,再到企业园区的消防隐患预判、设备故障自动告警,智能安防能在毫秒级完成风险研判,把安全防线从“事后处置”前移到“事前预防”。如今,它早已渗透到城市治理、居家生活、商业运营等各类场景,成为守护公共安全与私人空间的核心技术支撑。 不同于传统安防依赖人工盯守的高成本模式,智能安防凭借算法的持续迭代,不断拓展安全防护的边界。它可以通过对历史数据的深度挖掘,提前识别人群聚集、消防通道占用等潜在风险,联动公安、物业、应急等多部门快速响应,大幅降低安全事件的发生概率和处置时长。在老旧小区改造中,智能安防设备的加装解决了过去流动人口管理难、高空抛物溯源难等长期痛点;在家庭场景里,智能门锁、可视门铃、燃气泄漏报警器等设备组成的居家安防网络,让用户通过手机就能随时掌握家中安全状态。随着数字城市建设的推进,智能安防正从单一的安全工具,进化为构建智慧城市安全底座的关键组成部分,为人们的日常工作与生活筑牢更高效、更精准的防护屏障。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值