本文共 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/