现在的位置: 首页 > 综合 > 正文

kobject的理解

2013年09月14日 ⁄ 综合 ⁄ 共 20166字 ⁄ 字号 评论关闭

在LINUX中最让人不解的大概就是/sys下面的内容了


下面首先让我们来创建一个简单的platform设备,并从这个设备的视角进行深入,在此篇文章的深入过程中,我们只看kobeject的模型

我所使用的内核版本号为2.6.26,操作系统的内核版本号为2.6.27-7,暂未发现2.6.27-7与2.6.26的重大不同


首先写一个简单的模块


#include <linux/platform_device.h>

#include <linux/init.h>

#include <linux/module.h>


static int __init test_probe(struct platform_device *pdev)

{

        int err = 0;

        return err;

}


static int test_remove(struct platform_device *pdev)

{

        return 0;

}

static struct platform_device test_device = {

        .name = "test_ts",

        .id = -1,

};


static struct platform_driver test_driver = {

        .probe                = test_probe,

        .remove                = test_remove,

        .driver                = {

                .name        = "test_ts",

                .owner        = THIS_MODULE,

        },

};


static int __devinit test_init(void)

{

        platform_device_register(&test_device);        

        return platform_driver_register(&test_driver);

}


static void __exit test_exit(void)

{

        platform_device_unregister(&test_device);

        platform_driver_unregister(&test_driver);

}


module_init(test_init);

module_exit(test_exit);


MODULE_AUTHOR("zwolf");

MODULE_DESCRIPTION("Module test");

MODULE_LICENSE("GPL");

MODULE_ALIAS("test");



接下来是makefile


#Makefile


obj-m:=test.o

KDIR:=/lib/modules/2.6.27-7-generic/build

PWD:=$(shell pwd)


default:

        $(MAKE) -C $(KDIR) M=$(PWD) modules



KDIR中的目录请改为各位实际运行中的内核目录


make之后进行模块的加载 sudo insmod ./test.ko


现在到sys目录中查看我们的设备是否已经加载上了


首先是/sys/bus/platform/devices/


在devices下,每一个连接文件都代表了一个设备


ls可看见test_ts,进入test_ts,ls可发现driver这个链接文件,ls-l查看,发现这个文件是连到/sys/bus/platform/drivers/test_ts的


这里需要说明的是连接的含义,并不是driver驱动存在于test_ts这个设备中,而是test_ts使用的驱动为/sys/bus/platform/drivers/test_ts


现在换到/sys/bus/platform/drivers这个目录下


ls查看会发现这里的文件都为目录,而非连接文件,说明这是驱动真正放置的位置


现在进入test_ts目录,然后ls,发现有一个test_ts的连接文件,ls –l查看可发现该文件连接到/sys/devices/platform/test_ts下


回到/sys/bus/platform/devices/下ls –l也会发现test_ts连接到/sys/devices/platform/test_ts


为什么test_ts这个设备放置于/sys/devices/platform下,而不是/sys/bus/platform/devices下呢


我认为和直观性有关,在sys下有这么几个目录block  bus  class  dev  devices  firmware  kernel  module  fs power 

devices很直观的说明了设备在这个目录下,便于大家查找

而/sys/bus/platform/devices下的连接是为了分类查找


画了张目录图,如下,绿色框的为连接文件,绿色线条为连接的对象
sys_link.png 


题外话:我自身对于这样的分类不是很喜欢,臃肿 重复  而且信息也不好规划,希望在以后的版本能对sys进行大的改造



现在来看另两个图,也就是构成sys的核心kobject,首先第一个是我去掉了连接部分的内容  也就是绿色线条的目录图
sys.png 


第二个是组成这个目录图的核心,kobject图,我也叫他层次图
kobject.png 



不看大号绿色箭头右边的内容的话是不是发现两个架构相同?

对的,kobject的层次决定了目录的结构

kobeject图很大,但也不要担心,里面的内容其实不多,基础框架涉及3个主要结构kset kobject和ktype

