正点原子RK3568学习日志13-创建设备节点
1.创建设备节点
驱动编译成驱动模块ko 运行驱动编译成模块insmod
前面成功的申请了设备号并且注册了相应的字符设备
系统通过设备号对设备进行查找,而字符设备注册到内核并不能直接进行设备文件操作命令(打开、关闭、读、写等)
需要相应的设备文件作为桥梁以此来进行设备的访问——设备节点
设备节点被创建在/dev目录下,将内核中注册的设备与用户层进行链接,应用程序才能对设备进行访问
/sys/class/ 目录——class_create(…)函数对class进行创建
/include/linux/device.h”文件——class_create(…)函数对class进行创建
内核源码/include/linux/device.h”文件——class_destroy(…)函数
内核源码/include/linux/device.h”文件——device_create(…)函数
内核源码/include/linux/device.h”文件——device_destroy(…)函数
手动创建设备节点
mknod NAME TYPE MAJOR MINOR
要创建的节点名称
b表示块设备,c表示字符设备,p表示管道
要链接设备的主设备号
要链接设备的从设备号
rk3568创建一个名为device_test的字符设备节点,链接设备的主设备号和从设备号分别为236和0
mknod /dev/device_test c 236 0
自动创建设备节点
利用udev(mdev)机制来实现
首先使用class_create(…)函数对class进行创建,这个类存放于/sys/class/ 目录下
之后使用device_create(…)函数创建相应的设备,在进行模块加载时,用户空间中的udev会自动响应device_create()函数,寻找对应的类从而创建设备节点
class_create(…)函数
用于动态创建设备的逻辑类,并完成部分字段的初始化,然后将其添加进Linux内核系统
#define class_create(owner, name) \({ \static struct lock_class_key __key; \__class_create(owner, name, &__key); \ })
struct module结构体类型的指针,指向函数即将创建的这个structclass的模块。一般赋值为THIS_MODULE
char类型的指针,代表即将创建的struct class变量的名字
返回值:struct class * 类型的结构体。
device_create(…)函数
用来在class类中下创建一个设备属性文件,udev会自动识别从而进行设备节点的创建
struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata,const char *fmt, ...);
指定所要创建的设备所从属的类
指定该设备的父设备,如果没有就指定为NULL
指定创建设备的设备号
被添加到该设备回调的数据,没有则指定为NULL
添加到系统的设备节点名称
返回值:struct device * 类型结构体
class_destroy(…)函数
用于删除设备的逻辑类,即从Linux内核系统中删除设备的逻辑类
extern void class_destroy(struct class *cls);
struct module结构体类型的指针,指向函数即将创建的这个struct class的模块。一般赋值为THIS_MODULE
char类型的指针,代表即将创建的struct class变量的名字
device_destroy(…)函数
用来删除class类中的设备属性文件,udev会自动识别从而进行设备节点的删除
extern void device_destroy(struct class *cls, dev_t devt);
指定所要创建的设备所从属的类
指定创建设备的设备号
static struct class *class_test; //表示要创建的类 static struct device *device_test; //表示要创建的设备
class_test = class_create(THIS_MODULE, "class_test"); //创建类,名字为class_testdevice_test = device_create(class_test, NULL, dev_num, NULL, "device_test"); //创建设备,名字为device_test
device_destroy(class_test, dev_num); //删除设备class_destroy(class_test); //删除类
2.实验:06_node创建设备节点实验
自动申请设备号的方式进行设备号的申请
自动对设备节点进行创建
chrdev_node.c Makefile
chrdev_node.c
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/kdev_t.h> #include <linux/cdev.h>static dev_t dev_num; //定义32位的变量dev_num,用于存放设备号static struct cdev cdev_test; //定义cdev结构体类型的变量cdev_test static struct file_operations cdev_fops_test = { //file_operations结构体.owner = THIS_MODULE, //指向本模块 };static struct class *class_test; //表示要创建的类 static struct device *device_test; //表示要创建的设备static int __init chrdev_fops_init(void) {int ret; //判断函数返回值int major; //定义主设备号变量int minor; //定义次设备号变量//动态申请设备号ret = alloc_chrdev_region(&dev_num, 0, 1, "chrdev_name"); if(ret < 0) //申请失败{printk("alloc_chrdev_region is error\n");}printk("alloc_chrdev_region is ok\n"); major = MAJOR(dev_num); //获取主设备号minor = MINOR(dev_num); //获取次设备号printk("major = %d\n", major); //打印设备号printk("minor = %d\n", minor); //使用cdev_init()初始化cdev_test结构体,并且连接到cdev_fops_test结构体cdev_init(&cdev_test, &cdev_fops_test); cdev_test.owner = THIS_MODULE; //将owner字段指向本模块,防止模块被卸载ret = cdev_add(&cdev_test, dev_num, 1); //注册字符设备到内核if (ret < 0) //注册失败{printk("cdev_add is error\n");}printk("cdev_add is ok\n");class_test = class_create(THIS_MODULE, "class_test"); //创建类,名字为class_testdevice_test = device_create(class_test, NULL, dev_num, NULL, "device_test"); //创建设备,名字为device_testreturn 0; }static void __exit chrdev_fops_exit(void) {device_destroy(class_test, dev_num); //删除设备class_destroy(class_test); //删除类 cdev_del(&cdev_test); //注销字符设备 先删除设备,再删除设备号unregister_chrdev_region(dev_num, 1); //释放设备号printk("module exit. \n");} module_init(chrdev_fops_init); module_exit(chrdev_fops_exit); MODULE_LICENSE("GPL v2"); //声明模块许可证 MODULE_AUTHOR("AFANFAN"); //声明模块作者
Makefile
export ARCH=arm64#设置平台架构 export CROSS_COMPILE=/opt/atk-dlrk3568-5_10_sdk-toolchain/bin/aarch64-buildroot-linux-gnu-#交叉编译器前缀 obj-m += chrdev_node.o #此处要和你的驱动源文件同名 KDIR :=/home/alientek/rk3568_linux5.10_sdk/kernel #这里是你的内核目录 PWD ?= $(shell pwd) all:make -C $(KDIR) M=$(PWD) modules #make操作 clean:make -C $(KDIR) M=$(PWD) clean #make clean操作
驱动编译成驱动模块ko
使用命令“make”进行驱动的编译,编译完生成 chrdev_node.ko目标文件
运行驱动编译成模块insmod
开发板启动之后, insmod chrdev_node.ko
注册设备号的查看 cat /proc/devices
对class目录进行查看 ls /sys/class/ 会发现class_test类被创建
对class_test 目录 ls /sys/class/class_test/ 会发现device_test的设备节点被创建对驱动进行卸载 rmmod chrdev_node.ko
3.问题:
好像没有哦