driver_register()函數解析


driver_register()函數解析

/**
 * driver_register - register driver with bus
 * @drv: driver to register
 *
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 
 * driver_register - 注冊驅動到bus
 * @drv: 要注冊的驅動
 *
 * 我們把很多工作都放到bus_add_driver()中,因為我們要做的大部分事情都跟bus結構有關系
 
 */
我們首先來完整地看下driver_register函數定義:
int driver_register(struct device_driver *drv)
{
    int ret;
    struct device_driver *other;

    BUG_ON(!drv->bus->p);  //判斷bus->p是否為空,見第1部分分析

    if ((drv->bus->probe && drv->probe) ||    //判斷驅動跟驅動的總線是否有沖突的函數注冊,給出警告信息,見第2部分分析
        (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);  //在注冊在bus上的driver尋找是否有跟要注冊的driver相同,有則表明驅動已被注冊過,見第3部分分析
    if (other) {
        put_driver(other);
        printk(KERN_ERR "Error: Driver '%s' is already registered, "
            "aborting...\n", drv->name);
        return -EBUSY;
    }

    ret = bus_add_driver(drv); //經過上面的驗證后,將驅動添加注冊到bus上,見第4部分分析
    if (ret)
        return ret;
    ret = driver_add_groups(drv, drv->groups); //如果grop不為空的話,將在驅動文件夾下創建以group名字的子文件夾,然后在子文件夾下添加group的屬性文件
    if (ret)
        bus_remove_driver(drv);
    return ret;
}
這個函數開始先判斷bus->p是否為空,如果不為空然后判斷驅動跟驅動的總線是否有沖突的函數注冊,如果有沖突就給出警告信息,然后在注冊在bus上的driver尋找是否有跟
要注冊的driver相同,有則表明驅動已被注冊過,返回錯誤。經過上面的驗證后,將驅動添加注冊到bus上,如果沒問題,則再將驅動添加到同一屬性的組中,在sysfs下表現為同一個目錄。
有了大概的流程概念后,我們開始一步一步的詳細分析,分為四個部分:
1,BUG_ON(!drv->bus->p);
BUG_ON定義如下:
    #define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)
其中的BUG():
    #define BUG() do { \
        printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
        panic("BUG!"); \
    } while (0)
由上面定義可以看出,如果drv->bus->p為空,則打印失敗信息以及panic信息。其實這個主要是判斷bus是否存在,這個結論還需要論證!

2,    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);
主要是判斷驅動跟驅動的總線是否有沖突的函數注冊,給出警告信息

3,other = driver_find(drv->name, drv->bus)
driver_find()函數定義如下:
struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
    struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);//在bus的驅動集合里面發現同名自動的驅動
    struct driver_private *priv;

    if (k) {
        priv = to_driver(k);//如果找到,通過kobject轉換成driver_private,返回相應的驅動
        return priv->driver;
    }
    return NULL;
}
這個函數的功能就是查找bus上已經注冊的驅動,和要注冊的驅動比較,如果找到,則返回找到的驅動。bus->p->drivers_kset是bus上已經注冊的驅動的kobject的結合,會傳給kset_find_obj()作為參數。
讀到這里,應該去復習一下kobject,kset,sysfs等概念了。這里為了分析的連貫性就不再插入相關概念。
3-1:kset_find_obj()的定義如下:
struct kobject *kset_find_obj(struct kset *kset, const char *name)
{
    struct kobject *k;
    struct kobject *ret = NULL;

