现在的位置: 首页 > 综合 > 正文

driver_attach

2013年01月16日 ⁄ 综合 ⁄ 共 7050字 ⁄ 字号 评论关闭

int driver_attach(struct device_driver * drv)
{
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
调用该函数,那么drv驱动程序会和drv所在总线上连接了的物理设备进行一一匹配,再来看看下面:
int bus_for_each_dev(struct bus_type * bus, struct device * start,
         void * data, int (*fn)(struct device *,
void *))
{
    struct klist_iter i;//
专门用于遍历的链表结构体,其中i_cur是遍历移动的关键
    struct device * dev;
    int error = 0;
    if (!bus)
        return -EINVAL;
    klist_iter_init_node(&bus->klist_devices, &i,
             (start ?
&start->knode_bus : NULL));
    //i->i_klist = &bus->klist_devices;
    //i->i_head = &bus->klist_devices.k_list;
    //i->i_cur     = NULL;//
表示从最前端开始遍历挂接到bus总线上的整个设备链条.
    while ((dev = next_device(&i)) && !error)
    //dev
为该bus总线链表上的一个设备,[就像一根藤条上的一朵小花gliethttp_20071025]
    //
这些device设备把自己的&device->knode_bus链表单元链接到了bus->klist_devices
    //
这也说明名字为knode_buslist单元将是要被挂接到bus->klist_devices的链表上
    //
同理&device->knode_driver将是这个device设备链接到drivers驱动上的list节点识别单元
    //
driver_bound()->klist_add_tail(&dev->knode_driver,
&dev->driver->klist_devices);
        error = fn(dev, data);//
调用__driver_attach函数,进行匹配运算
    klist_iter_exit(&i);
    return error;//
成功匹配返回0
}
struct klist_iter {
    struct klist        * i_klist;
    struct list_head    * i_head;
    struct klist_node    * i_cur;
};
void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct
klist_node *n)
{
    i->i_klist = k;          
 //
需要被遍历的klist
    i->i_head = &k->k_list;    //
开始的链表头
    i->i_cur = n;          
 //
当前位置对应的klist_node节点,next_device()会从当前n开始一直搜索到
                
           //
链表的结尾,也就是i_head->prev处停止
    if (n)
        kref_get(&n->n_ref);//
引用计数加1
}
static struct device * next_device(struct klist_iter * i)
{
    struct klist_node * n = klist_next(i);
    return n ? container_of(n, struct device, knode_bus) : NULL;
    //
因为ndevice->knode_bus的指针,所以container_of将返回device的指针
}
struct klist_node * klist_next(struct klist_iter * i)
{
    struct list_head * next;
    struct klist_node * lnode = i->i_cur;
    struct klist_node * knode = NULL;//
0,next == i->i_head时用于退出
    void (*put)(struct klist_node *) = i->i_klist->put;
    spin_lock(&i->i_klist->k_lock);
    if (lnode) {
        next = lnode->n_node.next;
        if (!klist_dec_and_del(lnode))//
释放前一个i_cur对象的引用计数
            put = NULL;//klist_dec_and_del
成功的对引用计数做了减1操作,那么失效用户定义put
    } else
        next = i->i_head->next;//
如果lnode=0,那么从链表头开始,所以head->next指向第1个实际对象
    if (next != i->i_head) {//head
并不链接设备,所以head无效
    //
next == i->i_head,说明已经遍历到了head牵头的链表的末尾,回环到了head,
    //
所以knode将不会进行赋值,这时knode=0,while ((dev = next_device(&i)) && !error)因为0而退出
        knode = to_klist_node(next);//
调用container_of()获取klist_node->n_nodeklist_node地址
        kref_get(&knode->n_ref);//
对该node的引用计数加1
    }
    i->i_cur = knode;//
记住当前遍历到的对象,next == i->i_head,knode=0
    spin_unlock(&i->i_klist->k_lock);
    if (put && lnode)
        put(lnode);
    return knode;
}
static int klist_dec_and_del(struct klist_node *n)
{
    return kref_put(&n->n_ref, klist_release);//
对该node的引用计数减1,如果引用计数到达0,那么调用klist_release
}
static void klist_release(struct kref * kref)
{
    struct klist_node * n = container_of(kref, struct klist_node,
n_ref);
    list_del(&n->n_node);//
从节点链表上摘掉该node节点
    complete(&n->n_removed);//
    n->n_klist = NULL;
}
void fastcall complete(struct completion *x)
{
    unsigned long flags;
    spin_lock_irqsave(&x->wait.lock, flags);//
关闭中断,防止并发
    x->done++;
    //
唤醒因为某些原因悬停在klist_node->n_removed等待队列上的task
    //
这种现象之一是:__device_release_driver()删除挂接在设备上的driver,会出现
    //
删除task小憩在nodewait
    __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE |
TASK_INTERRUPTIBLE,
             1, 0, NULL);
    spin_unlock_irqrestore(&x->wait.lock, flags);//
恢复中断
}
static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
             int nr_exclusive, int
