Pcd driver with multiple devices code implementation part-3
In this article, let’s implement the pcd_driver_init function. Let’s shift #if 0 to somewhere below.
First of all, we have to dynamically allocate device_numbers. We are going to use the alloc_chrdev region. Here, this device number you have to get from the driver’s data structure. This would be pcdrv_data. Its address you have to give &pcdrv_data.device_number. And this is a first minor. First minor we can start from 0 and next is NO_OF_DEVICES.
So, now we have four devices. That’s why we want four device_numbers whose base is stored in this device_number variable.
The alloc_chrdev_region now actually allocates device_numbers dynamically for four devices. Please note that all those four device_numbers will not get stored inside this device_number variable. Only the base is stored.
Let’s assume this function returns the major number dynamically. Let’s say it is 127. That’s why this device_number variable actually it has two parts. It has major number section and the minor number section. In the major number section, 127 will be stored. And by changing the minor section number, you can derive the next device.
For example, if 127:0 is stored in this variable, then by changing this a minor number to next one, that is 127:1, you get the device number for the next device like that. That’s why the driver distinguishes between different devices using these minor numbers.
Then we are printing device_number information, but we have got four devices. Now, let’s use a loop to print it four times. So, now let me declare ‘i’ above. device_number you can extract the major number by using MAJOR macro. For this, you have to pass device_number+i. Because to print the next device number, you have to increment the minor count. That’s why I’m using +i device_number+i. And this device_number now it should be modified, you have to write pcdrv_data.
Our next task is to do cdev_init and cdev_add. This we have to do for every device. We have got four devices. So, we have to write all these codes in a loop, as shown below.
/*create device class under /sys/class/ */ pcdrv_data.class_pcd = class_create(THIS_MODULE,"pcd_class"); if(IS_ERR(pcdrv_data.class_pcd)){ pr_err("Class creation failed\n"); ret = PTR_ERR(pcdrv_data.class_pcd); goto unreg_chrdev; } for(i=0;i<NO_OF_DEVICES;i++){ pr_info("Device number <major>:<minor> = %d:%d\n",MAJOR(pcdrv_data.device_number+i),MINOR(pcdrv_data.device_number+i)); /*Initialize the cdev structure with fops*/ cdev_init(&pcdrv_data.pcdev_data[i].cdev,&pcd_fops); /* Register a device (cdev structure) with VFS */ pcdrv_data.pcdev_data[i].cdev.owner = THIS_MODULE; ret = cdev_add(&pcdrv_data.pcdev_data[i].cdev,pcdrv_data.device_number+i,1); if(ret < 0){ pr_err("Cdev add failed\n"); goto cdev_del; }
Cdev_init and cdev_add
And the class_create. The class_create need not be in a loop because only one time we create the class_create.
And after that, device_create has to be in loop. Anyway, we have this loop for printing device number. So, now let’s open the loop here, and let’s put cdev_init and cdev_add codes inside the loop , And let’s close the loop here.
First, I do the alloc_chrdev_region, and after that, I do the class_create. So, the code must be pcdrv_data.class_pcd = class_create(THIS_MODULE, “pcd_class”);
And after that, error checking should be same. And after that, PTR_ERR macro should take pcdrv_data.class_pcd.
Let’s check codes inside the for loop. Here, initialize the cdev structure with fops. Here, for the cdev_init, the first argument is address of the cdev structure, but the cdev is per device basis in this exercise. That’s why I’ll be writing this like you know pcdrv_data.pcdev_data [i].cdev. I hope this line is clear, and this will be the file operations. So, that means every cdev structure is initialized with file operation structure.
And after that, register a device with VFS. Here pcdev_owner, so this will be pcdrv_data.pcdev_data[i].cdev.owner.
After that, cdev_add. So, here also you should write something like this pcdrv_data.pcdev_data[i].cdev. And here, you have to mention the device_number. So, the device number is pcdrv_data.device_number. And we are adding one device. After is a error checking.
Now let’s go to the next one populate the sysfs with device information. So, device_pcd. This will be pcdrv_data.device_pcd. device_create(class_pcd). class_pcd will be pcdrv_data.NULL, device number will be a pcdrv_data.device_number, NULL. Now, here you have to create different device file names for different devices. So, it should be PCDDEV1, 2,3,4.
Let’s look at device tree API once again. Let’s look at its implementation shown in Figure 2. So, here I have a reference device_create. And look at the last argument. This actually takes a formatted string. A string for the device_name, so this is a formatted string. That’s why you can a write something like this.
Let’s get back to the code. I will write this as “pcdev-%d”, and here you can mention i as shown in Figure 3.
When this loop runs for the first time, this will be replaced by pcdev- this value i, that will be 0 like that. It creates a pcdev 0,1,2,3.
And after that, pcdrv_data.device_pcd. And in the error checking, this will be pcdrv_data.device_pcd. Our loop ends here.
Let’s remove if 0. We have almost reached the end. Remove #endif as well. Let me remove this return zero. If everything goes well here, then it would print “Module init was successful” and it returns zero. Otherwise, you have to do some cleanups.
Before that, let’s fix variables as shown below. So, this will be pcdrv_data.pcd (in class_destroy), and you have to delete the cdev structure. Actually, this you have to do it in a loop.
pr_info("Module init was successful\n"); return 0; class_del: class_destroy(pcdrv_data.class_pcd); cdev_del: cdev_del(&pcdrv_data.pcdev_data[i].cdev); unreg_chrdev: unregister_chrdev_region(pcdrv_data.device_number,NO_OF_DEVICES); out: pr_info("Module insertion failed\n"); return ret;
Fixing code for class_del, cdev_del, unreg_chrdev, out
But before that, This cdev should be &pcdrv_data.pcdev_data[i].cdev. Unregister_chrdev_region. You will be unregistering 4 devices. Here, you have to mention the number of devices, so let’s use the macro NO_OF_DEVICES. And you print “model insertion failed,” and you just return the error code. And cleanup is incomplete actually, we will code this later.
But let’s make host, and we have one error at 232, as shown in Figure 4.
Let’s check that this is pcdrv_data as shown in Figure 5.
So here, one more mistake. cdev_init is fine. In the cdev_add, for the next pass, it has to be the next device number. That’s why you have to do +i.
And in the device_create, for the next pass, it has to be the next device. That’s why you have to do +i here as well. Save and exit and compile the code.
In the next article, we will fix this cleanup procedure. Because we now have got multiple devices. So, that’s why here the cleanup procedure is a little different And we will cover that in the next article.
FastBit Embedded Brain Academy Courses
Click here: https://fastbitlab.com/course1