zoukankan      html  css  js  c++  java
  • 字符设备之register_chrdev与register_chrdev_region(转)

    之前写字符设备驱动,都是使用register_chrdev向内核注册驱动程序中构建的file_operations结构体,之后创建的设备文件,只要是主设备号相同(次设备号不同),则绑定的都是同一个file_operations结构体,应用程序使用的也都是这一个结构体中注册的函数。这就会出现这样的一个弊端:同一类字符设备(即主设备号相同),会在内核中连续注册了256(分析内核代码中可知),也就是所以的此设备号都会被占用,而在大多数情况下都不会用到这么多次设备号,所以会造成极大的资源浪费。所以register_chrdev在某个角度上是有弊端的,这也是老版本内核中使用。

       register_chrdev的注册,还分为静态注册和动态注册。而register_chrdev_region和alloc_chrdev_region正相当于将register_chrdev拆分来,它们分别是静态和动态注册的个体,但同时也解决了register_chrdev资源浪费的缺点。

    register_chrdev_region(dev_t from, unsigned count, const char * name)

    从参数中分析该函数的作用:

    from:要分配的设备号范围的起始值。

    count:所要求的连续设备编号个数。

    name:和该编号范围相关的设备名称。

    register_chrdev_region允许注册一个规定的设备号的范围,也就不一定把0~255个此设备号都注册占用。

    在2.6之后的内核,利用的是一个struct cdev结构体来描述一个字符设备。

    struct cdev {
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;
    struct list_head list;
    dev_t dev;
    unsigned int count;
    };

    再介绍几个用到的函数:

    void cdev_init(struct cdev *, const struct file_operations *);//清空cdev,并填充file_operations 结构体
    int cdev_add(struct cdev *, dev_t, unsigned);//注册字符设备到内核

    例子:写一个简单的字符设备驱动,主设备号为major,只注册0~1两个此设备号,并创建主设备号为major,次设备号创建0,1,2三个设备文件。利用应用程序打开这三个文件,看有什么现象(是否都能打开)

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/irq.h>
    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    #include <asm/arch/regs-gpio.h>
    #include <asm/hardware.h>
    #include <linux/poll.h>
    #include <linux/cdev.h>
    static int hello_open(struct inode *inode, struct file *filp)
    {
    printk("hello_open
    ");
    return 0;
    }
    //构建file_operations结构体
    static struct file_operations hello_fops={
    .owner=THIS_MODULE,
    .open   =   hello_open,
    };
    static int major;
    static struct cdev hello_cdev;
    static struct class* hello_class;
    static struct class_device* hello_class_dev[3];
    static int hello_init(void)
    {
    dev_t devid;
    if(major==0)
    {   
    alloc_chrdev_region(&devid,0,2,"hello");//主设备号为major,次设备号为0,1则对应该file_operations
    major=MAJOR(devid);
    //int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
    }
    else
    {
    devid=MKDEV(major,0);
    register_chrdev_region(devid,2,"hello");
    //int register_chrdev_region(dev_t from, unsigned count, const char *name)
    }
    cdev_init(&hello_cdev,&hello_fops);
    //注册
    cdev_add(&hello_cdev,devid,2);
    //创建类
    hello_class=class_create(THIS_MODULE,"hello");
    int i;
    for(i=0;i<3;i++)
    {   //自动创建设备
    hello_class_dev[i]=class_device_create(hello_class,NULL,MKDEV(major,i),NULL,"hello%d",i);
    }
    return 0;
    }
    static void hello_exit(void)
    {
    cdev_del(&hello_cdev);
    unregister_chrdev_region(MKDEV(major,0),2);
    int i;
    for(i=0;i<3;i++)
    {
    class_device_destroy(hello_class, MKDEV(major, i));
    }
    class_destroy(hello_class);
    }
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_LICENSE("GPL");

    应用程序很简单:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <fcntl.h>
    int main(int argc, char const *argv[])
    {
    int fd=open(argv[1],O_RDWR);
    if(-1==fd)
    {
    printf("Can‘t open!
    ");
    return ;
    }
    printf("Open OK!
    ");
    return 0;
    }

    结果/现象:

    技术分享

    从此可以看出,现在只有(252,0)和(252,1)对应了驱动程序中的file_operations结构体,而(252,2)虽然也是一个存在的设备文件,但是由于驱动程序中没有它对应的file_operations结构体,所以应用程序打开它的时候被拒绝了。

    http://10274409.blog.51cto.com/10264409/1762687

  • 相关阅读:
    net use命令详解(转)
    SQL Server架构SQL Server的执行模式和SQLOS
    SQL Server架构SQL Server的执行模式和SQLOS
    利用xcopy命令实现本地文件复制到远程服务器的方法
    利用xcopy命令实现本地文件复制到远程服务器的方法
    xcopy部署
    xcopy部署
    css样式—字体垂直、水平居中
    音视频&流媒体
    分布式编译工具
  • 原文地址:https://www.cnblogs.com/xihong2014/p/7729968.html
Copyright © 2011-2022 走看看