main.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * kernel/power/main.c - PM subsystem core functionality.
  3. *
  4. * Copyright (c) 2003 Patrick Mochel
  5. * Copyright (c) 2003 Open Source Development Lab
  6. *
  7. * This file is released under the GPLv2
  8. *
  9. */
  10. #include <linux/kobject.h>
  11. #include <linux/string.h>
  12. #include <linux/resume-trace.h>
  13. #include "power.h"
  14. DEFINE_MUTEX(pm_mutex);
  15. unsigned int pm_flags;
  16. EXPORT_SYMBOL(pm_flags);
  17. #ifdef CONFIG_PM_SLEEP
  18. /* Routines for PM-transition notifications */
  19. static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
  20. int register_pm_notifier(struct notifier_block *nb)
  21. {
  22. return blocking_notifier_chain_register(&pm_chain_head, nb);
  23. }
  24. EXPORT_SYMBOL_GPL(register_pm_notifier);
  25. int unregister_pm_notifier(struct notifier_block *nb)
  26. {
  27. return blocking_notifier_chain_unregister(&pm_chain_head, nb);
  28. }
  29. EXPORT_SYMBOL_GPL(unregister_pm_notifier);
  30. int pm_notifier_call_chain(unsigned long val)
  31. {
  32. return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
  33. == NOTIFY_BAD) ? -EINVAL : 0;
  34. }
  35. #ifdef CONFIG_PM_DEBUG
  36. int pm_test_level = TEST_NONE;
  37. static const char * const pm_tests[__TEST_AFTER_LAST] = {
  38. [TEST_NONE] = "none",
  39. [TEST_CORE] = "core",
  40. [TEST_CPUS] = "processors",
  41. [TEST_PLATFORM] = "platform",
  42. [TEST_DEVICES] = "devices",
  43. [TEST_FREEZER] = "freezer",
  44. };
  45. static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
  46. char *buf)
  47. {
  48. char *s = buf;
  49. int level;
  50. for (level = TEST_FIRST; level <= TEST_MAX; level++)
  51. if (pm_tests[level]) {
  52. if (level == pm_test_level)
  53. s += sprintf(s, "[%s] ", pm_tests[level]);
  54. else
  55. s += sprintf(s, "%s ", pm_tests[level]);
  56. }
  57. if (s != buf)
  58. /* convert the last space to a newline */
  59. *(s-1) = '\n';
  60. return (s - buf);
  61. }
  62. static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
  63. const char *buf, size_t n)
  64. {
  65. const char * const *s;
  66. int level;
  67. char *p;
  68. int len;
  69. int error = -EINVAL;
  70. p = memchr(buf, '\n', n);
  71. len = p ? p - buf : n;
  72. mutex_lock(&pm_mutex);
  73. level = TEST_FIRST;
  74. for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
  75. if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
  76. pm_test_level = level;
  77. error = 0;
  78. break;
  79. }
  80. mutex_unlock(&pm_mutex);
  81. return error ? error : n;
  82. }
  83. power_attr(pm_test);
  84. #endif /* CONFIG_PM_DEBUG */
  85. #endif /* CONFIG_PM_SLEEP */
  86. struct kobject *power_kobj;
  87. /**
  88. * state - control system power state.
  89. *
  90. * show() returns what states are supported, which is hard-coded to
  91. * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
  92. * 'disk' (Suspend-to-Disk).
  93. *
  94. * store() accepts one of those strings, translates it into the
  95. * proper enumerated value, and initiates a suspend transition.
  96. */
  97. static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
  98. char *buf)
  99. {
  100. char *s = buf;
  101. #ifdef CONFIG_SUSPEND
  102. int i;
  103. for (i = 0; i < PM_SUSPEND_MAX; i++) {
  104. if (pm_states[i] && valid_state(i))
  105. s += sprintf(s,"%s ", pm_states[i]);
  106. }
  107. #endif
  108. #ifdef CONFIG_HIBERNATION
  109. s += sprintf(s, "%s\n", "disk");
  110. #else
  111. if (s != buf)
  112. /* convert the last space to a newline */
  113. *(s-1) = '\n';
  114. #endif
  115. return (s - buf);
  116. }
  117. static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
  118. const char *buf, size_t n)
  119. {
  120. #ifdef CONFIG_SUSPEND
  121. suspend_state_t state = PM_SUSPEND_STANDBY;
  122. const char * const *s;
  123. #endif
  124. char *p;
  125. int len;
  126. int error = -EINVAL;
  127. p = memchr(buf, '\n', n);
  128. len = p ? p - buf : n;
  129. /* First, check if we are requested to hibernate */
  130. if (len == 4 && !strncmp(buf, "disk", len)) {
  131. error = hibernate();
  132. goto Exit;
  133. }
  134. #ifdef CONFIG_SUSPEND
  135. for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
  136. if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
  137. break;
  138. }
  139. if (state < PM_SUSPEND_MAX && *s)
  140. error = enter_state(state);
  141. #endif
  142. Exit:
  143. return error ? error : n;
  144. }
  145. power_attr(state);
  146. #ifdef CONFIG_PM_TRACE
  147. int pm_trace_enabled;
  148. static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
  149. char *buf)
  150. {
  151. return sprintf(buf, "%d\n", pm_trace_enabled);
  152. }
  153. static ssize_t
  154. pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
  155. const char *buf, size_t n)
  156. {
  157. int val;
  158. if (sscanf(buf, "%d", &val) == 1) {
  159. pm_trace_enabled = !!val;
  160. return n;
  161. }
  162. return -EINVAL;
  163. }
  164. power_attr(pm_trace);
  165. #endif /* CONFIG_PM_TRACE */
  166. static struct attribute * g[] = {
  167. &state_attr.attr,
  168. #ifdef CONFIG_PM_TRACE
  169. &pm_trace_attr.attr,
  170. #endif
  171. #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
  172. &pm_test_attr.attr,
  173. #endif
  174. NULL,
  175. };
  176. static struct attribute_group attr_group = {
  177. .attrs = g,
  178. };
  179. static int __init pm_init(void)
  180. {
  181. power_kobj = kobject_create_and_add("power", NULL);
  182. if (!power_kobj)
  183. return -ENOMEM;
  184. return sysfs_create_group(power_kobj, &attr_group);
  185. }
  186. core_initcall(pm_init);