驱动开发环境搭建好了,下面就可以开发驱动了,但是怎么开始第一个驱动呢,我们开发其他软件的时候都是习惯先编写个hello world,这个驱动我们也从这个开始最简单的驱动 开始,开启驱动的大门。
编译驱动前提,内核预先编译好。
一. 编写驱动代码
1,用什么工具去写---source insight(看代码的工具)
新建工程的方法不多说,环境搭建部分我们已经说明。
2,怎么写
在souceinsght去写?
驱动的编写是有规则的,记住规则套用就可以了。
驱动代码需要有四个部分
hello_world.c
/*******************************
1,头文件
2,驱动模块装载和卸载函数入口到声明
3,实现模块装载和卸载函数入口
4,GPL声明
********************************/
#include
#include
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");
二 .编译驱动代码--Makefile (.ko)
编写makefile文件:(当前的makefile实际上被读取两次)
ROOTFS_DIR = /nfs/rootfs //选择自己的根文件系统路径
ifeq ($(KERNELRELEASE), )
//内核源码到路径,不同环境会不一样,内核源码一定要先编译
KERNEL_DIR = /home/george/Linux_4412/kernel/linux-3.14
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 //把Ko放到我们的根文件系统中
else
//用于指定到底编译哪个代码--hello.c
obj-m += hello_world.o
endif
三. 装载和卸载驱动
开发板上电,通过串口进行打印信息查看,此时已经通过tftp加载了最新的内核
加载内核:
但是出现了报错,百度说是加载的和编译的内核版本不一致导致的。
查看了一下开发板的内核
确实不对,重新编译下内核,和设备树,拷贝到/tftpboot/目录下。
然后就可以正常加载了。
卸载也没什么问题了。
四.参数传递
加载ko: insmod hello.ko myname="george" myvalue=33
用途: wifi驱动,wifi硬件中内部也运行内部代码,原厂开发,这些代码叫做固件--firmware.bin
装载wifi驱动,必须告诉固件到文件在哪里
insmod rtxxx.ko path=/lib/modules/firmware/xxx.bin
在代码如何处理参数:
module_param(name, type, perm)
参数1:表示参数到名字,比如myname, myvalue
参数2:参数到类型, charp, int
参数3: /sys/modules/表示文件到权限: 0666
用法:
module_param(myvalue, int, 0666);
module_param(myname, charp, S_IRUGO|S_IWUGO|S_IXUGO);
/*******************************
1,头文件
2,驱动模块装载和卸载函数入口到声明
3,实现模块装载和卸载函数入口
4,GPL声明
********************************/
#include
#include
static int myvalue = 56;
static char *myname = "li";
static int __init hello_drv_init(void)
{
//一般做系统资源申请
printk("-------%s-------------\n", __FUNCTION__);
printk("name =%s,value=%d\n",myname,myvalue);
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");
module_param(myvalue,int,0644);
module_param(myname, charp, 0644);
五.符号导出
模块化设计,自己写好的代码按功能单独封装在一个KO里面,EXPORT_SYMBOL之后就将函数放到了全局符号表(一个链式结构),内核可以找到相应的函数。其他模块可以调用它实现代码的共用。有点类似于动态库。
#include
#include
//不需要模块加载和卸载到入口声明,直接定义好一些封装的函数
int my_add(int a, int b)
{
return a+b;
}
EXPORT_SYMBOL(my_add);
int my_sub(int a, int b)
{
return a-b;
}
EXPORT_SYMBOL(my_sub);
MODULE_LICENSE("GPL");
#include
#include
#include
#include "math.h"
static int myvalue = 56;
static char *myname = "peter";
static int __init hello_drv_init(void)
{
//一般做系统申请资源
printk("-------%s-------------\n", __FUNCTION__);
printk("name = %s, value = %d\n", myname, myvalue);
printk("a+b = %d, a-b = %d\n", my_add(33,22), my_sub(44,22));
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");
module_param(myvalue, int, 0644);
module_param(myname, charp, S_IRUGO|S_IWUSR);
math.h
#ifndef __MATH_H__
#define __MATH_H__
int my_add(int a, int b);
int my_sub(int a, int b);
#endif
编译好ko文件后,设备进行加载
出现了报错。。
原因是math.ko还没有在内核中,先insmod math.ko进行装载,然后ls /sys/module/进行查看,此时math已经有了
再进行hello world的装载就成功了。