驱动开发初探
驱动分为四个部分:
- 头文件
- 驱动模块的入口函数和出口函数
- 声明信息
- 功能实现
创建一个 helloworld.c文件。
// 第一步,包含头文件
#include <linux/init.h> // 包含宏定义的头文件
#include <linux/module.h> // 包含初始化加载模块的头文件
// 第二步,驱动模块的入口函数和出口函数
module_init();
module_exit();
// 第三步,声明模块拥有开源许可证
MODULE_LICENSE("GPL");
// 第四步,功能实现:
// 内核模块加载的时候打印 hello world! ,内核模块卸载的时候打印 goodbye!
// 注意:内核打印函数不能用printf,因为内核没有办法使用C语言库。
static int hello_init(void)
{
printk("hello world!\n");
return 0;
}
static void hello_exit(void)
{
printk("goodbye!\n");
}
完整的一个最简单的Linux内核模块:
#include <linux/init.h>
#include <linux/module.h>
static int hello_init(void)
{
printk("hello world!\n");
return 0;
}
static void hello_exit(void)
{
printk("goodbye!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
代码中的陌生元素是linux内核为了字符设备,以实现驱动与内核接口而定义的。Linux对各类设备的驱动都定义了类似的数据结构和函数。
内核模块
Linux 设备驱动会以内核模块的形式出现,因此,学会编写Linux内核模块编程是学习Linux设备驱动的先决条件。
内核模块简介
编译驱动有两种方式:
- 第一种方法:
- Linux提供了这样的机制,这种机制被称为模块(Module)。把驱动编译成模块,然后使用命令把驱动加载到内核里面。模块本身不被编译入内核映像,从而控制了内核的大小。模块一旦被加载,它就和内核中的其他部分完全一样。
- 第二种方法:
- 直接把驱动编译到内核中。
将helloworld.c编译成驱动文件
创建 Makefile 文件,内容如下:
#先写生成的中间文件的名字是什么,-m 的意思是把我们的驱动编译成模块
obj-m += helloworld.o
KDIR:=/home/topeet/driver/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga/
#获取当前目录的变量
PWD?=$(shell pwd)
#make 会进入内核源码的路径,然后把当前路径下的代码编译成模块
all:
make -C $(KDIR) M=$(PWD) modules
注意:
- KDIR:=/home/topeet/driver/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga/ 是设备树内核的源码路径,需要根据自己的实际情况进行修改。
- 设备树内核源码一定要先编译通过,才能编译驱动,否则会报错。
- make -C 前面的空格是一个tab键
设备交叉编译器,输入以下命令:
export CROSS_COMPILE=arm-none-linux-gnueabi-
export ARCH=arm
设置环境变量,输入以下命令:
export PATH=/usr/local/arm/gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12/fsl-linaro-toolchain/bin:$PATH
然后输入“echo $PATH” 查看环境变量是否设置成功。
编译环境准备完毕,将helloworld.c拷贝到Makefile同级目录,然后输入命令“make”,进行编译。
编译它会生成 helloworld.ko 目标文件。
测试驱动
通过“nfs”将编译好的驱动程序在开发板上加载驱动模块。
进入共享目录,输入命令“insmod helloworld.ko”,可以看到编写的helloworld驱动加载成功,打印出“hello world!”。
输入命令“rmmod helloworld”,可以看到helloworld驱动拆卸成功,打印“goodbye!”。
如果出现报错:
rmmod: can't change directory to '4.14.2': No such file or directory
输入以下命令在 lib/modules 下新建4.14.2的文件夹就好了
mkdir /lib/modules/4.14.2
在Linux中,使用lsmod命令可以获得系统中已加载的所有模块以及模块间的依赖关系。
卸载驱动模块,使用rmmod命令,注意,不要加ko的后缀
rmmod helloworld