zoukankan      html  css  js  c++  java
  • 【整理】--【字符设备】cdev_init()/cdev_alloc(),cdev_add(),cdev_del()

    (1)

    内核中每个字符设备都对应一个 cdev结构的变量,下面是它的定义:

    linux-2.6.22/include/linux/cdev.h

    struct cdev {

    struct kobject kobj;          // 每个 cdev都是一个 kobject

    struct module *owner;       //指向实现驱动的模块

    const struct file_operations *ops;   // 操纵这个字符设备文件的方法

    struct list_head list;       // 与 cdev对应的字符设备文件的inode->i_devices的链表头

    dev_t dev;                  // 起始设备编号

    unsigned int count;       // 设备范围号大小

    };

    (2)

    初始化的两种方式:cdev_init() , cdev_allonc()

    一个 cdev一般它有两种定义初始化方式:静态的和动态的。

    静态内存定义初始化:

    struct cdev my_cdev;

    cdev_init(&my_cdev, &fops);

    my_cdev.owner = THIS_MODULE;

    动态内存定义初始化:

    struct cdev *my_cdev = cdev_alloc();

    my_cdev->ops = &fops;

    my_cdev->owner = THIS_MODULE;

    两种使用方式的功能是一样的,只是使用的内存区不一样,一般视实际的数据结构需求而定。

    下面贴出了两个函数的代码,以具体看一下它们之间的差异。

    struct cdev *cdev_alloc(void)

    {

       struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);

       if (p) {

       INIT_LIST_HEAD(&p->list);

       kobject_init(&p->kobj, &ktype_cdev_dynamic);

       }

       return p;

    }

    void cdev_init(struct cdev *cdev, const struct file_operations *fops)

    {

       memset(cdev, 0, sizeof *cdev); 注1;

       INIT_LIST_HEAD(&cdev->list);

       kobject_init(&cdev->kobj, &ktype_cdev_default);

       cdev->ops = fops;

    }

    由此可见,两个函数完成的功能基本一致,只是 cdev_init()还多赋了一个 cdev->ops的值。

    这里需要注意的是kzalloc后的空间是不需要再执行memset的,因为它本身就包含了这个操作。而memset一般作用在已经存在的空间上。

    由此基本上对这两个函数有了一个基本的概念:cdev_alloc函数针对于需要空间申请的操作,而cdev_init针对于不需要空间申请的操作;因此如果你定义的是一个指针,那么只需要使用cdev_alloc函数并在其后做一个ops的赋值操作就可以了;如果你定义的是一个结构体而非指针,那么只需要使用cdev_init函数就可以了。

    看到有些代码在定义一个指针后使用了cdev_alloc函数,紧接着又使用了cdev_init函数,这个过程不会出现错误,但只是做了一些重复的无用工作,其实完全可以不需要的。

    (3)

    初始化cdev后,需要把它添加到系统中去。为此可以调用 cdev_add()函数。传入 cdev结构的指针,起始设备编号,以及设备编号范围

    Synopsis

      int fsfunc cdev_add(struct cdev *p , dev_t dev , unsigned count);

    Arguments

      p  : the cdev structure for the device

      dev  :  the first device number for which this device is responsible

      count  :  the number of consecutive minor numbers corresponding to this device

    Description

      cdev_add adds the device represented by p to the system, making it live immediately. A negative error code is returned on failure.

    int cdev_add(struct cdev *p, dev_t dev,unsigned count)

    {

       p->dev = dev;

       p->count = count;

       return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);

    }

    关于kobj_map()函数就不展开了,我只是大致讲一下它的原理。内核中所有的字符设备都会记录在一个 kobj_map结构的 cdev_map变量中。这个结构的变量中包含一个散列表用来快速存取所有的对象。kobj_map()函数就是用来把字符设备编号和 cdev结构变量一起保存到 cdev_map这个散列表里。当后续要打开一个字符设备文件时,通过调用 kobj_lookup()函数,根据设备编号就可以找到cdev结构变量,从而取出其中的ops字段。

     (4)

    当一个字符设备驱动不再需要的时候(比如模块卸载),就可以用 cdev_del()函数来释放 cdev占用的内存。

    Name

      cdev_del — remove a cdev from the system

    Synopsis

      void fsfunc cdev_del( struct cdev * p);

    Arguments

      p : the cdev structure to be removed

    Description

    cdev_del removes p from the system, possibly freeing the structure itself.

    void cdev_del(struct cdev *p)

    {

      cdev_unmap(p->dev, p->count);

      kobject_put(&p->kobj);

    }

    其中cdev_unmap()调用 kobj_unmap()来释放 cdev_map散列表中的对象。kobject_put()释放 cdev结构本身。

    注1:

    Memset  用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘/0’;

    例:chara[100];memset(a, '/0', sizeof(a));

    memcpy  用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度。

    例:chara[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。

    Strcpy   就只能拷贝字符串了,它遇到'/0'就结束拷贝。

    例:chara[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘/0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。

    memset主要应用是初始化某个内存空间。

    memcpy是用于copy源空间的数据到目的空间中。

    strcpy用于字符串copy,遇到‘/0’,将结束。

  • 相关阅读:
    FZU 2112 并查集、欧拉通路
    HDU 5686 斐波那契数列、Java求大数
    Codeforces 675C Money Transfers 思维题
    HDU 5687 字典树插入查找删除
    HDU 1532 最大流模板题
    HDU 5384 字典树、AC自动机
    山科第三届校赛总结
    HDU 2222 AC自动机模板题
    HDU 3911 线段树区间合并、异或取反操作
    CodeForces 615B Longtail Hedgehog
  • 原文地址:https://www.cnblogs.com/apolloenterprise/p/4663115.html
Copyright © 2011-2022 走看看