Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 462
Mike Avatar asked Aug 16 '12 18:08

Mike


People also ask

What is Device_create?

NAME. device_create - creates a device and registers it with sysfs.

What is Cdev in Linux?

struct cdev is the kernel's internal structure that represents char devices; this field contains a pointer to that structure when the inode refers to a char device file.

What is sysfs in Linux?

sysfs is a pseudo file system provided by the Linux kernel that exports information about various kernel subsystems, hardware devices, and associated device drivers from the kernel's device model to user space through virtual files.

What is Class_create?

DESCRIPTION. This is used to create a struct class pointer that can then be used in calls to device_create. Returns struct class pointer on success, or ERR_PTR on error. Note, the pointer created here is to be destroyed when finished by making a call to class_destroy.


1 Answers

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.

like image 107
Vilhelm Gray Avatar answered Nov 08 '22 23:11

Vilhelm Gray