linux 驱动——私有数据

文章目录

linux 驱动中的私有数据

前面的程序中,都只申请了一个从设备号,这里使用 alloc_chrdev_region 分配两个设备号,这两个设备共用 ops 方法。

所以需要在 ops 方法中区分两个设备

container_of

参考:linux------宏 list_entry/container_of

驱动程序

数据结构定义

c 复制代码
typedef struct {
    dev_t dev_id;          /* 设备号 */
    struct cdev c_dev;     /* cdev */
    struct class *class;   /* 类 */
    struct device *device; /* 设备 */
    int major;             /* 主设备号 */
    int minor;             /* 次设备号 */
    char write_buf[100];
    char read_buf[100];
} new_chrdev_t;

static new_chrdev_t new_chrdev1;
static new_chrdev_t new_chrdev2;

这里定义了两个设备,分别为 new_chrdev1 和 ·new_chrdev2·

  • new_chrdev1
    • 设备号:通过 alloc_chrdev_region 分配;
    • 主设备号:major = MAJOR(dev_id);
    • 次设备号:minor = MINOR(dev_id);
  • new_chrdev2
    • 主设备号:major = MAJOR(new_chrdev1.dev_id);
    • 次设备号:minor = MINOR(new_chrdev1.dev_id) + 1;
    • 设备号: dev_id = MKDEV(new_chrdev2.major, new_chrdev2.minor);

程序源码

c 复制代码
#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/uaccess.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>

#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */
#define CHRDEVBASE_NUM 2             /* 设备数目 */

static char *string_test = "kernel data this tyustli test";

typedef struct {
    dev_t dev_id;          /* 设备号 */
    struct cdev c_dev;     /* cdev */
    struct class *class;   /* 类 */
    struct device *device; /* 设备 */
    int major;             /* 主设备号 */
    int minor;             /* 次设备号 */
    char write_buf[100];
    char read_buf[100];
} new_chrdev_t;

static new_chrdev_t new_chrdev1;
static new_chrdev_t new_chrdev2;

static int chrdevbase_open(struct inode *inode, struct file *file)
{
    new_chrdev1.minor = 0;
    new_chrdev2.minor = 1;

    file->private_data =
            container_of(inode->i_cdev, new_chrdev_t, c_dev); /* 设置私有数据 */

    printk("k: chrdevbase open\r\n");

    return 0;
}

static ssize_t chrdevbase_read(struct file *file, char __user *buf,
                               size_t count, loff_t *ppos)
{
    unsigned long ret = 0;
    new_chrdev_t *dev = (new_chrdev_t *)file->private_data;

    printk("k: chrdevbase read major %d\r\n", dev->major);

    memcpy(dev->read_buf, string_test, strlen(string_test));

    ret = copy_to_user(buf, dev->read_buf, count);
    if (ret == 0) {
        printk("k: read data success\r\n");
    } else {
        printk("k: read data failed ret = %ld\r\n", ret);
    }

    return ret;
}

static ssize_t chrdevbase_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
{
    unsigned long ret = 0;

    printk("k: chrdevbase write\r\n");
    new_chrdev_t *dev = (new_chrdev_t *)file->private_data;

    printk("k: chrdevbase read minor %d\r\n", dev->minor);

    ret = copy_from_user(dev->write_buf, buf, count);
    if (ret == 0) {
        printk("k: write data success write data is: %s\r\n", dev->write_buf);
    } else {
        printk("k: write data failed ret = %ld\r\n", ret);
    }

    return count;
}

static int chrdevbase_release(struct inode *inode, struct file *file)
{
    printk("k: chrdevbase release\r\n");

    return 0;
}

static struct file_operations chrdevbase_fops = {
    .owner = THIS_MODULE,
    .open = chrdevbase_open,
    .read = chrdevbase_read,
    .write = chrdevbase_write,
    .release = chrdevbase_release,
};

static int __init chrdevbase_init(void)
{
    int err = 0;

    err = alloc_chrdev_region(&new_chrdev1.dev_id, 0, CHRDEVBASE_NUM,
                              CHRDEVBASE_NAME);
    if (err < 0) {
        printk("k: alloc chrdev region failed err = %d\r\n", err);
        goto err_chrdev;
    }

    /* get major 1 and minor 1 */
    new_chrdev1.major = MAJOR(new_chrdev1.dev_id);
    new_chrdev1.minor = MINOR(new_chrdev1.dev_id);
    printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev1.major,
           new_chrdev1.minor);

    new_chrdev1.c_dev.owner = THIS_MODULE;
    cdev_init(&new_chrdev1.c_dev, &chrdevbase_fops);
    err = cdev_add(&new_chrdev1.c_dev, new_chrdev1.dev_id, 1);
    if (err < 0) {
        printk("k: cdev add failed err = %d\r\n", err);
        goto err_cdev_add;
    }
    new_chrdev1.class = class_create("chr_test1");
    if (IS_ERR(new_chrdev1.class)) {
        err = PTR_ERR(new_chrdev1.class);
        goto err_class_create;
    }

    new_chrdev1.device = device_create(new_chrdev1.class, NULL,
                                       new_chrdev1.dev_id, NULL, "chr_test1");
    if (IS_ERR(new_chrdev1.device)) {
        err = PTR_ERR(new_chrdev1.device);
        goto err_device_create;
    }

    /* get major 2 and minor 2 */
    new_chrdev2.major = MAJOR(new_chrdev2.dev_id);
    new_chrdev2.minor = MINOR(new_chrdev2.dev_id) + 1;
    new_chrdev2.dev_id = MKDEV(new_chrdev2.major, new_chrdev2.minor);
    printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev2.major,
           new_chrdev2.minor);

    new_chrdev2.c_dev.owner = THIS_MODULE;
    cdev_init(&new_chrdev2.c_dev, &chrdevbase_fops);
    err = cdev_add(&new_chrdev2.c_dev, new_chrdev2.dev_id, 1);
    if (err < 0) {
        printk("k: cdev add failed err = %d\r\n", err);
        goto err_cdev_add;
    }

    new_chrdev2.class = class_create("chr_test2");
    if (IS_ERR(new_chrdev2.class)) {
        err = PTR_ERR(new_chrdev2.class);
        goto err_class_create;
    }

    new_chrdev2.device = device_create(
            new_chrdev2.class, NULL, new_chrdev2.dev_id, NULL, "chr_test2");
    if (IS_ERR(new_chrdev2.device)) {
        err = PTR_ERR(new_chrdev2.device);
        goto err_device_create;
    }

    printk("k: base module init\r\n");

    return 0;

