加入收藏 | 设为首页 | 会员中心 | 我要投稿 银川站长网 (https://www.0951zz.com/)- 云通信、基础存储、云上网络、机器学习、视觉智能!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

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

发布时间:2023-03-24 13:56:01 所属栏目:Linux 来源:
导读:Linux驱动小技巧 运用DRIVER_ATTR实现调用内核函数:1. 前言很多朋友在调试驱动的时候,都会遇到这样一个场景:修改一个参数,然后调用某个内核中的函数。比如将某个gpio的值拉高/拉低,修改某个寄存器的值等等。如果
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;

}

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

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. 编译运行

第一步:编译

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

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

复制

echo 1 > peng

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

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

复制

static struct platform_driver hello_driver =

{

.driver.name = "duang",

};

6. 一次注册多个节点

需要借助结构体

复制

drivers/input/touchscreen/ads7846.c

1.

复制

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);

else

 ads7846_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);

(编辑:银川站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!