    spin_lock(&kset->list_lock);
    list_for_each_entry(k, &kset->list, entry) {  //遍歷kset->list中的每個kobject
        if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
            ret = kobject_get(k);  //若有同名字的,增加kobject的kref,並返回該kobject
            break;
        }
    }
    spin_unlock(&kset->list_lock);
    return ret;
}
它會查找在kset->list上的每一個kobject與改驅動的名字是否有同名字的,如果找到則返回改kobject。
4,bus_add_driver(drv);
它的定義如下:
int bus_add_driver(struct device_driver *drv)
{
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;

    bus = bus_get(drv->bus);  //找到該drv所屬的bus,其實就是增加該bus->p->subsys->kobject->kref的引用計數
    if (!bus)
        return -EINVAL;

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

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);  //分配driver_private結構
    if (!priv) {
        error = -ENOMEM;
        goto out_put_bus;
    }
    klist_init(&priv->klist_devices, NULL, NULL);  //初始化priv->klist_devices
    priv->driver = drv;  //將該drv賦值給priv->driver
    drv->p = priv;  //而drv的drv->p又等於priv
    priv->kobj.kset = bus->p->drivers_kset; //指向bus的drvier容器
    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                     "%s", drv->name); //驅動的kobject初始化和添加dir到sysfs中,后面會有分析,見4-1部分
    if (error)
        goto out_unregister;

    if (drv->bus->p->drivers_autoprobe) {  //這個變量默認是為1的
        error = driver_attach(drv);   //匹配函數,后面會分析,見4-2部分
        if (error)
            goto out_unregister;
    }
    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //將priv->knode_bus添加到bus->p->klist_drivers,見4-3部分
    module_add_driver(drv->owner, drv);  //添加drv的module,見4-4部分

    error = driver_create_file(drv, &driver_attr_uevent); //在sysfs的目錄下創建文件uevent屬性文件,見4-5分析
    if (error) {
        printk(KERN_ERR "%s: uevent attr (%s) failed\n",
            __func__, drv->name);
    }
    error = driver_add_attrs(bus, drv);   //給driver添加bus上的所有屬性
    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);
    }
    error = add_bind_files(drv);  //添加綁定文件,driver_attr_bind 和 driver_attr_unbind見4-5分析
    if (error) {
        /* Ditto */
        printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
            __func__, drv->name);
    }

    kobject_uevent(&priv->kobj, KOBJ_ADD);  //產生一個KOBJ_ADD uevent
    return 0;
out_unregister:
    kfree(drv->p);
    drv->p = NULL;
    kobject_put(&priv->kobj);
out_put_bus:
    bus_put(bus);
    return error;
}
這個函數是driver_register中核心函數,真正的功能實現都在這個函數里面。這個函數首先找到該drv所屬的bus,然后為driver_private結構分配空間,
然后初始化priv,把driver,bus,priv聯系在一塊,然后添加驅動的kobject到kobject的層次中,也就是添加驅動文件夾到sysfs,然后根據drivers_autoprobe決定是否去bus上尋找與driver匹配的device。
然后將driver添加到bus上的驅動列表中。然后添加驅動的模塊,再然后就是生成sysfs下面的一些屬性文件。
4-1,kobject_init_and_add()
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
             struct kobject *parent, const char *fmt, ...)
{
    va_list args;
    int retval;

    kobject_init(kobj, ktype);  //初始化kobject

    va_start(args, fmt);  //動態可變參數的使用
    retval = kobject_add_varg(kobj, parent, fmt, args);
    va_end(args);

    return retval;
}
4-1-1,kobject_init()
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
...

    kobject_init_internal(kobj);
    kobj->ktype = ktype;
