嵌入式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;

步骤流程:

  1. 定义一个cdev结构体。
  2. 使用cdev_init函数初始化cdev结构体成员变量。
void cdev_init(struct cdev *, const struct file_operations *);

参数:

  • 第一个:要初始化的cdev结构体
  • 第二个:文件操作集:cdev->ops = fops;//实际就是把文件操作集写ops
  1. 使用cdev_add函数注册到内核。
int cdev_add(struct cdev*, dev_t, unsigned);

参数:

  • 第一个:cdev的结构体指针。
  • 第二个:设备号。
  • 第三个:次设备号的数量。
  1. 创建字符设备节点

字符设备注册完以后不会自动生成设备节点(杂项设备在注册完以后就会自动生成设备节点)。

上面的代码里面没有自动创建字符设备节点。

需要使用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

运行:

[root@RK356X:/opt]# ./app.armelf
[29334.729056] chrdev_open

没有问题。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值