【Linux设备驱动】--0x03字符设备模块-完整的错误处理+全局数据结构放在同一结构体内

简介: 项目中经常会将所用到的所有全局数据结构放到同一个结构体内struct simple_dev { dev_t dev_no; struct cdev cdev; struct class *class; struct device *device;};该...

项目中经常会将所用到的所有全局数据结构放到同一个结构体内

struct simple_dev {
    dev_t  dev_no;
    struct cdev   cdev;
    struct class  *class;
    struct device *device;
};

该结构体将所用到的全局数据结构放在一起,这样可以在open的时候,将该指针放到file->private_data = dev;私有data字段内,方便其他系统调用接口使用

这里container_of无法操作内部嵌套的指针类型,所以struct cdev cdev;不能用作指针类型

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/slab.h>   // kfree,kmalloc
#include <linux/cdev.h>   // cdev_xxx
#include <linux/device.h> // device_xxx

struct simple_dev {
    dev_t  dev_no;
    struct cdev   cdev;
    struct class  *class;
    struct device *device;
};

struct simple_dev *g_simple_dev;

static int simple_cdev_open(struct inode *inode, struct file *file)
{
    struct simple_dev *dev;

    dev = container_of(inode->i_cdev, struct simple_dev, cdev);
    file->private_data = dev;

    return 0;
}

static int simple_cdev_release(struct inode *inode, struct file *file)
{
    struct simple_dev *dev;

    dev = file->private_data;

    return 0;
}

/* File operations struct for character device */
static const struct file_operations g_simple_dev_fops = {
    .owner   = THIS_MODULE,
    .open    = simple_cdev_open,
    .release = simple_cdev_release,
};

static int __init simple_cdev_init(void)
{
    int ret;

    g_simple_dev = kzalloc(sizeof(struct simple_dev), GFP_KERNEL);
    if (!g_simple_dev) {
        return -1;
    }

    ret = alloc_chrdev_region(&g_simple_dev->dev_no, 0, 1, "simple_cdev");
    if (!ret) {
        goto alloc_chrdev_failed;
    }

    cdev_init(&g_simple_dev->cdev, &g_simple_dev_fops);
    g_simple_dev->cdev.owner = THIS_MODULE;

    ret = cdev_add(&g_simple_dev->cdev, g_simple_dev->dev_no, 1);
    if (!ret) {
        goto cdev_add_failed;
    }

    g_simple_dev->class = class_create(THIS_MODULE, "simple_cdev");
    if (!g_simple_dev->class) {
        goto class_create_failed;
    }

    g_simple_dev->device = device_create(g_simple_dev->class, NULL, g_simple_dev->dev_no, NULL, "simple_cdev");
    if (!g_simple_dev->device) {
        goto device_create_failed;
    }
    
    return 0;

device_create_failed:
    class_destroy(g_simple_dev->class);
class_create_failed:
    cdev_del(&g_simple_dev->cdev);
cdev_add_failed:
    unregister_chrdev_region(g_simple_dev->dev_no, 1);
alloc_chrdev_failed:
    kfree(g_simple_dev);

    return -1;
}

static void __exit simple_cdev_exit(void)
{
    device_destroy(g_simple_dev->class, g_simple_dev->dev_no);
    class_destroy(g_simple_dev->class);
    cdev_del(&g_simple_dev->cdev);
    unregister_chrdev_region(g_simple_dev->dev_no, 1);
    kfree(g_simple_dev);
}

MODULE_LICENSE("GPL");
module_init(simple_cdev_init);
module_exit(simple_cdev_exit);
目录
相关文章
|
15天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
58 16
|
9天前
|
Linux 开发工具 Perl
在Linux中,有一个文件,如何删除包含“www“字样的字符?
在Linux中,如果你想删除一个文件中包含特定字样(如“www”)的所有字符或行,你可以使用多种文本处理工具来实现。以下是一些常见的方法:
34 5
|
25天前
|
Linux 开发工具 Perl
Linux命令替换目录下所有文件里有"\n"的字符为""如何操作?
【10月更文挑战第20天】Linux命令替换目录下所有文件里有"\n"的字符为""如何操作?
37 4
|
1月前
|
存储 编译器 C++
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
【初阶数据结构】掌握二叉树遍历技巧与信息求解:深入解析四种遍历方法及树的结构与统计分析
|
1月前
探索顺序结构:栈的实现方式
探索顺序结构:栈的实现方式
|
1月前
|
存储 算法
【数据结构】二叉树——顺序结构——堆及其实现
【数据结构】二叉树——顺序结构——堆及其实现
|
2月前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
2月前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
3月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
44 6
|
3月前
|
消息中间件 算法 Unix
Linux设备驱动开发详解1
Linux设备驱动开发详解
49 5