Linux内核驱动编程

Linux内核驱动编程

2015-02-12

驱动程序基础的东西这儿就不罗嗦了,百度上有更好的资料,此处我们只是注重实际用处。

    下面我们开始写程序:

一、初步helloword程序

首先是来一个简单的hello。

hello.c代码:

技术分享
 1 /******************************
 2 
 3 the first program
 4 
 5 Hello World!
 6 
 7 ******************************/
 8 
 9 #include <linux/module.h>
10 
11 #include <linux/init.h>
12 
13  
14 
15 static int hello_init(void)
16 
17 {
18 
19 printk("<0>\nHello, world!\n\n");
20 
21 return 0;
22 
23 }
24 
25  
26 
27 static void hello_exit(void)
28 
29 {
30 
31 printk("<0>\nGoodbye,world \n\n");
32 
33 }
34 
35  
36 
37 module_init(hello_init);
38 
39 module_exit(hello_exit);
40 
41 MODULE_LICENSE("Dual BSD/GPL"); //Any version of public GNU license
View Code

Make代码:

技术分享
 1 ifeq ($(KERNELRELEASE),)
 2 
 3 KERNELDIR ?= /home/study/system/linux-2.6.31
 4 
 5 PWD := $(shell pwd)
 6 
 7 modules:
 8 
 9 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
10 
11 modules_install:
12 
13 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
14 
15 clean:
16 
17 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
18 
19  
20 
21 else
22 
23 obj-m := hello.o
24 
25 endif
View Code

注意:

①:Makefile中的KERNELDIR ,这个linux源代码的版本是和你的开发板的一模一样,必须修改,否侧或有错误

②:该应用程序必须在开发板上运行,千万注意别再服务器操作系统使用,否则存在破坏系统的危险。

接下来就是,编译->加载,使用以下命令

 1 make CROSS_COMPILE=arm-none-linux-gnueabi-
 2 
 3 //此处为修改为你操作系统上的gcc 交叉编译
 4 
 5 insmod hello.ko
 6 
 7 //加载模块,此时屏幕上会打印,hello,world
 8 
 9 rmmod hello.ko
10 
11 //卸载模块,同样会打印 goodsbye world

接下来我们对其进行改进

 

二、改进helloword程序,增加输入模块参数

我们在代码中增加以下代码:

1 static char *name = "LoverXue";
2 
3 static int age = 1;
4 
5  
6
7 module_param(name,charp,S_IRUGO);
8 
9 module_param(age,int,S_IRUGO);

编译后,加载时,输入以下命令

make CROSS_COMPILE=arm-none-linux-gnueabi-

insmod hello.ko name="lihaiyan" age=20

结果如下:

技术分享

附上源代码如下:

hello.c代码:

技术分享
 1 /******************************
 2 
 3 the first program
 4 
 5 Hello World!
 6 
 7 ******************************/
 8 
 9  
10 
11 #include <linux/module.h>
12 
13 #include <linux/init.h>
14 
15  
16 
17 //module param list
18 
19 static char *name = "LoverXue";
20 
21 static int age = 1;
22 
23  
24 
25 static int hello_init(void)
26 
27 {
28 
29     printk("<0>\nHello, %s\nI know you age is%d\n\n",name,age);
30 
31     return 0;
32 
33 }
34 
35  
36 
37 static void hello_exit(void)
38 
39 {
40 
41     printk("<0>\nGoodbye,%s\n\n",name);
42 
43 }
44 
45  
46 
47 module_init(hello_init);
48 
49 module_exit(hello_exit);
50 
51 MODULE_LICENSE("Dual BSD/GPL"); //Any version of public GNU license
52 
53  
54 
55 module_param(name,charp,S_IRUGO);
56 
57 module_param(age,int,S_IRUGO);
View Code

 

三、改进helloword程序,增加模块之间的依赖

此时,我们的目的是:写两个模块,模块二调用模块一中的函数。

