• 14、字符驱动编程模型


    字符驱动编程模型

    上面就是内核的cdev的结构。他只有6个成员。有一些是内核自己回去用的,有一些是我们程序员要去用的。例如:count,表明设备有几个可以用。例如,我的开发板支持三个串口。所以count=3.还有设备号:查看设备文件:

    我们从前面知道,我们是通过字符设备文件来访问我们的字符设备驱动的。两者是通过主设备号来建立联系的。

    一个主设备好可以对应多个此设备号。他们是同一类型的设备。驱动程序就是通过次设备号来区分是串口1还是串口2的

    设备号的操作

     

     

     

     

     

     

    设备号分配

     

    设备号-注销

     

     

    这是一个很重要的结构。

    上面的方法,存在很多新的类型:

    F_pos用来保存读写指针的位置

    驱动操作方法:

    接下来我们来分析前面的memdev.c:

    #include <linux/module.h>

    #include <linux/fs.h>

    #include <linux/init.h>

    #include <linux/cdev.h>

    #include <asm/uaccess.h>

    int dev1_registers[5];

    int dev2_registers[5];

    struct cdev cdev;

    dev_t devno;

    /*文件打开函数*/

    int mem_open(struct inode *inode, struct file *filp)

    {

    /*获取次设备号*/

    int num = MINOR(inode->i_rdev);

    if (num==0)

    filp->private_data = dev1_registers;

    else if(num == 1)

    filp->private_data = dev2_registers;

    else

    return -ENODEV; //无效的次设备号

    return 0;

    }

    /*文件释放函数*/

    int mem_release(struct inode *inode, struct file *filp)

    {

    return 0;

    }

    /*读函数*/

    static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)

    {

    unsigned long p = *ppos;

    unsigned int count = size;

    int ret = 0;

    int *register_addr = filp->private_data; /*获得设备的寄存器地址*/

    /*判断读位置是否有效*/

    if (p >= 5*sizeof(int))

    return 0;

    if (count > 5*sizeof(int) - p)

    count = 5*sizeof(int) - p;

    /*读取数据到用户空间*/

    if (copy_to_user(buf, register_addr+p, count))

    {

    ret = -EFAULT;

    }

    else

    {

    *ppos += count;

    ret = count;

    }

    return ret;

    }

    /*写函数*/

    static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)

    {

    unsigned long p = *ppos;

    unsigned int count = size;

    int ret = 0;

    int *register_addr = filp->private_data; /*获取设备的寄存器地址*/

    /*分析和获取有效的写长度*/

    if (p >= 5*sizeof(int))

    return 0;

    if (count > 5*sizeof(int) - p)

    count = 5*sizeof(int) - p;

    /*从用户空间写入数据*/

    if (copy_from_user(register_addr + p, buf, count))

    ret = -EFAULT;

    else

    {

    *ppos += count;

    ret = count;

    }

    return ret;

    }

    /* seek文件定位函数*/

    static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)

    {

    loff_t newpos;

    switch(whence) {

    case SEEK_SET:

    newpos = offset;

    break;

    case SEEK_CUR:

    newpos = filp->f_pos + offset;

    break;

    case SEEK_END:

    newpos = 5*sizeof(int)-1 + offset;

    break;

    default:

    return -EINVAL;

    }

    if ((newpos<0) || (newpos>5*sizeof(int)))

        return -EINVAL;

          

    filp->f_pos = newpos;

    return newpos;

    }

    /*文件操作结构体*/

    static const struct file_operations mem_fops =

    {

    .llseek = mem_llseek,

    .read = mem_read,

    .write = mem_write,

    .open = mem_open,

    .release = mem_release,

    };

    /*设备驱动模块加载函数*/

    static int memdev_init(void)

    {

    /*初始化cdev结构*/

    cdev_init(&cdev, &mem_fops);

    /* 注册字符设备*/

    alloc_chrdev_region(&devno, 0, 2, "memdev");

    cdev_add(&cdev, devno, 2);

    }

    /*模块卸载函数*/

    static void memdev_exit(void)

    {

    cdev_del(&cdev); /*注销设备*/

    unregister_chrdev_region(devno, 2); /*释放设备号*/

    }

    MODULE_LICENSE("GPL");

    module_init(memdev_init);

    module_exit(memdev_exit);

    相关信息:

  • 相关阅读:
    php-fpm: 某项目网站频繁出现503问题解决( WARNING: [pool www] server reached pm.max_children setting (50), consider raising it)
    spring mvc: rss(xml)输出
    spring mvc: json练习
    spring mvc: xml练习
    spring mvc:输出json,输出多个json
    phalcon: 目录分组后的acl权限控制
    spring mvc: xml生成
    spring mvc:视图解析器
    Python爬虫从入门到放弃(二十)之 Scrapy分布式原理
    Python爬虫从入门到放弃(十九)之 Scrapy爬取所有知乎用户信息(下)
  • 原文地址:https://www.cnblogs.com/FORFISH/p/5188455.html
Copyright © 2020-2023  润新知