main.c 5.0 KB

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