linux/drivers/acpi/power.c
<<
>>
Prefs
   1/*
   2 *  acpi_power.c - ACPI Bus Power Management ($Revision: 39 $)
   3 *
   4 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   5 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
   6 *
   7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; either version 2 of the License, or (at
  12 *  your option) any later version.
  13 *
  14 *  This program is distributed in the hope that it will be useful, but
  15 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 *  General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License along
  20 *  with this program; if not, write to the Free Software Foundation, Inc.,
  21 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  22 *
  23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24 */
  25
  26/*
  27 * ACPI power-managed devices may be controlled in two ways:
  28 * 1. via "Device Specific (D-State) Control"
  29 * 2. via "Power Resource Control".
  30 * This module is used to manage devices relying on Power Resource Control.
  31 * 
  32 * An ACPI "power resource object" describes a software controllable power
  33 * plane, clock plane, or other resource used by a power managed device.
  34 * A device may rely on multiple power resources, and a power resource
  35 * may be shared by multiple devices.
  36 */
  37
  38#include <linux/kernel.h>
  39#include <linux/module.h>
  40#include <linux/init.h>
  41#include <linux/types.h>
  42#include <linux/slab.h>
  43#include <linux/pm_runtime.h>
  44#include <acpi/acpi_bus.h>
  45#include <acpi/acpi_drivers.h>
  46#include "sleep.h"
  47#include "internal.h"
  48
  49#define PREFIX "ACPI: "
  50
  51#define _COMPONENT                      ACPI_POWER_COMPONENT
  52ACPI_MODULE_NAME("power");
  53#define ACPI_POWER_CLASS                "power_resource"
  54#define ACPI_POWER_DEVICE_NAME          "Power Resource"
  55#define ACPI_POWER_FILE_INFO            "info"
  56#define ACPI_POWER_FILE_STATUS          "state"
  57#define ACPI_POWER_RESOURCE_STATE_OFF   0x00
  58#define ACPI_POWER_RESOURCE_STATE_ON    0x01
  59#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
  60
  61static int acpi_power_add(struct acpi_device *device);
  62static int acpi_power_remove(struct acpi_device *device, int type);
  63
  64static const struct acpi_device_id power_device_ids[] = {
  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};
  99
 100struct acpi_power_resource {
 101        struct acpi_device * device;
 102        acpi_bus_id name;
 103        u32 system_level;
 104        u32 order;
 105        unsigned int ref_count;
 106        struct mutex resource_lock;
 107
 108        /* List of devices relying on this power resource */
 109        struct acpi_power_resource_device *devices;
 110        struct mutex devices_lock;
 111};
 112
 113static struct list_head acpi_power_resource_list;
 114
 115/* --------------------------------------------------------------------------
 116                             Power Resource Management
 117   -------------------------------------------------------------------------- */
 118
 119static int
 120acpi_power_get_context(acpi_handle handle,
 121                       struct acpi_power_resource **resource)
 122{
 123        int result = 0;
 124        struct acpi_device *device = NULL;
 125
 126
 127        if (!resource)
 128                return -ENODEV;
 129
 130        result = acpi_bus_get_device(handle, &device);
 131        if (result) {
 132                printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle);
 133                return result;
 134        }
 135
 136        *resource = acpi_driver_data(device);
 137        if (!*resource)
 138                return -ENODEV;
 139
 140        return 0;
 141}
 142
 143static int acpi_power_get_state(acpi_handle handle, int *state)
 144{
 145        acpi_status status = AE_OK;
 146        unsigned long long sta = 0;
 147        char node_name[5];
 148        struct acpi_buffer buffer = { sizeof(node_name), node_name };
 149
 150
 151        if (!handle || !state)
 152                return -EINVAL;
 153
 154        status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
 155        if (ACPI_FAILURE(status))
 156                return -ENODEV;
 157
 158        *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
 159                              ACPI_POWER_RESOURCE_STATE_OFF;
 160
 161        acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
 162
 163        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
 164                          node_name,
 165                                *state ? "on" : "off"));
 166
 167        return 0;
 168}
 169
 170static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
 171{
 172        int cur_state;
 173        int i = 0;
 174
 175        if (!list || !state)
 176                return -EINVAL;
 177
 178        /* The state of the list is 'on' IFF all resources are 'on'. */
 179
 180        for (i = 0; i < list->count; i++) {
 181                struct acpi_power_resource *resource;
 182                acpi_handle handle = list->handles[i];
 183                int result;
 184
 185                result = acpi_power_get_context(handle, &resource);
 186                if (result)
 187                        return result;
 188
 189                mutex_lock(&resource->resource_lock);
 190
 191                result = acpi_power_get_state(handle, &cur_state);
 192
 193                mutex_unlock(&resource->resource_lock);
 194
 195                if (result)
 196                        return result;
 197
 198                if (cur_state != ACPI_POWER_RESOURCE_STATE_ON)
 199                        break;
 200        }
 201
 202        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
 203                          cur_state ? "on" : "off"));
 204
 205        *state = cur_state;
 206
 207        return 0;
 208}
 209
 210/* Resume the device when all power resources in _PR0 are on */
 211static void acpi_power_on_device(struct acpi_power_managed_device *device)
 212{
 213        struct acpi_device *acpi_dev;
 214        acpi_handle handle = device->handle;
 215        int state;
 216
 217        if (acpi_bus_get_device(handle, &acpi_dev))
 218                return;
 219
 220        if(acpi_power_get_inferred_state(acpi_dev, &state))
 221                return;
 222
 223        if (state == ACPI_STATE_D0 && pm_runtime_suspended(device->dev))
 224                pm_request_resume(device->dev);
 225}
 226
 227static int __acpi_power_on(struct acpi_power_resource *resource)
 228{
 229        acpi_status status = AE_OK;
 230
 231        status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
 232        if (ACPI_FAILURE(status))
 233                return -ENODEV;
 234
 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",
 239                          resource->name));
 240
 241        return 0;
 242}
 243
 244static int acpi_power_on(acpi_handle handle)
 245{
 246        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
 255        mutex_lock(&resource->resource_lock);
 256
 257        if (resource->ref_count++) {
 258                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 259                                  "Power resource [%s] already on",
 260                                  resource->name));
 261        } else {
 262                result = __acpi_power_on(resource);
 263                if (result)
 264                        resource->ref_count--;
 265                else
 266                        resume_device = true;
 267        }
 268
 269        mutex_unlock(&resource->resource_lock);
 270
 271        if (!resume_device)
 272                return result;
 273
 274        mutex_lock(&resource->devices_lock);
 275
 276        device_list = resource->devices;
 277        while (device_list) {
 278                acpi_power_on_device(device_list->device);
 279                device_list = device_list->next;
 280        }
 281
 282        mutex_unlock(&resource->devices_lock);
 283
 284        return result;
 285}
 286
 287static int acpi_power_off(acpi_handle handle)
 288{
 289        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
 297        mutex_lock(&resource->resource_lock);
 298
 299        if (!resource->ref_count) {
 300                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 301                                  "Power resource [%s] already off",
 302                                  resource->name));
 303                goto unlock;
 304        }
 305
 306        if (--resource->ref_count) {
 307                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 308                                  "Power resource [%s] still in use\n",
 309                                  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 {
 317                /* Update the power resource's _device_ power state */
 318                resource->device->power.state = ACPI_STATE_D3;
 319
 320                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 321                                  "Power resource [%s] turned off\n",
 322                                  resource->name));
 323        }
 324
 325 unlock:
 326        mutex_unlock(&resource->resource_lock);
 327
 328        return result;
 329}
 330
 331static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
 332{
 333        int i;
 334
 335        for (i = num_res - 1; i >= 0 ; i--)
 336                acpi_power_off(list->handles[i]);
 337}
 338
 339static void acpi_power_off_list(struct acpi_handle_list *list)
 340{
 341        __acpi_power_off_list(list, list->count);
 342}
 343
 344static int acpi_power_on_list(struct acpi_handle_list *list)
 345{
 346        int result = 0;
 347        int i;
 348
 349        for (i = 0; i < list->count; i++) {
 350                result = acpi_power_on(list->handles[i]);
 351                if (result) {
 352                        __acpi_power_off_list(list, i);
 353                        break;
 354                }
 355        }
 356
 357        return result;
 358}
 359
 360static void __acpi_power_resource_unregister_device(struct device *dev,
 361                acpi_handle res_handle)
 362{
 363        struct acpi_power_resource *resource = NULL;
 364        struct acpi_power_resource_device *prev, *curr;
 365
 366        if (acpi_power_get_context(res_handle, &resource))
 367                return;
 368
 369        mutex_lock(&resource->devices_lock);
 370        prev = NULL;
 371        curr = resource->devices;
 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
 383                prev = curr;
 384                curr = curr->next;
 385        }
 386        mutex_unlock(&resource->devices_lock);
 387}
 388
 389/* Unlink dev from all power resources in _PR0 */
 390void acpi_power_resource_unregister_device(struct device *dev, acpi_handle handle)
 391{
 392        struct acpi_device *acpi_dev;
 393        struct acpi_handle_list *list;
 394        int i;
 395
 396        if (!dev || !handle)
 397                return;
 398
 399        if (acpi_bus_get_device(handle, &acpi_dev))
 400                return;
 401
 402        list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
 403
 404        for (i = 0; i < list->count; i++)
 405                __acpi_power_resource_unregister_device(dev,
 406                        list->handles[i]);
 407}
 408EXPORT_SYMBOL_GPL(acpi_power_resource_unregister_device);
 409
 410static int __acpi_power_resource_register_device(
 411        struct acpi_power_managed_device *powered_device, acpi_handle handle)
 412{
 413        struct acpi_power_resource *resource = NULL;
 414        struct acpi_power_resource_device *power_resource_device;
 415        int result;
 416
 417        result = acpi_power_get_context(handle, &resource);
 418        if (result)
 419                return result;
 420
 421        power_resource_device = kzalloc(
 422                sizeof(*power_resource_device), GFP_KERNEL);
 423        if (!power_resource_device)
 424                return -ENOMEM;
 425
 426        power_resource_device->device = powered_device;
 427
 428        mutex_lock(&resource->devices_lock);
 429        power_resource_device->next = resource->devices;
 430        resource->devices = power_resource_device;
 431        mutex_unlock(&resource->devices_lock);
 432
 433        return 0;
 434}
 435
 436/* Link dev to all power resources in _PR0 */
 437int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
 438{
 439        struct acpi_device *acpi_dev;
 440        struct acpi_handle_list *list;
 441        struct acpi_power_managed_device *powered_device;
 442        int i, ret;
 443
 444        if (!dev || !handle)
 445                return -ENODEV;
 446
 447        ret = acpi_bus_get_device(handle, &acpi_dev);
 448        if (ret)
 449                goto no_power_resource;
 450
 451        if (!acpi_dev->power.flags.power_resources)
 452                goto no_power_resource;
 453
 454        powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL);
 455        if (!powered_device)
 456                return -ENOMEM;
 457
 458        powered_device->dev = dev;
 459        powered_device->handle = handle;
 460
 461        list = &acpi_dev->power.states[ACPI_STATE_D0].resources;
 462
 463        for (i = 0; i < list->count; i++) {
 464                ret = __acpi_power_resource_register_device(powered_device,
 465                        list->handles[i]);
 466
 467                if (ret) {
 468                        acpi_power_resource_unregister_device(dev, handle);
 469                        break;
 470                }
 471        }
 472
 473        return ret;
 474
 475no_power_resource:
 476        printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!");
 477        return -ENODEV;
 478}
 479EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
 480
 481/**
 482 * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
 483 *                          ACPI 3.0) _PSW (Power State Wake)
 484 * @dev: Device to handle.
 485 * @enable: 0 - disable, 1 - enable the wake capabilities of the device.
 486 * @sleep_state: Target sleep state of the system.
 487 * @dev_state: Target power state of the device.
 488 *
 489 * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 490 * State Wake) for the device, if present.  On failure reset the device's
 491 * wakeup.flags.valid flag.
 492 *
 493 * RETURN VALUE:
 494 * 0 if either _DSW or _PSW has been successfully executed
 495 * 0 if neither _DSW nor _PSW has been found
 496 * -ENODEV if the execution of either _DSW or _PSW has failed
 497 */
 498int acpi_device_sleep_wake(struct acpi_device *dev,
 499                           int enable, int sleep_state, int dev_state)
 500{
 501        union acpi_object in_arg[3];
 502        struct acpi_object_list arg_list = { 3, in_arg };
 503        acpi_status status = AE_OK;
 504
 505        /*
 506         * Try to execute _DSW first.
 507         *
 508         * Three agruments are needed for the _DSW object:
 509         * Argument 0: enable/disable the wake capabilities
 510         * Argument 1: target system state
 511         * Argument 2: target device state
 512         * When _DSW object is called to disable the wake capabilities, maybe
 513         * the first argument is filled. The values of the other two agruments
 514         * are meaningless.
 515         */
 516        in_arg[0].type = ACPI_TYPE_INTEGER;
 517        in_arg[0].integer.value = enable;
 518        in_arg[1].type = ACPI_TYPE_INTEGER;
 519        in_arg[1].integer.value = sleep_state;
 520        in_arg[2].type = ACPI_TYPE_INTEGER;
 521        in_arg[2].integer.value = dev_state;
 522        status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL);
 523        if (ACPI_SUCCESS(status)) {
 524                return 0;
 525        } else if (status != AE_NOT_FOUND) {
 526                printk(KERN_ERR PREFIX "_DSW execution failed\n");
 527                dev->wakeup.flags.valid = 0;
 528                return -ENODEV;
 529        }
 530
 531        /* Execute _PSW */
 532        arg_list.count = 1;
 533        in_arg[0].integer.value = enable;
 534        status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
 535        if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
 536                printk(KERN_ERR PREFIX "_PSW execution failed\n");
 537                dev->wakeup.flags.valid = 0;
 538                return -ENODEV;
 539        }
 540
 541        return 0;
 542}
 543
 544/*
 545 * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
 546 * 1. Power on the power resources required for the wakeup device 
 547 * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 548 *    State Wake) for the device, if present
 549 */
 550int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
 551{
 552        int i, err = 0;
 553
 554        if (!dev || !dev->wakeup.flags.valid)
 555                return -EINVAL;
 556
 557        mutex_lock(&acpi_device_lock);
 558
 559        if (dev->wakeup.prepare_count++)
 560                goto out;
 561
 562        /* Open power resource */
 563        for (i = 0; i < dev->wakeup.resources.count; i++) {
 564                int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
 565                if (ret) {
 566                        printk(KERN_ERR PREFIX "Transition power state\n");
 567                        dev->wakeup.flags.valid = 0;
 568                        err = -ENODEV;
 569                        goto err_out;
 570                }
 571        }
 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)
 581                dev->wakeup.prepare_count = 0;
 582
 583 out:
 584        mutex_unlock(&acpi_device_lock);
 585        return err;
 586}
 587
 588/*
 589 * Shutdown a wakeup device, counterpart of above method
 590 * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 591 *    State Wake) for the device, if present
 592 * 2. Shutdown down the power resources
 593 */
 594int acpi_disable_wakeup_device_power(struct acpi_device *dev)
 595{
 596        int i, err = 0;
 597
 598        if (!dev || !dev->wakeup.flags.valid)
 599                return -EINVAL;
 600
 601        mutex_lock(&acpi_device_lock);
 602
 603        if (--dev->wakeup.prepare_count > 0)
 604                goto out;
 605
 606        /*
 607         * Executing the code below even if prepare_count is already zero when
 608         * the function is called may be useful, for example for initialisation.
 609         */
 610        if (dev->wakeup.prepare_count < 0)
 611                dev->wakeup.prepare_count = 0;
 612
 613        err = acpi_device_sleep_wake(dev, 0, 0, 0);
 614        if (err)
 615                goto out;
 616
 617        /* Close power resource */
 618        for (i = 0; i < dev->wakeup.resources.count; i++) {
 619                int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
 620                if (ret) {
 621                        printk(KERN_ERR PREFIX "Transition power state\n");
 622                        dev->wakeup.flags.valid = 0;
 623                        err = -ENODEV;
 624                        goto out;
 625                }
 626        }
 627
 628 out:
 629        mutex_unlock(&acpi_device_lock);
 630        return err;
 631}
 632
 633/* --------------------------------------------------------------------------
 634                             Device Power Management
 635   -------------------------------------------------------------------------- */
 636
 637int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
 638{
 639        int result = 0;
 640        struct acpi_handle_list *list = NULL;
 641        int list_state = 0;
 642        int i = 0;
 643
 644        if (!device || !state)
 645                return -EINVAL;
 646
 647        /*
 648         * We know a device's inferred power state when all the resources
 649         * required for a given D-state are 'on'.
 650         */
 651        for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
 652                list = &device->power.states[i].resources;
 653                if (list->count < 1)
 654                        continue;
 655
 656                result = acpi_power_get_list_state(list, &list_state);
 657                if (result)
 658                        return result;
 659
 660                if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
 661                        *state = i;
 662                        return 0;
 663                }
 664        }
 665
 666        *state = ACPI_STATE_D3;
 667        return 0;
 668}
 669
 670int acpi_power_on_resources(struct acpi_device *device, int state)
 671{
 672        if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
 673                return -EINVAL;
 674
 675        return acpi_power_on_list(&device->power.states[state].resources);
 676}
 677
 678int acpi_power_transition(struct acpi_device *device, int state)
 679{
 680        int result = 0;
 681
 682        if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
 683                return -EINVAL;
 684
 685        if (device->power.state == state)
 686                return 0;
 687
 688        if ((device->power.state < ACPI_STATE_D0)
 689            || (device->power.state > ACPI_STATE_D3_COLD))
 690                return -ENODEV;
 691
 692        /* TBD: Resources must be ordered. */
 693
 694        /*
 695         * First we reference all power resources required in the target list
 696         * (e.g. so the device doesn't lose power while transitioning).  Then,
 697         * we dereference all power resources used in the current list.
 698         */
 699        if (state < ACPI_STATE_D3_COLD)
 700                result = acpi_power_on_list(
 701                        &device->power.states[state].resources);
 702
 703        if (!result && device->power.state < ACPI_STATE_D3_COLD)
 704                acpi_power_off_list(
 705                        &device->power.states[device->power.state].resources);
 706
 707        /* We shouldn't change the state unless the above operations succeed. */
 708        device->power.state = result ? ACPI_STATE_UNKNOWN : state;
 709
 710        return result;
 711}
 712
 713/* --------------------------------------------------------------------------
 714                                Driver Interface
 715   -------------------------------------------------------------------------- */
 716
 717static int acpi_power_add(struct acpi_device *device)
 718{
 719        int result = 0, state;
 720        acpi_status status = AE_OK;
 721        struct acpi_power_resource *resource = NULL;
 722        union acpi_object acpi_object;
 723        struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
 724
 725
 726        if (!device)
 727                return -EINVAL;
 728
 729        resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
 730        if (!resource)
 731                return -ENOMEM;
 732
 733        resource->device = device;
 734        mutex_init(&resource->resource_lock);
 735        mutex_init(&resource->devices_lock);
 736        strcpy(resource->name, device->pnp.bus_id);
 737        strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
 738        strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
 739        device->driver_data = resource;
 740
 741        /* Evalute the object to get the system level and resource order. */
 742        status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
 743        if (ACPI_FAILURE(status)) {
 744                result = -ENODEV;
 745                goto end;
 746        }
 747        resource->system_level = acpi_object.power_resource.system_level;
 748        resource->order = acpi_object.power_resource.resource_order;
 749
 750        result = acpi_power_get_state(device->handle, &state);
 751        if (result)
 752                goto end;
 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
 766        printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
 767               acpi_device_bid(device), state ? "on" : "off");
 768
 769      end:
 770        if (result)
 771                kfree(resource);
 772
 773        return result;
 774}
 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
 789        return 0;
 790}
 791
 792#ifdef CONFIG_PM_SLEEP
 793static int acpi_power_resume(struct device *dev)
 794{
 795        int result = 0, state;
 796        struct acpi_device *device;
 797        struct acpi_power_resource *resource;
 798
 799        if (!dev)
 800                return -EINVAL;
 801
 802        device = to_acpi_device(dev);
 803        resource = acpi_driver_data(device);
 804        if (!resource)
 805                return -EINVAL;
 806
 807        mutex_lock(&resource->resource_lock);
 808
 809        result = acpi_power_get_state(device->handle, &state);
 810        if (result)
 811                goto unlock;
 812
 813        if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
 814                result = __acpi_power_on(resource);
 815
 816 unlock:
 817        mutex_unlock(&resource->resource_lock);
 818
 819        return result;
 820}
 821#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}
 828
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.