...
}
kobject_init將調用kobject_init_internal()
4-1-1-1,kobject_init_internal()
static void kobject_init_internal(struct kobject *kobj)
{
    if (!kobj)
        return;
    kref_init(&kobj->kref);  //原子地將kobj->kref設為1
    INIT_LIST_HEAD(&kobj->entry); //初始化kobj->entry列表
    kobj->state_in_sysfs = 0;
    kobj->state_add_uevent_sent = 0;
    kobj->state_remove_uevent_sent = 0;
    kobj->state_initialized = 1;
}
可以看出kobject_init()的功能就是初始化kobject結構中的成員狀態。
4-1-2,這里我們不介紹動態變量的使用方法,開始分析kobject_add_varg()
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
                const char *fmt, va_list vargs)
{
    int retval;

    retval = kobject_set_name_vargs(kobj, fmt, vargs);  //主要是將vargs按照fmt格式給kobject起個名字,從調用關系知道vargs是drv->name,也就是驅動的名字
    if (retval) {
        printk(KERN_ERR "kobject: can not set name properly!\n");
        return retval;
    }
    kobj->parent = parent;  //由上面的函數調用關系可以知道這個將被賦值為NULL
    return kobject_add_internal(kobj);  //見4-2-1
}
4-1-2-1,kobject_add_internal()
static int kobject_add_internal(struct kobject *kobj)
{
...
    parent = kobject_get(kobj->parent);  //得到父節點,從上面知道parent是NULL

    /* join kset if set, use it as parent if we do not already have one */
    if (kobj->kset) {  //kset不為空 

        if (!parent)  //parent為空
            parent = kobject_get(&kobj->kset->kobj);
        kobj_kset_join(kobj);
        kobj->parent = parent;
 /*如果kset不為空,而parent為空(這里這個條件一定成立的,因為kset=bus->p->drivers_kset,parent=NULL),
則該kobj->parent指向kobj->kset->kobj,而且將kobj加入到kobj->kset的list中,也就是driver放入bus的kset列表中,也就是bus是driver的容器,實際上bus同時還是device的容器,當然bus本身實質上也是個kobject,所以理解kset這個容器的概念至關重要,它是構成了sysfs的層次結構關系*/
    }

    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
         kobject_name(kobj), kobj, __func__,
         parent ? kobject_name(parent) : "",
         kobj->kset ? kobject_name(&kobj->kset->kobj) : "");

    error = create_dir(kobj);  //建立該驅動的文件夾,見4-2-1-1分析
    if (error) {
        kobj_kset_leave(kobj);
        kobject_put(parent);
        kobj->parent = NULL;

        /* be noisy on error issues */
        if (error == -EEXIST)
            printk(KERN_ERR "%s failed for %s with "
                   "-EEXIST, don't try to register things with "
                   "the same name in the same directory.\n",
                   __func__, kobject_name(kobj));
        else
            printk(KERN_ERR "%s failed for %s (%d)\n",
                   __func__, kobject_name(kobj), error);
        dump_stack();
    } else
        kobj->state_in_sysfs = 1;

    return error;
}
這個函數主要設置drvier的kobject和bus之間的層次關系,然后在sysfs中建立該驅動的文件夾
4-1-2-1-1,create_dir()
static int create_dir(struct kobject *kobj)
{
    int error = 0;
    if (kobject_name(kobj)) {
        error = sysfs_create_dir(kobj);  //創建該kobj(driver的)文件夾,見4-2-1-1-1
        if (!error) {
            error = populate_dir(kobj);
            if (error)
                sysfs_remove_dir(kobj);
        }
    }
    return error;
}
4-1-2-1-1-1,sysfs_create_dir
int sysfs_create_dir(struct kobject * kobj)
{
    struct sysfs_dirent *parent_sd, *sd; //sysfs層次結構的基石
    int error = 0;

    BUG_ON(!kobj);

    if (kobj->parent)  //到這步驅動的kobj->parent是bus->p->drivers_kset
        parent_sd = kobj->parent->sd; //bus->p->drivers_kset的目錄
    else
        parent_sd = &sysfs_root; //否則添加到sys的根目錄下,即/sys/

    error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); //在bus->p->drivers_kset的文件夾下創建該驅動的文件夾
    if (!error)
        kobj->sd = sd;
    return error;
}
說到這里,可能一直感覺很空洞,很抽象,拿i2c總線舉個例子吧,i2c總線注冊好后將會有如下文件夾結構/sys/bus/i2c/,在/sys/bus/i2c/文件夾下會有如下文件夾uevent
devices、drivers、drivers_probe、drivers_autoprobe,當你注冊驅動的時候,將會在/sys/bus/i2c/drivers/下注冊一個改驅動的文件夾,比如ov7675,那么它將會注冊成
/sys/bus/i2c/drivers/ov7675/,其實這些文件夾都對應一個kobject,通過kset容器組成一個很清晰的層次結構。經過漫長的過程我們分析完了kobject_init_and_add(),我們下面進入
4-2部分driver_attach進行分析。這也是一個非常重要的函數,好吧,開始我們的又一個漫長之旅吧!

