Chinaunix首页 | 论坛 | 博客
  • 博客访问: 746946
  • 博文数量: 370
  • 博客积分: 2334
  • 博客等级: 大尉
  • 技术积分: 3222
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-06 16:56
文章分类

全部博文(370)

文章存档

2013年(2)

2012年(368)

分类: LINUX

2012-05-23 23:25:20

总线相关的操作

注册

int bus_register(struct bus_type *bus)
{
        int retval;
        struct subsys_private *priv;
 
        priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        priv->bus = bus;
        bus->p = priv;
 
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
 
        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
        if (retval)
                goto out;
 
        priv->subsys.kobj.kset = bus_kset;
        priv->subsys.kobj.ktype = &bus_ktype;
        priv->drivers_autoprobe = 1;
 
        retval = kset_register(&priv->subsys);
        if (retval)
                goto out;
 
        retval = bus_create_file(bus, &bus_attr_uevent);
        if (retval)
                goto bus_uevent_fail;
 
        priv->devices_kset = kset_create_and_add("devices", NULL,
                                                 &priv->subsys.kobj);
        if (!priv->devices_kset) {
                retval = -ENOMEM;
                goto bus_devices_fail;
        }
 
        priv->drivers_kset = kset_create_and_add("drivers", NULL,
                                                 &priv->subsys.kobj);
        if (!priv->drivers_kset) {
                retval = -ENOMEM;
                goto bus_drivers_fail;
        }
 
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
        klist_init(&priv->klist_drivers, NULL, NULL);
 
        retval = add_probe_files(bus);
        if (retval)
                goto bus_probe_files_fail;
 
        retval = bus_add_attrs(bus);
        if (retval)
                goto bus_attrs_fail;
 
        pr_debug("bus: '%s': registered\n", bus->name);
        return 0;
 
bus_attrs_fail:
        remove_probe_files(bus);
bus_probe_files_fail:
        kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
        kset_unregister(bus->p->devices_kset);
bus_devices_fail:
        bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
        kset_unregister(&bus->p->subsys);
out:
        kfree(bus->p);
        bus->p = NULL;
        return retval;
}
EXPORT_SYMBOL_GPL(bus_register);

此函数包括如下几项工作:

1、首先会动态创建一个subsys_private结构体priv,并且设置priv与bus之间的映射关系。然后会阻塞notifier。紧接 着会初始化priv->subsys.kobj,其中包括设置名称、其属于bus_kset以及类型为bus_ktype,接着就会注册此 kset(关于kset_register参见前文)。紧接着会在sysfs文件系统中创建响应的目录以及文件。

2、接下来,就会创建两个kset,一个用于组织本总线上的设备对应的kobject,另一个用于组织本总线上的驱动对应的kobject。如果成功,就会创建两个klist用于组织设备和驱动的相关信息。

3、最后,就是根据默认属性在sysfs文件系统中创建相关的文件。

注销

void bus_unregister(struct bus_type *bus)
{
        pr_debug("bus: '%s': unregistering\n", bus->name);
        bus_remove_attrs(bus);
        remove_probe_files(bus);
        kset_unregister(bus->p->drivers_kset);
        kset_unregister(bus->p->devices_kset);
        bus_remove_file(bus, &bus_attr_uevent);
        kset_unregister(&bus->p->subsys);
        kfree(bus->p);
        bus->p = NULL;
}

和注册完全相反的过程。

驱动

注册

int driver_register(struct device_driver *drv)
{
        int ret;
        struct device_driver *other;
 
        BUG_ON(!drv->bus->p);
 
        if ((drv->bus->probe && drv->probe) ||
            (drv->bus->remove && drv->remove) ||
            (drv->bus->shutdown && drv->shutdown))
                printk(KERN_WARNING "Driver '%s' needs updating - please use "
                        "bus_type methods\n", drv->name);
 
        other = driver_find(drv->name, drv->bus);
        if (other) {
                put_driver(other);
                printk(KERN_ERR "Error: Driver '%s' is already registered, "
                        "aborting...\n", drv->name);
                return -EBUSY;
        }
 
        ret = bus_add_driver(drv);
        if (ret)
                return ret;
        ret = driver_add_groups(drv, drv->groups);
        if (ret)
                bus_remove_driver(drv);
        return ret;
}
EXPORT_SYMBOL_GPL(driver_register);

