LINUX字符型设备驱动 二.自动创建设备节点

时间:2020-12-03 19:02:10

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