4-2,driver_attach()
定義如下:
int driver_attach(struct device_driver *drv)
{
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
該函數將調用bus_for_each_dev()。
4-2-1,bus_for_each_dev()
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));  //將bus中的已注冊的device列表放到迭代器中,方便索引
    while ((dev = next_device(&i)) && !error)  //將驅動逐個地與列表中每一個的device匹配,可能一個驅動匹配好幾個設備
        error = fn(dev, data);  //這個fn就是上面傳下來的__driver_attach
    klist_iter_exit(&i);
    return error;
}
4-2-1-1,__driver_attach
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))  //跟名字的意思一樣,driver跟device嘗試匹配
        return 0;

    if (dev->parent)    /* Needed for USB */
        down(&dev->parent->sem);
    down(&dev->sem);
    if (!dev->driver)
        driver_probe_device(drv, dev);
    up(&dev->sem);
    if (dev->parent)
        up(&dev->parent->sem);

    return 0;
}
4-2-1-1-1,driver_match_device()
static inline int driver_match_device(struct device_driver *drv,
                      struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
這里看bus的總線的match函數是否已經注冊,如果沒注冊則直接返回1,如果注冊,則調用注冊的匹配函數。同樣,以i2c總線為例吧,
struct bus_type i2c_bus_type = {
    .name        = "i2c",
    .dev_attrs    = i2c_dev_attrs,
    .match        = i2c_device_match,
...
};
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
    struct i2c_client    *client = to_i2c_client(dev);
    struct i2c_driver    *driver = to_i2c_driver(drv);

    /* match on an id table if there is one */
    if (driver->id_table)
        return i2c_match_id(driver->id_table, client) != NULL;//只匹配id的名字和client的名字,跟驅動的名字沒有關系,注意這里的client是設備轉換過來,而不是設備的本身

    return 0;
}
轉而調用i2c_match_id();
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
                        const struct i2c_client *client)
{
    while (id->name[0]) {
        if (strcmp(client->name, id->name) == 0)  //匹配設備client名字和id_table中的名字
            return id;
        id++;
    }
    return NULL;
}
所以i2c總線根據設備client名字和id_table中的名字進行匹配的。如果匹配了,則返回id值,在i2c_device_match中則返回真。也就是bus的match函數將會返回真。那將會進入driver_probe_device()。
4-2-1-1-2,driver_probe_device()
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;

    if (!device_is_registered(dev))  //首先判斷這個device是否已經注冊
        return -ENODEV;

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

    ret = really_probe(dev, drv); //轉而調用really_probe()

    return ret;
}

4-2-1-1-2-1,really_probe()

static atomic_t probe_count = ATOMIC_INIT(0);  //記錄probe數目
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);  //probe隊列

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; //把驅動賦值給dev->drvier
    if (driver_sysfs_add(dev)) {  //主要是添加driver和dev之間的連接文件,見4-2-1-1-2-1-1分析
        printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
            __func__, dev_name(dev));
        goto probe_failed;
    }

    if (dev->bus->probe) {  //如果bus的probe注冊將執行,否則執行driver的probe,這也是函數開始時檢測的原因!
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }

    driver_bound(dev);  //driver綁定dev,見4-2-1-1-2-1-2分析
    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;
}
4-2-1-1-2-1-1,driver_sysfs_add
static int driver_sysfs_add(struct device *dev)
{
    int ret;

    ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
              kobject_name(&dev->kobj)); //在driver目錄下添加以dev->kobj名字的連接文件,連接到device
    if (ret == 0) {
        ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
                    "driver");  //同樣在device目錄下添加‘driver’為名字的連接文件連接到drvier
        if (ret)
            sysfs_remove_link(&dev->driver->p->kobj,
                    kobject_name(&dev->kobj));
    }
    return ret;
}
4-2-1-1-2-1-2,driver_bound()
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);

    if (dev->bus)
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                         BUS_NOTIFY_BOUND_DRIVER, dev);  //調用注冊bus通知鏈上的所有函數

    klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);  //將設備的驅動node添加到diver的klist_devices中.定義同4-3部分
}
4-3,klist_add_tail()
定義如下:
void klist_add_tail(struct klist_node *n, struct klist *k)
{
    klist_node_init(k, n);  //初始化一個klist_node,並將klist聯系起來
    add_tail(k, n);  //將n添加到k的末尾
}

