概述
linux设备驱动服务于应用程序,是链接硬件设备和应用程序之间的桥梁。主要做两部分工作:
1、操作硬件。
2、给用户提供访问操作硬件的接口(函数)。
驱动程序
1、驱动入口函数通过module_init指定,函数类型为int func(void)。
/* 驱动加载时执行,调用insmod或者modprobe加载驱动 */ static int __init drv_base_init(void) { printk("hello : drv_base_init\n"); return 0; } module_init(drv_base_init); /* 指定入口函数 */
2、驱动出口函数通过module_exit指定,函数类型为void func(void)。
/* 驱动卸载时执行,调用rmsmod或者modprobe -r卸载驱动 */ static void __exit drv_base_exit(void) { printk("bye : drv_base_exit\n"); } module_exit(drv_base_exit); /* 指定出口函数 */
3、模块许可证通过MODULE_LICENSE声明。
MODULE_LICENSE("GPL"); /* 模块的许可证声明 */
4、模块的其它说明,包括作者、版本号、描述等,调用命令modinfo查看。
/* 调用modinfo xx(模块名)查看 */ MODULE_AUTHOR("feng"); /* 模块的作者 */ MODULE_VERSION ("1.00"); /* 模块版本号 */ /* MODULE_DESCRIPTION("xxxxx"); 模块描述 */ /* MODULE_ALIAS("xxx"); 模块别名 */
Makefile
1、指定路径,包括根文件、驱动存放位置、内核路径等。
#根文件所在目录 ROOTFS_DIR = /home/feng/atomic/rootfs #驱动目录路径 DRV_DIR = $(ROOTFS_DIR)/home/drv DRV_DIR_LIB = $(ROOTFS_DIR)/lib/modules/4.1.15 #内核路径 KERNEL_DIR =/home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga #当前文件路径 CURR_DIR = $(shell pwd)
2、指定编译器。
#交叉编译工具链 CROSS_COMPILE = arm-linux-gnueabihf- CC = $(CROSS_COMPILE)gcc
3、编译模块,注意install命令用于将模块拷贝到目标机指定位置。
#KERNELRELEASE由内核makefile赋值 ifeq ($(KERNELRELEASE), ) all: #编译模块 make -C $(KERNEL_DIR) M=$(CURR_DIR) modules clean: #清除模块文件 make -C $(KERNEL_DIR) M=$(CURR_DIR) clean install: #拷贝模块文件 cp -raf *.ko $(DRV_DIR_LIB) else #指定编译什么文件 obj-m += drv_base.o endif
示例
★包含源文件drv_base.c和makefile文件Makefile(均已验证通过)。
drv_base.c
/** * @Filename : drv_base.c * @Revision : $Revision: 1.00 $ * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅) * @Description : 驱动框架示例 **/ #include <linux/init.h> #include <linux/module.h> /* 驱动加载时执行,调用insmod或者modprobe加载驱动 */ static int __init drv_base_init(void) { printk("hello : drv_base_init\n"); return 0; } /* 驱动卸载时执行,调用rmsmod或者modprobe -r卸载驱动 */ static void __exit drv_base_exit(void) { printk("bye : drv_base_exit\n"); } module_init(drv_base_init); /* 指定入口函数 */ module_exit(drv_base_exit); /* 指定出口函数 */ /* 调用modinfo xx(模块名)查看 */ MODULE_LICENSE("GPL"); /* 模块的许可证声明 */ MODULE_AUTHOR("feng"); /* 模块的作者 */ MODULE_VERSION ("1.00"); /* 模块版本号 */ /* MODULE_DESCRIPTION("xxxxx"); 模块描述 */ /* MODULE_ALIAS("xxx"); 模块别名 */
Makefile
#根文件所在目录 ROOTFS_DIR = /home/feng/atomic/rootfs #交叉编译工具链 CROSS_COMPILE = arm-linux-gnueabihf- CC = $(CROSS_COMPILE)gcc #驱动目录路径 DRV_DIR = $(ROOTFS_DIR)/home/drv DRV_DIR_LIB = $(ROOTFS_DIR)/lib/modules/4.1.15 #KERNELRELEASE由内核makefile赋值 ifeq ($(KERNELRELEASE), ) #内核路径 KERNEL_DIR =/home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga #当前文件路径 CURR_DIR = $(shell pwd) all: #编译模块 make -C $(KERNEL_DIR) M=$(CURR_DIR) modules clean: #清除模块文件 make -C $(KERNEL_DIR) M=$(CURR_DIR) clean install: #拷贝模块文件 cp -raf *.ko $(DRV_DIR_LIB) else #指定编译什么文件 obj-m += drv_base.o endif
结论
1、进入目录,执行make命令,编译模块。
feng:drv_base$ make #编译模块 make -C /home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/mnt/hgfs/Share/linux/atomic/driver/drv_base modules make[1]: 进入目录“/home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga” CC [M] /mnt/hgfs/Share/linux/atomic/driver/drv_base/drv_base.o Building modules, stage 2. MODPOST 1 modules CC /mnt/hgfs/Share/linux/atomic/driver/drv_base/drv_base.mod.o LD [M] /mnt/hgfs/Share/linux/atomic/driver/drv_base/drv_base.ko make[1]: 离开目录“/home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga” feng:drv_base$
2、执行make install命令,拷贝模块到目标机指定位置。
feng:drv_base$ make install #拷贝模块文件 cp -raf *.ko /home/feng/atomic/rootfs/lib/modules/4.1.15 feng:drv_base$
3、装载/卸载模块,在目标机上执行insmod/rmmod命令。
/lib/modules/4.1.15 # insmod drv_base.ko hello : drv_base_init /lib/modules/4.1.15 # lsmod Module Size Used by Tainted: G drv_base 678 0 /lib/modules/4.1.15 # rmmod drv_base bye : drv_base_exit /lib/modules/4.1.15 #
4、也可使用modprobe/modprobe -r装载和卸载模块,注意,在使用之前需要先执行depmod命令,用以分析加载模块的依赖性,并生成modulse.dep文件和映射文件,在多模块的情况下尤其有用。
/lib/modules/4.1.15 # depmod /lib/modules/4.1.15 # ls drv_base.ko modules.alias modules.dep modules.symbols /lib/modules/4.1.15 # modprobe drv_base.ko /lib/modules/4.1.15 # lsmod Module Size Used by Tainted: G drv_base 678 0 /lib/modules/4.1.15 # modprobe -r drv_base bye : drv_base_exit /lib/modules/4.1.15 #
5、查看作者、版本信息,使用modinfo命令。
/lib/modules/4.1.15 # modinfo drv_base filename: drv_base.ko author: feng license: GPL version: 1.00 srcversion: 8C72DB448C1E6781B7DB1A4 depends: vermagic: 4.1.15 SMP preempt mod_unload modversions ARMv6 p2v8 /lib/modules/4.1.15 #
6、综上,在装载模块的时候,程序执行drv_base_init函数,输出hello : drv_base_init,卸载模块时候,程序执行drv_base_exit函数,输出:bye : drv_base_exit,同时执行modinfo查看到作者、版本号与代码中设置一致。
往期 · 推荐
帮你自动化办公的python-自动提取pdf指定页(文件处理篇)
帮你自动化办公的python-自动提取pdf指定页(项目概述)
也没想象中那么神秘的数据结构-一种通用化的双向链表设计(底层源码)
关注
更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:linux驱动源码。