- 論壇徽章:
- 0
|
現(xiàn)在到bus_register了
注冊(cè)的參數(shù)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;
//聲明一個(gè)總線私有數(shù)據(jù)并分配空間
struct bus_type_private *priv;
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
//互相關(guān)聯(lián)
priv->bus = bus;
bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
//設(shè)置私有數(shù)據(jù)中kobj對(duì)象的名字
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;
//設(shè)置父容器為bus_kset,操作集為bus_ktype
priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;
//注冊(cè)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中
//提取父對(duì)象,因?yàn)闆](méi)有設(shè)置父對(duì)象,所以為空
parent = kobject_get(kobj->parent);
//父容器存在則設(shè)置父對(duì)象,在上文中設(shè)置了父容器priv->subsys.kobj.kset = bus_kset
if (kobj->kset) {
//檢測(cè)是否已經(jīng)設(shè)置父對(duì)象
if (!parent)
//無(wú)則使用父容器為父對(duì)象
parent = kobject_get(&kobj->kset->kobj);
//添加該kobj到父容器的鏈表中
kobj_kset_join(kobj);
//設(shè)置父對(duì)象
kobj->parent = parent;
}
在retval = kset_register(&priv->subsys)完成之后platform在bus下的模型如下圖
platform_bus.png (84.78 KB, 下載次數(shù): 214)
下載附件
2009-01-19 01:31 上傳
有印象的話大家還記得在platform下面有兩個(gè)目錄devices和drivers吧~
現(xiàn)在就到這兩個(gè)目錄的注冊(cè)了
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
注意這兩條語(yǔ)句的頭部
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)在來(lái)看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)
//參數(shù)為"devices", NULL,&priv->subsys.kobj
{
struct kset *kset;
int error;
//創(chuàng)建一個(gè)kset容器
kset = kset_create(name, uevent_ops, parent_kobj);
if (!kset)
return NULL;
//注冊(cè)創(chuàng)建的kset容器
error = kset_register(kset);
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
在kset_create 中比較重要的操作為
kset->kobj.ktype = &kset_ktype //設(shè)置了ktype,為kset_ktype
kset->kobj.parent = parent_kobj; //設(shè)置了父對(duì)象,為priv->subsys.kobj,也就是platform_bus_type->p->subsys.kobj
kset->kobj.kset = NULL; //設(shè)置父容器為空
在kset_register中
//提取父對(duì)象
parent = kobject_get(kobj->parent); //在之前設(shè)置為了
//父容器存在則設(shè)置父對(duì)象,由于父容器為空,不執(zhí)行以下代碼
if (kobj->kset) {
//檢測(cè)是否已經(jīng)設(shè)置父對(duì)象
if (!parent)
//無(wú)則使用父容器為父對(duì)象
parent = kobject_get(&kobj->kset->kobj);
//添加該kobj到父容器的鏈表中
kobj_kset_join(kobj);
//設(shè)置父對(duì)象
kobj->parent = parent;
}
至此, devices的模型就建立好了,drivers模型的建立和devices是一致的,只是名字不同而已,我就不復(fù)述了,建立好的模型如下
platform_devices_drivers.png (111.97 KB, 下載次數(shù): 215)
下載附件
2009-01-19 01:31 上傳
好了~ 到了這里,bus,devices和platform的基礎(chǔ)模型就就建立好了,就等設(shè)備來(lái)注冊(cè)了
在platform模型設(shè)備的建立中,需要2個(gè)部分的注冊(cè),驅(qū)動(dòng)的注冊(cè)和設(shè)備的注冊(cè)
platform_device_register(&test_device);
platform_driver_register(&test_driver);
首先看platform_device_register
注冊(cè)參數(shù)為test_device,結(jié)構(gòu)如下
static struct platform_device test_device = {
.name = "test_ts",
.id = -1,
//. resource
//.dev
};
這個(gè)結(jié)構(gòu)主要描述了設(shè)備的名字,ID和資源和私有數(shù)據(jù),其中資源和私有數(shù)據(jù)我們?cè)谶@里不使用,將在別的文章中進(jìn)行講解
int platform_device_register(struct platform_device *pdev)
{
//設(shè)備屬性的初始化
device_initialize(&pdev->dev);
//將設(shè)備添加進(jìn)platform里
return platform_device_add(pdev);
}
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset; //設(shè)置kset為devices_kset,則將設(shè)備掛接上了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;
//檢測(cè)是否設(shè)置了dev中的parent,無(wú)則賦為platform_bus
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
//設(shè)置dev中的bus為platform_bus_type
pdev->dev.bus = &platform_bus_type;
//檢測(cè)id,id為-1表明該設(shè)備只有一個(gè),用設(shè)備名為bus_id
//不為1則表明該設(shè)備有數(shù)個(gè),需要用序號(hào)標(biāo)明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);
//增加資源到資源樹(shù)中
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);
//添加設(shè)備到設(shè)備層次中
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為準(zhǔn)重設(shè)dev->kobj.parent
setup_parent(dev, parent);
if (parent)
set_dev_node(dev, dev_to_node(parent));
//設(shè)置dev->kobj的名字和父對(duì)象,并建立相應(yīng)目錄
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
if (error)
goto Error;
if (platform_notify)
platform_notify(dev);
//一種新型的通知機(jī)制,但是platform中沒(méi)有設(shè)置相應(yīng)的結(jié)構(gòu),所以在這里跳過(guò)
/* 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;
//設(shè)備有設(shè)備號(hào)則建立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);
//檢測(cè)驅(qū)動(dòng)中有無(wú)適合的設(shè)備進(jìn)行匹配,現(xiàn)在只添加了設(shè)備,還沒(méi)有加載驅(qū)動(dòng),所以不會(huì)進(jì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不為空則重設(shè)dev->kobj.parent
if (kobj)
dev->kobj.parent = kobj;
}
static struct kobject *get_device_parent(struct device *dev,
struct device *parent)
{
int retval;
//因?yàn)閐ev->class為空,所以跳過(guò)這段代碼
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中雖然沒(méi)有成功進(jìn)行匹配,但是有很重要的一步為之后正確的匹配打下基礎(chǔ)
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)就是這一行
在這一行代碼中將設(shè)備掛載到了bus下的devices鏈表下,這樣,當(dāng)驅(qū)動(dòng)請(qǐng)求匹配的時(shí)候,platform總線就會(huì)歷遍devices鏈表為驅(qū)動(dòng)尋找合適的設(shè)備
現(xiàn)在來(lái)看一下test_device的模型
test_device.png (141.22 KB, 下載次數(shù): 219)
下載附件
2009-01-19 01:31 上傳
然后platform_driver_unregister,他的參數(shù) test_driver的結(jié)構(gòu)如下
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中設(shè)置了probe, remove, shutdown, suspend或resume函數(shù)的話
則drv->driver也會(huì)設(shè)置成platform對(duì)應(yīng)的函數(shù)
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
//檢測(cè)總線的操作函數(shù)和驅(qū)動(dòng)的操作函數(shù)是否同時(shí)存在,同時(shí)存在則提示使用總線提供的操作函數(shù)
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);
//檢測(cè)是否已經(jīng)注冊(cè)過(guò)
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;
}
//添加驅(qū)動(dòng)到總線上
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結(jié)構(gòu)
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
//分配驅(qū)動(dòng)私有數(shù)據(jù)
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
//初始化klist_devices鏈表
klist_init(&priv->klist_devices, NULL, NULL);
//互相關(guān)聯(lián)
priv->driver = drv;
drv->p = priv;
//設(shè)置私有數(shù)據(jù)的父容器,在這一步中,設(shè)置了kset為platform下的drivers_kset結(jié)構(gòu),也就是drivers呢個(gè)目錄
priv->kobj.kset = bus->p->drivers_kset;
//初始化kobj對(duì)象,設(shè)置容器操作集并建立相應(yīng)的目錄,這里由于沒(méi)有提供parent,所以會(huì)使用父容器中的kobj為父對(duì)象
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
//檢測(cè)所屬總線的drivers_autoprobe屬性是否為真
//為真則進(jìn)行與設(shè)備的匹配,到這里,就會(huì)與我們之前注冊(cè)的test_device連接上了,至于如何連接,進(jìn)行了什么操作,將在別的文章中詳細(xì)描述
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
//掛載到所屬總線驅(qū)動(dòng)鏈表上
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);
}
//建立設(shè)備屬性文件
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的模型就建立好了,圖就是最上面的層次圖,我就不再貼了
到這里一個(gè)基本的框架就建立起來(lái)了~
[ 本帖最后由 superfight 于 2009-1-19 01:59 編輯 ] |
|