4-4,module_add_driver()

void module_add_driver(struct module *mod, struct device_driver *drv)
{
    char *driver_name;
    int no_warn;
    struct module_kobject *mk = NULL;

    if (!drv)
        return;

    if (mod)  //一般情況下為THIS_MODULE
        mk = &mod->mkobj;
    else if (drv->mod_name) {  //如果沒模塊,則檢查驅動的模塊名
        struct kobject *mkobj;

        /* Lookup built-in module entry in /sys/modules */
        mkobj = kset_find_obj(module_kset, drv->mod_name);  //根據驅動模塊的名字去module_kset集合中找
        if (mkobj) {
            mk = container_of(mkobj, struct module_kobject, kobj);  //用container_of方法通過kobj轉換成module_kobject
            /* remember our module structure */
            drv->p->mkobj = mk;  //賦值給驅動的mkobj
            /* kset_find_obj took a reference */
            kobject_put(mkobj);
        }
    }

    if (!mk)  //mk如果為null則返回
        return;

    /* Don't check return codes; these calls are idempotent */
    no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");  //在驅動文件夾下創建名為‘module’的鏈接文件,鏈接到module文件夾
    driver_name = make_driver_name(drv);  //生成driver_name,給module用,見4-4-1分析
    if (driver_name) {
        module_create_drivers_dir(mk);  //在具體的module文件夾下創建driver目錄
        no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,  //在上面創建的driver目錄下,生成一個名為driver_name指定的鏈接文件,鏈接到驅動的文件夾
                        make_driver_name();
        kfree(driver_name);
    }
}

4-4-1,make_driver_name()
static char *make_driver_name(struct device_driver *drv)
{
    char *driver_name;

    driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
                  GFP_KERNEL);  //申請這么大內存
    if (!driver_name)
        return NULL;

    sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);  //將bus的名字和驅動的名字組成一塊,中間加一個冒號
    return driver_name;
}
這個函數的功能就是生成一個名字,這個有bus和驅動的名字組成

4-5,
在drivers/base/bus.c中driver_attr_uevent,driver_attr_unbind,driver_attr_bind這幾個屬性的定義如下:
static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
在include/linux/device.h中DRIVER_ATTR宏的定義如下:
#define DRIVER_ATTR(_name, _mode, _show, _store)   /
struct driver_attribute driver_attr_##_name =      /
     __ATTR(_name, _mode, _show, _store)
 
