包含模块参数在内的hello world驱动:(hello.c)
#include#include #include #include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andy"); MODULE_DESCRIPTION("Fist Test Module!"); MODULE_VERSION("1.0"); // 模块参数 // 加载时,使用中 都可以进行修改值 // su 权限修改有问题,需要切换到root账户修改 /sys/module/hello/parameters/paramx int param1 = 10; unsigned char param2 = 20; char* param3 = "<7>"; int param4[4] = {1,3,1,4}; module_param(param1,int,0755); module_param(param2,byte,0750); module_param(param3,charp,0644); module_param_array(param4, int, NULL, 0700); #define MYMAJOR 200 #define MYCNT 2 #define MYNAME "helloCHR" static struct cdev hello_cdev; static struct class* hello_class; static struct device* hello_class_dev[2]; static int helloOpen(struct inode *inode, struct file *filp) { printk( KERN_ERR"hello_openn"); printk("open: p1=%d, p2=%d, p3=%s, p4=[%d,%d,%d,%d]n", param1, param2, param3, param4[0],param4[1],param4[2],param4[3]); return 0; } //构建file_operations结构体 static struct file_operations hello_fops = { .owner = THIS_MODULE, .open = helloOpen, // 就是这个.open对应的函数 // .release = test_chrdev_release, // .write = test_chrdev_write, // .read = test_chrdev_read, }; static int helloInit(void) { int i; dev_t devid = MKDEV(MYMAJOR, 0); printk( KERN_ERR "Hello, kernel!n"); printk("init: p1=%d, p2=%d, p3=%s, p4=[%d,%d,%d,%d]n", param1, param2, param3, param4[0],param4[1],param4[2],param4[3]); // int register_chrdev_region(dev_t from, unsigned count, const char *name) register_chrdev_region(devid, MYCNT, MYNAME); // 绑定 cdev_init(&hello_cdev, &hello_fops); // 注册 cdev_add(&hello_cdev, devid, MYCNT); // 创建user space设备 hello_class = class_create(THIS_MODULE, "helloCls"); for(i=0;i hello_class_dev[i] = device_create(hello_class,NULL,MKDEV(MYMAJOR,i),NULL,"helloDev%d", i); } return 0; } static void helloExit(void) { int i; printk( KERN_ERR "hello exit!"); // rm dev cdev_del(&hello_cdev); unregister_chrdev_region(MKDEV(MYMAJOR, 0), MYCNT); // del user space device for(i=0;i device_destroy(hello_class, MKDEV(MYMAJOR,i)); } class_destroy(hello_class); } module_init(helloInit); module_exit(helloExit); // kernel default print level => /proc/sys/kernel/printk // 4 4 1 7 => 内核默认打印级别 printk默认级别 xxx xxxx // echo 5 > /proc/sys/kernel/printk // 修改内核默认级别,高于5的log才能打印 <= 重启失效,并且有权限问题 // 修改uboot环境变量, set bootargs xxx=yy ... loglevel=8
注意:printk(“…n”)一定要带上换行符,否则 tail -f /var/log/kern.log不能及时输出日志。
Makefile
# ifneq ($(KERNELRELEASE),) # mymodule-bojs := hello.o PWD := $(shell pwd) KERNELDIR = /lib/modules/$(shell uname -r)/build obj-m := hello.o build: all all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
注意参数的权限问题:
- 只有设置了其他权限的能够被其他账户访问或修改,如果使用sudo insmod在0750以及以上权限会提示权限问题。建议切换到root账户进行测试
- 如果sudo修改权限时遇到问题,切换到root账户修改
测试文件:(hello_call.c)
#include#include #include #include #include int main(int argc, char const *argv[]) { int fd = open(argv[1],O_RDWR); if(-1==fd) { printf("Can't open!n"); return ; } printf("Open OK!n"); return 0; }
编译为可执行文件使用,并且使用sudo或者root进行测试。
导出函数、符号并不是所有的模块都需要导出函数/符号,只有需要的时候导出给其他模块使用。
symbol.c
#include#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andy"); MODULE_DESCRIPTION("Fist Test symbol export Module!"); MODULE_VERSION("1.0"); int add (int a, int b){ return a+b; } int mul(int a, int b){ return a*b; } EXPORT_SYMBOL(add); // 普通导出,所有模块都能访问 EXPORT_SYMBOL_GPL(mul); // GPL导出,只有遵循GPL的模块可以使用
symbol_call.c
#include#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andy"); MODULE_DESCRIPTION("Fist Test call symbol export Module!"); MODULE_VERSION("1.0"); // symbol.c 导出函数, 一般是提供头文件的 // 只有模块能调用模块的导出参数 extern int add(int a, int b); extern int mul(int a, int b); // call static int symbol_call_init(void) { printk("Call symbol function add = %dn", add(2,3)); return 0; } static void symbol_call_exit(void) { printk("Call symbol function mul = %dn", mul(2,3)); } module_init(symbol_call_init); module_exit(symbol_call_exit);
Makefile
# ifneq ($(KERNELRELEASE),) # mymodule-bojs := hello.o PWD := $(shell pwd) KERNELDIR = /lib/modules/$(shell uname -r)/build obj-m := symbol_call.o symbol.o build: all all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
使用:
- make clean & make
- sudo tail -f /var/log/kern.log
- sudo insmod symbol.ko
- sudo insmod symbol_call.ko
- sudo rmmod symbol_call
- sudo rmmod symbol
所以symbol模块只有导出功能,symbol_call模块引用symbol的导出函数使用。
至此,一个驱动模块所缺的所有功能都已经完备,只有虚拟设备/dev/helloDev0的open函数提供了接口,其他函数需要继续完善。



