简体   繁体   中英

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

Note: I'm listing this problem as it is today, I'm not opposed 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:

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.

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

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:

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 module I 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.

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

Since you want to call device_create in 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_SYMBOL macro to do this.


For example:

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

Note: You'll need to insert module1 before module2 since the class pointer is defined and exported in module1 .

That should create the directories you are expecting:

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

By the way, if you are getting an Invalid parameters error when you try to load the second module, you might have to add a KBUILD_EXTRA_SYMBOLS line to your Makefile .

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

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 == NULL or use a flag if you must.

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.

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.

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

**[  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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM