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