作为驱动的开始,我们来看一看:
1. 底层函数和上层函数的不同:
|
app(c)
|
驱动模块
|
入口函数 |
main
|
加载函数
|
库
|
应用层的库(usr/lib)
| 内核API |
运行空间 |
用户空间(高3G的内存)
|
内核空间(低1G)
|
释放资源
|
要求释放
|
必须释放
|
2.写一个模块要有的三要素:
- 模块许可证的声明 MODULE_LICENSE("GPL");
- 模块加载函数 __init 标识,或者module_init(xx)
- 模块卸载函数 __exit 标识,或者module_exit(xxx)
-- 其他还可以有:模块的作者,描述,模块导出符号,参数等信息声明
MODULE_AUTHOR("DDD");
MODULE_DESCRIPTION("DDD");
MODULE_SUPPORTED_DEVICE("Test...");
3. 模块编译和装载的命令:
在linux端的命令如下:
- insmod,将某个模块插入到加载,如果有 printk 可以用 dmesg 查看
- rmmod,将某个模块从内核中删除
- lsmod,显示所有已经被内核调入的模块
- modinfo,关键点是 vermagic:3.2.0-29... 是模块运行的内核版本
- modprobe,智能加载,如果依赖别的模块,会加载上别的模块
添加一个Makefile文件,文件内容如下:
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
#KERNELDIR ?= ~/wor_lip/linux-3.4.112
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules* Module*
.PHONY: modules modules_install clean
else
obj-m := hello.o
endif
其中需要改动的是:
KERNELDIR :内核所在路径,如果想要模块在开发板上运行,需要添加制作开发板上的linux内核源码所在路径,就是上边注释掉的部分,如果是要在自己的ubuntu中运行,未注释掉的部分就是。
obj-m:你要生成的xxx.ko ,就要改成 xxx.o
4. 模块编写的两种方式:
默认模式
自定义模式
5. 向模块内传参:--insmod传参
5.1 声明
5.1.1 基本数据类型:
基本数据类型包括 bool/invbool/short/int/long/uint/ushort/ulong
module_param(mystring, bool/invbool/short/int/long/uint/ushort/ulong, 0000); 声明可以从命令行取得参数,括号中的参数一次表示:变量名,变量类型,权限
0000 的介绍:
数字的大小表示的是 读写权限 , r w x,分别代表可读,可写,可执行,最大数字是 6,模块没有可执行的权限
这里还要说明的一点是,这个读写权限表示的是
/sys/modules/ 中模块的名字文件夹下边的变量名字的文件,
这里的文件可以用cat 来查看,echo A > B 来写(写的时候要先变身,su ),并且起作用
数字的位置表示的是 按从左到右 依次是 ,超级用户,用户组,。。
5.1.2 char*,...: --指针
module_param(mystring, charp, 0000);
5.1.3 array[]: --数组,传参用逗号隔开
module_param_array(array, int/.., &arr_argc, 0000);
int/..,数组中成员的数据类型
arr_argc,用于存放系统记录用户传入的数据个数
注意:
声明的数据都要进行初始化。
5.2 加载的时候传参的操作:
对基本数据传参,在insmod的时候,变量名=数据,多个参数空格隔开
对数组传参,在insmod的时候,数组名=数组成员1的数据,数组成员2的参数。用的是逗号隔开
module_param
module_param_array(array, int/.., &arr_argc, 0000);
int/..,数组中成员的数据类型
arr_argc,用于存放系统记录用户传入的数据个数
注意:
声明的数据都要进行初始化。