嵌入式内核及驱动开发之学习笔记(一) 认识与使用驱动模块
应用层的进程是通过内核层驱动来访问硬件的,Linux内核源码在每次编译之后生成一个总的镜像,将镜像加载内存中运行并使用(内核在系统运行时会占用内核空间)。驱动属于内核源码的一部分,如果每次修改驱动都要重新编译加载内核的话,这太麻烦了,所以我们通过模块,使驱动可以独立于内核镜像之外,并能动态的加载和卸载。
在搭建好开发环境之后,通过source insight我们可以方便的查看和编辑内核源码,并结合交叉编译工具链实现编辑--编译--烧录--执行 的完整开发流程。
- 物理机(Win7) 程序编辑环境
- 虚拟机(Ubuntu14.04) 程序的编译环境
- 开发板(FS4412) 程序的调试运行环境
编写驱动
创建驱动文件hello.c,编辑源码
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/stat.h>
-
-
-
static int __init hello_drv_init(void)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
return 0;
-
}
-
-
static void __exit hello_drv_exit(void)
-
{
-
printk("-------%s-------------\n", __FUNCTION__);
-
}
-
-
-
module_init(hello_drv_init);
-
module_exit(hello_drv_exit);
-
-
MODULE_LICENSE("GPL");
这个简单的驱动模块代码,没有涉及到任何硬件,它的功能是可以在加载和卸载该模块时打印输出信息,仅此。要建立这个框架,分成4个步骤:
1.加载头文件
#include <linux/init.h> 包含模块装卸载函数原型声明
#include <linux/module.h> 这里没有用到其实
#include <linux/stat.h> 包含printk函数的原型声明
2.驱动模块装载/卸载函数声明
module_init(hello_drv_init); 装载 hello_drv_init为回调函数
module_exit(hello_drv_exit); 卸载 hello_drv_exit为回调函数
3.实现函数入口(回调函数实现)
static int __init hello_drv_init(void)
{undefined
return 0;
}
static void __exit hello_drv_exit(void)
{undefined
return ;
}
4.GPL声明
MODULE_LICENSE("GPL"); 一种开源声明
编辑Makefile的规则
用来负责驱动文件的编译和管理。这里make -C参数,借用了内核源码根目录中的Makefile文件的规则来编译驱动代码生成成.ko模块。
-
ROOTFS_DIR = /nfs/rootfs
-
-
ifeq ($(KERNELRELEASE), )
-
-
#利用当前系统的内核中的Makefile进行编译
-
#KERNELDIR:= /lib/modules/$(shell uname -r)/build/
-
-
#或是指定内核源码的根目录
-
KERNEL_DIR = /mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412
-
CUR_DIR = $(shell pwd)
-
-
all :
-
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
-
-
clean :
-
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
-
-
install:
-
cp -raf *.ko $(ROOTFS_DIR)/drv_module
-
-
-
else
-
-
obj-m += hello.o
-
-
-
endif
-
ROOTFS_DIR变量指定 nfs共享根目录
KERNEL_DIR变量指定 内核源码的根目录(绝对路径)
obj-m += hello.o 表示将hello.o这个目标文件编译成模块
编译动作
Ubuntu系统中进入Makefile所在目录
-
linux@linux:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/hello_drv$ make
-
-
linux@linux:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/hello_drv$ make install
加载/卸载模块的指令
在内核运行时
- insmod xxx.ko 装载
- rmmod xxx 卸载
- modinfo 查看
其他
对模块的传参
有时候对原厂开发,一些代码叫做固件,我们不能进入函数的内部去修改参数的默认指定。通过命令行传参
- 手动传递
insmod hello.ko myname="george" myvalue=33
- 函数接收
module_param(name, type, perm)
符号表
使用 EXPORT_SYMBOL 可以将一个函数以符号的方式导出给其他模块使用。原理类似于应用层的动态库。 这样就使模块与模块之间形成依赖关系(使用方依赖于导出符号的模块),例如
EXPORT_SYMBOL(my_add); my_add是导出的函数名
-
//math.c
-
#include <linux/module.h>
-
#include <linux/init.h>
-
-
int my_add(int a, int b)
-
{
-
return a+b;
-
}
-
-
EXPORT_SYMBOL(my_add);
-
-
-
MODULE_LICENSE("GPL");
文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/feit2417/article/details/83994667
- 点赞
- 收藏
- 关注作者
评论(0)