亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標題: 個人對kobject的一點研究 [打印本頁]

作者: superfight    時間: 2009-01-19 01:27
標題: 個人對kobject的一點研究
在LINUX中最讓人不解的大概就是/sys下面的內容了

下面首先讓我們來創(chuàng)建一個簡單的platform設備,并從這個設備的視角進行深入,在此篇文章的深入過程中,我們只看kobeject的模型
我所使用的內核版本號為2.6.26,操作系統(tǒng)的內核版本號為2.6.27-7,暫未發(fā)現(xiàn)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

現(xiàn)在到sys目錄中查看我們的設備是否已經加載上了

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

在devices下,每一個連接文件都代表了一個設備

ls可看見test_ts,進入test_ts,ls可發(fā)現(xiàn)driver這個鏈接文件,ls-l查看,發(fā)現(xiàn)這個文件是連到/sys/bus/platform/drivers/test_ts的

這里需要說明的是連接的含義,并不是driver驅動存在于test_ts這個設備中,而是test_ts使用的驅動為/sys/bus/platform/drivers/test_ts

現(xiàn)在換到/sys/bus/platform/drivers這個目錄下

ls查看會發(fā)現(xiàn)這里的文件都為目錄,而非連接文件,說明這是驅動真正放置的位置

現(xiàn)在進入test_ts目錄,然后ls,發(fā)現(xiàn)有一個test_ts的連接文件,ls –l查看可發(fā)現(xiàn)該文件連接到/sys/devices/platform/test_ts下

回到/sys/bus/platform/devices/下ls –l也會發(fā)現(xiàn)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下的連接是為了分類查找

畫了張目錄圖,如下,綠色框的為連接文件,綠色線條為連接的對象


題外話:我自身對于這樣的分類不是很喜歡,臃腫 重復  而且信息也不好規(guī)劃,希望在以后的版本能對sys進行大的改造


現(xiàn)在來看另兩個圖,也就是構成sys的核心kobject,首先第一個是我去掉了連接部分的內容  也就是綠色線條的目錄圖


第二個是組成這個目錄圖的核心,kobject圖,我也叫他層次圖



不看大號綠色箭頭右邊的內容的話是不是發(fā)現(xiàn)兩個架構相同?
對的,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;

        //創(chuàng)建一個kset容器
        kset = kset_create(name, uevent_ops, parent_kobj);
        if (!kset)
                return NULL;

        //注冊創(chuàng)建的kset容器
        error = kset_register(kset);
        if (error) {
                kfree(kset);
                return NULL;
        }
        return kset;
}

首先需要創(chuàng)建一個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函數,具體什么怎么運用,將在后面講解

現(xiàn)在回到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的目錄就建立起來了

模型如下


接下來是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的注冊一致,我就不復述了~
模型如下


然后是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;
}

現(xiàn)在devices下的platform目錄建立好了,模型如下,其中紅線描繪了目錄關系


[ 本帖最后由 superfight 于 2009-2-3 15:45 編輯 ]
作者: superfight    時間: 2009-01-19 01:28
現(xiàn)在到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;

        //互相關聯(lián)
        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下面有兩個目錄devices和drivers吧~
現(xiàn)在就到這兩個目錄的注冊了
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上

現(xiàn)在來看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;

        //創(chuàng)建一個kset容器
        kset = kset_create(name, uevent_ops, parent_kobj);
        if (!kset)
                return NULL;

        //注冊創(chuàng)建的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); //在之前設置為了

//父容器存在則設置父對象,由于父容器為空,不執(zhí)行以下代碼
if (kobj->kset) {

        //檢測是否已經設置父對象
        if (!parent)
                //無則使用父容器為父對象
                parent = kobject_get(&kobj->kset->kobj);

        //添加該kobj到父容器的鏈表中
        kobj_kset_join(kobj);

        //設置父對象
        kobj->parent = parent;
}

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



好了~  到了這里,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);

        //檢測驅動中有無適合的設備進行匹配,現(xiàn)在只添加了設備,還沒有加載驅動,所以不會進行匹配
        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->parent == parent_kobj) {
                                kobj = kobject_get(k);
                                break;
                        }
                spin_unlock(&dev->class->class_dirs.list_lock);
                if (kobj)
                        return kobj;

                k = kobject_create();
                if (!k)
                        return NULL;
                k->kset = &dev->class->class_dirs;
                retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
                if (retval < 0) {
                        kobject_put(k);
                        return NULL;
                }
                return k;
        }

        if (parent)
                //返回上層device的kobj
                return &parent->kobj;
        return NULL;
}

在bus_attach_device中雖然沒有成功進行匹配,但是有很重要的一步為之后正確的匹配打下基礎
void bus_attach_device(struct device *dev)
{
        struct bus_type *bus = dev->bus;
        int ret = 0;

        if (bus) {
                if (bus->p->drivers_autoprobe)
                        ret = device_attach(dev);
                WARN_ON(ret < 0);
                if (ret >= 0)
                        klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
        }
}

klist_add_tail(&dev->knode_bus, &bus->p->klist_devices)就是這一行
在這一行代碼中將設備掛載到了bus下的devices鏈表下,這樣,當驅動請求匹配的時候,platform總線就會歷遍devices鏈表為驅動尋找合適的設備


現(xiàn)在來看一下test_device的模型



然后platform_driver_unregister,他的參數 test_driver的結構如下
static struct platform_driver test_driver = {
        .probe                = test_probe,
        .remove                = test_remove,
        .driver                = {
                .name        = "test_ts",
                .owner        = THIS_MODULE,
        },
};

int platform_driver_register(struct platform_driver *drv)
{
        drv->driver.bus = &platform_bus_type;
        if (drv->probe)
                drv->driver.probe = platform_drv_probe;
        if (drv->remove)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;
        if (drv->suspend)
                drv->driver.suspend = platform_drv_suspend;
        if (drv->resume)
                drv->driver.resume = platform_drv_resume;
        return driver_register(&drv->driver);
}

從上面代碼可以看出,在platform_driver中設置了probe, remove, shutdown, suspend或resume函數的話
則drv->driver也會設置成platform對應的函數

int driver_register(struct device_driver *drv)
{
        int ret;
        struct device_driver *other;
        
        //檢測總線的操作函數和驅動的操作函數是否同時存在,同時存在則提示使用總線提供的操作函數
        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 -EEXIST;
        }

        //添加驅動到總線上
        ret = bus_add_driver(drv);
        if (ret)
                return ret;

        
        ret = driver_add_groups(drv, drv->groups);
        if (ret)
                bus_remove_driver(drv);
        return ret;
}



int bus_add_driver(struct device_driver *drv)
{
        struct bus_type *bus;
        struct driver_private *priv;
        int error = 0;

        //取bus結構
        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_devices鏈表
        klist_init(&priv->klist_devices, NULL, NULL);

        //互相關聯(lián)
        priv->driver = drv;
        drv->p = priv;

        //設置私有數據的父容器,在這一步中,設置了kset為platform下的drivers_kset結構,也就是drivers呢個目錄
        priv->kobj.kset = bus->p->drivers_kset;

        //初始化kobj對象,設置容器操作集并建立相應的目錄,這里由于沒有提供parent,所以會使用父容器中的kobj為父對象
        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                                     "%s", drv->name);
        if (error)
                goto out_unregister;

        //檢測所屬總線的drivers_autoprobe屬性是否為真
        //為真則進行與設備的匹配,到這里,就會與我們之前注冊的test_device連接上了,至于如何連接,進行了什么操作,將在別的文章中詳細描述
        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);

        //建立uevent屬性文件
        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) {
                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name);
        }
        error = add_bind_files(drv);
        if (error) {
                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",__func__, drv->name);
        }

        kobject_uevent(&priv->kobj, KOBJ_ADD);
        return error;
out_unregister:
        kobject_put(&priv->kobj);
out_put_bus:
        bus_put(bus);
        return error;
}

到這里test_driver的模型就建立好了,圖就是最上面的層次圖,我就不再貼了

到這里一個基本的框架就建立起來了~


[ 本帖最后由 superfight 于 2009-1-19 01:59 編輯 ]
作者: superfight    時間: 2009-01-19 01:31
下面,我開始對kobject kset和ktype做分析

先說說關系,ktype與kobject和kset這兩者之前的關系較少,讓我畫一個圖,是這樣的




ktype依賴于kobject,kset也依賴于kobject,而kobject有時需要kset(所以用了一個白箭頭),不一定需要ktype(真可憐,連白箭頭都沒有)

首先先說一下這個可有可無的ktype

到/sys/bus/platform下面可以看見一個drivers_autoprobe的文件
cat drivers_autoprobe可以查看這個文件的值
echo 0 > drivers_autoprobe則可以改變這個文件的值
drivers_autoprobe這個文件表示的是是否自動進行初始化

void bus_attach_device(struct device *dev)
{
        struct bus_type *bus = dev->bus;
        int ret = 0;

        if (bus) {
                if (bus->p->drivers_autoprobe)
                        ret = device_attach(dev);
                WARN_ON(ret < 0);
                if (ret >= 0)
                        klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
        }
}
中可以看見這么一段代碼
if (bus->p->drivers_autoprobe)
        ret = device_attach(dev);
bus->p->drivers_autoprobe的值為真則進行匹配
而drivers_autoprobe這個文件則可以動態(tài)的修改這個值選擇是否進行匹配
使用外部文件修改內核參數,ktype就是提供了這么一種方法

現(xiàn)在讓我們看看ktype是怎么通過kobject進行運作的
首先是ktype及通過ktype進行運作的drivers_autoprobe的注冊

ktype的掛載十分簡單,因為他是和kobject是一體的
只有這么下面一句       
priv->subsys.kobj.ktype = &bus_ktype;
這樣就將bus_ktype掛載到了platform_bus_type的kobject上
drivers_autoprobe的注冊如下
retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);

bus_attr_drivers_autoprobe這個結構由一系列的宏進行組裝
static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
                show_drivers_autoprobe, store_drivers_autoprobe);

#define BUS_ATTR(_name, _mode, _show, _store)        \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

#define __ATTR(_name,_mode,_show,_store) { \
        .attr = {.name = __stringify(_name), .mode = _mode },        \
        .show        = _show,                                        \
        .store        = _store,                                        \
}

最后bus_attr_drivers_autoprobe的模型如下

struct bus_attribute  bus_attr_drivers_autoprobe
{
        .attr = {
.name = “drivers_autoprobe”,
.mode = S_IWUSR | S_IRUGO
},       
        .show        = show_drivers_autoprobe,                                       
        .store        = store_drivers_autoprobe,                                       

}

進入到bus_create_file中
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
//參數為(bus, &bus_attr_drivers_autoprobe)
{
        int error;
        if (bus_get(bus)) {
                error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
                bus_put(bus);
        } else
                error = -EINVAL;
        return error;
}

int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
//參數為(&bus->p->subsys.kobj, &attr->attr)
{
        BUG_ON(!kobj || !kobj->sd || !attr);

        return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);

}

int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,int type)
//參數為(&bus->p->subsys.kobj ->sd, &attr->attr, SYSFS_KOBJ_ATTR)
{
        return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
}


int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
                        const struct attribute *attr, int type, mode_t amode)
//整理一下參數,現(xiàn)在應該為
//(&platform_bus_type->p->subsys.kobj ->sd, &bus_attr_drivers_autoprobe->attr, SYSFS_KOBJ_ATTR, &bus_attr_drivers_autoprobe->attr->mode)
{
        umode_t mode = (amode & S_IALLUGO) | S_IFREG;
        struct sysfs_addrm_cxt acxt;
        struct sysfs_dirent *sd;
        int rc;

        //在這一步中可以看出新建了一個節(jié)點
        sd = sysfs_new_dirent(attr->name, mode, type);
        if (!sd)
                return -ENOMEM;
       
        //這一步掛載了&bus_attr_drivers_autoprobe->attr到節(jié)點中,為以后提取attr及上層結構做準備
        sd->s_attr.attr = (void *)attr;

        // dir_sd也就是上層目錄,在這里為platform_bus_type->p->subsys.kobj ->sd
        //也就是/sys/bus/platform這個目錄
        sysfs_addrm_start(&acxt, dir_sd);
        rc = sysfs_add_one(&acxt, sd);
        sysfs_addrm_finish(&acxt);

        if (rc)
                sysfs_put(sd);

        return rc;
}


struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
{
        char *dup_name = NULL;
        struct sysfs_dirent *sd;

        if (type & SYSFS_COPY_NAME) {
                name = dup_name = kstrdup(name, GFP_KERNEL);
                if (!name)
                        return NULL;
        }

        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
        if (!sd)
                goto err_out1;

        if (sysfs_alloc_ino(&sd->s_ino))
                goto err_out2;

        atomic_set(&sd->s_count, 1);
        atomic_set(&sd->s_active, 0);

        sd->s_name = name;   //節(jié)點的名字為&bus_attr_drivers_autoprobe->attr->name  也就是drivers_autoprobe
        sd->s_mode = mode;
sd->s_flags = type;   //節(jié)點的type為SYSFS_KOBJ_ATTR


        return sd;

err_out2:
        kmem_cache_free(sysfs_dir_cachep, sd);
err_out1:
        kfree(dup_name);
        return NULL;
}

現(xiàn)在一切準備就緒,來看看怎么讀取吧
首先是open,大概流程可以看我的另一篇文章<從文件到設備>,一直看到ext3_lookup
這里和ext3_lookup不同的是,sys的文件系統(tǒng)是sysfs文件系統(tǒng),所以應該使用的lookup函數為sysfs_lookup(/fs/sysfs/dir.c)

static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
                                struct nameidata *nd)
{
        struct dentry *ret = NULL;
        struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
        struct sysfs_dirent *sd;
        struct inode *inode;

        mutex_lock(&sysfs_mutex);

        sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);

        if (!sd) {
                ret = ERR_PTR(-ENOENT);
                goto out_unlock;
        }

        //節(jié)點的初始化在這里
        inode = sysfs_get_inode(sd);
        if (!inode) {
                ret = ERR_PTR(-ENOMEM);
                goto out_unlock;
        }

        dentry->d_op = &sysfs_dentry_ops;
        dentry->d_fsdata = sysfs_get(sd);
        d_instantiate(dentry, inode);
        d_rehash(dentry);

out_unlock:
        mutex_unlock(&sysfs_mutex);
        return ret;
}


struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
{
        struct inode *inode;

        inode = iget_locked(sysfs_sb, sd->s_ino);
        if (inode && (inode->i_state & I_NEW))
                //為節(jié)點賦值
                sysfs_init_inode(sd, inode);

        return inode;
}


static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
        struct bin_attribute *bin_attr;

        inode->i_blocks = 0;
        inode->i_mapping->a_ops = &sysfs_aops;
        inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
        inode->i_op = &sysfs_inode_operations;
        inode->i_ino = sd->s_ino;
        lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);

        if (sd->s_iattr) {
                set_inode_attr(inode, sd->s_iattr);
        } else
                set_default_inode_attr(inode, sd->s_mode);

        //判斷類型
        switch (sysfs_type(sd)) {
        case SYSFS_DIR:
                inode->i_op = &sysfs_dir_inode_operations;
                inode->i_fop = &sysfs_dir_operations;
                inode->i_nlink = sysfs_count_nlink(sd);
                break;
        //還記得在注冊的時候有一個參數為SYSFS_KOBJ_ATTR賦到了sd->s_flags上面吧
        case SYSFS_KOBJ_ATTR:
                inode->i_size = PAGE_SIZE;
                inode->i_fop = &sysfs_file_operations;
                break;
        case SYSFS_KOBJ_BIN_ATTR:
                bin_attr = sd->s_bin_attr.bin_attr;
                inode->i_size = bin_attr->size;
                inode->i_fop = &bin_fops;
                break;
        case SYSFS_KOBJ_LINK:
                inode->i_op = &sysfs_symlink_inode_operations;
                break;
        default:
                BUG();
        }

        unlock_new_inode(inode);
}

sysfs_file_operations的結構如下,之后open和read,write都明了了

const struct file_operations sysfs_file_operations = {
        .read                = sysfs_read_file,
        .write                = sysfs_write_file,
        .llseek                = generic_file_llseek,
        .open                = sysfs_open_file,
        .release        = sysfs_release,
        .poll                = sysfs_poll,
};

有關在哪調用open還是請查閱我的另一篇文章<從文件到設備>中 nameidata_to_filp之后的操作

好的~  現(xiàn)在進入到了sysfs_open_file中

static int sysfs_open_file(struct inode *inode, struct file *file)
{
        struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
        //要重的取值,在這里取得了drivers_autoprobe的目錄platform的kproject
        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        struct sysfs_buffer *buffer;
        struct sysfs_ops *ops;
        int error = -EACCES;

        if (!sysfs_get_active_two(attr_sd))
                return -ENODEV;

        if (kobj->ktype && kobj->ktype->sysfs_ops)
                //這里可謂是ktype實現(xiàn)中的核心,在這里ops設置成了platform_bus_type中kobject->ktype的sysfs_ops
                ops = kobj->ktype->sysfs_ops;
        else {
                printk(KERN_ERR "missing sysfs attribute operations for ""kobject: %s\n", kobject_name(kobj));
                WARN_ON(1);
                goto err_out;
        }

        if (file->f_mode & FMODE_WRITE) {
                if (!(inode->i_mode & S_IWUGO) || !ops->store)
                        goto err_out;
        }

        if (file->f_mode & FMODE_READ) {
                if (!(inode->i_mode & S_IRUGO) || !ops->show)
                        goto err_out;
        }

        error = -ENOMEM;
        buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
        if (!buffer)
                goto err_out;

        mutex_init(&buffer->mutex);
        buffer->needs_read_fill = 1;
        //然后將設置好的ops掛載到buffer上
        buffer->ops = ops;
        //再將buffer掛載到file->private_data中
        file->private_data = buffer;

        error = sysfs_get_open_dirent(attr_sd, buffer);
        if (error)
                goto err_free;

        sysfs_put_active_two(attr_sd);
        return 0;

err_free:
        kfree(buffer);
err_out:
        sysfs_put_active_two(attr_sd);
        return error;
}


