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 \r\n");
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\r\n");
//第一步:将主设备号、次设备号转化成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 \r\n");
return ret;
}
printk(KERN_INFO "register_chrdev_region success\n");
//第二步:创建设备类,注册字符设备!
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\r\n");
return -EBUSY;
}
printk(KERN_INFO "class create success\r\n");
//第三步: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\n");
return -EBUSY;
}
printk(KERN_INFO "cdev_add success\n");
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\r\n");
}
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 \n");
return ;
}else
{
printf("open /dev/hello success! \n");
}
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