先附上代码,我们看着代码来讲解:

模块一:包含 add_sub.c add_sub.h Makefile 三个文件

add_sub.h

技术分享
1 #ifndef _ADD_SUB_H_
2 
3 #define _ADD_SUB_H_
4 
5 long add_integer(long a,long b);//function add
6 
7 long sub_integer(long a,long b);//function sub
8 
9 #endif
View Code

add_sub.h 中定义声明了模块二中要调用的函数,函数具体实现,看add_sub.c

add_sub.c

技术分享
 1 /*************************************
 2 
 3 add_sub function
 4 
 5 *************************************/
 6 
 7 #include <linux/init.h>
 8 
 9 #include <linux/module.h>
10 
11  
12 
13 #include "add_sub.h" //包含函数声明的头文件
14 
15  
16 
17 //returen sum of the two //实现函数
18 
19 long add_integer(long a,long b)
20 
21 {
22 
23     return a+b;
24 
25 }
26 
27  
28 
29 //returen subtraction of the two
30 
31 long sub_integer(long a,long b)
32 
33 {
34 
35     return a-b;
36 
37 }
38 
39 //为了让其他模块可以调用此函数,
40 
41 //必须用EXPORT_SYMBOL将函数导出到内核
42 
43 //export the function
44 
45 EXPORT_SYMBOL(add_integer); /
46 
47 EXPORT_SYMBOL(sub_integer);
48 
49  
50 
51 MODULE_LICENSE("Dual BSD/GPL");
View Code

Makefile代码:

技术分享
 1 ifeq ($(KERNELRELEASE),)
 2 
 3 KERNELDIR ?= /home/study/system/linux-2.6.31
 4 
 5 PWD := $(shell pwd)
 6 
 7 #################################################
 8 
 9 PRINT_INC = $(PWD)/
10 
11 EXTRA_CFLAGS += -I $(PRINT_INC)
12 
13 #################################################
14 
15 modules:
16 
17 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
18 
19 modules_install:
20 
21 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
22 
23 clean:
24 
25 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
26 
27  
28 
29 else
30 
31 obj-m := add_sub.o
32 
33 endif
View Code

修改前面的代码,必须增加#号内的代码。

此时,我们模块一全部写完。

make 编译。

 

模块二:包含hello.c Makefile

hello.c代码:

技术分享
 1 /******************************
 2 
 3 the first program
 4 Hello World!
 5 ******************************/
 6 #include <linux/module.h>
 7 #include <linux/init.h>
 8 
 9 //extern module
10 #include "./add/add_sub.h" //包含头文件
11 
12 //module param list
13 static char *name = "LoverXue";
14 static int age = 20;
15 static long num1 = 1;
16 static long num2 = 0;
17 static short flag = 1;
18 
19 static int hello_init(void)
20 {
21     printk("<0>\nHello, %s\nI know you age is%d\n\n",name,age);
22     if(flag == 1 ){
23         printk("<0>sum of two %ld + %ld = %ld \n", num1,num2,add_integer(num1,num2));
24 
25     }else{
26         printk("<0>subtraction of two %ld - %ld = %ld \n", num1,num2,sub_integer(num1,num2));
27     }
28     return 0;
29 }
30 
31 static void hello_exit(void)
32 {
33     printk("<0>\nGoodbye,%s\n\n",name);
34 }
35 
36 module_init(hello_init);
37 module_exit(hello_exit);
38 MODULE_LICENSE("Dual BSD/GPL"); //Any version of public GNU license
39 MODULE_VERSION("V1.0");
40 
41 module_param(name,charp,S_IRUGO);
42 module_param(age,int,S_IRUGO);
43 module_param(num1,long,S_IRUGO);
44 module_param(num2,long,S_IRUGO);
45 module_param(flag,short,S_IRUGO);        
View Code

Makefile文件代码:

