您的位置:首页 > 运维架构 > Linux

我对linux理解之driver_register

2013-02-26 08:17 344 查看
/**

* 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) : "<NULL>",

kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");

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().
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: