1/* $NetBSD: vald_acpi.c,v 1.8 2021/12/07 21:37:36 andvar Exp $ */ 2 3/*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Masanori Kanaoka. 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 2001 Bill Sommerfeld. 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 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed for the NetBSD Project by 47 * Wasabi Systems, Inc. 48 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 49 * or promote products derived from this software without specific prior 50 * written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 56 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62 * POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65/* 66 * ACPI VALD Driver for Toshiba Libretto L3. 67 * This driver is based on acpibat driver. 68 */ 69 70/* 71 * Obtain information of Toshiba "GHCI" Method from next URL. 72 * http://www.buzzard.org.uk/toshiba/docs.html 73 * http://memebeam.org/toys/ToshibaAcpiDriver 74 */ 75 76#include <sys/cdefs.h> 77__KERNEL_RCSID(0, "$NetBSD: vald_acpi.c,v 1.8 2021/12/07 21:37:36 andvar Exp $"); 78 79#include <sys/param.h> 80#include <sys/systm.h> 81#include <sys/device.h> 82 83#include <dev/acpi/acpica.h> 84#include <dev/acpi/acpireg.h> 85#include <dev/acpi/acpivar.h> 86 87#define _COMPONENT ACPI_RESOURCE_COMPONENT 88ACPI_MODULE_NAME ("vald_acpi") 89 90#define GHCI_WORDS 6 91#define GHCI_FIFO_EMPTY 0x8c00 92#define GHCI_NOT_SUPPORT 0x8000 93 94#define GHCI_BACKLIGHT 0x0002 95#define GHCI_ACADAPTOR 0x0003 96#define GHCI_FAN 0x0004 97#define GHCI_SYSTEM_EVENT_FIFO 0x0016 98#define GHCI_DISPLAY_DEVICE 0x001C 99#define GHCI_HOTKEY_EVENT 0x001E 100 101#define GHCI_ON 0x0001 102#define GHCI_OFF 0x0000 103#define GHCI_ENABLE 0x0001 104#define GHCI_DISABLE 0x0000 105 106#define GHCI_CRT 0x0002 107#define GHCI_LCD 0x0001 108 109 110struct vald_acpi_softc { 111 device_t sc_dev; /* base device glue */ 112 struct acpi_devnode *sc_node; /* our ACPI devnode */ 113 int sc_flags; /* see below */ 114 115 ACPI_HANDLE lcd_handle; /* lcd handle */ 116 int *lcd_level; /* lcd brightness table */ 117 int lcd_num; /* size of lcd brightness table */ 118 int lcd_index; /* index of lcd brightness table */ 119 120 ACPI_INTEGER sc_ac_status; /* AC adaptor status when attach */ 121}; 122 123static const struct device_compatible_entry compat_data[] = { 124 { .compat = "TOS6200" }, 125 DEVICE_COMPAT_EOL 126}; 127 128#define LIBRIGHT_HOLD 0x00 129#define LIBRIGHT_UP 0x01 130#define LIBRIGHT_DOWN 0x02 131 132static int vald_acpi_match(device_t, cfdata_t, void *); 133static void vald_acpi_attach(device_t, device_t, void *); 134 135static void vald_acpi_event(void *); 136static void vald_acpi_notify_handler(ACPI_HANDLE, uint32_t, void *); 137 138#define ACPI_NOTIFY_ValdStatusChanged 0x80 139 140 141static ACPI_STATUS vald_acpi_ghci_get(struct vald_acpi_softc *, uint32_t, 142 uint32_t *, uint32_t *); 143static ACPI_STATUS vald_acpi_ghci_set(struct vald_acpi_softc *, uint32_t, 144 uint32_t, uint32_t *); 145 146static ACPI_STATUS vald_acpi_libright_get_bus(ACPI_HANDLE, uint32_t, 147 void *, void **); 148static void vald_acpi_libright_get(struct vald_acpi_softc *); 149static void vald_acpi_libright_set(struct vald_acpi_softc *, int); 150 151static void vald_acpi_video_switch(struct vald_acpi_softc *); 152static void vald_acpi_fan_switch(struct vald_acpi_softc *); 153 154static ACPI_STATUS vald_acpi_bcm_set(ACPI_HANDLE, uint32_t); 155static ACPI_STATUS vald_acpi_dssx_set(uint32_t); 156 157CFATTACH_DECL_NEW(vald_acpi, sizeof(struct vald_acpi_softc), 158 vald_acpi_match, vald_acpi_attach, NULL, NULL); 159 160/* 161 * vald_acpi_match: 162 * 163 * Autoconfiguration `match' routine. 164 */ 165static int 166vald_acpi_match(device_t parent, cfdata_t match, void *aux) 167{ 168 struct acpi_attach_args *aa = aux; 169 170 return acpi_compatible_match(aa, compat_data); 171} 172 173/* 174 * vald_acpi_attach: 175 * 176 * Autoconfiguration `attach' routine. 177 */ 178static void 179vald_acpi_attach(device_t parent, device_t self, void *aux) 180{ 181 struct vald_acpi_softc *sc = device_private(self); 182 struct acpi_attach_args *aa = aux; 183 ACPI_STATUS rv; 184 uint32_t value, result; 185 186 aprint_naive(": Toshiba VALD\n"); 187 aprint_normal(": Toshiba VALD\n"); 188 189 sc->sc_node = aa->aa_node; 190 sc->sc_dev = self; 191 192 /* Get AC adaptor status via _PSR. */ 193 rv = acpi_eval_integer(ACPI_ROOT_OBJECT, "\\_SB_.ADP1._PSR", 194 &sc->sc_ac_status); 195 if (ACPI_FAILURE(rv)) 196 aprint_error_dev(self, "Unable to evaluate _PSR: %s\n", 197 AcpiFormatException(rv)); 198 else 199 aprint_verbose_dev(self, "AC adaptor %sconnected\n", 200 (sc->sc_ac_status == 0 ? "not ": "")); 201 202 /* Get LCD backlight status. */ 203 rv = vald_acpi_ghci_get(sc, GHCI_BACKLIGHT, &value, &result); 204 if (ACPI_SUCCESS(rv)) { 205 if (result != 0) 206 aprint_error_dev(self, 207 "can't get backlight status error=%d\n", result); 208 else 209 aprint_verbose_dev(self, "LCD backlight %s\n", 210 ((value == GHCI_ON) ? "on" : "off")); 211 } 212 213 /* Enable SystemEventFIFO,HotkeyEvent */ 214 rv = vald_acpi_ghci_set(sc, GHCI_SYSTEM_EVENT_FIFO, GHCI_ENABLE, 215 &result); 216 if (ACPI_SUCCESS(rv) && result != 0) 217 aprint_error_dev(self, 218 "can't enable SystemEventFIFO error=%d\n", result); 219 220 rv = vald_acpi_ghci_set(sc, GHCI_HOTKEY_EVENT, GHCI_ENABLE, &result); 221 if (ACPI_SUCCESS(rv) && result != 0) 222 aprint_error_dev(self, "can't enable HotkeyEvent error=%d\n", 223 result); 224 225 /* Check SystemFIFO events. */ 226 vald_acpi_event(sc); 227 228 /* Get LCD brightness level via _BCL. */ 229 vald_acpi_libright_get(sc); 230 231 /* Set LCD brightness level via _BCM. */ 232 vald_acpi_libright_set(sc, LIBRIGHT_HOLD); 233 234 /* enable vald notify */ 235 rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "ENAB", NULL, NULL); 236 237 if (ACPI_SUCCESS(rv)) 238 (void)acpi_register_notify(sc->sc_node, 239 vald_acpi_notify_handler); 240} 241 242/* 243 * vald_acpi_notify_handler: 244 * 245 * Notify handler. 246 */ 247static void 248vald_acpi_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context) 249{ 250 struct vald_acpi_softc *sc; 251 device_t self = context; 252 253 sc = device_private(self); 254 255 switch (notify) { 256 257 case ACPI_NOTIFY_ValdStatusChanged: 258 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, vald_acpi_event, sc); 259 break; 260 261 default: 262 aprint_error_dev(sc->sc_dev, 263 "unknown notify 0x%02X\n", notify); 264 break; 265 } 266} 267 268/* 269 * vald_acpi_event: 270 * 271 * Check hotkey event and do it, if event occur. 272 */ 273static void 274vald_acpi_event(void *arg) 275{ 276 struct vald_acpi_softc *sc = arg; 277 ACPI_STATUS rv; 278 uint32_t value, result; 279 280 while(1) { 281 rv = vald_acpi_ghci_get(sc, GHCI_SYSTEM_EVENT_FIFO, &value, 282 &result); 283 if (ACPI_SUCCESS(rv) && result == 0) { 284 285 switch (value) { 286 case 0x1c3: /* Fn + F9 */ 287 break; 288 case 0x1c2: /* Fn + F8 */ 289 vald_acpi_fan_switch(sc); 290 break; 291 case 0x1c1: /* Fn + F7 */ 292 vald_acpi_libright_set(sc, LIBRIGHT_UP); 293 break; 294 case 0x1c0: /* Fn + F6 */ 295 vald_acpi_libright_set(sc, LIBRIGHT_DOWN); 296 break; 297 case 0x1bf: /* Fn + F5 */ 298 vald_acpi_video_switch(sc); 299 break; 300 default: 301 break; 302 } 303 } 304 if (ACPI_FAILURE(rv) || result == GHCI_FIFO_EMPTY) 305 break; 306 } 307} 308 309/* 310 * vald_acpi_ghci_get: 311 * 312 * Get value via "GHCI" Method. 313 */ 314static ACPI_STATUS 315vald_acpi_ghci_get(struct vald_acpi_softc *sc, 316 uint32_t reg, uint32_t *value, uint32_t *result) 317{ 318 ACPI_STATUS rv; 319 ACPI_OBJECT Arg[GHCI_WORDS]; 320 ACPI_OBJECT_LIST ArgList; 321 ACPI_OBJECT *param, *PrtElement; 322 ACPI_BUFFER buf; 323 int i; 324 325 for (i = 0; i < GHCI_WORDS; i++) { 326 Arg[i].Type = ACPI_TYPE_INTEGER; 327 Arg[i].Integer.Value = 0; 328 } 329 330 Arg[0].Integer.Value = 0xfe00; 331 Arg[1].Integer.Value = reg; 332 Arg[2].Integer.Value = 0; 333 334 ArgList.Count = GHCI_WORDS; 335 ArgList.Pointer = Arg; 336 337 buf.Pointer = NULL; 338 buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 339 340 rv = AcpiEvaluateObject(sc->sc_node->ad_handle, 341 "GHCI", &ArgList, &buf); 342 if (ACPI_FAILURE(rv)) { 343 aprint_error_dev(sc->sc_dev, "failed to evaluate GHCI: %s\n", 344 AcpiFormatException(rv)); 345 return (rv); 346 } 347 348 *result = GHCI_NOT_SUPPORT; 349 *value = 0; 350 param = buf.Pointer; 351 if (param->Type == ACPI_TYPE_PACKAGE) { 352 PrtElement = param->Package.Elements; 353 if (PrtElement->Type == ACPI_TYPE_INTEGER) 354 *result = PrtElement->Integer.Value; 355 PrtElement++; 356 PrtElement++; 357 if (PrtElement->Type == ACPI_TYPE_INTEGER) 358 *value = PrtElement->Integer.Value; 359 } 360 361 if (buf.Pointer) 362 ACPI_FREE(buf.Pointer); 363 return (rv); 364} 365 366/* 367 * vald_acpi_ghci_set: 368 * 369 * Set value via "GHCI" Method. 370 */ 371static ACPI_STATUS 372vald_acpi_ghci_set(struct vald_acpi_softc *sc, 373 uint32_t reg, uint32_t value, uint32_t *result) 374{ 375 ACPI_STATUS rv; 376 ACPI_OBJECT Arg[GHCI_WORDS]; 377 ACPI_OBJECT_LIST ArgList; 378 ACPI_OBJECT *param, *PrtElement; 379 ACPI_BUFFER buf; 380 int i; 381 382 383 for (i = 0; i < GHCI_WORDS; i++) { 384 Arg[i].Type = ACPI_TYPE_INTEGER; 385 Arg[i].Integer.Value = 0; 386 } 387 388 Arg[0].Integer.Value = 0xff00; 389 Arg[1].Integer.Value = reg; 390 Arg[2].Integer.Value = value; 391 392 ArgList.Count = GHCI_WORDS; 393 ArgList.Pointer = Arg; 394 395 buf.Pointer = NULL; 396 buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 397 398 rv = AcpiEvaluateObject(sc->sc_node->ad_handle, 399 "GHCI", &ArgList, &buf); 400 if (ACPI_FAILURE(rv)) { 401 aprint_error_dev(sc->sc_dev, "failed to evaluate GHCI: %s\n", 402 AcpiFormatException(rv)); 403 return (rv); 404 } 405 406 *result = GHCI_NOT_SUPPORT; 407 param = buf.Pointer; 408 if (param->Type == ACPI_TYPE_PACKAGE) { 409 PrtElement = param->Package.Elements; 410 if (PrtElement->Type == ACPI_TYPE_INTEGER) 411 *result = PrtElement->Integer.Value; 412 } 413 414 if (buf.Pointer) 415 ACPI_FREE(buf.Pointer); 416 return (rv); 417} 418 419/* 420 * vald_acpi_libright_get_bus: 421 * 422 * Get LCD brightness level via "_BCL" Method, 423 * and save this handle. 424 */ 425static ACPI_STATUS 426vald_acpi_libright_get_bus(ACPI_HANDLE handle, uint32_t level, 427 void *context, void **status) 428{ 429 struct vald_acpi_softc *sc = context; 430 ACPI_STATUS rv; 431 ACPI_BUFFER buf; 432 ACPI_OBJECT *param, *PrtElement; 433 int i, *pi; 434 435 rv = acpi_eval_struct(handle, "_BCL", &buf); 436 if (ACPI_FAILURE(rv)) 437 return (AE_OK); 438 439 sc->lcd_handle = handle; 440 param = buf.Pointer; 441 if (param->Type == ACPI_TYPE_PACKAGE) { 442 printf("_BCL return: %d packages\n", param->Package.Count); 443 444 sc->lcd_num = param->Package.Count; 445 sc->lcd_level = ACPI_ALLOCATE(sizeof(int) * sc->lcd_num); 446 if (sc->lcd_level == NULL) { 447 if (buf.Pointer) 448 ACPI_FREE(buf.Pointer); 449 return (AE_NO_MEMORY); 450 } 451 452 PrtElement = param->Package.Elements; 453 pi = sc->lcd_level; 454 for (i = 0; i < param->Package.Count; i++) { 455 if (PrtElement->Type == ACPI_TYPE_INTEGER) { 456 *pi = (unsigned)PrtElement->Integer.Value; 457 PrtElement++; 458 pi++; 459 } 460 } 461 if (sc->sc_ac_status == 1) /* AC adaptor on when attach */ 462 sc->lcd_index = sc->lcd_num -1; /* MAX Brightness */ 463 else 464 sc->lcd_index = 3; 465 466#ifdef ACPI_DEBUG 467 pi = sc->lcd_level; 468 printf("\t Full Power Level: %d\n", *pi); 469 printf("\t on Battery Level: %d\n", *(pi+1)); 470 printf("\t Possible Level: "); 471 for (i = 2;i < sc->lcd_num; i++) 472 printf(" %d", *(pi+i)); 473 printf("\n"); 474#endif 475 } 476 477 if (buf.Pointer) 478 ACPI_FREE(buf.Pointer); 479 return (AE_OK); 480} 481 482/* 483 * vald_acpi_libright_get: 484 * 485 * Search node that have "_BCL" Method. 486 */ 487static void 488vald_acpi_libright_get(struct vald_acpi_softc *sc) 489{ 490 ACPI_HANDLE parent; 491 ACPI_STATUS rv; 492 493 aprint_verbose_dev(sc->sc_dev, "get LCD brightness via _BCL\n"); 494 495#ifdef ACPI_DEBUG 496 printf("acpi_libright_get: start\n"); 497#endif 498 rv = AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent); 499 if (ACPI_FAILURE(rv)) 500 return; 501 502 AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100, 503 vald_acpi_libright_get_bus, NULL, sc, NULL); 504} 505 506/* 507 * vald_acpi_libright_set: 508 * 509 * Figure up next status and set it. 510 */ 511static void 512vald_acpi_libright_set(struct vald_acpi_softc *sc, int UpDown) 513{ 514 uint32_t backlight, backlight_new, result, bright; 515 ACPI_STATUS rv; 516 int *pi; 517 518 /* Skip,if it does not support _BCL. */ 519 if (sc->lcd_handle == NULL) 520 return; 521 522 /* Get LCD backlight status. */ 523 rv = vald_acpi_ghci_get(sc, GHCI_BACKLIGHT, &backlight, &result); 524 if (ACPI_FAILURE(rv) || result != 0) 525 return; 526 527 /* Figure up next status. */ 528 backlight_new = backlight; 529 if (UpDown == LIBRIGHT_UP) { 530 if (backlight == 1) 531 sc->lcd_index++; 532 else { 533 /* backlight on */ 534 backlight_new = 1; 535 sc->lcd_index = 2; 536 } 537 } else if (UpDown == LIBRIGHT_DOWN) { 538 if ((backlight == 1) && (sc->lcd_index > 2)) 539 sc->lcd_index--; 540 else { 541 /* backlight off */ 542 backlight_new = 0; 543 sc->lcd_index = 2; 544 } 545 } 546 547 /* Check index value. */ 548 if (sc->lcd_index < 2) 549 sc->lcd_index = 2; /* index Minimum Value */ 550 if (sc->lcd_index >= sc->lcd_num) 551 sc->lcd_index = sc->lcd_num - 1; 552 553 /* Set LCD backlight,if status is changed. */ 554 if (backlight_new != backlight) { 555 rv = vald_acpi_ghci_set(sc, GHCI_BACKLIGHT, backlight_new, 556 &result); 557 if (ACPI_SUCCESS(rv) && result != 0) 558 aprint_error_dev(sc->sc_dev, 559 "can't set LCD backlight %s error=%x\n", 560 ((backlight_new == 1) ? "on" : "off"), result); 561 } 562 563 if (backlight_new == 1) { 564 565 pi = sc->lcd_level; 566 bright = *(pi + sc->lcd_index); 567 568 rv = vald_acpi_bcm_set(sc->lcd_handle, bright); 569 if (ACPI_FAILURE(rv)) 570 aprint_error_dev(sc->sc_dev, 571 "unable to evaluate _BCM: %s\n", 572 AcpiFormatException(rv)); 573 } else { 574 bright = 0; 575 } 576#ifdef ACPI_DEBUG 577 printf("LCD bright"); 578 printf(" %s", ((UpDown == LIBRIGHT_UP) ? "up":"")); 579 printf("%s\n", ((UpDown == LIBRIGHT_DOWN) ? "down":"")); 580 printf("\t acpi_libright_set: Set brightness to %d%%\n", bright); 581#endif 582} 583 584/* 585 * vald_acpi_video_switch: 586 * 587 * Get video status(LCD/CRT) and set new video status. 588 */ 589static void 590vald_acpi_video_switch(struct vald_acpi_softc *sc) 591{ 592 ACPI_STATUS rv; 593 uint32_t value, result; 594 595 /* Get video status. */ 596 rv = vald_acpi_ghci_get(sc, GHCI_DISPLAY_DEVICE, &value, &result); 597 if (ACPI_FAILURE(rv)) 598 return; 599 if (result != 0) { 600 aprint_error_dev(sc->sc_dev, 601 "can't get video status error=%x\n", result); 602 return; 603 } 604 605#ifdef ACPI_DEBUG 606 printf("Toggle LCD/CRT\n"); 607 printf("\t Before switch, video status: %s", 608 (((value & GHCI_LCD) == GHCI_LCD) ? "LCD" : "")); 609 printf("%s\n", (((value & GHCI_CRT) == GHCI_CRT) ? "CRT": "")); 610#endif 611 612 /* Toggle LCD/CRT */ 613 if (value & GHCI_LCD) { 614 value &= ~GHCI_LCD; 615 value |= GHCI_CRT; 616 } else if (value & GHCI_CRT){ 617 value &= ~GHCI_CRT; 618 value |= GHCI_LCD; 619 } 620 621 rv = vald_acpi_dssx_set(value); 622 if (ACPI_FAILURE(rv)) 623 aprint_error_dev(sc->sc_dev, "unable to evaluate DSSX: %s\n", 624 AcpiFormatException(rv)); 625 626} 627 628/* 629 * vald_acpi_bcm_set: 630 * 631 * Set LCD brightness via "_BCM" Method. 632 */ 633static ACPI_STATUS 634vald_acpi_bcm_set(ACPI_HANDLE handle, uint32_t bright) 635{ 636 ACPI_STATUS rv; 637 ACPI_OBJECT Arg; 638 ACPI_OBJECT_LIST ArgList; 639 640 ArgList.Count = 1; 641 ArgList.Pointer = &Arg; 642 643 Arg.Type = ACPI_TYPE_INTEGER; 644 Arg.Integer.Value = bright; 645 646 rv = AcpiEvaluateObject(handle, "_BCM", &ArgList, NULL); 647 return (rv); 648} 649 650/* 651 * vald_acpi_dssx_set: 652 * 653 * Set value via "\\_SB_.VALX.DSSX" Method. 654 */ 655static ACPI_STATUS 656vald_acpi_dssx_set(uint32_t value) 657{ 658 return acpi_eval_set_integer(NULL, "\\_SB_.VALX.DSSX", value); 659} 660 661/* 662 * vald_acpi_fan_switch: 663 * 664 * Get FAN status and set new FAN status. 665 */ 666static void 667vald_acpi_fan_switch(struct vald_acpi_softc *sc) 668{ 669 ACPI_STATUS rv; 670 uint32_t value, result; 671 672 /* Get FAN status */ 673 rv = vald_acpi_ghci_get(sc, GHCI_FAN, &value, &result); 674 if (ACPI_FAILURE(rv)) 675 return; 676 if (result != 0) { 677 aprint_error_dev(sc->sc_dev, "can't get FAN status error=%d\n", 678 result); 679 return; 680 } 681 682#ifdef ACPI_DEBUG 683 printf("Toggle FAN on/off\n"); 684 printf("\t Before toggle, FAN status %s\n", 685 (value == GHCI_OFF ? "off" : "on")); 686#endif 687 688 /* Toggle FAN on/off */ 689 if (value == GHCI_OFF) 690 value = GHCI_ON; 691 else 692 value = GHCI_OFF; 693 694 /* Set FAN new status. */ 695 rv = vald_acpi_ghci_set(sc, GHCI_FAN, value, &result); 696 if (ACPI_FAILURE(rv)) 697 return; 698 if (result != 0) { 699 aprint_error_dev(sc->sc_dev, "can't set FAN status error=%d\n", 700 result); 701 return; 702 } 703 704#ifdef ACPI_DEBUG 705 printf("\t After toggle, FAN status %s\n", 706 (value == GHCI_OFF ? "off" : "on")); 707#endif 708} 709