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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11993467/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:06:00  来源:igfitidea点击:

In Linux, how do you use device_create within an existing class?

clinuxlinux-kerneldevice-driver

提问by Mike

Note:I'm listing this problem as it is today, I'm notopposed to changing the implementation (moving the creation of the class to a common area for example) if it makes things easier... I'm just not sure how to do it. :End Note

注意:我现在列出这个问题,我反对更改实现(例如,将类的创建移动到公共区域)如果它使事情变得更容易......我只是不确定怎么做。:尾注

I've got two linux kernel modules and I'm trying to update the /sys entries for them. Searching around on google and other sources, I've seen lots of code along the lines of:

我有两个 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);
    ....

And I've verified for my first module this code works, and that it correctly creates a:

我已经为我的第一个模块验证了这段代码有效,并且它正确地创建了一个:

/sys/class/chardrv/<MODULE_NAME>

entry. What I'd like to know is how do you create a device in an existing class. In other words, one of my modules created this new chardrv class, now I want my other module to be able to also register its devices under the same class.

入口。我想知道的是如何在现有课程中创建设备。换句话说,我的一个模块创建了这个新的 chardrv 类,现在我希望我的另一个模块也能够在同一类下注册其设备。

I can't call class_create() again (in the second module), because that "chardrv" class already exists...

我不能再次调用 class_create()(在第二个模块中),因为那个“chardrv”类已经存在......

So I can run a check to see if /sys/class/chardrv exists, and this can help me decide if I need to call class_create() or not, that's not a problem. Lets put some pseudo code in here to clarify:

因此,我可以运行检查以查看 /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, ...)

So as per this example, if my class already exists, and I just want to add my new device into it from a second moduleI assume I need to create a class structure and somehow populate it with the correct "chardrv class" attributes then call device_create as before, but I'm not sure how to do that.

因此,根据此示例,如果我的类已经存在,并且我只想将我的新设备从第二个模块添加到其中我假设我需要创建一个类结构并以某种方式使用正确的“chardrv 类”属性填充它,然后调用device_create 和以前一样,但我不知道该怎么做。

回答by duslabo

Linux kernel won't allow to do that. This is the ERROR you will get.

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)

回答by mpe

To follow your example code, you would simply call device_create()again, passing the same class, eg:

要遵循您的示例代码,您只需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");

You should definitely not need to check the path in order to determine if the class has been created. You are creating it in your code, so simply test for c1 == NULLor use a flag if you must.

您绝对不需要检查路径来确定类是否已创建。您正在代码中创建它,因此c1 == NULL如果必须,只需测试或使用标志。

回答by Vilhelm Gray

To use the device_createfunction with the same class, just pass it a pointer to the same class.

device_create在同一个类中使用该函数,只需向它传递一个指向同一个类的指针即可。

Since you want to call device_createin a different module than the one in which you create the class, you'll need to export the symbol for the pointer to the class. You can use the EXPORT_SYMBOLmacro to do this.

由于您要调用device_create与创建类的模块不同的模块,因此您需要导出指向类的指针的符号。您可以使用EXPORT_SYMBOL宏来执行此操作。



For example:

例如:

module1.c:

模块1.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

模块2.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");
        ....
}

Note: You'll need to insert module1before module2since the class pointer is defined and exported in module1.

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

That should create the directories you are expecting:

这应该创建您期望的目录:

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


By the way, if you are getting an Invalid parameterserror when you try to load the second module, you might have to add a KBUILD_EXTRA_SYMBOLSline to your Makefile.

顺便说一句,如果您Invalid parameters在尝试加载第二个模块时遇到错误,您可能需要在 Makefile 中添加KBUILD_EXTRA_SYMBOLS一行

回答by Gabor Jozsef Wacha

Just create the class in the module init function of your first module, export the - global - class symbol with EXPORT_SYMBOL and use it from the other module.

只需在第一个模块的模块 init 函数中创建类,使用 EXPORT_SYMBOL 导出 - 全局 - 类符号并从其他模块使用它。

Since the owner of the class is your first module, every time you add a device to that class the first module's reference counter will be increased: you cannot unload it while anyone is using it.

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