Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux cdev vs register_chrdev

I am reworking a driver and came across the cdev interface in LDD3. After reading http://lwn.net/Articles/195805/ I am more confused than enlightened. From the comments there

  • In order the device to actually appear in the file system, you have to call device_create (class, parent_dev, devno, device_name).
  • In order to call device_create you need to have a device class object: either use one of the existing classes, or create your own with create_class (THIS_MODULE, class_name)

I think this is for sysfs only.

  1. So, is the new interface an attempt to change something that failed, and is it thus recommended to continue using device_create?

  2. If cdev is recommended how do I create the sysfs entry?

  3. I never quite understood the benefit of having a device class, is there a point in having one and if so how do I implement it with cdev?

like image 763
ted Avatar asked Nov 27 '14 15:11

ted


1 Answers

cdev is the char device representation of the kernel. The general idea is to associate cdev with a set of file_operations. These file_operations are performed on a device node, typically present under /dev. cdev_init() is used to associate/link a cdev with a set of file_operations. Finally cdev_add() is called on the device to make it live, such that, the user could access them.

Now, while this is done, it doesn't mean that the device node is created for you. This is done manually by using mknod utility(as explained in LDD3). In general, the drivers are supposed to create the device nodes. This is achieved using device_create() function. Device nodes are generally associated with a class. Thus, we need to create a class first(using class_create()) and then create device nodes using that class.

Let me explain this through an example. Consider only the init function(error handling is avoided here to maintain clarity) :

struct class *my_class;
struct cdev my_cdev[N_MINORS];    
dev_t dev_num;

static int __init my_init(void)
{
    int i;
    dev_t curr_dev;

    /* Request the kernel for N_MINOR devices */
    alloc_chrdev_region(&dev_num, 0, N_MINORS, "my_driver");

    /* Create a class : appears at /sys/class */
    my_class = class_create(THIS_MODULE, "my_driver_class");

    /* Initialize and create each of the device(cdev) */
    for (i = 0; i < N_MINORS; i++) {

        /* Associate the cdev with a set of file_operations */
        cdev_init(&my_cdev[i], &fops);

        /* Build up the current device number. To be used further */
        curr_dev = MKDEV(MAJOR(dev_num), MINOR(dev_num) + i);

        /* Create a device node for this device. Look, the class is
         * being used here. The same class is associated with N_MINOR
         * devices. Once the function returns, device nodes will be
         * created as /dev/my_dev0, /dev/my_dev1,... You can also view
         * the devices under /sys/class/my_driver_class.
         */
        device_create(my_class, NULL, curr_dev, NULL, "my_dev%d", i);

        /* Now make the device live for the users to access */
        cdev_add(&my_cdev[i], curr_dev, 1); 
    }

    return 0;
}

Now, answering to your questions one by one :

So, is the new interface an attempt to change something that failed, and is it thus recommended to continue using device_create? This isn't a new interface. This can be said as an extension, generally used to create device nodes. It also gives us the advantage of creating sysfs attributes, which provides much flexible means to access kernel resources. The functions device_create() returns a pointer to struct device which has a very powerful meaning in the kernel. Take a look at the chapter on 'Linux Device Model' in LDD3.

If cdev is recommended how do I create the sysfs entry? cdev and sysfs entries are independent of one another. You can create sysfs entries even without cdev. Again, look at the chapter on 'Linux Device Model' in LDD3. You may also look at this sample code for creating sysfs entries : http://lxr.free-electrons.com/source/samples/kobject/kobject-example.c

I never quite understood the benefit of having a device class, is there a point in having one and if so how do I implement it with cdev? I hope the above code answers this question.

In general, you may not use cdev at all in your drivers. cdev is a very low level representation. Using cdev many powerful frameworks are built for the types of devices, such as, input, tty, ALSA, IIO, etc etc. All these frameworks are built upon cdev. So, you may not use cdev directly. Instead, you could register with these frameworks and access your device in a much more efficient way. Registering to these frameworks also create device nodes and sysfs entries for you.

Hope this helped.

like image 70
raghav3276 Avatar answered Sep 28 '22 18:09

raghav3276