我们写的驱动程序最终都是要加载进内核的,我们有两种方法添加到内核中。第一种是直接编进内核里,第二种是动态编进内核里。动态加入内核就是我们把自己的驱动程序看成一个模块,然后把这个模块加载到内核内。直接编译进内核就是这个模块和内核一起编译,如果有什么这个驱动有什么问题的话,我们还需要调试编译整个内核,因此刚开始学习的时候我采用了模块化的动态加载内核。

一、动态加入内核

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

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");

static int hello_init(void)
{
    printk(KERN_EMERG "HELLO WORLD enter!\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_EMERG "HELLO WORLD exit!\n");

}

module_init(hello_init);
module_exit(hello_exit);

这个内核模块只有简单的几个功能,加载模块、卸载模块、对 GPL 的声明、描述信息例如作者以及加载和卸载时候的打印函数

一个 Linux 内核模块主要由以下几个部分组成。
1)模块加载函数
当通过 insmod 命令加载内核模块的时候,模块的加载函数会自动被调用到内核运行,完成模块的初始化工作
2)模块卸载函数
当通过 rmmod 命令卸载内核模块的时候,模块的卸载函数会自动被调用到内核运行,完成模块的卸载工作,完成与模块卸载函数相反的功能。
3)模块的许可声明
LICENSE 声明描述内核的许可权限,如果不声明 LICENSE,模块被加载的时候,会受到内核被污染的警告.
Linux 在使用的过程中,需要接受 GPL 协议,体现在代码中就是添加类似
MODULE_LICENSE(“Dual BSD/GPL”);的语句
在 Linux 内核模块领域,可接受的 LICENSE 参数包括“GPL”、“GPL v2”、”GPL andaddtional” 、”Dual BSD/GPL”、”Dual MPL/GPL” 等,当参数是前面的几个时,那么就表明你遵循 GPL 协议。

还有一个参数”Proprietary”,这个参数表明是私有的,除非你的模块显式地声明一个开源版本,否则内核也会默认你这是一个私有的模块(Proprietary)。
4)模块作者信息等
体现在代码中,就是类似 MODULE_AUTHOR(“iTOPEET_dz”);的语句。其中 iTOPEET_dz是参数

#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += mini_linux_module.o 

#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0

#当前目录变量
PWD ?= $(shell pwd)

#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
    make -C $(KDIR) M=$(PWD) modules

#make clean执行的操作是删除后缀为o的文件
clean:
    rm -rf *.o

如上图所示,就是编译 mini_linux_module 的脚本文件。下面详细的介绍每一句的含义。

#!/bin/bash

通知编译器这个脚本使用的是那个脚本语言

obj-m += mini_linux_module.o

这是一个标准用法,表示要将 mini_linux_module.c 文件编译成 mini_linux_module.o 文件,如果还需要编译其它的文件,则在后面添加即可。

KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0

这一行代码表示内核代码的目录,如果没有内核源码,那么模块的编译无法进行,因为会缺乏版本支持和头文件。KDIR 是一个变量。

PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules

在使用执行脚本编译命令“make”的时候,它会默认来寻找这一句,make -C 表示调用执行的路径,也就是变量 KDIR,变量 KDIR 中有内核源码目录的路径。
PWD 表示当前目录。
modules 表示将驱动编译成模块的形式,也是就是最终生成 KO 文件。

clean:
rm -rf *.o

在重新修改了源码之后,可以执行“make clean”命令来清除一些无用的中间文件,这里选择的是清除后缀为“o”的文件这一句是提供一个变量,然后将当前目录的路径传给这个变量。

把helloworld.c和Makefile放到同一文件夹下,修改内核源码的目录,make编译,生成.ko文件拷贝到开发版中 。
使用命令“insmod /mnt/udisk/mini_linux_module.ko”加载模块,如下图所示

linux驱动入门,编译,动态加载_加载


使用命令“lsmod”,查看一下模块信息,如下图所示

linux驱动入门,编译,动态加载_加载_02


使用命令“rmmod mini_linux_module”卸载驱动模块

报错无法卸载,提示没有文件夹 。这里根据提示,使用命令“mkdir

lib/modules/3.0.15”新建目录“lib/modules/3.0.15”,

再使用卸载驱动模块的命令“rmmod mini_linux_module”,如下图所示,可以看到打印出了在卸载驱动函数里面添加的打印信息:Hello world exit!

最后使用命令:lsmod,对比前面的 lsmod,发现已经没有了加载的模块驱动了

linux驱动入门,编译,动态加载_加载_03