在Linux中,如何在现有类中使用device_create?

时间:2012-08-16 18:41:48

标签: c linux linux-kernel device-driver

注意:我列出了这个问题,因为它是今天,我反对改变实现(将类的创建移动到公共区域)例如)如果它让事情变得更容易......我只是不知道该怎么做。 :结束注释

我有两个Linux内核模块,我正在尝试为它们更新/ sys条目。搜索谷歌和其他来源,我已经看到了很多代码:

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,但我不知道该怎么做。

4 个答案:

答案 0 :(得分:10)

要将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");
        ....
}

注意:您需要在 module2 之前插入 module1 ,因为类指针已在 module1 中定义并导出。

那应该创建你期望的目录:

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

顺便说一句,如果您在尝试加载第二个模块时收到Invalid parameters错误,则可能需要add a KBUILD_EXTRA_SYMBOLS line to your Makefile

答案 1 :(得分:3)

要关注您的示例代码,您只需再次调用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或使用标记(如果必须)。

答案 2 :(得分:1)

只需在第一个模块的模块init函数中创建类,使用EXPORT_SYMBOL导出 - global - class符号,然后从另一个模块中使用它。

由于班级的所有者是您的第一个模块,因此每次向该班级添加设备时,第一个模块的参考计数器都会增加:当有人使用它时,您无法卸载它。

答案 3 :(得分:-1)

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)