由定義可知,這三個屬性文件的_show函數都為null,也就是都不具體讀的功能。
4-5-1,driver_attr_uevent,_store為driver_uevent_store:
static ssize_t driver_uevent_store(struct device_driver *drv,
                      const char *buf, size_t count)
{
     enum kobject_action action;
 
     if (kobject_action_type(buf, count, &action) == 0)  //kobject_action_type就是將buf轉換成action
         kobject_uevent(&drv->p->kobj, action);  //產生一個action的uevent事件,一般通過netlink機制與用戶空間通信,見4-5-1-1分析
     return count;
}
也就是說對drvier目錄下的uevent屬性文件進行寫操作時將會產生一個用戶指定的事件。
4-5-1-1,kobject_uevent()
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
    return kobject_uevent_env(kobj, action, NULL);
}
轉而看kobject_uevent_env():
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
               char *envp_ext[])
{
    struct kobj_uevent_env *env;
    const char *action_string = kobject_actions[action]; //通過數組下標找到對應的字符串
    const char *devpath = NULL;
    const char *subsystem;
    struct kobject *top_kobj;
    struct kset *kset;
    struct kset_uevent_ops *uevent_ops;
    u64 seq;
    int i = 0;
    int retval = 0;

    pr_debug("kobject: '%s' (%p): %s\n",
         kobject_name(kobj), kobj, __func__);

    /* search the kset we belong to */
    top_kobj = kobj;
    while (!top_kobj->kset && top_kobj->parent)
        top_kobj = top_kobj->parent; //通過不斷往前找父kobj,從而得到top kobj

    if (!top_kobj->kset) { //top kobj不能為null
        pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
             "without kset!\n", kobject_name(kobj), kobj,
             __func__);
        return -EINVAL;
    }

    kset = top_kobj->kset;  //找到以后賦值
    uevent_ops = kset->uevent_ops;

    /* skip the event, if uevent_suppress is set*/
    if (kobj->uevent_suppress) {
        pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
                 "caused the event to drop!\n",
                 kobject_name(kobj), kobj, __func__);
        return 0;
    }
    /* skip the event, if the filter returns zero. */
    if (uevent_ops && uevent_ops->filter) //判斷是否要進行的event
        if (!uevent_ops->filter(kset, kobj)) {
            pr_debug("kobject: '%s' (%p): %s: filter function "
                 "caused the event to drop!\n",
                 kobject_name(kobj), kobj, __func__);
            return 0;
        }

    /* originating subsystem */
    if (uevent_ops && uevent_ops->name) //得到subsystem
        subsystem = uevent_ops->name(kset, kobj);
    else
        subsystem = kobject_name(&kset->kobj);
    if (!subsystem) {
        pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
             "event to drop!\n", kobject_name(kobj), kobj,
             __func__);
        return 0;
    }

    /* environment buffer */
    env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);  //申請環境變量buffer
    if (!env)
        return -ENOMEM;

    /* complete object path */
    devpath = kobject_get_path(kobj, GFP_KERNEL);  //得到該kobj的完整路徑
    if (!devpath) {
        retval = -ENOENT;
        goto exit;
    }

    /* default keys */
    retval = add_uevent_var(env, "ACTION=%s", action_string); //將action的字符串添加到buffer中
    if (retval)
        goto exit;
    retval = add_uevent_var(env, "DEVPATH=%s", devpath); //同上
    if (retval)
        goto exit;
    retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); //同上
    if (retval)
        goto exit;

    /* keys passed in from the caller */
    if (envp_ext) { //如果不為空,則也添加到buffer中
        for (i = 0; envp_ext[i]; i++) {
            retval = add_uevent_var(env, "%s", envp_ext[i]);
            if (retval)
                goto exit;
        }
    }

    /* let the kset specific function add its stuff */
    if (uevent_ops && uevent_ops->uevent) {  //該集合的特定要加的東西到buffer中
        retval = uevent_ops->uevent(kset, kobj, env);
        if (retval) {
            pr_debug("kobject: '%s' (%p): %s: uevent() returned "
                 "%d\n", kobject_name(kobj), kobj,
                 __func__, retval);
            goto exit;
        }
    }

    /*
     * Mark "add" and "remove" events in the object to ensure proper
     * events to userspace during automatic cleanup. If the object did
     * send an "add" event, "remove" will automatically generated by
     * the core, if not already done by the caller.
     */
    if (action == KOBJ_ADD)  //標記一下
        kobj->state_add_uevent_sent = 1;
    else if (action == KOBJ_REMOVE)
        kobj->state_remove_uevent_sent = 1;

    /* we will send an event, so request a new sequence number */
    spin_lock(&sequence_lock);
    seq = ++uevent_seqnum;
    spin_unlock(&sequence_lock);
    retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);  //添加新的序列號到buffer中
    if (retval)
        goto exit;

