В Linux, как вы используете device_create в существующем классе?

Примечание.. Я перечисляю эту проблему, как и сегодня, я не против изменения реализации (например, перемещение создания класса в общую область), если это делает вещи проще... Я просто не знаю, как это сделать. : Конечная записка

У меня есть два модуля ядра Linux, и я пытаюсь обновить их /sys. Поиск в google и других источниках, я видел много кода в строках:

static dev_t MyDev;
static struct class *c1;

static int __init start_func(void)
{
    ...
    MyDev = MKDEV(nMajor, MINOR_VERSION);
    register_chrdev_region(MyDev, 1, MODULE_NAME);
    c1 = class_create(THIS_MODULE, "chardrv");
    device_create(c1, NULL, MyDev, NULL, MODULE_NAME);
    ....

И я проверил для своего первого модуля этот код работает и что он правильно создает:

/sys/class/chardrv/<MODULE_NAME>

запись. Я хотел бы знать, как создать устройство в существующем классе. Другими словами, один из моих модулей создал этот новый класс chardrv, теперь я хочу, чтобы мой другой модуль мог также зарегистрировать свои устройства в одном классе.

Я не могу снова вызвать class_create() (во втором модуле), потому что этот класс "chardrv" уже существует...

Итак, я могу запустить проверку, чтобы увидеть, существует ли /sys/class/chardrv, и это может помочь мне решить, нужно ли мне вызвать class_create() или нет, это не проблема. Здесь можно внести некоторые псевдокоды:

if ( path "/sys/class/chardrv" does not exist)
    new_class = class_create("chardrv")
else
    new_class = some how get class "chardrv" handle, or properties, or whatever
device_create(new_class, ...)

Итак, как в этом примере, если мой класс уже существует, и я просто хочу добавить в него свое новое устройство из второго модуля, я предполагаю, что мне нужно создать структуру класса и как-то заполнить его с правильными атрибутами класса chardrv, тогда вызовите device_create, как и раньше, но я не уверен, как это сделать.

Ответ 1

Чтобы использовать функцию device_create с тем же классом, просто передайте ей указатель на тот же класс.

Поскольку вы хотите вызвать device_create в другом модуле, чем тот, в котором вы создаете класс, вам нужно будет экспортировать символ для указателя на класс. Вы можете использовать макрос EXPORT_SYMBOL, чтобы сделать это.


Например:

module1.c

extern struct class *c1;    /* declare as extern */
EXPORT_SYMBOL(c1);          /* use EXPORT_SYMBOL to export c1 */

static dev_t mod1_dev;
static int __init start_func(void)
{
        ...
        /* define class here */
        c1 = class_create(THIS_MODULE, "chardrv");

        /* create first device */
        device_create(c1, NULL, mod1_dev, NULL, "mod1_dev");
        ....
}

module2.c

extern struct class *c1;    /* declare as extern */

static dev_t mod2_dev;
static int __init start_func(void)
{
        ...
        /* c1 is defined in module 1 */

        /* create second device */
        device_create(c1, NULL, mod2_dev, NULL, "mod2_dev");
        ....
}

Примечание. Вам нужно будет вставить module1 до module2, поскольку указатель класса определен и экспортирован в module1.

Это должно создать каталоги, которые вы ожидаете:

  • /sys/class/chardrv/mod1_dev
  • /sys/class/chardrv/mod2_dev

Кстати, если вы получаете ошибку Invalid parameters при попытке загрузить второй модуль, вам может потребоваться добавить строку KBUILD_EXTRA_SYMBOLS в ваш Makefile.

Ответ 2

Чтобы следовать вашему примеру, вы просто вызываете device_create() снова, передавая тот же класс, например:

MyDev = MKDEV(nMajor, MINOR_VERSION);
register_chrdev_region(MyDev, 1, MODULE_NAME);
c1 = class_create(THIS_MODULE, "chardrv");
device_create(c1, NULL, MyDev, NULL, MODULE_NAME);
...
device_create(c1, NULL, MyDev2, NULL, "mydev2");

Вам определенно не нужно проверять путь, чтобы определить, был ли класс создан. Вы создаете его в своем коде, поэтому просто проверяйте c1 == NULL или используйте флаг, если вам нужно.

Ответ 3

Ядро Linux не позволит этого сделать. Это ОШИБКА, которую вы получите.

**[  865.687824] kobject_add_internal failed for net with -EEXIST, don't try to register things with the same name in the same directory.  
[  865.687835] Pid: 6382, comm: insmod Tainted: P        W  O 3.2.16.1JeshuLinux #1  
[  865.687840] Call Trace:  
[  865.687849]  [<c1584382>] ? printk+0x2d/0x2f  
[  865.687859]  [<c12a5438>] kobject_add_internal+0x138/0x1d0  
[  865.687869]  [<c12a5a11>] kset_register+0x21/0x50  
[  865.687879]  [<c137b63d>] __class_register+0xcd/0x1b0  
[  865.687888]  [<f8d0a0aa>] hello_init+0x4a/0x80 [sysfs_Dev]  
[  865.687897]  [<c1003035>] do_one_initcall+0x35/0x170    
[  865.687909]  [<f8d0a060>] ? enable_show+0x40/0x40 [sysfs_Dev]    
[  865.687919]  [<c10928d0>] sys_init_module+0x2c0/0x1b50    
[  865.687941]  [<c159485f>] sysenter_do_call+0x12/0x28    
[  865.687947] Registering Class Failed**  

If you want to understand sysfs read: [mochel.pdf](www.kernel.org/pub/linux/kernel/people/mochel/doc/papers/ols-2005/mochel.pdf)