前言:
而今姐妹们对“c语言rmdir函数的使用”大体比较看重,兄弟们都需要剖析一些“c语言rmdir函数的使用”的相关知识。那么小编在网摘上搜集了一些对于“c语言rmdir函数的使用””的相关资讯,希望看官们能喜欢,朋友们一起来了解一下吧!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.oelseKDIR :=/lib/modules/$(shell uname -r)/build#KDIR :=/home/peng/linux-3.14PWD :=$(shell pwd)all: make -C $(KDIR) M=$(PWD) modulesclean: rm -f *.ko *.o *.mod.o *.symvers *.cmd *.mod.c *.orderendif5. 编译运行
第一步:编译
第二步:加载模块驱动
第三步:查看生成的文件节点:
第四步: 通过下面命令向节点输入一个数字(要管理员权限):
echo 1 > peng
由结果可知,我们通过向文件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); 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. 补充
当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等
如对设备的使用 DEVICE_ATTR 对驱动使用 DRIVER_ATTR对总线使用 BUS_ATTR 对类别 (class) 使用 CLASS_ATTR
好了,大家后面在调试驱动的时候别忘了有这些宏可以使用。
标签: #c语言rmdir函数的使用