2.linux内核模块

2.1 驱动模块框架

Linux内核的整体架构非常庞大,其包含组件也非常多,怎样把需要的部分包含在内核中?

一种方法是把所需要的功能编译到linux内核中,这会导致两个文件,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核。

Linux提供了这样一种机制,称为模块(Moudle)。可使编译出的内核本身并不包含所有的功能,而在这些被使用的时候,其对应的代码可被动态的加载到内核。

模块的特点

    模块本身不被编译到内核映像,从而控制了内核的大小。

    模块一旦被加载,它就和内核中的其他部分完全一样。

2.1.1对驱动模块进行操作的shell命令

insmod demo.ko  插入驱动模块

lsmod           查看插入正在运行驱动模块

rmmod demo      移除驱动模块  

modinfo demo.ko 查看驱动模块信息

dmesg           查看内核缓存信息

dmesg -c        清除内核缓存信息

有依赖关系的

modprobe (智能安装) xx(不加.ko)

modprobe -r 移除(注意:移除需要依赖的模块,同时会移除被依赖的模块)

2.1.2一个最简单的linux内核模块代码如下:

A.hello world驱动模块 demo.c

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

static int __init demo_init(void)
{
	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);/*指定驱动模块入口点*/


static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);/*指定驱动模块出口*/

MODULE_LICENSE("GPL");/*公共许可声明*/
MODULE_AUTHOR("Songze Lee");/*作者*/
MODULE_VERSION("Verson 1.0");/*版本号*/
MODULE_DESCRIPTION("It is a simple demo for driver module");/*描述*/

内核模块中用于输出的函数的内核空间的printk(),用法和printf基本相似,但可以定义输出级别。

Makefile编写如下:

obj-m	:= demo.o

OUR_KERNEL := /ARM/linux-3.5-songze/

all:
	make -C $(OUR_KERNEL) M=$(shell pwd) modules
#	进入到变量目录(内核源码目录)下编译  M 编译pwd路径下的模块
clean:
	make -C $(OUR_KERNEL) M=`pwd` clean

调试结果如下:

[projct /]# insmod demo.ko

[ 1670.390000]hello,word! driver module is inserted!

  [projct /]#rmmod demo

  [ 1681.215000]goodbye, word! driver is removed!

  rmmod: module'demo' not found

B.驱动模块调用子函数编写

demo.c

/**
 * 驱动模块调用子函数
 * 注意Makefile的编写
 */

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

extern void call_func0(void);

static int __init demo_init(void)
{
	call_func0();
	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);/*指定驱动模块入口点*/


static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);/*指定驱动模块出口*/

MODULE_LICENSE("GPL");/*公共许可声明*/
MODULE_AUTHOR("Songze Lee");/*作者*/
MODULE_VERSION("Verson 1.0");/*版本号*/
MODULE_DESCRIPTION("It is a simple demo for driver module");/*描述*/
fun0.c

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

extern void call_func1(void);

void call_func0(void)
{
	call_func1();
}

fun1.c

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

void call_func1(void)
{	
	printk("you are a good boy.\n");
}

Makefile(重点注意)

obj-m	:= team_hehe.o
team_hehe-objs	:= demo.o fun0.o fun1.o

OUR_KERNEL := /ARM/linux-3.5-songze/

all:
	make -C $(OUR_KERNEL) M=$(shell pwd) modules
clean:
	make -C $(OUR_KERNEL) M=`pwd` clean

调试结果如下:

   [projct /]# insmod team_hehe.ko

    [ 1920.880000]you are a good boy.

    [ 1920.880000]hello,word! driver module is inserted!

    [projct /]#rmmod team_hehe

    [ 1932.020000]goodbye, word! driver is removed!

    rmmod: module'team_hehe' not found

2.1.3导出符号

    Linux的“/proc/kallsyms”文件对应着内核符号表,它记录了符号以及符号所在的内存地址。

    模块可以使用如下宏导出符号到内核符号表中:

    EXPORT_SYMBOL(符号表);

    EXPORT_SYMBOL_GPL(符号表);

    导出的符号(变量或函数)可以被其他模块使用,只需要使用前声明一下即可。EXPORT_SYMBOL_GPL()只适用于包含GPL许可权的模块。

    示例代码如下:

demo1.c

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

extern int sure;
extern void pri_value(int);
extern void call_func0(void);

static int __init demo_init(void)
{
	sure = 3856;
	pri_value(sure);

	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);

static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Songze Lee");
MODULE_VERSION("verson 1.0");
MODULE_DESCRIPTION("It is a simple demo for driver module");

demo2.c

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

static int sure = 9527;

/*符号导出 static定义的变量或函数其他模块可以调用*/
EXPORT_SYMBOL_GPL(sure);

static void pri_value(int val)
{
	printk("In %s: sure = %d\n", __FILE__, sure);
}
EXPORT_SYMBOL_GPL(pri_value);

static int __init demo_init(void)
{
	pri_value(sure);

	printk("hello,word! driver module is inserted!\n");

	return 0;
}
module_init(demo_init);


static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Songze Lee");
MODULE_VERSION("verson 1.0");
MODULE_DESCRIPTION("It is a simple demo for driver module");

调试结果如下:

[projct /]# insmod demo02.ko

[ 2484.680000] In/ARM/linux-3.5-songze/drivers/songze_drivers/module/

demo05/demo02.c: sure = 9527

