Не удается настроить разрешение устройства из кода драйвера

Я хочу получить доступ к узлам драйвера устройства 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, поэтому нам нужно обратиться к документации по этому дистрибутиву.

Другие вопросы по тегам