linux核心學習(23)裝置模型之第二層driver_register

來源:互聯網
上載者:User

終於說到最後一個註冊了,今天也是年末了,可是我依然戰鬥在一線的感覺!說完這個,我也得放鬆一會兒。學習核心也接近大半個月了,收穫頗多,不過還有太多東西需要我在繼續努力了,雖然部落格的流量不是很理想,表明關注我部落格的網友不是很多,但是我相信,就會在不久,linux成為千家萬戶都在關注的對象時,我部落格將成為初學者很好的入門資料,這也是我寫這些文章的一個出發點,希望以後在來回味自己走過linux的路程時有所感慨!

來自:drivers/base/driver.c:
int driver_register(struct device_driver *drv)
{
    int ret;
    struct device_driver *other;

    BUG_ON(!drv->bus->p);

    if ((drv->bus->probe && drv->probe) ||
        (drv->bus->remove && drv->remove) ||
        (drv->bus->shutdown && drv->shutdown))
        printk(KERN_WARNING "Driver '%s' needs updating - please use "
            "bus_type methods/n", drv->name);

    other = driver_find(drv->name, drv->bus);  
 //比較好理解的函數,也就是在匯流排中找到和該驅動同名的驅動
//說白了,就是看看這個驅動之前註冊過沒
    if (other) {
        put_driver(other);        //如果註冊過,那麼我們將不再註冊,注意減少驅動引用,因為在driver_find中增加過
        printk(KERN_ERR "Error: Driver '%s' is already registered, "
            "aborting.../n", drv->name);
        return -EBUSY;
    }

    ret = bus_add_driver(drv);        //如果沒有註冊過,那麼我們將該驅動加入匯流排中
    if (ret)
        return ret;
    ret = driver_add_groups(drv, drv->groups);
    if (ret)
        bus_remove_driver(drv);
    return ret;
}

struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
    struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); 
 //這個函數顧名思義,就是在匯流排集合中找到名稱為name的kobject對象,其實就是驅動名稱了
    struct driver_private *priv;

    if (k) {   //如果找到了
        priv = to_driver(k);
        return priv->driver;     //返回驅動指標
    }
    return NULL;
}

int bus_add_driver(struct device_driver *drv)
{
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;

    bus = bus_get(drv->bus);
    if (!bus)
        return -EINVAL;

    pr_debug("bus: '%s': add driver %s/n", bus->name, drv->name);

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);   //為驅動私人成員申請記憶體且清0
    if (!priv) {
        error = -ENOMEM;
        goto out_put_bus;
    }
    klist_init(&priv->klist_devices, NULL, NULL);   //初始化驅動所支援的裝置鏈表
    priv->driver = drv;
    drv->p = priv;
    priv->kobj.kset = bus->p->drivers_kset;         //設定驅動kobject所屬集合,顯然這裡就是對於匯流排的驅動集合
    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                     "%s", drv->name);         //初始化並添加驅動kobject對象到匯流排驅動中
    if (error)
        goto out_unregister;

    if (drv->bus->p->drivers_autoprobe) {       //還記得我說過這個變數,
        error = driver_attach(drv);       //如果需要自動的去匹配,那麼調用驅動匹配函數
        if (error)
            goto out_unregister;
    }
    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);         //將驅動節點加入到匯流排鏈表中
    module_add_driver(drv->owner, drv);

    error = driver_create_file(drv, &driver_attr_uevent);
    if (error) {
        printk(KERN_ERR "%s: uevent attr (%s) failed/n",
            __func__, drv->name);
    }
    error = driver_add_attrs(bus, drv);
    if (error) {
        /* How the hell do we get out of this pickle? Give up */
        printk(KERN_ERR "%s: driver_add_attrs(%s) failed/n",
            __func__, drv->name);
    }

    if (!drv->suppress_bind_attrs) {
        error = add_bind_files(drv);
        if (error) {
            /* Ditto */
            printk(KERN_ERR "%s: add_bind_files(%s) failed/n",
                __func__, drv->name);
        }
    }

    kobject_uevent(&priv->kobj, KOBJ_ADD);
    return 0;

out_unregister:
    kobject_put(&priv->kobj);
    kfree(drv->p);
    drv->p = NULL;
out_put_bus:
    bus_put(bus);
    return error;
}