在说明test_ts的注册之前,先让我们看一下sys下的两个基础目录bus,devices


首先是bus

bus的注册在/drivers/base/bus.c里

int __init buses_init(void)

{

        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);

        if (!bus_kset)

                return -ENOMEM;

        return 0;

}


先看bus_uevent_ops,这是一个uevent的操作集(我也还没清楚uevent的用途,所以uevent的内容先放着)


然后到kset_create_and_add


struct kset *kset_create_and_add(const char *name,

                                 struct kset_uevent_ops *uevent_ops,

                                 struct kobject *parent_kobj)

//传递进来的参数为("bus", &bus_uevent_ops, NULL)

{

        struct kset *kset;

        int error;


        //创建一个kset容器

        kset = kset_create(name, uevent_ops, parent_kobj);

        if (!kset)

                return NULL;


        //注册创建的kset容器

        error = kset_register(kset);

        if (error) {

                kfree(kset);

                return NULL;

        }

        return kset;

}


首先需要创建一个kset容器

static struct kset *kset_create(const char *name,

                                struct kset_uevent_ops *uevent_ops,

                                struct kobject *parent_kobj)

//传递进来的参数为("bus", &bus_uevent_ops, NULL)

{

        struct kset *kset;


        //为kset分配内存

        kset = kzalloc(sizeof(*kset), GFP_KERNEL);

        if (!kset)

                return NULL;


        //设置kset中kobject的名字,这里为bus

        kobject_set_name(&kset->kobj, name);


        //设置uevent操作集,这里为bus_uevent_ops

        kset->uevent_ops = uevent_ops;


        //设置父对象,这里为NULL

        kset->kobj.parent = parent_kobj;


        //设置容器操作集

        kset->kobj.ktype = &kset_ktype;


        //设置父容器

        kset->kobj.kset = NULL;


        return kset;

}


这里的ktype,也就是kset_ktype是一个操作集,用于为sys下文件的实时反馈做服务,例如我们cat name的时候就要通过ktype提供的show函数,具体什么怎么运用,将在后面讲解


现在回到kset_create_and_add中的kset_register,将建立好的kset添加进sys里


int kset_register(struct kset *k)

{

        int err;


        if (!k)

                return -EINVAL;


        //初始化

        kset_init(k);


        //添加该容器

        err = kobject_add_internal(&k->kobj);

        if (err)

                return err;

        kobject_uevent(&k->kobj, KOBJ_ADD);

        return 0;

}


kset_init进行一些固定的初始化操作,里面没有我们需要关心的内容

kobject_add_internal为重要的一个函数,他对kset里kobj的从属关系进行解析,搭建正确的架构


static int kobject_add_internal(struct kobject *kobj)

{

        int error = 0;

        struct kobject *parent;


        //检测kobj是否为空

        if (!kobj)

                return -ENOENT;


        //检测kobj名字是否为空

        if (!kobj->name || !kobj->name[0]) {

                pr_debug("kobject: (%p): attempted to be registered with empty "

                         "name!\n", kobj);

                WARN_ON(1);

                return -EINVAL;

        }


        //提取父对象

        parent = kobject_get(kobj->parent);


        /* join kset if set, use it as parent if we do not already have one */

        //父容器存在则设置父对象

        if (kobj->kset) {//在bus的kset中为空,所以不会进入到下面的代码


                //检测是否已经设置父对象

                if (!parent)

                        //无则使用父容器为父对象

                        parent = kobject_get(&kobj->kset->kobj);


                //添加该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) : "<NULL>",

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


        //建立相应的目录

        error = create_dir(kobj);


        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;

}


至此bus的目录就建立起来了


模型如下
bus.png 


接下来是devices,在/drivers/base/core.c里


int __init devices_init(void)

{

        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);

        if (!devices_kset)

                return -ENOMEM;

        return 0;

}

过程和bus的注册一致,我就不复述了~

模型如下
devices.png 


然后是platform的注册

在platform的注册中,分为两个部分,一部分是注册到devices中,另一部分是注册到bus中,代码在/drivers/base/platform.c中

