diff options
| author | Paul Mackerras <paulus@samba.org> | 2007-04-29 22:38:01 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2007-04-29 22:38:01 -0400 |
| commit | 49e1900d4cc2e7bcecb681fe60f0990bec2dcce8 (patch) | |
| tree | 253801ebf57e0a23856a2c7be129c2c178f62fdf /drivers/base | |
| parent | 34f6d749c0a328817d5e36274e53121c1db734dc (diff) | |
| parent | b9099ff63c75216d6ca10bce5a1abcd9293c27e6 (diff) | |
Merge branch 'linux-2.6' into for-2.6.22
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/attribute_container.c | 26 | ||||
| -rw-r--r-- | drivers/base/base.h | 2 | ||||
| -rw-r--r-- | drivers/base/bus.c | 112 | ||||
| -rw-r--r-- | drivers/base/class.c | 2 | ||||
| -rw-r--r-- | drivers/base/core.c | 293 | ||||
| -rw-r--r-- | drivers/base/dd.c | 66 | ||||
| -rw-r--r-- | drivers/base/dmapool.c | 14 | ||||
| -rw-r--r-- | drivers/base/driver.c | 20 | ||||
| -rw-r--r-- | drivers/base/firmware_class.c | 10 | ||||
| -rw-r--r-- | drivers/base/power/main.c | 3 | ||||
| -rw-r--r-- | drivers/base/power/resume.c | 13 | ||||
| -rw-r--r-- | drivers/base/power/shutdown.c | 2 | ||||
| -rw-r--r-- | drivers/base/power/suspend.c | 12 |
13 files changed, 389 insertions, 186 deletions
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 22220733f76f..1ec0654665cf 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c | |||
| @@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); | |||
| 62 | 62 | ||
| 63 | static struct list_head attribute_container_list; | 63 | static struct list_head attribute_container_list; |
| 64 | 64 | ||
| 65 | static DECLARE_MUTEX(attribute_container_mutex); | 65 | static DEFINE_MUTEX(attribute_container_mutex); |
| 66 | 66 | ||
| 67 | /** | 67 | /** |
| 68 | * attribute_container_register - register an attribute container | 68 | * attribute_container_register - register an attribute container |
| @@ -77,9 +77,9 @@ attribute_container_register(struct attribute_container *cont) | |||
| 77 | klist_init(&cont->containers,internal_container_klist_get, | 77 | klist_init(&cont->containers,internal_container_klist_get, |
| 78 | internal_container_klist_put); | 78 | internal_container_klist_put); |
| 79 | 79 | ||
| 80 | down(&attribute_container_mutex); | 80 | mutex_lock(&attribute_container_mutex); |
| 81 | list_add_tail(&cont->node, &attribute_container_list); | 81 | list_add_tail(&cont->node, &attribute_container_list); |
| 82 | up(&attribute_container_mutex); | 82 | mutex_unlock(&attribute_container_mutex); |
| 83 | 83 | ||
| 84 | return 0; | 84 | return 0; |
| 85 | } | 85 | } |
| @@ -94,7 +94,7 @@ int | |||
| 94 | attribute_container_unregister(struct attribute_container *cont) | 94 | attribute_container_unregister(struct attribute_container *cont) |
| 95 | { | 95 | { |
| 96 | int retval = -EBUSY; | 96 | int retval = -EBUSY; |
| 97 | down(&attribute_container_mutex); | 97 | mutex_lock(&attribute_container_mutex); |
| 98 | spin_lock(&cont->containers.k_lock); | 98 | spin_lock(&cont->containers.k_lock); |
| 99 | if (!list_empty(&cont->containers.k_list)) | 99 | if (!list_empty(&cont->containers.k_list)) |
| 100 | goto out; | 100 | goto out; |
| @@ -102,7 +102,7 @@ attribute_container_unregister(struct attribute_container *cont) | |||
| 102 | list_del(&cont->node); | 102 | list_del(&cont->node); |
| 103 | out: | 103 | out: |
| 104 | spin_unlock(&cont->containers.k_lock); | 104 | spin_unlock(&cont->containers.k_lock); |
| 105 | up(&attribute_container_mutex); | 105 | mutex_unlock(&attribute_container_mutex); |
| 106 | return retval; | 106 | return retval; |
| 107 | 107 | ||
| 108 | } | 108 | } |
| @@ -145,7 +145,7 @@ attribute_container_add_device(struct device *dev, | |||
| 145 | { | 145 | { |
| 146 | struct attribute_container *cont; | 146 | struct attribute_container *cont; |
| 147 | 147 | ||
| 148 | down(&attribute_container_mutex); | 148 | mutex_lock(&attribute_container_mutex); |
| 149 | list_for_each_entry(cont, &attribute_container_list, node) { | 149 | list_for_each_entry(cont, &attribute_container_list, node) { |
| 150 | struct internal_container *ic; | 150 | struct internal_container *ic; |
| 151 | 151 | ||
| @@ -173,7 +173,7 @@ attribute_container_add_device(struct device *dev, | |||
| 173 | attribute_container_add_class_device(&ic->classdev); | 173 | attribute_container_add_class_device(&ic->classdev); |
| 174 | klist_add_tail(&ic->node, &cont->containers); | 174 | klist_add_tail(&ic->node, &cont->containers); |
| 175 | } | 175 | } |
| 176 | up(&attribute_container_mutex); | 176 | mutex_unlock(&attribute_container_mutex); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | /* FIXME: can't break out of this unless klist_iter_exit is also | 179 | /* FIXME: can't break out of this unless klist_iter_exit is also |
| @@ -211,7 +211,7 @@ attribute_container_remove_device(struct device *dev, | |||
| 211 | { | 211 | { |
| 212 | struct attribute_container *cont; | 212 | struct attribute_container *cont; |
| 213 | 213 | ||
| 214 | down(&attribute_container_mutex); | 214 | mutex_lock(&attribute_container_mutex); |
| 215 | list_for_each_entry(cont, &attribute_container_list, node) { | 215 | list_for_each_entry(cont, &attribute_container_list, node) { |
| 216 | struct internal_container *ic; | 216 | struct internal_container *ic; |
| 217 | struct klist_iter iter; | 217 | struct klist_iter iter; |
| @@ -234,7 +234,7 @@ attribute_container_remove_device(struct device *dev, | |||
| 234 | } | 234 | } |
| 235 | } | 235 | } |
| 236 | } | 236 | } |
| 237 | up(&attribute_container_mutex); | 237 | mutex_unlock(&attribute_container_mutex); |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | /** | 240 | /** |
| @@ -255,7 +255,7 @@ attribute_container_device_trigger(struct device *dev, | |||
| 255 | { | 255 | { |
| 256 | struct attribute_container *cont; | 256 | struct attribute_container *cont; |
| 257 | 257 | ||
| 258 | down(&attribute_container_mutex); | 258 | mutex_lock(&attribute_container_mutex); |
| 259 | list_for_each_entry(cont, &attribute_container_list, node) { | 259 | list_for_each_entry(cont, &attribute_container_list, node) { |
| 260 | struct internal_container *ic; | 260 | struct internal_container *ic; |
| 261 | struct klist_iter iter; | 261 | struct klist_iter iter; |
| @@ -273,7 +273,7 @@ attribute_container_device_trigger(struct device *dev, | |||
| 273 | fn(cont, dev, &ic->classdev); | 273 | fn(cont, dev, &ic->classdev); |
| 274 | } | 274 | } |
| 275 | } | 275 | } |
| 276 | up(&attribute_container_mutex); | 276 | mutex_unlock(&attribute_container_mutex); |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | /** | 279 | /** |
| @@ -295,12 +295,12 @@ attribute_container_trigger(struct device *dev, | |||
| 295 | { | 295 | { |
| 296 | struct attribute_container *cont; | 296 | struct attribute_container *cont; |
| 297 | 297 | ||
| 298 | down(&attribute_container_mutex); | 298 | mutex_lock(&attribute_container_mutex); |
| 299 | list_for_each_entry(cont, &attribute_container_list, node) { | 299 | list_for_each_entry(cont, &attribute_container_list, node) { |
| 300 | if (cont->match(cont, dev)) | 300 | if (cont->match(cont, dev)) |
| 301 | fn(cont, dev); | 301 | fn(cont, dev); |
| 302 | } | 302 | } |
| 303 | up(&attribute_container_mutex); | 303 | mutex_unlock(&attribute_container_mutex); |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | /** | 306 | /** |
diff --git a/drivers/base/base.h b/drivers/base/base.h index de7e1442ce60..d597f2659b23 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h | |||
| @@ -16,7 +16,7 @@ extern int cpu_dev_init(void); | |||
| 16 | extern int attribute_container_init(void); | 16 | extern int attribute_container_init(void); |
| 17 | 17 | ||
| 18 | extern int bus_add_device(struct device * dev); | 18 | extern int bus_add_device(struct device * dev); |
| 19 | extern int bus_attach_device(struct device * dev); | 19 | extern void bus_attach_device(struct device * dev); |
| 20 | extern void bus_remove_device(struct device * dev); | 20 | extern void bus_remove_device(struct device * dev); |
| 21 | extern struct bus_type *get_bus(struct bus_type * bus); | 21 | extern struct bus_type *get_bus(struct bus_type * bus); |
| 22 | extern void put_bus(struct bus_type * bus); | 22 | extern void put_bus(struct bus_type * bus); |
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 253868e03c70..1d76e2349654 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
| @@ -27,6 +27,9 @@ | |||
| 27 | #define to_driver(obj) container_of(obj, struct device_driver, kobj) | 27 | #define to_driver(obj) container_of(obj, struct device_driver, kobj) |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | static int __must_check bus_rescan_devices_helper(struct device *dev, | ||
| 31 | void *data); | ||
| 32 | |||
| 30 | static ssize_t | 33 | static ssize_t |
| 31 | drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) | 34 | drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) |
| 32 | { | 35 | { |
| @@ -60,8 +63,19 @@ static struct sysfs_ops driver_sysfs_ops = { | |||
| 60 | 63 | ||
| 61 | static void driver_release(struct kobject * kobj) | 64 | static void driver_release(struct kobject * kobj) |
| 62 | { | 65 | { |
| 63 | struct device_driver * drv = to_driver(kobj); | 66 | /* |
| 64 | complete(&drv->unloaded); | 67 | * Yes this is an empty release function, it is this way because struct |
| 68 | * device is always a static object, not a dynamic one. Yes, this is | ||
| 69 | * not nice and bad, but remember, drivers are code, reference counted | ||
| 70 | * by the module count, not a device, which is really data. And yes, | ||
| 71 | * in the future I do want to have all drivers be created dynamically, | ||
| 72 | * and am working toward that goal, but it will take a bit longer... | ||
| 73 | * | ||
| 74 | * But do not let this example give _anyone_ the idea that they can | ||
| 75 | * create a release function without any code in it at all, to do that | ||
| 76 | * is almost always wrong. If you have any questions about this, | ||
| 77 | * please send an email to <greg@kroah.com> | ||
| 78 | */ | ||
| 65 | } | 79 | } |
| 66 | 80 | ||
| 67 | static struct kobj_type ktype_driver = { | 81 | static struct kobj_type ktype_driver = { |
| @@ -133,7 +147,6 @@ static decl_subsys(bus, &ktype_bus, NULL); | |||
| 133 | 147 | ||
| 134 | 148 | ||
| 135 | #ifdef CONFIG_HOTPLUG | 149 | #ifdef CONFIG_HOTPLUG |
| 136 | |||
| 137 | /* Manually detach a device from its associated driver. */ | 150 | /* Manually detach a device from its associated driver. */ |
| 138 | static int driver_helper(struct device *dev, void *data) | 151 | static int driver_helper(struct device *dev, void *data) |
| 139 | { | 152 | { |
| @@ -199,6 +212,33 @@ static ssize_t driver_bind(struct device_driver *drv, | |||
| 199 | } | 212 | } |
| 200 | static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); | 213 | static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); |
| 201 | 214 | ||
| 215 | static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) | ||
| 216 | { | ||
| 217 | return sprintf(buf, "%d\n", bus->drivers_autoprobe); | ||
| 218 | } | ||
| 219 | |||
| 220 | static ssize_t store_drivers_autoprobe(struct bus_type *bus, | ||
| 221 | const char *buf, size_t count) | ||
| 222 | { | ||
| 223 | if (buf[0] == '0') | ||
| 224 | bus->drivers_autoprobe = 0; | ||
| 225 | else | ||
| 226 | bus->drivers_autoprobe = 1; | ||
| 227 | return count; | ||
| 228 | } | ||
| 229 | |||
| 230 | static ssize_t store_drivers_probe(struct bus_type *bus, | ||
| 231 | const char *buf, size_t count) | ||
| 232 | { | ||
| 233 | struct device *dev; | ||
| 234 | |||
| 235 | dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); | ||
| 236 | if (!dev) | ||
| 237 | return -ENODEV; | ||
| 238 | if (bus_rescan_devices_helper(dev, NULL) != 0) | ||
| 239 | return -EINVAL; | ||
| 240 | return count; | ||
| 241 | } | ||
| 202 | #endif | 242 | #endif |
| 203 | 243 | ||
| 204 | static struct device * next_device(struct klist_iter * i) | 244 | static struct device * next_device(struct klist_iter * i) |
| @@ -418,21 +458,21 @@ out_put: | |||
| 418 | * - Add device to bus's list of devices. | 458 | * - Add device to bus's list of devices. |
| 419 | * - Try to attach to driver. | 459 | * - Try to attach to driver. |
| 420 | */ | 460 | */ |
| 421 | int bus_attach_device(struct device * dev) | 461 | void bus_attach_device(struct device * dev) |
| 422 | { | 462 | { |
| 423 | struct bus_type *bus = dev->bus; | 463 | struct bus_type *bus = dev->bus; |
| 424 | int ret = 0; | 464 | int ret = 0; |
| 425 | 465 | ||
| 426 | if (bus) { | 466 | if (bus) { |
| 427 | dev->is_registered = 1; | 467 | dev->is_registered = 1; |
| 428 | ret = device_attach(dev); | 468 | if (bus->drivers_autoprobe) |
| 429 | if (ret >= 0) { | 469 | ret = device_attach(dev); |
| 470 | WARN_ON(ret < 0); | ||
| 471 | if (ret >= 0) | ||
| 430 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | 472 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); |
| 431 | ret = 0; | 473 | else |
| 432 | } else | ||
| 433 | dev->is_registered = 0; | 474 | dev->is_registered = 0; |
| 434 | } | 475 | } |
| 435 | return ret; | ||
| 436 | } | 476 | } |
| 437 | 477 | ||
| 438 | /** | 478 | /** |
| @@ -515,9 +555,41 @@ static void remove_bind_files(struct device_driver *drv) | |||
| 515 | driver_remove_file(drv, &driver_attr_bind); | 555 | driver_remove_file(drv, &driver_attr_bind); |
| 516 | driver_remove_file(drv, &driver_attr_unbind); | 556 | driver_remove_file(drv, &driver_attr_unbind); |
| 517 | } | 557 | } |
| 558 | |||
| 559 | static int add_probe_files(struct bus_type *bus) | ||
| 560 | { | ||
| 561 | int retval; | ||
| 562 | |||
| 563 | bus->drivers_probe_attr.attr.name = "drivers_probe"; | ||
| 564 | bus->drivers_probe_attr.attr.mode = S_IWUSR; | ||
| 565 | bus->drivers_probe_attr.attr.owner = bus->owner; | ||
| 566 | bus->drivers_probe_attr.store = store_drivers_probe; | ||
| 567 | retval = bus_create_file(bus, &bus->drivers_probe_attr); | ||
| 568 | if (retval) | ||
| 569 | goto out; | ||
| 570 | |||
| 571 | bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; | ||
| 572 | bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; | ||
| 573 | bus->drivers_autoprobe_attr.attr.owner = bus->owner; | ||
| 574 | bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; | ||
| 575 | bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; | ||
| 576 | retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); | ||
| 577 | if (retval) | ||
| 578 | bus_remove_file(bus, &bus->drivers_probe_attr); | ||
| 579 | out: | ||
| 580 | return retval; | ||
| 581 | } | ||
| 582 | |||
| 583 | static void remove_probe_files(struct bus_type *bus) | ||
| 584 | { | ||
| 585 | bus_remove_file(bus, &bus->drivers_autoprobe_attr); | ||
| 586 | bus_remove_file(bus, &bus->drivers_probe_attr); | ||
| 587 | } | ||
| 518 | #else | 588 | #else |
| 519 | static inline int add_bind_files(struct device_driver *drv) { return 0; } | 589 | static inline int add_bind_files(struct device_driver *drv) { return 0; } |
| 520 | static inline void remove_bind_files(struct device_driver *drv) {} | 590 | static inline void remove_bind_files(struct device_driver *drv) {} |
| 591 | static inline int add_probe_files(struct bus_type *bus) { return 0; } | ||
| 592 | static inline void remove_probe_files(struct bus_type *bus) {} | ||
| 521 | #endif | 593 | #endif |
| 522 | 594 | ||
| 523 | /** | 595 | /** |
| @@ -531,7 +603,7 @@ int bus_add_driver(struct device_driver *drv) | |||
| 531 | int error = 0; | 603 | int error = 0; |
| 532 | 604 | ||
| 533 | if (!bus) | 605 | if (!bus) |
| 534 | return 0; | 606 | return -EINVAL; |
| 535 | 607 | ||
| 536 | pr_debug("bus %s: add driver %s\n", bus->name, drv->name); | 608 | pr_debug("bus %s: add driver %s\n", bus->name, drv->name); |
| 537 | error = kobject_set_name(&drv->kobj, "%s", drv->name); | 609 | error = kobject_set_name(&drv->kobj, "%s", drv->name); |
| @@ -541,9 +613,11 @@ int bus_add_driver(struct device_driver *drv) | |||
| 541 | if ((error = kobject_register(&drv->kobj))) | 613 | if ((error = kobject_register(&drv->kobj))) |
| 542 | goto out_put_bus; | 614 | goto out_put_bus; |
| 543 | 615 | ||
| 544 | error = driver_attach(drv); | 616 | if (drv->bus->drivers_autoprobe) { |
| 545 | if (error) | 617 | error = driver_attach(drv); |
| 546 | goto out_unregister; | 618 | if (error) |
| 619 | goto out_unregister; | ||
| 620 | } | ||
| 547 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); | 621 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); |
| 548 | module_add_driver(drv->owner, drv); | 622 | module_add_driver(drv->owner, drv); |
| 549 | 623 | ||
| @@ -605,8 +679,6 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, | |||
| 605 | ret = device_attach(dev); | 679 | ret = device_attach(dev); |
| 606 | if (dev->parent) | 680 | if (dev->parent) |
| 607 | up(&dev->parent->sem); | 681 | up(&dev->parent->sem); |
| 608 | if (ret > 0) | ||
| 609 | ret = 0; | ||
| 610 | } | 682 | } |
| 611 | return ret < 0 ? ret : 0; | 683 | return ret < 0 ? ret : 0; |
| 612 | } | 684 | } |
| @@ -762,6 +834,12 @@ int bus_register(struct bus_type * bus) | |||
| 762 | 834 | ||
| 763 | klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); | 835 | klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); |
| 764 | klist_init(&bus->klist_drivers, NULL, NULL); | 836 | klist_init(&bus->klist_drivers, NULL, NULL); |
| 837 | |||
| 838 | bus->drivers_autoprobe = 1; | ||
| 839 | retval = add_probe_files(bus); | ||
| 840 | if (retval) | ||
| 841 | goto bus_probe_files_fail; | ||
| 842 | |||
| 765 | retval = bus_add_attrs(bus); | 843 | retval = bus_add_attrs(bus); |
| 766 | if (retval) | 844 | if (retval) |
| 767 | goto bus_attrs_fail; | 845 | goto bus_attrs_fail; |
| @@ -770,6 +848,8 @@ int bus_register(struct bus_type * bus) | |||
| 770 | return 0; | 848 | return 0; |
| 771 | 849 | ||
| 772 | bus_attrs_fail: | 850 | bus_attrs_fail: |
| 851 | remove_probe_files(bus); | ||
| 852 | bus_probe_files_fail: | ||
| 773 | kset_unregister(&bus->drivers); | 853 | kset_unregister(&bus->drivers); |
| 774 | bus_drivers_fail: | 854 | bus_drivers_fail: |
| 775 | kset_unregister(&bus->devices); | 855 | kset_unregister(&bus->devices); |
| @@ -779,7 +859,6 @@ out: | |||
| 779 | return retval; | 859 | return retval; |
| 780 | } | 860 | } |
| 781 | 861 | ||
| 782 | |||
| 783 | /** | 862 | /** |
| 784 | * bus_unregister - remove a bus from the system | 863 | * bus_unregister - remove a bus from the system |
| 785 | * @bus: bus. | 864 | * @bus: bus. |
| @@ -791,6 +870,7 @@ void bus_unregister(struct bus_type * bus) | |||
| 791 | { | 870 | { |
| 792 | pr_debug("bus %s: unregistering\n", bus->name); | 871 | pr_debug("bus %s: unregistering\n", bus->name); |
| 793 | bus_remove_attrs(bus); | 872 | bus_remove_attrs(bus); |
| 873 | remove_probe_files(bus); | ||
| 794 | kset_unregister(&bus->drivers); | 874 | kset_unregister(&bus->drivers); |
| 795 | kset_unregister(&bus->devices); | 875 | kset_unregister(&bus->devices); |
| 796 | subsystem_unregister(&bus->subsys); | 876 | subsystem_unregister(&bus->subsys); |
diff --git a/drivers/base/class.c b/drivers/base/class.c index d5968128be2b..80bbb2074636 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
| @@ -145,6 +145,7 @@ int class_register(struct class * cls) | |||
| 145 | INIT_LIST_HEAD(&cls->children); | 145 | INIT_LIST_HEAD(&cls->children); |
| 146 | INIT_LIST_HEAD(&cls->devices); | 146 | INIT_LIST_HEAD(&cls->devices); |
| 147 | INIT_LIST_HEAD(&cls->interfaces); | 147 | INIT_LIST_HEAD(&cls->interfaces); |
| 148 | kset_init(&cls->class_dirs); | ||
| 148 | init_MUTEX(&cls->sem); | 149 | init_MUTEX(&cls->sem); |
| 149 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); | 150 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); |
| 150 | if (error) | 151 | if (error) |
| @@ -163,7 +164,6 @@ int class_register(struct class * cls) | |||
| 163 | void class_unregister(struct class * cls) | 164 | void class_unregister(struct class * cls) |
| 164 | { | 165 | { |
| 165 | pr_debug("device class '%s': unregistering\n", cls->name); | 166 | pr_debug("device class '%s': unregistering\n", cls->name); |
| 166 | kobject_unregister(cls->virtual_dir); | ||
| 167 | remove_class_attrs(cls); | 167 | remove_class_attrs(cls); |
| 168 | subsystem_unregister(&cls->subsys); | 168 | subsystem_unregister(&cls->subsys); |
| 169 | } | 169 | } |
diff --git a/drivers/base/core.c b/drivers/base/core.c index d7fcf823a42a..8aa090da1cd7 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
| @@ -43,7 +43,8 @@ int (*platform_notify_remove)(struct device * dev) = NULL; | |||
| 43 | const char *dev_driver_string(struct device *dev) | 43 | const char *dev_driver_string(struct device *dev) |
| 44 | { | 44 | { |
| 45 | return dev->driver ? dev->driver->name : | 45 | return dev->driver ? dev->driver->name : |
| 46 | (dev->bus ? dev->bus->name : ""); | 46 | (dev->bus ? dev->bus->name : |
| 47 | (dev->class ? dev->class->name : "")); | ||
| 47 | } | 48 | } |
| 48 | EXPORT_SYMBOL(dev_driver_string); | 49 | EXPORT_SYMBOL(dev_driver_string); |
| 49 | 50 | ||
| @@ -119,6 +120,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) | |||
| 119 | 120 | ||
| 120 | if (ktype == &ktype_device) { | 121 | if (ktype == &ktype_device) { |
| 121 | struct device *dev = to_dev(kobj); | 122 | struct device *dev = to_dev(kobj); |
| 123 | if (dev->uevent_suppress) | ||
| 124 | return 0; | ||
| 122 | if (dev->bus) | 125 | if (dev->bus) |
| 123 | return 1; | 126 | return 1; |
| 124 | if (dev->class) | 127 | if (dev->class) |
| @@ -156,6 +159,11 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
| 156 | "MINOR=%u", MINOR(dev->devt)); | 159 | "MINOR=%u", MINOR(dev->devt)); |
| 157 | } | 160 | } |
| 158 | 161 | ||
| 162 | if (dev->type && dev->type->name) | ||
| 163 | add_uevent_var(envp, num_envp, &i, | ||
| 164 | buffer, buffer_size, &length, | ||
| 165 | "DEVTYPE=%s", dev->type->name); | ||
| 166 | |||
| 159 | if (dev->driver) | 167 | if (dev->driver) |
| 160 | add_uevent_var(envp, num_envp, &i, | 168 | add_uevent_var(envp, num_envp, &i, |
| 161 | buffer, buffer_size, &length, | 169 | buffer, buffer_size, &length, |
| @@ -238,71 +246,152 @@ static struct kset_uevent_ops device_uevent_ops = { | |||
| 238 | .uevent = dev_uevent, | 246 | .uevent = dev_uevent, |
| 239 | }; | 247 | }; |
| 240 | 248 | ||
| 249 | static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, | ||
| 250 | char *buf) | ||
| 251 | { | ||
| 252 | struct kobject *top_kobj; | ||
| 253 | struct kset *kset; | ||
| 254 | char *envp[32]; | ||
| 255 | char data[PAGE_SIZE]; | ||
| 256 | char *pos; | ||
| 257 | int i; | ||
| 258 | size_t count = 0; | ||
| 259 | int retval; | ||
| 260 | |||
| 261 | /* search the kset, the device belongs to */ | ||
| 262 | top_kobj = &dev->kobj; | ||
| 263 | if (!top_kobj->kset && top_kobj->parent) { | ||
| 264 | do { | ||
| 265 | top_kobj = top_kobj->parent; | ||
| 266 | } while (!top_kobj->kset && top_kobj->parent); | ||
| 267 | } | ||
| 268 | if (!top_kobj->kset) | ||
| 269 | goto out; | ||
| 270 | kset = top_kobj->kset; | ||
| 271 | if (!kset->uevent_ops || !kset->uevent_ops->uevent) | ||
| 272 | goto out; | ||
| 273 | |||
| 274 | /* respect filter */ | ||
| 275 | if (kset->uevent_ops && kset->uevent_ops->filter) | ||
| 276 | if (!kset->uevent_ops->filter(kset, &dev->kobj)) | ||
| 277 | goto out; | ||
| 278 | |||
| 279 | /* let the kset specific function add its keys */ | ||
| 280 | pos = data; | ||
| 281 | retval = kset->uevent_ops->uevent(kset, &dev->kobj, | ||
| 282 | envp, ARRAY_SIZE(envp), | ||
| 283 | pos, PAGE_SIZE); | ||
| 284 | if (retval) | ||
| 285 | goto out; | ||
| 286 | |||
| 287 | /* copy keys to file */ | ||
| 288 | for (i = 0; envp[i]; i++) { | ||
| 289 | pos = &buf[count]; | ||
| 290 | count += sprintf(pos, "%s\n", envp[i]); | ||
| 291 | } | ||
| 292 | out: | ||
| 293 | return count; | ||
| 294 | } | ||
| 295 | |||
| 241 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | 296 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, |
| 242 | const char *buf, size_t count) | 297 | const char *buf, size_t count) |
| 243 | { | 298 | { |
| 299 | if (memcmp(buf, "add", 3) != 0) | ||
| 300 | dev_err(dev, "uevent: unsupported action-string; this will " | ||
| 301 | "be ignored in a future kernel version"); | ||
| 244 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 302 | kobject_uevent(&dev->kobj, KOBJ_ADD); |
| 245 | return count; | 303 | return count; |
| 246 | } | 304 | } |
| 247 | 305 | ||
| 248 | static int device_add_groups(struct device *dev) | 306 | static int device_add_attributes(struct device *dev, |
| 307 | struct device_attribute *attrs) | ||
| 308 | { | ||
| 309 | int error = 0; | ||
| 310 | int i; | ||
| 311 | |||
| 312 | if (attrs) { | ||
| 313 | for (i = 0; attr_name(attrs[i]); i++) { | ||
| 314 | error = device_create_file(dev, &attrs[i]); | ||
| 315 | if (error) | ||
| 316 | break; | ||
| 317 | } | ||
| 318 | if (error) | ||
| 319 | while (--i >= 0) | ||
| 320 | device_remove_file(dev, &attrs[i]); | ||
| 321 | } | ||
| 322 | return error; | ||
| 323 | } | ||
| 324 | |||
| 325 | static void device_remove_attributes(struct device *dev, | ||
| 326 | struct device_attribute *attrs) | ||
| 249 | { | 327 | { |
| 250 | int i; | 328 | int i; |
| 329 | |||
| 330 | if (attrs) | ||
| 331 | for (i = 0; attr_name(attrs[i]); i++) | ||
| 332 | device_remove_file(dev, &attrs[i]); | ||
| 333 | } | ||
| 334 | |||
| 335 | static int device_add_groups(struct device *dev, | ||
| 336 | struct attribute_group **groups) | ||
| 337 | { | ||
| 251 | int error = 0; | 338 | int error = 0; |
| 339 | int i; | ||
| 252 | 340 | ||
| 253 | if (dev->groups) { | 341 | if (groups) { |
| 254 | for (i = 0; dev->groups[i]; i++) { | 342 | for (i = 0; groups[i]; i++) { |
| 255 | error = sysfs_create_group(&dev->kobj, dev->groups[i]); | 343 | error = sysfs_create_group(&dev->kobj, groups[i]); |
| 256 | if (error) { | 344 | if (error) { |
| 257 | while (--i >= 0) | 345 | while (--i >= 0) |
| 258 | sysfs_remove_group(&dev->kobj, dev->groups[i]); | 346 | sysfs_remove_group(&dev->kobj, groups[i]); |
| 259 | goto out; | 347 | break; |
| 260 | } | 348 | } |
| 261 | } | 349 | } |
| 262 | } | 350 | } |
| 263 | out: | ||
| 264 | return error; | 351 | return error; |
| 265 | } | 352 | } |
| 266 | 353 | ||
| 267 | static void device_remove_groups(struct device *dev) | 354 | static void device_remove_groups(struct device *dev, |
| 355 | struct attribute_group **groups) | ||
| 268 | { | 356 | { |
| 269 | int i; | 357 | int i; |
| 270 | if (dev->groups) { | 358 | |
| 271 | for (i = 0; dev->groups[i]; i++) { | 359 | if (groups) |
| 272 | sysfs_remove_group(&dev->kobj, dev->groups[i]); | 360 | for (i = 0; groups[i]; i++) |
| 273 | } | 361 | sysfs_remove_group(&dev->kobj, groups[i]); |
| 274 | } | ||
| 275 | } | 362 | } |
| 276 | 363 | ||
| 277 | static int device_add_attrs(struct device *dev) | 364 | static int device_add_attrs(struct device *dev) |
| 278 | { | 365 | { |
| 279 | struct class *class = dev->class; | 366 | struct class *class = dev->class; |
| 280 | struct device_type *type = dev->type; | 367 | struct device_type *type = dev->type; |
| 281 | int error = 0; | 368 | int error; |
| 282 | int i; | ||
| 283 | 369 | ||
| 284 | if (class && class->dev_attrs) { | 370 | if (class) { |
| 285 | for (i = 0; attr_name(class->dev_attrs[i]); i++) { | 371 | error = device_add_attributes(dev, class->dev_attrs); |
| 286 | error = device_create_file(dev, &class->dev_attrs[i]); | ||
| 287 | if (error) | ||
| 288 | break; | ||
| 289 | } | ||
| 290 | if (error) | 372 | if (error) |
| 291 | while (--i >= 0) | 373 | return error; |
| 292 | device_remove_file(dev, &class->dev_attrs[i]); | ||
| 293 | } | 374 | } |
| 294 | 375 | ||
| 295 | if (type && type->attrs) { | 376 | if (type) { |
| 296 | for (i = 0; attr_name(type->attrs[i]); i++) { | 377 | error = device_add_groups(dev, type->groups); |
| 297 | error = device_create_file(dev, &type->attrs[i]); | ||
| 298 | if (error) | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | if (error) | 378 | if (error) |
| 302 | while (--i >= 0) | 379 | goto err_remove_class_attrs; |
| 303 | device_remove_file(dev, &type->attrs[i]); | ||
| 304 | } | 380 | } |
| 305 | 381 | ||
| 382 | error = device_add_groups(dev, dev->groups); | ||
| 383 | if (error) | ||
| 384 | goto err_remove_type_groups; | ||
| 385 | |||
| 386 | return 0; | ||
| 387 | |||
| 388 | err_remove_type_groups: | ||
| 389 | if (type) | ||
| 390 | device_remove_groups(dev, type->groups); | ||
| 391 | err_remove_class_attrs: | ||
| 392 | if (class) | ||
| 393 | device_remove_attributes(dev, class->dev_attrs); | ||
| 394 | |||
| 306 | return error; | 395 | return error; |
| 307 | } | 396 | } |
| 308 | 397 | ||
| @@ -310,17 +399,14 @@ static void device_remove_attrs(struct device *dev) | |||
| 310 | { | 399 | { |
| 311 | struct class *class = dev->class; | 400 | struct class *class = dev->class; |
| 312 | struct device_type *type = dev->type; | 401 | struct device_type *type = dev->type; |
| 313 | int i; | ||
| 314 | 402 | ||
| 315 | if (class && class->dev_attrs) { | 403 | device_remove_groups(dev, dev->groups); |
| 316 | for (i = 0; attr_name(class->dev_attrs[i]); i++) | ||
| 317 | device_remove_file(dev, &class->dev_attrs[i]); | ||
| 318 | } | ||
| 319 | 404 | ||
| 320 | if (type && type->attrs) { | 405 | if (type) |
| 321 | for (i = 0; attr_name(type->attrs[i]); i++) | 406 | device_remove_groups(dev, type->groups); |
| 322 | device_remove_file(dev, &type->attrs[i]); | 407 | |
| 323 | } | 408 | if (class) |
| 409 | device_remove_attributes(dev, class->dev_attrs); | ||
| 324 | } | 410 | } |
| 325 | 411 | ||
| 326 | 412 | ||
| @@ -394,9 +480,10 @@ void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) | |||
| 394 | EXPORT_SYMBOL_GPL(device_remove_bin_file); | 480 | EXPORT_SYMBOL_GPL(device_remove_bin_file); |
| 395 | 481 | ||
| 396 | /** | 482 | /** |
| 397 | * device_schedule_callback - helper to schedule a callback for a device | 483 | * device_schedule_callback_owner - helper to schedule a callback for a device |
| 398 | * @dev: device. | 484 | * @dev: device. |
| 399 | * @func: callback function to invoke later. | 485 | * @func: callback function to invoke later. |
| 486 | * @owner: module owning the callback routine | ||
| 400 | * | 487 | * |
| 401 | * Attribute methods must not unregister themselves or their parent device | 488 | * Attribute methods must not unregister themselves or their parent device |
| 402 | * (which would amount to the same thing). Attempts to do so will deadlock, | 489 | * (which would amount to the same thing). Attempts to do so will deadlock, |
| @@ -407,20 +494,23 @@ EXPORT_SYMBOL_GPL(device_remove_bin_file); | |||
| 407 | * argument in the workqueue's process context. @dev will be pinned until | 494 | * argument in the workqueue's process context. @dev will be pinned until |
| 408 | * @func returns. | 495 | * @func returns. |
| 409 | * | 496 | * |
| 497 | * This routine is usually called via the inline device_schedule_callback(), | ||
| 498 | * which automatically sets @owner to THIS_MODULE. | ||
| 499 | * | ||
| 410 | * Returns 0 if the request was submitted, -ENOMEM if storage could not | 500 | * Returns 0 if the request was submitted, -ENOMEM if storage could not |
| 411 | * be allocated. | 501 | * be allocated, -ENODEV if a reference to @owner isn't available. |
| 412 | * | 502 | * |
| 413 | * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an | 503 | * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an |
| 414 | * underlying sysfs routine (since it is intended for use by attribute | 504 | * underlying sysfs routine (since it is intended for use by attribute |
| 415 | * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. | 505 | * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. |
| 416 | */ | 506 | */ |
| 417 | int device_schedule_callback(struct device *dev, | 507 | int device_schedule_callback_owner(struct device *dev, |
| 418 | void (*func)(struct device *)) | 508 | void (*func)(struct device *), struct module *owner) |
| 419 | { | 509 | { |
| 420 | return sysfs_schedule_callback(&dev->kobj, | 510 | return sysfs_schedule_callback(&dev->kobj, |
| 421 | (void (*)(void *)) func, dev); | 511 | (void (*)(void *)) func, dev, owner); |
| 422 | } | 512 | } |
| 423 | EXPORT_SYMBOL_GPL(device_schedule_callback); | 513 | EXPORT_SYMBOL_GPL(device_schedule_callback_owner); |
| 424 | 514 | ||
| 425 | static void klist_children_get(struct klist_node *n) | 515 | static void klist_children_get(struct klist_node *n) |
| 426 | { | 516 | { |
| @@ -477,34 +567,58 @@ static struct kobject * get_device_parent(struct device *dev, | |||
| 477 | return NULL; | 567 | return NULL; |
| 478 | } | 568 | } |
| 479 | #else | 569 | #else |
| 480 | static struct kobject * virtual_device_parent(struct device *dev) | 570 | static struct kobject *virtual_device_parent(struct device *dev) |
| 481 | { | 571 | { |
| 482 | if (!dev->class) | 572 | static struct kobject *virtual_dir = NULL; |
| 483 | return ERR_PTR(-ENODEV); | ||
| 484 | 573 | ||
| 485 | if (!dev->class->virtual_dir) { | 574 | if (!virtual_dir) |
| 486 | static struct kobject *virtual_dir = NULL; | 575 | virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); |
| 487 | 576 | ||
| 488 | if (!virtual_dir) | 577 | return virtual_dir; |
| 489 | virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); | ||
| 490 | dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); | ||
| 491 | } | ||
| 492 | |||
| 493 | return dev->class->virtual_dir; | ||
| 494 | } | 578 | } |
| 495 | 579 | ||
| 496 | static struct kobject * get_device_parent(struct device *dev, | 580 | static struct kobject * get_device_parent(struct device *dev, |
| 497 | struct device *parent) | 581 | struct device *parent) |
| 498 | { | 582 | { |
| 499 | /* if this is a class device, and has no parent, create one */ | 583 | if (dev->class) { |
| 500 | if ((dev->class) && (parent == NULL)) { | 584 | struct kobject *kobj = NULL; |
| 501 | return virtual_device_parent(dev); | 585 | struct kobject *parent_kobj; |
| 502 | } else if (parent) | 586 | struct kobject *k; |
| 587 | |||
| 588 | /* | ||
| 589 | * If we have no parent, we live in "virtual". | ||
| 590 | * Class-devices with a bus-device as parent, live | ||
| 591 | * in a class-directory to prevent namespace collisions. | ||
| 592 | */ | ||
| 593 | if (parent == NULL) | ||
| 594 | parent_kobj = virtual_device_parent(dev); | ||
| 595 | else if (parent->class) | ||
| 596 | return &parent->kobj; | ||
| 597 | else | ||
| 598 | parent_kobj = &parent->kobj; | ||
| 599 | |||
| 600 | /* find our class-directory at the parent and reference it */ | ||
| 601 | spin_lock(&dev->class->class_dirs.list_lock); | ||
| 602 | list_for_each_entry(k, &dev->class->class_dirs.list, entry) | ||
| 603 | if (k->parent == parent_kobj) { | ||
| 604 | kobj = kobject_get(k); | ||
| 605 | break; | ||
| 606 | } | ||
| 607 | spin_unlock(&dev->class->class_dirs.list_lock); | ||
| 608 | if (kobj) | ||
| 609 | return kobj; | ||
| 610 | |||
| 611 | /* or create a new class-directory at the parent device */ | ||
| 612 | return kobject_kset_add_dir(&dev->class->class_dirs, | ||
| 613 | parent_kobj, dev->class->name); | ||
| 614 | } | ||
| 615 | |||
| 616 | if (parent) | ||
| 503 | return &parent->kobj; | 617 | return &parent->kobj; |
| 504 | return NULL; | 618 | return NULL; |
| 505 | } | 619 | } |
| 506 | |||
| 507 | #endif | 620 | #endif |
| 621 | |||
| 508 | static int setup_parent(struct device *dev, struct device *parent) | 622 | static int setup_parent(struct device *dev, struct device *parent) |
| 509 | { | 623 | { |
| 510 | struct kobject *kobj; | 624 | struct kobject *kobj; |
| @@ -541,7 +655,6 @@ int device_add(struct device *dev) | |||
| 541 | pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); | 655 | pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); |
| 542 | 656 | ||
| 543 | parent = get_device(dev->parent); | 657 | parent = get_device(dev->parent); |
| 544 | |||
| 545 | error = setup_parent(dev, parent); | 658 | error = setup_parent(dev, parent); |
| 546 | if (error) | 659 | if (error) |
| 547 | goto Error; | 660 | goto Error; |
| @@ -562,10 +675,11 @@ int device_add(struct device *dev) | |||
| 562 | BUS_NOTIFY_ADD_DEVICE, dev); | 675 | BUS_NOTIFY_ADD_DEVICE, dev); |
| 563 | 676 | ||
| 564 | dev->uevent_attr.attr.name = "uevent"; | 677 | dev->uevent_attr.attr.name = "uevent"; |
| 565 | dev->uevent_attr.attr.mode = S_IWUSR; | 678 | dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR; |
| 566 | if (dev->driver) | 679 | if (dev->driver) |
| 567 | dev->uevent_attr.attr.owner = dev->driver->owner; | 680 | dev->uevent_attr.attr.owner = dev->driver->owner; |
| 568 | dev->uevent_attr.store = store_uevent; | 681 | dev->uevent_attr.store = store_uevent; |
| 682 | dev->uevent_attr.show = show_uevent; | ||
| 569 | error = device_create_file(dev, &dev->uevent_attr); | 683 | error = device_create_file(dev, &dev->uevent_attr); |
| 570 | if (error) | 684 | if (error) |
| 571 | goto attrError; | 685 | goto attrError; |
| @@ -614,16 +728,12 @@ int device_add(struct device *dev) | |||
| 614 | 728 | ||
| 615 | if ((error = device_add_attrs(dev))) | 729 | if ((error = device_add_attrs(dev))) |
| 616 | goto AttrsError; | 730 | goto AttrsError; |
| 617 | if ((error = device_add_groups(dev))) | ||
| 618 | goto GroupError; | ||
| 619 | if ((error = device_pm_add(dev))) | 731 | if ((error = device_pm_add(dev))) |
| 620 | goto PMError; | 732 | goto PMError; |
| 621 | if ((error = bus_add_device(dev))) | 733 | if ((error = bus_add_device(dev))) |
| 622 | goto BusError; | 734 | goto BusError; |
| 623 | if (!dev->uevent_suppress) | 735 | kobject_uevent(&dev->kobj, KOBJ_ADD); |
| 624 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 736 | bus_attach_device(dev); |
| 625 | if ((error = bus_attach_device(dev))) | ||
| 626 | goto AttachError; | ||
| 627 | if (parent) | 737 | if (parent) |
| 628 | klist_add_tail(&dev->knode_parent, &parent->klist_children); | 738 | klist_add_tail(&dev->knode_parent, &parent->klist_children); |
| 629 | 739 | ||
| @@ -639,19 +749,15 @@ int device_add(struct device *dev) | |||
| 639 | up(&dev->class->sem); | 749 | up(&dev->class->sem); |
| 640 | } | 750 | } |
| 641 | Done: | 751 | Done: |
| 642 | kfree(class_name); | 752 | kfree(class_name); |
| 643 | put_device(dev); | 753 | put_device(dev); |
| 644 | return error; | 754 | return error; |
| 645 | AttachError: | ||
| 646 | bus_remove_device(dev); | ||
| 647 | BusError: | 755 | BusError: |
| 648 | device_pm_remove(dev); | 756 | device_pm_remove(dev); |
| 649 | PMError: | 757 | PMError: |
| 650 | if (dev->bus) | 758 | if (dev->bus) |
| 651 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | 759 | blocking_notifier_call_chain(&dev->bus->bus_notifier, |
| 652 | BUS_NOTIFY_DEL_DEVICE, dev); | 760 | BUS_NOTIFY_DEL_DEVICE, dev); |
| 653 | device_remove_groups(dev); | ||
| 654 | GroupError: | ||
| 655 | device_remove_attrs(dev); | 761 | device_remove_attrs(dev); |
| 656 | AttrsError: | 762 | AttrsError: |
| 657 | if (dev->devt_attr) { | 763 | if (dev->devt_attr) { |
| @@ -677,15 +783,6 @@ int device_add(struct device *dev) | |||
| 677 | #endif | 783 | #endif |
| 678 | sysfs_remove_link(&dev->kobj, "device"); | 784 | sysfs_remove_link(&dev->kobj, "device"); |
| 679 | } | 785 | } |
| 680 | |||
| 681 | down(&dev->class->sem); | ||
| 682 | /* notify any interfaces that the device is now gone */ | ||
| 683 | list_for_each_entry(class_intf, &dev->class->interfaces, node) | ||
| 684 | if (class_intf->remove_dev) | ||
| 685 | class_intf->remove_dev(dev, class_intf); | ||
| 686 | /* remove the device from the class list */ | ||
| 687 | list_del_init(&dev->node); | ||
| 688 | up(&dev->class->sem); | ||
| 689 | } | 786 | } |
| 690 | ueventattrError: | 787 | ueventattrError: |
| 691 | device_remove_file(dev, &dev->uevent_attr); | 788 | device_remove_file(dev, &dev->uevent_attr); |
| @@ -796,9 +893,33 @@ void device_del(struct device * dev) | |||
| 796 | /* remove the device from the class list */ | 893 | /* remove the device from the class list */ |
| 797 | list_del_init(&dev->node); | 894 | list_del_init(&dev->node); |
| 798 | up(&dev->class->sem); | 895 | up(&dev->class->sem); |
| 896 | |||
| 897 | /* If we live in a parent class-directory, unreference it */ | ||
| 898 | if (dev->kobj.parent->kset == &dev->class->class_dirs) { | ||
| 899 | struct device *d; | ||
| 900 | int other = 0; | ||
| 901 | |||
| 902 | /* | ||
| 903 | * if we are the last child of our class, delete | ||
| 904 | * our class-directory at this parent | ||
| 905 | */ | ||
| 906 | down(&dev->class->sem); | ||
| 907 | list_for_each_entry(d, &dev->class->devices, node) { | ||
| 908 | if (d == dev) | ||
| 909 | continue; | ||
| 910 | if (d->kobj.parent == dev->kobj.parent) { | ||
| 911 | other = 1; | ||
| 912 | break; | ||
| 913 | } | ||
| 914 | } | ||
| 915 | if (!other) | ||
| 916 | kobject_del(dev->kobj.parent); | ||
| 917 | |||
| 918 | kobject_put(dev->kobj.parent); | ||
| 919 | up(&dev->class->sem); | ||
| 920 | } | ||
| 799 | } | 921 | } |
| 800 | device_remove_file(dev, &dev->uevent_attr); | 922 | device_remove_file(dev, &dev->uevent_attr); |
| 801 | device_remove_groups(dev); | ||
| 802 | device_remove_attrs(dev); | 923 | device_remove_attrs(dev); |
| 803 | bus_remove_device(dev); | 924 | bus_remove_device(dev); |
| 804 | 925 | ||
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 6a48824e43ff..18dba8e78da7 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
| @@ -94,19 +94,11 @@ int device_bind_driver(struct device *dev) | |||
| 94 | return ret; | 94 | return ret; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | struct stupid_thread_structure { | ||
| 98 | struct device_driver *drv; | ||
| 99 | struct device *dev; | ||
| 100 | }; | ||
| 101 | |||
| 102 | static atomic_t probe_count = ATOMIC_INIT(0); | 97 | static atomic_t probe_count = ATOMIC_INIT(0); |
| 103 | static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); | 98 | static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); |
| 104 | 99 | ||
| 105 | static int really_probe(void *void_data) | 100 | static int really_probe(struct device *dev, struct device_driver *drv) |
| 106 | { | 101 | { |
| 107 | struct stupid_thread_structure *data = void_data; | ||
| 108 | struct device_driver *drv = data->drv; | ||
| 109 | struct device *dev = data->dev; | ||
| 110 | int ret = 0; | 102 | int ret = 0; |
| 111 | 103 | ||
| 112 | atomic_inc(&probe_count); | 104 | atomic_inc(&probe_count); |
| @@ -154,7 +146,6 @@ probe_failed: | |||
| 154 | */ | 146 | */ |
| 155 | ret = 0; | 147 | ret = 0; |
| 156 | done: | 148 | done: |
| 157 | kfree(data); | ||
| 158 | atomic_dec(&probe_count); | 149 | atomic_dec(&probe_count); |
| 159 | wake_up(&probe_waitqueue); | 150 | wake_up(&probe_waitqueue); |
| 160 | return ret; | 151 | return ret; |
| @@ -186,16 +177,14 @@ int driver_probe_done(void) | |||
| 186 | * format of the ID structures, nor what is to be considered a match and | 177 | * format of the ID structures, nor what is to be considered a match and |
| 187 | * what is not. | 178 | * what is not. |
| 188 | * | 179 | * |
| 189 | * This function returns 1 if a match is found, an error if one occurs | 180 | * This function returns 1 if a match is found, -ENODEV if the device is |
| 190 | * (that is not -ENODEV or -ENXIO), and 0 otherwise. | 181 | * not registered, and 0 otherwise. |
| 191 | * | 182 | * |
| 192 | * This function must be called with @dev->sem held. When called for a | 183 | * This function must be called with @dev->sem held. When called for a |
| 193 | * USB interface, @dev->parent->sem must be held as well. | 184 | * USB interface, @dev->parent->sem must be held as well. |
| 194 | */ | 185 | */ |
| 195 | int driver_probe_device(struct device_driver * drv, struct device * dev) | 186 | int driver_probe_device(struct device_driver * drv, struct device * dev) |
| 196 | { | 187 | { |
| 197 | struct stupid_thread_structure *data; | ||
| 198 | struct task_struct *probe_task; | ||
| 199 | int ret = 0; | 188 | int ret = 0; |
| 200 | 189 | ||
| 201 | if (!device_is_registered(dev)) | 190 | if (!device_is_registered(dev)) |
| @@ -206,19 +195,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) | |||
| 206 | pr_debug("%s: Matched Device %s with Driver %s\n", | 195 | pr_debug("%s: Matched Device %s with Driver %s\n", |
| 207 | drv->bus->name, dev->bus_id, drv->name); | 196 | drv->bus->name, dev->bus_id, drv->name); |
| 208 | 197 | ||
| 209 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 198 | ret = really_probe(dev, drv); |
| 210 | if (!data) | ||
| 211 | return -ENOMEM; | ||
| 212 | data->drv = drv; | ||
| 213 | data->dev = dev; | ||
| 214 | |||
| 215 | if (drv->multithread_probe) { | ||
| 216 | probe_task = kthread_run(really_probe, data, | ||
| 217 | "probe-%s", dev->bus_id); | ||
| 218 | if (IS_ERR(probe_task)) | ||
| 219 | ret = really_probe(data); | ||
| 220 | } else | ||
| 221 | ret = really_probe(data); | ||
| 222 | 199 | ||
| 223 | done: | 200 | done: |
| 224 | return ret; | 201 | return ret; |
| @@ -230,30 +207,57 @@ static int __device_attach(struct device_driver * drv, void * data) | |||
| 230 | return driver_probe_device(drv, dev); | 207 | return driver_probe_device(drv, dev); |
| 231 | } | 208 | } |
| 232 | 209 | ||
| 210 | static int device_probe_drivers(void *data) | ||
| 211 | { | ||
| 212 | struct device *dev = data; | ||
| 213 | int ret = 0; | ||
| 214 | |||
| 215 | if (dev->bus) { | ||
| 216 | down(&dev->sem); | ||
| 217 | ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); | ||
| 218 | up(&dev->sem); | ||
| 219 | } | ||
| 220 | return ret; | ||
| 221 | } | ||
| 222 | |||
| 233 | /** | 223 | /** |
| 234 | * device_attach - try to attach device to a driver. | 224 | * device_attach - try to attach device to a driver. |
| 235 | * @dev: device. | 225 | * @dev: device. |
| 236 | * | 226 | * |
| 237 | * Walk the list of drivers that the bus has and call | 227 | * Walk the list of drivers that the bus has and call |
| 238 | * driver_probe_device() for each pair. If a compatible | 228 | * driver_probe_device() for each pair. If a compatible |
| 239 | * pair is found, break out and return. | 229 | * pair is found, break out and return. If the bus specifies |
| 230 | * multithreaded probing, walking the list of drivers is done | ||
| 231 | * on a probing thread. | ||
| 240 | * | 232 | * |
| 241 | * Returns 1 if the device was bound to a driver; | 233 | * Returns 1 if the device was bound to a driver; |
| 242 | * 0 if no matching device was found; error code otherwise. | 234 | * 0 if no matching device was found or multithreaded probing is done; |
| 235 | * -ENODEV if the device is not registered. | ||
| 243 | * | 236 | * |
| 244 | * When called for a USB interface, @dev->parent->sem must be held. | 237 | * When called for a USB interface, @dev->parent->sem must be held. |
| 245 | */ | 238 | */ |
| 246 | int device_attach(struct device * dev) | 239 | int device_attach(struct device * dev) |
| 247 | { | 240 | { |
| 248 | int ret = 0; | 241 | int ret = 0; |
| 242 | struct task_struct *probe_task = ERR_PTR(-ENOMEM); | ||
| 249 | 243 | ||
| 250 | down(&dev->sem); | 244 | down(&dev->sem); |
| 251 | if (dev->driver) { | 245 | if (dev->driver) { |
| 252 | ret = device_bind_driver(dev); | 246 | ret = device_bind_driver(dev); |
| 253 | if (ret == 0) | 247 | if (ret == 0) |
| 254 | ret = 1; | 248 | ret = 1; |
| 255 | } else | 249 | else { |
| 256 | ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); | 250 | dev->driver = NULL; |
| 251 | ret = 0; | ||
| 252 | } | ||
| 253 | } else { | ||
| 254 | if (dev->bus->multithread_probe) | ||
| 255 | probe_task = kthread_run(device_probe_drivers, dev, | ||
| 256 | "probe-%s", dev->bus_id); | ||
| 257 | if(IS_ERR(probe_task)) | ||
| 258 | ret = bus_for_each_drv(dev->bus, NULL, dev, | ||
| 259 | __device_attach); | ||
| 260 | } | ||
| 257 | up(&dev->sem); | 261 | up(&dev->sem); |
| 258 | return ret; | 262 | return ret; |
| 259 | } | 263 | } |
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index cd467c9f33b3..9406259754ad 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c | |||
| @@ -37,7 +37,7 @@ struct dma_page { /* cacheable header for 'allocation' bytes */ | |||
| 37 | 37 | ||
| 38 | #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) | 38 | #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) |
| 39 | 39 | ||
| 40 | static DECLARE_MUTEX (pools_lock); | 40 | static DEFINE_MUTEX (pools_lock); |
| 41 | 41 | ||
| 42 | static ssize_t | 42 | static ssize_t |
| 43 | show_pools (struct device *dev, struct device_attribute *attr, char *buf) | 43 | show_pools (struct device *dev, struct device_attribute *attr, char *buf) |
| @@ -55,7 +55,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf) | |||
| 55 | size -= temp; | 55 | size -= temp; |
| 56 | next += temp; | 56 | next += temp; |
| 57 | 57 | ||
| 58 | down (&pools_lock); | 58 | mutex_lock(&pools_lock); |
| 59 | list_for_each_entry(pool, &dev->dma_pools, pools) { | 59 | list_for_each_entry(pool, &dev->dma_pools, pools) { |
| 60 | unsigned pages = 0; | 60 | unsigned pages = 0; |
| 61 | unsigned blocks = 0; | 61 | unsigned blocks = 0; |
| @@ -73,7 +73,7 @@ show_pools (struct device *dev, struct device_attribute *attr, char *buf) | |||
| 73 | size -= temp; | 73 | size -= temp; |
| 74 | next += temp; | 74 | next += temp; |
| 75 | } | 75 | } |
| 76 | up (&pools_lock); | 76 | mutex_unlock(&pools_lock); |
| 77 | 77 | ||
| 78 | return PAGE_SIZE - size; | 78 | return PAGE_SIZE - size; |
| 79 | } | 79 | } |
| @@ -143,7 +143,7 @@ dma_pool_create (const char *name, struct device *dev, | |||
| 143 | if (dev) { | 143 | if (dev) { |
| 144 | int ret; | 144 | int ret; |
| 145 | 145 | ||
| 146 | down (&pools_lock); | 146 | mutex_lock(&pools_lock); |
| 147 | if (list_empty (&dev->dma_pools)) | 147 | if (list_empty (&dev->dma_pools)) |
| 148 | ret = device_create_file (dev, &dev_attr_pools); | 148 | ret = device_create_file (dev, &dev_attr_pools); |
| 149 | else | 149 | else |
| @@ -155,7 +155,7 @@ dma_pool_create (const char *name, struct device *dev, | |||
| 155 | kfree(retval); | 155 | kfree(retval); |
| 156 | retval = NULL; | 156 | retval = NULL; |
| 157 | } | 157 | } |
| 158 | up (&pools_lock); | 158 | mutex_unlock(&pools_lock); |
| 159 | } else | 159 | } else |
| 160 | INIT_LIST_HEAD (&retval->pools); | 160 | INIT_LIST_HEAD (&retval->pools); |
| 161 | 161 | ||
| @@ -231,11 +231,11 @@ pool_free_page (struct dma_pool *pool, struct dma_page *page) | |||
| 231 | void | 231 | void |
| 232 | dma_pool_destroy (struct dma_pool *pool) | 232 | dma_pool_destroy (struct dma_pool *pool) |
| 233 | { | 233 | { |
| 234 | down (&pools_lock); | 234 | mutex_lock(&pools_lock); |
| 235 | list_del (&pool->pools); | 235 | list_del (&pool->pools); |
| 236 | if (pool->dev && list_empty (&pool->dev->dma_pools)) | 236 | if (pool->dev && list_empty (&pool->dev->dma_pools)) |
| 237 | device_remove_file (pool->dev, &dev_attr_pools); | 237 | device_remove_file (pool->dev, &dev_attr_pools); |
| 238 | up (&pools_lock); | 238 | mutex_unlock(&pools_lock); |
| 239 | 239 | ||
| 240 | while (!list_empty (&pool->page_list)) { | 240 | while (!list_empty (&pool->page_list)) { |
| 241 | struct dma_page *page; | 241 | struct dma_page *page; |
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 082bfded3854..eb11475293ed 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c | |||
| @@ -149,10 +149,6 @@ void put_driver(struct device_driver * drv) | |||
| 149 | * We pass off most of the work to the bus_add_driver() call, | 149 | * We pass off most of the work to the bus_add_driver() call, |
| 150 | * since most of the things we have to do deal with the bus | 150 | * since most of the things we have to do deal with the bus |
| 151 | * structures. | 151 | * structures. |
| 152 | * | ||
| 153 | * The one interesting aspect is that we setup @drv->unloaded | ||
| 154 | * as a completion that gets complete when the driver reference | ||
| 155 | * count reaches 0. | ||
| 156 | */ | 152 | */ |
| 157 | int driver_register(struct device_driver * drv) | 153 | int driver_register(struct device_driver * drv) |
| 158 | { | 154 | { |
| @@ -162,35 +158,19 @@ int driver_register(struct device_driver * drv) | |||
| 162 | printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); | 158 | printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); |
| 163 | } | 159 | } |
| 164 | klist_init(&drv->klist_devices, NULL, NULL); | 160 | klist_init(&drv->klist_devices, NULL, NULL); |
| 165 | init_completion(&drv->unloaded); | ||
| 166 | return bus_add_driver(drv); | 161 | return bus_add_driver(drv); |
| 167 | } | 162 | } |
| 168 | 163 | ||
| 169 | |||
| 170 | /** | 164 | /** |
| 171 | * driver_unregister - remove driver from system. | 165 | * driver_unregister - remove driver from system. |
| 172 | * @drv: driver. | 166 | * @drv: driver. |
| 173 | * | 167 | * |
| 174 | * Again, we pass off most of the work to the bus-level call. | 168 | * Again, we pass off most of the work to the bus-level call. |
| 175 | * | ||
| 176 | * Though, once that is done, we wait until @drv->unloaded is completed. | ||
| 177 | * This will block until the driver refcount reaches 0, and it is | ||
| 178 | * released. Only modular drivers will call this function, and we | ||
| 179 | * have to guarantee that it won't complete, letting the driver | ||
| 180 | * unload until all references are gone. | ||
| 181 | */ | 169 | */ |
| 182 | 170 | ||
| 183 | void driver_unregister(struct device_driver * drv) | 171 | void driver_unregister(struct device_driver * drv) |
| 184 | { | 172 | { |
| 185 | bus_remove_driver(drv); | 173 | bus_remove_driver(drv); |
| 186 | /* | ||
| 187 | * If the driver is a module, we are probably in | ||
| 188 | * the module unload path, and we want to wait | ||
| 189 | * for everything to unload before we can actually | ||
| 190 | * finish the unload. | ||
| 191 | */ | ||
| 192 | if (drv->owner) | ||
| 193 | wait_for_completion(&drv->unloaded); | ||
| 194 | } | 174 | } |
| 195 | 175 | ||
| 196 | /** | 176 | /** |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index c0a979a5074b..97ab5bd1c4d6 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
| @@ -31,8 +31,6 @@ enum { | |||
| 31 | FW_STATUS_LOADING, | 31 | FW_STATUS_LOADING, |
| 32 | FW_STATUS_DONE, | 32 | FW_STATUS_DONE, |
| 33 | FW_STATUS_ABORT, | 33 | FW_STATUS_ABORT, |
| 34 | FW_STATUS_READY, | ||
| 35 | FW_STATUS_READY_NOHOTPLUG, | ||
| 36 | }; | 34 | }; |
| 37 | 35 | ||
| 38 | static int loading_timeout = 60; /* In seconds */ | 36 | static int loading_timeout = 60; /* In seconds */ |
| @@ -96,9 +94,6 @@ static int firmware_uevent(struct device *dev, char **envp, int num_envp, | |||
| 96 | struct firmware_priv *fw_priv = dev_get_drvdata(dev); | 94 | struct firmware_priv *fw_priv = dev_get_drvdata(dev); |
| 97 | int i = 0, len = 0; | 95 | int i = 0, len = 0; |
| 98 | 96 | ||
| 99 | if (!test_bit(FW_STATUS_READY, &fw_priv->status)) | ||
| 100 | return -ENODEV; | ||
| 101 | |||
| 102 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | 97 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, |
| 103 | "FIRMWARE=%s", fw_priv->fw_id)) | 98 | "FIRMWARE=%s", fw_priv->fw_id)) |
| 104 | return -ENOMEM; | 99 | return -ENOMEM; |
| @@ -333,6 +328,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, | |||
| 333 | f_dev->parent = device; | 328 | f_dev->parent = device; |
| 334 | f_dev->class = &firmware_class; | 329 | f_dev->class = &firmware_class; |
| 335 | dev_set_drvdata(f_dev, fw_priv); | 330 | dev_set_drvdata(f_dev, fw_priv); |
| 331 | f_dev->uevent_suppress = 1; | ||
| 336 | retval = device_register(f_dev); | 332 | retval = device_register(f_dev); |
| 337 | if (retval) { | 333 | if (retval) { |
| 338 | printk(KERN_ERR "%s: device_register failed\n", | 334 | printk(KERN_ERR "%s: device_register failed\n", |
| @@ -382,9 +378,7 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p, | |||
| 382 | } | 378 | } |
| 383 | 379 | ||
| 384 | if (uevent) | 380 | if (uevent) |
| 385 | set_bit(FW_STATUS_READY, &fw_priv->status); | 381 | f_dev->uevent_suppress = 0; |
| 386 | else | ||
| 387 | set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status); | ||
| 388 | *dev_p = f_dev; | 382 | *dev_p = f_dev; |
| 389 | goto out; | 383 | goto out; |
| 390 | 384 | ||
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index bbbb973a9d3c..05dc8764e765 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
| @@ -29,6 +29,9 @@ LIST_HEAD(dpm_off_irq); | |||
| 29 | DECLARE_MUTEX(dpm_sem); | 29 | DECLARE_MUTEX(dpm_sem); |
| 30 | DECLARE_MUTEX(dpm_list_sem); | 30 | DECLARE_MUTEX(dpm_list_sem); |
| 31 | 31 | ||
| 32 | int (*platform_enable_wakeup)(struct device *dev, int is_on); | ||
| 33 | |||
| 34 | |||
| 32 | /** | 35 | /** |
| 33 | * device_pm_set_parent - Specify power dependency. | 36 | * device_pm_set_parent - Specify power dependency. |
| 34 | * @dev: Device who needs power. | 37 | * @dev: Device who needs power. |
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 020be36705a6..a2c64188d713 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c | |||
| @@ -26,7 +26,9 @@ int resume_device(struct device * dev) | |||
| 26 | 26 | ||
| 27 | TRACE_DEVICE(dev); | 27 | TRACE_DEVICE(dev); |
| 28 | TRACE_RESUME(0); | 28 | TRACE_RESUME(0); |
| 29 | |||
| 29 | down(&dev->sem); | 30 | down(&dev->sem); |
| 31 | |||
| 30 | if (dev->power.pm_parent | 32 | if (dev->power.pm_parent |
| 31 | && dev->power.pm_parent->power.power_state.event) { | 33 | && dev->power.pm_parent->power.power_state.event) { |
| 32 | dev_err(dev, "PM: resume from %d, parent %s still %d\n", | 34 | dev_err(dev, "PM: resume from %d, parent %s still %d\n", |
| @@ -34,15 +36,24 @@ int resume_device(struct device * dev) | |||
| 34 | dev->power.pm_parent->bus_id, | 36 | dev->power.pm_parent->bus_id, |
| 35 | dev->power.pm_parent->power.power_state.event); | 37 | dev->power.pm_parent->power.power_state.event); |
| 36 | } | 38 | } |
| 39 | |||
| 37 | if (dev->bus && dev->bus->resume) { | 40 | if (dev->bus && dev->bus->resume) { |
| 38 | dev_dbg(dev,"resuming\n"); | 41 | dev_dbg(dev,"resuming\n"); |
| 39 | error = dev->bus->resume(dev); | 42 | error = dev->bus->resume(dev); |
| 40 | } | 43 | } |
| 41 | if (dev->class && dev->class->resume) { | 44 | |
| 45 | if (!error && dev->type && dev->type->resume) { | ||
| 46 | dev_dbg(dev,"resuming\n"); | ||
| 47 | error = dev->type->resume(dev); | ||
| 48 | } | ||
| 49 | |||
| 50 | if (!error && dev->class && dev->class->resume) { | ||
| 42 | dev_dbg(dev,"class resume\n"); | 51 | dev_dbg(dev,"class resume\n"); |
| 43 | error = dev->class->resume(dev); | 52 | error = dev->class->resume(dev); |
| 44 | } | 53 | } |
| 54 | |||
| 45 | up(&dev->sem); | 55 | up(&dev->sem); |
| 56 | |||
| 46 | TRACE_RESUME(error); | 57 | TRACE_RESUME(error); |
| 47 | return error; | 58 | return error; |
| 48 | } | 59 | } |
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c index 3483ae4d57f5..58b6f77a1b34 100644 --- a/drivers/base/power/shutdown.c +++ b/drivers/base/power/shutdown.c | |||
| @@ -36,7 +36,6 @@ void device_shutdown(void) | |||
| 36 | { | 36 | { |
| 37 | struct device * dev, *devn; | 37 | struct device * dev, *devn; |
| 38 | 38 | ||
| 39 | down_write(&devices_subsys.rwsem); | ||
| 40 | list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list, | 39 | list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list, |
| 41 | kobj.entry) { | 40 | kobj.entry) { |
| 42 | if (dev->bus && dev->bus->shutdown) { | 41 | if (dev->bus && dev->bus->shutdown) { |
| @@ -47,7 +46,6 @@ void device_shutdown(void) | |||
| 47 | dev->driver->shutdown(dev); | 46 | dev->driver->shutdown(dev); |
| 48 | } | 47 | } |
| 49 | } | 48 | } |
| 50 | up_write(&devices_subsys.rwsem); | ||
| 51 | 49 | ||
| 52 | sysdev_shutdown(); | 50 | sysdev_shutdown(); |
| 53 | } | 51 | } |
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index ece136bf97e3..42d2b86ba765 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c | |||
| @@ -78,6 +78,18 @@ int suspend_device(struct device * dev, pm_message_t state) | |||
| 78 | suspend_report_result(dev->class->suspend, error); | 78 | suspend_report_result(dev->class->suspend, error); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | if (!error && dev->type && dev->type->suspend && !dev->power.power_state.event) { | ||
| 82 | dev_dbg(dev, "%s%s\n", | ||
| 83 | suspend_verb(state.event), | ||
| 84 | ((state.event == PM_EVENT_SUSPEND) | ||
| 85 | && device_may_wakeup(dev)) | ||
| 86 | ? ", may wakeup" | ||
| 87 | : "" | ||
| 88 | ); | ||
| 89 | error = dev->type->suspend(dev, state); | ||
| 90 | suspend_report_result(dev->type->suspend, error); | ||
| 91 | } | ||
| 92 | |||
| 81 | if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) { | 93 | if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) { |
| 82 | dev_dbg(dev, "%s%s\n", | 94 | dev_dbg(dev, "%s%s\n", |
| 83 | suspend_verb(state.event), | 95 | suspend_verb(state.event), |
