Getting started with Linux drivers (4) - building the first driver


foreword

开发板以STM32MP157为例进行实验.
Everything is difficult at the beginning, and so is writing a driver. This chapter will build the first driver. The relationship between the driver and the module is very close, so the relevant knowledge of the module will be explained in detail here. The prerequisite for the success or failure of module programming is to have a unified kernel version, so here will explain how to upgrade the kernel version. Finally, in order to improve the programming efficiency of programmers, two integrated development environments will be introduced here.

Kernel upgrade for development environment configuration

Building a correct development environment is very important for writing drivers. In the wrong development environment, the written driver cannot run correctly. Especially regarding the kernel version, if the kernel version does not match, the driver cannot run in the system, so the meshing needs to be upgraded. 实际以STM32MP157为例, the reference tutorial takes ``Fedora Core9 as an example to upgrade the kernel. Pay attention to the distinction. First, explain why the kernel needs to be upgraded.

Why upgrade the kernel

内核时一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。According to whether the kernel has been modified, the kernel can be divided into 标准内核和厂商内核two categories, as shown in the figure below.
insert image description here
标准内核源码和标准内核
The standard kernel source code refers to kernel.orgthe standard code downloaded from the official website. It is the kernel code built by Linux kernel developers after rigorous testing. The standard kernel is the binary image file obtained after compiling the standard kernel source code, as shown in the left half of the figure above.
厂商内核源码和厂商内核
In some cases, distribution vendors make appropriate changes to the standard kernel source code to optimize the kernel's performance. This modified standard kernel source code is the kernel source code modified by the manufacturer. After compiling the kernel source code modified by the manufacturer, the kernel of the manufacturer's release version will be formed. So, the vendor distribution kernel is a modification and optimization of the standard kernel. Here, 需要注意的是,厂商发行版内核和标准内核对于驱动程序是不兼容的,根据不同内核源码编译的驱动程序是不能互用的。
两者兼容性问题
when building a driver module, the compatibility of the driver with the kernel must be considered. A kernel module built using standard kernel sources is a standard kernel module, which cannot be used in a vendor kernel. The kernel module built using the kernel source code modified by the manufacturer is the manufacturer's kernel module, which cannot be used in the standard kernel. Here, you can check the kernel version used 需要注意的是,即使模块代码相同,标准内核模块和特定厂商的内核模块,其模块格式也是不相同的。
by command.uname -r

kernel upgrade

Although many development boards can use the "package manager tool" to upgrade the kernel, after all, the kernel compiled by the developer has its limitations, and many modules that are not needed by the driver development system are added in it. module is not enabled. Therefore, it is also necessary to learn to manually compile and upgrade by yourself. For example, the steps to upgrade a kernel to linux 2.6.39.4a kernel upgrade are as follows:

  1. http://www.kernel.org/pub/linux/kernelDownload the kernel source package from above linux-2.6.29.4.tar.bz2.
  2. mkdir linux-2.6.29.4Create a directory in the root directory using
  3. Copy the tarball into the created directory
  4. Enter the directory to decompress the source package
  5. Enter the second-level source code directory
  6. Execute make menuconfigconfigure kernel and save. ——For details, please refer to the characteristics of the manufacturer or development board
  7. Compile the kernel makecommand
  8. Compile the kernel modulemake modules
  9. Install kernel modulesmake modules_install
  10. install kernelmake install
  11. Use rebootrestart the computer, select the new kernel to start the system.
    After the kernel is upgraded successfully, you can uname -rcheck the kernel version by command.
    To save time, you can write a shell program. code show as below:
#! /bin/sh
cd /
mkdir linux-2.6.29.4
cp linux-2.6.29.4.tar.bz2 /linux-2.6.29.4/
cd linux-2.6.29.4
tar -xjvf linux-2.6.29.4.tar.bz2
cd linux-2.6.29.4
make menuconfig
make
make modules
make modules_install
make install
reboot

The shell file does not have executable permission, you need to use the command chmodto make the shell file have executable permission, the command is as follows:

chmod a+x install-new-core

Then execute the shell file to automatically upgrade the kernel, use the following command:

./install-new-core

注意:对内核的升级并不会破坏现有的内核,也不会破坏系统上的文件等资源。内核升级以后,除了性能上的改变外,对用户来说就像什么也没有发生一样

Hello world driver

This section will lead readers to write the first driver module, the function of which is to output "Hello World" when loading; output "Goodbye World" when unloading. Although the driver module is simple, it also contains the important components of the driver module. At the beginning of this section, the important components of the module will be introduced.

Composition of the drive module

A driver module is mainly composed of the following parts:
insert image description here
图中的顺序也是源文件中的顺序。不按照这个顺序来编写驱动模块也不会出错,只是大多数开发人员都喜欢这样的顺序规范。These structures are described below.
1、头文件(必须)
The driver module uses many functions in the kernel, so the necessary header files need to be included. 有两个头文件是所有驱动模块都必须包含的.

#inlcude <linux/module.h>
#inlcude <linux/init.h>

module.hThe file contains a large number of symbols and function definitions needed to load the module. init.hContains the macro definition of the module load function and release function.
2、模块参数(可选)
Module parameters are parameters that need to be passed to the driver module when the driver module is loaded. If a drive module needs to complete two functions, then you can choose which function to use through the module parameters.
3、模块加载函数(必须)
The module loading function is a function that needs to be executed when the module is loaded.
4、模块卸载函数(必须)
The module unload function is the function that needs to be executed when the module is unloaded. The module
5、模块许可声明(必须)
license statement indicates the degree to which the module is supported by the kernel. Modules with permissions will be more valued by developers. Requires MODULE_LICENSEpermission to use that represents the module. The permissions recognized by the kernel are as follows:

MODULE_LICENSE("GPL");   /*任一版本的GNU公告许可权*/
MODULE_LICENSE("GPL v2"); /* GPL版本2许可权*/
MODULE_LICENSE("GPL and additional rights"); /*GPL及其附加许可权*/
MODULE_LICENSE("Dual BSD/GPL"); /*BSD/GPL双重许可权*/
MODULE_LICENSE("Dual MPL/GPL"); /*MPL/GPL双重许可权*/
MODULE_LICENSE("Proprietary"); /*专有许可权*/

If a module does not contain any permissions, it is considered non-compliant. At this time, when the kernel loads such a module, it will receive a warning that the kernel loads a non-standard module. Developers don't like maintaining kernel modules that don't follow the standard permissions.
Take the GPL as an example to illustrate the meaning of license rights. GPL is the abbreviation of General Public License, which means General Public License. The GNU General Public License guarantees your freedom to distribute free software; guarantees that you can receive the source program or get it when you need it; guarantees that you can modify the software or use parts of it in new free software.

Hello World module

Almost any book about programming starts with "Hello World". Now, let's look at the simplest driver module.

#include <linux/init.h>   /*定义了一些相关的宏*/
#include <linux/module.h> /*定义了模块需要的*/
static int hello_init(void)
{
    
    
	printk(KERN_ALERT "Hello World\n"); /*打印 Hello World*/
	return 0;
}
static void hello_exit(void)
{
    
    
	printk(KERNEL_ALERT "Goodbye World\n"); /*打印Goodbye World*/
}
module_init(hello_init);   /*指定加载模块函数*/
module_exit(hello_exit);   /*指定模块卸载函数*/
MODULE_LICENSE("Dual BSD/GPL"); /*指定许可权为Dual BSD/GPL*/

Source code analysis:

  • Lines 1~2 are two necessary header files
  • Lines 3~7 are the loading function of the module, insmodwhich will be called when the module is loaded with the command.
  • Lines 8~11 are the release function of the module, which rmmodwill be called when the module is uninstalled with the command
  • Line 12 module_initis a macro of the kernel module. It is used to declare the loading function of the module, that is, insmodthe function called when the module is loaded using the command hello_init().
  • Line 13 module_exitis also a macro of the kernel module. Used to declare the release function of the module, that is, rmmodthe function called when the module is unloaded with the command hello_exit().
  • Line 14, using MODULE_LICENSE()the specification that the code follows, the module code follows the dual specification of BSD and GPL. These specifications define copyright issues in the distribution of modules.

Compile the Hello World module

When compiling the Hello World module, certain conditions need to be met.
1、编译内核模块的条件
Correctly compiling a kernel module meets some important prerequisites:
I. The reader should make sure to use the correct versions of the build tools, module tools, and other necessary tools. Different versions of the kernel require different versions of compilation tools.
II. There should be a kernel source code, and the version of the source code should be consistent with the kernel version currently used by the system.
III. The kernel source code should be compiled at least once, that is, makethe command has been executed.
2、Makefile文件
Compiling the Hello World module requires writing a Makefilefile. Let's take a look at a complete Makefile first, so as to have an overall understanding of the file.

ifeq ($(KERNELRELEASE),)
	KERNELDIR ?= /linux-2.6.29.4/linux-2.6.29.4
	PWD := $(shell pwd)
modules:
	$(MAKE) -C $(KERNELDIR) M= $(PWD) modules
modules_install:
	$(MAKE) -C $(KERNELDIR) M= $(PWD) modules_install
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
	obj-m := hello.o
endif

Makefile analysis

  • 1 line, to determine KERNELRELEASEwhether the variable is empty, the variable is a string describing the kernel version. Only makewhen the current directory where the command is executed is the kernel source code directory, this variable is not a null character.
  • Lines 2~3 define KERNELDIRand PWDvariables. KERNELDIRIs the kernel path variable, which is the current module path obtained PWDby executing the command.pwd
  • Line 4 is an identifier, ending with a colon, which identifies a functional option of the Makefile.
  • The syntax of line 5 makeis "Make -C kernel path M=module path modules". This statement executes the compilation of the kernel module
  • The 6-line and 4-line marks have the same meaning.
  • Line 7 is to install the module into the path corresponding to the module. When the command is executed make modules_install, the command is executed, and it is not executed at other times.
  • Line 8 is to delete redundant file identifiers
  • Line 9 is the command to delete the intermediate files of the compilation process
  • Line 11, 意思是将hello.o编译成hello.komodule. If you want to compile other modules, just change hello.oin helloto the file name of the module.

3、Makefile文件的执行过程
The execution process of the Makefile is somewhat complicated. In order to give readers a clear understanding of the execution process of the file, the following figure is used for analysis.
insert image description here
After executing makethe command, the Makefile will be entered. At this time KERNELRELEASE, the variable is empty, and it is the first to enter the Makefile at this time. After executing 2 or 3 lines of code, makedifferent logic will be executed according to the parameters of the command, as follows:

  • make modules_installcommand, will execute lines 6 and 7 to install the module into the operating system.
  • make cleancommand, which deletes all temporary files in the directory
  • makeThe command will execute 4 or 5 lines to compile the module. $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesThe option in the first -C $(KERNELDIR)will make the compilation enter the kernel source code directory /linux-2.6.29.4/linux-2.6.29.4, read the Makefile file, and get some information from it, such as variables KERNELRELEASEwill be assigned here. After reading the Makefile in the kernel source code directory, the compiler will M=$(PWD)enter the directory where the module is located for the second time according to the options, and execute the Makefile again. When the second Makefile is executed, the KERNELRELEASEvalue of the variable is the kernel release version information, that is, it is not empty. At this time, lines 10, 11, and 12 of the code will be executed. The code here indicates the dependencies of each file in the module source code and the name of the target module to be generated. Here, the module is officially compiled.

Module operation

Linux provides modutilstools for users to manipulate modules. This toolset mainly includes:

  • insmodcommand to load the module. Use insmod hello.koloadable hello.komodules. The function is called automatically after the module is loaded hello_init(). This function prints the "Hello World" message. If you don't see the message in the terminal, the message was sent to /var/log/messagethe file. You can use demsg | tailthe command to view the last few lines of the file. If the module has parameters, the following format can be used to pass parameters to the module:insmod 模块.ko 参数1=值1 参数2=值2 参数3=值3 /*参数之间没有逗号*/
  • rmmodcommand to unload a module. rmmod hello.koExecution can unload the module if it is not being used hello.ko.
  • modprobeThe command is a relatively advanced load and delete module command, which can solve the dependency problem between modules. Will be introduced later.
  • lsmodThe command lists the loaded module information. insmod hello.koYou can know hello.kowhether the module is loaded by executing this command before and after.
  • modinfoThe command is used to query module-related information, such as author, copyright, etc.

File system changes after the Hello World module is loaded

insmod hello.koWhat happens to the file system when the module is loaded ? The file system stores attribute information about modules. Programmers can know the current state of the module in the system from these attribute information, and these states are very important for development and debugging.
/proc/modules发生变化,在modules文件中会增加如下一行:
insert image description here
The information in these fields is the module name, memory used, reference count, delimiter, activity status, and address loaded into the kernel.
lsmodThe command /proc/moduleslists the module information currently loaded by the kernel by reading the file. lsmodRemoved some information and made the display more tidy. lsmodThe structure of the execution command is as follows:
insert image description here
/proc/devices文件没有变化,因为hello.ko模块并不是一个设备模块.
在/sys/module/目录会增加hello这个模块的基本信息
在/sys/module/目录下会增加一个hello目录。该目录中包含了一些以层次结构组织的内核模块的属性信息。使用tree -a hello目录可以得到下面的目录结构.
insert image description here

Module parameters and communication between modules

In order to increase the flexibility of the module, parameters can be added to the module. Module parameters can control the internal logic of the module. In this way, the module can perform different functions under different circumstances. The module parameters are firstly introduced below.

module parameters

Applications for space can accept user parameters, and device drivers sometimes need to accept parameters. For example, a module can implement two similar functions. At this time, a parameter can be passed to the driver module to determine which function it uses. The parameters need to be specified when loading the module, for example, insmod xxx.ko param=1
you can use "module_param(parameter name, parameter data type, parameter read and write permission)" to define parameters for the module. For example, the following code defines a long integer and an integer parameter:

static long a = 1;
static int b = 1;
module_param(a, long, S_IRUGO);
module_param(b, int , S_IRUGO);

The parameter data type can be byte、short、ushort、int、uint、long、ulong、bool、charp(字符指针类型). Careful readers can see that there is no floating-point type among the types of module parameters. This is because the kernel does not perfectly support floating-point operations. When using floating-point numbers in the kernel, there are some trivial things to do besides manually saving and restoring floating-point number registers. As an example to avoid trouble usually do not use floating point numbers in the kernel. In addition, printk()the function does not support floating point types.

Module file format ELF

Knowing what format the modules are stored on the hard disk is necessary to understand how the modules communicate with each other. You can use filethe command to know the file format hello.koused by the module ELF. The command is as follows:
insert image description here
This command is often used in the development of linux drivers, please pay attention to its usage.
The figure below describes the overall structure of the ELF object file. In the figure, some cumbersome structures of ELF are omitted, and the main structure is extracted to form the basic structure diagram of the ELF file shown in the figure below.
insert image description here

  1. ELF HeaderThe header is at the very front of the file. It contains the basic attributes describing the entire file, such as ELF file version, target machine model, program entry address, etc.
  2. .textIndicates the code segment, which stores the code part of the file.
  3. .dataRepresents the data segment, storing initialized data, etc.
  4. .Section TableThe table describes the information of all segments contained in the ELF file, such as the segment name of each segment, the length of the segment, the offset in the file, read and write permissions, and other attributes of the segment.
  5. .symtabRepresents a symbol table. A symbol table is a data structure that maps functions to real memory addresses. It is like a dictionary, which records functions whose addresses cannot be determined during the compilation phase. The symbol table will be assigned a real memory address by the system during the module file loading stage.

Communication between modules

Modules are designed to accomplish a specific task. Its function is relatively simple, in order to enrich the function of the system, so the communication between the modules is often carried out. They can share variables and data structures, and can also call functions provided by each other.
As shown in the figure below, analyze how module 1 calls the function of module 2. In order to clarify this process, we need to start with the loading of module 2.
insert image description here
The loading process of module 2 is as follows:
(1) Use insmod 模块2.koloading block 2
(2) The kernel allocates space for module 2, and then loads the code and data of the module into the allocated memory.
(3) The kernel finds that function 1 and function 2 can be exported in the symbol table, so 将其内存地址记录在内核符号表中.
When module 1 is loaded into the kernel, the system will perform the following operations:
(1) insmodThe command will allocate space for the module, and then load the code and data of the module into the memory. (2) The kernel found some unresolved functions in
the symbol table ( ) of module 1 . symtabThese unanalyzed functions in the figure above are "function 1" and "function 2", and these functions are located in the code of module 2. Therefore, module 1 will find the corresponding function through the kernel symbol table, and fill the function address into the symbol table of module 1.
After passing the loading process of module 1, module 1 can use "function 1" and "function 2" provided by module 2.

Example of communication between modules

This example introduces the communication between modules through two modules. The module add_subprovides two exported functions add_integer()and sub_integer(), which respectively complete the addition and subtraction of two numbers. The module testis used to debug add_subthe two methods provided by the module to complete the operation of addition or subtraction.
1、add_sub模块
An addition function and a subtraction function are provided in the module add_sub, and its add_sub.c file is as follows:

#inlcude <linux/init.h>
#include <linux/module.h>
#include "add_sub.h" 
long add_integer(int a, int b)
{
    
    
	return a+b;
}
long sub_integer(int a, int b)
{
    
    
   return a-b;
}
EXPORT_SYMBOL(add_integer);        	/*导出加法函数*/
EXPORT_SYMBOL(sub_integer);          /*导出减法函数*/
MODULE_LICENSE("Dual BSD/GPL");

This file defines an addition and subtraction function, which 两个函数需要导出到内核符号表can be called by other modules. EXPORT_SYMBOLJust export the macro. The function of this macro is to let the kernel know that the function it defines can be used by other functions.
Using EXPORT_SYMBOLmake a function as an exported function is convenient, but not casual. There are millions of lines of code and tens of thousands of functions in a Linux kernel source code, and functions with the same name are likely to appear in modules. Fortunately, the compiler thinks that the functions in the module are private, and the same function name in different modules will not affect the compilation, provided that the export EXPORT_SYMBOLsymbols cannot be used.
In order to test the functionality of the module add_sub, another test module is created here. The test module needs to know which functions are provided by the add_sub module, so a add_sub.hheader file is defined, the code is as follows:

#ifndef _ADD_SUB_H_
#define _ADD_SUB_H_
long add_integer(int a, int b);
long sub_integer(int a, int b);
#endif

2、test模块
The test module is used to test the two methods provided by the add_sub module, and the test module can also accept one AddOrSubto decide whether to call add_integer()a function or sub_integer()a function. When AddOrSubit is 1, add_integer()the function is called; when AddOrSubit is not 1, sub_integer()the function is called. The code of the test module is as follows:

#include <linux/init.h>
#include <linux/module.h>
#include "add_sub.h"      		/*不要使用<>包含文件,否则找不到该文件*/
/*定义模块传递的参数a, b*/
static long a = 1;
static long b = 1;
static int AddOrSub = 1;
static int test_init(void)     /*模块加载函数*/
{
    
    
	long result = 0;
	printk(KERN_ALERT "test init\n");
	if(1==AddOrSub)
	{
    
    
		result=add_integer(a, b);
	}
	else
	{
    
    
		result=sun_integer(a, b);
	}
	printk(KERN_ALERT "The %s result is %ld", AddOrSub==1?"Add":
	"Sub", result);
	return 0;
}
static void test_exit(void)     /*模块卸载函数*/
{
    
    
	printk(KERN_ALERT "test exit\n");
}
module_init(test_init);
module_exit(test_exit);
module_param(a, long, S_IRUGO);
module_param(b, long, S_IRUGO);
module_param(AddOrSub, int, S_IRUGO);
/*描述信息*/
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Jacky Hu");
MODULE_DESCRIPTION("A module for testing module params and EXPORT_SYMBOL");
MODULE_VERSION("V1.0");

3、编译模块
Compile the two modules separately to obtain two module files. add_subThe Makefile of the module is different from the Makefile of the Hello World module. In add_subthe Makefile of the module, the variable PRINT_INCrepresents add_sub.hthe directory where the file is located, and the file declares the prototypes of the add_integer() function and the sub_integer() function. EXTRA_CFLAGSThe variable indicates the directory that needs to be added when compiling the module. The compiler will find the required header files from these directories. add_subThe Makefile of the module is as follows:

ifeq($(KERNELRELEASE),)
	KERNELDIR ?=/linux-2.6.29.4/linux-2.6.29.4
	PWD := $(shell pwd)
	PRINT_INC = $(PWD)/../include
	EXTRA_CFLAGS += -I $(PRINT_INC)
modules:
	$(MAKE) -I $(PRINT_INC) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_version
.PHYONY:modules modules_install clean
else
	#called from kernel build system: just declare what our modules are
	obj-m := add_sub.o
endif

The Makefile of the test module is shown in the following code. SYMBOL_INCis the include directory, which contains the add_sub.hheader files. This file defines two functions that are called in the test module. KBUILD_EXTRA_SYMBOLSContains add_subthe symbol table file generated when compiling the module Module.symvers, which lists add_subthe address of the function in the module. This symbol table is required when compiling the test module.

obj-m := test.o
KERNELDIR ?= /linux-2.6.29.4/linux-2.6.29.4
PWD := $(shell pwd)
SYMBOL_INC = $(obj)/../include
EXTRA_CFLAGS += -I $(SYMBOL_INC)
KBUILD_EXTRA_SYMBOL=$(obj)/../print/Module.symvers
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY:modules modules_install clean

4、测试模块
Before loading the test module, you need to load the add_sub module first, so that the test module can access the export functions provided by the add_sub module. The command is as follows:
insert image description here
use insmodthe load module and pass parameters to the module. Parameters AddOrSub=2indicate execution. A test directory will be created a-b
insert image description here
under /sys/module/the directory, in which you can clearly see that there are 3 files under paramters, each representing 3 parameters.
insert image description here

add the module to the kernel

After compiling the module, if you want the module to start together with the system, you need to install the module 静态编译进内核. To statically compile a module into the kernel, some necessary steps need to be completed.

Add modules to the kernel

To add a driver module to the Linux kernel, three tasks need to be completed:
(1) Write the driver program file
(2) Put the driver program file into the corresponding directory of the Linux kernel source code. If there is no suitable directory, you can create a directory for storage driver files.
(3) KconfigAdd the project compilation selection corresponding to the new driver in the file in the directory.
(4) MakefileAdd the compilation statement of the new driver to the file in the directory.

Kconfig

KconfigThere are two files and in the directory of the kernel source tree Makefile. The files distributed into the directories Kconfigmake up a 分布式的内核配置数据库, 每个Kconfig文件分别描述了所属目录源文档相关的内核配置菜单. When configuring the kernel make menuconfig(或xconfig等), the menu is read Kconfigfrom it , and the user selects it and saves .configit in the kernel configuration file. When the kernel is compiled, the user's choice is known Makefileby calling this file in the main directory. The above content shows that Kconfig is the configuration menu corresponding to the kernel. If you want to add a new driver to the kernel source, you need to modify the file. In order to make readers have an intuitive understanding of the file, here is a simple example, this example is the IIC driver. The source code of the I2c device driver is included in the linux-2.6.29.4/drivers/i2c directory, and its directory structure is as follows: This directory contains a Kconfig file, which contains configuration options. This script in the above file configures the options. This option is a tri-state configuration option, which means module . When the option is Y, it means compiling into the kernel; when the option is M, it means compiling as a module; when the option is N, it means not compiling. As shown in the figure below, the "I2C device interface" option is set to M, which means it is compiled as a kernel module. The following content is help information,.config
Kconfig
Kconfig
insert image description here
I2C_CHARDEV
insert image description here
KconfigI2C_CHARDEVtristate要么编译为内核,要么编译为内核模块help在单击“快捷键?”时,会显示帮助信息。
insert image description here

Kconfig syntax

The Kconfig syntax is relatively simple, and its syntax Documentation/kbuild/kconfig-language.txtis introduced in the file. In summary, the grammar of Kconfig mainly includes the following aspects.
1、主要语法总览
The Kconfig configuration file describes a series of menu entries. Except for help information, each line begins with a keyword, and these keywords are as follows:

config
menuconfig
choice/endchoice
comment
menu/endmenu
if/endif

The first 5 keywords all define a menu option, if/endifwhich is a conditional option. Some commonly used menu syntaxes are described below.
2、菜单入口(config)
Most kernel configuration options correspond to a menu in Kconfig, which can be make menuconfigdisplayed in , as follows:

config MODVERSIONS
	bool "Set version infomation on all module symbols"
	depends on MODULES
	help
Usually, modules have to be recompiled whenever you switch to a new kernel...

Each line begins with a keyword and can have multiple parameters. configkeyword defines a new configuration option, and the following lines define the properties of that configuration option. Properties can have types, input prompts, dependencies, help information, default values, etc.
Two identical configuration options can appear, but each option can only have one input prompt and the types must not conflict.
Each configuration option must specify a type, including bool、tristate、string、hex和int, where tristate和stringare the two basic types on which other types are based. A bool type is defined as follows:
insert image description here
The type definition is followed by input prompts that will be displayed in the configuration menu. The following two methods can be used to input prompts:
Method 1:

bool "Neworking support"

Method 2:

bool
prompt "Networking support"

The general syntax for an input prompt is as follows:

prompt <prompt> ["if" <expr>]

where promptis a keyword that represents an input prompt. <prompt>is a prompt message. Optionals ifare used to indicate dependencies for this hint.
The syntax for default values ​​is as follows:

default <expr> [if <expr>]

A configuration option can have multiple default values, but only the first default value is valid. Only configoptions may configure default values.
The dependencies are as follows:

depends on <expr>

If multiple dependencies are defined, you can use "&&" to connect to indicate the relationship with. Dependencies can be applied to all other selections in the menu, the following two examples are equivalent.
Example 1:

bool "foo" if BAR  #如果定义BAR选项,那么就使能foo选项
default y if BAR  #如果定义BAR选项,那么foo的默认值就是y,表示编译入内核

Example 2:

depends on BAR  # foo选项的可配置与否,依赖于BAR选项
bool "foo"
default y

dependsThe ability to define an configoption, that is, if A depends on B, then in the case where B is configured as Y, A can be Y, M, N; in the case where B is configured as M, A can be M, N ; When B is configured as N, A can only be N, indicating that this function is disabled.

help(或者---help---)
begin
...
end

You can use "help" or "--help-" to define help information. Help information can give hints when developers configure the kernel.
3、菜单结构(menu)
The menu structure is generally used as the parent menu of the menu entry. The position of a menu entry in the menu structure can be determined in two ways. The first way is as follows:

menu "Network device support"
	depends on NET
config NETDEVICES
...
endmenu

menuand endmenuare the keywords of the menu structure, and the options in it configare menu entries. Menu entries NETDEVICESare Network device supportsubmenus of the menu structure. depends on NETIs menua dependency of the main menu, and only if configured , the menu item NETcan be configured . Network device supportMoreover, all submenu options will inherit the dependencies of the parent menu, for example, the dependencies Network device supporton NETwill be added to NETDEVICESthe dependencies of the configuration options.
The second way is to generate the menu structure by analyzing dependencies. If a menu option depends to some extent on another menu option, it becomes a submenu of that option. If the parent menu option is Y or M, then the submenu is visible; if the parent menu is N, then the submenu is not visible. For example:

config MODULES
	bool "Enable loadable module support"
config MODVERSIONS
	bool "Set version information on all module symbols"
	depends on MODULES
comment "module support disabled"
	depends on !MODULES

From the statement "depends on MODULES", it can be seen that MODVERSIONSit is directly dependent on MODULES, so MODVERSIONSit is MODULESa submenu of MODULES. If MODULESnot N, then MODVERSIONSit is visible.
4、选择菜单(choice)
A selection menu defines a set of options. The type of this option can only be booleanor tristatetype. The syntax for this option is as follows:

"choice"
<choice options>
<choice block>
"endchoice"

The menu can be used when a piece of hardware has multiple drivers choice, and choiceonly one driver can be compiled into the kernel by using the menu. choiceAnother option that the menu can accept is optionalsuch that the option is set to N, indicating that the kernel is not selected.
5、注释菜单(comment)
The Comments menu defines comments displayed to the user during configuration. This comment can also be output to a file for viewing. The syntax for comments is as follows:

comment <prompt>
<comment options>

The only attribute that can be defined in annotations is dependencies, other attributes cannot be defined.

Application example: add add_sub module in the kernel

A comprehensive example is explained below, assuming that we are going to add a module to the kernel add_sub. Considering add_subthe function of the module, it is decided to add the module to driversthe directory of the kernel source code. driversAdd a subdirectory to the directory add_sub_Kconfig. add_subThe source code directory of the module add_sub_Kconfigis as follows:
insert image description here
subdirectories are added to the kernel, and files Kconfigand Makefilefiles for the corresponding directories need to be created in order to configure and compile the module. KconfigAt the same time, the and files in the parent directory of the subdirectory Makefilealso need to be modified so that Kconfigthe and Makefilefiles in the subdirectory can be referenced.
In the newly added add_sub_Kconfigdirectory, the following Kconfigfiles should be included:

#
# add_sub configuration
#
menu "ADD_SUB"  #主菜单
	comment "ADD_SUB"
config CONFIG_ADD_SUB    #子菜单,添加add_sub模块的功能
	boolean "ADD_SUB support"
	default y
#子菜单,添加test模块的功能,只有配置CONFIG_ADD_SUB选项时,该菜单才会显示
config CONFIG_TEST
	tristate "ADD_SUB test support"
	depends on CONFIG_ADD_SUB    #依赖CONFIG_ADD_SUB
	default y
endmenu

Since ADD_SUBit is a new function for the kernel, it is first necessary to create a ADD_SUBmenu; then use commentthe display ADD_SUBto wait for the user to select; then judge whether the user has selected ADD_SUB, if ADD_SUB is selected, then ADD_SUB support will be displayed, and the default setting of this option is Y , which means compiled into the kernel. Next, if ADD_SUB support is configured as Y, that is, the variable CONFIG_ADD_SUB=y, then ADD_SUB test support will be displayed, this option depends on CONFIG_ADD_SUB. Since CONFIG_TEST can be compiled into the kernel or as a kernel module, the option type here is set to tristate.
In order to make this Kconfigfile work, you need to modify the linux-2.6.29.4/drivers/Kconfig file, and add the following content at the end of the file:

source "drivers/add_sub_Kconfig/Kconfig"

means in the script sourceto refer to the new Kconfig file, and the parameter is the relative path name of the Kconfig file. At the same time, in order to enable add_subthe testmodule to be compiled, add_sub_Kconfiga Makefile needs to be added to the directory. The Makefile is as follows:

obj-$(CONFIG_ADD_SUB) +=add_sub.o
obj-$(CONFIG_TEST) +=test.o

The variables CONFIG_ADD_SUBand CONFIG_TESTare Kconfigthe variables defined in the file. The script is based on the value of the configuration variable 构建obj-*列表. For example , when obj-$(CONFIG_ADD_SUB)it is equal obj-yto, it means to build add_sub.othe module and compile it into the kernel; when obj-$(CONFIG_ADD_SUB)it is equal obj-nto, it means not to build add_sub.othe module; when obj-$(CONFIG_ADD_SUB)it is equal obj-mto, it means to compile the module separately and not put it into the kernel.
In order to make the entire add_sub_Kconfigdirectory attract the attention of the compiler, add_sub_Kconfigthe Makefile in the parent directory drivers also needs to add the following script:

obj-$(ADD_SUB) +=add_sub_Kconfig/

add_sub_KconfigAdd obj-$(ADD_SUB)+=add_sub_Kconfig/ in linux-2.6.29.4/drivers/Makefile, so that the user can enter the directory when compiling the kernel . The new add_sub_Kconfig tree directory after adding Kconfig and Makefile files is as follows:
insert image description here

Configure the add_sub module

After the source file of the add_sub module is added to the kernel source code, it needs to be configured before the module can be compiled. The configuration steps are as follows:
(1) Execute the command in the kernel source code directory make menuconfig.
insert image description here
(2) Select Device DriversOptions, and then select SelectOptions.
insert image description here
(3) Select the ADD_SUB option in the entered interface, which is menudefined by the menu in the Kconfig file, and then select the Select option.
insert image description here
(4) As shown in the figure below, there are two options, ADD_SUB support and ADD_SUB test support, to choose from. Among them ADD_SUB supportis ADD_SUB test supportthe parent option, which ADD_SUB supportcan only be ADD_SUB test supportselected when it is selected. The figure *means selected; if it is empty, it means not selected.
insert image description here

summary

This blog mainly explains how to build a driver. First explained why the kernel should be upgraded. Then the Hello World program is briefly introduced. On this basis, the communication between modules is explained in detail, which are the basis of driver program development. Finally, it explains how to add the module to the kernel and let the module run.

Guess you like

Origin blog.csdn.net/m0_56145255/article/details/131274076