linux驱动模板

目录

说明

  1. 这是一个ai生成的模板
  2. 生成这个模板主要是因为我看了正点原子的视频,但是都没有总结过,但是每次开发写的东西都大差不差的

模板

跟ai的对话:

写一个linux下驱动开发模板,基于platform,匹配设备树对应的compatible,设备号可以自主定义,或者交给api生成,最后在dev下生成设备

补齐上面的模板,可以执行read,write,open,release等操作

alloc_chrdev_region等错误,可以使用goto作为统一处理,避免出现过多重复释放的代码

c 复制代码
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>

// 定义驱动名称和作者
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Template Platform Driver");
MODULE_LICENSE("GPL");

// 定义设备类
static struct class *my_class = NULL;

// 定义设备号结构体
static dev_t my_devt;

// 定义设备结构体
struct my_device {
    struct cdev cdev;
    struct device *dev;
};

// 定义设备实例
static struct my_device *my_device_instance;

// 定义设备打开函数
static int my_device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "My Device Opened\n");
    return 0;
}

// 定义设备释放函数
static int my_device_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "My Device Released\n");
    return 0;
}

// 定义设备读函数
static ssize_t my_device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
    char temp_buffer[256];
    const char *message = "Hello, World!\n";
    int length = strlen(message);

    if (*ppos > 0) {
        return 0;
    }

    if (count > length) {
        count = length;
    }

    if (copy_to_user(buf, message, count)) {
        return -EFAULT;
    }

    *ppos += count;
    return count;
}

// 定义设备写函数
static ssize_t my_device_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
    char temp_buffer[256];

    if (*ppos > 0) {
        return 0;
    }

    if (count > sizeof(temp_buffer) - 1) {
        count = sizeof(temp_buffer) - 1;
    }

    if (copy_from_user(temp_buffer, buf, count)) {
        return -EFAULT;
    }

    temp_buffer[count] = '\0';
    printk(KERN_INFO "My Device Write: %s\n", temp_buffer);

    *ppos += count;
    return count;
}

// 定义文件操作结构体
static const struct file_operations my_device_fops = {
    .owner = THIS_MODULE,
    .open = my_device_open,
    .read = my_device_read,
    .write = my_device_write,
    .release = my_device_release,
};

// 驱动初始化函数
static int my_driver_probe(struct platform_device *pdev) {
    int ret;

    printk(KERN_INFO "My Driver Probe Called\n");

    // 检查设备树中的compatible属性
    if (!of_device_is_compatible(pdev->dev.of_node, "vendor,devicename")) {
        dev_err(&pdev->dev, "Device not compatible\n");
        return -ENODEV;
    }

    // 创建设备类
    my_class = class_create(THIS_MODULE, "my_driver_class");
    if (IS_ERR(my_class)) {
        ret = PTR_ERR(my_class);
        dev_err(&pdev->dev, "Failed to create class\n");
        return ret;
    }

    // 动态分配设备号
    ret = alloc_chrdev_region(&my_devt, 0, 1, "my_driver");
    if (ret < 0) {
        dev_err(&pdev->dev, "Failed to allocate char device region\n");
        class_destroy(my_class);
        return ret;
    }

    // 创建设备实例
    my_device_instance = devm_kzalloc(&pdev->dev, sizeof(struct my_device), GFP_KERNEL);
    if (!my_device_instance) {
        ret = -ENOMEM;
        goto err_device_instance;
    }

    // 初始化cdev
    cdev_init(&my_device_instance->cdev, &my_device_fops);
    my_device_instance->cdev.owner = THIS_MODULE;

    // 添加cdev
    ret = cdev_add(&my_device_instance->cdev, my_devt, 1);
    if (ret) {
        dev_err(&pdev->dev, "Failed to add cdev\n");
        goto err_cdev_add;
    }

    // 创建设备
    my_device_instance->dev = device_create(my_class, NULL, my_devt, NULL, "my_device%d", MINOR(my_devt));
    if (IS_ERR(my_device_instance->dev)) {
        ret = PTR_ERR(my_device_instance->dev);
        dev_err(&pdev->dev, "Failed to create device\n");
        goto err_device_create;
    }

    platform_set_drvdata(pdev, my_device_instance);

    return 0;

err_device_create:
    cdev_del(&my_device_instance->cdev);
err_cdev_add:
    devm_kfree(&pdev->dev, my_device_instance);
err_device_instance:
    unregister_chrdev_region(my_devt, 1);
    class_destroy(my_class);
    return ret;
}

// 驱动退出函数
static int my_driver_remove(struct platform_device *pdev) {
    struct my_device *dev = platform_get_drvdata(pdev);

    device_destroy(my_class, MKDEV(MAJOR(my_devt), MINOR(my_devt)));
    cdev_del(&dev->cdev);
    devm_kfree(&pdev->dev, dev);
    unregister_chrdev_region(my_devt, 1);
    class_destroy(my_class);

    printk(KERN_INFO "My Driver Remove Called\n");

    return 0;
}

// 设备树中compatible属性匹配表
static const struct of_device_id my_driver_dt_ids[] = {
    { .compatible = "vendor,devicename" },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_driver_dt_ids);

// 定义platform_driver结构体
static struct platform_driver my_driver = {
    .probe = my_driver_probe,
    .remove = my_driver_remove,
    .driver = {
        .name = "my_platform_driver",
        .of_match_table = my_driver_dt_ids,
        .owner = THIS_MODULE,
    },
};

module_platform_driver(my_driver);

跟正点原子代码的差异

驱动的进入和退出在哪里?

简单来说这个module_platform_driver函数可以替代module_init()、module_exit();

为什么要有 MODULE_DEVICE_TABLE

问AI:总结来说,MODULE_DEVICE_TABLE 宏和 platform_driver 结构体中的 .of_match_table 字段都用于设备和驱动的匹配,但它们在某些情况下可以提供不同的功能和好处。如果您的驱动已经通过 .of_match_table 正确匹配设备,并且没有特殊的热插拔或其他需求,那么您可能不需要额外使用 MODULE_DEVICE_TABLE 宏。

相关推荐
cominglately2 小时前
centos单机部署seata
linux·运维·centos
魏 无羡2 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos
CircleMouse2 小时前
Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org
linux·运维·服务器·centos
木子Linux3 小时前
【Linux打怪升级记 | 问题01】安装Linux系统忘记设置时区怎么办?3个方法教你回到东八区
linux·运维·服务器·centos·云计算
mit6.8243 小时前
Ubuntu 系统下性能剖析工具: perf
linux·运维·ubuntu
鹏大师运维3 小时前
聊聊开源的虚拟化平台--PVE
linux·开源·虚拟化·虚拟机·pve·存储·nfs
watermelonoops3 小时前
Windows安装Ubuntu,Deepin三系统启动问题(XXX has invalid signature 您需要先加载内核)
linux·运维·ubuntu·deepin
滴水之功4 小时前
VMware OpenWrt怎么桥接模式联网
linux·openwrt
ldinvicible4 小时前
How to run Flutter on an Embedded Device
linux
YRr YRr5 小时前
解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误
linux·opencv·ubuntu