Linux驱动私有数据
在Linux驱动开发中,私有数据(private data) 是一个重要概念,它允许驱动程序为每个设备实例存储特定的信息。以下是详细说明:
1. 私有数据的概念
私有数据是一个指向任意数据结构的指针,通常用于:
- 存储设备特定的信息
- 在文件操作函数之间传递数据
- 管理设备的硬件资源
- 保持设备状态信息
2. 设置和获取私有数据
2.1 在设备结构体中设置私有数据
#include <linux/fs.h>
#include <linux/cdev.h>
struct my_device_data {
    struct cdev cdev;
    int device_id;
    void __iomem *reg_base;
    spinlock_t lock;
    // 其他设备特定数据
};
static int my_open(struct inode *inode, struct file *filp)
{
    struct my_device_data *dev_data;
    
    // 从inode获取cdev,然后获取包含cdev的设备结构体
    dev_data = container_of(inode->i_cdev, struct my_device_data, cdev);
    
    // 将设备数据存储为文件的私有数据
    filp->private_data = dev_data;
    
    return 0;
}
2.2 在probe函数中设置
static int my_probe(struct platform_device *pdev)
{
    struct my_device_data *dev_data;
    int ret;
    
    // 分配设备数据结构
    dev_data = devm_kzalloc(&pdev->dev, sizeof(*dev_data), GFP_KERNEL);
    if (!dev_data)
        return -ENOMEM;
    
    // 初始化设备数据
    dev_data->device_id = 0;
    spin_lock_init(&dev_data->lock);
    
    // 将私有数据存储到平台设备中
    platform_set_drvdata(pdev, dev_data);
    
    // 硬件初始化
    dev_data->reg_base = devm_platform_ioremap_resource(pdev, 0);
    if (IS_ERR(dev_data->reg_base))
        return PTR_ERR(dev_data->reg_base);
    
    return 0;
}
3. 在文件操作中使用私有数据
static ssize_t my_read(struct file *filp, char __user *buf, 
                      size_t count, loff_t *f_pos)
{
    struct my_device_data *dev_data = filp->private_data;
    ssize_t ret;
    
    if (!dev_data)
        return -ENODEV;
    
    spin_lock(&dev_data->lock);
    // 使用设备数据进行读取操作
    // ...
    spin_unlock(&dev_data->lock);
    
    return ret;
}
static ssize_t my_write(struct file *filp, const char __user *buf,
                       size_t count, loff_t *f_pos)
{
    struct my_device_data *dev_data = filp->private_data;
    
    if (!dev_data)
        return -ENODEV;
    
    // 使用设备数据进行写入操作
    // ...
    
    return count;
}
static int my_release(struct inode *inode, struct file *filp)
{
    // 清除私有数据引用
    filp->private_data = NULL;
    return 0;
}
static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = my_open,
    .release = my_release,
    .read = my_read,
    .write = my_write,
    // 其他操作...
};
4. 完整的驱动示例
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "mydevice"
#define MAX_DEVICES 2
struct my_device_data {
    struct cdev cdev;
    struct device *device;
    int device_id;
    unsigned long usage_count;
    spinlock_t lock;
    char buffer[1024];
};
static int major;
static struct class *my_class;
static struct my_device_data devices[MAX_DEVICES];
static int my_open(struct inode *inode, struct file *filp)
{
    struct my_device_data *dev_data;
    
    dev_data = container_of(inode->i_cdev, struct my_device_data, cdev);
    filp->private_data = dev_data;
    
    spin_lock(&dev_data->lock);
    dev_data->usage_count++;
    spin_unlock(&dev_data->lock);
    
    printk(KERN_INFO "Device %d opened, usage count: %lu\n",
           dev_data->device_id, dev_data->usage_count);
    
    return 0;
}
static int my_release(struct inode *inode, struct file *filp)
{
    struct my_device_data *dev_data = filp->private_data;
    
    spin_lock(&dev_data->lock);
    dev_data->usage_count--;
    spin_unlock(&dev_data->lock);
    
    printk(KERN_INFO "Device %d closed, usage count: %lu\n",
           dev_data->device_id, dev_data->usage_count);
    
    return 0;
}
static ssize_t my_read(struct file *filp, char __user *buf,
                      size_t count, loff_t *f_pos)
{
    struct my_device_data *dev_data = filp->private_data;
    ssize_t ret;
    
    if (*f_pos >= sizeof(dev_data->buffer))
        return 0;
    
    if (*f_pos + count > sizeof(dev_data->buffer))
        count = sizeof(dev_data->buffer) - *f_pos;
    
    if (copy_to_user(buf, dev_data->buffer + *f_pos, count))
        return -EFAULT;
    
    *f_pos += count;
    return count;
}
static ssize_t my_write(struct file *filp, const char __user *buf,
                       size_t count, loff_t *f_pos)
{
    struct my_device_data *dev_data = filp->private_data;
    
    if (*f_pos >= sizeof(dev_data->buffer))
        return -ENOSPC;
    
    if (*f_pos + count > sizeof(dev_data->buffer))
        count = sizeof(dev_data->buffer) - *f_pos;
    
    if (copy_from_user(dev_data->buffer + *f_pos, buf, count))
        return -EFAULT;
    
    *f_pos += count;
    return count;
}
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 i, ret;
    dev_t dev;
    
    // 分配设备号
    ret = alloc_chrdev_region(&dev, 0, MAX_DEVICES, DEVICE_NAME);
    if (ret < 0)
        return ret;
    
    major = MAJOR(dev);
    
    // 创建设备类
    my_class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(my_class)) {
        unregister_chrdev_region(dev, MAX_DEVICES);
        return PTR_ERR(my_class);
    }
    
    // 初始化每个设备
    for (i = 0; i < MAX_DEVICES; i++) {
        devices[i].device_id = i;
        spin_lock_init(&devices[i].lock);
        devices[i].usage_count = 0;
        memset(devices[i].buffer, 0, sizeof(devices[i].buffer));
        
        // 初始化cdev
        cdev_init(&devices[i].cdev, &my_fops);
        devices[i].cdev.owner = THIS_MODULE;
        
        // 添加cdev到系统
        ret = cdev_add(&devices[i].cdev, MKDEV(major, i), 1);
        if (ret) {
            printk(KERN_ERR "Failed to add cdev for device %d\n", i);
            continue;
        }
        
        // 创建设备节点
        devices[i].device = device_create(my_class, NULL, 
                                        MKDEV(major, i), NULL,
                                        "mydevice%d", i);
        if (IS_ERR(devices[i].device)) {
            cdev_del(&devices[i].cdev);
            printk(KERN_ERR "Failed to create device for device %d\n", i);
        }
    }
    
    printk(KERN_INFO "My device driver loaded\n");
    return 0;
}
static void __exit my_exit(void)
{
    int i;
    dev_t dev = MKDEV(major, 0);
    
    for (i = 0; i < MAX_DEVICES; i++) {
        if (devices[i].device)
            device_destroy(my_class, MKDEV(major, i));
        cdev_del(&devices[i].cdev);
    }
    
    class_destroy(my_class);
    unregister_chrdev_region(dev, MAX_DEVICES);
    
    printk(KERN_INFO "My device driver unloaded\n");
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Example driver using private data");
5. 关键要点
- 线程安全:在多线程环境中访问私有数据时,需要使用适当的锁机制
- 内存管理:确保在设备生命周期内私有数据保持有效
- 错误处理:始终检查私有数据指针是否为NULL
- 资源清理:在模块卸载时正确释放所有资源
私有数据是Linux驱动开发中的核心概念,正确使用它可以创建更加模块化和可维护的驱动程序。
            本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 恒星不见
        
     评论
            
                匿名评论
                隐私政策
            
            
                你无需删除空行,直接评论以获取最佳展示效果
            
         
            
        
