这个宏我们在内核里面使用非常频繁,这个宏的作用可以抛出sys设备节点给用户使用。用户可以读写sys/class下面的文件节点,以达到控制内核驱动的功效。
比如,像这样的设备节点
weiqifa:/sys/class/zigbee/onoff $ ls
gpio_en power subsystem uevent
weiqifa:/sys/class/zigbee/onoff $
使用方法
static ssize_t gpio_store_en(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)
{struct gpio_dev_data *dev_data = dev_get_drvdata(dev);unsigned long value = 0;int ret;/*将echo进来的buf转换成整型*/ret = kstrtoul(buf, 16, &value);if (ret < 0) {printk( "%s:kstrtoul failed, ret=%d\n", __func__, ret);return ret;}printk("%s: en value : %d\n", __func__, (int)value);if (value) {gpio_direction_output(dev_data->en_pin, dev_data->en_val);dev_data->gpio_val = 1;} else {gpio_direction_output(dev_data->en_pin, !dev_data->en_val);dev_data->gpio_val = 0;}return count;
}static char mybuf[10]="123";/*cat命令时,将会调用该函数*/
static ssize_t gpio_show_en(struct device *dev,struct device_attribute *attr, char *buf)
{struct gpio_dev_data *dev_data = dev_get_drvdata(dev);snprintf(mybuf,sizeof(mybuf),"%d",dev_data->gpio_val);return sprintf(buf, "%s\n", mybuf);
}static DEVICE_ATTR(gpio_en,0664,gpio_show_en, gpio_store_en);...dev_class = class_create(THIS_MODULE, class_name);
ctl_dev = device_create(dev_class, NULL, 0, NULL, "onoff");
if (IS_ERR(ctl_dev)) {dev_err(ctl_dev, "Failed to create device\n");ret = PTR_ERR(ctl_dev);goto err_create_dev;
}err = device_create_file(ctl_dev, &dev_attr_gpio_en);
if (err){printk("driver_create_file = %d\n", err);
}
DEVICE_ATTR 0777 引发的血案
如果你想给一个节点设置 0777 或者写操作,那你编译的时候,会出现下面的编译错误。
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/include/linux/kernel.h:840:3: note: in expansion of macro 'BUILD_BUG_ON_ZERO'BUILD_BUG_ON_ZERO((perms) & 2) + \^
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/include/linux/sysfs.h:102:12: note: in expansion of macro 'VERIFY_OCTAL_PERMISSIONS'.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \^
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/include/linux/device.h:573:45: note: in expansion of macro '__ATTR'struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)^
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/drivers/misc/gpio_control.c:62:8: note: in expansion of macro 'DEVICE_ATTR'static DEVICE_ATTR(gpio_en,0777,gpio_show_en, gpio_store_en);
这个错误的原因主要是出现在
VERIFY_OCTAL_PERMISSIONS
这个宏上面
这个宏定义在
include/linux/
下面
/* Permissions on a sysfs file: you didn't miss the 0 prefix did you? */
#define VERIFY_OCTAL_PERMISSIONS(perms) \(BUILD_BUG_ON_ZERO((perms) < 0) + \BUILD_BUG_ON_ZERO((perms) > 0777) + \/* USER_READABLE >= GROUP_READABLE >= OTHER_READABLE */ \BUILD_BUG_ON_ZERO((((perms) >> 6) & 4) < (((perms) >> 3) & 4)) + \BUILD_BUG_ON_ZERO((((perms) >> 3) & 4) < ((perms) & 4)) + \/* USER_WRITABLE >= GROUP_WRITABLE */ \BUILD_BUG_ON_ZERO((((perms) >> 6) & 2) < (((perms) >> 3) & 2)) + \/* OTHER_WRITABLE? Generally considered a bad idea. */ \BUILD_BUG_ON_ZERO((perms) & 2) + \(perms))
#endif
BUILD_BUG_ON_ZERO 的作用
这个宏的作用是,如果里面传进来的值是 「true」编译的时候就会出错。
写个代码举个例子
#include <stdio.h>
#include <stdbool.h>
//#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
/* Force a compilation error if condition is true */
#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
/* Force a compilation error if condition is true, but also produce aresult (of value 0 and type size_t), so the expression can be usede.g. in a structure initializer (or where-ever else comma expressionsaren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
int main()
{BUILD_BUG_ON(1!=0);bool zero = false;printf("%d\n", !!zero);printf("%d\n", !zero);return 0;
}
输出
VERIFY_OCTAL_PERMISSIONS 的作用?
所以在回到这个宏,这个宏的作用就是限制我们在内核里面设置DEVICE_ATTR的权限,如果你要是设置 0777,那肯定就会给你提示编译错误。
0777 对应的是 8进制
整个流程
整个流程是如上图,代码是在mode部分那里做了限制。
怎么让DEVICE_ATTR 0777 生效?
既然我们知道是
VERIFY_OCTAL_PERMISSIONS 这个宏限制的,那就直接把这个宏修改就好了。
当然了,这样使用是不符合要求的,如果这样,很容易被裁员的哦,毕竟用户可能随便写一段代码就可能让你的系统不正常。
看烧录看效果
推荐阅读:
专辑|Linux文章汇总
专辑|程序人生
专辑|C语言
嵌入式Linux
微信扫描二维码,关注我的公众号