Linux Device Driver Development Cookbook
上QQ阅读APP看书,第一时间看更新

How it works...

In step 1, As you can see, it's very similar to the kernel module we presented in the previous chapter, even if there are some new include files. However, the most important new entry is the major variable and, in order to understand what it is useful for, we should directly go to the end of the file, where we find the real char driver registration.

In step 2, Again, we have the module_init() and module_exit() functions and macros such as MODULE_LICENSE() (see Chapter 2, A Peek Inside the Kernel, the Working with kernel modules recipe); however, what is really important here is what the chrdev_init() and chrdev_exit() functions effectively do. In fact, chrdev_init() calls the register_chrdev() function, which, in turn, is the one that registers a new char driver into the system, labeling it as chrdev and using the provided chrdev_fops as file operations, while storing the return value into the major variable.

We should take into account this fact because, in case no errors were returned, major is the main reference of our new driver in the system! In fact, the kernel distinguishes one char driver from another by just using its major number (that's why we save it and then we use it in the chrdev_exit() function as a parameter of unregister_chrdev()).

In step 3, Each field then points to a well-defined function, which, in turn, implements the system call body. The only non-function field here is owner, which is just used to point to the module's owner and it's not related to the driver but to the kernel modules management system only.

In step 4Through the means of the preceding code our char driver implements four system calls by using four methods: open(), close() (called as release()), read(), and write(), which are a very minimal (and simple) system calls set we can define into a char driver.

Note that, at this time, all methods simply do nothing! When we issue a  read() system call on our driver, the chrdev_read() method is properly called inside our driver in kernel space (see the next section in order to understand how to exchange data with the user space).

I use both   function  and   method  names interchangeably because all of these functions can be seen as methods in object programming, where the same function names specialize into different steps according to the object they are applied to.
With drivers it is the same: for example, they all have a   read()  method, but this method's behavior changes according to the object (or peripheral) it is applied to.

In step 6Again, the loading out-of-tree module taints kernel message is just a warning and can be safely ignored; please note, however, that the module filename is chrdev_legacy.ko while the driver's name is just chrdev.