#include <linux/kernel.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/fs.h> #define HELLO_MAJOR 250 #define HELLO_MINOR 0 #define DEV_NUM 1 #define DEV_NAME "hello_world" dev_t devno; struct cdev hello_cdev; struct file_operations hello_fops={ .owner = THIS_MODULE, }; int __init hello_init(void) { int ret; //申请设备号 devno = MKDEV(HELLO_MAJOR,HELLO_MINOR); //注册设备号 ret = register_chrdev_region(devno,DEV_NUM,DEV_NAME); if (ret < 0) { printk(" register_chrdev_region fail!!!\n"); ret = alloc_chrdev_region(&devno,HELLO_MINOR,DEV_NUM,DEV_NAME); if (ret < 0) { printk(" alloc_chrdev_region fail!!!\n"); return -EFAULT; } } //printk(" register_chrdev_region success!!!\n"); printk(" major = %d,minor = %d\n",MAJOR(devno),MINOR(devno)); //申请字符设备 //初始化字符设备 cdev_init(&hello_cdev,&hello_fops); hello_cdev.owner = THIS_MODULE; //注册字符设备 ret = cdev_add(&hello_cdev,devno,DEV_NUM); if (ret < 0) { printk(" cdev_add fail !!!\n"); return -EFAULT; } printk(" cdev_add success!!!\n"); printk(" hello_init!!!\n"); return 0; } module_init(hello_init); void __exit hello_exit(void) { printk(" hello_exit!!!\n"); cdev_del(&hello_cdev); printk(" cdev_del!!!\n"); unregister_chrdev_region(devno,DEV_NUM); printk(" unregister_chrdev_region!!!\n"); } module_exit(hello_exit); MODULE_LICENSE("GPL");
ifeq ($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname -r)/build/ #KERNELDIR ?= /home/linux/linux-3.14/ PWD := $(shell pwd) module: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean .PHONY: module clean else obj-m += hello.o endif
Makefile文件解析:
ifeq ($(KERNELRELEASE),)
内核源码底层Makefile文件中定义的变量,判断变量是否为空值,如果为空,跳到else后面执行语句,并且对变量赋值
KERNELDIR ?= /lib/modules/$(shell uname -r)/build/ 定义一个内核路径
PWD ?= $(shell pwd) 定义一个当前路径的变量
module:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
$(MAKE) 在这里等价make
-C $(KERNELDIR) 链接到内核路径
M=$(PWD) modules 指定要编译的模块的路径,并编译
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
调用内核中Makefile文件命令清空中间文件和最终目标文件
.PHONY: module clean
指定目标文件为伪目标文件,当我执行目标文件时,后面的命令必须要执行。
else
obj-m += xxx.o
endif