美文网首页
Linux字符设备驱动的读写功能实现

Linux字符设备驱动的读写功能实现

作者: 二进制人类 | 来源:发表于2022-11-21 12:07 被阅读0次

读写方法集的实现

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); /* 用户调用read函数的回调函数 */
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); /* 用户调用write函数的回调函数 */ 

读写函数

/*
功能:将用户空间from数据写入到内核空间to;
参数:
    参数1:to指针,指向的是内核缓存空间的起始地址;
    参数2:from指针,指向的是用户缓存空间的起始地址;
    参数3:n表示拷贝数据的字节数; 
返回值:
    成功返回拷贝的字节数;失败返回-EFAULT    
*/
extern int copy_from_user(void *to, const void __user *from, int n);
/*
功能:将内核空间from数据写入到用户空间to中;
参数:
    参数1:to指针,指向的用户缓存控件的起始地址;
    参数2:from指针,指向的是内核缓存空间的起始地址;
    参数3:n表示拷贝数据的字节数;
返回值:
    成功返回拷贝的字节数;失败返回-EFAULT
*/
extern int copy_to_user(void __user *to, const void *from, int n);

实例

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

#define KBUFSIZE 64

static dev_t dev_num;/* dev_num存储申请成功的设备号 */
static unsigned int count = 4;/* 次设备的数量 */
static struct cdev *cdev_p;/* 字符设备注册结构体指针 */
static struct class *class_p;
static struct device *device_p;


static unsigned char kernel_buf[KBUFSIZE];

int my_char_driver_open(struct inode *inode_p, struct file *file_p)
{
    dev_t my_dev;

    my_dev = inode_p->i_rdev;
    printk(KERN_INFO "my char driver open <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));

    return 0;
}

int my_char_driver_release(struct inode *inode_p, struct file *file_p)
{
    dev_t my_dev;

    my_dev = inode_p->i_rdev;
    printk(KERN_INFO "my char driver release <%d:%d> success\n", MAJOR(my_dev), MINOR(my_dev));

    return 0;
}

/* 提供给用户的read函数调用时,内核中的驱动调用read */
ssize_t my_char_driver_read(struct file *file_p, char __user *buf, size_t size, loff_t *loff_p)
{
    int ret;

    if (size < 0)
        size = 0;

    if (size > KBUFSIZE)
        size = KBUFSIZE;

    ret = copy_to_user(buf, kernel_buf, size);
    if (ret == -EFAULT)
        return ret;

    return size;
}

ssize_t  my_char_driver_write(struct file *file_p, const char __user *buf, size_t size, loff_t *loff_p)
{
    int ret;

    if (size < 0)
        size = 0;

    if (size > KBUFSIZE)
        size = KBUFSIZE;

    ret = copy_from_user(kernel_buf, buf, size);
    if (ret == -EFAULT)
        return ret;

    printk(KERN_INFO "kernel_buf : %s\n", kernel_buf);

    return size;
}

const struct file_operations fops =
{
    .owner = THIS_MODULE,
    .open = my_char_driver_open,
    .release = my_char_driver_release,
    .read = my_char_driver_read,
    .write = my_char_driver_write
};

/* 定义模块加载入口函数 */
static int __init my_char_driver_init(void)
{
    int ret = 0;

    /* 1. 申请设备号:手动申请(给定主设备号和起始次设备号)/动态申请(返回设备号) */
    ret = alloc_chrdev_region(&dev_num, 0, count, "chrdev");/* 动态申请设备号 */
    if (ret != 0)
    {
        goto err0;
    }

    /* 2. 注册设备到系统中,有系统统一调度管理 */
    /* 2.1 申请字符设备注册结构体空间*/
    cdev_p = cdev_alloc();
    if (cdev_p == NULL)
    {
        ret = - ENOMEM;
        goto err1;
    }

    /* 2.2 初始化字符数设备结构体空间中的操作方法集 */
    cdev_init(cdev_p, &fops);

    /* 2.3 添加字符设备结构体到系统中,由系统统一调度管理 */
    ret = cdev_add(cdev_p, dev_num, count);
    if (ret != 0)
    {
        goto err2;
    }

    /* 3. 创建设备节点(可选:一般都会加上) */
    /* 3.1 创建节点对象 */
    class_p =  class_create(THIS_MODULE, "mychar");
    if (IS_ERR(class_p))
    {
        ret = - ENOMEM;
        goto err3;
    }

    int i;
    for (i = 0; i < count; i++)  /* 由于驱动可以管理多个设备文件,需要循环创建设备文件 */
    {
        char drv_name[20] = {0};
        sprintf(drv_name, "mychar%d", i);

        /* 3.2 创建设备节点 */
        device_p = device_create(class_p, NULL, MKDEV(MAJOR(dev_num), i), NULL, drv_name);
        if (IS_ERR(device_p))
        {
            ret = - ENOMEM;
            goto err4;
        }
    }

    printk(KERN_INFO "my char driver : <major: %d, minor: %d> init success\n", MAJOR(dev_num), MINOR(dev_num));
    return 0;

err4:
    /* 释放创建成功的设备节点 */
    for (i--; i >= 0; i--)
        device_destroy(class_p, MKDEV(MAJOR(dev_num), i));

    /* 释放设备节点对象 */
    class_destroy(class_p);
err3:

err2:
    /* 释放字符设备结构体空间 */
    cdev_del(cdev_p);
err1:
    /* 释放设备号 */
    unregister_chrdev_region(dev_num, count);
err0:
    return ret;
}

/* 定义模块卸载入口函数 */
static void __exit my_char_driver_exit(void)
{
    /* 释放设备节点 */
    int i;
    for (i = 0; i < count; i++)
        device_destroy(class_p, MKDEV(MAJOR(dev_num), i));

    /* 释放设备节点对象 */
    class_destroy(class_p);

    /* 释放字符设备结构体空间 */
    cdev_del(cdev_p);

    /* 释放设备号 */
    unregister_chrdev_region(dev_num, count);
    printk(KERN_INFO "my char driver exit success\n");
}

module_init(my_char_driver_init);/* 声明模块加载入口函数 */
module_exit(my_char_driver_exit);/* 声明模块卸载入口函数 */
MODULE_LICENSE("GPL");

相关文章

网友评论

      本文标题:Linux字符设备驱动的读写功能实现

      本文链接:https://www.haomeiwen.com/subject/bimttdtx.html