文章目录
1,驱动模块开发
驱动代码需要有四个部分
1.头文件
2.驱动模块装载和卸载函数入口声明
3.实现模块装载和卸载函数入口
4.GPL声明
1.1,编辑驱动代码hell.c
在Ubuntu下Samba共享文件夹中组织自己的目录结构
linux@linux:~/share$ mkdir my_driver
linux@linux:~/share$ cd my_driver/
linux@linux:~/share/my_driver$ mkdir 1_driver
linux@linux:~/share/my_driver$ cd 1_driver/
linux@linux:~/share/my_driver/1_driver$ mkdir hello_drv
linux@linux:~/share/my_driver/1_driver$ cd hello_drv/
linux@linux:~/share/my_driver/1_driver/hello_drv$ touch hello.c
linux@linux:~/share/my_driver/1_driver/hello_drv$ ls
hello.c
在Windows下将Samba共享文件夹中的驱动程序拖到source insight中编辑
1.1.1,例—驱动代码hello.c
/*
驱动代码需要有四个部分
1.头文件
2.驱动模块装载和卸载函数入口声明
3.实现模块装载和卸载函数入口
4.GPL声明
*/
//头文件
#include <linux/init.h>
#include <linux/module.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);
//GPL声明
MODULE_LICENSE("GPL");
1.2,编写Makefile
- Mkaefile会被读两次
- 第一次是make的时候,这时候主要读取的路径
- 第二次是内核源码变异的时候,这时候,内核源码要知道要把该路径下哪个文件编译成ko
1.2.1,例—Makefile
ROOTFS_DIR = /nfs/rootfs#根文件系统路径
ifeq ($(KERNELRELEASE),)
KERNEL_DIR = /home/linux/linux-3.14.79 #编译过的内核源码的路径
CPU_DIR = $(shell pwd) #当前路径
all:
make -C $(KERNEL_DIR) M=$(CPU_DIR) modules #把当前路径编成modules
@#make -C 进入到内核路径
@#M 指定当前路径(模块位置)
clean:
make -C $(KERNEL_DIR) M=$(CPU_DIR) clean
install:
sudo cp -raf *.ko $(ROOTFS_DIR)/drv_module #把当前的所有.ko文件考到根文件系统的drv_module目录
else
obj-m += hello.o #指定内核要把哪个文件编译成ko
endif
1.3,insmod 加载ko模块
1.4,lsmod 查看系统中装载了哪些模块
1.5,rmmod 卸载ko模块
注意:卸载时是驱动名,不加后缀.ko
2,模块ko参数传递
- 加载模块时
insmod hello.ko myname="xinyuan" 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);
传参(当驱动内部已经定义了参数后,优先使用外部传入的参数)
3,ko模块的符号导出
3.1,新建math.c
#include <linux/init.h>
#include <linux/module.h>
//不需要模块加载和卸载的入口申明,直接定义好一些封装的函数
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");
3.2,新建math.h
#ifndef __MATH_H__
#define __MATH_H__
int my_add(int a,int b);
int my_sub(int a,int b);
#endif
3.3,修改Makefile
3.4,hello.c
/*
驱动代码需要有四个部分
1.头文件
2.驱动模块装载和卸载函数入口声明
3.实现模块装载和卸载函数入口
4.GPL声明
*/
//头文件
#include <linux/init.h>
#include <linux/module.h>
#include "math.h"
static int myvalue = 56;
static char *myname = "xinyuan";
//实现模块装载和卸载函数入口
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,12));
return 0;
}
static void __exit hello_drv_exit(void)
{
//释放资源
printk("-----------%s-------------\n",__FUNCTION__);
}
//驱动模块装载和卸载函数入口声明
module_init(hello_drv_init);
module_exit(hello_drv_exit);
//GPL声明
MODULE_LICENSE("GPL");
//传参(当驱动内部已经定义了参数后,优先使用外部传入的参数)
module_param(myvalue,int,0644);
module_param(myname,charp,S_IRUGO|S_IWUSR);
3.5,调用模块符号
hello.ko里面调用了math.ko中的符号,所以要先加载math.ko