正点原子RK3568学习日志15-杂项设备驱动
1.杂项设备驱动
杂项设备的主设备号固定为10,
内核源码/include/linux/miscdevice.h”文件——miscdevice结构体
内核源码/include/linux/miscdevice.h”——misc_register函数,misc_deregister函数
miscdevice结构体
struct miscdevice {int minor; /* 子设备号 需要用户填写*/const char *name;/* 设备名 需要用户填写*/const struct file_operations *fops;/* 设备操作集 需要用户填写*/struct list_head list;struct device *parent;struct device *this_device;const struct attribute_group **groups;const char *nodename;umode_t mode; };
minor指次设备号 通常情况下将该参数设置为MISC_DYNAMIC_MINOR,表示自动分配子设备号
name表示misc设备的名字,misc设备驱动注册成功之后,会在dev目录下生成名为name的设备节点
fops 指向了file_operations的结构体,表示字符设备的操作集合
杂项设备的注册
int misc_register(struct miscdevice *misc)
misc: 杂项设备的结构体指针
函数返回值:申请成功返回0,申请失败返回负数
杂项设备的卸载
int misc_deregister(struct miscdevice *misc) misc: 杂项设备的结构体指针
**函数返回值:**卸载成功返回0,申请失败返回负数
MISC驱动一般使用以下结构
static struct file_operations xxx_fops{.owner = THIS_MODULE,.read = xxx_read, ...... }; struct miscdevice xxx_dev{.minor = MISC_DYNAMIC_MINOR,.name = "xxx",.fops = &xxx_fops };static int __init xxx_init(void) //驱动入口函数 {int ret;printk(KERN_EMERG "xxx_init\r\n");ret = misc_register(&xxx_dev);//注册杂项设备if(ret<0){printk( "misc_register failed\r\n"); }printk( "misc_register ok\r\n");return 0; }static void __exit xxx_exit(void) //驱动出口函数 {printk(KERN_EMERG "xxx_exit\r\n");misc_deregister(&xxx_dev); //卸载杂项设备 } module_init(xxx_init); //注册入口函数 module_exit(xxx_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("topeet");
static struct miscdevice misc_dev ={ //杂项设备结构体.minor = MISC_DYNAMIC_MINOR, //动态申请的次设备号.name = "test", //杂项设备的名字是test.fops = &misc_fops, //关联文件操作结构体};
ret = misc_register(&misc_dev); //注册杂项设备
2.实验:08_misvdevice
miscdevice.c
#include <linux/init.h> //初始化头文件 #include <linux/module.h> //最基本的文件,支持动态添加和卸载模块。 #include <linux/miscdevice.h> //注册杂项设备头文件 #include <linux/fs.h> //注册设备节点的文件结构体static struct file_operations misc_fops = { //file_operations结构体.owner = THIS_MODULE, //指向本模块 };static struct miscdevice misc_dev ={ //杂项设备结构体.minor = MISC_DYNAMIC_MINOR, //动态申请的次设备号.name = "test", //杂项设备的名字是test.fops = &misc_fops, //关联文件操作结构体};static int __init misc_init(void) {int ret; //判断函数返回值ret = misc_register(&misc_dev); //注册杂项设备if(ret < 0 ){ //注册失败printk("misc device register failed\n");}printk("misc device register success, minor=%d\n", misc_dev.minor);return 0; } static void __exit misc_exit(void) {misc_deregister(&misc_dev); //注销杂项设备printk("byebye misc. \n");} module_init(misc_init); module_exit(misc_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 += miscdevice.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”进行驱动的编译,编译完生成 miscdevice.ko目标文件
运行驱动编译成模块insmod
开发板启动之后, insmod miscdevice.ko
查看
/sys/class/misc目录下有misc类的所有设备,每个注册的杂项设备对应一个文件夹目录
查看杂项设备的主次设备号 ls /dev/test -al
3.问题:
1.file_operations 文件操作集
cdev,miscdevice 会指针联系到这个fops
struct file_operations结构体就是把系统调用和驱动程序关联起来的关键数据结构。该结构体的每一个成员都对应着一个系统调用,读取file_operation中相应的函数指针,接着把控制权转交给函数,从而完成了Linux设备驱动程序的工作