1 /* $NetBSD: acpi_power.c,v 1.35 2017/06/01 02:45:09 chs 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.35 2017/06/01 02:45:09 chs 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 res->res_handle = hdl; 135 res->res_level = obj->PowerResource.SystemLevel; 136 res->res_order = obj->PowerResource.ResourceOrder; 137 138 (void)strlcpy(res->res_name, 139 acpi_xname(hdl), sizeof(res->res_name)); 140 141 for (i = 0; i < __arraycount(res->res_ref); i++) 142 res->res_ref[i] = NULL; 143 144 mutex_init(&res->res_mutex, MUTEX_DEFAULT, IPL_NONE); 145 146 /* 147 * Power resources should be ordered. 148 * 149 * These *should* be enabled from low values to high 150 * values and disabled from high values to low values. 151 */ 152 TAILQ_FOREACH(tmp, &res_head, res_list) { 153 154 if (res->res_order < tmp->res_order) { 155 TAILQ_INSERT_BEFORE(tmp, res, res_list); 156 break; 157 } 158 } 159 160 if (tmp == NULL) 161 TAILQ_INSERT_TAIL(&res_head, res, res_list); 162 163 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s added to the " 164 "power resource queue\n", res->res_name)); 165 166 out: 167 if (buf.Pointer != NULL) 168 ACPI_FREE(buf.Pointer); 169 170 return res; 171 } 172 173 static struct acpi_power_res * 174 acpi_power_res_get(ACPI_HANDLE hdl) 175 { 176 struct acpi_power_res *res; 177 178 TAILQ_FOREACH(res, &res_head, res_list) { 179 180 if (res->res_handle == hdl) 181 return res; 182 } 183 184 return acpi_power_res_init(hdl); 185 } 186 187 bool 188 acpi_power_register(ACPI_HANDLE hdl) 189 { 190 return true; 191 } 192 193 void 194 acpi_power_deregister(ACPI_HANDLE hdl) 195 { 196 struct acpi_devnode *ad = acpi_match_node(hdl); 197 struct acpi_power_res *res; 198 199 if (ad == NULL) 200 return; 201 202 /* 203 * Remove all references in each resource. 204 */ 205 TAILQ_FOREACH(res, &res_head, res_list) 206 (void)acpi_power_res_deref(res, ad->ad_handle); 207 } 208 209 /* 210 * Get the D-state of an ACPI device node. 211 */ 212 bool 213 acpi_power_get(ACPI_HANDLE hdl, int *state) 214 { 215 struct acpi_devnode *ad = acpi_match_node(hdl); 216 ACPI_STATUS rv; 217 218 if (ad == NULL) 219 return false; 220 221 /* 222 * As _PSC may be broken, first try to 223 * retrieve the power state indirectly 224 * via power resources. 225 */ 226 rv = acpi_power_get_indirect(ad); 227 228 if (ACPI_FAILURE(rv)) 229 rv = acpi_power_get_direct(ad); 230 231 if (ACPI_FAILURE(rv)) 232 goto fail; 233 234 KASSERT(ad->ad_state != ACPI_STATE_ERROR); 235 236 if (ad->ad_state < ACPI_STATE_D0 || ad->ad_state > ACPI_STATE_D3) { 237 rv = AE_BAD_VALUE; 238 goto fail; 239 } 240 241 if (state != NULL) 242 *state = ad->ad_state; 243 244 return true; 245 246 fail: 247 ad->ad_state = ACPI_STATE_ERROR; 248 249 if (state != NULL) 250 *state = ad->ad_state; 251 252 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "failed to get power state " 253 "for %s: %s\n", ad->ad_name, AcpiFormatException(rv))); 254 255 return false; 256 } 257 258 static ACPI_STATUS 259 acpi_power_get_direct(struct acpi_devnode *ad) 260 { 261 ACPI_INTEGER val = 0; 262 ACPI_STATUS rv; 263 264 rv = acpi_eval_integer(ad->ad_handle, "_PSC", &val); 265 266 KDASSERT((uint64_t)val < INT_MAX); 267 268 ad->ad_state = (int)val; 269 270 return rv; 271 } 272 273 static ACPI_STATUS 274 acpi_power_get_indirect(struct acpi_devnode *ad) 275 { 276 ACPI_OBJECT *pkg; 277 ACPI_STATUS rv; 278 int i; 279 280 CTASSERT(ACPI_STATE_D0 == 0 && ACPI_STATE_D1 == 1); 281 CTASSERT(ACPI_STATE_D2 == 2 && ACPI_STATE_D3 == 3); 282 283 /* 284 * The device is in a given D-state if all resources are on. 285 * To derive this, evaluate all elements in each _PRx package 286 * (x = 0 ... 3) and break if the noted condition becomes true. 287 */ 288 for (ad->ad_state = ACPI_STATE_D3, i = 0; i < ACPI_STATE_D3; i++) { 289 290 pkg = acpi_power_pkg_get(ad->ad_handle, i); 291 292 if (pkg == NULL) 293 continue; 294 295 /* 296 * For each element in the _PRx package, evaluate _STA 297 * and return AE_OK only if all power resources are on. 298 */ 299 rv = acpi_foreach_package_object(pkg, acpi_power_res_sta, ad); 300 301 if (ACPI_FAILURE(rv) && rv != AE_CTRL_FALSE) 302 goto out; 303 304 if (ACPI_SUCCESS(rv)) { 305 ad->ad_state = i; 306 goto out; 307 } 308 309 ACPI_FREE(pkg); pkg = NULL; 310 } 311 312 KASSERT(ad->ad_state == ACPI_STATE_D3); 313 314 return AE_OK; 315 316 out: 317 ACPI_FREE(pkg); 318 319 return rv; 320 } 321 322 /* 323 * Set the D-state of an ACPI device node. 324 */ 325 bool 326 acpi_power_set(ACPI_HANDLE hdl, int state) 327 { 328 struct acpi_devnode *ad = acpi_match_node(hdl); 329 ACPI_STATUS rv; 330 char path[5]; 331 int old; 332 333 if (ad == NULL) 334 return false; 335 336 if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3) { 337 rv = AE_BAD_PARAMETER; 338 goto fail; 339 } 340 341 if (acpi_power_get(ad->ad_handle, &old) != true) { 342 rv = AE_NOT_FOUND; 343 goto fail; 344 } 345 346 KASSERT(ad->ad_state == old); 347 KASSERT(ad->ad_state != ACPI_STATE_ERROR); 348 349 if (ad->ad_state == state) { 350 rv = AE_ALREADY_EXISTS; 351 goto fail; 352 } 353 354 /* 355 * It is only possible to go to D0 ("on") from D3 ("off"). 356 */ 357 if (ad->ad_state == ACPI_STATE_D3 && state != ACPI_STATE_D0) { 358 rv = AE_BAD_PARAMETER; 359 goto fail; 360 } 361 362 /* 363 * As noted in ACPI 4.0 (appendix A.2.1), the bus power state 364 * should never be lower than the highest state of one of its 365 * devices. Consequently, we cannot set the state to a lower 366 * (i.e. higher power) state than the parent device's state. 367 */ 368 if ((ad->ad_parent != NULL) && 369 (ad->ad_parent->ad_flags & ACPI_DEVICE_POWER) != 0) { 370 371 if (ad->ad_parent->ad_state > state) { 372 rv = AE_ABORT_METHOD; 373 goto fail; 374 } 375 } 376 377 /* 378 * We first sweep through the resources required for the target 379 * state, turning things on and building references. After this 380 * we dereference the resources required for the current state, 381 * turning the resources off as we go. 382 */ 383 rv = acpi_power_switch(ad, state, true); 384 385 if (ACPI_FAILURE(rv) && rv != AE_CTRL_CONTINUE) 386 goto fail; 387 388 rv = acpi_power_switch(ad, ad->ad_state, false); 389 390 if (ACPI_FAILURE(rv) && rv != AE_CTRL_CONTINUE) 391 goto fail; 392 393 /* 394 * Last but not least, invoke the power state switch method, 395 * if available. Because some systems use only _PSx for the 396 * power state transitions, we do this even if there is no _PRx. 397 */ 398 (void)snprintf(path, sizeof(path), "_PS%d", state); 399 (void)AcpiEvaluateObject(ad->ad_handle, path, NULL, NULL); 400 401 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s turned from " 402 "D%d to D%d\n", ad->ad_name, old, state)); 403 404 ad->ad_state = state; 405 406 return true; 407 408 fail: 409 ad->ad_state = ACPI_STATE_ERROR; 410 411 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "failed to set power state to D%d " 412 "for %s: %s\n", state, ad->ad_name, AcpiFormatException(rv))); 413 414 return false; 415 } 416 417 static ACPI_STATUS 418 acpi_power_switch(struct acpi_devnode *ad, int state, bool on) 419 { 420 ACPI_OBJECT *elm, *pkg; 421 ACPI_STATUS rv = AE_OK; 422 ACPI_HANDLE hdl; 423 uint32_t i, n; 424 425 /* 426 * For each element in the _PRx package, fetch 427 * the reference handle, search for this handle 428 * from the power resource queue, and turn the 429 * resource behind the handle on or off. 430 */ 431 pkg = acpi_power_pkg_get(ad->ad_handle, state); 432 433 if (pkg == NULL) 434 return AE_CTRL_CONTINUE; 435 436 n = pkg->Package.Count; 437 438 for (i = 0; i < n; i++) { 439 440 elm = &pkg->Package.Elements[i]; 441 rv = acpi_eval_reference_handle(elm, &hdl); 442 443 if (ACPI_FAILURE(rv)) 444 continue; 445 446 (void)acpi_power_res(hdl, ad->ad_handle, on); 447 } 448 449 ACPI_FREE(pkg); 450 451 return rv; 452 } 453 454 ACPI_STATUS 455 acpi_power_res(ACPI_HANDLE hdl, ACPI_HANDLE ref, bool on) 456 { 457 struct acpi_power_res *res; 458 const char *str; 459 ACPI_STATUS rv; 460 461 /* 462 * Search for the resource. 463 */ 464 res = acpi_power_res_get(hdl); 465 466 if (res == NULL) 467 return AE_NOT_FOUND; 468 469 if (ref == NULL) 470 return AE_BAD_PARAMETER; 471 472 /* 473 * Adjust the reference counting. This is 474 * necessary since a single power resource 475 * can be shared by multiple devices. 476 */ 477 if (on) { 478 rv = acpi_power_res_ref(res, ref); 479 str = "_ON"; 480 } else { 481 rv = acpi_power_res_deref(res, ref); 482 str = "_OFF"; 483 } 484 485 if (ACPI_FAILURE(rv)) 486 return rv; 487 488 /* 489 * Turn the resource on or off. 490 */ 491 return AcpiEvaluateObject(res->res_handle, str, NULL, NULL); 492 } 493 494 static ACPI_STATUS 495 acpi_power_res_ref(struct acpi_power_res *res, ACPI_HANDLE ref) 496 { 497 size_t i, j = SIZE_MAX; 498 499 mutex_enter(&res->res_mutex); 500 501 for (i = 0; i < __arraycount(res->res_ref); i++) { 502 503 /* 504 * Do not error out if the handle 505 * has already been referenced. 506 */ 507 if (res->res_ref[i] == ref) { 508 mutex_exit(&res->res_mutex); 509 return AE_OK; 510 } 511 512 if (j == SIZE_MAX && res->res_ref[i] == NULL) 513 j = i; 514 } 515 516 if (j == SIZE_MAX) { 517 mutex_exit(&res->res_mutex); 518 return AE_LIMIT; 519 } 520 521 res->res_ref[j] = ref; 522 mutex_exit(&res->res_mutex); 523 524 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s referenced " 525 "by %s\n", res->res_name, acpi_xname(ref))); 526 527 return AE_OK; 528 } 529 530 static ACPI_STATUS 531 acpi_power_res_deref(struct acpi_power_res *res, ACPI_HANDLE ref) 532 { 533 size_t i; 534 535 mutex_enter(&res->res_mutex); 536 537 for (i = 0; i < __arraycount(res->res_ref); i++) { 538 539 if (res->res_ref[i] != ref) 540 continue; 541 542 res->res_ref[i] = NULL; 543 mutex_exit(&res->res_mutex); 544 545 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s dereferenced " 546 "by %s\n", res->res_name, acpi_xname(ref))); 547 548 return AE_OK; 549 } 550 551 /* 552 * If the array remains to be non-empty, 553 * something else is using the resource 554 * and hence it can not be turned off. 555 */ 556 mutex_exit(&res->res_mutex); 557 558 return AE_ABORT_METHOD; 559 } 560 561 static ACPI_STATUS 562 acpi_power_res_sta(ACPI_OBJECT *elm, void *arg) 563 { 564 ACPI_INTEGER val; 565 ACPI_HANDLE hdl; 566 ACPI_STATUS rv; 567 568 rv = acpi_eval_reference_handle(elm, &hdl); 569 570 if (ACPI_FAILURE(rv)) 571 goto fail; 572 573 rv = acpi_eval_integer(hdl, "_STA", &val); 574 575 if (ACPI_FAILURE(rv)) 576 goto fail; 577 578 KDASSERT((uint64_t)val < INT_MAX); 579 580 if ((int)val != ACPI_STA_POW_ON && (int)val != ACPI_STA_POW_OFF) 581 return AE_BAD_VALUE; 582 583 if ((int)val != ACPI_STA_POW_ON) 584 return AE_CTRL_FALSE; /* XXX: Not an error. */ 585 586 return AE_OK; 587 588 fail: 589 if (rv == AE_CTRL_FALSE) 590 rv = AE_ERROR; 591 592 ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, "failed to evaluate _STA " 593 "for %s: %s\n", acpi_xname(hdl), AcpiFormatException(rv))); 594 595 return rv; 596 } 597 598 static ACPI_OBJECT * 599 acpi_power_pkg_get(ACPI_HANDLE hdl, int state) 600 { 601 char path[5] = "_PR?"; 602 ACPI_OBJECT *obj; 603 ACPI_BUFFER buf; 604 ACPI_STATUS rv; 605 606 path[3] = '0' + state; 607 608 rv = acpi_eval_struct(hdl, path, &buf); 609 610 if (ACPI_FAILURE(rv)) 611 goto fail; 612 613 if (buf.Length == 0) { 614 rv = AE_LIMIT; 615 goto fail; 616 } 617 618 obj = buf.Pointer; 619 620 if (obj->Type != ACPI_TYPE_PACKAGE) { 621 rv = AE_TYPE; 622 goto fail; 623 } 624 625 if (obj->Package.Count == 0) { 626 rv = AE_LIMIT; 627 goto fail; 628 } 629 630 return obj; 631 632 fail: 633 if (buf.Pointer != NULL) 634 ACPI_FREE(buf.Pointer); 635 636 ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT, "failed to evaluate %s for " 637 "%s: %s\n", path, acpi_xname(hdl), AcpiFormatException(rv))); 638 639 return NULL; 640 } 641 642 SYSCTL_SETUP(sysctl_acpi_power_setup, "sysctl hw.acpi.power subtree setup") 643 { 644 const struct sysctlnode *anode; 645 int err; 646 647 err = sysctl_createv(NULL, 0, NULL, &anode, 648 CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", 649 NULL, NULL, 0, NULL, 0, 650 CTL_HW, CTL_CREATE, CTL_EOL); 651 652 if (err != 0) 653 return; 654 655 acpi_power_acpinode = anode->sysctl_num; 656 657 err = sysctl_createv(NULL, 0, &anode, &anode, 658 CTLFLAG_PERMANENT, CTLTYPE_NODE, 659 "power", SYSCTL_DESCR("ACPI device power states"), 660 NULL, 0, NULL, 0, 661 CTL_CREATE, CTL_EOL); 662 663 if (err != 0) 664 return; 665 666 acpi_power_powernode = anode->sysctl_num; 667 } 668 669 void 670 acpi_power_add(struct acpi_devnode *ad) 671 { 672 const char *str = NULL; 673 device_t dev; 674 int err; 675 676 KASSERT(ad != NULL && ad->ad_root != NULL); 677 KASSERT((ad->ad_flags & ACPI_DEVICE_POWER) != 0); 678 679 if (acpi_power_acpinode == CTL_EOL || 680 acpi_power_powernode == CTL_EOL) 681 return; 682 683 if (ad->ad_device != NULL) 684 str = device_xname(ad->ad_device); 685 else { 686 dev = acpi_pcidev_find_dev(ad); 687 688 if (dev != NULL) 689 str = device_xname(dev); 690 } 691 692 if (str == NULL) 693 return; 694 695 err = sysctl_createv(NULL, 0, NULL, NULL, 696 CTLFLAG_READONLY, CTLTYPE_STRING, str, 697 NULL, acpi_power_sysctl, 0, (void *)ad, 0, CTL_HW, 698 acpi_power_acpinode, acpi_power_powernode, 699 CTL_CREATE, CTL_EOL); 700 701 if (err != 0) 702 aprint_error_dev(ad->ad_root, "sysctl_createv" 703 "(hw.acpi.power.%s) failed (err %d)\n", str, err); 704 } 705 706 static int 707 acpi_power_sysctl(SYSCTLFN_ARGS) 708 { 709 struct acpi_devnode *ad; 710 struct sysctlnode node; 711 int err, state; 712 char t[3]; 713 714 node = *rnode; 715 ad = rnode->sysctl_data; 716 717 if (acpi_power_get(ad->ad_handle, &state) != true) 718 state = 0; 719 720 (void)memset(t, '\0', sizeof(t)); 721 (void)snprintf(t, sizeof(t), "D%d", state); 722 723 node.sysctl_data = &t; 724 725 err = sysctl_lookup(SYSCTLFN_CALL(&node)); 726 727 if (err || newp == NULL) 728 return err; 729 730 return 0; 731 } 732 733 /* 734 * XXX: Move this to acpi_util.c by refactoring 735 * acpi_name() to optionally return a single name. 736 */ 737 static const char * 738 acpi_xname(ACPI_HANDLE hdl) 739 { 740 static char str[5]; 741 ACPI_BUFFER buf; 742 ACPI_STATUS rv; 743 744 buf.Pointer = str; 745 buf.Length = sizeof(str); 746 747 rv = AcpiGetName(hdl, ACPI_SINGLE_NAME, &buf); 748 749 if (ACPI_FAILURE(rv)) 750 return "????"; 751 752 return str; 753 } 754