From adf094931ffb25ef4b381559918f1a34181a5273 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 6 Oct 2008 22:46:05 +0200 Subject: PM: Simplify the new suspend/hibernation framework for devices PM: Simplify the new suspend/hibernation framework for devices Following the discussion at the Kernel Summit, simplify the new device PM framework by merging 'struct pm_ops' and 'struct pm_ext_ops' and removing pointers to 'struct pm_ext_ops' from 'struct platform_driver' and 'struct pci_driver'. After this change, the suspend/hibernation callbacks will only reside in 'struct device_driver' as well as at the bus type/ device class/device type level. Accordingly, PCI and platform device drivers are now expected to put their suspend/hibernation callbacks into the 'struct device_driver' embedded in 'struct pci_driver' or 'struct platform_driver', respectively. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Cc: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 115 ++++++++++++++++++++++++---------------------- drivers/base/power/main.c | 19 ++++---- 2 files changed, 70 insertions(+), 64 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index dfcbfe5..6c743b6 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -503,8 +503,6 @@ int platform_driver_register(struct platform_driver *drv) drv->driver.suspend = platform_drv_suspend; if (drv->resume) drv->driver.resume = platform_drv_resume; - if (drv->pm) - drv->driver.pm = &drv->pm->base; return driver_register(&drv->driver); } EXPORT_SYMBOL_GPL(platform_driver_register); @@ -686,7 +684,10 @@ static int platform_pm_suspend(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->suspend) ret = drv->pm->suspend(dev); } else { @@ -698,16 +699,15 @@ static int platform_pm_suspend(struct device *dev) static int platform_pm_suspend_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->suspend_noirq) - ret = pdrv->pm->suspend_noirq(dev); + if (drv->pm) { + if (drv->pm->suspend_noirq) + ret = drv->pm->suspend_noirq(dev); } else { ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND); } @@ -720,7 +720,10 @@ static int platform_pm_resume(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->resume) ret = drv->pm->resume(dev); } else { @@ -732,16 +735,15 @@ static int platform_pm_resume(struct device *dev) static int platform_pm_resume_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->resume_noirq) - ret = pdrv->pm->resume_noirq(dev); + if (drv->pm) { + if (drv->pm->resume_noirq) + ret = drv->pm->resume_noirq(dev); } else { ret = platform_legacy_resume_early(dev); } @@ -780,16 +782,15 @@ static int platform_pm_freeze(struct device *dev) static int platform_pm_freeze_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->freeze_noirq) - ret = pdrv->pm->freeze_noirq(dev); + if (drv->pm) { + if (drv->pm->freeze_noirq) + ret = drv->pm->freeze_noirq(dev); } else { ret = platform_legacy_suspend_late(dev, PMSG_FREEZE); } @@ -802,7 +803,10 @@ static int platform_pm_thaw(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->thaw) ret = drv->pm->thaw(dev); } else { @@ -814,16 +818,15 @@ static int platform_pm_thaw(struct device *dev) static int platform_pm_thaw_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->thaw_noirq) - ret = pdrv->pm->thaw_noirq(dev); + if (drv->pm) { + if (drv->pm->thaw_noirq) + ret = drv->pm->thaw_noirq(dev); } else { ret = platform_legacy_resume_early(dev); } @@ -836,7 +839,10 @@ static int platform_pm_poweroff(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->poweroff) ret = drv->pm->poweroff(dev); } else { @@ -848,16 +854,15 @@ static int platform_pm_poweroff(struct device *dev) static int platform_pm_poweroff_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->poweroff_noirq) - ret = pdrv->pm->poweroff_noirq(dev); + if (drv->pm) { + if (drv->pm->poweroff_noirq) + ret = drv->pm->poweroff_noirq(dev); } else { ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE); } @@ -870,7 +875,10 @@ static int platform_pm_restore(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->restore) ret = drv->pm->restore(dev); } else { @@ -882,16 +890,15 @@ static int platform_pm_restore(struct device *dev) static int platform_pm_restore_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->restore_noirq) - ret = pdrv->pm->restore_noirq(dev); + if (drv->pm) { + if (drv->pm->restore_noirq) + ret = drv->pm->restore_noirq(dev); } else { ret = platform_legacy_resume_early(dev); } @@ -912,17 +919,15 @@ static int platform_pm_restore_noirq(struct device *dev) #endif /* !CONFIG_HIBERNATION */ -static struct pm_ext_ops platform_pm_ops = { - .base = { - .prepare = platform_pm_prepare, - .complete = platform_pm_complete, - .suspend = platform_pm_suspend, - .resume = platform_pm_resume, - .freeze = platform_pm_freeze, - .thaw = platform_pm_thaw, - .poweroff = platform_pm_poweroff, - .restore = platform_pm_restore, - }, +static struct dev_pm_ops platform_dev_pm_ops = { + .prepare = platform_pm_prepare, + .complete = platform_pm_complete, + .suspend = platform_pm_suspend, + .resume = platform_pm_resume, + .freeze = platform_pm_freeze, + .thaw = platform_pm_thaw, + .poweroff = platform_pm_poweroff, + .restore = platform_pm_restore, .suspend_noirq = platform_pm_suspend_noirq, .resume_noirq = platform_pm_resume_noirq, .freeze_noirq = platform_pm_freeze_noirq, @@ -931,7 +936,7 @@ static struct pm_ext_ops platform_pm_ops = { .restore_noirq = platform_pm_restore_noirq, }; -#define PLATFORM_PM_OPS_PTR &platform_pm_ops +#define PLATFORM_PM_OPS_PTR (&platform_dev_pm_ops) #else /* !CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 692c20b..a8e4dcb 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -112,7 +112,8 @@ void device_pm_remove(struct device *dev) * @ops: PM operations to choose from. * @state: PM transition of the system being carried out. */ -static int pm_op(struct device *dev, struct pm_ops *ops, pm_message_t state) +static int pm_op(struct device *dev, struct dev_pm_ops *ops, + pm_message_t state) { int error = 0; @@ -174,7 +175,7 @@ static int pm_op(struct device *dev, struct pm_ops *ops, pm_message_t state) * The operation is executed with interrupts disabled by the only remaining * functional CPU in the system. */ -static int pm_noirq_op(struct device *dev, struct pm_ext_ops *ops, +static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops, pm_message_t state) { int error = 0; @@ -354,7 +355,7 @@ static int resume_device(struct device *dev, pm_message_t state) if (dev->bus) { if (dev->bus->pm) { pm_dev_dbg(dev, state, ""); - error = pm_op(dev, &dev->bus->pm->base, state); + error = pm_op(dev, dev->bus->pm, state); } else if (dev->bus->resume) { pm_dev_dbg(dev, state, "legacy "); error = dev->bus->resume(dev); @@ -451,9 +452,9 @@ static void complete_device(struct device *dev, pm_message_t state) dev->type->pm->complete(dev); } - if (dev->bus && dev->bus->pm && dev->bus->pm->base.complete) { + if (dev->bus && dev->bus->pm && dev->bus->pm->complete) { pm_dev_dbg(dev, state, "completing "); - dev->bus->pm->base.complete(dev); + dev->bus->pm->complete(dev); } up(&dev->sem); @@ -624,7 +625,7 @@ static int suspend_device(struct device *dev, pm_message_t state) if (dev->bus) { if (dev->bus->pm) { pm_dev_dbg(dev, state, ""); - error = pm_op(dev, &dev->bus->pm->base, state); + error = pm_op(dev, dev->bus->pm, state); } else if (dev->bus->suspend) { pm_dev_dbg(dev, state, "legacy "); error = dev->bus->suspend(dev, state); @@ -685,10 +686,10 @@ static int prepare_device(struct device *dev, pm_message_t state) down(&dev->sem); - if (dev->bus && dev->bus->pm && dev->bus->pm->base.prepare) { + if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) { pm_dev_dbg(dev, state, "preparing "); - error = dev->bus->pm->base.prepare(dev); - suspend_report_result(dev->bus->pm->base.prepare, error); + error = dev->bus->pm->prepare(dev); + suspend_report_result(dev->bus->pm->prepare, error); if (error) goto End; } -- cgit v1.1 From 1e0b2cf933ebf32494eba3f668859ba57f06a951 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 30 Oct 2008 01:36:48 +0100 Subject: driver core: struct device - replace bus_id with dev_name(), dev_set_name() Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/attribute_container.c | 2 +- drivers/base/bus.c | 12 ++++++------ drivers/base/core.c | 36 ++++++++++++++++++------------------ drivers/base/dd.c | 12 ++++++------ drivers/base/firmware_class.c | 8 +------- drivers/base/isa.c | 7 +++---- drivers/base/platform.c | 15 +++++++-------- drivers/base/power/main.c | 2 +- drivers/base/power/trace.c | 4 ++-- 9 files changed, 45 insertions(+), 53 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index f57652d..b9cda05 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -167,7 +167,7 @@ attribute_container_add_device(struct device *dev, ic->classdev.parent = get_device(dev); ic->classdev.class = cont->class; cont->class->dev_release = attribute_container_release; - strcpy(ic->classdev.bus_id, dev->bus_id); + dev_set_name(&ic->classdev, dev_name(dev)); if (fn) fn(cont, dev, &ic->classdev); else diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 5aee1c0..83f32b8 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -333,7 +333,7 @@ static int match_name(struct device *dev, void *data) { const char *name = data; - return sysfs_streq(name, dev->bus_id); + return sysfs_streq(name, dev_name(dev)); } /** @@ -461,12 +461,12 @@ int bus_add_device(struct device *dev) int error = 0; if (bus) { - pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id); + 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->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out_id; error = sysfs_create_link(&dev->kobj, @@ -482,7 +482,7 @@ int bus_add_device(struct device *dev) out_deprecated: sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: - sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id); + sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); out_id: device_remove_attrs(bus, dev); out_put: @@ -526,13 +526,13 @@ void bus_remove_device(struct device *dev) sysfs_remove_link(&dev->kobj, "subsystem"); remove_deprecated_bus_links(dev); sysfs_remove_link(&dev->bus->p->devices_kset->kobj, - dev->bus_id); + dev_name(dev)); device_remove_attrs(dev->bus, dev); if (klist_node_attached(&dev->knode_bus)) klist_del(&dev->knode_bus); pr_debug("bus: '%s': remove device %s\n", - dev->bus->name, dev->bus_id); + dev->bus->name, dev_name(dev)); device_release_driver(dev); bus_put(dev->bus); } diff --git a/drivers/base/core.c b/drivers/base/core.c index 8c2cc26..14aa2b6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -119,7 +119,7 @@ static void device_release(struct kobject *kobj) else WARN(1, KERN_ERR "Device '%s' does not have a release() " "function, it is broken and must be fixed.\n", - dev->bus_id); + dev_name(dev)); } static struct kobj_type device_ktype = { @@ -209,7 +209,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, retval = dev->bus->uevent(dev, env); if (retval) pr_debug("device: '%s': %s: bus uevent() returned %d\n", - dev->bus_id, __func__, retval); + dev_name(dev), __func__, retval); } /* have the class specific function add its stuff */ @@ -217,7 +217,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("device: '%s': %s: class uevent() " - "returned %d\n", dev->bus_id, + "returned %d\n", dev_name(dev), __func__, retval); } @@ -226,7 +226,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, retval = dev->type->uevent(dev, env); if (retval) pr_debug("device: '%s': %s: dev_type uevent() " - "returned %d\n", dev->bus_id, + "returned %d\n", dev_name(dev), __func__, retval); } @@ -672,7 +672,7 @@ static int device_add_class_symlinks(struct device *dev) if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) { error = sysfs_create_link(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out_subsys; } @@ -712,11 +712,11 @@ out_busid: if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) sysfs_remove_link(&dev->class->p->class_subsys.kobj, - dev->bus_id); + dev_name(dev)); #else /* link in the class directory pointing to the device */ error = sysfs_create_link(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out_subsys; @@ -729,7 +729,7 @@ out_busid: return 0; out_busid: - sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev)); #endif out_subsys: @@ -758,12 +758,12 @@ static void device_remove_class_symlinks(struct device *dev) if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) sysfs_remove_link(&dev->class->p->class_subsys.kobj, - dev->bus_id); + dev_name(dev)); #else if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev)); #endif sysfs_remove_link(&dev->kobj, "subsystem"); @@ -866,7 +866,7 @@ int device_add(struct device *dev) if (!strlen(dev->bus_id)) goto done; - pr_debug("device: '%s': %s\n", dev->bus_id, __func__); + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); parent = get_device(dev->parent); setup_parent(dev, parent); @@ -876,7 +876,7 @@ int device_add(struct device *dev) set_dev_node(dev, dev_to_node(parent)); /* first, register with generic layer. */ - error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); + error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev)); if (error) goto Error; @@ -1086,7 +1086,7 @@ void device_del(struct device *dev) */ void device_unregister(struct device *dev) { - pr_debug("device: '%s': %s\n", dev->bus_id, __func__); + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); device_del(dev); put_device(dev); } @@ -1199,7 +1199,7 @@ EXPORT_SYMBOL_GPL(device_remove_file); static void device_create_release(struct device *dev) { - pr_debug("device: '%s': %s\n", dev->bus_id, __func__); + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); kfree(dev); } @@ -1344,7 +1344,7 @@ int device_rename(struct device *dev, char *new_name) if (!dev) return -EINVAL; - pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id, + pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev), __func__, new_name); #ifdef CONFIG_SYSFS_DEPRECATED @@ -1381,7 +1381,7 @@ int device_rename(struct device *dev, char *new_name) #else if (dev->class) { error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out; sysfs_remove_link(&dev->class->p->class_subsys.kobj, @@ -1459,8 +1459,8 @@ int device_move(struct device *dev, struct device *new_parent) new_parent = get_device(new_parent); new_parent_kobj = get_device_parent(dev, new_parent); - pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, - __func__, new_parent ? new_parent->bus_id : ""); + pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), + __func__, new_parent ? dev_name(new_parent) : ""); error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { cleanup_glue_dir(dev, new_parent_kobj); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 20febc0..17a8e45 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -34,7 +34,7 @@ static void driver_bound(struct device *dev) return; } - pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id, + pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev), __func__, dev->driver->name); if (dev->bus) @@ -104,13 +104,13 @@ static int really_probe(struct device *dev, struct device_driver *drv) atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", - drv->bus->name, __func__, drv->name, dev->bus_id); + drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", - __func__, dev->bus_id); + __func__, dev_name(dev)); goto probe_failed; } @@ -127,7 +127,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) driver_bound(dev); ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", - drv->bus->name, __func__, dev->bus_id, drv->name); + drv->bus->name, __func__, dev_name(dev), drv->name); goto done; probe_failed: @@ -139,7 +139,7 @@ probe_failed: /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, ret); + drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next driver can try @@ -194,7 +194,7 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) goto done; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", - drv->bus->name, __func__, dev->bus_id, drv->name); + drv->bus->name, __func__, dev_name(dev), drv->name); ret = really_probe(dev, drv); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b7e5710..44699d9 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -291,12 +291,6 @@ firmware_class_timeout(u_long data) fw_load_abort(fw_priv); } -static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) -{ - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); -} - static int fw_register_device(struct device **dev_p, const char *fw_name, struct device *device) { @@ -321,7 +315,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, fw_priv->timeout.data = (u_long) fw_priv; init_timer(&fw_priv->timeout); - fw_setup_device_id(f_dev, device); + dev_set_name(f_dev, dev_name(device)); f_dev->parent = device; f_dev->class = &firmware_class; dev_set_drvdata(f_dev, fw_priv); diff --git a/drivers/base/isa.c b/drivers/base/isa.c index efd5775..479694b 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -11,7 +11,7 @@ #include static struct device isa_bus = { - .bus_id = "isa" + .init_name = "isa" }; struct isa_dev { @@ -135,9 +135,8 @@ int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) isa_dev->dev.parent = &isa_bus; isa_dev->dev.bus = &isa_bus_type; - snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u", - isa_driver->driver.name, id); - + dev_set_name(&isa_dev->dev, "%s.%u", + isa_driver->driver.name, id); isa_dev->dev.platform_data = isa_driver; isa_dev->dev.release = isa_dev_release; isa_dev->id = id; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 6c743b6..349a101 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -24,7 +24,7 @@ driver)) struct device platform_bus = { - .bus_id = "platform", + .init_name = "platform", }; EXPORT_SYMBOL_GPL(platform_bus); @@ -242,16 +242,15 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) - snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, - pdev->id); + dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); else - strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); + dev_set_name(&pdev->dev, pdev->name); for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; if (r->name == NULL) - r->name = pdev->dev.bus_id; + r->name = dev_name(&pdev->dev); p = r->parent; if (!p) { @@ -264,14 +263,14 @@ int platform_device_add(struct platform_device *pdev) if (p && insert_resource(p, r)) { printk(KERN_ERR "%s: failed to claim resource %d\n", - pdev->dev.bus_id, i); + dev_name(&pdev->dev), i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s\n", - pdev->dev.bus_id, pdev->dev.parent->bus_id); + dev_name(&pdev->dev), dev_name(pdev->dev.parent)); ret = device_add(&pdev->dev); if (ret == 0) @@ -607,7 +606,7 @@ static int platform_match(struct device *dev, struct device_driver *drv) struct platform_device *pdev; pdev = container_of(dev, struct platform_device, dev); - return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); + return (strcmp(pdev->name, drv->name) == 0); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a8e4dcb..670c9d6 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -76,7 +76,7 @@ void device_pm_add(struct device *dev) if (dev->parent) { if (dev->parent->power.status >= DPM_SUSPENDING) dev_warn(dev, "parent %s should not be sleeping\n", - dev->parent->bus_id); + dev_name(dev->parent)); } else if (transition_started) { /* * We refuse to register parentless devices while a PM diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 2aa6e8f..0a1a2c4 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -140,7 +140,7 @@ static unsigned int hash_string(unsigned int seed, const char *data, unsigned in void set_trace_device(struct device *dev) { - dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH); + dev_hash_value = hash_string(DEVSEED, dev_name(dev), DEVHASH); } EXPORT_SYMBOL(set_trace_device); @@ -192,7 +192,7 @@ static int show_dev_hash(unsigned int value) while (entry != &dpm_list) { struct device * dev = to_device(entry); - unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH); + unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH); if (hash == value) { dev_info(dev, "hash matches\n"); match++; -- cgit v1.1 From 2831fe6f9cc4e16c103504ee09a47a084297c0f3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Dec 2008 12:23:36 -0800 Subject: driver core: create a private portion of struct device This is to be used to move things out of struct device that no code outside of the driver core should ever touch. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 12 ++++++++++++ drivers/base/core.c | 8 ++++++++ 2 files changed, 20 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/base.h b/drivers/base/base.h index 0a5f055..6b20809 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -63,6 +63,18 @@ struct class_private { #define to_class(obj) \ container_of(obj, struct class_private, class_subsys.kobj) +/** + * struct device_private - structure to hold the private to the driver core portions of the device structure. + * + * @device - pointer back to the struct class that this structure is + * associated with. + * + * Nothing outside of the driver core should ever touch these fields. + */ +struct device_private { + struct device *device; +}; + /* initialisation functions */ extern int devices_init(void); extern int buses_init(void); diff --git a/drivers/base/core.c b/drivers/base/core.c index 14aa2b6..6657787 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -109,6 +109,7 @@ static struct sysfs_ops dev_sysfs_ops = { static void device_release(struct kobject *kobj) { struct device *dev = to_dev(kobj); + struct device_private *p = dev->p; if (dev->release) dev->release(dev); @@ -120,6 +121,7 @@ static void device_release(struct kobject *kobj) WARN(1, KERN_ERR "Device '%s' does not have a release() " "function, it is broken and must be fixed.\n", dev_name(dev)); + kfree(p); } static struct kobj_type device_ktype = { @@ -536,6 +538,12 @@ static void klist_children_put(struct klist_node *n) */ void device_initialize(struct device *dev) { + dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); + if (!dev->p) { + WARN_ON(1); + return; + } + dev->p->device = dev; dev->kobj.kset = devices_kset; kobject_init(&dev->kobj, &device_ktype); klist_init(&dev->klist_children, klist_children_get, -- cgit v1.1 From 11c3b5c3e08f4d855cbef52883c266b9ab9df879 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Dec 2008 12:24:56 -0800 Subject: driver core: move klist_children into private structure Nothing outside of the driver core should ever touch klist_children, or knode_parent, so move them out of the public eye. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 6 ++++++ drivers/base/core.c | 37 ++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 13 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/base.h b/drivers/base/base.h index 6b20809..f5cf31c 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -66,14 +66,20 @@ struct class_private { /** * struct device_private - structure to hold the private to the driver core portions of the device structure. * + * @klist_children - klist containing all children of this device + * @knode_parent - node in sibling list * @device - pointer back to the struct class that this structure is * associated with. * * Nothing outside of the driver core should ever touch these fields. */ struct device_private { + struct klist klist_children; + struct klist_node knode_parent; struct device *device; }; +#define to_device_private_parent(obj) \ + container_of(obj, struct device_private, knode_parent) /* initialisation functions */ extern int devices_init(void); diff --git a/drivers/base/core.c b/drivers/base/core.c index 6657787..180ff84 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -509,14 +509,16 @@ EXPORT_SYMBOL_GPL(device_schedule_callback_owner); static void klist_children_get(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_parent); + struct device_private *p = to_device_private_parent(n); + struct device *dev = p->device; get_device(dev); } static void klist_children_put(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_parent); + struct device_private *p = to_device_private_parent(n); + struct device *dev = p->device; put_device(dev); } @@ -546,7 +548,7 @@ void device_initialize(struct device *dev) dev->p->device = dev; dev->kobj.kset = devices_kset; kobject_init(&dev->kobj, &device_ktype); - klist_init(&dev->klist_children, klist_children_get, + klist_init(&dev->p->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); @@ -927,7 +929,8 @@ int device_add(struct device *dev) kobject_uevent(&dev->kobj, KOBJ_ADD); bus_attach_device(dev); if (parent) - klist_add_tail(&dev->knode_parent, &parent->klist_children); + klist_add_tail(&dev->p->knode_parent, + &parent->p->klist_children); if (dev->class) { mutex_lock(&dev->class->p->class_mutex); @@ -1038,7 +1041,7 @@ void device_del(struct device *dev) device_pm_remove(dev); dpm_sysfs_remove(dev); if (parent) - klist_del(&dev->knode_parent); + klist_del(&dev->p->knode_parent); if (MAJOR(dev->devt)) { device_remove_sys_dev_entry(dev); device_remove_file(dev, &devt_attr); @@ -1102,7 +1105,14 @@ void device_unregister(struct device *dev) static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - return n ? container_of(n, struct device, knode_parent) : NULL; + struct device *dev = NULL; + struct device_private *p; + + if (n) { + p = to_device_private_parent(n); + dev = p->device; + } + return dev; } /** @@ -1124,7 +1134,7 @@ int device_for_each_child(struct device *parent, void *data, struct device *child; int error = 0; - klist_iter_init(&parent->klist_children, &i); + klist_iter_init(&parent->p->klist_children, &i); while ((child = next_device(&i)) && !error) error = fn(child, data); klist_iter_exit(&i); @@ -1155,7 +1165,7 @@ struct device *device_find_child(struct device *parent, void *data, if (!parent) return NULL; - klist_iter_init(&parent->klist_children, &i); + klist_iter_init(&parent->p->klist_children, &i); while ((child = next_device(&i))) if (match(child, data) && get_device(child)) break; @@ -1478,9 +1488,10 @@ int device_move(struct device *dev, struct device *new_parent) old_parent = dev->parent; dev->parent = new_parent; if (old_parent) - klist_remove(&dev->knode_parent); + klist_remove(&dev->p->knode_parent); if (new_parent) { - klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + klist_add_tail(&dev->p->knode_parent, + &new_parent->p->klist_children); set_dev_node(dev, dev_to_node(new_parent)); } @@ -1492,11 +1503,11 @@ int device_move(struct device *dev, struct device *new_parent) device_move_class_links(dev, new_parent, old_parent); if (!kobject_move(&dev->kobj, &old_parent->kobj)) { if (new_parent) - klist_remove(&dev->knode_parent); + klist_remove(&dev->p->knode_parent); dev->parent = old_parent; if (old_parent) { - klist_add_tail(&dev->knode_parent, - &old_parent->klist_children); + klist_add_tail(&dev->p->knode_parent, + &old_parent->p->klist_children); set_dev_node(dev, dev_to_node(old_parent)); } } -- cgit v1.1 From 93e746db183b3bdbbda67900f79b5835f9cb388f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Dec 2008 12:25:49 -0800 Subject: driver core: move knode_driver into private structure Nothing outside of the driver core should ever touch knode_driver, so move it out of the public eye. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 4 ++++ drivers/base/dd.c | 13 ++++++++----- drivers/base/driver.c | 13 ++++++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/base.h b/drivers/base/base.h index f5cf31c..8af0bb2 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -68,6 +68,7 @@ struct class_private { * * @klist_children - klist containing all children of this device * @knode_parent - node in sibling list + * @knode_driver - node in driver list * @device - pointer back to the struct class that this structure is * associated with. * @@ -76,10 +77,13 @@ struct class_private { struct device_private { struct klist klist_children; struct klist_node knode_parent; + struct klist_node knode_driver; struct device *device; }; #define to_device_private_parent(obj) \ container_of(obj, struct device_private, knode_parent) +#define to_device_private_driver(obj) \ + container_of(obj, struct device_private, knode_driver) /* initialisation functions */ extern int devices_init(void); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 17a8e45..bb5f1eb 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -28,7 +28,7 @@ static void driver_bound(struct device *dev) { - if (klist_node_attached(&dev->knode_driver)) { + if (klist_node_attached(&dev->p->knode_driver)) { printk(KERN_WARNING "%s: device %s already bound\n", __func__, kobject_name(&dev->kobj)); return; @@ -41,7 +41,7 @@ static void driver_bound(struct device *dev) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); - klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices); + klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); } static int driver_sysfs_add(struct device *dev) @@ -311,7 +311,7 @@ static void __device_release_driver(struct device *dev) drv->remove(dev); devres_release_all(dev); dev->driver = NULL; - klist_remove(&dev->knode_driver); + klist_remove(&dev->p->knode_driver); } } @@ -341,6 +341,7 @@ EXPORT_SYMBOL_GPL(device_release_driver); */ void driver_detach(struct device_driver *drv) { + struct device_private *dev_prv; struct device *dev; for (;;) { @@ -349,8 +350,10 @@ void driver_detach(struct device_driver *drv) spin_unlock(&drv->p->klist_devices.k_lock); break; } - dev = list_entry(drv->p->klist_devices.k_list.prev, - struct device, knode_driver.n_node); + dev_prv = list_entry(drv->p->klist_devices.k_list.prev, + struct device_private, + knode_driver.n_node); + dev = dev_prv->device; get_device(dev); spin_unlock(&drv->p->klist_devices.k_lock); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 1e2bda7..b76cc69 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -19,7 +19,14 @@ static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - return n ? container_of(n, struct device, knode_driver) : NULL; + struct device *dev = NULL; + struct device_private *dev_prv; + + if (n) { + dev_prv = to_device_private_driver(n); + dev = dev_prv->device; + } + return dev; } /** @@ -42,7 +49,7 @@ int driver_for_each_device(struct device_driver *drv, struct device *start, return -EINVAL; klist_iter_init_node(&drv->p->klist_devices, &i, - start ? &start->knode_driver : NULL); + start ? &start->p->knode_driver : NULL); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); @@ -76,7 +83,7 @@ struct device *driver_find_device(struct device_driver *drv, return NULL; klist_iter_init_node(&drv->p->klist_devices, &i, - (start ? &start->knode_driver : NULL)); + (start ? &start->p->knode_driver : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) break; -- cgit v1.1 From b9daa99ee533578e3f88231e7a16784dcb44ec42 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 16 Dec 2008 12:26:21 -0800 Subject: driver core: move knode_bus into private structure Nothing outside of the driver core should ever touch knode_bus, so move it out of the public eye. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 4 ++++ drivers/base/bus.c | 40 +++++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 13 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/base.h b/drivers/base/base.h index 8af0bb2..b676f8f 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -69,6 +69,7 @@ struct class_private { * @klist_children - klist containing all children of this device * @knode_parent - node in sibling list * @knode_driver - node in driver list + * @knode_bus - node in bus list * @device - pointer back to the struct class that this structure is * associated with. * @@ -78,12 +79,15 @@ struct device_private { struct klist klist_children; struct klist_node knode_parent; struct klist_node knode_driver; + struct klist_node knode_bus; struct device *device; }; #define to_device_private_parent(obj) \ container_of(obj, struct device_private, knode_parent) #define to_device_private_driver(obj) \ container_of(obj, struct device_private, knode_driver) +#define to_device_private_bus(obj) \ + container_of(obj, struct device_private, knode_bus) /* initialisation functions */ extern int devices_init(void); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 83f32b8..0f0a504 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -253,7 +253,14 @@ static ssize_t store_drivers_probe(struct bus_type *bus, static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - return n ? container_of(n, struct device, knode_bus) : NULL; + struct device *dev = NULL; + struct device_private *dev_prv; + + if (n) { + dev_prv = to_device_private_bus(n); + dev = dev_prv->device; + } + return dev; } /** @@ -286,7 +293,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start, return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->knode_bus : NULL)); + (start ? &start->p->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); @@ -320,7 +327,7 @@ struct device *bus_find_device(struct bus_type *bus, return NULL; klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->knode_bus : NULL)); + (start ? &start->p->knode_bus : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) break; @@ -507,7 +514,8 @@ void bus_attach_device(struct device *dev) 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->p->knode_bus, + &bus->p->klist_devices); } } @@ -528,8 +536,8 @@ void bus_remove_device(struct device *dev) sysfs_remove_link(&dev->bus->p->devices_kset->kobj, dev_name(dev)); device_remove_attrs(dev->bus, dev); - if (klist_node_attached(&dev->knode_bus)) - klist_del(&dev->knode_bus); + if (klist_node_attached(&dev->p->knode_bus)) + klist_del(&dev->p->knode_bus); pr_debug("bus: '%s': remove device %s\n", dev->bus->name, dev_name(dev)); @@ -831,14 +839,16 @@ static void bus_remove_attrs(struct bus_type *bus) static void klist_devices_get(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_bus); + struct device_private *dev_prv = to_device_private_bus(n); + struct device *dev = dev_prv->device; get_device(dev); } static void klist_devices_put(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_bus); + struct device_private *dev_prv = to_device_private_bus(n); + struct device *dev = dev_prv->device; put_device(dev); } @@ -993,18 +1003,20 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list { struct list_head *pos; struct klist_node *n; + struct device_private *dev_prv; struct device *b; list_for_each(pos, list) { n = container_of(pos, struct klist_node, n_node); - b = container_of(n, struct device, knode_bus); + dev_prv = to_device_private_bus(n); + b = dev_prv->device; if (compare(a, b) <= 0) { - list_move_tail(&a->knode_bus.n_node, - &b->knode_bus.n_node); + list_move_tail(&a->p->knode_bus.n_node, + &b->p->knode_bus.n_node); return; } } - list_move_tail(&a->knode_bus.n_node, list); + list_move_tail(&a->p->knode_bus.n_node, list); } void bus_sort_breadthfirst(struct bus_type *bus, @@ -1014,6 +1026,7 @@ void bus_sort_breadthfirst(struct bus_type *bus, LIST_HEAD(sorted_devices); struct list_head *pos, *tmp; struct klist_node *n; + struct device_private *dev_prv; struct device *dev; struct klist *device_klist; @@ -1022,7 +1035,8 @@ void bus_sort_breadthfirst(struct bus_type *bus, spin_lock(&device_klist->k_lock); list_for_each_safe(pos, tmp, &device_klist->k_list) { n = container_of(pos, struct klist_node, n_node); - dev = container_of(n, struct device, knode_bus); + dev_prv = to_device_private_bus(n); + dev = dev_prv->device; device_insertion_sort_klist(dev, &sorted_devices, compare); } list_splice(&sorted_devices, &device_klist->k_list); -- cgit v1.1 From ec0676ee28528dc8dda13a93ee4b1f215a0c2f9d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 5 Dec 2008 14:10:31 -0500 Subject: Driver core: move the bus notifier call points This patch (as1184) changes the location of the notifications in device_add() and device_del(). Now the BUS_NOTIFY_ADD_DEVICE message is sent after dpm_sysfs_add(), which is necessary for clients that want to add attributes to the power/ subdirectory. The BUS_NOTIFY_DEL_DEVICE message is correspondingly moved before dpm_sysfs_remove(). Signed-off-by: Alan Stern Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index 180ff84..ee555d7 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -894,11 +894,6 @@ int device_add(struct device *dev) if (platform_notify) platform_notify(dev); - /* notify clients of device entry (new way) */ - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_ADD_DEVICE, dev); - error = device_create_file(dev, &uevent_attr); if (error) goto attrError; @@ -926,6 +921,14 @@ int device_add(struct device *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_attach_device(dev); if (parent) @@ -951,9 +954,6 @@ done: DPMError: 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); @@ -1038,6 +1038,12 @@ void device_del(struct device *dev) struct device *parent = dev->parent; struct class_interface *class_intf; + /* Notify clients of device removal. This call must come + * before dpm_sysfs_remove(). + */ + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); device_pm_remove(dev); dpm_sysfs_remove(dev); if (parent) @@ -1075,9 +1081,6 @@ void device_del(struct device *dev) */ if (platform_notify_remove) platform_notify_remove(dev); - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_DEL_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); cleanup_device_parent(dev); kobject_del(&dev->kobj); -- cgit v1.1 From 7232800ba8aca1c070d43a81cc49991f230b5da1 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 17 Dec 2008 23:15:35 +0800 Subject: driver core:fix duplicate removing driver link in __device_release_driver In __device_release_driver(),driver_sysfs_remove() has removed the driver link under device dir in sysfs, but sysfs_remove_link() is called again to do such thing. Remove the duplicate call to sys_remove_link(). Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index bb5f1eb..6fdaf76 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -298,7 +298,6 @@ static void __device_release_driver(struct device *dev) drv = dev->driver; if (drv) { driver_sysfs_remove(dev); - sysfs_remove_link(&dev->kobj, "driver"); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, -- cgit v1.1 From 0aa0dc41bfd993491c2344870eee7a3b218551fb Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 15 Dec 2008 12:58:26 +0000 Subject: driver core: add root_device_register() Add support for allocating root device objects which group device objects under /sys/devices directories. Also add a sysfs 'module' symlink which points to the owner of the root device object. This symlink will be used in virtio to allow userspace to determine which virtio bus implementation a given device is associated with. [Includes suggestions from Cornelia Huck] Signed-off-by: Mark McLoughlin Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index ee555d7..61df508 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1217,6 +1217,97 @@ EXPORT_SYMBOL_GPL(put_device); EXPORT_SYMBOL_GPL(device_create_file); EXPORT_SYMBOL_GPL(device_remove_file); +struct root_device +{ + struct device dev; + struct module *owner; +}; + +#define to_root_device(dev) container_of(dev, struct root_device, dev) + +static void root_device_release(struct device *dev) +{ + kfree(to_root_device(dev)); +} + +/** + * __root_device_register - allocate and register a root device + * @name: root device name + * @owner: owner module of the root device, usually THIS_MODULE + * + * This function allocates a root device and registers it + * using device_register(). In order to free the returned + * device, use root_device_unregister(). + * + * Root devices are dummy devices which allow other devices + * to be grouped under /sys/devices. Use this function to + * allocate a root device and then use it as the parent of + * any device which should appear under /sys/devices/{name} + * + * The /sys/devices/{name} directory will also contain a + * 'module' symlink which points to the @owner directory + * in sysfs. + * + * Note: You probably want to use root_device_register(). + */ +struct device *__root_device_register(const char *name, struct module *owner) +{ + struct root_device *root; + int err = -ENOMEM; + + root = kzalloc(sizeof(struct root_device), GFP_KERNEL); + if (!root) + return ERR_PTR(err); + + err = dev_set_name(&root->dev, name); + if (err) { + kfree(root); + return ERR_PTR(err); + } + + root->dev.release = root_device_release; + + err = device_register(&root->dev); + if (err) { + put_device(&root->dev); + return ERR_PTR(err); + } + +#ifdef CONFIG_MODULE /* gotta find a "cleaner" way to do this */ + if (owner) { + struct module_kobject *mk = &owner->mkobj; + + err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module"); + if (err) { + device_unregister(&root->dev); + return ERR_PTR(err); + } + root->owner = owner; + } +#endif + + return &root->dev; +} +EXPORT_SYMBOL_GPL(__root_device_register); + +/** + * root_device_unregister - unregister and free a root device + * @root: device going away. + * + * This function unregisters and cleans up a device that was created by + * root_device_register(). + */ +void root_device_unregister(struct device *dev) +{ + struct root_device *root = to_root_device(dev); + + if (root->owner) + sysfs_remove_link(&root->dev.kobj, "module"); + + device_unregister(dev); +} +EXPORT_SYMBOL_GPL(root_device_unregister); + static void device_create_release(struct device *dev) { -- cgit v1.1