Whenever you want to add something to the kernel code, there are two options – either add your code to the kernel code and compile/build the entire kernel image or compile your code separately and add it to the kernel image later. The first one is the earlier approach that was followed. But, considering the advantages that the second approach provides, it is better to go with it. Let us understand it with the help of an example.
Consider that you have a requirement of writing a new device driver code for your hardware. Now, you write your code, compile and build it separately. This code piece is known as a kernel module. Then you “insert” this module using standard commands(like insmod, modprobe etc.) when you need the hardware to support your driver functionality. And, when you are done, and have no use of the same, you can “remove” the module. Isn’t it easy than compiling your code with the entire kernel which is a tedious task especially if the additions/changes are small. The following are the main advantages provided by this “easy” approach:-
- No need to compile and build entire kernel code again and again.
- Insertion and removal of your code as and when required.
- Debugging becomes easy when it’s limited to your piece of code.
Major Number is a unique number that is used to identify a device driver. Kernel uses this number to identify the corresponding driver so that when a user-space application opens a device file, the kernel searches for the registered driver and passes the call to it.
A device driver can handle multiple devices for example, a single USB driver responds to multiple ports on your PC. To differentiate between multiple devices accessing the same driver, kernel uses minor number. Two or more devices can have same major number (if they are associated with the same driver) but not same minor number.
In a nutshell, minor number specifies the device and major number identifies the driver. These both numbers come into picture while writing a device driver.
The datatype that kernel uses for major and minor numbers is dev_t that is defined inside the file <linux/types.h>. The dev_t type is 32 bits wide in which 12 bits are used for major number and the rest 20 bits are used for minor number. These numbers are accessed by the following macros defined inside the file <linux/kdev_t.h>.
The function call below is used to register a character driver with the kernel and uses the major number also as its arguments.
int register_chrdev(unsigned int major, const char* name, struct file_operations fops);