From last two weeks i am working on Character Driver.
What is device driver and need of driver?
From my knowledge device driver is nothing but piece of code that runs the device . Every device need that code to run ,without driver device is dead, to make device alive we have to provide that code.
This code is nothing but the driver.
When the driver sit in the hardware permanently that that driver is called firmware , when this driver set the rule how the system boot up then this driver know as BIOS.
So i can conclude that every device need a piece of software to run the device. Driver not also run the device but it also decide that what will do i the device is on ,running and shutdown. From booting of the device to shutdown device need the support of the driver.
Types of device driver:
1. Character driver
2. block driver
3. Network driver/pipe driver
In this article i will talk about character driver. Character-driven drivers are device drivers that operate on characters (bytes) as the basic unit of input and
output. They are accessed in a sequential, nonrandom manner.
We can access the device as the file and operation of file like read, write ,open close and lseek.
Linux kernel have feature that we can add functionality when the system is being running and similarly we can remove some functionality. We can add or remove functionality by mean of piece of code and that piece of code is nothing but the module. When the module is inserted then it works as the part of the Linux kernel.
In short we can add or remove the module. For adding the module i used insmod command and for removing it i used rmmod command.
By doing insmode we can see our module is inserted in the kernel to cross check i used lsmod command and i saw that my module was i the list. As soon as i do rmmod i saw that my module was not there.
Now question comes what is moudle?
As i already told that module in nothing but the piece of code. Every module as at-least two function initialization function and cleanup function.
When the module is inserted by insmode the initialization function does it work and this function is initialized by a macro module_init().
And when we do rmmode the cleanup function does its job and this function is invoked by the module_exit() function .
And one thing we should keep in mind that what we have did in the initialization function we have do remove that in revere order int the cleanup function.
After inserted the module in the kernel i register the my module first by older way register_chrdev(), this function takes three argument major no, driver_name, and a pointer to struct file operations . By giving major number as 0 we do let the kernel to choose the lowest available major number and for unregistering the module i used unregister_chrdev(). It takes two argumnet major number and same device_name.
This method is now obsolete. Now a days developer used new method for registration and unregistration. But if we dig out the code of the old driver we still found that this method is being used.
The newer function to registering the device is alloc_chrdev_region and register_chrdev_region.
The alloc_chardev_region register the module by taking three argument first one is a pointer of dev_t and first minor no which is always 0 third argument is integer number and fourth is the deive name. By using this function we let the kernel to choice available major number.
Same thing is done by register_chrdev_region function but in this we have to provide the major number. It is always advisable that not to choose the major number statically because that major may also be used by the some other driver so a good developer pick the major number dynamically by using alloc_chrdev_region() for very first time . I also used alloc_chredv_region() for the first time and when i get the major number i used that major number in the second function and the number of node (ie how many i want to register the device for that particular driver/module ). The second one also prevent the registration of the same module in the kernel .
Then i declared a user defined structure struct ScullDev{}; this structure has initially it has two member first is pointer to struct scullqset and a varible of type struct cdec.
And the struct ScullQset has the the various member like a void pointer , a pointer itself and lot more like device size,qset size ,quantum size. The void pointer has the that address where our data actually reside.
Next i used cdev_init() and cdev_add() functionn. By using cdev_intit function i initialized the chracter device and by using cdev_add() i inform the kernel.
Before going on this step i understand the some structure like file structure , inode structure, file_operations structure and relation between them.
Then i made a simple application for testing the driver. In which i simply used open ,write,read and close command.
In my driver i mapped the open command to my own open routine same i did for read,write ,close and lseek . And made nod by using mknod of type c and provide this mode major and minor number which i got for the alloc_chrdev_region. By doing this when i run my application using this node and when my application try to open the device it open the device according to my routine.
I made my open routine , close routine and read and write . In this routine i used my own algorithm to read and write and trim .
In write function and also used kmallc function to allocate the memory from kernel space which is physical memory and cop_from_user macro.
And in read routine i track the quantum which is created and used copy_to_user macro.
In open routine i used container_of macro .
Until now i successfully implemented open ,write,read,release ,lseek
and application open the device in write only mode it first to trim. And open the driver after writing some data it will trim all the data and also implemented the driver for other version of read in which it free that quantum that is read.