Не удается настроить разрешение устройства из кода драйвера
Я хочу получить доступ к узлам драйвера устройства I2C из пространства пользователя в ядре Linux 3.10.14. Я добавил i2c-dev в конфигурацию ядра и получил узлы устройства /dev/i2c-*. Однако у них есть разрешение
$ ls -l /dev/i2c-*
crw------- root root 89, 1 2014-08-21 20:00 i2c-1
В drivers/i2c/i2c-dev.c я добавил обратный вызов
static char *i2c_dev_devnode(struct device *dev, umode_t *mode)
{
if (!mode)
return NULL;
if (MAJOR(dev->devt) == I2C_MAJOR)
*mode = 0666;
return NULL;
}
и в том же файле я добавил обратный вызов в структуру класса устройства:
static int __init i2c_dev_init(void)
{
...
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
...
/* set access rights */
i2c_dev_class->devnode = i2c_dev_devnode;
...
}
Однако права доступа узла устройства остаются
crw------- root root 89, 1 2014-08-21 20:00 i2c-1
Нет ни /lib/udev/rules.d, ни /etc/udev/rules.d
Буду признателен за любые предложения, что может пойти не так здесь.
Я также интересуюсь идеями, как проверить эту проблему.
3 ответа
Вы можете попробовать следующее. Это работает по крайней мере с ядром 4.9.56.
static int my_uevent(struct device *dev, struct kobj_uevent_env *env)
{
add_uevent_var(env, "DEVMODE=%#o", 0666);
return 0;
}
static int __init i2c_dev_init(void)
{
...
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
...
/* set access rights */
i2c_dev_class->dev_uevent = my_uevent;
...
}
Я понимаю, что возвращаемое значение функции обратного вызова devnode должно быть не "NULL", а именем узла устройства. Итак, измените возвращаемое значение вашей функции с "NULL" на devname. Ссылайтесь на код:
---------------------- патч --------------------
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 6f638bb..35a42c6 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -614,6 +614,14 @@ static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
.notifier_call = i2cdev_notifier_call,
};
+static char *i2c_dev_devnode(struct device *dev, umode_t *mode)
+{
+ printk("\n\n****%s: %d\n\n",__func__,__LINE__);
+ if (mode != NULL)
+ *mode = 0666;
+ return kasprintf(GFP_KERNEL, "i2cr/%s", dev_name(dev));;
+}
+
/* ------------------------------------------------------------------------- */
/*
@@ -636,7 +644,12 @@ static int __init i2c_dev_init(void)
goto out_unreg_chrdev;
}
i2c_dev_class->dev_groups = i2c_groups;
+ /* set access rights */
+ printk(KERN_INFO "i2c setting devnode\n");
+ i2c_dev_class->devnode = i2c_dev_devnode;
+
+
/* Keep track of adapters which will be added or removed later */
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
if (res)
Результаты: без применения этого патча:
root@x86-generic-64:~# ls -l /dev/i2c-*
crw------- 1 root root 89, 0 Nov 1 13:47 /dev/i2c-0
crw------- 1 root root 89, 1 Nov 1 13:47 /dev/i2c-1
С патчем:
root@x86-generic-64:~# ls -l /dev/i2cr/*
crw-rw-rw- 1 root root 89, 0 Nov 1 13:38 /dev/i2cr/i2c-0
crw-rw-rw- 1 root root 89, 1 Nov 1 13:38 /dev/i2cr/i2c-1
Настройка узла устройства является обязанностью udev. Поэтому нам нужно использовать правильное правило udev. Дальнейший подход init.rc потерпит неудачу, если драйвер будет загружен после загрузки, например, если это загружаемый модуль. В вашем дистрибутиве может использоваться другой способ поддержки hotplug, поэтому нам нужно обратиться к документации по этому дистрибутиву.