map.c 添加注释

/*
 *  linux/drivers/base/map.c
 *
 * (C) Copyright Al Viro 2002,2003
 *    Released under GPL v2.
 *
 * NOTE: data structure needs to be changed.  It works, but for large dev_t
 * it will be too slow.  It is isolated, though, so these changes will be
 * local to that file.
 */

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/kdev_t.h>
#include <linux/kobject.h>
#include <linux/kobj_map.h>

struct kobj_map {
    struct probe {
        struct probe *next;
        dev_t dev;
        unsigned long range;
        struct module *owner;
        kobj_probe_t *get;
        int (*lock)(dev_t, void *);
        void *data;
    } *probes[255];
    struct mutex *lock;
};

int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
         struct module *module, kobj_probe_t *probe,
         int (*lock)(dev_t, void *), void *data)
{
    /* [cgw]: 计算MAJOR(dev)到MAJOR(dev + range - 1)有几个
          * 主设备,由于主设备号都一样,所以这里n = 1
          */
    unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
    /* [cgw]: 以主设备号为索引 */
    unsigned index = MAJOR(dev);
    unsigned i;
    struct probe *p;

    /* [cgw]: 主设备超出255个 */
    if (n > 255)
        n = 255;
    /* [cgw]: 分配n个struct probe内存空间*/
    p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);
    /* [cgw]: 分配失败*/
    if (p == NULL)
        return -ENOMEM;
    /* [cgw]: 填装n个struct probe,对应n个主设备号
          * 
          */
    for (i = 0; i < n; i++, p++) {
        p->owner = module;
        p->get = probe;
        p->lock = lock;
        p->dev = dev;
        p->range = range;
        p->data = data;
    }
    /* [cgw]: 进入临界区*/
    mutex_lock(domain->lock);
    /* [cgw]: 这里p -= n是因为,在以上for循环中,p++了n次 */
    for (i = 0, p -= n; i < n; i++, p++, index++) {
        /* [cgw]: 根据当前索引,从probes[]中
              * 取出一个probe
              */
        struct probe **s = &domain->probes[index % 255];
        /* [cgw]: probe是一个链表,每个新加入的节点,
          * 按照其range的大小,从小到大排列,即头结点的
          * range是最小的
          */
        while (*s && (*s)->range < range)
            /* [cgw]: 继续查找下一个probe,直到其range大于
                      * 或等于新加入probe的range为止
                  */
            s = &(*s)->next;
        /* [cgw]: 找到了一个probe,其range大于或等于新加入
              * probe的range,把这个新加入的probe下一节点指向
              * 这个probe节点
              */
        p->next = *s;
        /* [cgw]: 新加入的节点代替旧的位置 */
        *s = p;
    }
    /* [cgw]: 退出临界区*/
    mutex_unlock(domain->lock);
    return 0;
}

void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
{
    /* [cgw]: 计算MAJOR(dev)到MAJOR(dev + range - 1)有几个
          * 主设备,由于主设备号都一样,所以这里n = 1
          */
    unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
    /* [cgw]: 以主设备号为索引 */
    unsigned index = MAJOR(dev);
    unsigned i;
    struct probe *found = NULL;
    /* [cgw]: 主设备超出255个 */
    if (n > 255)
        n = 255;
    /* [cgw]: 进入临界区*/
    mutex_lock(domain->lock);
    
    for (i = 0; i < n; i++, index++) {
        struct probe **s;
        for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
            struct probe *p = *s;
            /* [cgw]: 找到这个设备,并且其对应的次设备号个数也匹配 */
            if (p->dev == dev && p->range == range) {
                /* [cgw]: 这个设备对应的节点,被下一节点取代,即移除
                      * 这个节点
                      */
                *s = p->next;
                /* [cgw]: 记录这个节点 */
                if (!found)
                    found = p;
                break;
            }
        }
    }
    /* [cgw]: 退出临界区*/
    mutex_unlock(domain->lock);
    /* [cgw]: 释放这个节点对应的内存空间 */
    kfree(found);
}

struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
{
    struct kobject *kobj;
    struct probe *p;
    unsigned long best = ~0UL;

retry:  /* [cgw]: 重试 */
    /* [cgw]: 进入临界区 */
    mutex_lock(domain->lock);
    /* [cgw]: 以主设备号为索引,从probes数组取出一个probe */
    for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
        struct kobject *(*probe)(dev_t, int *, void *);
        struct module *owner;
        void *data;

        /* [cgw]: 取出的这个probe对应的设备号大于要查找的设备号
                  * 或 这个probe对应的设备号的最大次设备号小于要查找的设备号
                  * 即不在查找范围内,那么返回,继续取出下一个probe
                  */
        if (p->dev > dev || p->dev + p->range - 1 < dev)
            continue;
        /* [cgw]: 连续的次设备号个数超过最大范围,出错
          */
        if (p->range - 1 >= best)
            break;
        /* [cgw]: 模块引用失败???? */
        if (!try_module_get(p->owner))
            continue;
        /* [cgw]: 到此,找到了我们想要的那个probe,接着提取它的值 */
        owner = p->owner;
        data = p->data;
        probe = p->get;
        best = p->range - 1;
        /* [cgw]: 计算这个要找的设备的次设备号,相对于找到的probe对应
          * 设备号的次设备号的偏移,因为找到的probe对应设备号的次设备号
          * 是这个设备的次设备号基址
          */
        *index = dev - p->dev;
        /* [cgw]: 未搞明白这个判断的意思 */
        if (p->lock && p->lock(dev, data) < 0) {
            /* [cgw]: 放弃模块使用权???? */
            module_put(owner);
            continue;
        }
        /* [cgw]: 退出临界区 */
        mutex_unlock(domain->lock);
        /* [cgw]: 调用probe的实现函数,并返回对应的kobj */
        kobj = probe(dev, index, data);
        /* Currently ->owner protects _only_ ->probe() itself. */
        /* [cgw]: 放弃模块使用权???? */
        module_put(owner);
        /* [cgw]: 获得kobj,退出 */
        if (kobj)
            return kobj;
        goto retry;
    }
    /* [cgw]: 退出临界区 */
    mutex_unlock(domain->lock);
    return NULL;
}

struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
{
    /* [cgw]: 分配一个struct kobj_map内存空间 */
    struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
    /* [cgw]: 分配一个struct probe指针内存空间 */
    struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
    int i;

    /* [cgw]: 分配失败 */
    if ((p == NULL) || (base == NULL)) {
        /* [cgw]: 释放内存空间 */
        kfree(p);
        kfree(base);
        return NULL;
    }
    /* [cgw]: 设置默认设备号为1,连续range个次设备,设置probe的实现
          * 函数(回调)
          */
    base->dev = 1;
    base->range = ~0;
    base->get = base_probe;
    /* [cgw]: 设置probes数组的初始值 */
    for (i = 0; i < 255; i++)
        p->probes[i] = base;
    p->lock = lock;
    return p;                                                                                                                   }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值