Timeline
Timeline
2025-11-09
init
This article introduces the basics of the Linux driver framework, outlines the three fundamental categories of Linux drivers and the kernel source directory structure, and provides a detailed analysis of the essential components, optional information, and related module loading mechanisms of the simplest Linux driver module.
Linux Driver Notes
| Table of Contents | Links |
|---|---|
| 1. Linux Driver Framework | |
| 2. Linux Driver Loading Logic | |
| 3. Character Device Basics | |
| 4. Concurrency and Competition | |
| 5. Advanced Character Device Progression | |
| 6. Interrupts | |
| 7. Platform Bus | |
| 8. Device Tree | |
| 9. Device Model | |
| 10. Hot Plug | |
| 11. pinctrl Subsystem | |
| 12. GPIO Subsystem | |
| 13. Input Subsystem | |
| 14. Single Bus | |
| 15. I2C | |
| 16. SPI | |
| 17. UART | |
| 18. PWM | |
| 19. RTC | |
| 20. Watchdog | |
| 21. CAN | |
| 22. Network Device | |
| 23. ADC | |
| 24. IIO | |
| 25. USB | |
| 26. LCD |
Linux Kernel Related Materials:
https://github.com/0voice/linux_kernel_wiki/blob/main/README.md
Linux Driver Abstraction




Linux divides memory and peripherals into 3 basic categories:Character Device Driver,Block Device Driver,Network Device Driver。
Linux Source Directory Structure
| Directory | Description |
|---|---|
| arch | Architecture-related directory, containing adaptation code for multiple CPU architectures (e.g., ARM, x86, MIPS, etc.) |
| block | Block device-related code directory, managing storage devices such as hard drives and SD cards as block devices in Linux |
| crypto | Cryptographic algorithm directory, containing implementation code for various encryption-related algorithms |
| Documentation | Official Linux kernel documentation directory, containing detailed descriptions of kernel functions, interfaces, etc. |
| drivers | Driver directory, containing driver code for various hardware devices supported by the Linux system |
| firmware | Firmware directory, containing firmware files required by hardware devices |
| fs | File system directory, containing implementation code for file systems such as ext2, ext3, FAT, etc. |
| include | Common header file directory, providing header files shared by various kernel modules |
| init | Kernel boot initialization directory, containing initialization code for the Linux kernel boot phase |
| ipc | Inter-process communication directory, containing implementation code for IPC mechanisms such as pipes, message queues, and shared memory. |
| kernel | Kernel core directory, containing the core functional code of the kernel itself. |
| lib | Library function directory, containing various library functions used by the kernel. |
| mm | Memory management directory (mm stands for memory management), responsible for kernel memory management functions. |
| net | Network-related directory, containing implementation code for network functions such as the TCP/IP protocol stack. |
| scripts | Script directory, containing script files used in processes such as kernel compilation and testing. |
| security | Security-related directory, containing implementation code for kernel security mechanisms. |
| sound | Audio-related directory, containing code for audio device drivers and audio processing. |
| tools | Tools directory, containing tool programs used for Linux kernel development and debugging. |
| usr | Directory related to Linux kernel startup code. |
| virt | Kernel virtual machine-related directory, containing implementation code for kernel-level virtualization functions. |
Analysis of the simplest Linux driver structure
- Components
- Header files (mandatory): The driver must include kernel-related header files, among which
<linux/module.h>and<linux/init.h>are essential. - Driver loading function (required): When loading the driver, this function is automatically executed by the kernel.
- Driver unloading function (required): When unloading the driver, this function is automatically executed by the kernel.
- License declaration (required): Since the Linux kernel follows the GPL license, the driver must also comply with the relevant license when loading. Common license types include GPL v2 and others.
- Module parameters (optional): These are values passed to the kernel module when the module is loaded.
- Author and version information (optional): Used to declare the driver’s author and code version information.
- Header files (mandatory): The driver must include kernel-related header files, among which
- Example
1 |
|
The module will be loaded successfully if and only if the init function in module_init returns a value greater than or equal to 0.
Module information
1 | $ objdump -h hello_world.ko |
The kernel module uses its.modinfosection to store information about the module, and allMODULE_*macros update this section’s content with the values passed as parameters. Some of these macros areMODULE_DESCRIPTION()、MODULE_AUTHOR()andMODULE_LICENSE(). The truly low-level macro provided by the kernel for adding entries to the module information section isMODULE_INFO(tag,info), which adds general information in the form oftag=info. This means driver authors can freely add any form of information they want, for example:
1 | MODULE_INFO(my_field_name, "What eeasy value"); |
.modeinfoThe content of the section:
1 | $ readelf -x .modinfo hello_world.ko |
You can also usemodinfoto view
1 | $ modinfo hello_world.ko |
Compiling a Linux driver
- Placing the driver inside the Linux kernel, then compiling the Linux kernel. Compiling the driver into the Linux kernel.
- Compiling the driveras a kernel module, independent of the Linux kernel
- A kernel module is a special mechanism in the Linux system that cancompile some rarely used or temporarily unused functions into kernel modules, and dynamically load them into the kernel when needed.
- Using kernel modules can reduce the kernel size and speed up boot time. Drivers can also be inserted or removed while the system is running without rebooting. The suffix of kernel modules is .ko
obj-<X>kbuild variable
This actually corresponds toobj- <X>mode, where<X>should be y, m, blank, or n. In general, the makefile at the top of the kernel build system uses it.
1 | obj-y += mymodule.o |
This tells kbuild that there is an object named mymodule.o in the current directory. mymodule.o will be built from mymodule.c or mymodule.S.
How and whether to build or link mymodule.o depends on<X>the value of
- If
<X>is set to m, then the variable obj-m is used, and mymodule.o is built as a module. - If
<X>If set to y, the variable obj-y is used, and mymodule.o will be built as part of the kernel. It can also be said to be a built-in module. - If
<X>is set to n, mymodule.o will not be built at all.
Therefore, it is often usedobj-$(CONFIG_XXX)pattern (whereCONFIG_XXXis a kernel configuration option), which can be set or unset during the kernel configuration process. Here is an example:
1 | obj-$(CONFIG_MYMODULE) += mymodule.o |
$(CONFIG_MYMODULE)evaluates to y or m based on the value during kernel configuration (make menuconfig). IfCONFIG_MYMODULEis neither y nor m, the file will not be compiled or linked.
There is also a case:
1 | obj-<X> += somedir/ |
This means kbuild should enter the somedir directory, find all makefiles in it, and process them to decide which objects should be built.
Compiled as a kernel module
1 | obj-m += hello_world.o |
Local Linux code is under /lib/modules/$(uname -r)/kernel
Compile the driver into the kernel
Indrivers/char(taking a character driver as an example) create a folder helloworld, then put the driver source code into it, and then create a Kconfig file
1 | config helloworld |
Change drivers
1 | emacs ../Kconfig |
Create a Makefile in the driver source code
1 | obj-$(CONFIG_helloworld) += helloworld.o |
Then add the following in the parent directory’s Makefile:
1 | emacs ../Makefile |
Module-related commands
Module loading commands
- insmod
- Function: Load a Linux kernel module
- Syntax: insmod module_name
- Example: insmod hello_world.ko
- modprobe
- Function: Load a kernel module, and also load the modules it depends on
- Syntax: modprobe module_name
- Example: modprobe hello_world.ko
System administrators or those in production systems often use modprobe. modprobe is smarter; it parses the modules.dep file before loading the specified module to load dependencies first. It automatically handles module dependencies, much like a package manager does.
But**
modprobecannot directly load modules from arbitrary paths.kofiles** — it only looks for modules in standard kernel module directories (such as/lib/modules/$(uname -r)/) and relies onmodules.depindex.
Module Unload Command
rmmod
- Function: Remove a kernel module that has been loaded into Linux
- Syntax: rmmod module_name
- Example: rmmod hello_world.ko
modeprobe -r
- It not only attempts to unload
mymodule, but also automatically checks and unloads dependency modules that are only used bymymoduleand are not currently in use by other modules or processes. - Syntax:
modeprobe -r mymodule
- It not only attempts to unload
The enabling or disabling of the kernel module unload feature is determined by the CONFIG_MODULE_UNLOAD configuration option. Without this option, no modules can be unloaded.
At runtime, if unloading a module would cause other adverse effects, the kernel will prevent it even if someone requests the unload. This is becauseThe kernel records the usage count of modules through reference counting, so it knows whether a module is in use. If the kernel considers it unsafe to remove a module, it will not delete it. However, the following settings can change this behavior: MODULE_FORCE_UNLOAD=y
Setting modules to load at boot
If you want to load some modules at boot, simply create a file/etc/modules-load.d/<filename>.conf, and add the names of the modules to be loaded (one per line). People commonly use modules:/etc/modules-load.d/modules.conf. Of course, you can also create multiple .conf files as needed.
1 | emacs /etc/modules-load.d/mymodule.conf |
Command to view module information
- lsmodCommand
- Function: List kernel modules already loaded in Linux
- You can also use the command cat /proc/modules to check if a module has been loaded successfully
- modinfoCommand
- Function: View kernel module information
- Syntax: modinfo module_name
- Example: modinfo hello_world.ko
Configuration file
menuconfigConfigure driver option state operations:
Driver state:
- Compile the driver as a kernel module, represented by M
- **Compile the driver into the kernel, represented by ***
- Do not compile
Use the spacebar to toggle among these three states.
The states of options are:
[]: Indicates two states, can only be set to selected or not selected<>: Indicates three states, can be set to selected, not selected, or compiled as a module- () : Indicates used to store strings or hexadecimal numbers
Kconfig file
The Kconfig file is the source file for the graphical configuration interface; the options in the graphical configuration interface are determined by the Kconfig file. When we execute the commandmake menuconfigcommand, the kernel configuration tool reads thearch/xxx/Kconfig. xxx is the value of ARCH, such as arm64, and then generates the corresponding configuration interface for developers to use.
config file and .config file
Both the config file and the .config file are configuration files for the Linux kernel.
The config file is located in the arch/$(ARCH)/configs directory of the Linux kernel source code, and isthe default configuration file for the Linux system。.
The .config file is located in the top-level directory of the Linux kernel source code. When compiling the Linux kernel, the configuration in the .config file is used to compile the kernel image.
If .config exists, the default configuration in the make menuconfig interface is the configuration of the current .config file. If settings in the graphical configuration interface are modified and saved, the .config file will be updated.
If the .config file does not exist, the default configuration in the make menuconfig interface is the default configuration in the Kconfig file.
Using the command make xxx_defconfig will generate a .config file based on the default file in the arch/$(ARCH)/configs directory.
Kconfig syntax
Reference:
Main menu
mainmenuUsed to set the title of the main menu
Example:mainmenu "Linux/\$(ARCH) $(KERNELVERSION) Kernel Configuration"
The menu name set by the above name isLinux/\$(ARCH) $(KERNELVERSION) Kernel Configuration
Menu structure
You can use menu/endmenu to generate a menu. menu is the marker for the start of a menu, and endmenu is the marker for the end of a menu. These two appear in pairs.
The following describes a menu named: “Network device support”
1 | menu "Network device support" |
Configuration options
Use the keywordconfigto define a new option. Each option must specify a type, and the types includebool, tristate, string, hex, int. The most common ones are bool, tristate, and string.
The bool type has two values: y and n;
The tristate type has three values: y, m, and n;
string is the string type.
help indicates help information. When we press the h key in the graphical interface, the content of help pops up.
Example:
1 | config helloworld |
Dependencies
Dependencies in Kconfig can use depends on and select
depends on indicates a direct dependency:
1 | config A |
It means option A depends on option B; only when option B is selected can option A be selected
select indicates a reverse dependency:
1 | config A |
When option A is selected, option B is automatically selected
Optional options
Use choice and endchoice to define selectable items
1 | choice |
Comment
Display a comment in the graphical configuration interface
1 | config TEST_CONFIG |
souce
source is used to read another Kconfig file, for example, source “init/Kconfig” reads the Kconfig file in the init directory into the current Kconfig file
Driver module parameter passing
Significance of driver parameter passing:
Advantages:
- Driver parameter passing makes the driver more flexible and compatible.
- Security checks can be set via driver parameter passing to prevent driver theft
Disadvantages
- Complicates the driver code
- Increases driver resource usage
Parameter types that can be passed to a driver
Most data types commonly used in C language are supported by the kernel for driver parameter passing. Here, the parameter types supported by the kernel for driver passing are divided into three categories:
- Basic types:char, bool, int, long, short, byte, ushort, uint
- Array:array
- String:string
Methods for passing parameters to Linux drivers
Parameter types and corresponding functions
Parameter type Corresponding function Functionality Basic type module_paramPass basic type parameters Array type module_param_arrayPass array type parameters String type module_param_stringPassing a string type parameter Function definition location: These three functions are in the Linux kernel source code’s
include/linux/moduleparam.hdefined in.
module_param
1 | /** |
module_param_array
1 |
|
module_param_string
1 | /** |
MODULE_PARM_DESC
Function purpose: Describes module parameter information. Defined in include/linux/moduleparam.h
Function prototype:MODULE_PARM_DESC(_parm, desc)
Function parameters:_parm: The parameter name of the parameter to be described. desc: Description information
| Parameter name | Meaning |
|---|---|
name | Parameter name (can be passed via command line) |
type | Parameter type (e.g.,int、bool、charp) |
perm | in/sys/module/<modname>/parameters/permissions in, such as0644 |
nump | (array only) Variable address storing the number of array elements |
len | (string only) buffer length |
string | pointer to string buffer |
permission definition
permrefers toparameter file in sysfs’sfile permission bits。
read/write permissions are defined ininclude/linux/stat.handinclude/uapi/linux/stat.h.
- include/linux/stat.h
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
- include/uapi/linux/stat.h
1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ |
the relevant permissions are mainlyfile access permission macros (File Permission Bits)
| macro name | octal value | meaning |
|---|---|---|
S_IRWXU | 00700 | Owner (U) read, write, execute permissions (RWX) |
S_IRUSR | 00400 | Owner (USR) read permission ® |
S_IWUSR | 00200 | Owner (USR) write permission (W) |
S_IXUSR | 00100 | Owner (USR) execute permission (X) |
S_IRWXG | 00070 | Group (G) read, write, execute permissions (RWX) |
S_IRGRP | 00040 | Group (GRP) read permission ® |
S_IWGRP | 00020 | Group (GRP) write permission (W) |
S_IXGRP | 00010 | Group (GRP) execute permission (X) |
S_IRWXO | 00007 | Others (O) read, write, execute permissions (RWX) |
S_IROTH | 00004 | Others (OTH) read permission ® |
S_IWOTH | 00002 | Others (OTH) write permission (W) |
S_IXOTH | 00001 | Others (OTH) execute permission (X) |
AlsoCombined permissions
S_IRWXUGO
- Definition:
(S_IRWXU | S_IRWXG | S_IRWXO) - Meaning (expanded):
00700 | 00070 | 00007 = 00777 - Actual meaning: AllowOwner, group, other users(UGO) haveread, write, executepermissions
- Example usage: Set all users to read, write, execute, e.g., temporary directory
/tmp
S_IALLUGO
- Definition:
(S_ISUID | S_ISGID | S_ISVTX | S_IRWXUGO) - Meaning (expanded):
0004000 | 0002000 | 0001000 | 00777 = 01777 - Actual meaning: Includes special bits (SUID, SGID, Sticky) and all users’ read, write, execute permissions
- Example usage: Common permissions:
drwxrwxrwt(e.g.,/tmp)
S_IRUGO
- Definition:
(S_IRUSR | S_IRGRP | S_IROTH) - Meaning (expanded):
00400 | 00040 | 00004 = 00444 - Practical meaning: All usersreadpermission
- Example usage: Commonly used for read-only files
S_IWUGO
- Definition:
(S_IWUSR | S_IWGRP | S_IWOTH) - Meaning (expanded):
00200 | 00020 | 00002 = 00222 - Practical meaning: All userswritepermission
- Example usage: Rarely used, generally limited to specific directories
S_IXUGO
- Definition:
(S_IXUSR | S_IXGRP | S_IXOTH) - Meaning (expanded):
00100 | 00010 | 00001 = 00111 - Practical significance: EveryoneExecutepermission
- Example usage: Make a script or program executable by everyone
Example
1 |
|
Parameters can be passed when loading the module:
1 | insmod parameter.ko myint=42 mycharp="hello world" myarr=9,8,7 mystr="hello" |
View parameters at runtime:
1 | cd /sys/module/parameter/parameters/ |
Kernel symbol table import and export
Drivers can be compiled into kernel modules, i.e., KO files. Each KO file is independent, meaning modules cannot access each other. However, in some usage scenarios, they need to access each other, such as when module B needs to use a function from module A. (Module B depends on module A)
Symbol table
**“Symbols” refer to function names, global variable names, etc., in the kernel.**A symbol table is a file used to record these “symbols”.
Module dependency relationship
Modules in the Linux kernel can provide functions or variables, which areEXPORT_SYMBOLexported via macros for use by other modules; these are called symbols.
The dependency of module B on module A means that module B uses symbols exported from module A.
depmodis a user-space tool (usually provided by thekmodpackage), run after kernel installation:
1 | depmod -a <kernel_version> |
- It scans all
/lib/modules/<kernel_release>/module files under.ko:- Using
modinfo -F dependsor directly parsing the ELF symbol table; - Determine each moduleWhich symbols are needed (imports)andWhich symbols are provided (exports);
- Build a dependency graph between modules.
- Using
Generated dependency files
| File | Purpose |
|---|---|
modules.dep | Text format, each line format:module.ko: dependent_module1.ko dependent_module2.ko ... |
modules.dep.bin | Binary format, formodprobeFast loading (avoids parsing text each time) |
modules.symbols/modules.symbols.bin | Records all exported symbols and their modules (for reverse lookup) |
depmod also processes module files to extract and collect this information, and in/lib/modules/<kernel_release>/modules.aliasgenerates the modules.alias file, which maps devices to their corresponding drivers.
modprobe parses the modules.alias file.
Kernel symbol table export
Export Macro
| Macro Name | Applicable Scenario |
|---|---|
EXPORT_SYMBOL | Export Symbols to Kernel Symbol Table |
EXPORT_SYMBOL_GPL | Only Applicable to Modules with GPL License |
Exported symbols can be used by other modules; simply declare them before use.
Example
1 |
|
Import
1 |
|
Note: When loading, load the exporting module first; when unloading, unload the importing module first.Because the two modules now have a dependency relationship, modprobe will handle these dependencies automatically without explicit declaration.
Using Macros Defined in Makefile
Core idea: To make itvisible to C code, it must bepassed as a macro definition via the compiler command line:
1 | cc -D宏名=值 source.c |
Example:
1 | obj-m += mydriver.o |
Other variable names:
| Variable Name | Scope | Typical Use |
|---|---|---|
ccflags-y | All of the current module.cFiles | Common C compilation options |
asflags-y | Assembly files | Assembly parameters |
subdir-ccflags-y | Current directory and subdirectories | Global scope |
KBUILD_CFLAGS | Global (set by kernel top-level Makefile) | Platform-level CFLAGS |
KBUILD_CFLAGS_MODULE | Kernel module | |
EXTRA_CFLAGS | Deprecated (legacy usage) | Temporary additional options |
Then in the driver, you can use:
1 |
|