現(xiàn)在已經為read和write操作準備好了
馬上進入到read操作中



整個流程如上圖所示,如何進入到sysfs_read_file在上面open的操作中已經說明了
我們就從sysfs_read_file開始分析(該文件在/fs/sysfs/file.c中)

sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
        struct sysfs_buffer * buffer = file->private_data;
        ssize_t retval = 0;

        mutex_lock(&buffer->mutex);
        if (buffer->needs_read_fill || *ppos == 0) {
                //主要操作在fill_read_buffer中
                retval = fill_read_buffer(file->f_path.dentry,buffer);
                if (retval)
                        goto out;
        }
        pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",__func__, count, *ppos, buffer->page);
        retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
                                         buffer->count);
out:
        mutex_unlock(&buffer->mutex);
        return retval;
}

static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
{
        struct sysfs_dirent *attr_sd = dentry->d_fsdata;
        //取得父目錄的kobject,也就是platform的kobject
        struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
        //還記得這個buffer->ops在什么時候進行賦值的么?
        struct sysfs_ops * ops = buffer->ops;
        int ret = 0;
        ssize_t count;

        if (!buffer->page)
                buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
        if (!buffer->page)
                return -ENOMEM;

        if (!sysfs_get_active_two(attr_sd))
                return -ENODEV;

        buffer->event = atomic_read(&attr_sd->s_attr.open->event);

        //調用ops->show  也就是bus_sysfs_ops->show    具體就是bus_attr_show了
        //參數為父目錄的kobject, bus_attr_drivers_autoprobe->attr,和一段char信息
        count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);

        sysfs_put_active_two(attr_sd);

        if (count >= (ssize_t)PAGE_SIZE) {
                print_symbol("fill_read_buffer: %s returned bad count\n",
                        (unsigned long)ops->show);
                /* Try to struggle along */
                count = PAGE_SIZE - 1;
        }
        if (count >= 0) {
                buffer->needs_read_fill = 0;
                buffer->count = count;
        } else {
                ret = count;
        }
        return ret;
}


現(xiàn)在進入bus_attr_show中

static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,char *buf)
{
        //提取attr的上層結構,也就是bus_attr_drivers_autoprobe
        struct bus_attribute *bus_attr = to_bus_attr(attr);
        //提取kobj的上上層結構,也就是bus_type_private
        struct bus_type_private *bus_priv = to_bus(kobj);
        ssize_t ret = 0;

        if (bus_attr->show)
                //終于到了這里,最后的調用,調用bus_attr_drivers_autoprobe.show ,也就是show_drivers_autoprobe
                //參數為bus_priv->bus,也就是platform_bus_type , 及一段char信息
                ret = bus_attr->show(bus_priv->bus, buf);
        return ret;
}

static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
{
        return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
}

沒什么好介紹了就是打印 buf + bus->p->drivers_autoprobe   從結果來看~ buf是空的
到這里,終于把內核的信息給打印出來了,千辛萬苦,層層調用,就是為了取得上層kobject結構,逆運算再取得kobject的上層結構
大家是否對kobject有所了解了呢?~  
在對kobject進行介紹之前  還是先把write操作講完吧 哈哈~

write操作和read操作重要的步驟基本是一致的,只不過在最后的調用中
static ssize_t store_drivers_autoprobe(struct bus_type *bus,
                                       const char *buf, size_t count)
{
        if (buf[0] == '0')
                bus->p->drivers_autoprobe = 0;
        else
                bus->p->drivers_autoprobe = 1;
        return count;
}
不進行打印而對內核的參數進行了修改而已

好~ 現(xiàn)在讓我們來看看kobject吧

kobject的結構如下

