1 /* $NetBSD: thinkpad_acpi.c,v 1.11 2008/01/28 20:31:55 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jared D. McNeill. 18 * 4. Neither the name of The NetBSD Foundation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: thinkpad_acpi.c,v 1.11 2008/01/28 20:31:55 jmcneill Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/malloc.h> 41 #include <sys/buf.h> 42 #include <sys/callout.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/pmf.h> 46 #include <sys/queue.h> 47 #include <sys/kmem.h> 48 49 #include <dev/acpi/acpivar.h> 50 #include <dev/acpi/acpi_ecvar.h> 51 52 #if defined(__i386__) || defined(__amd64__) 53 #include <machine/pio.h> 54 #endif 55 56 #define THINKPAD_NSENSORS 8 57 58 typedef struct thinkpad_softc { 59 device_t sc_dev; 60 device_t sc_ecdev; 61 struct acpi_devnode *sc_node; 62 ACPI_HANDLE sc_cmoshdl; 63 bool sc_cmoshdl_valid; 64 65 #define TP_PSW_SLEEP 0 66 #define TP_PSW_HIBERNATE 1 67 #define TP_PSW_DISPLAY_CYCLE 2 68 #define TP_PSW_LOCK_SCREEN 3 69 #define TP_PSW_BATTERY_INFO 4 70 #define TP_PSW_EJECT_BUTTON 5 71 #define TP_PSW_ZOOM_BUTTON 6 72 #define TP_PSW_VENDOR_BUTTON 7 73 #define TP_PSW_LAST 8 74 struct sysmon_pswitch sc_smpsw[TP_PSW_LAST]; 75 bool sc_smpsw_valid; 76 77 struct sysmon_envsys *sc_sme; 78 envsys_data_t sc_sensor[THINKPAD_NSENSORS]; 79 80 int sc_display_state; 81 } thinkpad_softc_t; 82 83 /* Hotkey events */ 84 #define THINKPAD_NOTIFY_FnF1 0x001 85 #define THINKPAD_NOTIFY_LockScreen 0x002 86 #define THINKPAD_NOTIFY_BatteryInfo 0x003 87 #define THINKPAD_NOTIFY_SleepButton 0x004 88 #define THINKPAD_NOTIFY_WirelessSwitch 0x005 89 #define THINKPAD_NOTIFY_FnF6 0x006 90 #define THINKPAD_NOTIFY_DisplayCycle 0x007 91 #define THINKPAD_NOTIFY_PointerSwitch 0x008 92 #define THINKPAD_NOTIFY_EjectButton 0x009 93 #define THINKPAD_NOTIFY_FnF10 0x00a 94 #define THINKPAD_NOTIFY_FnF11 0x00b 95 #define THINKPAD_NOTIFY_HibernateButton 0x00c 96 #define THINKPAD_NOTIFY_BrightnessUp 0x010 97 #define THINKPAD_NOTIFY_BrightnessDown 0x011 98 #define THINKPAD_NOTIFY_ThinkLight 0x012 99 #define THINKPAD_NOTIFY_Zoom 0x014 100 #define THINKPAD_NOTIFY_ThinkVantage 0x018 101 102 #define THINKPAD_CMOS_BRIGHTNESS_UP 0x04 103 #define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05 104 105 #define THINKPAD_HKEY_VERSION 0x0100 106 107 #define THINKPAD_DISPLAY_LCD 0x01 108 #define THINKPAD_DISPLAY_CRT 0x02 109 #define THINKPAD_DISPLAY_DVI 0x08 110 #define THINKPAD_DISPLAY_ALL \ 111 (THINKPAD_DISPLAY_LCD | THINKPAD_DISPLAY_CRT | THINKPAD_DISPLAY_DVI) 112 113 static int thinkpad_match(device_t, struct cfdata *, void *); 114 static void thinkpad_attach(device_t, device_t, void *); 115 116 static ACPI_STATUS thinkpad_mask_init(thinkpad_softc_t *, uint32_t); 117 static void thinkpad_notify_handler(ACPI_HANDLE, UINT32, void *); 118 static void thinkpad_get_hotkeys(void *); 119 120 static void thinkpad_temp_init(thinkpad_softc_t *); 121 static void thinkpad_temp_refresh(struct sysmon_envsys *, envsys_data_t *); 122 123 static void thinkpad_wireless_toggle(thinkpad_softc_t *); 124 125 static bool thinkpad_resume(device_t); 126 static void thinkpad_brightness_up(device_t); 127 static void thinkpad_brightness_down(device_t); 128 static uint8_t thinkpad_brightness_read(thinkpad_softc_t *sc); 129 static void thinkpad_cmos(thinkpad_softc_t *, uint8_t); 130 131 CFATTACH_DECL_NEW(thinkpad, sizeof(thinkpad_softc_t), 132 thinkpad_match, thinkpad_attach, NULL, NULL); 133 134 static const char * const thinkpad_ids[] = { 135 "IBM0068", 136 NULL 137 }; 138 139 static int 140 thinkpad_match(device_t parent, struct cfdata *match, void *opaque) 141 { 142 struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; 143 ACPI_HANDLE hdl; 144 ACPI_INTEGER ver; 145 146 if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 147 return 0; 148 149 if (!acpi_match_hid(aa->aa_node->ad_devinfo, thinkpad_ids)) 150 return 0; 151 152 /* No point in attaching if we can't find the CMOS method */ 153 if (ACPI_FAILURE(AcpiGetHandle(NULL, "\\UCMS", &hdl))) 154 return 0; 155 156 /* We only support hotkey version 0x0100 */ 157 if (ACPI_FAILURE(acpi_eval_integer(aa->aa_node->ad_handle, "MHKV", 158 &ver))) 159 return 0; 160 161 if (ver != THINKPAD_HKEY_VERSION) 162 return 0; 163 164 /* Cool, looks like we're good to go */ 165 return 1; 166 } 167 168 static void 169 thinkpad_attach(device_t parent, device_t self, void *opaque) 170 { 171 thinkpad_softc_t *sc = device_private(self); 172 struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; 173 struct sysmon_pswitch *psw; 174 device_t curdev; 175 ACPI_STATUS rv; 176 ACPI_INTEGER val; 177 int i; 178 179 sc->sc_node = aa->aa_node; 180 sc->sc_dev = self; 181 sc->sc_display_state = THINKPAD_DISPLAY_LCD; 182 183 aprint_naive("\n"); 184 aprint_normal("\n"); 185 186 /* T61 uses \UCMS method for issuing CMOS commands */ 187 rv = AcpiGetHandle(NULL, "\\UCMS", &sc->sc_cmoshdl); 188 if (ACPI_FAILURE(rv)) 189 sc->sc_cmoshdl_valid = false; 190 else { 191 aprint_verbose_dev(self, "using CMOS at \\UCMS\n"); 192 sc->sc_cmoshdl_valid = true; 193 } 194 195 sc->sc_ecdev = NULL; 196 TAILQ_FOREACH(curdev, &alldevs, dv_list) 197 if (device_is_a(curdev, "acpiecdt") || 198 device_is_a(curdev, "acpiec")) { 199 sc->sc_ecdev = curdev; 200 break; 201 } 202 if (sc->sc_ecdev) 203 aprint_verbose_dev(self, "using EC at %s\n", 204 device_xname(sc->sc_ecdev)); 205 206 /* Get the supported event mask */ 207 rv = acpi_eval_integer(sc->sc_node->ad_handle, "MHKA", &val); 208 if (ACPI_FAILURE(rv)) { 209 aprint_error_dev(self, "couldn't evaluate MHKA: %s\n", 210 AcpiFormatException(rv)); 211 goto fail; 212 } 213 214 /* Enable all supported events */ 215 rv = thinkpad_mask_init(sc, val); 216 if (ACPI_FAILURE(rv)) { 217 aprint_error_dev(self, "couldn't set event mask: %s\n", 218 AcpiFormatException(rv)); 219 goto fail; 220 } 221 222 /* Install notify handler for events */ 223 rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, 224 ACPI_DEVICE_NOTIFY, thinkpad_notify_handler, sc); 225 if (ACPI_FAILURE(rv)) 226 aprint_error_dev(self, "couldn't install notify handler: %s\n", 227 AcpiFormatException(rv)); 228 229 /* Register power switches with sysmon */ 230 psw = sc->sc_smpsw; 231 sc->sc_smpsw_valid = true; 232 233 psw[TP_PSW_SLEEP].smpsw_name = device_xname(self); 234 psw[TP_PSW_SLEEP].smpsw_type = PSWITCH_TYPE_SLEEP; 235 #if notyet 236 psw[TP_PSW_HIBERNATE].smpsw_name = device_xname(self); 237 mpsw[TP_PSW_HIBERNATE].smpsw_type = PSWITCH_TYPE_HIBERNATE; 238 #endif 239 for (i = TP_PSW_DISPLAY_CYCLE; i < TP_PSW_LAST; i++) 240 sc->sc_smpsw[i].smpsw_type = PSWITCH_TYPE_HOTKEY; 241 psw[TP_PSW_DISPLAY_CYCLE].smpsw_name = PSWITCH_HK_DISPLAY_CYCLE; 242 psw[TP_PSW_LOCK_SCREEN].smpsw_name = PSWITCH_HK_LOCK_SCREEN; 243 psw[TP_PSW_BATTERY_INFO].smpsw_name = PSWITCH_HK_BATTERY_INFO; 244 psw[TP_PSW_EJECT_BUTTON].smpsw_name = PSWITCH_HK_EJECT_BUTTON; 245 psw[TP_PSW_ZOOM_BUTTON].smpsw_name = PSWITCH_HK_ZOOM_BUTTON; 246 psw[TP_PSW_VENDOR_BUTTON].smpsw_name = PSWITCH_HK_VENDOR_BUTTON; 247 248 for (i = 0; i < TP_PSW_LAST; i++) { 249 /* not supported yet */ 250 if (i == TP_PSW_HIBERNATE) 251 continue; 252 if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) { 253 aprint_error_dev(self, 254 "couldn't register with sysmon\n"); 255 sc->sc_smpsw_valid = false; 256 break; 257 } 258 } 259 260 /* Register temperature sensors with envsys */ 261 thinkpad_temp_init(sc); 262 263 fail: 264 if (!pmf_device_register(self, NULL, thinkpad_resume)) 265 aprint_error_dev(self, "couldn't establish power handler\n"); 266 if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, 267 thinkpad_brightness_up, true)) 268 aprint_error_dev(self, "couldn't register event handler\n"); 269 if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, 270 thinkpad_brightness_down, true)) 271 aprint_error_dev(self, "couldn't register event handler\n"); 272 } 273 274 static void 275 thinkpad_notify_handler(ACPI_HANDLE hdl, UINT32 notify, void *opaque) 276 { 277 thinkpad_softc_t *sc = (thinkpad_softc_t *)opaque; 278 device_t self = sc->sc_dev; 279 ACPI_STATUS rv; 280 281 if (notify != 0x80) { 282 aprint_debug_dev(self, "unknown notify 0x%02x\n", notify); 283 return; 284 } 285 286 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, thinkpad_get_hotkeys, sc); 287 if (ACPI_FAILURE(rv)) 288 aprint_error_dev(self, "couldn't queue hotkey handler: %s\n", 289 AcpiFormatException(rv)); 290 } 291 292 static void 293 thinkpad_get_hotkeys(void *opaque) 294 { 295 thinkpad_softc_t *sc = (thinkpad_softc_t *)opaque; 296 device_t self = sc->sc_dev; 297 ACPI_STATUS rv; 298 ACPI_INTEGER val; 299 int type, event; 300 301 for (;;) { 302 rv = acpi_eval_integer(sc->sc_node->ad_handle, "MHKP", &val); 303 if (ACPI_FAILURE(rv)) { 304 aprint_error_dev(self, "couldn't evaluate MHKP: %s\n", 305 AcpiFormatException(rv)); 306 return; 307 } 308 309 if (val == 0) 310 return; 311 312 type = (val & 0xf000) >> 12; 313 event = val & 0x0fff; 314 315 if (type != 1) 316 /* Only type 1 events are supported for now */ 317 continue; 318 319 switch (event) { 320 case THINKPAD_NOTIFY_BrightnessUp: 321 thinkpad_brightness_up(self); 322 break; 323 case THINKPAD_NOTIFY_BrightnessDown: 324 thinkpad_brightness_down(self); 325 break; 326 case THINKPAD_NOTIFY_WirelessSwitch: 327 thinkpad_wireless_toggle(sc); 328 break; 329 case THINKPAD_NOTIFY_SleepButton: 330 if (sc->sc_smpsw_valid == false) 331 break; 332 sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_SLEEP], 333 PSWITCH_EVENT_PRESSED); 334 break; 335 case THINKPAD_NOTIFY_HibernateButton: 336 #if notyet 337 if (sc->sc_smpsw_valid == false) 338 break; 339 sysmon_pswitch_event(&sc->sc_smpsw[TP_PSW_HIBERNATE], 340 PSWITCH_EVENT_PRESSED); 341 #endif 342 break; 343 case THINKPAD_NOTIFY_DisplayCycle: 344 if (sc->sc_smpsw_valid == false) 345 break; 346 sysmon_pswitch_event( 347 &sc->sc_smpsw[TP_PSW_DISPLAY_CYCLE], 348 PSWITCH_EVENT_PRESSED); 349 break; 350 case THINKPAD_NOTIFY_LockScreen: 351 if (sc->sc_smpsw_valid == false) 352 break; 353 sysmon_pswitch_event( 354 &sc->sc_smpsw[TP_PSW_LOCK_SCREEN], 355 PSWITCH_EVENT_PRESSED); 356 break; 357 case THINKPAD_NOTIFY_BatteryInfo: 358 if (sc->sc_smpsw_valid == false) 359 break; 360 sysmon_pswitch_event( 361 &sc->sc_smpsw[TP_PSW_BATTERY_INFO], 362 PSWITCH_EVENT_PRESSED); 363 break; 364 case THINKPAD_NOTIFY_EjectButton: 365 if (sc->sc_smpsw_valid == false) 366 break; 367 sysmon_pswitch_event( 368 &sc->sc_smpsw[TP_PSW_EJECT_BUTTON], 369 PSWITCH_EVENT_PRESSED); 370 break; 371 case THINKPAD_NOTIFY_Zoom: 372 if (sc->sc_smpsw_valid == false) 373 break; 374 sysmon_pswitch_event( 375 &sc->sc_smpsw[TP_PSW_ZOOM_BUTTON], 376 PSWITCH_EVENT_PRESSED); 377 break; 378 case THINKPAD_NOTIFY_ThinkVantage: 379 if (sc->sc_smpsw_valid == false) 380 break; 381 sysmon_pswitch_event( 382 &sc->sc_smpsw[TP_PSW_VENDOR_BUTTON], 383 PSWITCH_EVENT_PRESSED); 384 break; 385 case THINKPAD_NOTIFY_FnF1: 386 case THINKPAD_NOTIFY_FnF6: 387 case THINKPAD_NOTIFY_PointerSwitch: 388 case THINKPAD_NOTIFY_FnF10: 389 case THINKPAD_NOTIFY_FnF11: 390 case THINKPAD_NOTIFY_ThinkLight: 391 /* XXXJDM we should deliver hotkeys as keycodes */ 392 break; 393 default: 394 aprint_debug_dev(self, "notify event 0x%03x\n", event); 395 break; 396 } 397 } 398 } 399 400 static ACPI_STATUS 401 thinkpad_mask_init(thinkpad_softc_t *sc, uint32_t mask) 402 { 403 ACPI_OBJECT param[2]; 404 ACPI_OBJECT_LIST params; 405 ACPI_STATUS rv; 406 int i; 407 408 /* Update hotkey mask */ 409 params.Count = 2; 410 params.Pointer = param; 411 param[0].Type = param[1].Type = ACPI_TYPE_INTEGER; 412 413 for (i = 0; i < 32; i++) { 414 param[0].Integer.Value = i + 1; 415 param[1].Integer.Value = (((1 << i) & mask) != 0); 416 417 rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "MHKM", 418 ¶ms, NULL); 419 if (ACPI_FAILURE(rv)) 420 return rv; 421 } 422 423 /* Enable hotkey events */ 424 params.Count = 1; 425 param[0].Integer.Value = 1; 426 rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "MHKC", ¶ms, NULL); 427 if (ACPI_FAILURE(rv)) { 428 aprint_error_dev(sc->sc_dev, "couldn't enable hotkeys: %s\n", 429 AcpiFormatException(rv)); 430 return rv; 431 } 432 433 /* Claim ownership of brightness control */ 434 param[0].Integer.Value = 0; 435 (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "PWMS", ¶ms, NULL); 436 437 return AE_OK; 438 } 439 440 static void 441 thinkpad_temp_init(thinkpad_softc_t *sc) 442 { 443 char sname[5] = "TMP?"; 444 int i, err; 445 446 if (sc->sc_ecdev == NULL) 447 return; /* no chance of this working */ 448 449 sc->sc_sme = sysmon_envsys_create(); 450 for (i = 0; i < THINKPAD_NSENSORS; i++) { 451 sname[3] = '0' + i; 452 strcpy(sc->sc_sensor[i].desc, sname); 453 sc->sc_sensor[i].units = ENVSYS_STEMP; 454 455 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) 456 aprint_error_dev(sc->sc_dev, 457 "couldn't attach sensor %s\n", sname); 458 } 459 460 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 461 sc->sc_sme->sme_cookie = sc; 462 sc->sc_sme->sme_refresh = thinkpad_temp_refresh; 463 464 err = sysmon_envsys_register(sc->sc_sme); 465 if (err) { 466 aprint_error_dev(sc->sc_dev, 467 "couldn't register with sysmon: %d\n", err); 468 sysmon_envsys_destroy(sc->sc_sme); 469 } 470 } 471 472 static void 473 thinkpad_temp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 474 { 475 thinkpad_softc_t *sc = sme->sme_cookie; 476 char sname[5] = "TMP?"; 477 ACPI_INTEGER val; 478 ACPI_STATUS rv; 479 int temp; 480 481 sname[3] = '0' + edata->sensor; 482 rv = acpi_eval_integer(acpiec_get_handle(sc->sc_ecdev), sname, &val); 483 if (ACPI_FAILURE(rv)) { 484 edata->state = ENVSYS_SINVALID; 485 return; 486 } 487 temp = (int)val; 488 if (temp > 127 || temp < -127) { 489 edata->state = ENVSYS_SINVALID; 490 return; 491 } 492 493 edata->value_cur = temp * 1000000 + 273150000; 494 edata->state = ENVSYS_SVALID; 495 } 496 497 static void 498 thinkpad_wireless_toggle(thinkpad_softc_t *sc) 499 { 500 /* Ignore return value, as the hardware may not support bluetooth */ 501 (void)AcpiEvaluateObject(sc->sc_node->ad_handle, "BTGL", NULL, NULL); 502 } 503 504 static uint8_t 505 thinkpad_brightness_read(thinkpad_softc_t *sc) 506 { 507 #if defined(__i386__) || defined(__amd64__) 508 /* 509 * We have two ways to get the current brightness -- either via 510 * magic RTC registers, or using the EC. Since I don't dare mess 511 * with the EC, and Thinkpads are x86-only, this will have to do 512 * for now. 513 */ 514 outb(0x70, 0x6c); 515 return inb(0x71) & 7; 516 #else 517 return 0; 518 #endif 519 } 520 521 static void 522 thinkpad_brightness_up(device_t self) 523 { 524 thinkpad_softc_t *sc = device_private(self); 525 526 if (thinkpad_brightness_read(sc) == 7) 527 return; 528 thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_UP); 529 } 530 531 static void 532 thinkpad_brightness_down(device_t self) 533 { 534 thinkpad_softc_t *sc = device_private(self); 535 536 if (thinkpad_brightness_read(sc) == 0) 537 return; 538 thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_DOWN); 539 } 540 541 static void 542 thinkpad_cmos(thinkpad_softc_t *sc, uint8_t cmd) 543 { 544 ACPI_OBJECT param; 545 ACPI_OBJECT_LIST params; 546 ACPI_STATUS rv; 547 548 if (sc->sc_cmoshdl_valid == false) 549 return; 550 551 params.Count = 1; 552 params.Pointer = ¶m; 553 param.Type = ACPI_TYPE_INTEGER; 554 param.Integer.Value = cmd; 555 rv = AcpiEvaluateObject(sc->sc_cmoshdl, NULL, ¶ms, NULL); 556 if (ACPI_FAILURE(rv)) 557 aprint_error_dev(sc->sc_dev, "couldn't evalute CMOS: %s\n", 558 AcpiFormatException(rv)); 559 } 560 561 static bool 562 thinkpad_resume(device_t dv) 563 { 564 ACPI_STATUS rv; 565 ACPI_HANDLE pubs; 566 567 rv = AcpiGetHandle(NULL, "\\_SB.PCI0.LPC.EC.PUBS", &pubs); 568 if (ACPI_FAILURE(rv)) 569 return true; /* not fatal */ 570 571 rv = AcpiEvaluateObject(pubs, "_ON", NULL, NULL); 572 if (ACPI_FAILURE(rv)) 573 aprint_error_dev(dv, "failed to execute PUBS._ON: %s\n", 574 AcpiFormatException(rv)); 575 576 return true; 577 } 578