#if defined(CONFIG_NET) //一般情況都定義的,通過netlink機制實現hotplug的
    /* send netlink message */
    if (uevent_sock) {
        struct sk_buff *skb;
        size_t len;

        /* allocate message with the maximum possible size */
        len = strlen(action_string) + strlen(devpath) + 2;
        skb = alloc_skb(len + env->buflen, GFP_KERNEL); //申請skb buffer
        if (skb) {
            char *scratch;

            /* add header */
            scratch = skb_put(skb, len); //將scratch指向skb的tail,且后面有len大小的長度,相當與skb的位置指針,對它的賦值,實質是對skb buffer的賦值
            sprintf(scratch, "%s@%s", action_string, devpath); //將action和路徑添加到scratch

            /* copy keys to our continuous event payload buffer */
            for (i = 0; i < env->envp_idx; i++) {
                len = strlen(env->envp[i]) + 1;
                scratch = skb_put(skb, len);
                strcpy(scratch, env->envp[i]);//將envp[]添加到scratch
            }

            NETLINK_CB(skb).dst_group = 1; //目標組地址
            retval = netlink_broadcast(uevent_sock, skb, 0, 1,  //發送廣播消息
                           GFP_KERNEL);
            /* ENOBUFS should be handled in userspace */
            if (retval == -ENOBUFS)
                retval = 0;
        } else
            retval = -ENOMEM;
    }
#endif

    /* call uevent_helper, usually only enabled during early boot */
    if (uevent_helper[0]) { //從定義看該數組值為"/sbin/hotplug",現在一般udev系統已經沒有這個執行文件了,所以下面一般也不會執行,所以這里不做分析
        char *argv [3];

        argv [0] = uevent_helper;
        argv [1] = (char *)subsystem;
        argv [2] = NULL;
        retval = add_uevent_var(env, "HOME=/");
        if (retval)
            goto exit;
        retval = add_uevent_var(env,
                    "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
        if (retval)
            goto exit;

        retval = call_usermodehelper(argv[0], argv,
                         env->envp, UMH_WAIT_EXEC);
    }

exit:
    kfree(devpath);
    kfree(env);
    return retval;
}

4-5-2,driver_attr_bind屬性對應的寫函數如下:
static ssize_t driver_bind(struct device_driver *drv,
                 const char *buf, size_t count)
{
     struct bus_type *bus = bus_get(drv->bus);
     struct device *dev;
     int err = -ENODEV;
 
     dev = bus_find_device_by_name(bus, NULL, buf); //在bus上尋找buf指定的device
     if (dev && dev->driver == NULL) {
         if (dev->parent)   /* Needed for USB */
              down(&dev->parent->sem);
         down(&dev->sem);
         err = driver_probe_device(drv, dev); //在4-2-1-1-2中我們已經分析了driver_probe_device(),它的作用就是將driver和dev綁定起來,生成一些互相連接文件
         up(&dev->sem);
         if (dev->parent)
              up(&dev->parent->sem);
 
         if (err > 0) {
              /* success */
              err = count;
         } else if (err == 0) {
              /* driver didn't accept device */
              err = -ENODEV;
         }
     }
     put_device(dev);
     bus_put(bus);
     return err;
}
從該函數可以看出,對bind寫入一個device的名字,將會綁定設備和驅動。

4-5-3,driver_attr_unbind,對應的寫函數如下:
static ssize_t driver_unbind(struct device_driver *drv,
                   const char *buf, size_t count)
{
     struct bus_type *bus = bus_get(drv->bus);
     struct device *dev;
     int err = -ENODEV;
 
     dev = bus_find_device_by_name(bus, NULL, buf);  //同樣在bus上尋找buf指定的device
     if (dev && dev->driver == drv) {
         if (dev->parent)   /* Needed for USB */
              down(&dev->parent->sem);
         device_release_driver(dev); //斷開設備和驅動
         if (dev->parent)
              up(&dev->parent->sem);
         err = count;
     }
     put_device(dev);
     bus_put(bus);
     return err;
}
從該函數可以看出,對unbind寫入一個device的名字,將會斷開設備和驅動。

至此,我們已經詳細地分析了driver_register(),下面我們將開始分析device_register().


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM