1 /*- 2 * Copyright (c) 2001 Michael Smith 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include "opt_acpi.h" /* XXX trim includes */ 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/proc.h> 33 #include <sys/lock.h> 34 #include <sys/malloc.h> 35 #include <sys/mutex.h> 36 #include <sys/bus.h> 37 #include <sys/conf.h> 38 #include <sys/ioccom.h> 39 #include <sys/reboot.h> 40 #include <sys/sysctl.h> 41 #include <sys/systm.h> 42 #include <sys/ctype.h> 43 44 #include <machine/clock.h> 45 46 #include <machine/resource.h> 47 48 #include "acpi.h" 49 50 #include <dev/acpica/acpivar.h> 51 #include <dev/acpica/acpiio.h> 52 53 /* 54 * ACPI power resource management. 55 * 56 * Power resource behaviour is slightly complicated by the fact that 57 * a single power resource may provide power for more than one device. 58 * Thus, we must track the device(s) being powered by a given power 59 * resource, and only deactivate it when there are no powered devices. 60 * 61 * Note that this only manages resources for known devices. There is an 62 * ugly case where we may turn of power to a device which is in use because 63 * we don't know that it depends on a given resource. We should perhaps 64 * try to be smarter about this, but a more complete solution would involve 65 * scanning all of the ACPI namespace to find devices we're not currently 66 * aware of, and this raises questions about whether they should be left 67 * on, turned off, etc. 68 * 69 * XXX locking 70 */ 71 72 MALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources"); 73 74 /* 75 * Hooks for the ACPI CA debugging infrastructure 76 */ 77 #define _COMPONENT ACPI_POWER 78 MODULE_NAME("POWERRES") 79 80 /* return values from _STA on a power resource */ 81 #define ACPI_PWR_OFF 0 82 #define ACPI_PWR_ON 1 83 84 /* 85 * A relationship between a power resource and a consumer. 86 */ 87 struct acpi_powerreference { 88 struct acpi_powerconsumer *ar_consumer; 89 struct acpi_powerresource *ar_resource; 90 TAILQ_ENTRY(acpi_powerreference) ar_rlink; /* link on resource list */ 91 TAILQ_ENTRY(acpi_powerreference) ar_clink; /* link on consumer */ 92 }; 93 94 /* 95 * A power-managed device. 96 */ 97 struct acpi_powerconsumer { 98 ACPI_HANDLE ac_consumer; /* device which is powered */ 99 int ac_state; 100 TAILQ_ENTRY(acpi_powerconsumer) ac_link; 101 TAILQ_HEAD(,acpi_powerreference) ac_references; 102 }; 103 104 /* 105 * A power resource. 106 */ 107 struct acpi_powerresource { 108 TAILQ_ENTRY(acpi_powerresource) ap_link; 109 TAILQ_HEAD(,acpi_powerreference) ap_references; 110 ACPI_HANDLE ap_resource; /* the resource's handle */ 111 ACPI_INTEGER ap_systemlevel; 112 ACPI_INTEGER ap_order; 113 }; 114 115 TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource) acpi_powerresources; 116 TAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer) acpi_powerconsumers; 117 118 static ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE consumer); 119 static ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE consumer); 120 static ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE res); 121 static ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE res); 122 static void acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg); 123 static ACPI_STATUS acpi_pwr_switch_power(void); 124 static struct acpi_powerresource *acpi_pwr_find_resource(ACPI_HANDLE res); 125 static struct acpi_powerconsumer *acpi_pwr_find_consumer(ACPI_HANDLE consumer); 126 127 /* 128 * Initialise our lists. 129 */ 130 static void 131 acpi_pwr_init(void *junk) 132 { 133 TAILQ_INIT(&acpi_powerresources); 134 TAILQ_INIT(&acpi_powerconsumers); 135 } 136 SYSINIT(acpi_powerresource, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_pwr_init, NULL); 137 138 /* 139 * Register a power resource. 140 * 141 * It's OK to call this if we already know about the resource. 142 */ 143 static ACPI_STATUS 144 acpi_pwr_register_resource(ACPI_HANDLE res) 145 { 146 ACPI_STATUS status; 147 ACPI_BUFFER buf; 148 ACPI_OPERAND_OBJECT *obj; 149 struct acpi_powerresource *rp, *srp; 150 151 FUNCTION_TRACE(__func__); 152 153 rp = NULL; 154 obj = NULL; 155 156 /* look to see if we know about this resource */ 157 if (acpi_pwr_find_resource(res) != NULL) 158 return_ACPI_STATUS(AE_OK); /* already know about it */ 159 160 /* allocate a new resource */ 161 if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) { 162 status = AE_NO_MEMORY; 163 goto out; 164 } 165 TAILQ_INIT(&rp->ap_references); 166 rp->ap_resource = res; 167 168 /* get the Power Resource object */ 169 if ((status = acpi_EvaluateIntoBuffer(res, NULL, NULL, &buf)) != AE_OK) { 170 DEBUG_PRINT(TRACE_OBJECTS, ("no power resource object\n")); 171 goto out; 172 } 173 obj = buf.Pointer; 174 if (obj->Common.Type != ACPI_TYPE_POWER) { 175 DEBUG_PRINT(TRACE_OBJECTS, ("questionable power resource object %s\n", acpi_name(res))); 176 /* XXX ACPI CA seems to return ACPI_TYPE_ANY, needs to be fixed */ 177 rp->ap_systemlevel = 0; 178 rp->ap_order = 0; 179 } else { 180 rp->ap_systemlevel = obj->PowerResource.SystemLevel; 181 rp->ap_order = obj->PowerResource.ResourceOrder; 182 } 183 184 /* sort the resource into the list */ 185 status = AE_OK; 186 srp = TAILQ_FIRST(&acpi_powerresources); 187 if ((srp == NULL) || (rp->ap_order < srp->ap_order)) { 188 TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link); 189 goto done; 190 } 191 TAILQ_FOREACH(srp, &acpi_powerresources, ap_link) 192 if (rp->ap_order < srp->ap_order) { 193 TAILQ_INSERT_BEFORE(srp, rp, ap_link); 194 goto done; 195 } 196 TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link); 197 198 done: 199 DEBUG_PRINT(TRACE_OBJECTS, ("registered power resource %s\n", acpi_name(res))); 200 out: 201 if (obj != NULL) 202 AcpiOsFree(obj); 203 if ((status != AE_OK) && (rp != NULL)) 204 free(rp, M_ACPIPWR); 205 return_ACPI_STATUS(status); 206 } 207 208 /* 209 * Deregister a power resource. 210 */ 211 static ACPI_STATUS 212 acpi_pwr_deregister_resource(ACPI_HANDLE res) 213 { 214 struct acpi_powerresource *rp; 215 216 FUNCTION_TRACE(__func__); 217 218 rp = NULL; 219 220 /* find the resource */ 221 if ((rp = acpi_pwr_find_resource(res)) == NULL) 222 return_ACPI_STATUS(AE_BAD_PARAMETER); 223 224 /* check that there are no consumers referencing this resource */ 225 if (TAILQ_FIRST(&rp->ap_references) != NULL) 226 return_ACPI_STATUS(AE_BAD_PARAMETER); 227 228 /* pull it off the list and free it */ 229 TAILQ_REMOVE(&acpi_powerresources, rp, ap_link); 230 free(rp, M_ACPIPWR); 231 232 DEBUG_PRINT(TRACE_OBJECTS, ("deregistered power resource %s\n", acpi_name(res))); 233 234 return_ACPI_STATUS(AE_OK); 235 } 236 237 /* 238 * Register a power consumer. 239 * 240 * It's OK to call this if we already know about the consumer. 241 */ 242 static ACPI_STATUS 243 acpi_pwr_register_consumer(ACPI_HANDLE consumer) 244 { 245 struct acpi_powerconsumer *pc; 246 247 FUNCTION_TRACE(__func__); 248 249 /* check to see whether we know about this consumer already */ 250 if ((pc = acpi_pwr_find_consumer(consumer)) != NULL) 251 return_ACPI_STATUS(AE_OK); 252 253 /* allocate a new power consumer */ 254 if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL) 255 return_ACPI_STATUS(AE_NO_MEMORY); 256 TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link); 257 TAILQ_INIT(&pc->ac_references); 258 pc->ac_consumer = consumer; 259 260 pc->ac_state = ACPI_STATE_UNKNOWN; /* XXX we should try to find its current state */ 261 262 DEBUG_PRINT(TRACE_OBJECTS, ("registered power consumer %s\n", acpi_name(consumer))); 263 264 return_ACPI_STATUS(AE_OK); 265 } 266 267 /* 268 * Deregister a power consumer. 269 * 270 * This should only be done once the consumer has been powered off. 271 * (XXX is this correct? Check once implemented) 272 */ 273 static ACPI_STATUS 274 acpi_pwr_deregister_consumer(ACPI_HANDLE consumer) 275 { 276 struct acpi_powerconsumer *pc; 277 278 FUNCTION_TRACE(__func__); 279 280 /* find the consumer */ 281 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) 282 return_ACPI_STATUS(AE_BAD_PARAMETER); 283 284 /* make sure the consumer's not referencing anything right now */ 285 if (TAILQ_FIRST(&pc->ac_references) != NULL) 286 return_ACPI_STATUS(AE_BAD_PARAMETER); 287 288 /* pull the consumer off the list and free it */ 289 TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link); 290 291 DEBUG_PRINT(TRACE_OBJECTS, ("deregistered power consumer %s\n", acpi_name(consumer))); 292 293 return_ACPI_STATUS(AE_OK); 294 } 295 296 /* 297 * Set a power consumer to a particular power state. 298 */ 299 ACPI_STATUS 300 acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) 301 { 302 struct acpi_powerconsumer *pc; 303 struct acpi_powerreference *pr; 304 ACPI_HANDLE method_handle, reslist_handle; 305 ACPI_BUFFER reslist_buffer; 306 ACPI_OBJECT *reslist_object; 307 ACPI_STATUS status; 308 char *method_name, *reslist_name; 309 int res_changed; 310 311 FUNCTION_TRACE(__func__); 312 313 /* find the consumer */ 314 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { 315 if ((status = acpi_pwr_register_consumer(consumer)) != AE_OK) 316 return_ACPI_STATUS(status); 317 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { 318 return_ACPI_STATUS(AE_ERROR); /* something very wrong */ 319 } 320 } 321 322 /* check for valid transitions */ 323 if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0)) 324 return_ACPI_STATUS(AE_BAD_PARAMETER); /* can only go to D0 from D3 */ 325 326 /* find transition mechanism(s) */ 327 switch(state) { 328 case ACPI_STATE_D0: 329 method_name = "_PS0"; 330 reslist_name = "_PR0"; 331 break; 332 case ACPI_STATE_D1: 333 method_name = "_PS1"; 334 reslist_name = "_PR1"; 335 break; 336 case ACPI_STATE_D2: 337 method_name = "_PS2"; 338 reslist_name = "_PR2"; 339 break; 340 case ACPI_STATE_D3: 341 method_name = "_PS3"; 342 reslist_name = "_PR3"; 343 break; 344 default: 345 return_ACPI_STATUS(AE_BAD_PARAMETER); 346 } 347 DEBUG_PRINT(TRACE_OBJECTS, ("setup to switch %s D%d -> D%d\n", 348 acpi_name(consumer), pc->ac_state, state)); 349 350 /* 351 * Verify that this state is supported, ie. one of method or 352 * reslist must be present. We need to do this before we go 353 * dereferencing resources (since we might be trying to go to 354 * a state we don't support). 355 * 356 * Note that if any states are supported, the device has to 357 * support D0 and D3. It's never an error to try to go to 358 * D0. 359 */ 360 if (AcpiGetHandle(consumer, method_name, &method_handle) != AE_OK) 361 method_handle = NULL; 362 if (AcpiGetHandle(consumer, reslist_name, &reslist_handle) != AE_OK) 363 reslist_handle = NULL; 364 if ((reslist_handle == NULL) && (method_handle == NULL)) { 365 if (state == ACPI_STATE_D0) { 366 pc->ac_state = ACPI_STATE_D0; 367 return_ACPI_STATUS(AE_OK); 368 } 369 DEBUG_PRINT(TRACE_OBJECTS, ("attempt to set unsupported state D%d\n", 370 state)); 371 return_ACPI_STATUS(AE_BAD_PARAMETER); 372 } 373 374 /* 375 * Check that we can actually fetch the list of power resources 376 */ 377 if (reslist_handle != NULL) { 378 if ((status = acpi_EvaluateIntoBuffer(reslist_handle, NULL, NULL, &reslist_buffer)) != AE_OK) { 379 DEBUG_PRINT(TRACE_OBJECTS, ("can't evaluate resource list %s\n", 380 acpi_name(reslist_handle))); 381 return_ACPI_STATUS(status); 382 } 383 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer; 384 if (reslist_object->Type != ACPI_TYPE_PACKAGE) { 385 DEBUG_PRINT(TRACE_OBJECTS, ("resource list is not ACPI_TYPE_PACKAGE (%d)\n", 386 reslist_object->Type)); 387 return_ACPI_STATUS(AE_TYPE); 388 } 389 } else { 390 reslist_object = NULL; 391 } 392 393 /* 394 * Now we are ready to switch, so kill off any current power resource references. 395 */ 396 res_changed = 0; 397 while((pr = TAILQ_FIRST(&pc->ac_references)) != NULL) { 398 res_changed = 1; 399 DEBUG_PRINT(TRACE_OBJECTS, ("removing reference to %s\n", acpi_name(pr->ar_resource->ap_resource))); 400 TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink); 401 TAILQ_REMOVE(&pc->ac_references, pr, ar_clink); 402 free(pr, M_ACPIPWR); 403 } 404 405 /* 406 * Add new power resource references, if we have any. Traverse the 407 * package that we got from evaluating reslist_handle, and look up each 408 * of the resources that are referenced. 409 */ 410 if (reslist_object != NULL) { 411 DEBUG_PRINT(TRACE_OBJECTS, ("referencing %d new resources\n", 412 reslist_object->Package.Count)); 413 acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, pc); 414 res_changed = 1; 415 } 416 417 /* 418 * If we changed anything in the resource list, we need to run a switch 419 * pass now. 420 */ 421 if ((status = acpi_pwr_switch_power()) != AE_OK) { 422 DEBUG_PRINT(TRACE_OBJECTS, ("failed to correctly switch resources to move %s to D%d\n", 423 acpi_name(consumer), state)); 424 return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */ 425 } 426 427 /* invoke power state switch method (if present) */ 428 if (method_handle != NULL) { 429 DEBUG_PRINT(TRACE_OBJECTS, ("invoking state transition method %s\n", 430 acpi_name(method_handle))); 431 if ((status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL)) != AE_OK) 432 pc->ac_state = ACPI_STATE_UNKNOWN; 433 return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */ 434 } 435 436 /* transition was successful */ 437 pc->ac_state = state; 438 return_ACPI_STATUS(AE_OK); 439 } 440 441 /* 442 * Called to create a reference between a power consumer and a power resource 443 * identified in the object. 444 */ 445 static void 446 acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg) 447 { 448 struct acpi_powerconsumer *pc = (struct acpi_powerconsumer *)arg; 449 struct acpi_powerreference *pr; 450 struct acpi_powerresource *rp; 451 ACPI_HANDLE res; 452 ACPI_STATUS status; 453 454 FUNCTION_TRACE(__func__); 455 456 /* check the object type */ 457 if (obj->Type != ACPI_TYPE_STRING) { 458 DEBUG_PRINT(TRACE_OBJECTS, ("don't know how to create a power reference to object type %d\n", 459 obj->Type)); 460 return_VOID; 461 } 462 463 DEBUG_PRINT(TRACE_OBJECTS, ("building reference from %s to %s\n", 464 acpi_name(pc->ac_consumer), obj->String.Pointer)); 465 466 /* get the handle of the resource */ 467 if (ACPI_FAILURE(status = AcpiGetHandle(NULL, obj->String.Pointer, &res))) { 468 DEBUG_PRINT(TRACE_OBJECTS, ("couldn't find power resource %s\n", 469 obj->String.Pointer)); 470 return_VOID; 471 } 472 473 /* create/look up the resource */ 474 if (ACPI_FAILURE(status = acpi_pwr_register_resource(res))) { 475 DEBUG_PRINT(TRACE_OBJECTS, ("couldn't register power resource %s - %s\n", 476 obj->String.Pointer, acpi_strerror(status))); 477 return_VOID; 478 } 479 if ((rp = acpi_pwr_find_resource(res)) == NULL) { 480 DEBUG_PRINT(TRACE_OBJECTS, ("power resource list corrupted\n")); 481 return_VOID; 482 } 483 DEBUG_PRINT(TRACE_OBJECTS, ("found power resource %s\n", acpi_name(rp->ap_resource))); 484 485 /* create a reference between the consumer and resource */ 486 if ((pr = malloc(sizeof(*pr), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) { 487 DEBUG_PRINT(TRACE_OBJECTS, ("couldn't allocate memory for a power consumer reference\n")); 488 return_VOID; 489 } 490 pr->ar_consumer = pc; 491 pr->ar_resource = rp; 492 TAILQ_INSERT_TAIL(&pc->ac_references, pr, ar_clink); 493 TAILQ_INSERT_TAIL(&rp->ap_references, pr, ar_rlink); 494 495 return_VOID; 496 } 497 498 499 /* 500 * Switch power resources to conform to the desired state. 501 * 502 * Consumers may have modified the power resource list in an arbitrary 503 * fashion; we sweep it in sequence order. 504 */ 505 static ACPI_STATUS 506 acpi_pwr_switch_power(void) 507 { 508 struct acpi_powerresource *rp; 509 ACPI_STATUS status; 510 int cur; 511 512 FUNCTION_TRACE(__func__); 513 514 /* 515 * Sweep the list forwards turning things on. 516 */ 517 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) { 518 if (TAILQ_FIRST(&rp->ap_references) == NULL) { 519 DEBUG_PRINT(TRACE_OBJECTS, ("%s has no references, not turning on\n", 520 acpi_name(rp->ap_resource))); 521 continue; 522 } 523 524 /* we could cache this if we trusted it not to change under us */ 525 if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) { 526 DEBUG_PRINT(TRACE_OBJECTS, ("can't get status of %s - %d\n", 527 acpi_name(rp->ap_resource), status)); 528 continue; /* XXX is this correct? Always switch if in doubt? */ 529 } 530 531 /* 532 * Switch if required. Note that we ignore the result of the switch 533 * effort; we don't know what to do if it fails, so checking wouldn't 534 * help much. 535 */ 536 if (cur != ACPI_PWR_ON) { 537 if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL))) { 538 DEBUG_PRINT(TRACE_OBJECTS, ("failed to switch %s on - %s\n", 539 acpi_name(rp->ap_resource), acpi_strerror(status))); 540 } else { 541 DEBUG_PRINT(TRACE_OBJECTS, ("switched %s on\n", acpi_name(rp->ap_resource))); 542 } 543 } else { 544 DEBUG_PRINT(TRACE_OBJECTS, ("%s is already on\n", acpi_name(rp->ap_resource))); 545 } 546 } 547 548 /* 549 * Sweep the list backwards turning things off. 550 */ 551 TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) { 552 if (TAILQ_FIRST(&rp->ap_references) != NULL) { 553 DEBUG_PRINT(TRACE_OBJECTS, ("%s has references, not turning off\n", 554 acpi_name(rp->ap_resource))); 555 continue; 556 } 557 558 /* we could cache this if we trusted it not to change under us */ 559 if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) { 560 DEBUG_PRINT(TRACE_OBJECTS, ("can't get status of %s - %d\n", 561 acpi_name(rp->ap_resource), status)); 562 continue; /* XXX is this correct? Always switch if in doubt? */ 563 } 564 565 /* 566 * Switch if required. Note that we ignore the result of the switch 567 * effort; we don't know what to do if it fails, so checking wouldn't 568 * help much. 569 */ 570 if (cur != ACPI_PWR_OFF) { 571 if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL))) { 572 DEBUG_PRINT(TRACE_OBJECTS, ("failed to switch %s off - %s\n", 573 acpi_name(rp->ap_resource), acpi_strerror(status))); 574 } else { 575 DEBUG_PRINT(TRACE_OBJECTS, ("switched %s off\n", acpi_name(rp->ap_resource))); 576 } 577 } else { 578 DEBUG_PRINT(TRACE_OBJECTS, ("%s is already off\n", acpi_name(rp->ap_resource))); 579 } 580 } 581 return_ACPI_STATUS(AE_OK); 582 } 583 584 /* 585 * Find a power resource's control structure. 586 */ 587 static struct acpi_powerresource * 588 acpi_pwr_find_resource(ACPI_HANDLE res) 589 { 590 struct acpi_powerresource *rp; 591 592 FUNCTION_TRACE(__func__); 593 594 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) 595 if (rp->ap_resource == res) 596 break; 597 return_VALUE(rp); 598 } 599 600 /* 601 * Find a power consumer's control structure. 602 */ 603 static struct acpi_powerconsumer * 604 acpi_pwr_find_consumer(ACPI_HANDLE consumer) 605 { 606 struct acpi_powerconsumer *pc; 607 608 FUNCTION_TRACE(__func__); 609 610 TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link) 611 if (pc->ac_consumer == consumer) 612 break; 613 return_VALUE(pc); 614 } 615 616