struct kobject {
        const char                *name;          //kobject的名字
        struct kref                kref;                                //kobject的原子操作
        struct list_head        entry;
        struct kobject                *parent;                        //父對象
        struct kset                *kset;                        //父容器
        struct kobj_type        *ktype;                        //ktype
        struct sysfs_dirent        *sd;                                //文件節(jié)點
        unsigned int state_initialized:1;
        unsigned int state_in_sysfs:1;
        unsigned int state_add_uevent_sent:1;
        unsigned int state_remove_uevent_sent:1;
};

kobject描述的是較具體的對象,一個設備,一個驅動,一個總線,一類設備

在層次圖上可以看出,每個存在于層次圖中的設備,驅動,總線,類別都有自己的kobject

kobject與kobject之間的層次由kobject中的parent指針決定

而kset指針則表明了kobject的容器

像platform_bus 和test_device的kset都是devices_kset

呢parent和kset有什么不同呢

我認為是人工和默認的區(qū)別,看下面這張圖 ,藍框為kset,紅框為kobject





容器提供了一種默認的層次~  但也可以人工設置層次

對于kobject現(xiàn)在我只理解了這么多,歡迎大家指出有疑問的地方

最后是kset,kset比較簡單,看下面的結構
struct kset {
        struct list_head list;
        spinlock_t list_lock;
        struct kobject kobj;
        struct kset_uevent_ops *uevent_ops;
};

