1.利用mdev来实现设备文件的自动创建
因为我的文件系统是基于buildroot的,并且已经配置了mdev。
所以在驱动初始化代码中调用class_create(),为该设备创建一个class,再调用device_create()创建对应的设备。
内核中定义了struct class 结构体,这个类是一个设备高层抽象的属性,隐藏了底层具体实现过程。
2.实例
hello.c
#include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> static int major = 99; //主设备号(用于区分设备类) static int minor = 0; //次设备号(用于区分哪个设备) static dev_t devno; static struct class *hello_class; static struct device *hello_device; static int hello_open(struct inode *inodep, struct file *filep) { printk(KERN_ALERT "hello are opened "); return 0; } //通过file_operations 对应open、close、sleek等文件操作 static struct file_operations hello_ops = { .open = hello_open, }; static int hello_init(void) { int ret; printk(KERN_ALERT "hello_init "); //第一步:将主设备号、次设备号转化成dev_t类型 devno = MKDEV(major, minor); //注册字符设备:在/porc/devices中可以查看设备号 ret = register_chrdev(major, "hello", &hello_ops); if (ret < 0) { printk(KERN_ERR "my register_chrdev fail "); return ret; } printk(KERN_INFO "register_chrdev_region success "); //第二步:创建设备类,注册字符设备! hello_class = class_create(THIS_MODULE, "myclass");//将在/sys/class/下创建maclass文件夹 if (IS_ERR(hello_class)) { unregister_chrdev(major, "hello"); printk(KERN_ERR "class create failed "); return -EBUSY; } printk(KERN_INFO "class create success "); //第三步:2.6内核之后要向sys文件系统中添加设备 hello_device=device_create(hello_class,NULL,devno,NULL,"hello");//此处将在/dev下创建hello设备! if (IS_ERR(hello_device)) { class_destroy(hello_class); unregister_chrdev(major,"hello"); printk(KERN_ERR "Uable to add dev "); return -EBUSY; } printk(KERN_INFO "cdev_add success "); return 0; } static void hello_exit(void) { //先删除设备,再删除类 device_destroy(hello_class,devno); class_destroy(hello_class); unregister_chrdev(major,"hello"); //注销设备号 printk(KERN_ALERT "hell_exit "); } MODULE_LICENSE("GPL"); module_init(hello_init); module_exit(hello_exit);
test.c
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> main() { int fd; fd = open("/dev/hello",O_RDWR); if(fd<0) { perror("open fail "); return ; }else { printf("open /dev/hello success! "); } close(fd); }
makefile
#General Purpose Makefile for cross compile Linux Kernel module ifneq ($(KERNELRELEASE),) obj-m := hello.o #+=是连接字符串 else ARCH := arm CROSS_COMPILE := arm-linux-gnueabihf- KERN_DIR := /home/zqh/lichee/linux-zero-4.14.y #选择内核路径 PWD :=$(shell pwd) #当前路径 all: $(info "1st") make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERN_DIR) M=$(PWD) modules clean: rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order .*.o.ko.cmd .*.ko.cmd .*.mod.o.cmd .*.o.cmd endif
3.现象
# insmod hello.ko # dmesg | tail -20 [ 2.196495] RTL8723BS: rtl8723bs BT-Coex version = BTCOEX20140507-4E40 [ 2.204039] pnetdev = c327f800 [ 2.241016] RTL8723BS: rtw_ndev_init(wlan0) [ 2.247054] RTL8723BS: module init ret =0 [ 2.259012] rtl8723bs: acquire FW from file:rtlwifi/rtl8723bs_nic.bin [ 2.503466] random: crng init done [ 5.493474] RTL8723BS: rtw_set_802_11_connect(wlan0) fw_state = 0x00000008 [ 5.802276] RTL8723BS: start auth [ 5.806943] RTL8723BS: auth success, start assoc [ 5.813025] RTL8723BS: rtw_cfg80211_indicate_connect(wlan0) BSS not found !! [ 5.820189] RTL8723BS: assoc success [ 5.829687] RTL8723BS: send eapol packet [ 5.840116] RTL8723BS: send eapol packet [ 5.844757] RTL8723BS: set pairwise key camid:4, addr:e6:02:9b:c8:c8:41, kid:0, type:AES [ 5.855579] RTL8723BS: set group key camid:5, addr:e6:02:9b:c8:c8:41, kid:2, type:AES [ 93.720373] hello: loading out-of-tree module taints kernel. [ 93.726625] hello_init [ 93.729093] register_chrdev_region success [ 93.733210] class create success [ 93.737712] cdev_add success
# ./test
open /dev/hello success!
# cd /sys/class/myclass/ # ls hello # cd hello/ # ls dev power subsystem uevent
# ls /dev/hello /dev/hello