來自base/dd.c:
int driver_attach(struct device_driver *drv)
{
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

來自base/bus.c:
int bus_for_each_dev(struct bus_type *bus, struct device *start,
             void *data, int (*fn)(struct device *, void *))
{
    struct klist_iter i;
    struct device *dev;
    int error = 0;

    if (!bus)
        return -EINVAL;

    klist_iter_init_node(&bus->p->klist_devices, &i,
                 (start ? &start->p->knode_bus : NULL));    
//初始化i結構體,我們可以進去看看
    while ((dev = next_device(&i)) && !error)   //在匯流排的裝置鏈表中遍曆鏈表
        error = fn(dev, data);          //然後將裝置和驅動進行匹配,這個fn=__driver_attch
    klist_iter_exit(&i);                 //清除i結構體
    return error;
}

struct klist_iter {
    struct klist        *i_klist;      //所屬鏈表
    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;
    i->i_cur = n;  //這裡的n為NULL
    if (n)
        kref_get(&n->n_ref);
}

static struct device *next_device(struct klist_iter *i)
{
    struct klist_node *n = klist_next(i);      //以i->i_cur節點為起點,得到鏈表i->i_klist的下一個節點
    struct device *dev = NULL;
    struct device_private *dev_prv;

    if (n) {       //如果有,返回該裝置
        dev_prv = to_device_private_bus(n);
        dev = dev_prv->device;
    }
    return dev;
}

struct klist_node *klist_next(struct klist_iter *i)
{
    void (*put)(struct klist_node *) = i->i_klist->put;
    struct klist_node *last = i->i_cur;
    struct klist_node *next;

    spin_lock(&i->i_klist->k_lock);

    if (last) {      //這裡的last為空白
        next = to_klist_node(last->n_node.next);
        if (!klist_dec_and_del(last))
            put = NULL;
    } else
        next = to_klist_node(i->i_klist->k_list.next);  //得到鏈表的第一個節點

    i->i_cur = NULL;
    while (next != to_klist_node(&i->i_klist->k_list)) {  //遍曆鏈表,如果沒有到頭
        if (likely(!knode_dead(next))) {  //如果發現節點next為有效節點
            kref_get(&next->n_ref);      //增加節點引用
            i->i_cur = next;                   //將i結構的起始節點設為next
            break;
        }
        next = to_klist_node(next->n_node.next);   //繼續遍曆鏈表中下一個節點
    }

    spin_unlock(&i->i_klist->k_lock);

    if (put && last)
        put(last);
    return i->i_cur;
}

static int __driver_attach(struct device *dev, void *data)
{
    struct device_driver *drv = data;

    /*
     * Lock device and try to bind to it. We drop the error
     * here and always return 0, because we need to keep trying
     * to bind to devices and some drivers will return an error
     * simply if it didn't support the device.
     *
     * driver_probe_device() will spit a warning if there
     * is an error.
     */

    if (!driver_match_device(drv, dev))   //將驅動和裝置匹配,如果成功返回0
        return 0;

//匯流排去匹配沒有成功不要緊,因為,它只是一個很低級的匹配函數,我們還有更進階的
    if (dev->parent)    /* Needed for USB */
        device_lock(dev->parent);
    device_lock(dev);
    if (!dev->driver)
        driver_probe_device(drv, dev);   //驅動去匹配裝置的進階匹配函數
    device_unlock(dev);
    if (dev->parent)
        device_unlock(dev->parent);

    return 0;
}

static inline int driver_match_device(struct device_driver *drv,
                      struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;  
//這裡就要用到匯流排的match函數了,所有的匹配都是通過它來的
}

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;

    if (!device_is_registered(dev))  //裝置是否註冊過,顯然這裡肯定註冊過
        return -ENODEV;

    pr_debug("bus: '%s': %s: matched device %s with driver %s/n",
         drv->bus->name, __func__, dev_name(dev), drv->name);

    pm_runtime_get_noresume(dev);  //pm_xxx電源管理類
    pm_runtime_barrier(dev);
    ret = really_probe(dev, drv);    //真正執行的寒酸
    pm_runtime_put_sync(dev);

    return ret;
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
    int ret = 0;

    atomic_inc(&probe_count);
    pr_debug("bus: '%s': %s: probing driver %s with device %s/n",
         drv->bus->name, __func__, drv->name, dev_name(dev));
    WARN_ON(!list_empty(&dev->devres_head));

    dev->driver = drv;
    if (driver_sysfs_add(dev)) {
        printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",
            __func__, dev_name(dev));
        goto probe_failed;
    }

    if (dev->bus->probe) {        //如果匯流排的probe函數存在就用匯流排的
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {       //匯流排不存在,則看驅動的probe寒酸
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }

    driver_bound(dev);  //將裝置綁定到驅動上
    ret = 1;
    pr_debug("bus: '%s': %s: bound device %s to driver %s/n",
         drv->bus->name, __func__, dev_name(dev), drv->name);
    goto done;

probe_failed:
    devres_release_all(dev);
    driver_sysfs_remove(dev);
    dev->driver = NULL;

    if (ret != -ENODEV && ret != -ENXIO) {
        /* driver matched but the probe failed */
        printk(KERN_WARNING
               "%s: probe of %s failed with error %d/n",
               drv->name, dev_name(dev), ret);
    }
    /*
     * Ignore errors returned by ->probe so that the next driver can try
     * its luck.
     */
    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->p->knode_driver)) {   //如果裝置已經綁定到了一個驅動,則返回
        printk(KERN_WARNING "%s: device %s already bound/n",
            __func__, kobject_name(&dev->kobj));
        return;
    }

    pr_debug("driver: '%s': %s: bound to device '%s'/n", dev_name(dev),
         __func__, dev->driver->name);

    klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);  //將裝置節點加入到該裝置對應的驅動鏈表中

    if (dev->bus)
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                         BUS_NOTIFY_BOUND_DRIVER, dev);
}

總體來說,驅動的註冊比較複雜,但是我們可以簡單概況一下。
1、在匯流排上找找該驅動有沒有被註冊過
2、若沒有註冊過,則將驅動加入到匯流排驅動集合中
3、在匯流排上找能匹配驅動的裝置
     1、將匯流排上每個裝置進行匹配
     2、首先用匯流排的match 函數進行低級匹配
     3、然後在用匯流排的probe函數進行進階匹配,若失敗,則用驅動上的probe寒酸進行進階匹配
     4、如果匹配成功,則將裝置綁定到驅動鏈表中
4、如果匹配成功,則將驅動加入到匯流排的驅動鏈表中

好不容易啊,我們終於將3大註冊函數說完,很興奮,下一步做什麼呢?其實我也不知道,繼續探索吧... ....

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.