这个宏我们在内核里面使用非常频繁,这个宏的作用可以抛出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)) #endifBUILD_BUG_ON_ZERO 的作用
这个宏的作用是,如果里面传进来的值是 「true」编译的时候就会出错。
写个代码举个例子
#include #include //#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 a result (of value 0 and type size_t), so the expression can be used e.g. in a structure initializer (or where-ever else comma expressions aren'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; }输出
所以在回到这个宏,这个宏的作用就是限制我们在内核里面设置DEVICE_ATTR的权限,如果你要是设置 0777,那肯定就会给你提示编译错误。
0777 对应的是 8进制
整个流程是如上图,代码是在mode部分那里做了限制。
怎么让DEVICE_ATTR 0777 生效?既然我们知道是
VERIFY_OCTAL_PERMISSIONS 这个宏限制的,那就直接把这个宏修改就好了。
当然了,这样使用是不符合要求的,如果这样,很容易被裁员的哦,毕竟用户可能随便写一段代码就可能让你的系统不正常。
看烧录看效果
推荐阅读:
专辑|Linux文章汇总
专辑|程序人生
专辑|C语言
嵌入式Linux
微信扫描二维码,关注我的公众号