aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r--drivers/acpi/power.c735
1 files changed, 394 insertions, 341 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 7db61b8fa11f..b820528a5fa3 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -41,6 +41,7 @@
41#include <linux/types.h> 41#include <linux/types.h>
42#include <linux/slab.h> 42#include <linux/slab.h>
43#include <linux/pm_runtime.h> 43#include <linux/pm_runtime.h>
44#include <linux/sysfs.h>
44#include <acpi/acpi_bus.h> 45#include <acpi/acpi_bus.h>
45#include <acpi/acpi_drivers.h> 46#include <acpi/acpi_drivers.h>
46#include "sleep.h" 47#include "sleep.h"
@@ -58,88 +59,121 @@ ACPI_MODULE_NAME("power");
58#define ACPI_POWER_RESOURCE_STATE_ON 0x01 59#define ACPI_POWER_RESOURCE_STATE_ON 0x01
59#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF 60#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
60 61
61static int acpi_power_add(struct acpi_device *device); 62struct acpi_power_dependent_device {
62static int acpi_power_remove(struct acpi_device *device, int type); 63 struct list_head node;
63 64 struct acpi_device *adev;
64static const struct acpi_device_id power_device_ids[] = { 65 struct work_struct work;
65 {ACPI_POWER_HID, 0},
66 {"", 0},
67};
68MODULE_DEVICE_TABLE(acpi, power_device_ids);
69
70#ifdef CONFIG_PM_SLEEP
71static int acpi_power_resume(struct device *dev);
72#endif
73static SIMPLE_DEV_PM_OPS(acpi_power_pm, NULL, acpi_power_resume);
74
75static struct acpi_driver acpi_power_driver = {
76 .name = "power",
77 .class = ACPI_POWER_CLASS,
78 .ids = power_device_ids,
79 .ops = {
80 .add = acpi_power_add,
81 .remove = acpi_power_remove,
82 },
83 .drv.pm = &acpi_power_pm,
84};
85
86/*
87 * A power managed device
88 * A device may rely on multiple power resources.
89 * */
90struct acpi_power_managed_device {
91 struct device *dev; /* The physical device */
92 acpi_handle *handle;
93};
94
95struct acpi_power_resource_device {
96 struct acpi_power_managed_device *device;
97 struct acpi_power_resource_device *next;
98}; 66};
99 67
100struct acpi_power_resource { 68struct acpi_power_resource {
101 struct acpi_device * device; 69 struct acpi_device device;
102 acpi_bus_id name; 70 struct list_head list_node;
71 struct list_head dependent;
72 char *name;
103 u32 system_level; 73 u32 system_level;
104 u32 order; 74 u32 order;
105 unsigned int ref_count; 75 unsigned int ref_count;
106 struct mutex resource_lock; 76 struct mutex resource_lock;
77};
107 78
108 /* List of devices relying on this power resource */ 79struct acpi_power_resource_entry {
109 struct acpi_power_resource_device *devices; 80 struct list_head node;
110 struct mutex devices_lock; 81 struct acpi_power_resource *resource;
111}; 82};
112 83
113static struct list_head acpi_power_resource_list; 84static LIST_HEAD(acpi_power_resource_list);
85static DEFINE_MUTEX(power_resource_list_lock);
114 86
115/* -------------------------------------------------------------------------- 87/* --------------------------------------------------------------------------
116 Power Resource Management 88 Power Resource Management
117 -------------------------------------------------------------------------- */ 89 -------------------------------------------------------------------------- */
118 90
119static int 91static inline
120acpi_power_get_context(acpi_handle handle, 92struct acpi_power_resource *to_power_resource(struct acpi_device *device)
121 struct acpi_power_resource **resource)
122{ 93{
123 int result = 0; 94 return container_of(device, struct acpi_power_resource, device);
124 struct acpi_device *device = NULL; 95}
96
97static struct acpi_power_resource *acpi_power_get_context(acpi_handle handle)
98{
99 struct acpi_device *device;
125 100
101 if (acpi_bus_get_device(handle, &device))
102 return NULL;
126 103
127 if (!resource) 104 return to_power_resource(device);
128 return -ENODEV; 105}
129 106
130 result = acpi_bus_get_device(handle, &device); 107static int acpi_power_resources_list_add(acpi_handle handle,
131 if (result) { 108 struct list_head *list)
132 printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle); 109{
133 return result; 110 struct acpi_power_resource *resource = acpi_power_get_context(handle);
134 } 111 struct acpi_power_resource_entry *entry;
135 112
136 *resource = acpi_driver_data(device); 113 if (!resource || !list)
137 if (!*resource) 114 return -EINVAL;
138 return -ENODEV; 115
116 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
117 if (!entry)
118 return -ENOMEM;
119
120 entry->resource = resource;
121 if (!list_empty(list)) {
122 struct acpi_power_resource_entry *e;
139 123
124 list_for_each_entry(e, list, node)
125 if (e->resource->order > resource->order) {
126 list_add_tail(&entry->node, &e->node);
127 return 0;
128 }
129 }
130 list_add_tail(&entry->node, list);
140 return 0; 131 return 0;
141} 132}
142 133
134void acpi_power_resources_list_free(struct list_head *list)
135{
136 struct acpi_power_resource_entry *entry, *e;
137
138 list_for_each_entry_safe(entry, e, list, node) {
139 list_del(&entry->node);
140 kfree(entry);
141 }
142}
143
144int acpi_extract_power_resources(union acpi_object *package, unsigned int start,
145 struct list_head *list)
146{
147 unsigned int i;
148 int err = 0;
149
150 for (i = start; i < package->package.count; i++) {
151 union acpi_object *element = &package->package.elements[i];
152 acpi_handle rhandle;
153
154 if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
155 err = -ENODATA;
156 break;
157 }
158 rhandle = element->reference.handle;
159 if (!rhandle) {
160 err = -ENODEV;
161 break;
162 }
163 err = acpi_add_power_resource(rhandle);
164 if (err)
165 break;
166
167 err = acpi_power_resources_list_add(rhandle, list);
168 if (err)
169 break;
170 }
171 if (err)
172 acpi_power_resources_list_free(list);
173
174 return err;
175}
176
143static int acpi_power_get_state(acpi_handle handle, int *state) 177static int acpi_power_get_state(acpi_handle handle, int *state)
144{ 178{
145 acpi_status status = AE_OK; 179 acpi_status status = AE_OK;
@@ -167,31 +201,23 @@ static int acpi_power_get_state(acpi_handle handle, int *state)
167 return 0; 201 return 0;
168} 202}
169 203
170static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) 204static int acpi_power_get_list_state(struct list_head *list, int *state)
171{ 205{
206 struct acpi_power_resource_entry *entry;
172 int cur_state; 207 int cur_state;
173 int i = 0;
174 208
175 if (!list || !state) 209 if (!list || !state)
176 return -EINVAL; 210 return -EINVAL;
177 211
178 /* The state of the list is 'on' IFF all resources are 'on'. */ 212 /* The state of the list is 'on' IFF all resources are 'on'. */
179 213 list_for_each_entry(entry, list, node) {
180 for (i = 0; i < list->count; i++) { 214 struct acpi_power_resource *resource = entry->resource;
181 struct acpi_power_resource *resource; 215 acpi_handle handle = resource->device.handle;
182 acpi_handle handle = list->handles[i];
183 int result; 216 int result;
184 217
185 result = acpi_power_get_context(handle, &resource);
186 if (result)
187 return result;
188
189 mutex_lock(&resource->resource_lock); 218 mutex_lock(&resource->resource_lock);
190
191 result = acpi_power_get_state(handle, &cur_state); 219 result = acpi_power_get_state(handle, &cur_state);
192
193 mutex_unlock(&resource->resource_lock); 220 mutex_unlock(&resource->resource_lock);
194
195 if (result) 221 if (result)
196 return result; 222 return result;
197 223
@@ -203,54 +229,52 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
203 cur_state ? "on" : "off")); 229 cur_state ? "on" : "off"));
204 230
205 *state = cur_state; 231 *state = cur_state;
206
207 return 0; 232 return 0;
208} 233}
209 234
210/* Resume the device when all power resources in _PR0 are on */ 235static void acpi_power_resume_dependent(struct work_struct *work)
211static void acpi_power_on_device(struct acpi_power_managed_device *device)
212{ 236{
213 struct acpi_device *acpi_dev; 237 struct acpi_power_dependent_device *dep;
214 acpi_handle handle = device->handle; 238 struct acpi_device_physical_node *pn;
239 struct acpi_device *adev;
215 int state; 240 int state;
216 241
217 if (acpi_bus_get_device(handle, &acpi_dev)) 242 dep = container_of(work, struct acpi_power_dependent_device, work);
243 adev = dep->adev;
244 if (acpi_power_get_inferred_state(adev, &state))
218 return; 245 return;
219 246
220 if(acpi_power_get_inferred_state(acpi_dev, &state)) 247 if (state > ACPI_STATE_D0)
221 return; 248 return;
222 249
223 if (state == ACPI_STATE_D0 && pm_runtime_suspended(device->dev)) 250 mutex_lock(&adev->physical_node_lock);
224 pm_request_resume(device->dev); 251
252 list_for_each_entry(pn, &adev->physical_node_list, node)
253 pm_request_resume(pn->dev);
254
255 list_for_each_entry(pn, &adev->power_dependent, node)
256 pm_request_resume(pn->dev);
257
258 mutex_unlock(&adev->physical_node_lock);
225} 259}
226 260
227static int __acpi_power_on(struct acpi_power_resource *resource) 261static int __acpi_power_on(struct acpi_power_resource *resource)
228{ 262{
229 acpi_status status = AE_OK; 263 acpi_status status = AE_OK;
230 264
231 status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); 265 status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL);
232 if (ACPI_FAILURE(status)) 266 if (ACPI_FAILURE(status))
233 return -ENODEV; 267 return -ENODEV;
234 268
235 /* Update the power resource's _device_ power state */
236 resource->device->power.state = ACPI_STATE_D0;
237
238 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", 269 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
239 resource->name)); 270 resource->name));
240 271
241 return 0; 272 return 0;
242} 273}
243 274
244static int acpi_power_on(acpi_handle handle) 275static int acpi_power_on(struct acpi_power_resource *resource)
245{ 276{
246 int result = 0; 277 int result = 0;;
247 bool resume_device = false;
248 struct acpi_power_resource *resource = NULL;
249 struct acpi_power_resource_device *device_list;
250
251 result = acpi_power_get_context(handle, &resource);
252 if (result)
253 return result;
254 278
255 mutex_lock(&resource->resource_lock); 279 mutex_lock(&resource->resource_lock);
256 280
@@ -260,39 +284,38 @@ static int acpi_power_on(acpi_handle handle)
260 resource->name)); 284 resource->name));
261 } else { 285 } else {
262 result = __acpi_power_on(resource); 286 result = __acpi_power_on(resource);
263 if (result) 287 if (result) {
264 resource->ref_count--; 288 resource->ref_count--;
265 else 289 } else {
266 resume_device = true; 290 struct acpi_power_dependent_device *dep;
291
292 list_for_each_entry(dep, &resource->dependent, node)
293 schedule_work(&dep->work);
294 }
267 } 295 }
268 296
269 mutex_unlock(&resource->resource_lock); 297 mutex_unlock(&resource->resource_lock);
270 298
271 if (!resume_device) 299 return result;
272 return result; 300}
273
274 mutex_lock(&resource->devices_lock);
275 301
276 device_list = resource->devices; 302static int __acpi_power_off(struct acpi_power_resource *resource)
277 while (device_list) { 303{
278 acpi_power_on_device(device_list->device); 304 acpi_status status;
279 device_list = device_list->next;
280 }
281 305
282 mutex_unlock(&resource->devices_lock); 306 status = acpi_evaluate_object(resource->device.handle, "_OFF",
307 NULL, NULL);
308 if (ACPI_FAILURE(status))
309 return -ENODEV;
283 310
284 return result; 311 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned off\n",
312 resource->name));
313 return 0;
285} 314}
286 315
287static int acpi_power_off(acpi_handle handle) 316static int acpi_power_off(struct acpi_power_resource *resource)
288{ 317{
289 int result = 0; 318 int result = 0;
290 acpi_status status = AE_OK;
291 struct acpi_power_resource *resource = NULL;
292
293 result = acpi_power_get_context(handle, &resource);
294 if (result)
295 return result;
296 319
297 mutex_lock(&resource->resource_lock); 320 mutex_lock(&resource->resource_lock);
298 321
@@ -307,19 +330,10 @@ static int acpi_power_off(acpi_handle handle)
307 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 330 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
308 "Power resource [%s] still in use\n", 331 "Power resource [%s] still in use\n",
309 resource->name)); 332 resource->name));
310 goto unlock;
311 }
312
313 status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
314 if (ACPI_FAILURE(status)) {
315 result = -ENODEV;
316 } else { 333 } else {
317 /* Update the power resource's _device_ power state */ 334 result = __acpi_power_off(resource);
318 resource->device->power.state = ACPI_STATE_D3; 335 if (result)
319 336 resource->ref_count++;
320 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
321 "Power resource [%s] turned off\n",
322 resource->name));
323 } 337 }
324 338
325 unlock: 339 unlock:
@@ -328,155 +342,202 @@ static int acpi_power_off(acpi_handle handle)
328 return result; 342 return result;
329} 343}
330 344
331static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) 345static int acpi_power_off_list(struct list_head *list)
332{ 346{
333 int i; 347 struct acpi_power_resource_entry *entry;
348 int result = 0;
334 349
335 for (i = num_res - 1; i >= 0 ; i--) 350 list_for_each_entry_reverse(entry, list, node) {
336 acpi_power_off(list->handles[i]); 351 result = acpi_power_off(entry->resource);
337} 352 if (result)
353 goto err;
354 }
355 return 0;
338 356
339static void acpi_power_off_list(struct acpi_handle_list *list) 357 err:
340{ 358 list_for_each_entry_continue(entry, list, node)
341 __acpi_power_off_list(list, list->count); 359 acpi_power_on(entry->resource);
360
361 return result;
342} 362}
343 363
344static int acpi_power_on_list(struct acpi_handle_list *list) 364static int acpi_power_on_list(struct list_head *list)
345{ 365{
366 struct acpi_power_resource_entry *entry;
346 int result = 0; 367 int result = 0;
347 int i;
348 368
349 for (i = 0; i < list->count; i++) { 369 list_for_each_entry(entry, list, node) {
350 result = acpi_power_on(list->handles[i]); 370 result = acpi_power_on(entry->resource);
351 if (result) { 371 if (result)
352 __acpi_power_off_list(list, i); 372 goto err;
353 break;
354 }
355 } 373 }
374 return 0;
375
376 err:
377 list_for_each_entry_continue_reverse(entry, list, node)
378 acpi_power_off(entry->resource);
356 379
357 return result; 380 return result;
358} 381}
359 382
360static void __acpi_power_resource_unregister_device(struct device *dev, 383static void acpi_power_add_dependent(struct acpi_power_resource *resource,
361 acpi_handle res_handle) 384 struct acpi_device *adev)
362{ 385{
363 struct acpi_power_resource *resource = NULL; 386 struct acpi_power_dependent_device *dep;
364 struct acpi_power_resource_device *prev, *curr;
365 387
366 if (acpi_power_get_context(res_handle, &resource)) 388 mutex_lock(&resource->resource_lock);
367 return;
368 389
369 mutex_lock(&resource->devices_lock); 390 list_for_each_entry(dep, &resource->dependent, node)
370 prev = NULL; 391 if (dep->adev == adev)
371 curr = resource->devices; 392 goto out;
372 while (curr) {
373 if (curr->device->dev == dev) {
374 if (!prev)
375 resource->devices = curr->next;
376 else
377 prev->next = curr->next;
378
379 kfree(curr);
380 break;
381 }
382 393
383 prev = curr; 394 dep = kzalloc(sizeof(*dep), GFP_KERNEL);
384 curr = curr->next; 395 if (!dep)
385 } 396 goto out;
386 mutex_unlock(&resource->devices_lock); 397
398 dep->adev = adev;
399 INIT_WORK(&dep->work, acpi_power_resume_dependent);
400 list_add_tail(&dep->node, &resource->dependent);
401
402 out:
403 mutex_unlock(&resource->resource_lock);
387} 404}
388 405
389/* Unlink dev from all power resources in _PR0 */ 406static void acpi_power_remove_dependent(struct acpi_power_resource *resource,
390void acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle) 407 struct acpi_device *adev)
391{ 408{
392 struct acpi_device *acpi_dev; 409 struct acpi_power_dependent_device *dep;
393 struct acpi_handle_list *list; 410 struct work_struct *work = NULL;
394 int i;
395 411
396 if (!dev || !handle) 412 mutex_lock(&resource->resource_lock);
397 return;
398 413
399 if (acpi_bus_get_device(handle, &acpi_dev)) 414 list_for_each_entry(dep, &resource->dependent, node)
400 return; 415 if (dep->adev == adev) {
416 list_del(&dep->node);
417 work = &dep->work;
418 break;
419 }
401 420
402 list = &acpi_dev->power.states[ACPI_STATE_D0].resources; 421 mutex_unlock(&resource->resource_lock);
403 422
404 for (i = 0; i < list->count; i++) 423 if (work) {
405 __acpi_power_resource_unregister_device(dev, 424 cancel_work_sync(work);
406 list->handles[i]); 425 kfree(dep);
426 }
407} 427}
408EXPORT_SYMBOL_GPL(acpi_power_resource_unregister_device);
409 428
410static int __acpi_power_resource_register_device( 429static struct attribute *attrs[] = {
411 struct acpi_power_managed_device *powered_device, acpi_handle handle) 430 NULL,
412{ 431};
413 struct acpi_power_resource *resource = NULL;
414 struct acpi_power_resource_device *power_resource_device;
415 int result;
416 432
417 result = acpi_power_get_context(handle, &resource); 433static struct attribute_group attr_groups[] = {
418 if (result) 434 [ACPI_STATE_D0] = {
419 return result; 435 .name = "power_resources_D0",
436 .attrs = attrs,
437 },
438 [ACPI_STATE_D1] = {
439 .name = "power_resources_D1",
440 .attrs = attrs,
441 },
442 [ACPI_STATE_D2] = {
443 .name = "power_resources_D2",
444 .attrs = attrs,
445 },
446 [ACPI_STATE_D3_HOT] = {
447 .name = "power_resources_D3hot",
448 .attrs = attrs,
449 },
450};
420 451
421 power_resource_device = kzalloc( 452static void acpi_power_hide_list(struct acpi_device *adev, int state)
422 sizeof(*power_resource_device), GFP_KERNEL); 453{
423 if (!power_resource_device) 454 struct acpi_device_power_state *ps = &adev->power.states[state];
424 return -ENOMEM; 455 struct acpi_power_resource_entry *entry;
425 456
426 power_resource_device->device = powered_device; 457 if (list_empty(&ps->resources))
458 return;
427 459
428 mutex_lock(&resource->devices_lock); 460 list_for_each_entry_reverse(entry, &ps->resources, node) {
429 power_resource_device->next = resource->devices; 461 struct acpi_device *res_dev = &entry->resource->device;
430 resource->devices = power_resource_device;
431 mutex_unlock(&resource->devices_lock);
432 462
433 return 0; 463 sysfs_remove_link_from_group(&adev->dev.kobj,
464 attr_groups[state].name,
465 dev_name(&res_dev->dev));
466 }
467 sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
434} 468}
435 469
436/* Link dev to all power resources in _PR0 */ 470static void acpi_power_expose_list(struct acpi_device *adev, int state)
437int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
438{ 471{
439 struct acpi_device *acpi_dev; 472 struct acpi_device_power_state *ps = &adev->power.states[state];
440 struct acpi_handle_list *list; 473 struct acpi_power_resource_entry *entry;
441 struct acpi_power_managed_device *powered_device; 474 int ret;
442 int i, ret;
443 475
444 if (!dev || !handle) 476 if (list_empty(&ps->resources))
445 return -ENODEV; 477 return;
446 478
447 ret = acpi_bus_get_device(handle, &acpi_dev); 479 ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
448 if (ret) 480 if (ret)
449 goto no_power_resource; 481 return;
450 482
451 if (!acpi_dev->power.flags.power_resources) 483 list_for_each_entry(entry, &ps->resources, node) {
452 goto no_power_resource; 484 struct acpi_device *res_dev = &entry->resource->device;
453 485
454 powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL); 486 ret = sysfs_add_link_to_group(&adev->dev.kobj,
455 if (!powered_device) 487 attr_groups[state].name,
456 return -ENOMEM; 488 &res_dev->dev.kobj,
489 dev_name(&res_dev->dev));
490 if (ret) {
491 acpi_power_hide_list(adev, state);
492 break;
493 }
494 }
495}
457 496
458 powered_device->dev = dev; 497void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
459 powered_device->handle = handle; 498{
499 struct acpi_device_power_state *ps;
500 struct acpi_power_resource_entry *entry;
501 int state;
460 502
461 list = &acpi_dev->power.states[ACPI_STATE_D0].resources; 503 if (!adev->power.flags.power_resources)
504 return;
462 505
463 for (i = 0; i < list->count; i++) { 506 ps = &adev->power.states[ACPI_STATE_D0];
464 ret = __acpi_power_resource_register_device(powered_device, 507 list_for_each_entry(entry, &ps->resources, node) {
465 list->handles[i]); 508 struct acpi_power_resource *resource = entry->resource;
466 509
467 if (ret) { 510 if (add)
468 acpi_power_resource_unregister_device(dev, handle); 511 acpi_power_add_dependent(resource, adev);
469 break; 512 else
470 } 513 acpi_power_remove_dependent(resource, adev);
514 }
515
516 for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
517 if (add)
518 acpi_power_expose_list(adev, state);
519 else
520 acpi_power_hide_list(adev, state);
471 } 521 }
522}
523
524int acpi_power_min_system_level(struct list_head *list)
525{
526 struct acpi_power_resource_entry *entry;
527 int system_level = 5;
472 528
473 return ret; 529 list_for_each_entry(entry, list, node) {
530 struct acpi_power_resource *resource = entry->resource;
474 531
475no_power_resource: 532 if (system_level > resource->system_level)
476 printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!\n"); 533 system_level = resource->system_level;
477 return -ENODEV; 534 }
535 return system_level;
478} 536}
479EXPORT_SYMBOL_GPL(acpi_power_resource_register_device); 537
538/* --------------------------------------------------------------------------
539 Device Power Management
540 -------------------------------------------------------------------------- */
480 541
481/** 542/**
482 * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in 543 * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
@@ -549,7 +610,7 @@ int acpi_device_sleep_wake(struct acpi_device *dev,
549 */ 610 */
550int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) 611int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
551{ 612{
552 int i, err = 0; 613 int err = 0;
553 614
554 if (!dev || !dev->wakeup.flags.valid) 615 if (!dev || !dev->wakeup.flags.valid)
555 return -EINVAL; 616 return -EINVAL;
@@ -559,24 +620,17 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
559 if (dev->wakeup.prepare_count++) 620 if (dev->wakeup.prepare_count++)
560 goto out; 621 goto out;
561 622
562 /* Open power resource */ 623 err = acpi_power_on_list(&dev->wakeup.resources);
563 for (i = 0; i < dev->wakeup.resources.count; i++) { 624 if (err) {
564 int ret = acpi_power_on(dev->wakeup.resources.handles[i]); 625 dev_err(&dev->dev, "Cannot turn wakeup power resources on\n");
565 if (ret) { 626 dev->wakeup.flags.valid = 0;
566 printk(KERN_ERR PREFIX "Transition power state\n"); 627 } else {
567 dev->wakeup.flags.valid = 0; 628 /*
568 err = -ENODEV; 629 * Passing 3 as the third argument below means the device may be
569 goto err_out; 630 * put into arbitrary power state afterward.
570 } 631 */
632 err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
571 } 633 }
572
573 /*
574 * Passing 3 as the third argument below means the device may be placed
575 * in arbitrary power state afterwards.
576 */
577 err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);
578
579 err_out:
580 if (err) 634 if (err)
581 dev->wakeup.prepare_count = 0; 635 dev->wakeup.prepare_count = 0;
582 636
@@ -593,7 +647,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
593 */ 647 */
594int acpi_disable_wakeup_device_power(struct acpi_device *dev) 648int acpi_disable_wakeup_device_power(struct acpi_device *dev)
595{ 649{
596 int i, err = 0; 650 int err = 0;
597 651
598 if (!dev || !dev->wakeup.flags.valid) 652 if (!dev || !dev->wakeup.flags.valid)
599 return -EINVAL; 653 return -EINVAL;
@@ -614,15 +668,10 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
614 if (err) 668 if (err)
615 goto out; 669 goto out;
616 670
617 /* Close power resource */ 671 err = acpi_power_off_list(&dev->wakeup.resources);
618 for (i = 0; i < dev->wakeup.resources.count; i++) { 672 if (err) {
619 int ret = acpi_power_off(dev->wakeup.resources.handles[i]); 673 dev_err(&dev->dev, "Cannot turn wakeup power resources off\n");
620 if (ret) { 674 dev->wakeup.flags.valid = 0;
621 printk(KERN_ERR PREFIX "Transition power state\n");
622 dev->wakeup.flags.valid = 0;
623 err = -ENODEV;
624 goto out;
625 }
626 } 675 }
627 676
628 out: 677 out:
@@ -630,14 +679,9 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
630 return err; 679 return err;
631} 680}
632 681
633/* --------------------------------------------------------------------------
634 Device Power Management
635 -------------------------------------------------------------------------- */
636
637int acpi_power_get_inferred_state(struct acpi_device *device, int *state) 682int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
638{ 683{
639 int result = 0; 684 int result = 0;
640 struct acpi_handle_list *list = NULL;
641 int list_state = 0; 685 int list_state = 0;
642 int i = 0; 686 int i = 0;
643 687
@@ -649,8 +693,9 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
649 * required for a given D-state are 'on'. 693 * required for a given D-state are 'on'.
650 */ 694 */
651 for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) { 695 for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
652 list = &device->power.states[i].resources; 696 struct list_head *list = &device->power.states[i].resources;
653 if (list->count < 1) 697
698 if (list_empty(list))
654 continue; 699 continue;
655 700
656 result = acpi_power_get_list_state(list, &list_state); 701 result = acpi_power_get_list_state(list, &list_state);
@@ -669,7 +714,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
669 714
670int acpi_power_on_resources(struct acpi_device *device, int state) 715int acpi_power_on_resources(struct acpi_device *device, int state)
671{ 716{
672 if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) 717 if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3_HOT)
673 return -EINVAL; 718 return -EINVAL;
674 719
675 return acpi_power_on_list(&device->power.states[state].resources); 720 return acpi_power_on_list(&device->power.states[state].resources);
@@ -682,7 +727,7 @@ int acpi_power_transition(struct acpi_device *device, int state)
682 if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) 727 if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
683 return -EINVAL; 728 return -EINVAL;
684 729
685 if (device->power.state == state) 730 if (device->power.state == state || !device->flags.power_manageable)
686 return 0; 731 return 0;
687 732
688 if ((device->power.state < ACPI_STATE_D0) 733 if ((device->power.state < ACPI_STATE_D0)
@@ -710,118 +755,126 @@ int acpi_power_transition(struct acpi_device *device, int state)
710 return result; 755 return result;
711} 756}
712 757
713/* -------------------------------------------------------------------------- 758static void acpi_release_power_resource(struct device *dev)
714 Driver Interface 759{
715 -------------------------------------------------------------------------- */ 760 struct acpi_device *device = to_acpi_device(dev);
761 struct acpi_power_resource *resource;
762
763 resource = container_of(device, struct acpi_power_resource, device);
764
765 mutex_lock(&power_resource_list_lock);
766 list_del(&resource->list_node);
767 mutex_unlock(&power_resource_list_lock);
768
769 acpi_free_ids(device);
770 kfree(resource);
771}
716 772
717static int acpi_power_add(struct acpi_device *device) 773static ssize_t acpi_power_in_use_show(struct device *dev,
774 struct device_attribute *attr,
775 char *buf) {
776 struct acpi_power_resource *resource;
777
778 resource = to_power_resource(to_acpi_device(dev));
779 return sprintf(buf, "%u\n", !!resource->ref_count);
780}
781static DEVICE_ATTR(resource_in_use, 0444, acpi_power_in_use_show, NULL);
782
783static void acpi_power_sysfs_remove(struct acpi_device *device)
718{ 784{
719 int result = 0, state; 785 device_remove_file(&device->dev, &dev_attr_resource_in_use);
720 acpi_status status = AE_OK; 786}
721 struct acpi_power_resource *resource = NULL; 787
788int acpi_add_power_resource(acpi_handle handle)
789{
790 struct acpi_power_resource *resource;
791 struct acpi_device *device = NULL;
722 union acpi_object acpi_object; 792 union acpi_object acpi_object;
723 struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object }; 793 struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
794 acpi_status status;
795 int state, result = -ENODEV;
724 796
797 acpi_bus_get_device(handle, &device);
798 if (device)
799 return 0;
725 800
726 if (!device) 801 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
727 return -EINVAL;
728
729 resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
730 if (!resource) 802 if (!resource)
731 return -ENOMEM; 803 return -ENOMEM;
732 804
733 resource->device = device; 805 device = &resource->device;
806 acpi_init_device_object(device, handle, ACPI_BUS_TYPE_POWER,
807 ACPI_STA_DEFAULT);
734 mutex_init(&resource->resource_lock); 808 mutex_init(&resource->resource_lock);
735 mutex_init(&resource->devices_lock); 809 INIT_LIST_HEAD(&resource->dependent);
736 strcpy(resource->name, device->pnp.bus_id); 810 resource->name = device->pnp.bus_id;
737 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); 811 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
738 strcpy(acpi_device_class(device), ACPI_POWER_CLASS); 812 strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
739 device->driver_data = resource; 813 device->power.state = ACPI_STATE_UNKNOWN;
740 814
741 /* Evalute the object to get the system level and resource order. */ 815 /* Evalute the object to get the system level and resource order. */
742 status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer); 816 status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
743 if (ACPI_FAILURE(status)) { 817 if (ACPI_FAILURE(status))
744 result = -ENODEV; 818 goto err;
745 goto end; 819
746 }
747 resource->system_level = acpi_object.power_resource.system_level; 820 resource->system_level = acpi_object.power_resource.system_level;
748 resource->order = acpi_object.power_resource.resource_order; 821 resource->order = acpi_object.power_resource.resource_order;
749 822
750 result = acpi_power_get_state(device->handle, &state); 823 result = acpi_power_get_state(handle, &state);
751 if (result) 824 if (result)
752 goto end; 825 goto err;
753
754 switch (state) {
755 case ACPI_POWER_RESOURCE_STATE_ON:
756 device->power.state = ACPI_STATE_D0;
757 break;
758 case ACPI_POWER_RESOURCE_STATE_OFF:
759 device->power.state = ACPI_STATE_D3;
760 break;
761 default:
762 device->power.state = ACPI_STATE_UNKNOWN;
763 break;
764 }
765 826
766 printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), 827 printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
767 acpi_device_bid(device), state ? "on" : "off"); 828 acpi_device_bid(device), state ? "on" : "off");
768 829
769 end: 830 device->flags.match_driver = true;
831 result = acpi_device_add(device, acpi_release_power_resource);
770 if (result) 832 if (result)
771 kfree(resource); 833 goto err;
772 834
773 return result; 835 if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
774} 836 device->remove = acpi_power_sysfs_remove;
775
776static int acpi_power_remove(struct acpi_device *device, int type)
777{
778 struct acpi_power_resource *resource;
779
780 if (!device)
781 return -EINVAL;
782
783 resource = acpi_driver_data(device);
784 if (!resource)
785 return -EINVAL;
786
787 kfree(resource);
788 837
838 mutex_lock(&power_resource_list_lock);
839 list_add(&resource->list_node, &acpi_power_resource_list);
840 mutex_unlock(&power_resource_list_lock);
841 acpi_device_add_finalize(device);
789 return 0; 842 return 0;
843
844 err:
845 acpi_release_power_resource(&device->dev);
846 return result;
790} 847}
791 848
792#ifdef CONFIG_PM_SLEEP 849#ifdef CONFIG_ACPI_SLEEP
793static int acpi_power_resume(struct device *dev) 850void acpi_resume_power_resources(void)
794{ 851{
795 int result = 0, state;
796 struct acpi_device *device;
797 struct acpi_power_resource *resource; 852 struct acpi_power_resource *resource;
798 853
799 if (!dev) 854 mutex_lock(&power_resource_list_lock);
800 return -EINVAL;
801 855
802 device = to_acpi_device(dev); 856 list_for_each_entry(resource, &acpi_power_resource_list, list_node) {
803 resource = acpi_driver_data(device); 857 int result, state;
804 if (!resource)
805 return -EINVAL;
806 858
807 mutex_lock(&resource->resource_lock); 859 mutex_lock(&resource->resource_lock);
808 860
809 result = acpi_power_get_state(device->handle, &state); 861 result = acpi_power_get_state(resource->device.handle, &state);
810 if (result) 862 if (result)
811 goto unlock; 863 continue;
812 864
813 if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count) 865 if (state == ACPI_POWER_RESOURCE_STATE_OFF
814 result = __acpi_power_on(resource); 866 && resource->ref_count) {
867 dev_info(&resource->device.dev, "Turning ON\n");
868 __acpi_power_on(resource);
869 } else if (state == ACPI_POWER_RESOURCE_STATE_ON
870 && !resource->ref_count) {
871 dev_info(&resource->device.dev, "Turning OFF\n");
872 __acpi_power_off(resource);
873 }
815 874
816 unlock: 875 mutex_unlock(&resource->resource_lock);
817 mutex_unlock(&resource->resource_lock); 876 }
818 877
819 return result; 878 mutex_unlock(&power_resource_list_lock);
820} 879}
821#endif 880#endif
822
823int __init acpi_power_init(void)
824{
825 INIT_LIST_HEAD(&acpi_power_resource_list);
826 return acpi_bus_register_driver(&acpi_power_driver);
827}