自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux驅(qū)動(dòng)小技巧 | 利用DRIVER_ATTR實(shí)現(xiàn)調(diào)用內(nèi)核函數(shù)

系統(tǒng) Linux
很多朋友在調(diào)試驅(qū)動(dòng)的時(shí)候,都會(huì)遇到這樣一個(gè)場(chǎng)景:修改一個(gè)參數(shù),然后調(diào)用某個(gè)內(nèi)核中的函數(shù)。

1. 前言

很多朋友在調(diào)試驅(qū)動(dòng)的時(shí)候,都會(huì)遇到這樣一個(gè)場(chǎng)景:修改一個(gè)參數(shù),然后調(diào)用某個(gè)內(nèi)核中的函數(shù)。

比如將某個(gè)gpio的值拉高/拉低,修改某個(gè)寄存器的值等等。

如果每一個(gè)參數(shù)都通過(guò)字符設(shè)備的ioctl接口,增加對(duì)應(yīng)的cmd,會(huì)比較麻煩,

研究?jī)?nèi)核的計(jì)算機(jī)大牛門(mén)怎么會(huì)容忍這種事發(fā)生,

于是設(shè)計(jì)出了DRIVER_ATTR這個(gè)宏,完美解決這個(gè)需求。

下面一口君通過(guò)一個(gè)簡(jiǎn)單的實(shí)例,給大家講解如何使用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, \
}

說(shuō)明

 _name:名稱(chēng),也就是將在sys fs中生成的文件名稱(chēng)。
_mode:上述文件的訪問(wèn)權(quán)限,與普通文件相同,UGO的格式,最高權(quán)限0644,否則會(huì)報(bào)錯(cuò)。
_show:顯示函數(shù),cat該文件時(shí),此函數(shù)被調(diào)用。
_store:寫(xiě)函數(shù),echo內(nèi)容到該文件時(shí),此函數(shù)被調(diào)用。

3. 使用步驟定義一個(gè)寫(xiě)操作的回調(diào)函數(shù):

static ssize_t peng_test_store(struct device_driver *driver,
const char *buf, size_t count)
{
//對(duì)參數(shù)進(jìn)行檢查
if(NULL == buf || count >255 || count == 0 || strnchr(buf, count, 0x20))
return -1;

printk("buf:%s count:%d\n",buf,count);

return count;
}

聲明該函數(shù)與文件節(jié)點(diǎn)關(guān)系

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

創(chuàng)建文件節(jié)點(diǎ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;
}

這幾個(gè)名字之間關(guān)系如下:

4. 源碼

本實(shí)驗(yàn)代碼分為兩個(gè)模塊 device、driver, 分別定義結(jié)構(gòu)體platform_device、platform_driver并注冊(cè)到platform總線(xiàn)。

完整源碼如下:

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. 編譯運(yùn)行

第一步:編譯

第二步:加載模塊驅(qū)動(dòng) 第三步:查看生成的文件節(jié)點(diǎn):

第四步:通過(guò)下面命令向節(jié)點(diǎn)輸入一個(gè)數(shù)字(要管理員權(quán)限):

echo 1 > peng

由結(jié)果可知,我們通過(guò)向文件peng寫(xiě)入一個(gè)字符,實(shí)現(xiàn)了調(diào)用函數(shù)peng_test_store(),并且字符1傳遞給了參數(shù)buf,字符個(gè)數(shù)傳遞給了count。

其中目錄duang是由結(jié)構(gòu)體變量hello_driver 給出:

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

6. 一次注冊(cè)多個(gè)節(jié)點(diǎn)

需要借助結(jié)構(gòu)體

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

7. 補(bǔ)充

當(dāng)然_ATTR不是獨(dú)生子女,他還有一系列的姊妹__ATTR_RO宏只有讀方法,__ATTR_NULL等等

如對(duì)設(shè)備的使用        DEVICE_ATTR   
對(duì)驅(qū)動(dòng)使用 DRIVER_ATTR
對(duì)總線(xiàn)使用 BUS_ATTR
對(duì)類(lèi)別 (class) 使用 CLASS_ATTR

好了,大家后面在調(diào)試驅(qū)動(dòng)的時(shí)候別忘了有這些宏可以使用。


責(zé)任編輯:武曉燕 來(lái)源: 一口Linux
相關(guān)推薦

2023-10-26 11:39:54

Linux系統(tǒng)CPU

2015-08-03 10:43:58

Linux內(nèi)核驅(qū)動(dòng)

2023-10-07 09:37:53

2023-11-28 09:17:05

Linux編程

2022-10-08 11:57:30

Linux內(nèi)核架構(gòu)

2015-07-20 10:00:28

Linux內(nèi)核編碼風(fēng)格

2017-03-23 14:30:13

Linux內(nèi)核驅(qū)動(dòng)編碼風(fēng)格

2021-12-15 10:02:25

鴻蒙HarmonyOS應(yīng)用

2011-04-28 15:35:38

打印驅(qū)動(dòng)

2009-11-27 16:20:22

PHP遞歸調(diào)用

2023-05-15 08:58:41

塊設(shè)備驅(qū)動(dòng)Linux

2009-12-08 14:00:11

PHP函數(shù)microt

2017-08-01 17:34:47

Linux內(nèi)核驅(qū)動(dòng)文件讀寫(xiě)

2013-10-31 16:29:10

Linux內(nèi)核

2023-05-12 07:27:24

Linux內(nèi)核網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)

2009-08-07 10:28:03

2023-04-28 08:42:08

Linux內(nèi)核SPI驅(qū)動(dòng)

2023-01-03 15:47:09

Linux內(nèi)核C語(yǔ)言

2010-07-20 10:04:25

Linux內(nèi)核編譯

2015-07-30 10:51:42

Linux內(nèi)核Linux
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)