前言
杂项设备
注册杂项设备:
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 0
static 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");
}
else
printk("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");
}
else
printk("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.o
all:
make -C $(KERN_DIR) M=$(PWD) modules
clean:
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
运行:文章来源:https://www.toymoban.com/news/detail-421085.html
[root@RK356X:/opt]# ./app.armelf
[29334.729056] chrdev_open
没有问题。文章来源地址https://www.toymoban.com/news/detail-421085.html
到了这里,关于嵌入式Linux(8):字符设备驱动--注册字符类设备的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!