ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

power.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.