如何创建chardev

创建chardev



前言

之前一直没搞明白struct device 和 struct cdev 的关系,下面我们来问问chatgpt


让chatgpt帮我们写个例子

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>

MODULE_LICENSE("Dual BSD/GPL");

#define DEVICE_NAME "my_device"

struct my_device_data {
    dev_t dev_num;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    char buffer[256];
};

struct my_device_data my_data;

static int my_open(struct inode *inode, struct file *file)
{
    struct my_device_data *data = container_of(inode->i_cdev, struct my_device_data, cdev);
    file->private_data = data;
    printk(KERN_INFO "my_device opened\n");
    return 0;
}

static int my_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "my_device closed\n");
    return 0;
}

static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
    struct my_device_data *data = file->private_data;
    ssize_t ret = simple_read_from_buffer(buf, count, offset, data->buffer, strlen(data->buffer));
    printk(KERN_INFO "my_device read: %s\n", data->buffer);
    return ret;
}

static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
    struct my_device_data *data = file->private_data;
    ssize_t ret = simple_write_to_buffer(data->buffer, sizeof(data->buffer), offset, buf, count);
    printk(KERN_INFO "my_device write: %s\n", data->buffer);
    return ret;
}

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = my_open,
    .release = my_release,
    .read = my_read,
    .write = my_write,
};

static int __init my_init(void)
{
    int ret;
    printk(KERN_INFO "my_device driver loaded\n");

    /* Get a range of minor numbers (starting with 0) to work with */
    ret = alloc_chrdev_region(&my_data.dev_num, 0, 1, DEVICE_NAME);
    if (ret < 0) {
        printk(KERN_ALERT "Failed to allocate character device region\n");
        return ret;
    }

    /* Create a class for the devices to belong to */
    my_data.class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(my_data.class)) {
        unregister_chrdev_region(my_data.dev_num, 1);
        return PTR_ERR(my_data.class);
    }

    /* Initialize the character device and add it to the kernel */
    cdev_init(&my_data.cdev, &my_fops);
    my_data.cdev.owner = THIS_MODULE;
    ret = cdev_add(&my_data.cdev, my_data.dev_num, 1);
    if (ret < 0) {
        device_destroy(my_data.class, my_data.dev_num);
        class_destroy(my_data.class);
        unregister_chrdev_region(my_data.dev_num, 1);
        return ret;
    }

    /* Create the device and register it with sysfs */
    my_data.device = device_create(my_data.class, NULL, my_data.dev_num, NULL, DEVICE_NAME);
    if (IS_ERR(my_data.device)) {
        cdev_del(&my_data.cdev);
        class_destroy(my_data.class);
        unregister_chrdev_region(my_data.dev_num, 1);
        printk(KERN_ERR "Failed to create device node\n");
        return PTR_ERR(my_data.device);
    }

    printk(KERN_INFO "my_device initialized\n");
    return 0;
}

static void my_exit(void)
{
    device_destroy(my_data.class, my_data.dev_num);
    cdev_del(&my_data.cdev);
    unregister_chrdev_region(my_data.dev_num, 1);
    class_destroy(my_data.class);
    printk(KERN_INFO "my_device unloaded\n");
}

module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

这个例子最初明显漏了几行,我问他是否每次打印的字符串数量受限,他也不理我。后来我让它开开给我函数,这才补齐。

补上Makefile

obj-m += my_module.o
all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

问答

我问它:
上面的例子中,如果我不调用cdev_add,会影响内核态驱动的功能吗?
它回答说:
是的,如果你不调用 cdev_add() 函数将字符设备对象添加到内核中,那么该设备就无法正常工作。当应用程序尝试打开这个设备文件时,内核会无法找到对应的设备对象,从而无法分配资源或处理数据传输请求。因此,一旦你创建了一个字符设备对象,就必须调用 cdev_add() 函数将其添加到内核中,以使其能够正常工作。

总结

简单来说,应该是alloc_chrdev_region申请设备号,cdev_init cdev_add 创建cdev,device_create 创建device。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值