err_device_create:
    class_destroy(new_chrdev1.class);
    class_destroy(new_chrdev2.class);
err_class_create:
    cdev_del(&new_chrdev1.c_dev);
    cdev_del(&new_chrdev2.c_dev);
err_cdev_add:
    unregister_chrdev_region(new_chrdev1.dev_id, CHRDEVBASE_NUM);
err_chrdev:
    return err;
}

static void __exit chrdevbase_exit(void)
{
    device_destroy(new_chrdev1.class, new_chrdev1.dev_id);
    device_destroy(new_chrdev2.class, new_chrdev2.dev_id);

    class_destroy(new_chrdev1.class);
    class_destroy(new_chrdev2.class);

    cdev_del(&new_chrdev1.c_dev);
    cdev_del(&new_chrdev2.c_dev);

    unregister_chrdev_region(new_chrdev1.dev_id, CHRDEVBASE_NUM);

    printk("k: base module exit!\r\n");
}

module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyustli");
MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */

应用程序

c 复制代码
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"

static char usrdata[] = { "user data!" };

int main(int argc, char *argv[])
{
    int fd, retvalue;
    char *filename;
    char readbuf[100], writebuf[100];

    if (argc != 3) {
        printf("u: error Usage!\r\n");
        return -1;
    }

    filename = argv[1];

    /* 打开驱动文件 */
    fd = open(filename, O_RDWR);
    if (fd < 0) {
        printf("u: can't open file %s\r\n", filename);
        return -1;
    }

    /* 从驱动文件读取数据 */
    if (atoi(argv[2]) == 1) {
        retvalue = read(fd, readbuf, 50);
        if (retvalue < 0) {
            printf("u: read file %s failed!\r\n", filename);
        } else {
            /*  读取成功,打印出读取成功的数据 */
            printf("u: read data:%s\r\n", readbuf);
        }
    }

    /* 向设备驱动写数据 */
    if (atoi(argv[2]) == 2) {
        memcpy(writebuf, usrdata, sizeof(usrdata));
        retvalue = write(fd, writebuf, 50);
        if (retvalue < 0) {
            printf("u: write file %s failed!\r\n", filename);
        }
    }

    /* 关闭设备 */
    retvalue = close(fd);
    if (retvalue < 0) {
        printf("u: can't close file %s\r\n", filename);
        return -1;
    }

    return 0;
}

模块使用

模块安装

c 复制代码
modprobe my_module

查看设备节点

c 复制代码
ls /dev/

模块使用

c 复制代码
#设备1
lib/modules/6.5.7+/my_app /dev/chr_test1  1
lib/modules/6.5.7+/my_app /dev/chr_test1  2
#设备2
lib/modules/6.5.7+/my_app /dev/chr_test2  1
lib/modules/6.5.7+/my_app /dev/chr_test2  2

模块打印日志

c 复制代码
~ # lib/modules/6.5.7+/my_app /dev/chr_test1  1
k: chrdevbase open
k: chrdevbase read major 248
k: read data success
u: read data:kernel data this tyustli test
k: chrdevbase release
~ # lib/modules/6.5.7+/my_app /dev/chr_test1  2
k: chrdevbase open
k: chrdevbase write
k: chrdevbase read minor 0
k: write data success write data is: user data!
k: chrdevbase release
~ # lib/modules/6.5.7+/my_app /dev/chr_test2  1
k: chrdevbase open
k: chrdevbase read major 248
k: read data success
u: read data:kernel data this tyustli test
k: chrdevbase release
~ # lib/modules/6.5.7+/my_app /dev/chr_test2 2
k: chrdevbase open
k: chrdevbase write
k: chrdevbase read minor 1
k: write data success write data is: user data!
k: chrdevbase release
~ # 
相关推荐
Alex_StarSky10 个月前
GPT实战系列-P-Tuning本地化训练ChatGLM2等LLM模型,到底做了什么?(一)
chatgpt·llm·chatglm2·私有数据·p-tuning·微调训练·本地化训练
六个九十度1 年前
从Linux的tty_struct指针获取驱动上下文
linux·tty·container_of
LookLook同学1 年前
ChatGPT私有数据结合有什么效果?它难吗?
人工智能·chatgpt·helplook·chatgpt私有数据·私有数据·创建训练机器人