linux驱动之模块化编程
概念
区别于直接编译源码,可以快速编译功能代码,以模块的形式添加到linux系统中,便于测试,而不是反复修复源码进行编译。
步骤
第1步
包含头文件,并通过MODULE_LICENSE("GPL")
告诉内核模块遵从GPL
协议,这个事情必须要做。MODULE_AUTHOR("CYG")
指定模块的作者,可不写。
第2步
编辑模块的入口函数,一般叫xxx_init
,在模块加载到Linux内核时,Linux会调用该函数。
第3步
编辑模块的出口函数,一般叫xxx_exit
,在模块卸载的时候释放资源。
第4步
内核通过module_init
宏查找入口函数,用module_exit
宏查找出口函数。
注意按该框架进行编程
printk
优先级
printk
函数用法与printf
类似,printf
用于用户空间,printk
用于内核空间。用printk
函数时,内核会根据日志级别,可能把消息打印到当前控制台上。这些消息正常输出的前提是:日志输出级别小于console_loglevel
(在内核中数字越小优先级越高)。日志级别一共有8个,printk
的日志级别定义如下(/linux/kernel.h
):
没有指定日志级别的printk
语句默认采用的级别是DEFAULT_MESSAGE_LOGLEVEL
(这个默认级别一般为<4>,即与KERN_WARNING
一个级别),可以通过 cat /proc/sys/kernel/printk
查看系统默认的日志级别
ring buffer
在 Linux 刚启动内核初始化时,控制台设备还没有初始化的时候,printk 只会把信息输送到 ring buffer 中,等控制台设备初始化好后,再根据 ring buffer 中消息的优先级决定是否需要输送到控制台设备上。可以通过dmesg
或dmesg|tail
读取 ring buffer(环形缓冲区)信息,通过dmesg -c
清空 ring buffer。
模块编译
第1步
调用 Linux 源码树的 Makefile 进行收集编译一个模块所需要的信息
第2步
Linux 源码树的 Makefile 收集玩信息后,调用模块的 Makefile 获取需要编译成模块的.c
文件,最后生成模块.ko
模块的 Makefile 实例如下:
obj-m := hello.o
KERNELDIR := /home/fa/linux-3.4.y
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
make -C 表示调用指定路径下的 Makefile ,M 后边跟的是模块的绝对路径,modules 告诉 Makefile 要进行模块编译。当我们在调用 Linux 内核源码树顶层的 Makefile 时,找到的是顶层 Makefile 的modules
目标,截取片段如下:
obj-m := hello.o
,这里的obj=m
告诉 Linux 源码树的顶层 Makefile 是动态编译(编译成模块),而不是编译进内核(obj-y),顶层Makefile会根据 hello.o 去找到 hello.c 文件。
模块的加载&卸载
$ insmod xxx.ko #加载,注意只有root超级用户权限才可以添加模块到内核
$ lsmod #查看模块
$ rmmod xxx.ko #卸载模块
实例
编写 hello 驱动
//hell.c
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
//加载或卸载时会有打印
# Makefile
obj-m := hello.o
KERNELDIR := /home/fa/linux-3.4.y
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
注意 makefile 的格式,如果直接 copy 可能会有格式错误,最好使用 vim 检查一下
上一篇: 触摸屏
下一篇: 字符设备驱动----LED驱动程序