int __init platform_bus_init(void)

{

        int error;

        

        //注册到devices目录中

        error = device_register(&platform_bus);

        if (error)

                return error;


        //注册到bus目录中

        error =  bus_register(&platform_bus_type);

        

if (error)

                device_unregister(&platform_bus);

        return error;

}


首先是device_register,注册的参数为platform_bus,如下所示

struct device platform_bus = {

        .bus_id                = "platform",

};

很简单,只有一个参数,表明了目录名


int device_register(struct device *dev)

{

        //初始化dev结构

        device_initialize(dev);

        //添加dev至目录

        return device_add(dev);

}


void device_initialize(struct device *dev)

{

        //重要的一步,指明了父容器为devices_kset,而devices_kset的注册在前面已经介绍过了

        dev->kobj.kset = devices_kset;

        //初始化kobj的ktype为device_ktype

        kobject_init(&dev->kobj, &device_ktype);

        klist_init(&dev->klist_children, klist_children_get,

                   klist_children_put);

        INIT_LIST_HEAD(&dev->dma_pools);

        INIT_LIST_HEAD(&dev->node);

        init_MUTEX(&dev->sem);

        spin_lock_init(&dev->devres_lock);

        INIT_LIST_HEAD(&dev->devres_head);

        device_init_wakeup(dev, 0);

        set_dev_node(dev, -1);

}


int device_add(struct device *dev)

{

        struct device *parent = NULL;

        struct class_interface *class_intf;

        int error;


        dev = get_device(dev);

        if (!dev || !strlen(dev->bus_id)) {

                error = -EINVAL;

                goto Done;

        }


        pr_debug("device: '%s': %s\n", dev->bus_id, __func__);


        parent = get_device(dev->parent);

        setup_parent(dev, parent);


        if (parent)

                set_dev_node(dev, dev_to_node(parent));


        //设置dev->kobj的名字和父对象,并建立相应的目录

        error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);

        if (error)

                goto Error;


        if (platform_notify)

                platform_notify(dev);


        if (dev->bus)

                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,

                                             BUS_NOTIFY_ADD_DEVICE, dev);


        //建立uevent文件

        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;

        }

        //建立subsystem连接文件连接到所属class,这里没有设置class对象所以不会建立

        error = device_add_class_symlinks(dev);

        if (error)

                goto SymlinkError;

        //建立dev的描述文件,这里没有设置描述文件所以不会建立

        error = device_add_attrs(dev);

        if (error)

                goto AttrsError;

        //建立链接文件至所属bus,这里没有设置所属bus所以不会建立

        error = bus_add_device(dev);

        if (error)

                goto BusError;

        //添加power文件,因为platform不属于设备,所以不会建立power文件

        error = device_pm_add(dev);

        if (error)

                goto PMError;

        kobject_uevent(&dev->kobj, KOBJ_ADD);


        //检测驱动中有无适合的设备进行匹配,但没有设置bus,所以不会进行匹配

        bus_attach_device(dev);

        if (parent)

                klist_add_tail(&dev->knode_parent, &parent->klist_children);


        if (dev->class) {

                down(&dev->class->sem);

                list_add_tail(&dev->node, &dev->class->devices);


                list_for_each_entry(class_intf, &dev->class->interfaces, node)

                        if (class_intf->add_dev)

                                class_intf->add_dev(dev, class_intf);

                up(&dev->class->sem);

        }

Done:

        put_device(dev);

        return error;

PMError:

        bus_remove_device(dev);

BusError:

        if (dev->bus)

                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,

                                             BUS_NOTIFY_DEL_DEVICE, dev);

        device_remove_attrs(dev);

AttrsError:

        device_remove_class_symlinks(dev);

SymlinkError:

        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);

        goto Done;

}




在kobject_add-> kobject_add_varg-> kobject_add_internal中


//提取父对象,因为没有设置,所以为空

parent = kobject_get(kobj->parent);


//父容器存在则设置父对象,在前面的dev->kobj.kset = devices_kset中设为了devices_kset

if (kobj->kset) {

//检测是否已经设置父对象

        if (!parent)

                //无则使用父容器为父对象

                parent = kobject_get(&kobj->kset->kobj);

//添加该kobj到父容器的链表中

        kobj_kset_join(kobj);


        //设置父对象

        kobj->parent = parent;

}


现在devices下的platform目录建立好了,模型如下,其中红线描绘了目录关系

platform_devices.png 

现在到bus_register了


注册的参数platform_bus_type如下所示

struct bus_type platform_bus_type = {

        .name                = "platform",

        .dev_attrs        = platform_dev_attrs,

        .match                = platform_match,

        .uevent                = platform_uevent,

        .suspend                = platform_suspend,

        .suspend_late        = platform_suspend_late,

        .resume_early        = platform_resume_early,

        .resume                = platform_resume,

};



int bus_register(struct bus_type *bus)

{

        int retval;


        //声明一个总线私有数据并分配空间

        struct bus_type_private *priv;

        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);

        if (!priv)

                return -ENOMEM;


        //互相关联

        priv->bus = bus;

        bus->p = priv;


        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);


        //设置私有数据中kobj对象的名字

        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);

        if (retval)

                goto out;


        //设置父容器为bus_kset,操作集为bus_ktype

        priv->subsys.kobj.kset = bus_kset;

        priv->subsys.kobj.ktype = &bus_ktype;

        priv->drivers_autoprobe = 1;


        //注册bus容器

        retval = kset_register(&priv->subsys);

        if (retval)

                goto out;


        //建立uevent属性文件

        retval = bus_create_file(bus, &bus_attr_uevent);

        if (retval)

                goto bus_uevent_fail;


        //建立devices目录

        priv->devices_kset = kset_create_and_add("devices", NULL,

                                                 &priv->subsys.kobj);

        if (!priv->devices_kset) {

                retval = -ENOMEM;

                goto bus_devices_fail;

        }


        //建立drivers目录

        priv->drivers_kset = kset_create_and_add("drivers", NULL,

                                                 &priv->subsys.kobj);

        if (!priv->drivers_kset) {

                retval = -ENOMEM;

                goto bus_drivers_fail;

        }


        //初始化klist_devices和klist_drivers链表

        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);

        klist_init(&priv->klist_drivers, NULL, NULL);


        //增加probe属性文件

        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);

        kfree(bus->p);

out:

        return retval;

}


在kset_register-> kobject_add_internal中


//提取父对象,因为没有设置父对象,所以为空

parent = kobject_get(kobj->parent);


//父容器存在则设置父对象,在上文中设置了父容器priv->subsys.kobj.kset = bus_kset

if (kobj->kset) {


        //检测是否已经设置父对象

        if (!parent)

                //无则使用父容器为父对象

                parent = kobject_get(&kobj->kset->kobj);


        //添加该kobj到父容器的链表中

        kobj_kset_join(kobj);


        //设置父对象

        kobj->parent = parent;

}


在retval = kset_register(&priv->subsys)完成之后platform在bus下的模型如下图

platform_bus.png 


有印象的话大家还记得在platform下面有两个目录devices和drivers吧~

现在就到这两个目录的注册了

priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);

priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);

注意这两条语句的头部

priv->devices_kset = kset_create_and_add

priv->drivers_kset = kset_create_and_add

可以清楚的看到bus_type_private下的devices_kset, drivers_kset分别连接到了devices,drivers的kset上


现在来看kset_create_and_add("devices", NULL,&priv->subsys.kobj);

struct kset *kset_create_and_add(const char *name,

                                 struct kset_uevent_ops *uevent_ops,

                                 struct kobject *parent_kobj)

//参数为"devices", NULL,&priv->subsys.kobj

{

        struct kset *kset;

        int error;


        //创建一个kset容器

        kset = kset_create(name, uevent_ops, parent_kobj);

        if (!kset)

                return NULL;


        //注册创建的kset容器

        error = kset_register(kset);

        if (error) {

                kfree(kset);

                return NULL;

        }

        return kset;

}

