Blame view

kernel/power/main.c 11 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   * kernel/power/main.c - PM subsystem core functionality.
   *
   * Copyright (c) 2003 Patrick Mochel
   * Copyright (c) 2003 Open Source Development Lab
341d41661   Srivatsa S. Bhat   PM: Fix indentati...
6
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
   * This file is released under the GPLv2
   *
   */
6e5fdeedc   Paul Gortmaker   kernel: Fix files...
10
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
  #include <linux/kobject.h>
  #include <linux/string.h>
c5c6ba4e0   Rafael J. Wysocki   [PATCH] PM: Add p...
13
  #include <linux/resume-trace.h>
5e928f77a   Rafael J. Wysocki   PM: Introduce cor...
14
  #include <linux/workqueue.h>
2a77c46de   ShuoX Liu   PM / Suspend: Add...
15
16
  #include <linux/debugfs.h>
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  
  #include "power.h"
a6d709806   Stephen Hemminger   [PATCH] convert p...
19
  DEFINE_MUTEX(pm_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

cd51e61cf   Rafael J. Wysocki   PM / ACPI: Remove...
21
  #ifdef CONFIG_PM_SLEEP
825257569   Alan Stern   PM: Convert PM no...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  /* Routines for PM-transition notifications */
  
  static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
  
  int register_pm_notifier(struct notifier_block *nb)
  {
  	return blocking_notifier_chain_register(&pm_chain_head, nb);
  }
  EXPORT_SYMBOL_GPL(register_pm_notifier);
  
  int unregister_pm_notifier(struct notifier_block *nb)
  {
  	return blocking_notifier_chain_unregister(&pm_chain_head, nb);
  }
  EXPORT_SYMBOL_GPL(unregister_pm_notifier);
  
  int pm_notifier_call_chain(unsigned long val)
  {
f0c077a8b   Akinobu Mita   PM: Improve error...
40
41
42
  	int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
  
  	return notifier_to_errno(ret);
825257569   Alan Stern   PM: Convert PM no...
43
  }
0e06b4a89   Rafael J. Wysocki   PM: Add a switch ...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  /* If set, devices may be suspended and resumed asynchronously. */
  int pm_async_enabled = 1;
  
  static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
  			     char *buf)
  {
  	return sprintf(buf, "%d
  ", pm_async_enabled);
  }
  
  static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
  			      const char *buf, size_t n)
  {
  	unsigned long val;
  
  	if (strict_strtoul(buf, 10, &val))
  		return -EINVAL;
  
  	if (val > 1)
  		return -EINVAL;
  
  	pm_async_enabled = val;
  	return n;
  }
  
  power_attr(pm_async);
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
70
71
  #ifdef CONFIG_PM_DEBUG
  int pm_test_level = TEST_NONE;
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
72
73
74
75
76
77
78
79
  static const char * const pm_tests[__TEST_AFTER_LAST] = {
  	[TEST_NONE] = "none",
  	[TEST_CORE] = "core",
  	[TEST_CPUS] = "processors",
  	[TEST_PLATFORM] = "platform",
  	[TEST_DEVICES] = "devices",
  	[TEST_FREEZER] = "freezer",
  };
039a75c6e   Rafael J. Wysocki   suspend: build fi...
80
81
  static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
  				char *buf)
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  {
  	char *s = buf;
  	int level;
  
  	for (level = TEST_FIRST; level <= TEST_MAX; level++)
  		if (pm_tests[level]) {
  			if (level == pm_test_level)
  				s += sprintf(s, "[%s] ", pm_tests[level]);
  			else
  				s += sprintf(s, "%s ", pm_tests[level]);
  		}
  
  	if (s != buf)
  		/* convert the last space to a newline */
  		*(s-1) = '
  ';
  
  	return (s - buf);
  }
039a75c6e   Rafael J. Wysocki   suspend: build fi...
101
102
  static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
  				const char *buf, size_t n)
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
103
104
105
106
107
108
109
110
111
112
  {
  	const char * const *s;
  	int level;
  	char *p;
  	int len;
  	int error = -EINVAL;
  
  	p = memchr(buf, '
  ', n);
  	len = p ? p - buf : n;
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
113
  	lock_system_sleep();
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
114
115
116
117
118
119
120
121
  
  	level = TEST_FIRST;
  	for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
  		if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
  			pm_test_level = level;
  			error = 0;
  			break;
  		}
bcda53faf   Srivatsa S. Bhat   PM / Sleep: Repla...
122
  	unlock_system_sleep();
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
123
124
125
126
127
  
  	return error ? error : n;
  }
  
  power_attr(pm_test);
091d71e02   Rafael J. Wysocki   PM: Fix compilati...
128
  #endif /* CONFIG_PM_DEBUG */
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
129

2a77c46de   ShuoX Liu   PM / Suspend: Add...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  #ifdef CONFIG_DEBUG_FS
  static char *suspend_step_name(enum suspend_stat_step step)
  {
  	switch (step) {
  	case SUSPEND_FREEZE:
  		return "freeze";
  	case SUSPEND_PREPARE:
  		return "prepare";
  	case SUSPEND_SUSPEND:
  		return "suspend";
  	case SUSPEND_SUSPEND_NOIRQ:
  		return "suspend_noirq";
  	case SUSPEND_RESUME_NOIRQ:
  		return "resume_noirq";
  	case SUSPEND_RESUME:
  		return "resume";
  	default:
  		return "";
  	}
  }
  
  static int suspend_stats_show(struct seq_file *s, void *unused)
  {
  	int i, index, last_dev, last_errno, last_step;
  
  	last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
  	last_dev %= REC_FAILED_NUM;
  	last_errno = suspend_stats.last_failed_errno + REC_FAILED_NUM - 1;
  	last_errno %= REC_FAILED_NUM;
  	last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1;
  	last_step %= REC_FAILED_NUM;
  	seq_printf(s, "%s: %d
  %s: %d
  %s: %d
  %s: %d
  "
  			"%s: %d
  %s: %d
  %s: %d
  %s: %d
  ",
  			"success", suspend_stats.success,
  			"fail", suspend_stats.fail,
  			"failed_freeze", suspend_stats.failed_freeze,
  			"failed_prepare", suspend_stats.failed_prepare,
  			"failed_suspend", suspend_stats.failed_suspend,
  			"failed_suspend_noirq",
  				suspend_stats.failed_suspend_noirq,
  			"failed_resume", suspend_stats.failed_resume,
  			"failed_resume_noirq",
  				suspend_stats.failed_resume_noirq);
  	seq_printf(s,	"failures:
    last_failed_dev:\t%-s
  ",
  			suspend_stats.failed_devs[last_dev]);
  	for (i = 1; i < REC_FAILED_NUM; i++) {
  		index = last_dev + REC_FAILED_NUM - i;
  		index %= REC_FAILED_NUM;
  		seq_printf(s, "\t\t\t%-s
  ",
  			suspend_stats.failed_devs[index]);
  	}
  	seq_printf(s,	"  last_failed_errno:\t%-d
  ",
  			suspend_stats.errno[last_errno]);
  	for (i = 1; i < REC_FAILED_NUM; i++) {
  		index = last_errno + REC_FAILED_NUM - i;
  		index %= REC_FAILED_NUM;
  		seq_printf(s, "\t\t\t%-d
  ",
  			suspend_stats.errno[index]);
  	}
  	seq_printf(s,	"  last_failed_step:\t%-s
  ",
  			suspend_step_name(
  				suspend_stats.failed_steps[last_step]));
  	for (i = 1; i < REC_FAILED_NUM; i++) {
  		index = last_step + REC_FAILED_NUM - i;
  		index %= REC_FAILED_NUM;
  		seq_printf(s, "\t\t\t%-s
  ",
  			suspend_step_name(
  				suspend_stats.failed_steps[index]));
  	}
  
  	return 0;
  }
  
  static int suspend_stats_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, suspend_stats_show, NULL);
  }
  
  static const struct file_operations suspend_stats_operations = {
  	.open           = suspend_stats_open,
  	.read           = seq_read,
  	.llseek         = seq_lseek,
  	.release        = single_release,
  };
  
  static int __init pm_debugfs_init(void)
  {
  	debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
  			NULL, NULL, &suspend_stats_operations);
  	return 0;
  }
  
  late_initcall(pm_debugfs_init);
  #endif /* CONFIG_DEBUG_FS */
ca123102f   Rafael J. Wysocki   PM: Fix build iss...
239
  #endif /* CONFIG_PM_SLEEP */
d76e15fb2   Greg Kroah-Hartman   driver core: make...
240
  struct kobject *power_kobj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
245
246
247
248
  
  /**
   *	state - control system power state.
   *
   *	show() returns what states are supported, which is hard-coded to
   *	'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and
   *	'disk' (Suspend-to-Disk).
   *
341d41661   Srivatsa S. Bhat   PM: Fix indentati...
249
   *	store() accepts one of those strings, translates it into the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
   *	proper enumerated value, and initiates a suspend transition.
   */
386f275f5   Kay Sievers   Driver Core: swit...
252
253
  static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
  			  char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  {
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
255
256
  	char *s = buf;
  #ifdef CONFIG_SUSPEND
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
  
  	for (i = 0; i < PM_SUSPEND_MAX; i++) {
123d3c13e   Pavel Machek   [PATCH] fix swsus...
260
261
  		if (pm_states[i] && valid_state(i))
  			s += sprintf(s,"%s ", pm_states[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  	}
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
263
  #endif
b0cb1a19d   Rafael J. Wysocki   Replace CONFIG_SO...
264
  #ifdef CONFIG_HIBERNATION
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
265
266
267
268
269
270
271
272
  	s += sprintf(s, "%s
  ", "disk");
  #else
  	if (s != buf)
  		/* convert the last space to a newline */
  		*(s-1) = '
  ';
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  	return (s - buf);
  }
386f275f5   Kay Sievers   Driver Core: swit...
275
276
  static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
  			   const char *buf, size_t n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  {
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
278
  #ifdef CONFIG_SUSPEND
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	suspend_state_t state = PM_SUSPEND_STANDBY;
3b364b8d5   Andreas Mohr   [PATCH] constify ...
280
  	const char * const *s;
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
281
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  	char *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	int len;
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
284
  	int error = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
  
  	p = memchr(buf, '
  ', n);
  	len = p ? p - buf : n;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
289
  	/* First, check if we are requested to hibernate */
8d98a690f   Rafael J. Wysocki   swsusp: fix sysfs...
290
  	if (len == 4 && !strncmp(buf, "disk", len)) {
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
291
  		error = hibernate();
341d41661   Srivatsa S. Bhat   PM: Fix indentati...
292
  		goto Exit;
a3d25c275   Rafael J. Wysocki   PM: Separate hibe...
293
  	}
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
294
  #ifdef CONFIG_SUSPEND
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
8d98a690f   Rafael J. Wysocki   swsusp: fix sysfs...
296
  		if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  			break;
  	}
501a708f1   Srivatsa S. Bhat   PM / Suspend: Fix...
299
  	if (state < PM_SUSPEND_MAX && *s) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  		error = enter_state(state);
2a77c46de   ShuoX Liu   PM / Suspend: Add...
301
302
303
304
305
  		if (error) {
  			suspend_stats.fail++;
  			dpm_save_failed_errno(error);
  		} else
  			suspend_stats.success++;
501a708f1   Srivatsa S. Bhat   PM / Suspend: Fix...
306
  	}
296699de6   Rafael J. Wysocki   Introduce CONFIG_...
307
308
309
  #endif
  
   Exit:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
  	return error ? error : n;
  }
  
  power_attr(state);
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  #ifdef CONFIG_PM_SLEEP
  /*
   * The 'wakeup_count' attribute, along with the functions defined in
   * drivers/base/power/wakeup.c, provides a means by which wakeup events can be
   * handled in a non-racy way.
   *
   * If a wakeup event occurs when the system is in a sleep state, it simply is
   * woken up.  In turn, if an event that would wake the system up from a sleep
   * state occurs when it is undergoing a transition to that sleep state, the
   * transition should be aborted.  Moreover, if such an event occurs when the
   * system is in the working state, an attempt to start a transition to the
   * given sleep state should fail during certain period after the detection of
   * the event.  Using the 'state' attribute alone is not sufficient to satisfy
   * these requirements, because a wakeup event may occur exactly when 'state'
   * is being written to and may be delivered to user space right before it is
   * frozen, so the event will remain only partially processed until the system is
   * woken up by another event.  In particular, it won't cause the transition to
   * a sleep state to be aborted.
   *
   * This difficulty may be overcome if user space uses 'wakeup_count' before
   * writing to 'state'.  It first should read from 'wakeup_count' and store
   * the read value.  Then, after carrying out its own preparations for the system
   * transition to a sleep state, it should write the stored value to
25985edce   Lucas De Marchi   Fix common misspe...
337
   * 'wakeup_count'.  If that fails, at least one wakeup event has occurred since
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
338
339
340
341
342
343
344
345
346
   * 'wakeup_count' was read and 'state' should not be written to.  Otherwise, it
   * is allowed to write to 'state', but the transition will be aborted if there
   * are any wakeup events detected after 'wakeup_count' was written to.
   */
  
  static ssize_t wakeup_count_show(struct kobject *kobj,
  				struct kobj_attribute *attr,
  				char *buf)
  {
074037ec7   Rafael J. Wysocki   PM / Wakeup: Intr...
347
  	unsigned int val;
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
348

074037ec7   Rafael J. Wysocki   PM / Wakeup: Intr...
349
350
  	return pm_get_wakeup_count(&val) ? sprintf(buf, "%u
  ", val) : -EINTR;
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
351
352
353
354
355
356
  }
  
  static ssize_t wakeup_count_store(struct kobject *kobj,
  				struct kobj_attribute *attr,
  				const char *buf, size_t n)
  {
074037ec7   Rafael J. Wysocki   PM / Wakeup: Intr...
357
  	unsigned int val;
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
358

074037ec7   Rafael J. Wysocki   PM / Wakeup: Intr...
359
  	if (sscanf(buf, "%u", &val) == 1) {
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
360
361
362
363
364
365
366
367
  		if (pm_save_wakeup_count(val))
  			return n;
  	}
  	return -EINVAL;
  }
  
  power_attr(wakeup_count);
  #endif /* CONFIG_PM_SLEEP */
c5c6ba4e0   Rafael J. Wysocki   [PATCH] PM: Add p...
368
369
  #ifdef CONFIG_PM_TRACE
  int pm_trace_enabled;
386f275f5   Kay Sievers   Driver Core: swit...
370
371
  static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
  			     char *buf)
c5c6ba4e0   Rafael J. Wysocki   [PATCH] PM: Add p...
372
373
374
375
376
377
  {
  	return sprintf(buf, "%d
  ", pm_trace_enabled);
  }
  
  static ssize_t
386f275f5   Kay Sievers   Driver Core: swit...
378
379
  pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
  	       const char *buf, size_t n)
c5c6ba4e0   Rafael J. Wysocki   [PATCH] PM: Add p...
380
381
382
383
384
385
386
387
388
389
390
  {
  	int val;
  
  	if (sscanf(buf, "%d", &val) == 1) {
  		pm_trace_enabled = !!val;
  		return n;
  	}
  	return -EINVAL;
  }
  
  power_attr(pm_trace);
d33ac60be   James Hogan   PM: Add sysfs att...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  
  static ssize_t pm_trace_dev_match_show(struct kobject *kobj,
  				       struct kobj_attribute *attr,
  				       char *buf)
  {
  	return show_trace_dev_match(buf, PAGE_SIZE);
  }
  
  static ssize_t
  pm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr,
  			 const char *buf, size_t n)
  {
  	return -EINVAL;
  }
  
  power_attr(pm_trace_dev_match);
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
407
  #endif /* CONFIG_PM_TRACE */
c5c6ba4e0   Rafael J. Wysocki   [PATCH] PM: Add p...
408
409
410
  
  static struct attribute * g[] = {
  	&state_attr.attr,
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
411
  #ifdef CONFIG_PM_TRACE
c5c6ba4e0   Rafael J. Wysocki   [PATCH] PM: Add p...
412
  	&pm_trace_attr.attr,
d33ac60be   James Hogan   PM: Add sysfs att...
413
  	&pm_trace_dev_match_attr.attr,
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
414
  #endif
0e06b4a89   Rafael J. Wysocki   PM: Add a switch ...
415
416
  #ifdef CONFIG_PM_SLEEP
  	&pm_async_attr.attr,
c125e96f0   Rafael J. Wysocki   PM: Make it possi...
417
  	&wakeup_count_attr.attr,
0e06b4a89   Rafael J. Wysocki   PM: Add a switch ...
418
  #ifdef CONFIG_PM_DEBUG
0e7d56e3d   Rafael J. Wysocki   Suspend: Testing ...
419
420
  	&pm_test_attr.attr,
  #endif
0e06b4a89   Rafael J. Wysocki   PM: Add a switch ...
421
  #endif
c5c6ba4e0   Rafael J. Wysocki   [PATCH] PM: Add p...
422
423
  	NULL,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
427
  
  static struct attribute_group attr_group = {
  	.attrs = g,
  };
5e928f77a   Rafael J. Wysocki   PM: Introduce cor...
428
429
  #ifdef CONFIG_PM_RUNTIME
  struct workqueue_struct *pm_wq;
7b199ca20   Alan Stern   PM / Runtime: Exp...
430
  EXPORT_SYMBOL_GPL(pm_wq);
5e928f77a   Rafael J. Wysocki   PM: Introduce cor...
431
432
433
  
  static int __init pm_start_workqueue(void)
  {
58a69cb47   Tejun Heo   workqueue, freeze...
434
  	pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);
5e928f77a   Rafael J. Wysocki   PM: Introduce cor...
435
436
437
438
439
440
  
  	return pm_wq ? 0 : -ENOMEM;
  }
  #else
  static inline int pm_start_workqueue(void) { return 0; }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
  static int __init pm_init(void)
  {
5e928f77a   Rafael J. Wysocki   PM: Introduce cor...
443
444
445
  	int error = pm_start_workqueue();
  	if (error)
  		return error;
ac5c24ec1   Rafael J. Wysocki   PM / Hibernate: M...
446
  	hibernate_image_size_init();
ddeb64870   Rafael J. Wysocki   PM / Hibernate: A...
447
  	hibernate_reserved_size_init();
d76e15fb2   Greg Kroah-Hartman   driver core: make...
448
449
  	power_kobj = kobject_create_and_add("power", NULL);
  	if (!power_kobj)
039a5dcd2   Greg Kroah-Hartman   kset: convert /sy...
450
  		return -ENOMEM;
d76e15fb2   Greg Kroah-Hartman   driver core: make...
451
  	return sysfs_create_group(power_kobj, &attr_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
  }
  
  core_initcall(pm_init);