嵌入式Linux(8):字符设备驱动--注册字符类设备
文章目录
- 前言
- 上代码
前言
misc_register(&misc_dev);
注销杂项设备:
misc_deregister(&misc_dev);
字符类设备
文件:include/linux/cdev.h
struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;
} __randomize_layout;
步骤流程:
- 定义一个cdev结构体。
- 使用cdev_init函数初始化cdev结构体成员变量。
void cdev_init(struct cdev *, const struct file_operations *);
参数:
- 第一个:要初始化的cdev结构体
- 第二个:文件操作集:
cdev->ops = fops;//实际就是把文件操作集写ops
- 使用cdev_add函数注册到内核。
int cdev_add(struct cdev*, dev_t, unsigned);
参数:
- 第一个:cdev的结构体指针。
- 第二个:设备号。
- 第三个:次设备号的数量。
- 创建字符设备节点
字符设备注册完以后不会自动生成设备节点(杂项设备在注册完以后就会自动生成设备节点)。
上面的代码里面没有自动创建字符设备节点。
需要使用mknod命令(命令行手动输入创建)创建一个设备节点。
格式:mknod 名称 类型 主设备号 次设备号
举例:mknod /dev/test c 236 0
上代码
chrdev.c
#include <linux/init.h> // 包含宏定义
#include <linux/module.h> // 包含初始化、加载模块的头文件
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>#define DEVICE_NUMBER 1
#define DEVICE_SNAME "schrdev"
#define DEVICE_ANAME "achrdev"#define DEVICE_MINOR_NUMBER 0static int major_num, minor_num;struct cdev cdev;int chrdev_open(struct inode *inode, struct file *file)
{printk("chrdev_open\\n");return 0;
}struct file_operations chrdev_ops = {.owner = THIS_MODULE,.open = chrdev_open
};module_param(major_num, int, S_IRUSR);
module_param(minor_num, int, S_IRUSR);static int hello_init(void)
{dev_t dev_num;int ret;if(major_num){printk("major_num: %d\\n", major_num);printk("minor_num: %d\\n", minor_num);dev_num = MKDEV(major_num, minor_num);ret = register_chrdev_region(dev_num, DEVICE_NUMBER, DEVICE_SNAME);if(ret < 0){printk("register_chrdev_region error\\n");}elseprintk("register_chrdev_region ok\\n");}else{ret = alloc_chrdev_region(&dev_num, DEVICE_MINOR_NUMBER, DEVICE_NUMBER, DEVICE_ANAME);if(ret <0){printk("alloc_chrdev_region error\\n");}elseprintk("alloc_chrdev_region ok\\n");major_num = MAJOR(dev_num);minor_num = MINOR(dev_num);printk("major_num: %d\\n", major_num);printk("minor_num: %d\\n", minor_num);}printk("major_num = %d, minor_num = %d\\n",major_num, minor_num);cdev.owner = THIS_MODULE;cdev_init(&cdev, &chrdev_ops);cdev_add(&cdev, dev_num, DEVICE_NUMBER);return 0;
}
static void hello_exit(void)
{unregister_chrdev_region(MKDEV(major_num, minor_num), DEVICE_NUMBER);cdev_del(&cdev);printk("Bye Bye\\n");
}/* 模块的入口 */
module_init(hello_init);
/* 模块的出口 */
module_exit(hello_exit);/* 模块声明 */
MODULE_LICENSE("GPL");
Makefile
# 定义内核源码的目录
KERN_DIR ?= /home/liefyuan/Linux/rk356x_linux/kernel
# 定义当前目录
PWD := $(shell pwd)
# 要生成的内核模块
obj-m += chrdev.oall:make -C $(KERN_DIR) M=$(PWD) modulesclean:rm -rf *.order *o *.symvers *.mod.c *.mod *.ko
编译模块
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make
需要手动创建设备节点:
[root@RK356X:/opt]# insmod chrdev.ko
[29223.082788] alloc_chrdev_region ok
[29223.082898] major_num: 236
[29223.08290[root@RK356X:/opt]# 7] minor_num: 0
[29223.082915] major_num = 236, minor_num = 0[root@RK356X:/opt]# mknod /dev/test c 236 0
[root@RK356X:/opt]# ls /dev/test
/dev/test
app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{int fd;//打开设备节点fd = open("/dev/test",O_RDWR);if(fd < 0){//打开设备节点失败perror("open error \\n"); return fd;}close(fd);return 0;
}
编译
aarch64-linux-gnu-gcc app.c -o app.armelf
运行:
[root@RK356X:/opt]# ./app.armelf
[29334.729056] chrdev_open
没有问题。