The development of Linux drivers is quite different from the development of application programs. These differences lead to the essential distinction between writing Linux device drivers and writing application programs.
The Linux operating system is divided into user mode and kernel mode. The kernel mode completes interactions with hardware, such as reading and writing memory and loading data from the hard disk into memory. Driver programs interact with hardware at a low level, thus operating in kernel mode. User mode can be understood as the upper-level application programs, which can be Java applications, Qt applications, Python applications, etc. The reason for dividing the Linux operating system into two states is that even if an application in user mode encounters an exception, it will not cause the operating system to crash, thanks to the strong protective capabilities of the kernel mode over the operating system.
On the other hand, the main reason for dividing the Linux operating system into two states is to provide application programs with a unified abstraction of computer hardware. Application programs working in user mode do not need to consider low-level hardware operations, which are handled by the kernel mode programs. Most of these kernel mode programs are device drivers. Application programs can operate hardware devices effectively without understanding the working principles of the hardware, while also preventing the hardware devices from entering an illegal state.
It is worth noting that user mode and kernel mode can be converted to each other. Whenever an application executes a system call or is suspended by a hardware interrupt, the Linux operating system switches from user mode to kernel mode; when the system call is completed or the interrupt handling is done, the operating system returns from kernel mode to user mode to continue executing the application.
A module is code that can be added to the kernel at runtime, which is a great feature of Linux. This feature allows the kernel to easily expand or shrink. Expanding the kernel can increase its functionality, while shrinking the kernel can reduce its size. The Linux kernel supports various modules, with device drivers being one of the most important. Each module consists of compiled object code, which can be added to the running kernel using the insmod
command and removed from the kernel using the rmmod
command.
Modules loaded when the kernel starts are called statically loaded, while those loaded when the kernel is already running are called dynamically loaded. Modules can extend any functionality expected by the kernel but are typically used to implement device drivers.
The most basic framework code for a module is as follows:
To master Linux driver development, one must deeply understand the Linux bus device driver framework. The reason for forming this framework is mainly for code reusability, as the relationship between drivers and devices is one-to-many. Just as there is a distinction between major and minor device numbers, the major device number represents the driver program, while the minor device number represents a specific device.
Additionally, this framework aims to improve the portability of drivers. Linux separates the resources (such as GPIO and interrupts) required by drivers for management by the device. This means that the device contains its own device attributes as well as the resources used to connect to the SOC. The driver focuses on the process and methods of operation.
The role of the bus is to manage devices and drivers at the software level. For a device to let the system perceive its existence, it needs to register itself with the bus; similarly, for a driver to let the system perceive its existence, it also needs to register itself with the bus. Both the device and the bus must clearly define which type of bus they belong to during initialization. Therefore, to achieve operational consistency, Linux has invented a virtual bus called the Platform bus.
When multiple devices and multiple drivers are registered on the same bus, how does a device find the most suitable driver for itself, or how does a driver find the devices it supports? This responsibility also falls to the bus, which acts like a matchmaker, connecting devices and drivers. Devices will present their conditions for drivers to the bus (the simplest and most precise condition is to specify the name of the driver), while drivers will inform the bus of the conditions of the devices they can support (usually model IDs, or simply the device name).
When a device registers, the bus will traverse the drivers registered on it to find the most suitable driver for this device and fill it into the device’s structure members; when a driver registers, the bus will also traverse the devices registered on it to find the devices it supports (which can be multiple, as the relationship between drivers and devices is 1:N), and fill the devices into the driver’s support list. We refer to this matchmaking behavior of the bus as match. After the match is made, the interaction between the device and driver is no longer the concern of the matchmaking bus.
Regularly share embedded knowledge in an easy-to-understand manner,follow the public account, star it, and make progress every day.
Statement:
This account’s original articles, images, etc., are copyrighted to the original author. If there is any infringement, please contact us for removal.

