Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpower.c
Go to the documentation of this file.
00001 /* 00002 * acpi_power.c - ACPI Bus Power Management ($Revision: 39 $) 00003 * 00004 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 00005 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 00006 * 00007 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or (at 00012 * your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, but 00015 * WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License along 00020 * with this program; if not, write to the Free Software Foundation, Inc., 00021 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00022 * 00023 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00024 */ 00025 00026 /* 00027 * ACPI power-managed devices may be controlled in two ways: 00028 * 1. via "Device Specific (D-State) Control" 00029 * 2. via "Power Resource Control". 00030 * This module is used to manage devices relying on Power Resource Control. 00031 * 00032 * An ACPI "power resource object" describes a software controllable power 00033 * plane, clock plane, or other resource used by a power managed device. 00034 * A device may rely on multiple power resources, and a power resource 00035 * may be shared by multiple devices. 00036 */ 00037 00038 /* 00039 * Modified for ReactOS and latest ACPICA 00040 * Copyright (C)2009 Samuel Serapion 00041 */ 00042 00043 #include <ntddk.h> 00044 #include <acpi.h> 00045 #include <acpi_bus.h> 00046 #include <acpi_drivers.h> 00047 #include <glue.h> 00048 00049 #define NDEBUG 00050 #include <debug.h> 00051 00052 00053 #define _COMPONENT ACPI_POWER_COMPONENT 00054 ACPI_MODULE_NAME ("acpi_power") 00055 00056 #define ACPI_POWER_RESOURCE_STATE_OFF 0x00 00057 #define ACPI_POWER_RESOURCE_STATE_ON 0x01 00058 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF 00059 00060 int acpi_power_nocheck; 00061 00062 static int acpi_power_add (struct acpi_device *device); 00063 static int acpi_power_remove (struct acpi_device *device, int type); 00064 static int acpi_power_resume(struct acpi_device *device, int state); 00065 00066 static struct acpi_driver acpi_power_driver = { 00067 {0,0}, 00068 ACPI_POWER_DRIVER_NAME, 00069 ACPI_POWER_CLASS, 00070 0, 00071 0, 00072 ACPI_POWER_HID, 00073 {acpi_power_add, acpi_power_remove, NULL, NULL, acpi_power_resume} 00074 }; 00075 00076 struct acpi_power_reference { 00077 struct list_head node; 00078 struct acpi_device *device; 00079 }; 00080 00081 struct acpi_power_resource 00082 { 00083 struct acpi_device * device; 00084 acpi_bus_id name; 00085 UINT32 system_level; 00086 UINT32 order; 00087 //struct mutex resource_lock; 00088 struct list_head reference; 00089 }; 00090 00091 static struct list_head acpi_power_resource_list; 00092 00093 00094 /* -------------------------------------------------------------------------- 00095 Power Resource Management 00096 -------------------------------------------------------------------------- */ 00097 00098 static int 00099 acpi_power_get_context ( 00100 ACPI_HANDLE handle, 00101 struct acpi_power_resource **resource) 00102 { 00103 int result = 0; 00104 struct acpi_device *device = NULL; 00105 00106 if (!resource) 00107 return_VALUE(-15); 00108 00109 result = acpi_bus_get_device(handle, &device); 00110 if (result) { 00111 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error getting context [%p]\n", 00112 handle)); 00113 return_VALUE(result); 00114 } 00115 00116 *resource = (struct acpi_power_resource *) acpi_driver_data(device); 00117 if (!*resource) 00118 return_VALUE(-15); 00119 00120 return 0; 00121 } 00122 00123 00124 static int 00125 acpi_power_get_state ( 00126 ACPI_HANDLE handle, 00127 int *state) 00128 { 00129 ACPI_STATUS status = AE_OK; 00130 unsigned long long sta = 0; 00131 char node_name[5]; 00132 ACPI_BUFFER buffer = { sizeof(node_name), node_name }; 00133 00134 00135 if (!handle || !state) 00136 return_VALUE(-1); 00137 00138 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 00139 if (ACPI_FAILURE(status)) 00140 return_VALUE(-15); 00141 00142 *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON: 00143 ACPI_POWER_RESOURCE_STATE_OFF; 00144 00145 AcpiGetName(handle, ACPI_SINGLE_NAME, &buffer); 00146 00147 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", 00148 node_name, *state?"on":"off")); 00149 00150 return 0; 00151 } 00152 00153 00154 static int 00155 acpi_power_get_list_state ( 00156 struct acpi_handle_list *list, 00157 int *state) 00158 { 00159 int result = 0, state1; 00160 UINT32 i = 0; 00161 00162 if (!list || !state) 00163 return_VALUE(-1); 00164 00165 /* The state of the list is 'on' IFF all resources are 'on'. */ 00166 00167 for (i=0; i<list->count; i++) { 00168 /* 00169 * The state of the power resource can be obtained by 00170 * using the ACPI handle. In such case it is unnecessary to 00171 * get the Power resource first and then get its state again. 00172 */ 00173 result = acpi_power_get_state(list->handles[i], &state1); 00174 if (result) 00175 return result; 00176 00177 *state = state1; 00178 00179 if (*state != ACPI_POWER_RESOURCE_STATE_ON) 00180 break; 00181 } 00182 00183 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", 00184 *state?"on":"off")); 00185 00186 return result; 00187 } 00188 00189 00190 static int 00191 acpi_power_on ( 00192 ACPI_HANDLE handle, struct acpi_device *dev) 00193 { 00194 int result = 0; 00195 int found = 0; 00196 ACPI_STATUS status = AE_OK; 00197 struct acpi_power_resource *resource = NULL; 00198 struct list_head *node, *next; 00199 struct acpi_power_reference *ref; 00200 00201 result = acpi_power_get_context(handle, &resource); 00202 if (result) 00203 return result; 00204 00205 //mutex_lock(&resource->resource_lock); 00206 list_for_each_safe(node, next, &resource->reference) { 00207 ref = container_of(node, struct acpi_power_reference, node); 00208 if (dev->handle == ref->device->handle) { 00209 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n", 00210 dev->pnp.bus_id, resource->name)); 00211 found = 1; 00212 break; 00213 } 00214 } 00215 00216 if (!found) { 00217 ref = ExAllocatePoolWithTag(NonPagedPool,sizeof (struct acpi_power_reference),'IPCA'); 00218 if (!ref) { 00219 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n")); 00220 //mutex_unlock(&resource->resource_lock); 00221 return -1;//-ENOMEM; 00222 } 00223 list_add_tail(&ref->node, &resource->reference); 00224 ref->device = dev; 00225 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n", 00226 dev->pnp.bus_id, resource->name)); 00227 } 00228 //mutex_unlock(&resource->resource_lock); 00229 00230 status = AcpiEvaluateObject(resource->device->handle, "_ON", NULL, NULL); 00231 if (ACPI_FAILURE(status)) 00232 return_VALUE(-15); 00233 00234 /* Update the power resource's _device_ power state */ 00235 resource->device->power.state = ACPI_STATE_D0; 00236 00237 return 0; 00238 } 00239 00240 00241 static int 00242 acpi_power_off_device ( 00243 ACPI_HANDLE handle, 00244 struct acpi_device *dev) 00245 { 00246 int result = 0; 00247 ACPI_STATUS status = AE_OK; 00248 struct acpi_power_resource *resource = NULL; 00249 struct list_head *node, *next; 00250 struct acpi_power_reference *ref; 00251 00252 result = acpi_power_get_context(handle, &resource); 00253 if (result) 00254 return result; 00255 00256 //mutex_lock(&resource->resource_lock); 00257 list_for_each_safe(node, next, &resource->reference) { 00258 ref = container_of(node, struct acpi_power_reference, node); 00259 if (dev->handle == ref->device->handle) { 00260 list_del(&ref->node); 00261 ExFreePool(ref); 00262 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n", 00263 dev->pnp.bus_id, resource->name)); 00264 break; 00265 } 00266 } 00267 00268 if (!list_empty(&resource->reference)) { 00269 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n", 00270 resource->name)); 00271 //mutex_unlock(&resource->resource_lock); 00272 return 0; 00273 } 00274 //mutex_unlock(&resource->resource_lock); 00275 00276 status = AcpiEvaluateObject(resource->device->handle, "_OFF", NULL, NULL); 00277 if (ACPI_FAILURE(status)) 00278 return -1; 00279 00280 /* Update the power resource's _device_ power state */ 00281 resource->device->power.state = ACPI_STATE_D3; 00282 00283 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n", 00284 resource->name)); 00285 00286 return 0; 00287 } 00288 00306 int acpi_device_sleep_wake(struct acpi_device *dev, 00307 int enable, int sleep_state, int dev_state) 00308 { 00309 union acpi_object in_arg[3]; 00310 struct acpi_object_list arg_list = { 3, in_arg }; 00311 ACPI_STATUS status = AE_OK; 00312 00313 /* 00314 * Try to execute _DSW first. 00315 * 00316 * Three agruments are needed for the _DSW object: 00317 * Argument 0: enable/disable the wake capabilities 00318 * Argument 1: target system state 00319 * Argument 2: target device state 00320 * When _DSW object is called to disable the wake capabilities, maybe 00321 * the first argument is filled. The values of the other two agruments 00322 * are meaningless. 00323 */ 00324 in_arg[0].Type = ACPI_TYPE_INTEGER; 00325 in_arg[0].Integer.Value = enable; 00326 in_arg[1].Type = ACPI_TYPE_INTEGER; 00327 in_arg[1].Integer.Value = sleep_state; 00328 in_arg[2].Type = ACPI_TYPE_INTEGER; 00329 in_arg[2].Integer.Value = dev_state; 00330 status = AcpiEvaluateObject(dev->handle, "_DSW", &arg_list, NULL); 00331 if (ACPI_SUCCESS(status)) { 00332 return 0; 00333 } else if (status != AE_NOT_FOUND) { 00334 DPRINT1("_DSW execution failed\n"); 00335 dev->wakeup.flags.valid = 0; 00336 return -1; 00337 } 00338 00339 /* Execute _PSW */ 00340 arg_list.Count = 1; 00341 in_arg[0].Integer.Value = enable; 00342 status = AcpiEvaluateObject(dev->handle, "_PSW", &arg_list, NULL); 00343 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { 00344 DPRINT1("_PSW execution failed\n"); 00345 dev->wakeup.flags.valid = 0; 00346 return -1; 00347 } 00348 00349 return 0; 00350 } 00351 00352 /* 00353 * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): 00354 * 1. Power on the power resources required for the wakeup device 00355 * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 00356 * State Wake) for the device, if present 00357 */ 00358 int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) 00359 { 00360 int i, err = 0; 00361 00362 if (!dev || !dev->wakeup.flags.valid) 00363 return -1; 00364 00365 //mutex_lock(&acpi_device_lock); 00366 00367 if (dev->wakeup.prepare_count++) 00368 goto out; 00369 00370 /* Open power resource */ 00371 for (i = 0; i < dev->wakeup.resources.count; i++) { 00372 int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev); 00373 if (ret) { 00374 DPRINT( "Transition power state\n"); 00375 dev->wakeup.flags.valid = 0; 00376 err = -1; 00377 goto err_out; 00378 } 00379 } 00380 00381 /* 00382 * Passing 3 as the third argument below means the device may be placed 00383 * in arbitrary power state afterwards. 00384 */ 00385 err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); 00386 00387 err_out: 00388 if (err) 00389 dev->wakeup.prepare_count = 0; 00390 00391 out: 00392 //mutex_unlock(&acpi_device_lock); 00393 return err; 00394 } 00395 00396 /* 00397 * Shutdown a wakeup device, counterpart of above method 00398 * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power 00399 * State Wake) for the device, if present 00400 * 2. Shutdown down the power resources 00401 */ 00402 int acpi_disable_wakeup_device_power(struct acpi_device *dev) 00403 { 00404 int i, err = 0; 00405 00406 if (!dev || !dev->wakeup.flags.valid) 00407 return -1; 00408 00409 //mutex_lock(&acpi_device_lock); 00410 00411 if (--dev->wakeup.prepare_count > 0) 00412 goto out; 00413 00414 /* 00415 * Executing the code below even if prepare_count is already zero when 00416 * the function is called may be useful, for example for initialisation. 00417 */ 00418 if (dev->wakeup.prepare_count < 0) 00419 dev->wakeup.prepare_count = 0; 00420 00421 err = acpi_device_sleep_wake(dev, 0, 0, 0); 00422 if (err) 00423 goto out; 00424 00425 /* Close power resource */ 00426 for (i = 0; i < dev->wakeup.resources.count; i++) { 00427 int ret = acpi_power_off_device( 00428 dev->wakeup.resources.handles[i], dev); 00429 if (ret) { 00430 DPRINT("Transition power state\n"); 00431 dev->wakeup.flags.valid = 0; 00432 err = -1; 00433 goto out; 00434 } 00435 } 00436 00437 out: 00438 //mutex_unlock(&acpi_device_lock); 00439 return err; 00440 } 00441 00442 /* -------------------------------------------------------------------------- 00443 Device Power Management 00444 -------------------------------------------------------------------------- */ 00445 00446 int 00447 acpi_power_get_inferred_state ( 00448 struct acpi_device *device) 00449 { 00450 int result = 0; 00451 struct acpi_handle_list *list = NULL; 00452 int list_state = 0; 00453 int i = 0; 00454 00455 00456 if (!device) 00457 return_VALUE(-1); 00458 00459 device->power.state = ACPI_STATE_UNKNOWN; 00460 00461 /* 00462 * We know a device's inferred power state when all the resources 00463 * required for a given D-state are 'on'. 00464 */ 00465 for (i=ACPI_STATE_D0; i<ACPI_STATE_D3; i++) { 00466 list = &device->power.states[i].resources; 00467 if (list->count < 1) 00468 continue; 00469 00470 result = acpi_power_get_list_state(list, &list_state); 00471 if (result) 00472 return_VALUE(result); 00473 00474 if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { 00475 device->power.state = i; 00476 return_VALUE(0); 00477 } 00478 } 00479 00480 device->power.state = ACPI_STATE_D3; 00481 00482 return_VALUE(0); 00483 } 00484 00485 00486 int 00487 acpi_power_transition ( 00488 struct acpi_device *device, 00489 int state) 00490 { 00491 int result = 0; 00492 struct acpi_handle_list *cl = NULL; /* Current Resources */ 00493 struct acpi_handle_list *tl = NULL; /* Target Resources */ 00494 int i = 0; 00495 00496 if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) 00497 return_VALUE(-1); 00498 00499 if ((device->power.state < ACPI_STATE_D0) || (device->power.state > ACPI_STATE_D3)) 00500 return_VALUE(-15); 00501 00502 cl = &device->power.states[device->power.state].resources; 00503 tl = &device->power.states[state].resources; 00504 00505 /* TBD: Resources must be ordered. */ 00506 00507 /* 00508 * First we reference all power resources required in the target list 00509 * (e.g. so the device doesn't lose power while transitioning). 00510 */ 00511 for (i = 0; i < tl->count; i++) { 00512 result = acpi_power_on(tl->handles[i], device); 00513 if (result) 00514 goto end; 00515 } 00516 00517 if (device->power.state == state) { 00518 goto end; 00519 } 00520 00521 /* 00522 * Then we dereference all power resources used in the current list. 00523 */ 00524 for (i = 0; i < cl->count; i++) { 00525 result = acpi_power_off_device(cl->handles[i], device); 00526 if (result) 00527 goto end; 00528 } 00529 00530 end: 00531 if (result) 00532 device->power.state = ACPI_STATE_UNKNOWN; 00533 else { 00534 /* We shouldn't change the state till all above operations succeed */ 00535 device->power.state = state; 00536 } 00537 00538 return result; 00539 } 00540 00541 /* -------------------------------------------------------------------------- 00542 Driver Interface 00543 -------------------------------------------------------------------------- */ 00544 00545 int 00546 acpi_power_add ( 00547 struct acpi_device *device) 00548 { 00549 int result = 0, state; 00550 ACPI_STATUS status = AE_OK; 00551 struct acpi_power_resource *resource = NULL; 00552 union acpi_object acpi_object; 00553 ACPI_BUFFER buffer = {sizeof(ACPI_OBJECT), &acpi_object}; 00554 00555 00556 if (!device) 00557 return_VALUE(-1); 00558 00559 resource = ExAllocatePoolWithTag(NonPagedPool,sizeof(struct acpi_power_resource),'IPCA'); 00560 if (!resource) 00561 return_VALUE(-4); 00562 00563 resource->device = device; 00564 //mutex_init(&resource->resource_lock); 00565 INIT_LIST_HEAD(&resource->reference); 00566 00567 strcpy(resource->name, device->pnp.bus_id); 00568 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); 00569 strcpy(acpi_device_class(device), ACPI_POWER_CLASS); 00570 device->driver_data = resource; 00571 00572 /* Evalute the object to get the system level and resource order. */ 00573 status = AcpiEvaluateObject(device->handle, NULL, NULL, &buffer); 00574 if (ACPI_FAILURE(status)) { 00575 result = -15; 00576 goto end; 00577 } 00578 resource->system_level = acpi_object.PowerResource.SystemLevel; 00579 resource->order = acpi_object.PowerResource.ResourceOrder; 00580 00581 result = acpi_power_get_state(device->handle, &state); 00582 if (result) 00583 goto end; 00584 00585 switch (state) { 00586 case ACPI_POWER_RESOURCE_STATE_ON: 00587 device->power.state = ACPI_STATE_D0; 00588 break; 00589 case ACPI_POWER_RESOURCE_STATE_OFF: 00590 device->power.state = ACPI_STATE_D3; 00591 break; 00592 default: 00593 device->power.state = ACPI_STATE_UNKNOWN; 00594 break; 00595 } 00596 00597 00598 DPRINT("%s [%s] (%s)\n", acpi_device_name(device), 00599 acpi_device_bid(device), state?"on":"off"); 00600 00601 end: 00602 if (result) 00603 ExFreePool(resource); 00604 00605 return result; 00606 } 00607 00608 00609 int 00610 acpi_power_remove ( 00611 struct acpi_device *device, 00612 int type) 00613 { 00614 struct acpi_power_resource *resource = NULL; 00615 struct list_head *node, *next; 00616 00617 if (!device || !acpi_driver_data(device)) 00618 return_VALUE(-1); 00619 00620 resource = acpi_driver_data(device); 00621 00622 //mutex_lock(&resource->resource_lock); 00623 list_for_each_safe(node, next, &resource->reference) { 00624 struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node); 00625 list_del(&ref->node); 00626 ExFreePool(ref); 00627 } 00628 //mutex_unlock(&resource->resource_lock); 00629 ExFreePool(resource); 00630 00631 return_VALUE(0); 00632 } 00633 00634 static int acpi_power_resume(struct acpi_device *device, int state) 00635 { 00636 int result = 0; 00637 struct acpi_power_resource *resource = NULL; 00638 struct acpi_power_reference *ref; 00639 00640 if (!device || !acpi_driver_data(device)) 00641 return -1; 00642 00643 resource = acpi_driver_data(device); 00644 00645 result = acpi_power_get_state(device->handle, &state); 00646 if (result) 00647 return result; 00648 00649 //mutex_lock(&resource->resource_lock); 00650 if (state == ACPI_POWER_RESOURCE_STATE_OFF && 00651 !list_empty(&resource->reference)) { 00652 ref = container_of(resource->reference.next, struct acpi_power_reference, node); 00653 //mutex_unlock(&resource->resource_lock); 00654 result = acpi_power_on(device->handle, ref->device); 00655 return result; 00656 } 00657 00658 //mutex_unlock(&resource->resource_lock); 00659 return 0; 00660 } 00661 00662 int 00663 acpi_power_init (void) 00664 { 00665 int result = 0; 00666 00667 DPRINT("acpi_power_init"); 00668 00669 INIT_LIST_HEAD(&acpi_power_resource_list); 00670 00671 00672 result = acpi_bus_register_driver(&acpi_power_driver); 00673 if (result < 0) { 00674 return_VALUE(-15); 00675 } 00676 00677 return_VALUE(0); 00678 } Generated on Mon May 28 2012 04:24:07 for ReactOS by
1.7.6.1
|