ARM学习笔记之驱动程序篇三----内核模块

1.6 内核模块

1.6.1 内核模块基础知识

     内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),我们简称为模块。Linux内核之所以提供模块机制,是因为它本身是一个单内核(monolithic kernel)。单内核的最大优点是效率高,因为所有的内容都集成在一起,但其缺点是可扩展性和可维护性相对较差,模块机制就是为了弥补这一缺陷。模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。总之,模块是一个为内核(从某种意义上来说,内核也是一个模块)或其他内核模块提供使用功能的代码块。

1,内核模块的特点

(1)模块本身并不被编译进内核文件(zImage或者bzImage)

(2)可以根据需求,在内核运行期间动态的安装或者卸载。

2,安装/卸载内核模块

(1)安装insmod

    例:insmod dnw_usb.ko

(2)卸载rmmod

    例:rmmod dnw_usb.ko

(3)查看 lsmod

    例:lsmod

1.6.2 内核模块的设计

1,内核模块范例

#include<linux/init.h>
#include<linux/module.h>
static int hello_init(){
    printk(KERN_WARNING"hello world!\n");
    return 0;
}

static int hello_exit(){
    printk(KERN_WARNING"hell exit!\n");
    return 0;
}

module_init(hello_init);
module_exit(hello_exit);

内核通过printk()输出的信息具有日志级别,日志级别是通过在printk()输出的字符串前加一个带尖括号的整数来控制的,如printk("<6>Hello, world!\n");。内核中共提供了八种不同的日志级别,在 linux/kernel.h 中有相应的宏对应。

#define KERN_EMERG   "<0>"   /* system is unusable */

#define KERN_ALERT   "<1>"   /* action must be taken immediately */

#define KERN_CRIT     "<2>"   /* critical conditions */

#define KERN_ERR      "<3>"   /* error conditions */

#define KERN_WARNING "<4>"   /* warning conditions */

#define KERN_NOTICE   "<5>"   /* normal but significant */

#define KERN_INFO     "<6>"   /* informational */

#define KERN_DEBUG    "<7>"   /* debug-level messages */

KERN_EMERG

用于突发性事件的消息,通常在系统崩溃之前报告此类消息。 

KERN_ALERT

在需要立即操作的情况下使用此消息。 

KERN_CRIT

用于临界条件下,通常遇到严重的硬软件错误时使用此消息。 

KERN_ERR

用于报告错误条件;设备驱动经常使用KERN_ERR报告硬件难题。

KERN_WARNING

是关于问题状况的警告,一般这些状况不会引起系统的严重问题。 

KERN_NOTICE

该级别较为普通,但仍然值得注意。许多与安全性相关的情况会在这个级别被报告。 

KERN_INFO

信息消息。许多驱动程序在启动时刻用它来输出获得的硬件信息。

KERN_DEBUG

用于输出调试信息。

2.编写Makefile

obj-m:=helloworld.o
KDIR:=/home/win/Tiny6410/linux-tiny6410
all:
 make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux-ARCH=arm
clean:
 rm -f *.o,*.ko,*.order,*.symvers

obj-m := helloworld.o为固定格式,指明内核模块的名字,如该模块有多个文件组成则须在下面加一行helloworld-objs := file1.o file2.o;KDIR := /home/win/Tiny6410/linux-tiny6410指明内核代码位置;make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm,-C进入到内核代码中,M指明内核模块的位置。 

1.6.3 内核模块可选信息

1,模块申明

(1)申明该模块遵守的许可证协议,如:“GPL”,“GPL v2”等

     MODULE_LICENSE("GPL")

(2)申明模块的作者

     MODULE_AUTHOR("JON")

(3)申明模块的功能

    MODULE_DESCRIPTION("描述模块的功能")

(4)申明模块的版本

    MODULE_VERSION("V1.0")

2,模块参数

在应用程序中int main(int argc, char** argv)。argc表示命令行输入的参数个数,argv中保存输入的参数。通过宏module_param指定保存模块参数的变量。模块参数用于在加载模块时传递参数给模块。

module_param(name,type,perm);

说明:

name:变量的名称

type:变量类型,bool:布尔型 int:整型 charp:字符串型

perm:是访问权限。S_IRUGO:读权限 S_IWUSR:写权限

3,符号导出

如果内核模块中的变量或函数等要提供给其他内核模块使用,必须使用宏EXPORT_SYMBOL(或者EXPORT_SYMBOL_GPL)将符号导出。

EXPORT_SYMBOL(符号名)

EXPORT_SYMBOL_GPL(符号名)

说明:其中EXPORT_SYMBOL_GPL只能用于包含GPL许可证的模块。

//helloworld.c
#include<linux/init.h>
#include<linux/module.h>
extern int add(int a,int b);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("hello world");
MODULE_VERSION("V1.0");
int a=3;

module_param(a,int,S_IRUGO|S_IWUSR);

static int hello_init(){
    printk(KERN_WARNING"hello world!\n");
    printk("a=%d\n",a);
    return 0;
}

static int hello_exit(){
    int i;
    i=add(3,4);
    printk("3+4=%d\n");
    printk(KERN_WARNING"hello exit!\n");
    return 0;
}

module_init(hello_init);
module_exit(hello_exit);

//add.c
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("hello world");
MODULE_VERSION("V1.0");
int add(int a,int b){
    return (a+b);
}

static int add_init(){
    return 0;
}

static int add_exit(){
    return 0;
}

EXPORT_SYMBOL(add);
module_init(add_init);
module_exit(add_exit);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值