编写的驱动用户空间和内核空间数据交互

代码:006_kernel_user_data.c

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

struct device_data{
    dev_t dev_no; // 设备号

    struct cdev cdev_test; // 字符设备结构体
    struct class *class_test; // 类
    struct device *device_test; // 设备
    char kbuf[32];
};
struct device_data dev_data;
static int test_open(struct inode *inode,struct file *file)
{
    // 打开驱动时,配置私有数据
    file->private_data = &dev_data;
    printk("open\n");
    return 0;
}
static ssize_t test_read(struct file *file,char __user *buf, size_t size,loff_t *off){
    //拿到私有数据
    struct device_data *priv_data =  (struct device_data *)file->private_data;

    if(copy_to_user(buf,priv_data->kbuf , strlen(priv_data->kbuf))!=0){
        printk("copy_to_user failed\n");
        return -1;
    }
    printk("read\n");
    return 0;
}
static ssize_t test_write(struct file *file,const char __user *buf, size_t size,loff_t *off){
    // 拿到私有数据
    struct device_data *priv_data =  (struct device_data *)file->private_data;
    if(size > sizeof(priv_data->kbuf)){
        printk("data too large\n");
        return -ENOSPC;
    }
    if(copy_from_user(priv_data->kbuf, buf, size)!=0){
        printk("copy_from_user failed\n");
        return -EFAULT;
    }
    priv_data->kbuf[size - 1] = '\0'; // 确保字符串终止
    *off += size;
    printk("write\n");
    return size;
}
static int test_release(struct inode *inode,struct file *file)
{
    printk("release\n");
    return 0;
}
struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = test_open,
    .read = test_read,
    .write = test_write,
    .release = test_release,
};

//设备名称
static char* name = "006_kernel_user_data";

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyl");
MODULE_DESCRIPTION("006_kernel_user_data");
static int modulecdev_init(void)
{ 
    int ret;
    ret = alloc_chrdev_region(&dev_data.dev_no, 0, 1, name);
    if (ret<0) {
        printk("alloc_chrdev_region failed\n");
        return ret;
    }
    printk("major:%d, minor:%d\n", MAJOR(dev_data.dev_no), MINOR(dev_data.dev_no));
    cdev_init(&dev_data.cdev_test, &fops);
    cdev_add(&dev_data.cdev_test, dev_data.dev_no, 1);

    dev_data.class_test = class_create(THIS_MODULE, name); //创建类
    dev_data.device_test = device_create(dev_data.class_test, NULL, dev_data.dev_no, NULL, name);
    return 0;
}
static void modulecdev_exit(void)
{
    // 1. 先销毁设备节点
    device_destroy(dev_data.class_test, dev_data.dev_no);
    
    // 2. 销毁类 (原代码缺失此步,必须添加)
    class_destroy(dev_data.class_test);
    
    // 3. 删除字符设备
    cdev_del(&dev_data.cdev_test);
    
    // 4. 最后注销设备号
    unregister_chrdev_region(dev_data.dev_no, 1);
    
    printk("modulecdev exit\n");
}

module_init(modulecdev_init);
module_exit(modulecdev_exit);

代码:app.c

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int fd = open("/dev/006_kernel_user_data", O_RDWR);
    char rbuf[64];
    char wbuf[64];

    if (fd < 0)
    {
        printf("open error\n");
        return -1;
    }
    printf("open success\n");

    // 用户 -> 内核:写入数据到驱动
    strcpy(wbuf, "hello from user space!");
    write(fd, wbuf, strlen(wbuf) + 1);
    printf("write to kernel: %s\n", wbuf);

    // 内核 -> 用户:从驱动读取数据
    memset(rbuf, 0, sizeof(rbuf));
    read(fd, rbuf, sizeof(rbuf));
    printf("read from kernel: %s\n", rbuf);

    close(fd);
    return 0;
}