其实这个函数绝大部分工作都推到了函数bus_add_driver中(添加设备也是这种做法),在调用这个函数前只是简单的验证了一下该驱动是否已经注册过了。

int bus_add_driver(struct device_driver *drv)
{
        struct bus_type *bus;
        struct driver_private *priv;
        int error = 0;
 
        bus = bus_get(drv->bus);
        if (!bus)
                return -EINVAL;
 
        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                error = -ENOMEM;
                goto out_put_bus;
        }
        klist_init(&priv->klist_devices, NULL, NULL);
        priv->driver = drv;
        drv->p = priv;
        priv->kobj.kset = bus->p->drivers_kset;
        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                                     "%s", drv->name);
        if (error)
                goto out_unregister;
 
        if (drv->bus->p->drivers_autoprobe) {
                error = driver_attach(drv);
                if (error)
                        goto out_unregister;
        }
        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
        module_add_driver(drv->owner, drv);
 
        error = driver_create_file(drv, &driver_attr_uevent);
        if (error) {
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",
                        __func__, drv->name);
        }
        error = driver_add_attrs(bus, drv);
        if (error) {
                /* How the hell do we get out of this pickle? Give up */
                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
                        __func__, drv->name);
        }
 
        if (!drv->suppress_bind_attrs) {
                error = add_bind_files(drv);
                if (error) {
                        /* Ditto */
                        printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
                                __func__, drv->name);
                }
        }
 
        kobject_uevent(&priv->kobj, KOBJ_ADD);
        return 0;
 
out_unregister:
        kobject_put(&priv->kobj);
        kfree(drv->p);
        drv->p = NULL;
out_put_bus:
        bus_put(bus);
        return error;
}

这个函数在为驱动的私有数据分配了存储空间后,就会设置驱动模型中的核心结构,包括父节点、所属kset,以及初始化私有数据内嵌的kobject等。同时会将自己加入到所属总线的所有驱动构成的链表之中。

紧接着就会做sysfs相关的操作,包括创建对应的目录,属性文件等,同时会想用户空间发送uevent事件。

注销

和注册相反的过程

设备

注册

int device_register(struct device *dev)
{
        device_initialize(dev);
        return device_add(dev);
}
 
 
void device_initialize(struct device *dev)
{
        dev->kobj.kset = devices_kset;
        kobject_init(&dev->kobj, &device_ktype);
        INIT_LIST_HEAD(&dev->dma_pools);
        mutex_init(&dev->mutex);
        lockdep_set_novalidate_class(&dev->mutex);
        spin_lock_init(&dev->devres_lock);
        INIT_LIST_HEAD(&dev->devres_head);
        device_pm_init(dev);
        set_dev_node(dev, -1);
}
 