在kset_create 中比较重要的操作为

kset->kobj.ktype = &kset_ktype //设置了ktype,为kset_ktype

kset->kobj.parent = parent_kobj; //设置了父对象,为priv->subsys.kobj,也就是platform_bus_type->p->subsys.kobj

kset->kobj.kset = NULL;    //设置父容器为空

在kset_register中


//提取父对象

parent = kobject_get(kobj->parent); //在之前设置为了


//父容器存在则设置父对象,由于父容器为空,不执行以下代码

if (kobj->kset) {


        //检测是否已经设置父对象

        if (!parent)

                //无则使用父容器为父对象

                parent = kobject_get(&kobj->kset->kobj);


        //添加该kobj到父容器的链表中

        kobj_kset_join(kobj);


        //设置父对象

        kobj->parent = parent;

}


至此, devices的模型就建立好了,drivers模型的建立和devices是一致的,只是名字不同而已,我就不复述了,建立好的模型如下

platform_devices_drivers.png 


好了~  到了这里,bus,devices和platform的基础模型就就建立好了,就等设备来注册了

在platform模型设备的建立中,需要2个部分的注册,驱动的注册和设备的注册

platform_device_register(&test_device);        

platform_driver_register(&test_driver);

首先看platform_device_register

注册参数为test_device,结构如下

static struct platform_device test_device = {

        .name = "test_ts",

        .id = -1,

        //. resource

        //.dev

};

这个结构主要描述了设备的名字,ID和资源和私有数据,其中资源和私有数据我们在这里不使用,将在别的文章中进行讲解


int platform_device_register(struct platform_device *pdev)

{

        //设备属性的初始化

        device_initialize(&pdev->dev);

        //将设备添加进platform里

        return platform_device_add(pdev);

}


void device_initialize(struct device *dev)

{

        dev->kobj.kset = devices_kset;                   //设置kset为devices_kset,则将设备挂接上了devices目录

        kobject_init(&dev->kobj, &device_ktype);                    //初始化kobeject,置ktype为device_ktype

        klist_init(&dev->klist_children, klist_children_get,

                   klist_children_put);

        INIT_LIST_HEAD(&dev->dma_pools);

        INIT_LIST_HEAD(&dev->node);

        init_MUTEX(&dev->sem);

        spin_lock_init(&dev->devres_lock);

        INIT_LIST_HEAD(&dev->devres_head);

        device_init_wakeup(dev, 0);

        set_dev_node(dev, -1);

}


int platform_device_add(struct platform_device *pdev)

{

        int i, ret = 0;


        if (!pdev)

                return -EINVAL;


        //检测是否设置了dev中的parent,无则赋为platform_bus

        if (!pdev->dev.parent)

                pdev->dev.parent = &platform_bus;


        //设置dev中的bus为platform_bus_type

        pdev->dev.bus = &platform_bus_type;


        //检测id,id为-1表明该设备只有一个,用设备名为bus_id

        //不为1则表明该设备有数个,需要用序号标明bus_id

        if (pdev->id != -1)

                snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,

                         pdev->id);

        else

                strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);


        //增加资源到资源树中

        for (i = 0; i < pdev->num_resources; i++) {

                struct resource *p, *r = &pdev->resource;


                if (r->name == NULL)

                        r->name = pdev->dev.bus_id;


                p = r->parent;

                if (!p) {

                        if (r->flags & IORESOURCE_MEM)

                                p = &iomem_resource;

                        else if (r->flags & IORESOURCE_IO)

                                p = &ioport_resource;

                }


                if (p && insert_resource(p, r)) {

                        printk(KERN_ERR "%s: failed to claim resource %d\n",pdev->dev.bus_id, i);

                        ret = -EBUSY;

                        goto failed;

                }

        }


        pr_debug("Registering platform device '%s'. Parent at %s\n",pdev->dev.bus_id, pdev->dev.parent->bus_id);


        //添加设备到设备层次中

        ret = device_add(&pdev->dev);

        if (ret == 0)

                return ret;