[ 2484.680000] hello,word! driver module is inserted!

[projct /]# insmod msb.ko

[ 2491.690000] In /ARM/linux-3.5-songze/drivers/songze_drivers/module/

demo05/demo02.c: sure = 3856

[ 2491.690000] hello,word! driver module is inserted!

[projct /]# rmmod demo02

rmmod: remove 'demo02': Resource temporarily unavailabl两者有依赖关系

[projct /]# rmmod msb

[ 2531.345000] goodbye, word! driver is removed!

rmmod: module 'msb' not found

[projct /]# rmmod demo02

[ 2542.910000] goodbye, word! driver is removed!

rmmod: module 'demo02' not found

2.1.4模块参数

    在用户态下编程可以通过main()来传递命令行参数,而编写一个内核模块则可通过module_param()来传递命令行参数。

module_param宏是Linux 2.6内核中新增的,该宏被定义在include/linux/

moduleparam.h文件中,具体定义如下:

    #define module_param(name, type, perm)              

       module_param_named(name, name, type,perm)

由此可知module_param的实现是通过module_param_named(name, name, type,perm)的。

module_param(name,type, perm)

name:参数名 type:参数类型perm:参数读写权限

    参数类型可以是byte、short、ushort、int、uint、long、ulong、charp(字符指针)、bool或invbool(布尔的反),在模块被编译时会将module_param中声明的类型与变量定义的类型进行比较、判断是否一致。

    module_param_array(name,type,num,perm)

name:数组名 type:数组类型num:数组长 perm:参数读写权限

perm参数的作用是什么?

最后的 module_param字段是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 <linux/stat.h> 中定义的值. 这个值控制谁可以存取这些模块参数在 sysfs 中的表示.

当perm为0时,表示此参数不存在 sysfs文件系统下对应的文件节点。 否则, 模块被加载后,在/sys/module/ 目录下将出现以此模块名命名的目录, 带有给定的权限.。

权限在include/linux/stat.h中有定义

比如:

    #define S_IRWXU 00700

    #define S_IRUSR 00400

    #define S_IWUSR 00200

    #define S_IXUSR 00100

    #define S_IRWXG 00070

    #define S_IRGRP 00040

    #define S_IWGRP 00020

    #define S_IXGRP 00010

    #define S_IRWXO 00007

    #define S_IROTH 00004

    #define S_IWOTH 00002

    #define S_IXOTH 00001

使用 S_IRUGO 参数可以被所有人读取, 但是不能改变; S_IRUGO|S_IWUSR 允许 root 来改变参数.注意, 如果一个参数被 sysfs 修改, 你的模块看到的参数值也改变了, 但是你的模块没有任何其他的通知. 你应当不要使模块参数可写, 除非你准备好检测这个改变并且因而作出反应.

示例A:module_param(name, type, perm)

/**
 *module_param(name, type, perm) 内核模块传参
 *向当前模块传参
 */

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

static int x_rel = 480, y_rel = 272;

module_param(x_rel, int, 0);
module_param(y_rel, int, 0);

static char *info = "mdg: lol?";

static int num=10;
module_param(num,int,S_IRUGO);
module_param(info, charp, 0);

static int __init demo_init(void)
{
	printk("hello,word! driver module is inserted!\n");

	printk("x: %d, y: %d\n %s\n", x_rel, y_rel, info);
	printk("num=%d\n",num);
	return 0;
}
module_init(demo_init);

static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Songze Lee");
MODULE_VERSION("version 1.0");
MODULE_DESCRIPTION("It is a simple demo for driver module");

调试结果:

[projct /]# insmod demo.ko num=110 x_rel=123 y_rel=345info="hello world"

[ 4140.560000] hello,word! driver module is inserted!

[ 4140.560000] x: 123, y: 345

[ 4140.560000] hello world

[ 4140.560000] num=110

[projct /]# cat /sys/module/demo/parameters/num

110

[projct /]# ls -l /sys/module/demo/parameters/num

-r--r--r--    10        0             4096 Jan  1 14:06 /sys/module/demo/parameters/num

可发现num为只读文件

示例B:module_param_array(name,type,num,perm)

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

#define CNT 16
static int num = CNT;
static int array[CNT] = {1,2,3,4,5,6,7};
module_param_array(array, int, &num, 0);

static int __init demo_init(void)
{
	int i;
	printk("Insert module ok!\n");
	for(i = 0; i < num; i++){
		printk("array[%d] = %d\n", i, array[i]);
	}
	return 0;
}
module_init(demo_init);

static void __exit demo_exit(void)
{
	printk("goodbye, word! driver is removed!\n");
} 

module_exit(demo_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("millet9527");
MODULE_VERSION("uplooking plus 7");
MODULE_DESCRIPTION("It is a simple demo for driver module");

调试结果:

[projct /]# insmod demo.koarray=11,22,33,44,55,66,77,88,99

[ 4965.605000] Insert module ok!

[ 4965.605000] array[0] = 11

[ 4965.605000] array[1] = 22

[ 4965.605000] array[2] = 33

[ 4965.605000] array[3] = 44

[ 4965.605000] array[4] = 55

[ 4965.605000] array[5] = 66

[ 4965.605000] array[6] = 77

[ 4965.605000] array[7] = 88

[ 4965.605000] array[8] = 99


获取源码: git clone https://www.github.com/lisongze2016/Tiny4412_kernel.git


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值