Linux cdev vs register_chrdev
driver, linux, linux-device-driver
Solution
`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.
Problem
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. So, is the new interface an attempt to change something that failed, and is it thus recommended to continue using `device_create`? If `cdev` is recommended how do I create the sysfs entry? 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?