本文首先描述了一个可以实际测试运行的驱动实例,之后由此去讨论Linux下驱动模板的要素,以及Linux上应用程序到驱动的执行过程。相信这样由浅入深、由具体实例到具象理论的描述更容易初学者入手Linux驱动的房门。
一、一个简单的驱动程序实例
驱动文件hello.c
#include #include #include #include #include #define HELLO_MAJOR 231 #define DEVICE_NAME "HelloModule" static int hello_open(struct inode *inode, struct file *file){ printk(KERN_EMERG "hello open.n"); return 0; } static ssize_t hello_write(struct file *file, const char __user * buf, size_t count, loff_t *ppos){ printk(KERN_EMERG "hello write.n"); return 0; } static struct file_operations hello_flops = { .owner = THIS_MODULE, .open = hello_open, .write = hello_write, }; static int __init hello_init(void){ int ret; ret = register_chrdev(HELLO_MAJOR,DEVICE_NAME, &hello_flops); if (ret < 0) { printk(KERN_EMERG DEVICE_NAME " can't register major number.n"); return ret; } printk(KERN_EMERG DEVICE_NAME " initialized.n"); return 0; } static void __exit hello_exit(void){ unregister_chrdev(HELLO_MAJOR, DEVICE_NAME); printk(KERN_EMERG DEVICE_NAME " removed.n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");
驱动文件主要包括函数hello_open、hello_write、hello_init、hello_exit,测试案例中并没有赋于驱动模块具有实际意义的功能linux 驱动 makefile北京linux培训,只是通过复印日志的形式告知控制台一些调试信息,这样我们就可以掌握驱动程序的执行过程。
在使用printk复印的时侯,在参数中加上了“KERN_EMERG”可以确保待复印信息输出到控制台上。因为printk复印分8个等级,等级高的被复印到控制台上,而等级低的却输出到日志文件中。
编译驱动所需的Makefile
ifneq ($(KERNELRELEASE),) MODULE_NAME = hellomodule $(MODULE_NAME)-objs := hello.o obj-m := $(MODULE_NAME).o else KERNEL_DIR = /lib/modules/`uname -r`/build MODULEDIR := $(shell pwd) .PHONY: modules default: modules modules: make -C $(KERNEL_DIR) M=$(MODULEDIR) modules clean distclean: rm -f *.o *.mod.c .*.*.cmd *.ko rm -rf .tmp_versions endif
编译驱动文件须要一个合适的makefile,由于编译驱动的时侯须要晓得内核头文件,编译规则等。
测试驱动的下层应用代码hellotest.c
#include #include int main(void) { int fd; int val = 1; fd = open("/dev/hellodev", O_RDWR); if(fd < 0){ printf("can't open!n"); } write(fd, &val, 4); return 0; }
下层测试案例中,首先打开设备文件,之后向设备中写入数据。这般,则会调用驱动中对应的xxx_open和xxx_write函数,通过驱动程序的复印信息可以判定是否真的如愿执行了对应的函数。
二、驱动实例测试
测试的方式整体来说就是,编译驱动和下层测试应用;加载驱动,通过下层应用调用驱动;最后,卸载驱动。
1、编译驱动
#make
make命令,直接调用Makefile编译hello.c,最后会生成“hellomodule.ko”。
2、编译下层应用
#gcc hellotest.c -o hellotest
通过这条命令,能够编译出一个下层应用hellotest。
3、加载驱动
#insmod hellomodule.ko
insmod加载驱动的时侯,会调用函数hello_init(),复印的调试信息如下。
据悉,在"/proc/devices"中可以见到早已加载的模块。
4、创建节点
尽管已然加载了驱动hellomodule.ko,并且在/proc/devices文件中也看见了早已加载的模块HelloModule,然而这个模块依然不能被使用,由于在设备目录/dev目录下还没有它对应的设备文件。所以,须要创建一个设备节点。
#mknod /dev/hellodev c 231 0
在/proc/devices中见到HelloModule模块的主设备号为231,创建节点的时侯就是将设备文件/dev/hellodev与主设备号构建联接。这样在应用程序操作文件/dev/hellodev的时侯,都会定位到模块HelloModule。
/proc/devices与/dev的区别
5、上层应用调用驱动
#./hellotest
hellotest应用程序先打开文件“/dev/hellodev”,之后向此文件中写入一个变量val。期间会调用底层驱动中的hello_open和hello_write函数,hellotest的运行结果如下所示。
6、卸载驱动
#rmmod hellomodule
insmod卸载驱动的时侯,会调用函数hello_exit(),复印的调试信息如下。
总结一个模块的操作流程:
(1)通过insmod命令注册module
(2)通过mknod命令在/dev目录下构建一个设备文件"xxx",并通过主设备号与module构建联接
(3)应用程序层通过设备文件/dev/xxx对底层module进行操作
三、驱动模板
从宏观上掌握了驱动程序的框架,之后再从细节上建立驱动的功能linux 驱动 makefile,这是开发驱动程序的通常步骤。驱动模板必备要素有头文件、初始化函数、退出函数、版权信息,常用的扩充要素是降低一些功能函数建立底层驱动的功能。
1、头文件
#include #include #include #include #include
init.h定义了驱动的初始化和退出相关的函数
kernel.h定义了常常用到的函数原型及宏定义
module.h定义了内核模块相关的函数、变量及宏
2、初始化函数
static int __init hello_init(void){ int ret; ret = register_chrdev(HELLO_MAJOR,DEVICE_NAME,&hello_flops); if (ret < 0) { printk(KERN_EMERG DEVICE_NAME " can't register major number.n"); return ret; } printk(KERN_EMERG DEVICE_NAME " initialized.n"); return 0; } module_init(hello_init);
当加载驱动到内核的时侯,这个初始化函数才会被手动执行。
初始化函数顾名思义是拿来初始化模块的,常用的功能是通过register_chrdev来注册函数。内核分配了一块显存(字段)专门拿来储存字符设备的函数集,register_chrdev函数会在这个字段的HELLO_MAJOR位置将hello_flops中的内容进行填充,也就是将HelloModule的功能函数地址注册到设备管理显存集中。
形象的比喻似乎是操作系统提供了好多的鞋子架,注册设备就似乎是把一个衣物挂到某一个衣物架上。校服上有许多口袋,就似乎每一个模块有许多功能程序插口。其实,假如想使用设备的某个功能,就可以先找到对应的衣物架,之后找到相应的口袋,去调用对应的函数,执行动作。
3、退出函数
static void __exit hello_exit(void){ unregister_chrdev(HELLO_MAJOR, DEVICE_NAME); printk(KERN_EMERG DEVICE_NAME " removed.n"); } module_exit(hello_exit);
当卸载驱动的时侯,退出函数便会手动执行,完成一些列清楚工作。
在加载驱动的时侯,我们向设备管理显存集中注册了该模块的相关功能函数。当卸载驱动的时侯,就有必要将这个模块占用的显存空间清空。这样当其他的设备注册的时侯便有更多的空间可以选择。
形象的比喻是,当卸载驱动的时侯linux,就是把衣服从衣物架上取出来,这样衣物架就腾空了。
文章评论