sync, void *key)
{
    struct list_head *tmp, *next;
    list_for_each_safe(tmp, next, &q->task_list) {//
遍历以head牵头的链表上的task
        wait_queue_t *curr = list_entry(tmp,
wait_queue_t, task_list);
        unsigned flags = curr->flags;
        if (curr->func(curr, mode, sync, key)
&&//
调用wait上准备好了的回调函数func
                (flags &
WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
            break;
    }
}
//
抛开链表上的head,当最后一个post==head,说明链表已经遍历结束(gliethttp_20071025)
#define list_for_each_safe(pos, n, head) /
    for (pos = (head)->next, n = pos->next; pos != (head); /
        pos = n, n = pos->next)
void klist_iter_exit(struct klist_iter * i)
{
    if (i->i_cur) {
//
对于正常遍历的退出,i->i_cur会等于0,如果找到了匹配对象,提前退出了,那么就会在这里对引用进行释放
        klist_del(i->i_cur);
        i->i_cur = NULL;
    }
}
static int __driver_attach(struct device * dev, void * data)
{
    struct device_driver * drv = data;
//data
就是打算把自己匹配到bus上挂接的合适设备上的driver驱动
    if (dev->parent)
        down(&dev->parent->sem);//
使用信号量保护下面的操作
    down(&dev->sem);
    if (!dev->driver)//
如果当前这个dev设备还没有挂接一个driver驱动
        driver_probe_device(drv, dev);//
那么尝试该dev是否适合被该drv驱动管理
    up(&dev->sem);
    if (dev->parent)
        up(&dev->parent->sem);
    return 0;
}
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
    int ret = 0;
    if (!device_is_registered(dev))//
设备是否已经被bus总线认可
        return -ENODEV;
    if (drv->bus->match && !drv->bus->match(dev,
drv))
    //
调用该driver驱动自定义的match函数,:usb_device_match(),查看
    //
这个设备是否符合自己,drv->bus->match()返回1,表示本drv认可该设备
    //
否则,goto done,继续检测下一个device设备是否和本drv匹配
        goto done;
    pr_debug("%s: Matched Device %s with Driver %s/n",
         drv->bus->name, dev->bus_id,
drv->name);
    //
这下来真的了,
    ret = really_probe(dev, drv);
done:
    return ret;
}
static inline int device_is_registered(struct device *dev)
{
    return dev->is_registered;//
当调用bus_attach_device()之后,is_registered=1
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
    int ret = 0;
    atomic_inc(&probe_count);
    pr_debug("%s: Probing driver %s with device %s/n",
         drv->bus->name, drv->name,
dev->bus_id);
    WARN_ON(!list_empty(&dev->devres_head));
    dev->driver = drv;//
管理本dev的驱动指针指向drv
    if (driver_sysfs_add(dev)) {//
driverdev使用link,链接到一起,使他们真正相关
        printk(KERN_ERR "%s: driver_sysfs_add(%s)
failed/n",
            __FUNCTION__,
dev->bus_id);
        goto probe_failed;
    }
    if (dev->bus->probe) {//
总线提供了设备探测函数
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {//
驱动自己提供了设备探测函数
    //
因为drv驱动自己也不想管理那些意外的非法设备
    //
所以一般drv都会提供这个功能,相反
    //
比如:usb_bus_type没有提供probe,usb驱动提供了usb_probe_interface
    //
来确认我这个driver软件真的能够管理这个device设备
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }
    driver_bound(dev);
    ret = 1;
    pr_debug("%s: Bound Device %s to Driver %s/n",
         drv->bus->name, dev->bus_id,
drv->name);
    goto done;
probe_failed:
    devres_release_all(dev);
    driver_sysfs_remove(dev);
    dev->driver = NULL;
    if (ret != -ENODEV && ret != -ENXIO) {
        printk(KERN_WARNING
         "%s: probe of %s failed with error
%d/n",
         drv->name, dev->bus_id, ret);
    }
    ret = 0;
done:
    atomic_dec(&probe_count);
    wake_up(&probe_waitqueue);
    return ret;
}
static void driver_bound(struct device *dev)
{
    if (klist_node_attached(&dev->knode_driver)) {
    //
dev已经挂到了某个driver驱动的klist_devices链条上了
    //
感觉不应该发生
        printk(KERN_WARNING "%s: device %s
already bound/n",
            __FUNCTION__,
kobject_name(&dev->kobj));
        return;
    }
    pr_debug("bound device '%s' to driver '%s'/n",
         dev->bus_id,
dev->driver->name);
    if (dev->bus)
    
   blocking_notifier_call_chain(&dev->bus->bus_notifier,
                
    BUS_NOTIFY_BOUND_DRIVER, dev);
    //
将本devknode_driver链表结构体节点挂接到该driver->klist_devices
    //
这样driver所管理的device设备又多了1,
    //
也可以说又多了1device设备使用本driver驱动管理它自己(gilethttp_20071025).
    klist_add_tail(&dev->knode_driver,
&dev->driver->klist_devices);
}
以上的理解还缺少各种知识的汇集性(因为自己还缺少很多知识),甚至会存在若干错误性,当然正如开花的植物一样,一根藤条上需要开的花分几种,有已经绽开的,有含苞待放的,有蓄势待发的,还有10天以后才能显露的,那就让时间来完善吧,只要植物不被若干因素kill,我相信花会慢慢的开将来(gliethttp_20071025小感).

抱歉!评论已关闭.