diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/bus.c | 8 | ||||
-rw-r--r-- | drivers/base/class.c | 39 | ||||
-rw-r--r-- | drivers/base/core.c | 2 | ||||
-rw-r--r-- | drivers/base/dd.c | 2 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 79 | ||||
-rw-r--r-- | drivers/base/node.c | 24 | ||||
-rw-r--r-- | drivers/base/power/resume.c | 8 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 8 | ||||
-rw-r--r-- | drivers/base/power/suspend.c | 12 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 8 | ||||
-rw-r--r-- | drivers/base/sys.c | 110 |
11 files changed, 215 insertions, 85 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index ab53832d57e5..17e96698410e 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -156,7 +156,9 @@ static ssize_t driver_unbind(struct device_driver *drv, | |||
156 | device_release_driver(dev); | 156 | device_release_driver(dev); |
157 | err = count; | 157 | err = count; |
158 | } | 158 | } |
159 | return err; | 159 | if (err) |
160 | return err; | ||
161 | return count; | ||
160 | } | 162 | } |
161 | static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); | 163 | static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); |
162 | 164 | ||
@@ -358,7 +360,7 @@ int bus_add_device(struct device * dev) | |||
358 | if (bus) { | 360 | if (bus) { |
359 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); | 361 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); |
360 | device_attach(dev); | 362 | device_attach(dev); |
361 | klist_add_tail(&bus->klist_devices, &dev->knode_bus); | 363 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); |
362 | error = device_add_attrs(bus, dev); | 364 | error = device_add_attrs(bus, dev); |
363 | if (!error) { | 365 | if (!error) { |
364 | sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); | 366 | sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); |
@@ -446,7 +448,7 @@ int bus_add_driver(struct device_driver * drv) | |||
446 | } | 448 | } |
447 | 449 | ||
448 | driver_attach(drv); | 450 | driver_attach(drv); |
449 | klist_add_tail(&bus->klist_drivers, &drv->knode_bus); | 451 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); |
450 | module_add_driver(drv->owner, drv); | 452 | module_add_driver(drv->owner, drv); |
451 | 453 | ||
452 | driver_add_attrs(bus, drv); | 454 | driver_add_attrs(bus, drv); |
diff --git a/drivers/base/class.c b/drivers/base/class.c index 0154a1623b21..d164c32a97ad 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -299,10 +299,8 @@ static void class_dev_release(struct kobject * kobj) | |||
299 | 299 | ||
300 | pr_debug("device class '%s': release.\n", cd->class_id); | 300 | pr_debug("device class '%s': release.\n", cd->class_id); |
301 | 301 | ||
302 | if (cd->devt_attr) { | 302 | kfree(cd->devt_attr); |
303 | kfree(cd->devt_attr); | 303 | cd->devt_attr = NULL; |
304 | cd->devt_attr = NULL; | ||
305 | } | ||
306 | 304 | ||
307 | if (cls->release) | 305 | if (cls->release) |
308 | cls->release(cd); | 306 | cls->release(cd); |
@@ -452,10 +450,29 @@ void class_device_initialize(struct class_device *class_dev) | |||
452 | INIT_LIST_HEAD(&class_dev->node); | 450 | INIT_LIST_HEAD(&class_dev->node); |
453 | } | 451 | } |
454 | 452 | ||
453 | static char *make_class_name(struct class_device *class_dev) | ||
454 | { | ||
455 | char *name; | ||
456 | int size; | ||
457 | |||
458 | size = strlen(class_dev->class->name) + | ||
459 | strlen(kobject_name(&class_dev->kobj)) + 2; | ||
460 | |||
461 | name = kmalloc(size, GFP_KERNEL); | ||
462 | if (!name) | ||
463 | return ERR_PTR(-ENOMEM); | ||
464 | |||
465 | strcpy(name, class_dev->class->name); | ||
466 | strcat(name, ":"); | ||
467 | strcat(name, kobject_name(&class_dev->kobj)); | ||
468 | return name; | ||
469 | } | ||
470 | |||
455 | int class_device_add(struct class_device *class_dev) | 471 | int class_device_add(struct class_device *class_dev) |
456 | { | 472 | { |
457 | struct class * parent = NULL; | 473 | struct class * parent = NULL; |
458 | struct class_interface * class_intf; | 474 | struct class_interface * class_intf; |
475 | char *class_name = NULL; | ||
459 | int error; | 476 | int error; |
460 | 477 | ||
461 | class_dev = class_device_get(class_dev); | 478 | class_dev = class_device_get(class_dev); |
@@ -500,9 +517,13 @@ int class_device_add(struct class_device *class_dev) | |||
500 | } | 517 | } |
501 | 518 | ||
502 | class_device_add_attrs(class_dev); | 519 | class_device_add_attrs(class_dev); |
503 | if (class_dev->dev) | 520 | if (class_dev->dev) { |
521 | class_name = make_class_name(class_dev); | ||
504 | sysfs_create_link(&class_dev->kobj, | 522 | sysfs_create_link(&class_dev->kobj, |
505 | &class_dev->dev->kobj, "device"); | 523 | &class_dev->dev->kobj, "device"); |
524 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
525 | class_name); | ||
526 | } | ||
506 | 527 | ||
507 | /* notify any interfaces this device is now here */ | 528 | /* notify any interfaces this device is now here */ |
508 | if (parent) { | 529 | if (parent) { |
@@ -519,6 +540,7 @@ int class_device_add(struct class_device *class_dev) | |||
519 | if (error && parent) | 540 | if (error && parent) |
520 | class_put(parent); | 541 | class_put(parent); |
521 | class_device_put(class_dev); | 542 | class_device_put(class_dev); |
543 | kfree(class_name); | ||
522 | return error; | 544 | return error; |
523 | } | 545 | } |
524 | 546 | ||
@@ -584,6 +606,7 @@ void class_device_del(struct class_device *class_dev) | |||
584 | { | 606 | { |
585 | struct class * parent = class_dev->class; | 607 | struct class * parent = class_dev->class; |
586 | struct class_interface * class_intf; | 608 | struct class_interface * class_intf; |
609 | char *class_name = NULL; | ||
587 | 610 | ||
588 | if (parent) { | 611 | if (parent) { |
589 | down(&parent->sem); | 612 | down(&parent->sem); |
@@ -594,8 +617,11 @@ void class_device_del(struct class_device *class_dev) | |||
594 | up(&parent->sem); | 617 | up(&parent->sem); |
595 | } | 618 | } |
596 | 619 | ||
597 | if (class_dev->dev) | 620 | if (class_dev->dev) { |
621 | class_name = make_class_name(class_dev); | ||
598 | sysfs_remove_link(&class_dev->kobj, "device"); | 622 | sysfs_remove_link(&class_dev->kobj, "device"); |
623 | sysfs_remove_link(&class_dev->dev->kobj, class_name); | ||
624 | } | ||
599 | if (class_dev->devt_attr) | 625 | if (class_dev->devt_attr) |
600 | class_device_remove_file(class_dev, class_dev->devt_attr); | 626 | class_device_remove_file(class_dev, class_dev->devt_attr); |
601 | class_device_remove_attrs(class_dev); | 627 | class_device_remove_attrs(class_dev); |
@@ -605,6 +631,7 @@ void class_device_del(struct class_device *class_dev) | |||
605 | 631 | ||
606 | if (parent) | 632 | if (parent) |
607 | class_put(parent); | 633 | class_put(parent); |
634 | kfree(class_name); | ||
608 | } | 635 | } |
609 | 636 | ||
610 | void class_device_unregister(struct class_device *class_dev) | 637 | void class_device_unregister(struct class_device *class_dev) |
diff --git a/drivers/base/core.c b/drivers/base/core.c index efe03a024a5b..c8a33df00761 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -249,7 +249,7 @@ int device_add(struct device *dev) | |||
249 | if ((error = bus_add_device(dev))) | 249 | if ((error = bus_add_device(dev))) |
250 | goto BusError; | 250 | goto BusError; |
251 | if (parent) | 251 | if (parent) |
252 | klist_add_tail(&parent->klist_children, &dev->knode_parent); | 252 | klist_add_tail(&dev->knode_parent, &parent->klist_children); |
253 | 253 | ||
254 | /* notify platform of device entry */ | 254 | /* notify platform of device entry */ |
255 | if (platform_notify) | 255 | if (platform_notify) |
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 16323f9cbff0..d5bbce38282f 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -42,7 +42,7 @@ void device_bind_driver(struct device * dev) | |||
42 | { | 42 | { |
43 | pr_debug("bound device '%s' to driver '%s'\n", | 43 | pr_debug("bound device '%s' to driver '%s'\n", |
44 | dev->bus_id, dev->driver->name); | 44 | dev->bus_id, dev->driver->name); |
45 | klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver); | 45 | klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); |
46 | sysfs_create_link(&dev->driver->kobj, &dev->kobj, | 46 | sysfs_create_link(&dev->driver->kobj, &dev->kobj, |
47 | kobject_name(&dev->kobj)); | 47 | kobject_name(&dev->kobj)); |
48 | sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); | 48 | sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 652281402c92..5bfa2e9a7c26 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -28,6 +28,7 @@ enum { | |||
28 | FW_STATUS_DONE, | 28 | FW_STATUS_DONE, |
29 | FW_STATUS_ABORT, | 29 | FW_STATUS_ABORT, |
30 | FW_STATUS_READY, | 30 | FW_STATUS_READY, |
31 | FW_STATUS_READY_NOHOTPLUG, | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | static int loading_timeout = 10; /* In seconds */ | 34 | static int loading_timeout = 10; /* In seconds */ |
@@ -344,7 +345,7 @@ error_kfree: | |||
344 | 345 | ||
345 | static int | 346 | static int |
346 | fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p, | 347 | fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p, |
347 | const char *fw_name, struct device *device) | 348 | const char *fw_name, struct device *device, int hotplug) |
348 | { | 349 | { |
349 | struct class_device *class_dev; | 350 | struct class_device *class_dev; |
350 | struct firmware_priv *fw_priv; | 351 | struct firmware_priv *fw_priv; |
@@ -376,7 +377,10 @@ fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p, | |||
376 | goto error_unreg; | 377 | goto error_unreg; |
377 | } | 378 | } |
378 | 379 | ||
379 | set_bit(FW_STATUS_READY, &fw_priv->status); | 380 | if (hotplug) |
381 | set_bit(FW_STATUS_READY, &fw_priv->status); | ||
382 | else | ||
383 | set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status); | ||
380 | *class_dev_p = class_dev; | 384 | *class_dev_p = class_dev; |
381 | goto out; | 385 | goto out; |
382 | 386 | ||
@@ -386,21 +390,9 @@ out: | |||
386 | return retval; | 390 | return retval; |
387 | } | 391 | } |
388 | 392 | ||
389 | /** | 393 | static int |
390 | * request_firmware: - request firmware to hotplug and wait for it | 394 | _request_firmware(const struct firmware **firmware_p, const char *name, |
391 | * Description: | 395 | struct device *device, int hotplug) |
392 | * @firmware will be used to return a firmware image by the name | ||
393 | * of @name for device @device. | ||
394 | * | ||
395 | * Should be called from user context where sleeping is allowed. | ||
396 | * | ||
397 | * @name will be use as $FIRMWARE in the hotplug environment and | ||
398 | * should be distinctive enough not to be confused with any other | ||
399 | * firmware image for this or any other device. | ||
400 | **/ | ||
401 | int | ||
402 | request_firmware(const struct firmware **firmware_p, const char *name, | ||
403 | struct device *device) | ||
404 | { | 396 | { |
405 | struct class_device *class_dev; | 397 | struct class_device *class_dev; |
406 | struct firmware_priv *fw_priv; | 398 | struct firmware_priv *fw_priv; |
@@ -419,22 +411,25 @@ request_firmware(const struct firmware **firmware_p, const char *name, | |||
419 | } | 411 | } |
420 | memset(firmware, 0, sizeof (*firmware)); | 412 | memset(firmware, 0, sizeof (*firmware)); |
421 | 413 | ||
422 | retval = fw_setup_class_device(firmware, &class_dev, name, device); | 414 | retval = fw_setup_class_device(firmware, &class_dev, name, device, |
415 | hotplug); | ||
423 | if (retval) | 416 | if (retval) |
424 | goto error_kfree_fw; | 417 | goto error_kfree_fw; |
425 | 418 | ||
426 | fw_priv = class_get_devdata(class_dev); | 419 | fw_priv = class_get_devdata(class_dev); |
427 | 420 | ||
428 | if (loading_timeout > 0) { | 421 | if (hotplug) { |
429 | fw_priv->timeout.expires = jiffies + loading_timeout * HZ; | 422 | if (loading_timeout > 0) { |
430 | add_timer(&fw_priv->timeout); | 423 | fw_priv->timeout.expires = jiffies + loading_timeout * HZ; |
431 | } | 424 | add_timer(&fw_priv->timeout); |
432 | 425 | } | |
433 | kobject_hotplug(&class_dev->kobj, KOBJ_ADD); | ||
434 | wait_for_completion(&fw_priv->completion); | ||
435 | set_bit(FW_STATUS_DONE, &fw_priv->status); | ||
436 | 426 | ||
437 | del_timer_sync(&fw_priv->timeout); | 427 | kobject_hotplug(&class_dev->kobj, KOBJ_ADD); |
428 | wait_for_completion(&fw_priv->completion); | ||
429 | set_bit(FW_STATUS_DONE, &fw_priv->status); | ||
430 | del_timer_sync(&fw_priv->timeout); | ||
431 | } else | ||
432 | wait_for_completion(&fw_priv->completion); | ||
438 | 433 | ||
439 | down(&fw_lock); | 434 | down(&fw_lock); |
440 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { | 435 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { |
@@ -455,6 +450,26 @@ out: | |||
455 | } | 450 | } |
456 | 451 | ||
457 | /** | 452 | /** |
453 | * request_firmware: - request firmware to hotplug and wait for it | ||
454 | * Description: | ||
455 | * @firmware will be used to return a firmware image by the name | ||
456 | * of @name for device @device. | ||
457 | * | ||
458 | * Should be called from user context where sleeping is allowed. | ||
459 | * | ||
460 | * @name will be use as $FIRMWARE in the hotplug environment and | ||
461 | * should be distinctive enough not to be confused with any other | ||
462 | * firmware image for this or any other device. | ||
463 | **/ | ||
464 | int | ||
465 | request_firmware(const struct firmware **firmware_p, const char *name, | ||
466 | struct device *device) | ||
467 | { | ||
468 | int hotplug = 1; | ||
469 | return _request_firmware(firmware_p, name, device, hotplug); | ||
470 | } | ||
471 | |||
472 | /** | ||
458 | * release_firmware: - release the resource associated with a firmware image | 473 | * release_firmware: - release the resource associated with a firmware image |
459 | **/ | 474 | **/ |
460 | void | 475 | void |
@@ -491,6 +506,7 @@ struct firmware_work { | |||
491 | struct device *device; | 506 | struct device *device; |
492 | void *context; | 507 | void *context; |
493 | void (*cont)(const struct firmware *fw, void *context); | 508 | void (*cont)(const struct firmware *fw, void *context); |
509 | int hotplug; | ||
494 | }; | 510 | }; |
495 | 511 | ||
496 | static int | 512 | static int |
@@ -503,7 +519,8 @@ request_firmware_work_func(void *arg) | |||
503 | return 0; | 519 | return 0; |
504 | } | 520 | } |
505 | daemonize("%s/%s", "firmware", fw_work->name); | 521 | daemonize("%s/%s", "firmware", fw_work->name); |
506 | request_firmware(&fw, fw_work->name, fw_work->device); | 522 | _request_firmware(&fw, fw_work->name, fw_work->device, |
523 | fw_work->hotplug); | ||
507 | fw_work->cont(fw, fw_work->context); | 524 | fw_work->cont(fw, fw_work->context); |
508 | release_firmware(fw); | 525 | release_firmware(fw); |
509 | module_put(fw_work->module); | 526 | module_put(fw_work->module); |
@@ -518,6 +535,9 @@ request_firmware_work_func(void *arg) | |||
518 | * Asynchronous variant of request_firmware() for contexts where | 535 | * Asynchronous variant of request_firmware() for contexts where |
519 | * it is not possible to sleep. | 536 | * it is not possible to sleep. |
520 | * | 537 | * |
538 | * @hotplug invokes hotplug event to copy the firmware image if this flag | ||
539 | * is non-zero else the firmware copy must be done manually. | ||
540 | * | ||
521 | * @cont will be called asynchronously when the firmware request is over. | 541 | * @cont will be called asynchronously when the firmware request is over. |
522 | * | 542 | * |
523 | * @context will be passed over to @cont. | 543 | * @context will be passed over to @cont. |
@@ -527,7 +547,7 @@ request_firmware_work_func(void *arg) | |||
527 | **/ | 547 | **/ |
528 | int | 548 | int |
529 | request_firmware_nowait( | 549 | request_firmware_nowait( |
530 | struct module *module, | 550 | struct module *module, int hotplug, |
531 | const char *name, struct device *device, void *context, | 551 | const char *name, struct device *device, void *context, |
532 | void (*cont)(const struct firmware *fw, void *context)) | 552 | void (*cont)(const struct firmware *fw, void *context)) |
533 | { | 553 | { |
@@ -548,6 +568,7 @@ request_firmware_nowait( | |||
548 | .device = device, | 568 | .device = device, |
549 | .context = context, | 569 | .context = context, |
550 | .cont = cont, | 570 | .cont = cont, |
571 | .hotplug = hotplug, | ||
551 | }; | 572 | }; |
552 | 573 | ||
553 | ret = kernel_thread(request_firmware_work_func, fw_work, | 574 | ret = kernel_thread(request_firmware_work_func, fw_work, |
diff --git a/drivers/base/node.c b/drivers/base/node.c index 904b27caf697..16c513aa4d48 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
@@ -39,13 +39,25 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) | |||
39 | int n; | 39 | int n; |
40 | int nid = dev->id; | 40 | int nid = dev->id; |
41 | struct sysinfo i; | 41 | struct sysinfo i; |
42 | struct page_state ps; | ||
42 | unsigned long inactive; | 43 | unsigned long inactive; |
43 | unsigned long active; | 44 | unsigned long active; |
44 | unsigned long free; | 45 | unsigned long free; |
45 | 46 | ||
46 | si_meminfo_node(&i, nid); | 47 | si_meminfo_node(&i, nid); |
48 | get_page_state_node(&ps, nid); | ||
47 | __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid)); | 49 | __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid)); |
48 | 50 | ||
51 | /* Check for negative values in these approximate counters */ | ||
52 | if ((long)ps.nr_dirty < 0) | ||
53 | ps.nr_dirty = 0; | ||
54 | if ((long)ps.nr_writeback < 0) | ||
55 | ps.nr_writeback = 0; | ||
56 | if ((long)ps.nr_mapped < 0) | ||
57 | ps.nr_mapped = 0; | ||
58 | if ((long)ps.nr_slab < 0) | ||
59 | ps.nr_slab = 0; | ||
60 | |||
49 | n = sprintf(buf, "\n" | 61 | n = sprintf(buf, "\n" |
50 | "Node %d MemTotal: %8lu kB\n" | 62 | "Node %d MemTotal: %8lu kB\n" |
51 | "Node %d MemFree: %8lu kB\n" | 63 | "Node %d MemFree: %8lu kB\n" |
@@ -55,7 +67,11 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) | |||
55 | "Node %d HighTotal: %8lu kB\n" | 67 | "Node %d HighTotal: %8lu kB\n" |
56 | "Node %d HighFree: %8lu kB\n" | 68 | "Node %d HighFree: %8lu kB\n" |
57 | "Node %d LowTotal: %8lu kB\n" | 69 | "Node %d LowTotal: %8lu kB\n" |
58 | "Node %d LowFree: %8lu kB\n", | 70 | "Node %d LowFree: %8lu kB\n" |
71 | "Node %d Dirty: %8lu kB\n" | ||
72 | "Node %d Writeback: %8lu kB\n" | ||
73 | "Node %d Mapped: %8lu kB\n" | ||
74 | "Node %d Slab: %8lu kB\n", | ||
59 | nid, K(i.totalram), | 75 | nid, K(i.totalram), |
60 | nid, K(i.freeram), | 76 | nid, K(i.freeram), |
61 | nid, K(i.totalram - i.freeram), | 77 | nid, K(i.totalram - i.freeram), |
@@ -64,7 +80,11 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) | |||
64 | nid, K(i.totalhigh), | 80 | nid, K(i.totalhigh), |
65 | nid, K(i.freehigh), | 81 | nid, K(i.freehigh), |
66 | nid, K(i.totalram - i.totalhigh), | 82 | nid, K(i.totalram - i.totalhigh), |
67 | nid, K(i.freeram - i.freehigh)); | 83 | nid, K(i.freeram - i.freehigh), |
84 | nid, K(ps.nr_dirty), | ||
85 | nid, K(ps.nr_writeback), | ||
86 | nid, K(ps.nr_mapped), | ||
87 | nid, K(ps.nr_slab)); | ||
68 | n += hugetlb_report_node_meminfo(nid, buf + n); | 88 | n += hugetlb_report_node_meminfo(nid, buf + n); |
69 | return n; | 89 | return n; |
70 | } | 90 | } |
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index bdd96b03b885..0a7aa07b9a2a 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c | |||
@@ -26,11 +26,11 @@ int resume_device(struct device * dev) | |||
26 | 26 | ||
27 | down(&dev->sem); | 27 | down(&dev->sem); |
28 | if (dev->power.pm_parent | 28 | if (dev->power.pm_parent |
29 | && dev->power.pm_parent->power.power_state) { | 29 | && dev->power.pm_parent->power.power_state.event) { |
30 | dev_err(dev, "PM: resume from %d, parent %s still %d\n", | 30 | dev_err(dev, "PM: resume from %d, parent %s still %d\n", |
31 | dev->power.power_state, | 31 | dev->power.power_state.event, |
32 | dev->power.pm_parent->bus_id, | 32 | dev->power.pm_parent->bus_id, |
33 | dev->power.pm_parent->power.power_state); | 33 | dev->power.pm_parent->power.power_state.event); |
34 | } | 34 | } |
35 | if (dev->bus && dev->bus->resume) { | 35 | if (dev->bus && dev->bus->resume) { |
36 | dev_dbg(dev,"resuming\n"); | 36 | dev_dbg(dev,"resuming\n"); |
@@ -54,7 +54,7 @@ void dpm_resume(void) | |||
54 | list_add_tail(entry, &dpm_active); | 54 | list_add_tail(entry, &dpm_active); |
55 | 55 | ||
56 | up(&dpm_list_sem); | 56 | up(&dpm_list_sem); |
57 | if (!dev->power.prev_state) | 57 | if (!dev->power.prev_state.event) |
58 | resume_device(dev); | 58 | resume_device(dev); |
59 | down(&dpm_list_sem); | 59 | down(&dpm_list_sem); |
60 | put_device(dev); | 60 | put_device(dev); |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 325962d80191..e8f0519f5dfa 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -13,10 +13,10 @@ | |||
13 | static void runtime_resume(struct device * dev) | 13 | static void runtime_resume(struct device * dev) |
14 | { | 14 | { |
15 | dev_dbg(dev, "resuming\n"); | 15 | dev_dbg(dev, "resuming\n"); |
16 | if (!dev->power.power_state) | 16 | if (!dev->power.power_state.event) |
17 | return; | 17 | return; |
18 | if (!resume_device(dev)) | 18 | if (!resume_device(dev)) |
19 | dev->power.power_state = 0; | 19 | dev->power.power_state = PMSG_ON; |
20 | } | 20 | } |
21 | 21 | ||
22 | 22 | ||
@@ -49,10 +49,10 @@ int dpm_runtime_suspend(struct device * dev, pm_message_t state) | |||
49 | int error = 0; | 49 | int error = 0; |
50 | 50 | ||
51 | down(&dpm_sem); | 51 | down(&dpm_sem); |
52 | if (dev->power.power_state == state) | 52 | if (dev->power.power_state.event == state.event) |
53 | goto Done; | 53 | goto Done; |
54 | 54 | ||
55 | if (dev->power.power_state) | 55 | if (dev->power.power_state.event) |
56 | runtime_resume(dev); | 56 | runtime_resume(dev); |
57 | 57 | ||
58 | if (!(error = suspend_device(dev, state))) | 58 | if (!(error = suspend_device(dev, state))) |
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 2ccee3763acf..50501764d050 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c | |||
@@ -40,22 +40,22 @@ int suspend_device(struct device * dev, pm_message_t state) | |||
40 | int error = 0; | 40 | int error = 0; |
41 | 41 | ||
42 | down(&dev->sem); | 42 | down(&dev->sem); |
43 | if (dev->power.power_state) { | 43 | if (dev->power.power_state.event) { |
44 | dev_dbg(dev, "PM: suspend %d-->%d\n", | 44 | dev_dbg(dev, "PM: suspend %d-->%d\n", |
45 | dev->power.power_state, state); | 45 | dev->power.power_state.event, state.event); |
46 | } | 46 | } |
47 | if (dev->power.pm_parent | 47 | if (dev->power.pm_parent |
48 | && dev->power.pm_parent->power.power_state) { | 48 | && dev->power.pm_parent->power.power_state.event) { |
49 | dev_err(dev, | 49 | dev_err(dev, |
50 | "PM: suspend %d->%d, parent %s already %d\n", | 50 | "PM: suspend %d->%d, parent %s already %d\n", |
51 | dev->power.power_state, state, | 51 | dev->power.power_state.event, state.event, |
52 | dev->power.pm_parent->bus_id, | 52 | dev->power.pm_parent->bus_id, |
53 | dev->power.pm_parent->power.power_state); | 53 | dev->power.pm_parent->power.power_state.event); |
54 | } | 54 | } |
55 | 55 | ||
56 | dev->power.prev_state = dev->power.power_state; | 56 | dev->power.prev_state = dev->power.power_state; |
57 | 57 | ||
58 | if (dev->bus && dev->bus->suspend && !dev->power.power_state) { | 58 | if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { |
59 | dev_dbg(dev, "suspending\n"); | 59 | dev_dbg(dev, "suspending\n"); |
60 | error = dev->bus->suspend(dev, state); | 60 | error = dev->bus->suspend(dev, state); |
61 | } | 61 | } |
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index f82b3df9545f..8d04fb435c17 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -26,19 +26,19 @@ | |||
26 | 26 | ||
27 | static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf) | 27 | static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf) |
28 | { | 28 | { |
29 | return sprintf(buf, "%u\n", dev->power.power_state); | 29 | return sprintf(buf, "%u\n", dev->power.power_state.event); |
30 | } | 30 | } |
31 | 31 | ||
32 | static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n) | 32 | static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n) |
33 | { | 33 | { |
34 | u32 state; | 34 | pm_message_t state; |
35 | char * rest; | 35 | char * rest; |
36 | int error = 0; | 36 | int error = 0; |
37 | 37 | ||
38 | state = simple_strtoul(buf, &rest, 10); | 38 | state.event = simple_strtoul(buf, &rest, 10); |
39 | if (*rest) | 39 | if (*rest) |
40 | return -EINVAL; | 40 | return -EINVAL; |
41 | if (state) | 41 | if (state.event) |
42 | error = dpm_runtime_suspend(dev, state); | 42 | error = dpm_runtime_suspend(dev, state); |
43 | else | 43 | else |
44 | dpm_runtime_resume(dev); | 44 | dpm_runtime_resume(dev); |
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 214b96435409..3431eb6004c3 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -288,6 +288,27 @@ void sysdev_shutdown(void) | |||
288 | up(&sysdev_drivers_lock); | 288 | up(&sysdev_drivers_lock); |
289 | } | 289 | } |
290 | 290 | ||
291 | static void __sysdev_resume(struct sys_device *dev) | ||
292 | { | ||
293 | struct sysdev_class *cls = dev->cls; | ||
294 | struct sysdev_driver *drv; | ||
295 | |||
296 | /* First, call the class-specific one */ | ||
297 | if (cls->resume) | ||
298 | cls->resume(dev); | ||
299 | |||
300 | /* Call auxillary drivers next. */ | ||
301 | list_for_each_entry(drv, &cls->drivers, entry) { | ||
302 | if (drv->resume) | ||
303 | drv->resume(dev); | ||
304 | } | ||
305 | |||
306 | /* Call global drivers. */ | ||
307 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
308 | if (drv->resume) | ||
309 | drv->resume(dev); | ||
310 | } | ||
311 | } | ||
291 | 312 | ||
292 | /** | 313 | /** |
293 | * sysdev_suspend - Suspend all system devices. | 314 | * sysdev_suspend - Suspend all system devices. |
@@ -305,38 +326,93 @@ void sysdev_shutdown(void) | |||
305 | int sysdev_suspend(pm_message_t state) | 326 | int sysdev_suspend(pm_message_t state) |
306 | { | 327 | { |
307 | struct sysdev_class * cls; | 328 | struct sysdev_class * cls; |
329 | struct sys_device *sysdev, *err_dev; | ||
330 | struct sysdev_driver *drv, *err_drv; | ||
331 | int ret; | ||
308 | 332 | ||
309 | pr_debug("Suspending System Devices\n"); | 333 | pr_debug("Suspending System Devices\n"); |
310 | 334 | ||
311 | list_for_each_entry_reverse(cls, &system_subsys.kset.list, | 335 | list_for_each_entry_reverse(cls, &system_subsys.kset.list, |
312 | kset.kobj.entry) { | 336 | kset.kobj.entry) { |
313 | struct sys_device * sysdev; | ||
314 | 337 | ||
315 | pr_debug("Suspending type '%s':\n", | 338 | pr_debug("Suspending type '%s':\n", |
316 | kobject_name(&cls->kset.kobj)); | 339 | kobject_name(&cls->kset.kobj)); |
317 | 340 | ||
318 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | 341 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { |
319 | struct sysdev_driver * drv; | ||
320 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | 342 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); |
321 | 343 | ||
322 | /* Call global drivers first. */ | 344 | /* Call global drivers first. */ |
323 | list_for_each_entry(drv, &sysdev_drivers, entry) { | 345 | list_for_each_entry(drv, &sysdev_drivers, entry) { |
324 | if (drv->suspend) | 346 | if (drv->suspend) { |
325 | drv->suspend(sysdev, state); | 347 | ret = drv->suspend(sysdev, state); |
348 | if (ret) | ||
349 | goto gbl_driver; | ||
350 | } | ||
326 | } | 351 | } |
327 | 352 | ||
328 | /* Call auxillary drivers next. */ | 353 | /* Call auxillary drivers next. */ |
329 | list_for_each_entry(drv, &cls->drivers, entry) { | 354 | list_for_each_entry(drv, &cls->drivers, entry) { |
330 | if (drv->suspend) | 355 | if (drv->suspend) { |
331 | drv->suspend(sysdev, state); | 356 | ret = drv->suspend(sysdev, state); |
357 | if (ret) | ||
358 | goto aux_driver; | ||
359 | } | ||
332 | } | 360 | } |
333 | 361 | ||
334 | /* Now call the generic one */ | 362 | /* Now call the generic one */ |
335 | if (cls->suspend) | 363 | if (cls->suspend) { |
336 | cls->suspend(sysdev, state); | 364 | ret = cls->suspend(sysdev, state); |
365 | if (ret) | ||
366 | goto cls_driver; | ||
367 | } | ||
337 | } | 368 | } |
338 | } | 369 | } |
339 | return 0; | 370 | return 0; |
371 | /* resume current sysdev */ | ||
372 | cls_driver: | ||
373 | drv = NULL; | ||
374 | printk(KERN_ERR "Class suspend failed for %s\n", | ||
375 | kobject_name(&sysdev->kobj)); | ||
376 | |||
377 | aux_driver: | ||
378 | if (drv) | ||
379 | printk(KERN_ERR "Class driver suspend failed for %s\n", | ||
380 | kobject_name(&sysdev->kobj)); | ||
381 | list_for_each_entry(err_drv, &cls->drivers, entry) { | ||
382 | if (err_drv == drv) | ||
383 | break; | ||
384 | if (err_drv->resume) | ||
385 | err_drv->resume(sysdev); | ||
386 | } | ||
387 | drv = NULL; | ||
388 | |||
389 | gbl_driver: | ||
390 | if (drv) | ||
391 | printk(KERN_ERR "sysdev driver suspend failed for %s\n", | ||
392 | kobject_name(&sysdev->kobj)); | ||
393 | list_for_each_entry(err_drv, &sysdev_drivers, entry) { | ||
394 | if (err_drv == drv) | ||
395 | break; | ||
396 | if (err_drv->resume) | ||
397 | err_drv->resume(sysdev); | ||
398 | } | ||
399 | /* resume other sysdevs in current class */ | ||
400 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { | ||
401 | if (err_dev == sysdev) | ||
402 | break; | ||
403 | pr_debug(" %s\n", kobject_name(&err_dev->kobj)); | ||
404 | __sysdev_resume(err_dev); | ||
405 | } | ||
406 | |||
407 | /* resume other classes */ | ||
408 | list_for_each_entry_continue(cls, &system_subsys.kset.list, | ||
409 | kset.kobj.entry) { | ||
410 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { | ||
411 | pr_debug(" %s\n", kobject_name(&err_dev->kobj)); | ||
412 | __sysdev_resume(err_dev); | ||
413 | } | ||
414 | } | ||
415 | return ret; | ||
340 | } | 416 | } |
341 | 417 | ||
342 | 418 | ||
@@ -362,25 +438,9 @@ int sysdev_resume(void) | |||
362 | kobject_name(&cls->kset.kobj)); | 438 | kobject_name(&cls->kset.kobj)); |
363 | 439 | ||
364 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | 440 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { |
365 | struct sysdev_driver * drv; | ||
366 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | 441 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); |
367 | 442 | ||
368 | /* First, call the class-specific one */ | 443 | __sysdev_resume(sysdev); |
369 | if (cls->resume) | ||
370 | cls->resume(sysdev); | ||
371 | |||
372 | /* Call auxillary drivers next. */ | ||
373 | list_for_each_entry(drv, &cls->drivers, entry) { | ||
374 | if (drv->resume) | ||
375 | drv->resume(sysdev); | ||
376 | } | ||
377 | |||
378 | /* Call global drivers. */ | ||
379 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
380 | if (drv->resume) | ||
381 | drv->resume(sysdev); | ||
382 | } | ||
383 | |||
384 | } | 444 | } |
385 | } | 445 | } |
386 | return 0; | 446 | return 0; |