Vil*_*ray 18 c linux linux-device-driver linux-kernel sysfs
我正在学习如何在我的Linux模块中使用sysfs,但我最难找到有关这些主题的当前文档.我一直在使用的Linux设备驱动程序第3版书似乎在这个领域相当过时(例如,class_device在当前的Linux版本中,结构似乎完全消失了).
我只是试图在我的模块的相应sysfs类下获得一个属性,这将允许我从内核空间读取模块变量的值.
在我的代码中,我创建了一个类,允许udev在/ dev/foo为我的模块创建一个设备节点:
dev_t foo_dev;
alloc_chrdev_region(&foo_dev, 0, 1, "bar");
struct class *bar = class_create(THIS_MODULE, "bar");
device_create(bar, NULL, foo_dev, NULL, "foo");
struct cdev foo_dev_file;
cdev_init(&foo_dev_file, &fops); /* fops defined earlier */
cdev_add(&foo_dev_file, foo_dev, 1);
Run Code Online (Sandbox Code Playgroud)
当我插入模块时,我得到了一个sysfs类目录,并在/ sys/class/bar/foo /中填充了一些默认属性.如何创建显示在此新目录下的属性?
我相信我的概念非常好 - 创建属性结构,定义sysfs_ops函数等 - 我的问题是我不知道使用哪个特定的内核结构(class_attribute?),也不知道如何使这些属性出现在右边sysfs目录.
有人会指点我的教程或文章详细介绍当前Linux内核的过程吗?
Dan*_*tos 15
尽管我的知识在这个主题上仍然相当低,但我将仅仅因为这个问题的年龄而发布答案.如果有其他人有更好的答案,请发布!:)
首先,我将假设您已经阅读了整章(特别是关于kobjects和ksets).因此,几乎设备驱动程序模型中的每个结构都包含在其中.如果你想操纵它自己的类的kobject(不确定这是否明智),那就是你struct class的dev_kobj成员.
但是,您希望操纵该类的属性.我相信,通过定义它们的(通常是静态的),空值终止的数组,如下所示,然后到指定的地址,这样做struct class的class_attrs成员(摘自drivers/uwb/driver.c):
static struct class_attribute uwb_class_attrs[] = {
__ATTR(beacon_timeout_ms, S_IWUSR | S_IRUGO,
beacon_timeout_ms_show, beacon_timeout_ms_store),
__ATTR_NULL,
};
/** Device model classes */
struct class uwb_rc_class = {
.name = "uwb_rc",
.class_attrs = uwb_class_attrs,
};
Run Code Online (Sandbox Code Playgroud)
当我不知道如何使用某些东西时,我通常git grep是使用它的其他人的存储库,并尝试以这种方式学习它.看起来这就是为什么他们倾向于说内核"黑客"而不是"开发者".
最小的可运行示例
用法:
insmod /sysfs.ko
cd /sys/kernel/lkmc_sysfs
printf 12345 >foo
cat foo
# => 1234
dd if=foo bs=1 count=2 skip=1 status=none
# => 23
Run Code Online (Sandbox Code Playgroud)
sysfs.c
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <uapi/linux/stat.h> /* S_IRUSR, S_IWUSR */
enum { FOO_SIZE_MAX = 4 };
static int foo_size;
static char foo_tmp[FOO_SIZE_MAX];
static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buff)
{
strncpy(buff, foo_tmp, foo_size);
return foo_size;
}
static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buff, size_t count)
{
foo_size = min(count, (size_t)FOO_SIZE_MAX);
strncpy(foo_tmp, buff, foo_size);
return count;
}
static struct kobj_attribute foo_attribute =
__ATTR(foo, S_IRUGO | S_IWUSR, foo_show, foo_store);
static struct attribute *attrs[] = {
&foo_attribute.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static struct kobject *kobj;
static int myinit(void)
{
int ret;
kobj = kobject_create_and_add("lkmc_sysfs", kernel_kobj);
if (!kobj)
return -ENOMEM;
ret = sysfs_create_group(kobj, &attr_group);
if (ret)
kobject_put(kobj);
return ret;
}
static void myexit(void)
{
kobject_put(kobj);
}
module_init(myinit);
module_exit(myexit);
MODULE_LICENSE("GPL");
Run Code Online (Sandbox Code Playgroud)
经过Linux内核5.0测试。