zoukankan      html  css  js  c++  java
  • cdev_add

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

    函数首先将分配的设备号与设备数目保存进cdev结构体中。然后再讲cdev结构体记录在一个 kobj_map 结构的 cdev_map 变量中。

     1 /**
     2  * cdev_add() - add a char device to the system
     3  * @p: the cdev structure for the device
     4  * @dev: the first device number for which this device is responsible
     5  * @count: the number of consecutive minor numbers corresponding to this
     6  *         device
     7  *
     8  * cdev_add() adds the device represented by @p to the system, making it
     9  * live immediately.  A negative error code is returned on failure.
    10  */
    11 int cdev_add(struct cdev *p, dev_t dev, unsigned count)
    12 {
    13     p->dev = dev;
    14     p->count = count;
    15     return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
    16 }

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

    kobj_map函数中哈希表的实现原理和前面注册分配设备号中的几乎完全一样,通过要加入系统的设备的主设备号major(major=MAJOR(dev))来获得probes数组的索引值i(i = major % 255),然后把一个类型为struct probe的节点对象加入到probes[i]所管理的链表中,如图2-6所示。其中struct probe所在的矩形块中的深色部分是我们重点关注的内容,记录了当前正在加入系统的字符设备对象的有关信息。其中,dev是它的设备号,range是从次设备号开始连续的设备数量,data是一void *变量,指向当前正要加入系统的设备对象指针p。图2-6展示了两个满足主设备号major % 255 = 2的字符设备通过调用cdev_add之后,cdev_map所展现出来的数据结构状态。

    所以,简单地说,设备驱动程序通过调用cdev_add把它所管理的设备对象的指针嵌入到一个类型为struct probe的节点之中,然后再把该节点加入到cdev_map所实现的哈希链表中。对系统而言,当设备驱动程序成功调用了cdev_add之后,就意味着一个字符设备对象已经加入到了系统,在需要的时候,系统就可以找到它。对用户态的程序而言,cdev_add调用之后,就已经可以通过文件系统的接口呼叫到我们的驱动程序。

     1 static struct kobj_map *cdev_map;
     2 typedef struct kobject *kobj_probe_t(dev_t, int *, void *);
     3 struct kobj_map {
     4     struct probe {
     5         struct probe *next;
     6         dev_t dev;
     7         unsigned long range;
     8         struct module *owner;
     9         kobj_probe_t *get;
    10         int (*lock)(dev_t, void *);
    11         void *data;
    12     } *probes[255];
    13     struct mutex *lock;
    14 };

     1 //cdev_add(struct cdev *p, dev_t dev, unsigned count)
     2 //                   设备号,  设备数目,         匹配函数,   锁定函数,    cdev指针
     3 //kobj_map(cdev_map,    dev,    count,    NULL,   exact_match, exact_lock,    p);
     4 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
     5          struct module *module, kobj_probe_t *probe,
     6          int (*lock)(dev_t, void *), void *data)
     7 {
     8     unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;//判断占用几个主设备号
     9     unsigned index = MAJOR(dev);
    10     unsigned i;
    11     struct probe *p;
    12 
    13     if (n > 255)
    14         n = 255;
    15 
    16     p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);
    17 
    18     if (p == NULL)
    19         return -ENOMEM;
    20 
    21     for (i = 0; i < n; i++, p++) {
    22         p->owner = module;
    23         p->get = probe;
    24         p->lock = lock;
    25         p->dev = dev;
    26         p->range = range;
    27         p->data = data;
    28     }
    29     mutex_lock(domain->lock);
    30     for (i = 0, p -= n; i < n; i++, p++, index++) 
    31     {
    32         struct probe **s = &domain->probes[index % 255];
    33         while (*s && (*s)->range < range)
    34             s = &(*s)->next;
    35         p->next = *s;
    36         *s = p;
    37     }
    38     mutex_unlock(domain->lock);
    39     return 0;
    40 }

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

     1 /**
     2  * cdev_del() - remove a cdev from the system
     3  * @p: the cdev structure to be removed
     4  *
     5  * cdev_del() removes @p from the system, possibly freeing the structure
     6  * itself.
     7  */
     8 void cdev_del(struct cdev *p)
     9 {
    10     cdev_unmap(p->dev, p->count);
    11     kobject_put(&p->kobj);
    12 }

    kobj_unmap() 释放 cdev_map 散列表中的对象。

     1 //void cdev_del(struct cdev *p)
     2 //cdev_unmap(p->dev, p->count);
     3 static void cdev_unmap(dev_t dev, unsigned count)
     4 {
     5     kobj_unmap(cdev_map, dev, count);
     6 }
     7 void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
     8 {
     9     unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
    10     unsigned index = MAJOR(dev);
    11     unsigned i;
    12     struct probe *found = NULL;
    13 
    14     if (n > 255)
    15         n = 255;
    16 
    17     mutex_lock(domain->lock);
    18     for (i = 0; i < n; i++, index++) {
    19         struct probe **s;
    20         for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) 
    21         {
    22             struct probe *p = *s;
    23             if (p->dev == dev && p->range == range) 
    24             {
    25                 *s = p->next;
    26                 if (!found)
    27                     found = p;
    28                 break;
    29             }
    30         }
    31     }
    32     mutex_unlock(domain->lock);
    33     kfree(found);
    34 }
    kobj_unmap()

    kobject_put() 释放 cdev 结构本身。

     1 /**
     2  * kobject_put - decrement refcount for object.
     3  * @kobj: object.
     4  *
     5  * Decrement the refcount, and if 0, call kobject_cleanup().
     6  */
     7 void kobject_put(struct kobject *kobj)
     8 {
     9     if (kobj) {
    10         if (!kobj->state_initialized)
    11             WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
    12                    "initialized, yet kobject_put() is being "
    13                    "called.
    ", kobject_name(kobj), kobj);
    14         kref_put(&kobj->kref, kobject_release);
    15     }
    16 }
    kobject_put()
  • 相关阅读:
    四、创建多线程、数据共享
    operator函数操作符
    三、线程传参
    二、线程创建、结束
    一、并发、进程、线程概念
    bagging和boosting的区别
    ID3,C4.5和CART三种决策树的区别
    7创建型模式之建造者模式
    6创建型模式之工厂模式与抽象工厂模式
    5创建型模式之简单工厂模式
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/6034776.html
Copyright © 2011-2022 走看看