X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fbase%2Fsys.c;h=6fc23ab127bd52abd01f10eb55136a7c3057a12b;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=9d10500cd961be44a74e178b3f4722f841dfd861;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 9d10500cd..6fc23ab12 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -20,7 +20,11 @@ #include #include #include +#include +#include +#include +#include "base.h" extern struct subsystem devices_subsys; @@ -36,7 +40,7 @@ sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer) if (sysdev_attr->show) return sysdev_attr->show(sysdev, buffer); - return 0; + return -EIO; } @@ -49,7 +53,7 @@ sysdev_store(struct kobject * kobj, struct attribute * attr, if (sysdev_attr->store) return sysdev_attr->store(sysdev, buffer, count); - return 0; + return -EIO; } static struct sysfs_ops sysfs_ops = { @@ -73,13 +77,13 @@ void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a) sysfs_remove_file(&s->kobj, &a->attr); } -EXPORT_SYMBOL(sysdev_create_file); -EXPORT_SYMBOL(sysdev_remove_file); +EXPORT_SYMBOL_GPL(sysdev_create_file); +EXPORT_SYMBOL_GPL(sysdev_remove_file); /* * declare system_subsys */ -decl_subsys(system, &ktype_sysdev, NULL); +static decl_subsys(system, &ktype_sysdev, NULL); int sysdev_class_register(struct sysdev_class * cls) { @@ -98,11 +102,12 @@ void sysdev_class_unregister(struct sysdev_class * cls) kset_unregister(&cls->kset); } -EXPORT_SYMBOL(sysdev_class_register); -EXPORT_SYMBOL(sysdev_class_unregister); +EXPORT_SYMBOL_GPL(sysdev_class_register); +EXPORT_SYMBOL_GPL(sysdev_class_unregister); -static LIST_HEAD(global_drivers); +static LIST_HEAD(sysdev_drivers); +static DECLARE_MUTEX(sysdev_drivers_lock); /** * sysdev_driver_register - Register auxillary driver @@ -112,14 +117,14 @@ static LIST_HEAD(global_drivers); * If @cls is valid, then @drv is inserted into @cls->drivers to be * called on each operation on devices of that class. The refcount * of @cls is incremented. - * Otherwise, @drv is inserted into global_drivers, and called for + * Otherwise, @drv is inserted into sysdev_drivers, and called for * each device. */ int sysdev_driver_register(struct sysdev_class * cls, struct sysdev_driver * drv) { - down_write(&system_subsys.rwsem); + down(&sysdev_drivers_lock); if (cls && kset_get(&cls->kset)) { list_add_tail(&drv->entry, &cls->drivers); @@ -130,8 +135,8 @@ int sysdev_driver_register(struct sysdev_class * cls, drv->add(dev); } } else - list_add_tail(&drv->entry, &global_drivers); - up_write(&system_subsys.rwsem); + list_add_tail(&drv->entry, &sysdev_drivers); + up(&sysdev_drivers_lock); return 0; } @@ -144,7 +149,7 @@ int sysdev_driver_register(struct sysdev_class * cls, void sysdev_driver_unregister(struct sysdev_class * cls, struct sysdev_driver * drv) { - down_write(&system_subsys.rwsem); + down(&sysdev_drivers_lock); list_del_init(&drv->entry); if (cls) { if (drv->remove) { @@ -154,11 +159,11 @@ void sysdev_driver_unregister(struct sysdev_class * cls, } kset_put(&cls->kset); } - up_write(&system_subsys.rwsem); + up(&sysdev_drivers_lock); } -EXPORT_SYMBOL(sysdev_driver_register); -EXPORT_SYMBOL(sysdev_driver_unregister); +EXPORT_SYMBOL_GPL(sysdev_driver_register); +EXPORT_SYMBOL_GPL(sysdev_driver_unregister); @@ -193,13 +198,13 @@ int sysdev_register(struct sys_device * sysdev) if (!error) { struct sysdev_driver * drv; - down_write(&system_subsys.rwsem); + down(&sysdev_drivers_lock); /* Generic notification is implicit, because it's that * code that should have called us. */ /* Notify global drivers */ - list_for_each_entry(drv, &global_drivers, entry) { + list_for_each_entry(drv, &sysdev_drivers, entry) { if (drv->add) drv->add(sysdev); } @@ -209,7 +214,7 @@ int sysdev_register(struct sys_device * sysdev) if (drv->add) drv->add(sysdev); } - up_write(&system_subsys.rwsem); + up(&sysdev_drivers_lock); } return error; } @@ -218,8 +223,8 @@ void sysdev_unregister(struct sys_device * sysdev) { struct sysdev_driver * drv; - down_write(&system_subsys.rwsem); - list_for_each_entry(drv, &global_drivers, entry) { + down(&sysdev_drivers_lock); + list_for_each_entry(drv, &sysdev_drivers, entry) { if (drv->remove) drv->remove(sysdev); } @@ -228,7 +233,7 @@ void sysdev_unregister(struct sys_device * sysdev) if (drv->remove) drv->remove(sysdev); } - up_write(&system_subsys.rwsem); + up(&sysdev_drivers_lock); kobject_unregister(&sysdev->kobj); } @@ -255,7 +260,7 @@ void sysdev_shutdown(void) pr_debug("Shutting Down System Devices\n"); - down_write(&system_subsys.rwsem); + down(&sysdev_drivers_lock); list_for_each_entry_reverse(cls, &system_subsys.kset.list, kset.kobj.entry) { struct sys_device * sysdev; @@ -268,7 +273,7 @@ void sysdev_shutdown(void) pr_debug(" %s\n", kobject_name(&sysdev->kobj)); /* Call global drivers first. */ - list_for_each_entry(drv, &global_drivers, entry) { + list_for_each_entry(drv, &sysdev_drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); } @@ -284,9 +289,30 @@ void sysdev_shutdown(void) cls->shutdown(sysdev); } } - up_write(&system_subsys.rwsem); + up(&sysdev_drivers_lock); } +static void __sysdev_resume(struct sys_device *dev) +{ + struct sysdev_class *cls = dev->cls; + struct sysdev_driver *drv; + + /* First, call the class-specific one */ + if (cls->resume) + cls->resume(dev); + + /* Call auxillary drivers next. */ + list_for_each_entry(drv, &cls->drivers, entry) { + if (drv->resume) + drv->resume(dev); + } + + /* Call global drivers. */ + list_for_each_entry(drv, &sysdev_drivers, entry) { + if (drv->resume) + drv->resume(dev); + } +} /** * sysdev_suspend - Suspend all system devices. @@ -301,41 +327,96 @@ void sysdev_shutdown(void) * all synchronization. */ -int sysdev_suspend(u32 state) +int sysdev_suspend(pm_message_t state) { struct sysdev_class * cls; + struct sys_device *sysdev, *err_dev; + struct sysdev_driver *drv, *err_drv; + int ret; pr_debug("Suspending System Devices\n"); list_for_each_entry_reverse(cls, &system_subsys.kset.list, kset.kobj.entry) { - struct sys_device * sysdev; pr_debug("Suspending type '%s':\n", kobject_name(&cls->kset.kobj)); list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); /* Call global drivers first. */ - list_for_each_entry(drv, &global_drivers, entry) { - if (drv->suspend) - drv->suspend(sysdev, state); + list_for_each_entry(drv, &sysdev_drivers, entry) { + if (drv->suspend) { + ret = drv->suspend(sysdev, state); + if (ret) + goto gbl_driver; + } } /* Call auxillary drivers next. */ list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->suspend) - drv->suspend(sysdev, state); + if (drv->suspend) { + ret = drv->suspend(sysdev, state); + if (ret) + goto aux_driver; + } } /* Now call the generic one */ - if (cls->suspend) - cls->suspend(sysdev, state); + if (cls->suspend) { + ret = cls->suspend(sysdev, state); + if (ret) + goto cls_driver; + } } } return 0; + /* resume current sysdev */ +cls_driver: + drv = NULL; + printk(KERN_ERR "Class suspend failed for %s\n", + kobject_name(&sysdev->kobj)); + +aux_driver: + if (drv) + printk(KERN_ERR "Class driver suspend failed for %s\n", + kobject_name(&sysdev->kobj)); + list_for_each_entry(err_drv, &cls->drivers, entry) { + if (err_drv == drv) + break; + if (err_drv->resume) + err_drv->resume(sysdev); + } + drv = NULL; + +gbl_driver: + if (drv) + printk(KERN_ERR "sysdev driver suspend failed for %s\n", + kobject_name(&sysdev->kobj)); + list_for_each_entry(err_drv, &sysdev_drivers, entry) { + if (err_drv == drv) + break; + if (err_drv->resume) + err_drv->resume(sysdev); + } + /* resume other sysdevs in current class */ + list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { + if (err_dev == sysdev) + break; + pr_debug(" %s\n", kobject_name(&err_dev->kobj)); + __sysdev_resume(err_dev); + } + + /* resume other classes */ + list_for_each_entry_continue(cls, &system_subsys.kset.list, + kset.kobj.entry) { + list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { + pr_debug(" %s\n", kobject_name(&err_dev->kobj)); + __sysdev_resume(err_dev); + } + } + return ret; } @@ -361,25 +442,9 @@ int sysdev_resume(void) kobject_name(&cls->kset.kobj)); list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* First, call the class-specific one */ - if (cls->resume) - cls->resume(sysdev); - - /* Call auxillary drivers next. */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->resume) - drv->resume(sysdev); - } - - /* Call global drivers. */ - list_for_each_entry(drv, &global_drivers, entry) { - if (drv->resume) - drv->resume(sysdev); - } - + __sysdev_resume(sysdev); } } return 0; @@ -392,5 +457,5 @@ int __init system_bus_init(void) return subsystem_register(&system_subsys); } -EXPORT_SYMBOL(sysdev_register); -EXPORT_SYMBOL(sysdev_unregister); +EXPORT_SYMBOL_GPL(sysdev_register); +EXPORT_SYMBOL_GPL(sysdev_unregister);