博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
driver_register 理解
阅读量:4225 次
发布时间:2019-05-26

本文共 23007 字,大约阅读时间需要 76 分钟。

我们首先来完整地看下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定义如下:
#defineBUG_ON(condition) do { if (unlikely(condition)) BUG(); }while(0)
其中的BUG():
#defineBUG() 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等概念了。这里为了分析的连贯性就不再插入相关概念。
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){      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){      printk(KERN_ERR "%s: add_bind_files(%s)failed\n",         __func__, drv->name);    }    kobject_uevent(&priv->kobj,KOBJ_ADD);  //产生一个KOBJ_ADD uevent    return0;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_listargs;    intretval;    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 nameproperly!\n");      return retval;    }    kobj->parent = parent; //由上面的函数调用关系可以知道这个将被赋值为NULL    return kobject_add_internal(kobj);  //见4-1-2-1}
4-1-2-1 kobject_add_internal()

static int kobject_add_internal(struct kobject *kobj){...    parent =kobject_get(kobj->parent); //得到父节点,从上面知道parent是NULL        if(kobj->kset) { //kset不为空       if (!parent) //parent为空         parent =kobject_get(&kobj->kset->kobj);      kobj_kset_join(kobj);      kobj->parent = parent;     }    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-1-2-1-1分析    if (error){      kobj_kset_leave(kobj);      kobject_put(parent);      kobj->parent = NULL;            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-1-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;        if(!driver_match_device(drv, dev)) //跟名字的意思一样,driver跟device尝试匹配       return 0;    if(dev->parent)          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, structdevice_driver *drv){    structi2c_client   *client = to_i2c_client(dev);    structi2c_driver   *driver = to_i2c_driver(drv);        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 structi2c_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 withdriver %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 withdevice %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 todriver %s\n",       drv->bus->name, __func__, dev_name(dev),drv->name);   gotodone;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_name(dev), ret);    }        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){    intret;    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 alreadybound\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;    intno_warn;    structmodule_kobject *mk = NULL;    if(!drv)      return;    if(mod)  //一般情况下为THIS_MODULE      mk = &mod->mkobj;    else if(drv->mod_name) {  //如果没模块,则检查驱动的模块名      struct kobject *mkobj;            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                  drv->p->mkobj = mk; //赋值给驱动的mkobj                  kobject_put(mkobj);      }    }    if(!mk)  //mk如果为null则返回      return;        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_actionaction){    returnkobject_uevent_env(kobj, action, NULL);}
转而看kobject_uevent_env():
int kobject_uevent_env(struct kobject *kobj, enum kobject_actionaction,            char *envp_ext[]){    structkobj_uevent_env *env;    const char*action_string = kobject_actions[action];//通过数组下标找到对应的字符串    const char*devpath = NULL;    const char*subsystem;    structkobject *top_kobj;    struct kset*kset;    structkset_uevent_ops *uevent_ops;    u64seq;    int i =0;    int retval =0;   pr_debug("kobject: '%s' (%p): %s\n",       kobject_name(kobj), kobj, __func__);        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 tosend uevent "          "without kset!\n", kobject_name(kobj),kobj,          __func__);      return -EINVAL;    }    kset =top_kobj->kset;  //找到以后赋值    uevent_ops =kset->uevent_ops;        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;    }        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;      }        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 subsystemcaused the "          "event to drop!\n", kobject_name(kobj),kobj,          __func__);      return 0;    }        env =kzalloc(sizeof(struct kobj_uevent_env),GFP_KERNEL);  //申请环境变量buffer    if(!env)      return -ENOMEM;        devpath =kobject_get_path(kobj, GFP_KERNEL); //得到该kobj的完整路径    if(!devpath) {      retval = -ENOENT;      goto exit;    }        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;        if(envp_ext) { //如果不为空,则也添加到buffer中      for (i = 0; envp_ext[i]; i++) {         retval = add_uevent_var(env, "%s",envp_ext[i]);         if (retval)            goto exit;      }    }        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;      }    }        if (action== KOBJ_ADD)  //标记一下      kobj->state_add_uevent_sent = 1;    else if(action == KOBJ_REMOVE)      kobj->state_remove_uevent_sent = 1;       spin_lock(&sequence_lock);    seq =++uevent_seqnum;   spin_unlock(&sequence_lock);    retval =add_uevent_var(env, "SEQNUM=%llu", (unsigned longlong)seq);  //添加新的序列号到buffer中    if(retval)      goto exit;#if defined(CONFIG_NET) //一般情况都定义的,通过netlink机制实现hotplug的        if(uevent_sock) {      struct sk_buff *skb;      size_t len;            len = strlen(action_string) + strlen(devpath) +2;      skb = alloc_skb(len + env->buflen,GFP_KERNEL); //申请skb buffer      if (skb) {         char *scratch;                  scratch = skb_put(skb, len);//将scratch指向skb的tail,且后面有len大小的长度,相当与skb的位置指针,对它的赋值,实质是对skbbuffer的赋值         sprintf(scratch, "%s@%s", action_string,devpath); //将action和路径添加到scratch                  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);                  if (retval == -ENOBUFS)            retval = 0;      } else         retval = -ENOMEM;    }#endif        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)               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) {                          err = count;        } else if (err == 0) {                          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)               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().

转载地址:http://gqbqi.baihongyu.com/

你可能感兴趣的文章
PDF转Word完全免费?这么好的事情我怎么不知道????
查看>>
数据解读---B站火过蔡徐坤的“鬼畜“区巨头们
查看>>
Squid代理服务器搭建亿级爬虫IP代理池
查看>>
JupyterNotebook‘s Magic
查看>>
在Linux 上部署Jenkins和项目
查看>>
Python+requests+unittest+excel实现接口自动化测试框架
查看>>
那些年我们听过的互联网公司的套路?
查看>>
谈谈python里面那些高级函数
查看>>
40行代码带你免费看《海贼王-和之国》篇章
查看>>
搭建炫酷的服务器监控平台
查看>>
垃圾分类:人机搭配,干活不累
查看>>
Nginx
查看>>
Memcached,session共享
查看>>
Tomcat,varnish
查看>>
SVN, 制作RPM包
查看>>
HTML 标签说明
查看>>
CSS 基本语法
查看>>
Nginx 常见异常
查看>>
10.shell基础
查看>>
加密与解密、抓包扫描
查看>>