1 /* $NetBSD: acpi_power.c,v 1.34 2014/02/25 18:30:09 pooka Exp $ */ 2 3 /*- 4 * Copyright (c) 2009, 2010, 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jukka Ruohonen. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /*- 33 * Copyright (c) 2001 Michael Smith 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58 #include <sys/cdefs.h> 59 __KERNEL_RCSID(0, "$NetBSD: acpi_power.c,v 1.34 2014/02/25 18:30:09 pooka Exp $"); 60 61 #include <sys/param.h> 62 #include <sys/kmem.h> 63 #include <sys/mutex.h> 64 #include <sys/sysctl.h> 65 66 #include <dev/acpi/acpireg.h> 67 #include <dev/acpi/acpivar.h> 68 #include <dev/acpi/acpi_pci.h> 69 #include <dev/acpi/acpi_power.h> 70 71 #define _COMPONENT ACPI_BUS_COMPONENT 72 ACPI_MODULE_NAME ("acpi_power") 73 74 #define ACPI_STA_POW_OFF 0x00 75 #define ACPI_STA_POW_ON 0x01 76 77 struct acpi_power_res { 78 ACPI_HANDLE res_handle; 79 ACPI_INTEGER res_level; 80 ACPI_INTEGER res_order; 81 ACPI_HANDLE res_ref[5]; 82 char res_name[5]; 83 kmutex_t res_mutex; 84 85 TAILQ_ENTRY(acpi_power_res) res_list; 86 }; 87 88 static TAILQ_HEAD(, acpi_power_res) res_head = 89 TAILQ_HEAD_INITIALIZER(res_head); 90 91 static int32_t acpi_power_acpinode = CTL_EOL; 92 static int32_t acpi_power_powernode = CTL_EOL; 93 94 static struct acpi_power_res *acpi_power_res_init(ACPI_HANDLE); 95 static struct acpi_power_res *acpi_power_res_get(ACPI_HANDLE); 96 97 static ACPI_STATUS acpi_power_get_direct(struct acpi_devnode *); 98 static ACPI_STATUS acpi_power_get_indirect(struct acpi_devnode *); 99 static ACPI_STATUS acpi_power_switch(struct acpi_devnode *, 100 int, bool); 101 static ACPI_STATUS acpi_power_res_ref(struct acpi_power_res *, 102 ACPI_HANDLE); 103 static ACPI_STATUS acpi_power_res_deref(struct acpi_power_res *, 104 ACPI_HANDLE); 105 static ACPI_STATUS acpi_power_res_sta(ACPI_OBJECT *, void *); 106 107 static ACPI_OBJECT *acpi_power_pkg_get(ACPI_HANDLE, int); 108 static int acpi_power_sysctl(SYSCTLFN_PROTO); 109 static const char *acpi_xname(ACPI_HANDLE); 110 111 static struct acpi_power_res * 112 acpi_power_res_init(ACPI_HANDLE hdl) 113 { 114 struct acpi_power_res *tmp = NULL; 115 struct acpi_power_res *res = NULL; 116 ACPI_OBJECT *obj; 117 ACPI_BUFFER buf; 118 ACPI_STATUS rv; 119 size_t i; 120 121 rv = acpi_eval_struct(hdl, NULL, &buf); 122 123 if (ACPI_FAILURE(rv)) 124 goto out; 125 126 obj = buf.Pointer; 127 128 if (obj->Type != ACPI_TYPE_POWER) { 129 rv = AE_TYPE; 130 goto out; 131 } 132 133 res = kmem_zalloc(sizeof(*res), KM_SLEEP); 134 135 if (res == NULL) { 136 rv = AE_NO_MEMORY; 137 goto out; 138 } 139 140 res->res_handle = hdl; 141 res->res_level = obj->PowerResource.SystemLevel; 142 res->res_order = obj->PowerResource.ResourceOrder; 143 144 (void)strlcpy(res->res_name, 145 acpi_xname(hdl), sizeof(res->res_name)); 146 147 for (i = 0; i < __arraycount(res->res_ref); i++) 148 res->res_ref[i] = NULL; 149 150 mutex_init(&res->res_mutex, MUTEX_DEFAULT, IPL_NONE); 151 152 /* 153 * Power resources should be ordered. 154 * 155 * These *should* be enabled from low values to high 156 * values and disabled from high values to low values. 157 */ 158 TAILQ_FOREACH(tmp, &res_head, res_list) { 159 160 if (res->res_order < tmp->res_order) { 161 TAILQ_INSERT_BEFORE(tmp, res, res_list); 162 break; 163 } 164 } 165 166 if (tmp == NULL) 167 TAILQ_INSERT_TAIL(&res_head, res, res_list); 168 169 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s added to the " 170 "power resource queue\n", res->res_name)); 171 172 out: 173 if (buf.Pointer != NULL) 174 ACPI_FREE(buf.Pointer); 175 176 return res; 177 } 178 179 static struct acpi_power_res * 180 acpi_power_res_get(ACPI_HANDLE hdl) 181 { 182 struct acpi_power_res *res; 183 184 TAILQ_FOREACH(res, &res_head, res_list) { 185 186 if (res->res_handle == hdl) 187 return res; 188 } 189 190 return acpi_power_res_init(hdl); 191 } 192 193 bool 194 acpi_power_register(ACPI_HANDLE hdl) 195 { 196 return true; 197 } 198 199 void 200 acpi_power_deregister(ACPI_HANDLE hdl) 201 { 202 struct acpi_devnode *ad = acpi_match_node(hdl); 203 struct acpi_power_res *res; 204 205 if (ad == NULL) 206 return; 207 208 /* 209 * Remove all references in each resource. 210 */ 211 TAILQ_FOREACH(res, &res_head, res_list) 212 (void)acpi_power_res_deref(res, ad->ad_handle); 213 } 214 215 /* 216 * Get the D-state of an ACPI device node. 217 */ 218 bool 219 acpi_power_get(ACPI_HANDLE hdl, int *state) 220 { 221 struct acpi_devnode *ad = acpi_match_node(hdl); 222 ACPI_STATUS rv; 223 224 if (ad == NULL) 225 return false; 226 227 /* 228 * As _PSC may be broken, first try to 229 * retrieve the power state indirectly 230 * via power resources. 231 */ 232 rv = acpi_power_get_indirect(ad); 233 234 if (ACPI_FAILURE(rv)) 235 rv = acpi_power_get_direct(ad); 236 237 if (ACPI_FAILURE(rv)) 238 goto fail; 239 240 KASSERT(ad->ad_state != ACPI_STATE_ERROR); 241 242 if (ad->ad_state < ACPI_STATE_D0 || ad->ad_state > ACPI_STATE_D3) { 243 rv = AE_BAD_VALUE; 244 goto fail; 245 } 246 247 if (state != NULL) 248 *state = ad->ad_state; 249 250 return true; 251 252 fail: 253 ad->ad_state = ACPI_STATE_ERROR; 254 255 if (state != NULL) 256 *state = ad->ad_state; 257 258 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "failed to get power state " 259 "for %s: %s\n", ad->ad_name, AcpiFormatException(rv))); 260 261 return false; 262 } 263 264 static ACPI_STATUS 265 acpi_power_get_direct(struct acpi_devnode *ad) 266 { 267 ACPI_INTEGER val = 0; 268 ACPI_STATUS rv; 269 270 rv = acpi_eval_integer(ad->ad_handle, "_PSC", &val); 271 272 KDASSERT((uint64_t)val < INT_MAX); 273 274 ad->ad_state = (int)val; 275 276 return rv; 277 } 278 279 static ACPI_STATUS 280 acpi_power_get_indirect(struct acpi_devnode *ad) 281 { 282 ACPI_OBJECT *pkg; 283 ACPI_STATUS rv; 284 int i; 285 286 CTASSERT(ACPI_STATE_D0 == 0 && ACPI_STATE_D1 == 1); 287 CTASSERT(ACPI_STATE_D2 == 2 && ACPI_STATE_D3 == 3); 288 289 /* 290 * The device is in a given D-state if all resources are on. 291 * To derive this, evaluate all elements in each _PRx package 292 * (x = 0 ... 3) and break if the noted condition becomes true. 293 */ 294 for (ad->ad_state = ACPI_STATE_D3, i = 0; i < ACPI_STATE_D3; i++) { 295 296 pkg = acpi_power_pkg_get(ad->ad_handle, i); 297 298 if (pkg == NULL) 299 continue; 300 301 /* 302 * For each element in the _PRx package, evaluate _STA 303 * and return AE_OK only if all power resources are on. 304 */ 305 rv = acpi_foreach_package_object(pkg, acpi_power_res_sta, ad); 306 307 if (ACPI_FAILURE(rv) && rv != AE_CTRL_FALSE) 308 goto out; 309 310 if (ACPI_SUCCESS(rv)) { 311 ad->ad_state = i; 312 goto out; 313 } 314 315 ACPI_FREE(pkg); pkg = NULL; 316 } 317 318 KASSERT(ad->ad_state == ACPI_STATE_D3); 319 320 return AE_OK; 321 322 out: 323 ACPI_FREE(pkg); 324 325 return rv; 326 } 327 328 /* 329 * Set the D-state of an ACPI device node. 330 */ 331 bool 332 acpi_power_set(ACPI_HANDLE hdl, int state) 333 { 334 struct acpi_devnode *ad = acpi_match_node(hdl); 335 ACPI_STATUS rv; 336 char path[5]; 337 int old; 338 339 if (ad == NULL) 340 return false; 341 342 if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3) { 343 rv = AE_BAD_PARAMETER; 344 goto fail; 345 } 346 347 if (acpi_power_get(ad->ad_handle, &old) != true) { 348 rv = AE_NOT_FOUND; 349 goto fail; 350 } 351 352 KASSERT(ad->ad_state == old); 353 KASSERT(ad->ad_state != ACPI_STATE_ERROR); 354 355 if (ad->ad_state == state) { 356 rv = AE_ALREADY_EXISTS; 357 goto fail; 358 } 359 360 /* 361 * It is only possible to go to D0 ("on") from D3 ("off"). 362 */ 363 if (ad->ad_state == ACPI_STATE_D3 && state != ACPI_STATE_D0) { 364 rv = AE_BAD_PARAMETER; 365 goto fail; 366 } 367 368 /* 369 * As noted in ACPI 4.0 (appendix A.2.1), the bus power state 370 * should never be lower than the highest state of one of its 371 * devices. Consequently, we cannot set the state to a lower 372 * (i.e. higher power) state than the parent device's state. 373 */ 374 if ((ad->ad_parent != NULL) && 375 (ad->ad_parent->ad_flags & ACPI_DEVICE_POWER) != 0) { 376 377 if (ad->ad_parent->ad_state > state) { 378 rv = AE_ABORT_METHOD; 379 goto fail; 380 } 381 } 382 383 /* 384 * We first sweep through the resources required for the target 385 * state, turning things on and building references. After this 386 * we dereference the resources required for the current state, 387 * turning the resources off as we go. 388 */ 389 rv = acpi_power_switch(ad, state, true); 390 391 if (ACPI_FAILURE(rv) && rv != AE_CTRL_CONTINUE) 392 goto fail; 393 394 rv = acpi_power_switch(ad, ad->ad_state, false); 395 396 if (ACPI_FAILURE(rv) && rv != AE_CTRL_CONTINUE) 397 goto fail; 398 399 /* 400 * Last but not least, invoke the power state switch method, 401 * if available. Because some systems use only _PSx for the 402 * power state transitions, we do this even if there is no _PRx. 403 */ 404 (void)snprintf(path, sizeof(path), "_PS%d", state); 405 (void)AcpiEvaluateObject(ad->ad_handle, path, NULL, NULL); 406 407 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s turned from " 408 "D%d to D%d\n", ad->ad_name, old, state)); 409 410 ad->ad_state = state; 411 412 return true; 413 414 fail: 415 ad->ad_state = ACPI_STATE_ERROR; 416 417 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "failed to set power state to D%d " 418 "for %s: %s\n", state, ad->ad_name, AcpiFormatException(rv))); 419 420 return false; 421 } 422 423 static ACPI_STATUS 424 acpi_power_switch(struct acpi_devnode *ad, int state, bool on) 425 { 426 ACPI_OBJECT *elm, *pkg; 427 ACPI_STATUS rv = AE_OK; 428 ACPI_HANDLE hdl; 429 uint32_t i, n; 430 431 /* 432 * For each element in the _PRx package, fetch 433 * the reference handle, search for this handle 434 * from the power resource queue, and turn the 435 * resource behind the handle on or off. 436 */ 437 pkg = acpi_power_pkg_get(ad->ad_handle, state); 438 439 if (pkg == NULL) 440 return AE_CTRL_CONTINUE; 441 442 n = pkg->Package.Count; 443 444 for (i = 0; i < n; i++) { 445 446 elm = &pkg->Package.Elements[i]; 447 rv = acpi_eval_reference_handle(elm, &hdl); 448 449 if (ACPI_FAILURE(rv)) 450 continue; 451 452 (void)acpi_power_res(hdl, ad->ad_handle, on); 453 } 454 455 ACPI_FREE(pkg); 456 457 return rv; 458 } 459 460 ACPI_STATUS 461 acpi_power_res(ACPI_HANDLE hdl, ACPI_HANDLE ref, bool on) 462 { 463 struct acpi_power_res *res; 464 const char *str; 465 ACPI_STATUS rv; 466 467 /* 468 * Search for the resource. 469 */ 470 res = acpi_power_res_get(hdl); 471 472 if (res == NULL) 473 return AE_NOT_FOUND; 474 475 if (ref == NULL) 476 return AE_BAD_PARAMETER; 477 478 /* 479 * Adjust the reference counting. This is 480 * necessary since a single power resource 481 * can be shared by multiple devices. 482 */ 483 if (on) { 484 rv = acpi_power_res_ref(res, ref); 485 str = "_ON"; 486 } else { 487 rv = acpi_power_res_deref(res, ref); 488 str = "_OFF"; 489 } 490 491 if (ACPI_FAILURE(rv)) 492 return rv; 493 494 /* 495 * Turn the resource on or off. 496 */ 497 return AcpiEvaluateObject(res->res_handle, str, NULL, NULL); 498 } 499 500 static ACPI_STATUS 501 acpi_power_res_ref(struct acpi_power_res *res, ACPI_HANDLE ref) 502 { 503 size_t i, j = SIZE_MAX; 504 505 mutex_enter(&res->res_mutex); 506 507 for (i = 0; i < __arraycount(res->res_ref); i++) { 508 509 /* 510 * Do not error out if the handle 511 * has already been referenced. 512 */ 513 if (res->res_ref[i] == ref) { 514 mutex_exit(&res->res_mutex); 515 return AE_OK; 516 } 517 518 if (j == SIZE_MAX && res->res_ref[i] == NULL) 519 j = i; 520 } 521 522 if (j == SIZE_MAX) { 523 mutex_exit(&res->res_mutex); 524 return AE_LIMIT; 525 } 526 527 res->res_ref[j] = ref; 528 mutex_exit(&res->res_mutex); 529 530 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s referenced " 531 "by %s\n", res->res_name, acpi_xname(ref))); 532 533 return AE_OK; 534 } 535 536 static ACPI_STATUS 537 acpi_power_res_deref(struct acpi_power_res *res, ACPI_HANDLE ref) 538 { 539 size_t i; 540 541 mutex_enter(&res->res_mutex); 542 543 for (i = 0; i < __arraycount(res->res_ref); i++) { 544 545 if (res->res_ref[i] != ref) 546 continue; 547 548 res->res_ref[i] = NULL; 549 mutex_exit(&res->res_mutex); 550 551 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s dereferenced " 552 "by %s\n", res->res_name, acpi_xname(ref))); 553 554 return AE_OK; 555 } 556 557 /* 558 * If the array remains to be non-empty, 559 * something else is using the resource 560 * and hence it can not be turned off. 561 */ 562 mutex_exit(&res->res_mutex); 563 564 return AE_ABORT_METHOD; 565 } 566 567 static ACPI_STATUS 568 acpi_power_res_sta(ACPI_OBJECT *elm, void *arg) 569 { 570 ACPI_INTEGER val; 571 ACPI_HANDLE hdl; 572 ACPI_STATUS rv; 573 574 rv = acpi_eval_reference_handle(elm, &hdl); 575 576 if (ACPI_FAILURE(rv)) 577 goto fail; 578 579 rv = acpi_eval_integer(hdl, "_STA", &val); 580 581 if (ACPI_FAILURE(rv)) 582 goto fail; 583 584 KDASSERT((uint64_t)val < INT_MAX); 585 586 if ((int)val != ACPI_STA_POW_ON && (int)val != ACPI_STA_POW_OFF) 587 return AE_BAD_VALUE; 588 589 if ((int)val != ACPI_STA_POW_ON) 590 return AE_CTRL_FALSE; /* XXX: Not an error. */ 591 592 return AE_OK; 593 594 fail: 595 if (rv == AE_CTRL_FALSE) 596 rv = AE_ERROR; 597 598 ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, "failed to evaluate _STA " 599 "for %s: %s\n", acpi_xname(hdl), AcpiFormatException(rv))); 600 601 return rv; 602 } 603 604 static ACPI_OBJECT * 605 acpi_power_pkg_get(ACPI_HANDLE hdl, int state) 606 { 607 char path[5] = "_PR?"; 608 ACPI_OBJECT *obj; 609 ACPI_BUFFER buf; 610 ACPI_STATUS rv; 611 612 path[3] = '0' + state; 613 614 rv = acpi_eval_struct(hdl, path, &buf); 615 616 if (ACPI_FAILURE(rv)) 617 goto fail; 618 619 if (buf.Length == 0) { 620 rv = AE_LIMIT; 621 goto fail; 622 } 623 624 obj = buf.Pointer; 625 626 if (obj->Type != ACPI_TYPE_PACKAGE) { 627 rv = AE_TYPE; 628 goto fail; 629 } 630 631 if (obj->Package.Count == 0) { 632 rv = AE_LIMIT; 633 goto fail; 634 } 635 636 return obj; 637 638 fail: 639 if (buf.Pointer != NULL) 640 ACPI_FREE(buf.Pointer); 641 642 ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, "failed to evaluate %s for " 643 "%s: %s\n", path, acpi_xname(hdl), AcpiFormatException(rv))); 644 645 return NULL; 646 } 647 648 SYSCTL_SETUP(sysctl_acpi_power_setup, "sysctl hw.acpi.power subtree setup") 649 { 650 const struct sysctlnode *anode; 651 int err; 652 653 err = sysctl_createv(NULL, 0, NULL, &anode, 654 CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", 655 NULL, NULL, 0, NULL, 0, 656 CTL_HW, CTL_CREATE, CTL_EOL); 657 658 if (err != 0) 659 return; 660 661 acpi_power_acpinode = anode->sysctl_num; 662 663 err = sysctl_createv(NULL, 0, &anode, &anode, 664 CTLFLAG_PERMANENT, CTLTYPE_NODE, 665 "power", SYSCTL_DESCR("ACPI device power states"), 666 NULL, 0, NULL, 0, 667 CTL_CREATE, CTL_EOL); 668 669 if (err != 0) 670 return; 671 672 acpi_power_powernode = anode->sysctl_num; 673 } 674 675 void 676 acpi_power_add(struct acpi_devnode *ad) 677 { 678 const char *str = NULL; 679 device_t dev; 680 int err; 681 682 KASSERT(ad != NULL && ad->ad_root != NULL); 683 KASSERT((ad->ad_flags & ACPI_DEVICE_POWER) != 0); 684 685 if (acpi_power_acpinode == CTL_EOL || 686 acpi_power_powernode == CTL_EOL) 687 return; 688 689 if (ad->ad_device != NULL) 690 str = device_xname(ad->ad_device); 691 else { 692 dev = acpi_pcidev_find_dev(ad); 693 694 if (dev != NULL) 695 str = device_xname(dev); 696 } 697 698 if (str == NULL) 699 return; 700 701 err = sysctl_createv(NULL, 0, NULL, NULL, 702 CTLFLAG_READONLY, CTLTYPE_STRING, str, 703 NULL, acpi_power_sysctl, 0, (void *)ad, 0, CTL_HW, 704 acpi_power_acpinode, acpi_power_powernode, 705 CTL_CREATE, CTL_EOL); 706 707 if (err != 0) 708 aprint_error_dev(ad->ad_root, "sysctl_createv" 709 "(hw.acpi.power.%s) failed (err %d)\n", str, err); 710 } 711 712 static int 713 acpi_power_sysctl(SYSCTLFN_ARGS) 714 { 715 struct acpi_devnode *ad; 716 struct sysctlnode node; 717 int err, state; 718 char t[3]; 719 720 node = *rnode; 721 ad = rnode->sysctl_data; 722 723 if (acpi_power_get(ad->ad_handle, &state) != true) 724 state = 0; 725 726 (void)memset(t, '\0', sizeof(t)); 727 (void)snprintf(t, sizeof(t), "D%d", state); 728 729 node.sysctl_data = &t; 730 731 err = sysctl_lookup(SYSCTLFN_CALL(&node)); 732 733 if (err || newp == NULL) 734 return err; 735 736 return 0; 737 } 738 739 /* 740 * XXX: Move this to acpi_util.c by refactoring 741 * acpi_name() to optionally return a single name. 742 */ 743 static const char * 744 acpi_xname(ACPI_HANDLE hdl) 745 { 746 static char str[5]; 747 ACPI_BUFFER buf; 748 ACPI_STATUS rv; 749 750 buf.Pointer = str; 751 buf.Length = sizeof(str); 752 753 rv = AcpiGetName(hdl, ACPI_SINGLE_NAME, &buf); 754 755 if (ACPI_FAILURE(rv)) 756 return "????"; 757 758 return str; 759 } 760