對于kset的描述,文檔里也有介紹
/**
* struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
*
* A kset defines a group of kobjects.  They can be individually
* different "types" but overall these kobjects all want to be grouped
* together and operated on in the same manner.  ksets are used to
* define the attribute callbacks and other common events that happen to
* a kobject.

翻譯過來大概就是
結構kset,一個指定類型的kobject的集合,屬于某一個指定的子系統(tǒng)
kset定義了一組kobject,它們可以是不同類型組成但卻希望捆在一起有一個統(tǒng)一的操作
kset通常被定義為回調屬性和其他通用的事件發(fā)生在kobject上

可能翻譯的不是很好,望大家見諒
從結構中能看出kset比kobject多了3個屬性
list_head                                //列表
spinlock_t                        //共享鎖
kset_uevent_ops                //uevent操作集

list_head        連接了所有kobject中kset屬性指向自己的kobject
而kset_uevent_ops則用于通知機制,由于uevent的作用我也沒接觸過,所以暫不解析uevent的機制了


寫到這里,不知道大家對內核驅動架構中的注冊和對kobject的了解有無加深呢?

轉帖請注明轉自BLOG http://blog.chinaunix.net/u1/57901/

[ 本帖最后由 superfight 于 2009-1-19 01:38 編輯 ]
作者: superfight    時間: 2009-01-19 01:40
這篇感覺我自己都覺得寫得蠻亂........ 但是又無從改起

大家有什么看法提出來討論討論吧~   說不定會有靈感讓我改得更通俗易懂

我個人對kobject的了解也還不夠深入,一起學習吧~

PS:帖了一堆代碼感覺挺浪費論壇資源的.................囧

[ 本帖最后由 superfight 于 2009-1-19 02:00 編輯 ]
作者: scutan    時間: 2009-01-19 09:23
謝謝分享, 拜讀一下.
作者: smartlinux    時間: 2009-01-19 09:46
有心人啊
作者: ynchnluiti    時間: 2009-01-19 10:07
感謝。學習
作者: scutan    時間: 2009-01-19 12:34
讀完了,很受用,而且圖也畫得很直觀。謝謝。
另外,能否麻煩superfight 兄將最前面那張大圖稍微縮小一點呢。
作者: Godbach    時間: 2009-01-19 12:57
有時間一定學習一下
作者: Solaris12    時間: 2009-01-19 13:32
原帖由 superfight 于 2009-1-19 01:27 發(fā)表
在LINUX中最讓人不解的大概就是/sys下面的內容了

下面首先讓我們來創(chuàng)建一個簡單的platform設備,并從這個設備的視角進行深入,在此篇文章的深入過程中,我們只看kobeject的模型
我所使用的內核版本號為2.6.26, ...



圖畫得不錯,什么工具畫的?
作者: Godbach    時間: 2009-01-19 13:34
VISIO 2007?
作者: superfight    時間: 2009-01-19 13:53
原帖由 scutan 于 2009-1-19 12:34 發(fā)表
讀完了,很受用,而且圖也畫得很直觀。謝謝。
另外,能否麻煩superfight 兄將最前面那張大圖稍微縮小一點呢。



= = 又縮了點~     可惜排線的工具不能做成點擊線條自動亮紅呢樣的FLASH式的~    沒辦法了~

要不還能再小點~




[ 本帖最后由 superfight 于 2009-2-3 15:48 編輯 ]
作者: superfight    時間: 2009-01-19 13:55
是VISIO 2007~

我之前用得WORD慢慢畫的........

后來別人教我用VISIO~   才解放出來~  

大家還有什么其它更好的布線工具推薦么~ = = ~
作者: scutan    時間: 2009-01-19 13:59
原帖由 superfight 于 2009-1-19 13:55 發(fā)表
是VISIO 2007~

我之前用得WORD慢慢畫的........

后來別人教我用VISIO~   才解放出來~  

大家還有什么其它更好的布線工具推薦么~ = = ~


我們平時也是用的VISIO畫。感覺還不錯。
作者: superfight    時間: 2009-01-19 14:05
原帖由 scutan 于 2009-1-19 13:59 發(fā)表


我們平時也是用的VISIO畫。感覺還不錯。



我覺得還是差一點~   對于大量的過線應該能一條主干道經過~

然后鼠標點擊線頭~   畫面就縮放到線頭到線尾中的部分這樣的FLASH之類的動態(tài)圖~

不知道VISIO能不能畫~   

其實現(xiàn)在這圖還有蠻多小關系我沒畫清楚~ 實在沒地方了~   在不影響大結構的情況下~  

我就沒細分~
作者: changzi100    時間: 2009-01-19 14:09
太詳細了,以至要花上幾袋煙的功夫才能看完!
作者: superfight    時間: 2009-01-19 14:16
原帖由 changzi100 于 2009-1-19 14:09 發(fā)表
太詳細了,以至要花上幾袋煙的功夫才能看完!


其實看看呢張大圖~  看看kobject是怎么連的就行了~

內核對kobject管理不當的地方就是注冊的時候以函數區(qū)分功能  而不是參數,才搞得這么多的~ 呵呵~
作者: axlrose    時間: 2009-01-20 10:19
強文,頂一個
作者: davhuang    時間: 2009-01-20 10:35
原帖由 superfight 于 2009-1-19 13:55 發(fā)表
是VISIO 2007~

我之前用得WORD慢慢畫的........

后來別人教我用VISIO~   才解放出來~  

大家還有什么其它更好的布線工具推薦么~ = = ~

個人覺得Edraw很不錯不輸于visio
如果要說正版價格的話,更是天壤之別
作者: Solaris12    時間: 2009-01-20 11:26
原帖由 superfight 于 2009-1-19 13:55 發(fā)表
是VISIO 2007~

我之前用得WORD慢慢畫的........

后來別人教我用VISIO~   才解放出來~  

大家還有什么其它更好的布線工具推薦么~ = = ~



奧,因為基本不用windows,很想知道有什么開源工具。
作者: T-bagwell    時間: 2009-01-20 11:42
原帖由 Solaris12 于 2009-1-20 11:26 發(fā)表



奧,因為基本不用windows,很想知道有什么開源工具。


OpenOffice里有個Draw
可能S12下兄覺得她不好用吧?

Screenshot-3.png (81.71 KB, 下載次數: 71)

Screenshot-3.png

Screenshot-4.png (73.24 KB, 下載次數: 66)

Screenshot-4.png

作者: wqhl.mark    時間: 2009-01-20 22:36
標題: 回復 #1 superfight 的帖子
看得出,superfight也是花了不少心思的,辛苦辛苦。

/sys及driver model是2.6內核中引入的概念,結合udev機制增強了系統(tǒng)管理的靈活性和層次性,使開發(fā)和管理更加容易。越是新的內核,driver model越趨于穩(wěn)定,2.6.25后基本沒什么變化,2.6.24向2.6.25時去除了 kset,subsystem的內容,統(tǒng)一通過kobject相關的操作來實現(xiàn),管理的粒度更細了。
作者: banggou    時間: 2009-01-20 23:47
受教  收藏先:wink:
作者: qunying    時間: 2009-01-21 03:06
提示: 作者被禁止或刪除 內容自動屏蔽
作者: lbaby    時間: 2009-01-24 11:52
畫圖可以參考下 graphviz
作者: dreamice    時間: 2009-01-25 13:54
先頂一下,年后學習研究研究
作者: gotop167    時間: 2009-02-01 15:48
建議整理下,發(fā)個pdf
作者: jacksting    時間: 2009-02-01 16:11
嗯,很好,不過圖看起來不是很方便。LZ可能用的22寸的寬屏,看著正好,我們這些用小屏幕的要不停滾動。
作者: firstfree04    時間: 2009-02-01 20:39
能整個文檔就好了
作者: superfight    時間: 2009-02-01 22:42
做PDF圖放不下.............

= = 其實我覺得我現(xiàn)在這個圖已經蠻小了~

之前的不用箭頭  用空格做分層~   上W分辨率了~   

樓上的同學說得真準 Orz  就是22寸的~   我覺得還小了~   下次就要28或者30寸的了~

PS:剛發(fā)現(xiàn)連線的錯誤~進行了修正

platform_driver.driver->p->driver應連接到platform_driver.driver

[ 本帖最后由 superfight 于 2009-2-3 15:54 編輯 ]
作者: dj_ukyo    時間: 2010-03-26 10:48
這篇感覺我自己都覺得寫得蠻亂........ 但是又無從改起

大家有什么看法提出來討論討論吧~   說不定會有靈 ...
superfight 發(fā)表于 2009-01-19 01:40


不得不說佩服,做圖也非常優(yōu)秀!就是太謙虛!
作者: duanjigang    時間: 2010-03-26 16:13
多謝樓主!學習
作者: lmarsin    時間: 2010-03-26 16:42
不得不頂
作者: epegasus    時間: 2010-03-27 00:06
沒看完...
感覺意圖太少,細節(jié)太過.
還沒搞懂kobj啥意思...
作者: ywf851207    時間: 2010-09-03 17:39
現(xiàn)在還有點看不懂 不過樓主寫的很詳細 向樓主致敬
作者: zd零    時間: 2010-09-03 18:04
拜讀。。。。!
作者: omycle    時間: 2010-09-04 20:09
樓主,搞一個PDF的出來
作者: lyl19    時間: 2010-09-05 12:08
回復 1# superfight


    這個要頂一下, 有時間好好研究研究
作者: kitifaye    時間: 2010-09-09 20:12
不得不頂
作者: 醉酒大哥    時間: 2011-07-14 10:58
{:3_192:} {:3_192:}
作者: longjiacheng    時間: 2011-07-27 17:16
學習了……
作者: yingqy88    時間: 2011-07-30 10:52

作者: qiangtoucao121    時間: 2011-08-06 16:55
這樣的好貼 頂一把
作者: sdydding    時間: 2011-08-13 10:25
向樓主學習,很久沒來論壇了,依然那么親切,呵呵
作者: 狼之鵬    時間: 2011-09-23 16:41
很好呀,再讀讀
作者: tsinhi    時間: 2011-09-25 20:18
留下一個腳印
作者: 孤行者_cuit    時間: 2011-10-28 14:07
呈現(xiàn)給讀者的思路很清晰,贊!
作者: victure83    時間: 2011-10-28 16:31
學習,寫得不錯,之前一直沒有完全明白。
作者: zheguzai    時間: 2012-02-14 14:12
很牛逼的,MARK以后看

作者: sygspjlsj    時間: 2012-05-09 11:18
太犀利了,符號鏈接都快整暈了!
作者: shallot2012    時間: 2013-11-16 15:14
截止到目前為止,看到的關于kobject最好的一篇文章,特地注冊了一個賬號留言,非常感謝樓主能把自己的study一起分享
作者: shallot2012    時間: 2013-11-16 15:56
目前為止接觸到的最好的一篇關于kobject的文章,特地注冊賬號,表示感謝
作者: wsshopping    時間: 2013-11-19 10:51
正在看,,,
作者: 624801474    時間: 2013-11-20 13:51
寫的真心不錯,讓我終于對Kobject有所理解了,不過對于剛接觸Kobject的人可能沒有毅力讀完,搞了7天終于OK了,謝謝樓主,那天我也寫個Kobject設計的靈魂和思想
作者: 黃筱諾    時間: 2014-07-08 17:29
求助樓主以及各位志同道合的朋友,那個畫圖軟件如何才能繪出樓主這樣的圖形呢?自己摸索、百度都沒解決問題。希望朋友們指點一二,我的QQ是:595004525.
作者: abin9630    時間: 2016-08-03 16:10
mark學習一下
作者: _nosay    時間: 2016-08-03 18:46





歡迎光臨 Chinaunix (http://www.72891.cn/) Powered by Discuz! X3.2