技术分享
 1 ifeq ($(KERNELRELEASE),)
 2 
 3 KERNELDIR ?= /home/study/system/linux-2.6.31
 4 
 5 PWD := $(shell pwd)
 6 
 7 ##########################################################
 8 
 9 export-objs := /home/study/EasyARM-iMX257/module_study/02_add/add/add_sub.o
10 
11 SYMBOL_INC = $(obj)/
12 
13 SYMBOL_INC += /home/study/EasyARM-iMX257/module_study/02_add/add
14 
15 EXTRA_CFLAGS += -I $(SYMBOL_INC)
16 
17 KBUILD_EXTRA_SYMBOLS = /home/study/EasyARM-iMX257/module_study/02_add/add/Module.symvers
18 
19 #########################################################
20 
21 modules:
22 
23 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
24 
25 modules_install:
26 
27 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
28 
29 clean:
30 
31 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
32 
33 else
34 
35 obj-m := hello.o
36 
37 endif
View Code

KBUILD_EXTRA_SYMBOLS的意思就是包含我们要调用的模块的Module.symvers,

此处最好使用绝对路径。

编译,

如果编译出错,如图所示。

技术分享

 

解决方法是;先编译模块一,然后将模块一的Module.symvers拷贝到我们的模块二的目录下,再编译模块二。

如图所示就不会再出这样的错误了。

 

技术分享

 

加载模块

接着就是在开发板中加载模块

insmod ./add/add_sub.ko

insmod hello.ko num1=50 num2=20 flag=0

结果如下:

技术分享

 

四、将驱动使用静态编译入内核

接下来,我们来将刚刚写的代码使用静态编译,加入内核

  1. :我们进入内核的driver目录,增加目录add_sub_Kconfig

 

mkdir add_sub_Kconfig

 

 

 

技术分享

 

  1. :将我们刚刚写的hello.c add_sub.c add_sub.h 三个文件拷贝入此文件夹

技术分享

  1. :在此文件夹中增加Makefile,Kconfig两个文件,代码如下:

Makefile代码

#drivers/add_sub_Kconfig/Makefile

# Makefile for the ADD_SUB core.

#

obj-$(CONFIG_ADD_SUB) := add_sub.o

obj-$(CONFIG_TEST) := hello.o

 

Kconfig代码如下:

#drivers/add_sub_Kconfig/Kconfig

menu "ADD_SUB" #main menu //增加主菜单

comment "ADD_SUB"

//增加子菜单

config CONFIG_ADD_SUB #children menu, add the add_sub module

boolean "ADD_SUB support"

default y

#children menu ,add the test menu

 

config CONFIG_TEST

tristate "ADD_SUB test support"

depends on CONFIG_ADD_SUB #Depends on the config CONFIG_ADD_SUB

default y

endmenu

 

  1. :修改driver下的Makefile,Kconfig 文件代码:

Makefile中增加:

obj-$(ADD_SUB) += add_sub_Kconfig/

将上面我们自己写的makefile文件包含进来:

技术分享

 

Kconfig中末尾增加以下代码:

将上面我们自己写的Kconfig文件包含进来

source "drivers/add_sub_Kconfig/Kconfig"

source "drivers/test//Kconfig"

 

技术分享

 

  1. :修改arch/arm/ 目录下的 Makefile Kconfig

实验证明只对,只对drivers/Kconfig中修改内容无效,drivers/Kconfig中修改内容无效,还要对arch/arm/Kconfig进行修改,很重要的一步,很多资料上都遗漏了这一步)

在Kconfig中加入代码:

 

source "drivers/add_sub_Kconfig/Kconfig"

 

技术分享

 

  1. :配置编译

在内核的根目录下执行,make menuconfig 如图所示:

进入Device Drivers 目录

技术分享

 

在最后面,我们看到了,我们自定义的模块:ADD_SUB模块

技术分享

进入ADD_SUB,我们会看到我们写的两个模块全都默认选中了

技术分享

 

此时,我们再次编译内核,就会把我们的模板使用静态编译进内核。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。