int device_add(struct device *dev)
{
        struct device *parent = NULL;
        struct class_interface *class_intf;
        int error = -EINVAL;
 
        dev = get_device(dev);
        if (!dev)
                goto done;
 
        if (!dev->p) {
                error = device_private_init(dev);
                if (error)
                        goto done;
        }
 
        /*
         * for statically allocated devices, which should all be converted
         * some day, we need to initialize the name. We prevent reading back
         * the name, and force the use of dev_name()
         */
        if (dev->init_name) {
                dev_set_name(dev, "%s", dev->init_name);
                dev->init_name = NULL;
        }
 
        if (!dev_name(dev)) {
                error = -EINVAL;
                goto name_error;
        }
 
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
 
        parent = get_device(dev->parent);
        setup_parent(dev, parent);
 
        /* use parent numa_node */
        if (parent)
                set_dev_node(dev, dev_to_node(parent));
 
        /* first, register with generic layer. */
        /* we require the name to be set before, and pass NULL */
        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
        if (error)
                goto Error;
 
        /* notify platform of device entry */
        if (platform_notify)
                platform_notify(dev);
 
        error = device_create_file(dev, &uevent_attr);
        if (error)
                goto attrError;
 
        if (MAJOR(dev->devt)) {
                error = device_create_file(dev, &devt_attr);
                if (error)
                        goto ueventattrError;
 
                error = device_create_sys_dev_entry(dev);
                if (error)
                        goto devtattrError;
 
                devtmpfs_create_node(dev);
        }
 
        error = device_add_class_symlinks(dev);
        if (error)
                goto SymlinkError;
        error = device_add_attrs(dev);
        if (error)
                goto AttrsError;
        error = bus_add_device(dev);
        if (error)
                goto BusError;
        error = dpm_sysfs_add(dev);
        if (error)
                goto DPMError;
        device_pm_add(dev);
 
        /* Notify clients of device addition.  This call must come
         * after dpm_sysf_add() and before kobject_uevent().
         */
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_ADD_DEVICE, dev);
 
        kobject_uevent(&dev->kobj, KOBJ_ADD);
        bus_probe_device(dev);
        if (parent)
                klist_add_tail(&dev->p->knode_parent,
                               &parent->p->klist_children);
 
        if (dev->class) {
                mutex_lock(&dev->class->p->class_mutex);
                /* tie the class to the device */
                klist_add_tail(&dev->knode_class,
                               &dev->class->p->klist_devices);
 
                /* notify any interfaces that the device is here */
                list_for_each_entry(class_intf,
                                   &dev->class->p->class_interfaces, node)
                        if (class_intf->add_dev)
                                class_intf->add_dev(dev, class_intf);
                mutex_unlock(&dev->class->p->class_mutex);
        }
done:
        put_device(dev);
        return error;
DPMError:
        bus_remove_device(dev);
 
BusError:
        device_remove_attrs(dev);
AttrsError:
        device_remove_class_symlinks(dev);
SymlinkError:
        if (MAJOR(dev->devt))
                devtmpfs_delete_node(dev);
        if (MAJOR(dev->devt))
                device_remove_sys_dev_entry(dev);
devtattrError:
       if (MAJOR(dev->devt))
               device_remove_file(dev, &devt_attr);
ueventattrError:
       device_remove_file(dev, &uevent_attr);
attrError:
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
        kobject_del(&dev->kobj);
Error:
        cleanup_device_parent(dev);
        if (parent)
                put_device(parent);
name_error:
        kfree(dev->p);
        dev->p = NULL;
        goto done;
}

1、首先初始化dev内嵌的kobject结构体,同时对内部的各种链表、互斥量惊醒初始化。

2、然后就会添加设备。首先会初始化设备私有数据device_private。然后会更新其名称(按照注释,以后所有的设备结构都会动态创建,不会有静态数据)。然后会在sysfs文件系统中创建相应的目录、文件。

int bus_add_device(struct device *dev)
{
        struct bus_type *bus = bus_get(dev->bus);
        int error = 0;
 
        if (bus) {
                pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
                error = device_add_attrs(bus, dev);
                if (error)
                        goto out_put;
                error = sysfs_create_link(&bus->p->devices_kset->kobj,
                                                &dev->kobj, dev_name(dev));
                if (error)
                        goto out_id;
                error = sysfs_create_link(&dev->kobj,
                                &dev->bus->p->subsys.kobj, "subsystem");
                if (error)
                        goto out_subsys;
                klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
        }
        return 0;
 
out_subsys:
        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_id:
        device_remove_attrs(bus, dev);
out_put:
        bus_put(dev->bus);
        return error;
}

3、紧接着会调用bus_add_device、bus_probe_device进行总线、设备、驱动三者之间的匹配、设置。

4、最后一步就是向用户空间发送uevent事件,设置设备类的关系。

注销

和注册相反的过程

阅读(1455) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~