Linux驱动小技巧 | 利用DRIVER_ATTR实现调用内核函数

1. 前言

很多朋友在调试驱动的时候,都会遇到这样一个场景:修改一个参数,然后调用某个内核中的函数。

比如将某个gpio的值拉高/拉低,修改某个寄存器的值等等。

如果每一个参数都通过字符设备的ioctl接口,增加对应的cmd,会比较麻烦,

研究内核的计算机大牛门怎么会容忍这种事发生,

于是设计出了DRIVER_ATTR这个宏,完美解决这个需求。

下面一口君通过一个简单的实例,给大家讲解如何使用DRIVER_ATTR

2. DRIVER_ATTR定义

该宏定义的文件如下:include/linux/device.h

struct driver_attribute {struct attribute attr;ssize_t (*show)(struct device_driver *driver, char *buf);ssize_t (*store)(struct device_driver *driver, const char *buf,size_t count);
};#define DRIVER_ATTR(_name, _mode, _show, _store) \struct driver_attribute driver_attr_##_name = __ATTR(_name, _mode, _show, _store)

__ATTR定义于文件 include/linux/sysfs.h

#define __ATTR(_name, _mode, _show, _store) {    \.attr = {.name = __stringify(_name), .mode = _mode },  \.show = _show,      \.store = _store,      \
}

说明

_name:名称,也就是将在sys fs中生成的文件名称。_mode:上述文件的访问权限,与普通文件相同,UGO的格式,最高权限0644,否则会报错。_show:显示函数,cat该文件时,此函数被调用。_store:写函数,echo内容到该文件时,此函数被调用。

3. 使用步骤

定义一个写操作的回调函数:

static ssize_t peng_test_store(struct device_driver *driver,const char *buf, size_t count)
{
//对参数进行检查if(NULL == buf || count >255 || count == 0 || strnchr(buf, count, 0x20))return -1;printk("buf:%s count:%d\n",buf,count);return count;
}

声明该函数与文件节点关系

static DRIVER_ATTR(peng, 0644, NULL, peng_test_store);

创建文件节点:

ret = driver_create_file(&(hello_driver.driver), &driver_attr_peng);if (ret < 0){dev_err(&pdev->dev, "could not create sysfs files\n");ret = -ENOENT;}

这几个名字之间关系如下:

bb0b13dc3f9d07571b4bc936d0f2941b.png

4. 源码

本实验代码分为两个模块 device、driver, 分别定义结构体platform_device、platform_driver并注册到platform总线。

完整源码如下:

device.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
static void hello_release(struct device *dev)
{return;
}
static struct platform_device hello_device = 
{.name = "duang",.id = -1,.dev.release = hello_release,
};
static int hello_init(void)
{printk("hello_init \n");return platform_device_register(&hello_device);}
static void hello_exit(void)
{printk("hello_exit \n");platform_device_unregister(&hello_device);return;
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

driver.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>static int hello_probe(struct platform_device *pdev);
static  int hello_remove(struct platform_device *pdev);static ssize_t peng_test_store(struct device_driver *driver,const char *buf, size_t count)
{if(NULL == buf || count >255 || count == 0 || strnchr(buf, count, 0x20))return -1;printk("buf:%s count:%d\n",buf,count);return count;
}
static DRIVER_ATTR(peng, 0644, NULL, peng_test_store);static struct platform_driver hello_driver =
{.probe = hello_probe,.driver.name = "duang",.remove = hello_remove,  
};struct resource *res;
static int hello_probe(struct platform_device *pdev)
{int ret;printk("match ok \n");ret = driver_create_file(&(hello_driver.driver), &driver_attr_peng);if (ret < 0){dev_err(&pdev->dev, "could not create sysfs files\n");ret = -ENOENT;}return 0;
}
static  int hello_remove(struct platform_device *pdev)
{printk("hello_remove \n");return 0;
}static int hello_init(void)
{printk("hello_init \n");return platform_driver_register(&hello_driver);
}
static void hello_exit(void)
{printk("hello_exit \n");platform_driver_unregister(&hello_driver);return;
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

Makefile

ifneq ($(KERNELRELEASE),)
obj-m:=device.o driver.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
#KDIR :=/home/peng/linux-3.14
PWD  :=$(shell pwd)
all:make -C $(KDIR) M=$(PWD) modules
clean:rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order
endif

5. 编译运行

第一步:编译2deba6b7da14b6101f9cfbc682cb6e9a.png

第二步:加载模块驱动04db3510f94604123323aa4091da67e5.png第三步:查看生成的文件节点:f417e14822d56ab29875be839f61331f.png

第四步:通过下面命令向节点输入一个数字(要管理员权限):

echo 1 > peng

a74567a1b1a08fd0fd9158905dc6e7ec.png由结果可知,我们通过向文件peng写入一个字符,实现了调用函数peng_test_store(),并且字符1传递给了参数buf,字符个数传递给了count

其中目录duang是由结构体变量hello_driver 给出:

static struct platform_driver hello_driver =
{.driver.name = "duang",
};

6. 一次注册多个节点

需要借助结构体

struct attribute

以及函数

/*** sysfs_create_group - given a directory kobject, create an attribute group* @kobj: The kobject to create the group on* @grp: The attribute group to create** This function creates a group for the first time.  It will explicitly* warn and error if any of the attribute files being created already exist.** Returns 0 on success or error.*/
int sysfs_create_group(struct kobject *kobj,const struct attribute_group *grp)

此处就不验证了,直接从内核找个例子给大家学习下吧

drivers\input\touchscreen\ads7846.c
static ssize_t ads7846_pen_down_show(struct device *dev,struct device_attribute *attr, char *buf)
{struct ads7846 *ts = dev_get_drvdata(dev);return sprintf(buf, "%u\n", ts->pendown);
}static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);static ssize_t ads7846_disable_show(struct device *dev,struct device_attribute *attr, char *buf)
{struct ads7846 *ts = dev_get_drvdata(dev);return sprintf(buf, "%u\n", ts->disabled);
}static ssize_t ads7846_disable_store(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{struct ads7846 *ts = dev_get_drvdata(dev);unsigned int i;int err;err = kstrtouint(buf, 10, &i);if (err)return err;if (i)ads7846_disable(ts);elseads7846_enable(ts);return count;
}
static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);static struct attribute *ads784x_attributes[] = {&dev_attr_pen_down.attr,&dev_attr_disable.attr,NULL,
};static struct attribute_group ads784x_attr_group = {.attrs = ads784x_attributes,
};
err = sysfs_create_group(&mydevice->dev.kobj, &ads784x_attr_group);

7. 补充

当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等

如对设备的使用        DEVICE_ATTR   
对驱动使用               DRIVER_ATTR
对总线使用               BUS_ATTR 
对类别 (class) 使用  CLASS_ATTR

好了,大家后面在调试驱动的时候别忘了有这些宏可以使用。

end

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

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

相关文章

myeclipse运行java项目_myeclipse运行自己从前的或其他人的javaweb项目

1.配置javaweb 连接部署好本地的tomcat服务器方法如下&#xff1a;1.运行Myecipse-->Window-->preference2.MyEclipse-->Servers-->Runtime Environments-->add-->Apache Tomcat v8.03.next->Browser(Tomcat的安装目录)-->finishMyeclipse 设置jdk版本…

MYSQL性能调优及架构设计学习笔记-影响MYSQL性能的相关因素之实例分析

为什么80%的码农都做不了架构师&#xff1f;>>> 需求概述 一个简单的讨论区系统&#xff0c;需要有用户&#xff0c;用户组&#xff0c;组讨论区这三部分基本功能 简要分析 1&#xff09; 须要存放用户数据的表&#xff1b; 2&#xff09; 须要存放分组信息和用户与…

软件测试第三次作业

一、开头 (1)合作者&#xff1a;201631062521&#xff0c;201631062421 (2)代码地址&#xff1a;https://gitee.com/h2503652646/WordCount.git (3)本次作业链接地址&#xff1a;https://edu.cnblogs.com/campus/xnsy/Test/homework/2203 二、正文 (1)互审代码情况 已经实现Wor…

Linux驱动开发中与设备树相关的6种debug方法

整理出了6种驱动开发时与设备注册、设备树相关的调试方法&#xff0c;彼此间没有优先级之分&#xff0c;每种方法不一定是最优解&#xff0c;但可以作为一种debug查找问题的手段&#xff0c;快速定位问题原因。例如在芯片验证时&#xff0c;不同时钟频率下系统启动情况摸底时&a…

DiscoveryService.getRemoteAdvertisements是否会获得本地通告?

从该方法名称上来说&#xff0c;应该是不能获得本地通告&#xff0c;本着探究的精神&#xff0c;首先做个小测试&#xff0c;再从源代码中寻找答案。----------------------------------------------------------------------------- 测试结果&#xff1a;本地通告确实取不到&a…

Linux的bc命令计算π的值预估系统算力

这是今天突然想到的一个事情&#xff0c;几年前我和一个朋友做一个开发板&#xff0c;然后我们需要完成的这个开发板有算力的要求&#xff0c;当时我们测试的时候就用了一个shell脚本来分析系统的算力。今天我突然想不起这个命令&#xff0c;然后就想写篇文章记录下&#xff0c…

面向对象的思想是什么?

我同事的回答&#xff0c;我觉得这句话可以读十遍说下我自己的理解你不是人&#xff0c;你是猪。解释一下我们在编写面向对象的代码时&#xff0c;一定要有抽象的思想&#xff0c;什么是抽象&#xff0c;抽象是一种概念的东西&#xff0c;不是实实在在的&#xff0c;看不见摸不…

python编程格式化输出_Python的三种格式化输出

今天刚学了python的三种格式化输出&#xff0c;以前没接触过这么有趣的输出方式&#xff0c;现在来分享一下。#!/user/bin/env python#coding:utf-8#三种格式化输出#第一种格式化输出nameinput("name:")ageinput("age:")jobinput("job:")salaryi…

多线程的异常捕捉

为什么要单独讲多线程的异常捕捉呢&#xff1f;先看个例子&#xff1a; public class ThreadException implements Runnable{Overridepublic void run() {throw new RuntimeException();}//现象&#xff1a;控制台打印出异常信息&#xff0c;并运行一段时间后才停止public stat…

Linux 安装配置JDK 、 MySQL 、nginx

今天我来讲一下在Linux下各环境的搭建&#xff0c;主要就讲一下jdk、MySQL、和一个代理服务器nginx 1、 jdk的安装配置 1)卸载自带openjdk 当我们拿到一个全新的ECS的时候上面有的会自带一个openjdk&#xff0c;但是我们一般不会用这个&#xff0c;所以在这里我们会先卸载这个自…

wat java_并发工具优于wati、notify(69)

现在几乎没有理由在使用wait 和 notify&#xff0c;使用高级工具代替java.util.concurrent 包并发工具分三类&#xff1a;Executor 框架并发集合(concurrent Collection)同步器(synchronizer)并发集合对标准集合接口(List、Map、Queue)封装了高性能的并发实现为了提高并发性&am…

一道关于 fork 的笔试题

题目阅读下面的代码&#xff0c;显示终端会打印出几个 hello world&#xff1f;#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h>int main() {fork();fork();fork();printf("hello world\n");exit(0); }…

小球游戏1

引用&#xff1a;http://www.oschina.net/code/snippet_12_4121 [图片] pic3.jpg [图片] pic4.jpg [代码] [Java]代码 01public class Player extends AnimatedSprite {02...03Override04 protected void onManagedUpdate(final float pSecondsElapsed) {05 super.…

java怎么调kettle_通过Java调取Kettle的结果集

Kettle端&#xff1a;Data Grid只是测试数据&#xff0c;目的是把数据传递到记录结果。Java端&#xff1a;package com.womai.util;import org.pentaho.di.core.KettleEnvironment;import org.pentaho.di.core.RowMetaAndData;import org.pentaho.di.trans.Trans;import org.pe…

我也确实很向往深圳这种拼搏的精神

今天跟个同学聊天&#xff0c;是关于他的offer选择&#xff0c;他拿了一个不错的外企岗位offer&#xff0c;这个offer的薪资是他现在薪资两倍还多一些&#xff0c;他现在人在外地&#xff0c;年后准备来深圳工作&#xff0c;他在微信说让我给些建议。首先我肯定的是&#xff0c…

中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux

去年 6 月份&#xff0c;中科院大学教授、中科院计算所研究员包云岗&#xff0c;发布了开源高性能 RISC-V 处理器核心 —— 香山。近日&#xff0c;包云岗在社交平台晒出图片&#xff0c;香山芯片已流片&#xff0c;回片后进行了串口调通&#xff0c;1 月 24 日成功运行了 Linu…

java io流操作_十个Demo进行讲解Java中IO流的常用操作~

好久不见的IO流对IO流的学习&#xff0c;我记得还是初学Java基础的时候&#xff0c;后来找工作过程中经常看到有些招聘信息中写到熟悉IO流&#xff0c;现在想想IO流&#xff0c;真的是一脸懵逼&#xff0c;不说这么多废话了&#xff0c;IO流这次好好整理一下。说说IO流的类别在…

这些应用仍未兼容安卓新版本,系统升级后将无法使用

8月7日&#xff0c;谷歌正式发布Android 9 Pie&#xff0c;至今已两月有余。近日&#xff0c;华为终端开放实验室对国内主流应用在Android 9 Pie的兼容性进行测试&#xff0c;结果显示&#xff1a;目前TOP3000应用兼容率已经超过95%&#xff0c;但仍有少量应用存在启动失败、闪…

非常郁闷,WinForm中正常显示的自定义控件无法在WebForm中正常显示!

我写了一个自定义控件(Win Control)&#xff0c;此控件在WinForm中运行正常&#xff0c;但在WebForm中无法显示(在WebForm中此控件并不显示为红叉&#xff0c;但是一个对象图标)。由于没有出现权限或安全方面的提示&#xff0c;因此我从头开始一行一行进行比对&#xff0c;最终…

在家过年这两天|多图

这两天收到了很多朋友的新年祝福&#xff0c;在这里回应下&#xff0c;希望看到这篇文章的朋友们新的一年快乐开心&#xff0c;在求学的人学有所成&#xff0c;在工作的朋友们功成名就&#xff0c;家人健康&#xff0c;吃喝不愁……祝你们㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱…