Porting and loading your own written drivers (keywords: makefile and kconfig writing, header file inclusion)

1. Write your own driver

        1.1 Preface: The driver framework deals with some algorithms and data structures. It is written by the kernel personnel. The kernel does not know what kind of hardware you are, so you cannot perform hardware operations. The actual hardware operation is the driver written by our driver personnel. , distinguish between driver and driver frame.


    1.2 makefile, kconfig, xxx.c (These 3 files need to be created by ourselves)

           1.2.1   kconfig: The modules defined in this file are finally configured in menuconfig through Y (add), N (not add), M (module loading), as follows: LEDS_CLASS, which will finally be added by a mechanism behind linux with CONFIG_ , The core code in kconfig is as follows:

                config LEDS_CLASS
                tristate "LED Class Support"

        1.2.2   makefile: Finally, make will generate a configuration file config, which records all the values ​​similar to CONFIG_LEDS_CLASS after the menuconfig configuration , and then pass the value configured by menuconfig in the makefile to see if it will be compiled into an o file and linked to the kernel middle. 

                    obj-$( CONFIG_ LEDS_CLASS ) += xxx.o is equivalent to  obj-m/y += xxx.o

                    (1) If it is a large project, you need to write and add a lot of modules yourself. There is no need to write the steps of how to generate .KO in the current makefile. Finally, it is written in the top-level makefile and compiled into ko at one time, instead of in the respective makefile. One by one make to generate: the relevant code is as follows:

                    $(MAKE) -C $(KENREL_DIR) M=$(PWD) modules

                    (2) The ko generated by a single module is written in its own makefile as follows:

# The source tree directory of the linux kernel of the development board

KERN_DIR = /root/driver/kernel

obj-m += module_test.o

all:

make -C $(KERN_DIR) M=`pwd` modules 

.PHONY: clean

clean:

make -C $(KERN_DIR) M=`pwd` modules clean   

(1) KERN_DIR, the value of the variable is the directory of the kernel source tree we use to compile this module
(2) obj-m += module_test.o, this line means that we want to compile the module_test.c file into a module (3 )make -C $(KERN_DIR) M=`pwd` modules This command is used to actually compile the modules. The working principle is: use make -C to enter the kernel source tree directory we specified, and then borrow the kernel source code under the source directory tree. Compile the module according to the module compilation rules defined in . After the compilation is completed, copy the generated files to the current directory to complete the compilation. M=`pwd`, record the current path, so that you can return to the previous directory after make -C $(KERN_DIR).

(4) make clean to clear compilation traces                     

Summary: The makefile of the module is very simple, and it cannot complete the compilation of the module itself. Instead, it enters the kernel source tree through make -C and borrows the system of the kernel source code to complete the compilation and linking of the module. The Makefile itself is very modal, parts 3 and 4 never need to be moved, only parts 1 and 2 need to be moved. 1 is the directory of the kernel source tree, you must compile according to your own environment

             1.2.3   For example, the driver module led.c

               (1) The inside is the specific operation of the hardware, if we want to add LEDs written by ourselves. There are two ways, one is like Jiuding, do not use the framework, write the probe function to complete the specific hardware operation, or use the framework written by the kernel to register, write the basic parameters, and then the framework will help us deal with it.

                 (2) For an example of the code writing process, see the previous article " The Concept of Kernel Modules "

                 (3) This kind of driver is a wild driver, and it is not in the kernel itself. It belongs to dynamic loading, so that we don't have to recompile the kernel.

                1.2.4  Write a driver C file from scratch

                   1. Contains 2 header files, one, linux/module.h, the installation function macro is defined in it, init.h, __init, defined in it

                            Explanation of header files: The header files included in the driver source code and the header files included in the original application programming program are not the same thing. The header files included in the application programming are the header files of the application layer, which are brought by the compiler of the application (for example, the path of the header files of gcc is under /usr/include, these things have nothing to do with the operating system). The driver source code is a part of the kernel source code. The header file in the driver source code is actually the header file in the include directory in the kernel source code directory. When we #include, it will automatically search for include.

                    2内核模块的概念》列出了基本的代码组成,这里直接说每一部分代码里面的内容

                           (1)代码如下:

#include <linux/module.h> // module_init  module_exit

#include <linux/init.h> // __init   __exit

#include <linux/fs.h>

#include <asm/uaccess.h>

//这个MYMAJOR、MYNAME很重要,我们APP想要操作这个驱动,就需要打开设备文件名

#define MYMAJOR 200  //内核可以自动分配,如我们传参有关

#define MYNAME "testchar"


// 代码块1:函数实体

static int test_chrdev_open(struct inode *inode, struct file *file)

{

// 这个函数中真正应该放置的是打开这个设备的硬件操作代码部分

}

……省略

// 代码块2:自定义一个file_operations结构体变量,并且去填充

static const struct file_operations test_fops = {

.owner = THIS_MODULE, // 惯例,直接写即可

.open = test_chrdev_open, // 将来应用open打开这个设备时实际调用的

.release = test_chrdev_release, // 就是这个.open对应的函数

.write = test_chrdev_write,

.read = test_chrdev_read,

};

// 代码块3:模块安装函数

static int __init chrdev_init(void)

{

// 在module_init宏调用的函数中去注册字符设备驱动

// major传0进去表示要让内核帮我们自动分配一个合适的空白的没被使用的主设备号

// 内核如果成功分配就会返回分配的主设备好;如果分配失败会返回负数

mymajor = register_chrdev(0, MYNAME, &test_fops);

}

// 代码块4:模块下载函数

static void __exit chrdev_exit(void)

{

// 在module_exit宏调用的函数中去注销字符设备驱动

unregister_chrdev(mymajor, MYNAME);

}

module_init(chrdev_init);

module_exit(chrdev_exit);

// 代码块5:MODULE_xxx这种宏作用是用来添加模块描述信息

MODULE_LICENSE("GPL"); // 描述模块的许可证

MODULE_AUTHOR("aston"); // 描述模块的作者

MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息

        MODULE_ALIAS("alias xxx"); // 描述模块的别名信息


2、安装写好的驱动

 2.1 安装自己写的驱动

        (1)自己写的驱动一般都是几个模块要安装,我们可以在包含KO的目录下直接insmod安装


 2.2 安装平台提供的驱动

        (2)平台提供的往往有几十个上百个需要安装,这个时候需在包含所有模块同一层目录下,编写脚本文件,统一安装。比如海思的HI3518e平台。

   

2.3 安装、卸载、查看驱动命令

        (1)insmod  module_name.ko

        (2)rmmod  module_name

        (3)modinfo module_name.ko(查看模块版本信息)

                当我们拿到一个别人写的模块,他可能针对的是某个版本的内核,你要看这个模块是否与你的内核匹配,包括版本信息,license是否一致,依赖等,这样你才能知道模块是否与你的内核匹配。


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325855791&siteId=291194637