failed:

        while (--i >= 0)

                if (pdev->resource.flags & (IORESOURCE_MEM|IORESOURCE_IO))

                        release_resource(&pdev->resource);

        return ret;

}




int device_add(struct device *dev)

{

        struct device *parent = NULL;

        struct class_interface *class_intf;

        int error;


        dev = get_device(dev);

        if (!dev || !strlen(dev->bus_id)) {

                error = -EINVAL;

                goto Done;

        }


        pr_debug("device: '%s': %s\n", dev->bus_id, __func__);


        //取得上层device,而dev->parent的赋值是在platform_device_add中的pdev->dev.parent = &platform_bus完成的

        parent = get_device(dev->parent);


        //以上层devices为准重设dev->kobj.parent

        setup_parent(dev, parent);


        if (parent)

                set_dev_node(dev, dev_to_node(parent));


        //设置dev->kobj的名字和父对象,并建立相应目录

        error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);

        if (error)

                goto Error;


        if (platform_notify)

                platform_notify(dev);


        //一种新型的通知机制,但是platform中没有设置相应的结构,所以在这里跳过

        /* notify clients of device entry (new way) */

        if (dev->bus)

                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);


        //建立uevent文件

        error = device_create_file(dev, &uevent_attr);

        if (error)

                goto attrError;


        //设备有设备号则建立dev文件

        if (MAJOR(dev->devt)) {

                error = device_create_file(dev, &devt_attr);

                if (error)

                        goto ueventattrError;

        }

        //建立subsystem连接文件连接到所属class

        error = device_add_class_symlinks(dev);

        if (error)

                goto SymlinkError;

        //添加dev的描述文件

        error = device_add_attrs(dev);

        if (error)

                goto AttrsError;

        //添加链接文件至所属bus

        error = bus_add_device(dev);

        if (error)

                goto BusError;

        //添加power文件

        error = device_pm_add(dev);

        if (error)

                goto PMError;

        kobject_uevent(&dev->kobj, KOBJ_ADD);


        //检测驱动中有无适合的设备进行匹配,现在只添加了设备,还没有加载驱动,所以不会进行匹配

        bus_attach_device(dev);

        if (parent)

                klist_add_tail(&dev->knode_parent, &parent->klist_children);


        if (dev->class) {

                down(&dev->class->sem);

                list_add_tail(&dev->node, &dev->class->devices);


                list_for_each_entry(class_intf, &dev->class->interfaces, node)

                        if (class_intf->add_dev)

                                class_intf->add_dev(dev, class_intf);

                up(&dev->class->sem);

        }

Done:

        put_device(dev);

        return error;

PMError:

        bus_remove_device(dev);

BusError:

        if (dev->bus)

                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);

        device_remove_attrs(dev);

AttrsError:

        device_remove_class_symlinks(dev);

SymlinkError:

        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);

        goto Done;

}


static void setup_parent(struct device *dev, struct device *parent)

{

        struct kobject *kobj;

        //取得上层device的kobj

        kobj = get_device_parent(dev, parent);

        //kobj不为空则重设dev->kobj.parent

        if (kobj)

                dev->kobj.parent = kobj;

}



static struct kobject *get_device_parent(struct device *dev,

                                         struct device *parent)

{

        int retval;


        //因为dev->class为空,所以跳过这段代码

        if (dev->class) {

                struct kobject *kobj = NULL;

                struct kobject *parent_kobj;

                struct kobject *k;


                if (parent == NULL)

                        parent_kobj = virtual_device_parent(dev);

                else if (parent->class)

                        return &parent->kobj;

                else

                        parent_kobj = &parent->kobj;


                spin_lock(&dev->class->class_dirs.list_lock);

                list_for_each_entry(k, &dev->class->class_dirs.list, entry)

                        if (k-&

抱歉!评论已关闭.