【问题标题】:In Linux, how do you use device_create within an existing class?在 Linux 中,如何在现有类中使用 device_create?
【发布时间】:2012-08-16 18:41:48
【问题描述】:

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

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

【问题讨论】:

    标签: c linux linux-kernel device-driver


    【解决方案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");
            ....
    }
    

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

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

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

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

    【讨论】:

    • 及以下/dev
    【解决方案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 或在必要时使用标志。

    【讨论】:

    • 对于这个简单的用例,是的,它会起作用。当我有第二个内核设备时怎么办?当我完善我的问题时,我提到一个 second 内核模块也希望在相同的 /sys/class/chardrv 目录中创建一个设备。显然没有必要在这两个地方都调用class_create()。但是,如果我不调用此方法,我如何访问device_create() 的参数1 所需的chardrv 类。还有一次:模块 1 调用 class_create()/device_create()模块 2 只想调用device_create(),但需要类引用。
    • 所以你需要添加一个API来检索类。最简单的选择是将其放入内核中(不是模块)并让模块调用它。
    • 我很好,实施很灵活。但是我仍然不确定如何。当我调用class_create() 时,参数1 是THIS_MODULE。将类的创建移到内核中,我认为THIS_MODULE 将不再起作用。 class_create 函数的 def 表明 P1 是:“owner: 指向拥有这个结构类的模块的指针”。这意味着所有者必须是一个模块。
    • 我的意思是礼貌,你想太多了。试试看 :) - 如果您的代码不在模块中,您会发现内核头文件使用 THIS_MODULE 做正确的事情。
    • 我在调用设备创建两次时遇到了崩溃。这是我的问题链接 - 任何想法 - stackoverflow.com/questions/23085691/…
    【解决方案3】:

    只需在您的第一个模块的模块初始化函数中创建类,使用 EXPORT_SYMBOL 导出 -global - 类符号并从另一个模块中使用它。

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

    【讨论】:

      【解决方案4】:

      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)
      

      【讨论】:

      • 我不确定您是否清楚我何时尝试在这里执行...至少该错误对我的问题没有意义。例如,我想创建一个类“chardrv”,然后让一个内核模块在其中注册一个设备。说“设备1”。然后第二个内核模块将第二个设备注册到同一个类“device2”中。所以现在在 /sys/class/chardrv 上运行 list 命令将显示两个设备。你是说在Linux中没有办法做到这一点?我觉得不合适...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多