1/* $NetBSD: acpi_display.c,v 1.24 2024/05/10 19:29:46 maya Exp $ */ 2 3/*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Gregoire Sutre. 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 * ACPI Display Adapter Driver. 34 * 35 * Appendix B of the ACPI specification presents ACPI extensions for display 36 * adapters. Systems containing a built-in display adapter are required to 37 * implement these extensions (in their ACPI BIOS). This driver uses these 38 * extensions to provide generic support for brightness control and display 39 * switching. 40 * 41 * If brightness control methods are absent or non-functional, ACPI brightness 42 * notifications are relayed to the PMF framework. 43 * 44 * This driver sets the BIOS switch policy (_DOS method) as follows: 45 * - The BIOS should automatically switch the active display output, with no 46 * interaction required on the OS part. 47 * - The BIOS should not automatically control the brightness levels. 48 * 49 * Brightness and BIOS switch policy can be adjusted from userland, via the 50 * sysctl variables acpivga<n>.policy and acpiout<n>.brightness under hw.acpi. 51 */ 52 53/* 54 * The driver uses mutex(9) protection since changes to the hardware/software 55 * state may be initiated both by the BIOS (ACPI notifications) and by the user 56 * (sysctl). The ACPI display adapter's mutex is shared with all ACPI display 57 * output devices attached to it. 58 * 59 * The mutex only prevents undesired interleavings of ACPI notify handlers, 60 * sysctl callbacks, and pmf(9) suspend/resume routines. Race conditions with 61 * autoconf(9) detachment routines could, in theory, still occur. 62 * 63 * The array of connected output devices (sc_odinfo) is, after attachment, only 64 * used in ACPI notify handler callbacks. Since two such callbacks cannot be 65 * running simultaneously, this information does not need protection. 66 */ 67 68#include <sys/cdefs.h> 69__KERNEL_RCSID(0, "$NetBSD: acpi_display.c,v 1.24 2024/05/10 19:29:46 maya Exp $"); 70 71#include <sys/param.h> 72#include <sys/device.h> 73#include <sys/kmem.h> 74#include <sys/module.h> 75#include <sys/mutex.h> 76#include <sys/pserialize.h> 77#include <sys/pslist.h> 78#include <sys/sysctl.h> 79#include <sys/systm.h> 80#include <sys/xcall.h> 81 82#include <dev/pci/pcireg.h> 83#include <dev/pci/pcidevs.h> 84 85#include <dev/acpi/acpi_display.h> 86#include <dev/acpi/acpireg.h> 87#include <dev/acpi/acpivar.h> 88 89#define _COMPONENT ACPI_DISPLAY_COMPONENT 90ACPI_MODULE_NAME ("acpi_display") 91 92/* Notifications specific to display adapter devices (ACPI 4.0a, Sec. B.5). */ 93#define ACPI_NOTIFY_CycleOutputDevice 0x80 94#define ACPI_NOTIFY_OutputDeviceStatusChange 0x81 95#define ACPI_NOTIFY_CycleDisplayOutputHotkeyPressed 0x82 96#define ACPI_NOTIFY_NextDisplayOutputHotkeyPressed 0x83 97#define ACPI_NOTIFY_PreviousDisplayOutputHotkeyPressed 0x84 98 99/* Notifications specific to display output devices (ACPI 4.0a, Sec. B.7). */ 100#define ACPI_NOTIFY_CycleBrightness 0x85 101#define ACPI_NOTIFY_IncreaseBrightness 0x86 102#define ACPI_NOTIFY_DecreaseBrightness 0x87 103#define ACPI_NOTIFY_ZeroBrightness 0x88 104#define ACPI_NOTIFY_DisplayDeviceOff 0x89 105 106/* Format of the BIOS switch policy set by _DOS (ACPI 4.0a, Sec. B.4.1). */ 107typedef union acpidisp_bios_policy_t { 108 uint8_t raw; 109 struct { 110 uint8_t output:2; 111 uint8_t brightness:1; 112 uint8_t reserved:5; 113 } __packed fmt; 114} acpidisp_bios_policy_t; 115 116/* Default BIOS switch policy (ACPI 4.0a, Sec. B.4.1). */ 117static const acpidisp_bios_policy_t acpidisp_default_bios_policy = { 118 .raw = 0x1 119}; 120 121/* BIOS output switch policies (ACPI 4.0a, Sec. B.4.1). */ 122#define ACPI_DISP_POLICY_OUTPUT_NORMAL 0x0 123#define ACPI_DISP_POLICY_OUTPUT_AUTO 0x1 124#define ACPI_DISP_POLICY_OUTPUT_LOCKED 0x2 125#define ACPI_DISP_POLICY_OUTPUT_HOTKEY 0x3 126 127/* BIOS brightness switch policies (ACPI 4.0a, Sec. B.4.1). */ 128#define ACPI_DISP_POLICY_BRIGHTNESS_AUTO 0x0 129#define ACPI_DISP_POLICY_BRIGHTNESS_NORMAL 0x1 130 131/* Format of output device attributes (ACPI 4.0a, Table B-2). */ 132typedef union acpidisp_od_attrs_t { 133 uint16_t device_id; 134 uint32_t raw; 135 struct { 136 uint8_t index:4; 137 uint8_t port:4; 138 uint8_t type:4; 139 uint8_t vendor_specific:4; 140 uint8_t bios_detect:1; 141 uint8_t non_vga:1; 142 uint8_t head_id:3; 143 uint16_t reserved:10; 144 uint8_t device_id_scheme:1; 145 } __packed fmt; 146} acpidisp_od_attrs_t; 147 148/* Common legacy output device IDs (ACPI 2.0c, Table B-3). */ 149#define ACPI_DISP_OUT_LEGACY_DEVID_MONITOR 0x0100 150#define ACPI_DISP_OUT_LEGACY_DEVID_PANEL 0x0110 151#define ACPI_DISP_OUT_LEGACY_DEVID_TV 0x0200 152 153/* Output device display types (ACPI 4.0a, Table B-2). */ 154#define ACPI_DISP_OUT_ATTR_TYPE_OTHER 0x0 155#define ACPI_DISP_OUT_ATTR_TYPE_VGA 0x1 156#define ACPI_DISP_OUT_ATTR_TYPE_TV 0x2 157#define ACPI_DISP_OUT_ATTR_TYPE_EXTDIG 0x3 158#define ACPI_DISP_OUT_ATTR_TYPE_INTDFP 0x4 159 160/* Format of output device status (ACPI 4.0a, Table B-4). */ 161typedef union acpidisp_od_status_t { 162 uint32_t raw; 163 struct { 164 uint8_t exists:1; 165 uint8_t activated:1; 166 uint8_t ready:1; 167 uint8_t not_defective:1; 168 uint8_t attached:1; 169 uint32_t reserved:27; 170 } __packed fmt; 171} acpidisp_od_status_t; 172 173/* Format of output device state (ACPI 4.0a, Table B-6). */ 174typedef union acpidisp_od_state_t { 175 uint32_t raw; 176 struct { 177 uint8_t active:1; 178 uint32_t reserved:29; 179 uint8_t no_switch:1; 180 uint8_t commit:1; 181 } __packed fmt; 182} acpidisp_od_state_t; 183 184/* 185 * acpidisp_outdev: 186 * 187 * Description of an ACPI display output device. This structure groups 188 * together: 189 * - the output device attributes, given in the display adapter's _DOD 190 * method (ACPI 4.0a, Sec. B.4.2). 191 * - the corresponding instance of the acpiout driver (if any). 192 */ 193struct acpidisp_outdev { 194 acpidisp_od_attrs_t od_attrs; /* Attributes */ 195 device_t od_device; /* Matching base device */ 196}; 197 198/* 199 * acpidisp_odinfo: 200 * 201 * Information on connected output devices (ACPI 4.0a, Sec. B.4.2). This 202 * structure enumerates all devices (_DOD package) connected to a display 203 * adapter. Currently, this information is only used for display output 204 * switching via hotkey. 205 * 206 * Invariants (after initialization): 207 * 208 * (oi_dev != NULL) && (oi_dev_count > 0) 209 */ 210struct acpidisp_odinfo { 211 struct acpidisp_outdev *oi_dev; /* Array of output devices */ 212 uint32_t oi_dev_count; /* Number of output devices */ 213}; 214 215/* 216 * acpidisp_vga_softc: 217 * 218 * Software state of an ACPI display adapter. 219 * 220 * Invariants (after attachment): 221 * 222 * ((sc_caps & ACPI_DISP_VGA_CAP__DOD) == 0) => (sc_odinfo == NULL) 223 */ 224struct acpidisp_vga_softc { 225 device_t sc_dev; /* Base device info */ 226 struct acpi_devnode *sc_node; /* ACPI device node */ 227 struct sysctllog *sc_log; /* Sysctl log */ 228 kmutex_t sc_mtx; /* Mutex (shared w/ outputs) */ 229 uint16_t sc_caps; /* Capabilities (methods) */ 230 acpidisp_bios_policy_t sc_policy; /* BIOS switch policy (_DOS) */ 231 struct acpidisp_odinfo *sc_odinfo; /* Connected output devices */ 232}; 233 234/* 235 * ACPI display adapter capabilities (methods). 236 */ 237#define ACPI_DISP_VGA_CAP__DOS __BIT(0) 238#define ACPI_DISP_VGA_CAP__DOD __BIT(1) 239#define ACPI_DISP_VGA_CAP__ROM __BIT(2) 240#define ACPI_DISP_VGA_CAP__GPD __BIT(3) 241#define ACPI_DISP_VGA_CAP__SPD __BIT(4) 242#define ACPI_DISP_VGA_CAP__VPO __BIT(5) 243 244/* 245 * acpidisp_acpivga_attach_args: 246 * 247 * Attachment structure for the acpivga interface. Used to attach display 248 * output devices under a display adapter. 249 */ 250struct acpidisp_acpivga_attach_args { 251 struct acpi_devnode *aa_node; /* ACPI device node */ 252 kmutex_t *aa_mtx; /* Shared mutex */ 253}; 254 255/* 256 * acpidisp_brctl: 257 * 258 * Brightness control (ACPI 4.0a, Sec. B.6.2 to B.6.4). This structure 259 * contains the supported brightness levels (_BCL package) and the current 260 * level. Following Windows 7 brightness control, we ignore the fullpower 261 * and battery levels (as it simplifies the code). 262 * 263 * The array bc_level is sorted in strictly ascending order. 264 * 265 * Invariants (after initialization): 266 * 267 * (bc_level != NULL) && (bc_level_count > 0) 268 */ 269struct acpidisp_brctl { 270 uint8_t *bc_level; /* Array of levels */ 271 uint16_t bc_level_count; /* Number of levels */ 272 uint8_t bc_current; /* Current level */ 273 274 /* 275 * Quirk if firmware returns wrong values for _BQC 276 * (acpidisp_get_brightness) 277 */ 278 bool bc_bqc_broken; 279}; 280 281/* 282 * Minimum brightness increment/decrement in response to increase/decrease 283 * brightness hotkey notifications. Must be strictly positive. 284 */ 285#define ACPI_DISP_BRCTL_STEP 5 286 287/* 288 * acpidisp_out_softc: 289 * 290 * Software state of an ACPI display output device. 291 * 292 * Invariants (after attachment): 293 * 294 * ((sc_caps & ACPI_DISP_OUT_CAP__BCL) == 0) => (sc_brctl == NULL) 295 * ((sc_caps & ACPI_DISP_OUT_CAP__BCM) == 0) => (sc_brctl == NULL) 296 */ 297struct acpidisp_out_softc { 298 device_t sc_dev; /* Base device info */ 299 struct acpi_devnode *sc_node; /* ACPI device node */ 300 struct sysctllog *sc_log; /* Sysctl log */ 301 kmutex_t *sc_mtx; /* Mutex (shared w/ adapter) */ 302 uint16_t sc_caps; /* Capabilities (methods) */ 303 struct acpidisp_brctl *sc_brctl; /* Brightness control */ 304}; 305 306/* 307 * ACPI display output device capabilities (methods). 308 */ 309#define ACPI_DISP_OUT_CAP__BCL __BIT(0) 310#define ACPI_DISP_OUT_CAP__BCM __BIT(1) 311#define ACPI_DISP_OUT_CAP__BQC __BIT(2) 312#define ACPI_DISP_OUT_CAP__DDC __BIT(3) 313#define ACPI_DISP_OUT_CAP__DCS __BIT(4) 314#define ACPI_DISP_OUT_CAP__DGS __BIT(5) 315#define ACPI_DISP_OUT_CAP__DSS __BIT(6) 316 317static int acpidisp_vga_match(device_t, cfdata_t, void *); 318static void acpidisp_vga_attach(device_t, device_t, void *); 319static int acpidisp_vga_detach(device_t, int); 320static void acpidisp_vga_childdetached(device_t, device_t); 321 322static void acpidisp_vga_scan_outdevs(struct acpidisp_vga_softc *); 323static int acpidisp_acpivga_print(void *, const char *); 324 325static int acpidisp_out_match(device_t, cfdata_t, void *); 326static void acpidisp_out_attach(device_t, device_t, void *); 327static int acpidisp_out_detach(device_t, int); 328 329CFATTACH_DECL2_NEW(acpivga, sizeof(struct acpidisp_vga_softc), 330 acpidisp_vga_match, acpidisp_vga_attach, acpidisp_vga_detach, NULL, 331 NULL, acpidisp_vga_childdetached); 332 333CFATTACH_DECL_NEW(acpiout, sizeof(struct acpidisp_out_softc), 334 acpidisp_out_match, acpidisp_out_attach, acpidisp_out_detach, NULL); 335 336static bool acpidisp_vga_resume(device_t, const pmf_qual_t *); 337static bool acpidisp_out_suspend(device_t, const pmf_qual_t *); 338static bool acpidisp_out_resume(device_t, const pmf_qual_t *); 339 340static uint16_t acpidisp_vga_capabilities(const struct acpi_devnode *); 341static uint16_t acpidisp_out_capabilities(const struct acpi_devnode *); 342static void acpidisp_vga_print_capabilities(device_t, uint16_t); 343static void acpidisp_out_print_capabilities(device_t, uint16_t); 344 345static void acpidisp_vga_notify_handler(ACPI_HANDLE, uint32_t, void *); 346static void acpidisp_out_notify_handler(ACPI_HANDLE, uint32_t, void *); 347 348static void acpidisp_vga_cycle_output_device_callback(void *); 349static void acpidisp_vga_output_device_change_callback(void *); 350static void acpidisp_out_increase_brightness_callback(void *); 351static void acpidisp_out_decrease_brightness_callback(void *); 352static void acpidisp_out_cycle_brightness_callback(void *); 353static void acpidisp_out_zero_brightness_callback(void *); 354 355static void acpidisp_vga_sysctl_setup(struct acpidisp_vga_softc *); 356static void acpidisp_out_sysctl_setup(struct acpidisp_out_softc *); 357#ifdef ACPI_DEBUG 358static int acpidisp_vga_sysctl_policy(SYSCTLFN_PROTO); 359#endif 360static int acpidisp_vga_sysctl_policy_output(SYSCTLFN_PROTO); 361#ifdef ACPI_DISP_SWITCH_SYSCTLS 362static int acpidisp_out_sysctl_status(SYSCTLFN_PROTO); 363static int acpidisp_out_sysctl_state(SYSCTLFN_PROTO); 364#endif 365static int acpidisp_out_sysctl_brightness(SYSCTLFN_PROTO); 366 367static struct acpidisp_odinfo * 368 acpidisp_init_odinfo(const struct acpidisp_vga_softc *); 369static void acpidisp_vga_bind_outdevs(struct acpidisp_vga_softc *); 370static struct acpidisp_brctl * 371 acpidisp_init_brctl(const struct acpidisp_out_softc *); 372 373static int acpidisp_set_policy(const struct acpidisp_vga_softc *, 374 uint8_t); 375static int acpidisp_get_status(const struct acpidisp_out_softc *, 376 uint32_t *); 377static int acpidisp_get_state(const struct acpidisp_out_softc *, 378 uint32_t *); 379static int acpidisp_set_state(const struct acpidisp_out_softc *, 380 uint32_t); 381static int acpidisp_get_brightness(const struct acpidisp_out_softc *, 382 uint8_t *); 383static int acpidisp_set_brightness(const struct acpidisp_out_softc *, 384 uint8_t); 385static int acpidisp_quirk_get_brightness(const struct acpidisp_out_softc *); 386 387static void acpidisp_print_odinfo(device_t, const struct acpidisp_odinfo *); 388static void acpidisp_print_brctl(device_t, const struct acpidisp_brctl *); 389static void acpidisp_print_od_attrs(acpidisp_od_attrs_t); 390 391static bool acpidisp_has_method(ACPI_HANDLE, const char *, 392 ACPI_OBJECT_TYPE); 393static ACPI_STATUS 394 acpidisp_eval_package(ACPI_HANDLE, const char *, ACPI_OBJECT **, 395 unsigned int); 396static void acpidisp_array_search(const uint8_t *, uint16_t, int, uint8_t *, 397 uint8_t *); 398 399/* 400 * Display notification callbacks -- used by i915 401 */ 402 403struct acpidisp_notifier { 404 void (*adn_func)(ACPI_HANDLE, uint32_t, void *); 405 void *adn_cookie; 406 struct pslist_entry adn_entry; 407}; 408 409static struct { 410 kmutex_t lock; 411 struct pslist_head list; 412} acpidisp_notifiers; 413 414struct acpidisp_notifier * 415acpidisp_register_notify(void (*func)(ACPI_HANDLE, uint32_t, void *), 416 void *cookie) 417{ 418 struct acpidisp_notifier *adn; 419 420 adn = kmem_zalloc(sizeof(*adn), KM_SLEEP); 421 adn->adn_func = func; 422 adn->adn_cookie = cookie; 423 PSLIST_ENTRY_INIT(adn, adn_entry); 424 425 mutex_enter(&acpidisp_notifiers.lock); 426 PSLIST_WRITER_INSERT_HEAD(&acpidisp_notifiers.list, adn, adn_entry); 427 mutex_exit(&acpidisp_notifiers.lock); 428 429 return adn; 430} 431 432void 433acpidisp_deregister_notify(struct acpidisp_notifier *adn) 434{ 435 436 mutex_enter(&acpidisp_notifiers.lock); 437 PSLIST_WRITER_REMOVE(adn, adn_entry); 438 mutex_exit(&acpidisp_notifiers.lock); 439 440 xc_barrier(0); 441 kmem_free(adn, sizeof(*adn)); 442} 443 444static void 445acpidisp_notify(ACPI_HANDLE handle, uint32_t notify) 446{ 447 struct acpidisp_notifier *adn; 448 int s; 449 450 s = pserialize_read_enter(); 451 PSLIST_READER_FOREACH(adn, &acpidisp_notifiers.list, 452 struct acpidisp_notifier, adn_entry) { 453 (*adn->adn_func)(handle, notify, adn->adn_cookie); 454 } 455 pserialize_read_exit(s); 456} 457 458/* 459 * Autoconfiguration for the acpivga driver. 460 */ 461 462static int 463acpidisp_vga_match(device_t parent, cfdata_t match, void *aux) 464{ 465 struct acpi_attach_args *aa = aux; 466 struct acpi_devnode *ad = aa->aa_node; 467 struct acpi_pci_info *ap; 468 pcireg_t id, class; 469 pcitag_t tag; 470 471 if (ad->ad_type != ACPI_TYPE_DEVICE) 472 return 0; 473 474 ap = ad->ad_pciinfo; 475 476 if (ap == NULL) 477 return 0; 478 479 if ((ap->ap_flags & ACPI_PCI_INFO_DEVICE) == 0) 480 return 0; 481 482 if (ap->ap_function == 0xffff) 483 return 0; 484 485 KASSERT(ap->ap_bus < 256); 486 KASSERT(ap->ap_device < 32); 487 KASSERT(ap->ap_function < 8); 488 489 /* 490 * Check that the PCI device is present, verify 491 * the class of the PCI device, and finally see 492 * if the ACPI device is capable of something. 493 */ 494 tag = pci_make_tag(aa->aa_pc, ap->ap_bus, 495 ap->ap_device, ap->ap_function); 496 497 id = pci_conf_read(aa->aa_pc, tag, PCI_ID_REG); 498 499 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || PCI_VENDOR(id) == 0) 500 return 0; 501 502 class = pci_conf_read(aa->aa_pc, tag, PCI_CLASS_REG); 503 504 if (PCI_CLASS(class) != PCI_CLASS_DISPLAY) 505 return 0; 506 507 if (acpidisp_vga_capabilities(ad) == 0) 508 return 0; 509 510 return 1; 511} 512 513static void 514acpidisp_vga_attach(device_t parent, device_t self, void *aux) 515{ 516 struct acpidisp_vga_softc *asc = device_private(self); 517 struct acpi_attach_args *aa = aux; 518 struct acpi_devnode *ad = aa->aa_node; 519 520 aprint_naive(": ACPI Display Adapter\n"); 521 aprint_normal(": ACPI Display Adapter\n"); 522 523 asc->sc_node = ad; 524 asc->sc_dev = self; 525 asc->sc_log = NULL; 526 527 mutex_init(&asc->sc_mtx, MUTEX_DEFAULT, IPL_NONE); 528 529 asc->sc_caps = acpidisp_vga_capabilities(ad); 530 asc->sc_policy = acpidisp_default_bios_policy; 531 asc->sc_odinfo = NULL; 532 533 acpidisp_vga_print_capabilities(self, asc->sc_caps); 534 535 /* 536 * Enumerate connected output devices, attach 537 * output display devices, and bind the attached 538 * output devices to the enumerated ones. 539 */ 540 asc->sc_odinfo = acpidisp_init_odinfo(asc); 541 542 acpidisp_vga_scan_outdevs(asc); 543 544 if (asc->sc_odinfo != NULL) { 545 acpidisp_vga_bind_outdevs(asc); 546 acpidisp_print_odinfo(self, asc->sc_odinfo); 547 } 548 549 /* 550 * Set BIOS automatic switch policy. 551 * 552 * Many laptops do not support output device switching with 553 * the methods specified in the ACPI extensions for display 554 * adapters. Therefore, we leave the BIOS output switch policy 555 * on "auto" instead of setting it to "normal". 556 */ 557 asc->sc_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_AUTO; 558 asc->sc_policy.fmt.brightness = ACPI_DISP_POLICY_BRIGHTNESS_NORMAL; 559 560 if (acpidisp_set_policy(asc, asc->sc_policy.raw)) 561 asc->sc_policy = acpidisp_default_bios_policy; 562 563 acpidisp_vga_sysctl_setup(asc); 564 565 (void)pmf_device_register(self, NULL, acpidisp_vga_resume); 566 (void)acpi_register_notify(asc->sc_node, acpidisp_vga_notify_handler); 567} 568 569static int 570acpidisp_vga_detach(device_t self, int flags) 571{ 572 struct acpidisp_vga_softc *asc = device_private(self); 573 struct acpidisp_odinfo *oi = asc->sc_odinfo; 574 int rc; 575 576 pmf_device_deregister(self); 577 578 if (asc->sc_log != NULL) 579 sysctl_teardown(&asc->sc_log); 580 581 asc->sc_policy = acpidisp_default_bios_policy; 582 acpidisp_set_policy(asc, asc->sc_policy.raw); 583 584 acpi_deregister_notify(asc->sc_node); 585 586 if ((rc = config_detach_children(self, flags)) != 0) 587 return rc; 588 589 if (oi != NULL) { 590 kmem_free(oi->oi_dev, 591 oi->oi_dev_count * sizeof(*oi->oi_dev)); 592 kmem_free(oi, sizeof(*oi)); 593 } 594 595 mutex_destroy(&asc->sc_mtx); 596 597 return 0; 598} 599 600void 601acpidisp_vga_childdetached(device_t self, device_t child) 602{ 603 struct acpidisp_vga_softc *asc = device_private(self); 604 struct acpidisp_odinfo *oi = asc->sc_odinfo; 605 struct acpidisp_outdev *od; 606 struct acpi_devnode *ad; 607 uint32_t i; 608 609 SIMPLEQ_FOREACH(ad, &asc->sc_node->ad_child_head, ad_child_list) { 610 611 if (ad->ad_device == child) 612 ad->ad_device = NULL; 613 } 614 615 if (oi == NULL) 616 return; 617 618 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 619 if (od->od_device == child) 620 od->od_device = NULL; 621 } 622} 623 624/* 625 * Attachment of acpiout under acpivga. 626 */ 627 628static void 629acpidisp_vga_scan_outdevs(struct acpidisp_vga_softc *asc) 630{ 631 struct acpidisp_acpivga_attach_args aa; 632 struct acpi_devnode *ad; 633 634 /* 635 * Display output devices are ACPI children of the display adapter. 636 */ 637 SIMPLEQ_FOREACH(ad, &asc->sc_node->ad_child_head, ad_child_list) { 638 639 if (ad->ad_device != NULL) /* This should not happen. */ 640 continue; 641 642 aa.aa_node = ad; 643 aa.aa_mtx = &asc->sc_mtx; 644 645 ad->ad_device = config_found(asc->sc_dev, 646 &aa, acpidisp_acpivga_print, CFARGS_NONE); 647 } 648} 649 650static int 651acpidisp_acpivga_print(void *aux, const char *pnp) 652{ 653 struct acpidisp_acpivga_attach_args *aa = aux; 654 struct acpi_devnode *ad = aa->aa_node; 655 656 if (pnp) { 657 aprint_normal("%s at %s", ad->ad_name, pnp); 658 } else { 659 aprint_normal(" (%s", ad->ad_name); 660 if (ad->ad_devinfo->Valid & ACPI_VALID_ADR) 661 aprint_normal(", 0x%04"PRIx64, ad->ad_devinfo->Address); 662 aprint_normal(")"); 663 } 664 665 return UNCONF; 666} 667 668/* 669 * Autoconfiguration for the acpiout driver. 670 */ 671 672static int 673acpidisp_out_match(device_t parent, cfdata_t match, void *aux) 674{ 675 struct acpidisp_acpivga_attach_args *aa = aux; 676 struct acpi_devnode *ad = aa->aa_node; 677 678 if (ad->ad_type != ACPI_TYPE_DEVICE) 679 return 0; 680 681 /* 682 * The method _ADR is required for display output 683 * devices (ACPI 4.0a, Sec. B.6.1). 684 */ 685 if (!(acpidisp_has_method(ad->ad_handle, "_ADR", ACPI_TYPE_INTEGER))) 686 return 0; 687 688 return 1; 689} 690 691static void 692acpidisp_out_attach(device_t parent, device_t self, void *aux) 693{ 694 struct acpidisp_out_softc *osc = device_private(self); 695 struct acpidisp_acpivga_attach_args *aa = aux; 696 struct acpi_devnode *ad = aa->aa_node; 697 struct acpidisp_brctl *bc; 698 699 aprint_naive("\n"); 700 aprint_normal(": ACPI Display Output Device\n"); 701 702 osc->sc_dev = self; 703 osc->sc_node = ad; 704 osc->sc_log = NULL; 705 osc->sc_mtx = aa->aa_mtx; 706 osc->sc_caps = acpidisp_out_capabilities(ad); 707 osc->sc_brctl = NULL; 708 709 acpidisp_out_print_capabilities(self, osc->sc_caps); 710 711 osc->sc_brctl = acpidisp_init_brctl(osc); 712 bc = osc->sc_brctl; 713 if (bc != NULL) { 714 bc->bc_current = bc->bc_level[bc->bc_level_count - 1]; 715 716 /* 717 * Synchronize ACPI and driver brightness levels, and 718 * check that brightness control is working. 719 */ 720 if (acpidisp_get_brightness(osc, &bc->bc_current) && 721 acpidisp_set_brightness(osc, bc->bc_current)) { 722 kmem_free(bc->bc_level, 723 bc->bc_level_count * sizeof(*bc->bc_level)); 724 kmem_free(bc, sizeof(*bc)); 725 osc->sc_brctl = NULL; 726 } else { 727 if (acpidisp_quirk_get_brightness(osc)) { 728 aprint_error_dev(self, 729 "failed to test _BQC quirk\n"); 730 } 731 acpidisp_print_brctl(self, osc->sc_brctl); 732 } 733 } 734 735 /* Install ACPI notify handler. */ 736 (void)acpi_register_notify(osc->sc_node, acpidisp_out_notify_handler); 737 738 /* Setup sysctl. */ 739 acpidisp_out_sysctl_setup(osc); 740 741 /* Power management. */ 742 if (!pmf_device_register(self, acpidisp_out_suspend, 743 acpidisp_out_resume)) 744 aprint_error_dev(self, "couldn't establish power handler\n"); 745} 746 747static int 748acpidisp_out_detach(device_t self, int flags) 749{ 750 struct acpidisp_out_softc *osc = device_private(self); 751 struct acpidisp_brctl *bc = osc->sc_brctl; 752 753 pmf_device_deregister(self); 754 755 if (osc->sc_log != NULL) 756 sysctl_teardown(&osc->sc_log); 757 758 acpi_deregister_notify(osc->sc_node); 759 760 if (bc != NULL) { 761 kmem_free(bc->bc_level, 762 bc->bc_level_count * sizeof(*bc->bc_level)); 763 kmem_free(bc, sizeof(*bc)); 764 } 765 766 return 0; 767} 768 769/* 770 * Power management. 771 */ 772 773static bool 774acpidisp_vga_resume(device_t self, const pmf_qual_t *qual) 775{ 776 struct acpidisp_vga_softc *asc = device_private(self); 777 778 mutex_enter(&asc->sc_mtx); 779 (void)acpidisp_set_policy(asc, asc->sc_policy.raw); 780 mutex_exit(&asc->sc_mtx); 781 782 return true; 783} 784 785static bool 786acpidisp_out_suspend(device_t self, const pmf_qual_t *qual) 787{ 788 struct acpidisp_out_softc *osc = device_private(self); 789 790 mutex_enter(osc->sc_mtx); 791 if (osc->sc_brctl != NULL) 792 (void)acpidisp_get_brightness(osc, &osc->sc_brctl->bc_current); 793 mutex_exit(osc->sc_mtx); 794 795 return true; 796} 797 798static bool 799acpidisp_out_resume(device_t self, const pmf_qual_t *qual) 800{ 801 struct acpidisp_out_softc *osc = device_private(self); 802 803 mutex_enter(osc->sc_mtx); 804 if (osc->sc_brctl != NULL) 805 (void)acpidisp_set_brightness(osc, osc->sc_brctl->bc_current); 806 mutex_exit(osc->sc_mtx); 807 808 return true; 809} 810 811/* 812 * Capabilities (available methods). 813 */ 814 815static uint16_t 816acpidisp_vga_capabilities(const struct acpi_devnode *ad) 817{ 818 uint16_t cap; 819 820 cap = 0; 821 822 if (acpidisp_has_method(ad->ad_handle, "_DOS", ACPI_TYPE_METHOD)) 823 cap |= ACPI_DISP_VGA_CAP__DOS; 824 825 if (acpidisp_has_method(ad->ad_handle, "_DOD", ACPI_TYPE_PACKAGE)) 826 cap |= ACPI_DISP_VGA_CAP__DOD; 827 828 if (acpidisp_has_method(ad->ad_handle, "_ROM", ACPI_TYPE_BUFFER)) 829 cap |= ACPI_DISP_VGA_CAP__ROM; 830 831 if (acpidisp_has_method(ad->ad_handle, "_GPD", ACPI_TYPE_INTEGER)) 832 cap |= ACPI_DISP_VGA_CAP__GPD; 833 834 if (acpidisp_has_method(ad->ad_handle, "_SPD", ACPI_TYPE_METHOD)) 835 cap |= ACPI_DISP_VGA_CAP__SPD; 836 837 if (acpidisp_has_method(ad->ad_handle, "_VPO", ACPI_TYPE_INTEGER)) 838 cap |= ACPI_DISP_VGA_CAP__VPO; 839 840 return cap; 841} 842 843static void 844acpidisp_vga_print_capabilities(device_t self, uint16_t cap) 845{ 846 aprint_debug_dev(self, "capabilities:%s%s%s%s%s%s\n", 847 (cap & ACPI_DISP_VGA_CAP__DOS) ? " _DOS" : "", 848 (cap & ACPI_DISP_VGA_CAP__DOD) ? " _DOD" : "", 849 (cap & ACPI_DISP_VGA_CAP__ROM) ? " _ROM" : "", 850 (cap & ACPI_DISP_VGA_CAP__GPD) ? " _GPD" : "", 851 (cap & ACPI_DISP_VGA_CAP__SPD) ? " _SPD" : "", 852 (cap & ACPI_DISP_VGA_CAP__VPO) ? " _VPO" : ""); 853} 854 855static uint16_t 856acpidisp_out_capabilities(const struct acpi_devnode *ad) 857{ 858 uint16_t cap; 859 860 cap = 0; 861 862 /* List of Brightness levels */ 863 if (acpidisp_has_method(ad->ad_handle, "_BCL", ACPI_TYPE_PACKAGE)) 864 cap |= ACPI_DISP_OUT_CAP__BCL; 865 866 /* Set brightness level */ 867 if (acpidisp_has_method(ad->ad_handle, "_BCM", ACPI_TYPE_METHOD)) 868 cap |= ACPI_DISP_OUT_CAP__BCM; 869 870 /* Get brightless level */ 871 if (acpidisp_has_method(ad->ad_handle, "_BQC", ACPI_TYPE_INTEGER)) 872 cap |= ACPI_DISP_OUT_CAP__BQC; 873 874 /* Return EDID */ 875 if (acpidisp_has_method(ad->ad_handle, "_DDC", ACPI_TYPE_METHOD)) 876 cap |= ACPI_DISP_OUT_CAP__DDC; 877 878 /* Get Status */ 879 if (acpidisp_has_method(ad->ad_handle, "_DCS", ACPI_TYPE_INTEGER)) 880 cap |= ACPI_DISP_OUT_CAP__DCS; 881 882 /* Get Graphics State */ 883 if (acpidisp_has_method(ad->ad_handle, "_DGS", ACPI_TYPE_INTEGER)) 884 cap |= ACPI_DISP_OUT_CAP__DGS; 885 886 /* Set Graphics State */ 887 if (acpidisp_has_method(ad->ad_handle, "_DSS", ACPI_TYPE_METHOD)) 888 cap |= ACPI_DISP_OUT_CAP__DSS; 889 890 return cap; 891} 892 893static void 894acpidisp_out_print_capabilities(device_t self, uint16_t cap) 895{ 896 aprint_debug_dev(self, "capabilities:%s%s%s%s%s%s%s\n", 897 (cap & ACPI_DISP_OUT_CAP__BCL) ? " _BCL" : "", 898 (cap & ACPI_DISP_OUT_CAP__BCM) ? " _BCM" : "", 899 (cap & ACPI_DISP_OUT_CAP__BQC) ? " _BQC" : "", 900 (cap & ACPI_DISP_OUT_CAP__DDC) ? " _DDC" : "", 901 (cap & ACPI_DISP_OUT_CAP__DCS) ? " _DCS" : "", 902 (cap & ACPI_DISP_OUT_CAP__DGS) ? " _DGS" : "", 903 (cap & ACPI_DISP_OUT_CAP__DSS) ? " _DSS" : ""); 904} 905 906/* 907 * ACPI notify handlers. 908 */ 909 910static void 911acpidisp_vga_notify_handler(ACPI_HANDLE handle, uint32_t notify, 912 void *context) 913{ 914 struct acpidisp_vga_softc *asc = device_private(context); 915 ACPI_OSD_EXEC_CALLBACK callback; 916 917 callback = NULL; 918 919 switch (notify) { 920 case ACPI_NOTIFY_CycleOutputDevice: 921 callback = acpidisp_vga_cycle_output_device_callback; 922 break; 923 case ACPI_NOTIFY_OutputDeviceStatusChange: 924 callback = acpidisp_vga_output_device_change_callback; 925 break; 926 case ACPI_NOTIFY_CycleDisplayOutputHotkeyPressed: 927 case ACPI_NOTIFY_NextDisplayOutputHotkeyPressed: 928 case ACPI_NOTIFY_PreviousDisplayOutputHotkeyPressed: 929 aprint_debug_dev(asc->sc_dev, 930 "unhandled notify: 0x%"PRIx32"\n", notify); 931 return; 932 default: 933 aprint_error_dev(asc->sc_dev, 934 "unknown notify: 0x%"PRIx32"\n", notify); 935 return; 936 } 937 938 KASSERT(callback != NULL); 939 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, callback, asc); 940 941 acpidisp_notify(handle, notify); 942} 943 944static void 945acpidisp_out_notify_handler(ACPI_HANDLE handle, uint32_t notify, 946 void *context) 947{ 948 struct acpidisp_out_softc *osc = device_private(context); 949 ACPI_OSD_EXEC_CALLBACK callback; 950 951 callback = NULL; 952 953 switch (notify) { 954 case ACPI_NOTIFY_IncreaseBrightness: 955 callback = acpidisp_out_increase_brightness_callback; 956 break; 957 case ACPI_NOTIFY_DecreaseBrightness: 958 callback = acpidisp_out_decrease_brightness_callback; 959 break; 960 case ACPI_NOTIFY_CycleBrightness: 961 callback = acpidisp_out_cycle_brightness_callback; 962 break; 963 case ACPI_NOTIFY_ZeroBrightness: 964 callback = acpidisp_out_zero_brightness_callback; 965 break; 966 case ACPI_NOTIFY_DisplayDeviceOff: 967 aprint_debug_dev(osc->sc_dev, 968 "unhandled notify: 0x%"PRIx32"\n", notify); 969 return; 970 default: 971 aprint_error_dev(osc->sc_dev, 972 "unknown notify: 0x%"PRIx32"\n", notify); 973 return; 974 } 975 976 KASSERT(callback != NULL); 977 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, callback, osc); 978} 979 980/* 981 * ACPI notify callbacks. 982 * 983 * Exclusive access to the sc_odinfo field of struct acpidisp_vga_softc is 984 * guaranteed since: 985 * 986 * (a) this field is only used in ACPI display notify callbacks, 987 * (b) ACPI display notify callbacks are scheduled with AcpiOsExecute, 988 * (c) callbacks scheduled with AcpiOsExecute are executed sequentially. 989 */ 990 991static void 992acpidisp_vga_cycle_output_device_callback(void *arg) 993{ 994 struct acpidisp_vga_softc *asc = arg; 995 struct acpidisp_odinfo *oi = asc->sc_odinfo; 996 struct acpidisp_outdev *od; 997 struct acpidisp_out_softc *osc, *last_osc; 998 acpidisp_od_state_t state, last_state; 999 acpidisp_od_status_t status; 1000 acpidisp_bios_policy_t lock_policy; 1001 uint32_t i; 1002 1003 if (oi == NULL) 1004 return; 1005 1006 /* Mutual exclusion with callbacks of connected output devices. */ 1007 mutex_enter(&asc->sc_mtx); 1008 1009 /* Lock the _DGS values. */ 1010 lock_policy = asc->sc_policy; 1011 lock_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_LOCKED; 1012 (void)acpidisp_set_policy(asc, lock_policy.raw); 1013 1014 last_osc = NULL; 1015 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 1016 if (od->od_device == NULL) 1017 continue; 1018 osc = device_private(od->od_device); 1019 1020 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DSS)) 1021 continue; 1022 if (acpidisp_get_state(osc, &state.raw)) 1023 continue; 1024 1025 if (acpidisp_get_status(osc, &status.raw)) { 1026 state.fmt.no_switch = 0; 1027 } else { 1028 state.fmt.active &= status.fmt.ready; 1029 1030 if (state.fmt.active == status.fmt.activated) 1031 state.fmt.no_switch = 1; 1032 else 1033 state.fmt.no_switch = 0; 1034 } 1035 1036 state.fmt.commit = 0; 1037 1038 if (last_osc != NULL) 1039 (void)acpidisp_set_state(last_osc, last_state.raw); 1040 1041 last_osc = osc; 1042 last_state = state; 1043 } 1044 1045 if (last_osc != NULL) { 1046 last_state.fmt.commit = 1; 1047 (void)acpidisp_set_state(last_osc, last_state.raw); 1048 } 1049 1050 /* Restore the original BIOS policy. */ 1051 (void)acpidisp_set_policy(asc, asc->sc_policy.raw); 1052 1053 mutex_exit(&asc->sc_mtx); 1054} 1055 1056static void 1057acpidisp_vga_output_device_change_callback(void *arg) 1058{ 1059 struct acpidisp_vga_softc *asc = arg; 1060 struct acpidisp_odinfo *oi = asc->sc_odinfo; 1061 bool switch_outputs; 1062 1063 if (oi != NULL) { 1064 kmem_free(oi->oi_dev, 1065 oi->oi_dev_count * sizeof(*oi->oi_dev)); 1066 kmem_free(oi, sizeof(*oi)); 1067 } 1068 1069 asc->sc_odinfo = acpidisp_init_odinfo(asc); 1070 if (asc->sc_odinfo != NULL) { 1071 acpidisp_vga_bind_outdevs(asc); 1072 acpidisp_print_odinfo(asc->sc_dev, asc->sc_odinfo); 1073 } 1074 1075 /* Perform display output switch if needed. */ 1076 mutex_enter(&asc->sc_mtx); 1077 switch_outputs = 1078 (asc->sc_policy.fmt.output == ACPI_DISP_POLICY_OUTPUT_NORMAL); 1079 mutex_exit(&asc->sc_mtx); 1080 if (switch_outputs) 1081 acpidisp_vga_cycle_output_device_callback(arg); 1082} 1083 1084static void 1085acpidisp_out_increase_brightness_callback(void *arg) 1086{ 1087 struct acpidisp_out_softc *osc = arg; 1088 struct acpidisp_brctl *bc = osc->sc_brctl; 1089 uint8_t max, lo, up; 1090 int cur; 1091 1092 if (bc == NULL) { 1093 /* Fallback to pmf(9). */ 1094 pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP); 1095 return; 1096 } 1097 1098 mutex_enter(osc->sc_mtx); 1099 max = bc->bc_level[bc->bc_level_count - 1]; 1100 if (acpidisp_get_brightness(osc, &bc->bc_current)) 1101 goto out; 1102 for (cur = bc->bc_current; (cur += ACPI_DISP_BRCTL_STEP) <= max;) { 1103 acpidisp_array_search(bc->bc_level, bc->bc_level_count, cur, 1104 &lo, &up); 1105 bc->bc_current = up; 1106 if (acpidisp_set_brightness(osc, bc->bc_current)) 1107 goto out; 1108 if (acpidisp_get_brightness(osc, &bc->bc_current)) 1109 goto out; 1110 if (bc->bc_current >= cur) 1111 break; 1112 } 1113out: mutex_exit(osc->sc_mtx); 1114} 1115 1116static void 1117acpidisp_out_decrease_brightness_callback(void *arg) 1118{ 1119 struct acpidisp_out_softc *osc = arg; 1120 struct acpidisp_brctl *bc = osc->sc_brctl; 1121 uint8_t min, lo, up; 1122 int cur; 1123 1124 if (bc == NULL) { 1125 /* Fallback to pmf(9). */ 1126 pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN); 1127 return; 1128 } 1129 1130 mutex_enter(osc->sc_mtx); 1131 min = bc->bc_level[0]; 1132 if (acpidisp_get_brightness(osc, &bc->bc_current)) 1133 goto out; 1134 for (cur = bc->bc_current; (cur -= ACPI_DISP_BRCTL_STEP) >= min;) { 1135 acpidisp_array_search(bc->bc_level, bc->bc_level_count, cur, 1136 &lo, &up); 1137 bc->bc_current = lo; 1138 if (acpidisp_set_brightness(osc, bc->bc_current)) 1139 goto out; 1140 if (acpidisp_get_brightness(osc, &bc->bc_current)) 1141 goto out; 1142 if (bc->bc_current <= cur) 1143 break; 1144 } 1145out: mutex_exit(osc->sc_mtx); 1146} 1147 1148static void 1149acpidisp_out_cycle_brightness_callback(void *arg) 1150{ 1151 struct acpidisp_out_softc *osc = arg; 1152 struct acpidisp_brctl *bc = osc->sc_brctl; 1153 uint8_t lo, up; 1154 1155 if (bc == NULL) { 1156 /* No fallback. */ 1157 return; 1158 } 1159 1160 mutex_enter(osc->sc_mtx); 1161 1162 (void)acpidisp_get_brightness(osc, &bc->bc_current); 1163 1164 if (bc->bc_current >= bc->bc_level[bc->bc_level_count - 1]) { 1165 bc->bc_current = bc->bc_level[0]; 1166 } else { 1167 acpidisp_array_search(bc->bc_level, bc->bc_level_count, 1168 bc->bc_current + 1, &lo, &up); 1169 bc->bc_current = up; 1170 } 1171 1172 (void)acpidisp_set_brightness(osc, bc->bc_current); 1173 1174 mutex_exit(osc->sc_mtx); 1175} 1176 1177static void 1178acpidisp_out_zero_brightness_callback(void *arg) 1179{ 1180 struct acpidisp_out_softc *osc = arg; 1181 struct acpidisp_brctl *bc = osc->sc_brctl; 1182 1183 if (bc == NULL) { 1184 /* Fallback to pmf(9). */ 1185 /* XXX Is this the intended meaning of PMFE_DISPLAY_REDUCED? */ 1186 pmf_event_inject(NULL, PMFE_DISPLAY_REDUCED); 1187 return; 1188 } 1189 1190 mutex_enter(osc->sc_mtx); 1191 1192 bc->bc_current = bc->bc_level[0]; 1193 (void)acpidisp_set_brightness(osc, bc->bc_current); 1194 1195 mutex_exit(osc->sc_mtx); 1196} 1197 1198/* 1199 * Sysctl setup. 1200 */ 1201 1202static void 1203acpidisp_vga_sysctl_setup(struct acpidisp_vga_softc *asc) 1204{ 1205 const struct sysctlnode *rnode; 1206 1207 if (asc->sc_caps & ACPI_DISP_VGA_CAP__DOS) { 1208 if ((sysctl_createv(&asc->sc_log, 0, NULL, &rnode, 1209 0, CTLTYPE_NODE, "acpi", NULL, 1210 NULL, 0, NULL, 0, 1211 CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 1212 goto fail; 1213 1214 if ((sysctl_createv(&asc->sc_log, 0, &rnode, &rnode, 1215 0, CTLTYPE_NODE, device_xname(asc->sc_dev), 1216 SYSCTL_DESCR("ACPI display adapter controls"), 1217 NULL, 0, NULL, 0, 1218 CTL_CREATE, CTL_EOL)) != 0) 1219 goto fail; 1220 1221#ifdef ACPI_DEBUG 1222 (void)sysctl_createv(&asc->sc_log, 0, &rnode, NULL, 1223 CTLFLAG_READWRITE | CTLFLAG_HEX, CTLTYPE_INT, "bios_policy", 1224 SYSCTL_DESCR("Current BIOS switch policies (debug)"), 1225 acpidisp_vga_sysctl_policy, 0, (void *)asc, 0, 1226 CTL_CREATE, CTL_EOL); 1227#endif 1228 1229 (void)sysctl_createv(&asc->sc_log, 0, &rnode, NULL, 1230 CTLFLAG_READWRITE, CTLTYPE_BOOL, "bios_switch", 1231 SYSCTL_DESCR("Current BIOS output switching policy"), 1232 acpidisp_vga_sysctl_policy_output, 0, (void *)asc, 0, 1233 CTL_CREATE, CTL_EOL); 1234 } 1235 1236 return; 1237 1238 fail: 1239 aprint_error_dev(asc->sc_dev, "couldn't add sysctl nodes\n"); 1240} 1241 1242static void 1243acpidisp_out_sysctl_setup(struct acpidisp_out_softc *osc) 1244{ 1245 const struct sysctlnode *rnode; 1246 1247#ifdef ACPI_DISP_SWITCH_SYSCTLS 1248 if ((osc->sc_brctl != NULL) || 1249 (osc->sc_caps & ACPI_DISP_OUT_CAP__DCS) || 1250 (osc->sc_caps & ACPI_DISP_OUT_CAP__DGS)) { 1251#else 1252 if (osc->sc_brctl != NULL) { 1253#endif 1254 if ((sysctl_createv(&osc->sc_log, 0, NULL, &rnode, 1255 0, CTLTYPE_NODE, "acpi", NULL, 1256 NULL, 0, NULL, 0, 1257 CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 1258 goto fail; 1259 1260 if ((sysctl_createv(&osc->sc_log, 0, &rnode, &rnode, 1261 0, CTLTYPE_NODE, device_xname(osc->sc_dev), 1262 SYSCTL_DESCR("ACPI display output device controls"), 1263 NULL, 0, NULL, 0, 1264 CTL_CREATE, CTL_EOL)) != 0) 1265 goto fail; 1266 } 1267 1268 if (osc->sc_brctl != NULL) { 1269 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1270 CTLFLAG_READWRITE, CTLTYPE_INT, "brightness", 1271 SYSCTL_DESCR("Current brightness level"), 1272 acpidisp_out_sysctl_brightness, 0, (void *)osc, 0, 1273 CTL_CREATE, CTL_EOL); 1274 } 1275 1276#ifdef ACPI_DISP_SWITCH_SYSCTLS 1277 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DCS) { 1278 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1279 CTLFLAG_READONLY | CTLFLAG_HEX, CTLTYPE_INT, "status", 1280 SYSCTL_DESCR("Current status"), 1281 acpidisp_out_sysctl_status, 0, (void *)osc, 0, 1282 CTL_CREATE, CTL_EOL); 1283 } 1284 1285 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DGS) { 1286 int access; 1287 1288 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DSS) 1289 access = CTLFLAG_READWRITE; 1290 else 1291 access = CTLFLAG_READONLY; 1292 1293 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1294 access | CTLFLAG_HEX, CTLTYPE_INT, "state", 1295 SYSCTL_DESCR("Next state (active or inactive)"), 1296 acpidisp_out_sysctl_state, 0, (void *)osc, 0, 1297 CTL_CREATE, CTL_EOL); 1298 } 1299#endif 1300 1301 return; 1302 1303 fail: 1304 aprint_error_dev(osc->sc_dev, "couldn't add sysctl nodes\n"); 1305} 1306 1307/* 1308 * Sysctl callbacks. 1309 */ 1310 1311#ifdef ACPI_DEBUG 1312static int 1313acpidisp_vga_sysctl_policy(SYSCTLFN_ARGS) 1314{ 1315 struct sysctlnode node; 1316 struct acpidisp_vga_softc *asc; 1317 uint32_t val; 1318 int error; 1319 1320 node = *rnode; 1321 asc = node.sysctl_data; 1322 1323 mutex_enter(&asc->sc_mtx); 1324 val = (uint32_t)asc->sc_policy.raw; 1325 mutex_exit(&asc->sc_mtx); 1326 1327 node.sysctl_data = &val; 1328 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1329 if (error || newp == NULL) 1330 return error; 1331 1332 if (val > 0x7) 1333 return EINVAL; 1334 1335 mutex_enter(&asc->sc_mtx); 1336 asc->sc_policy.raw = (uint8_t)val; 1337 error = acpidisp_set_policy(asc, asc->sc_policy.raw); 1338 mutex_exit(&asc->sc_mtx); 1339 1340 return error; 1341} 1342#endif 1343 1344static int 1345acpidisp_vga_sysctl_policy_output(SYSCTLFN_ARGS) 1346{ 1347 struct sysctlnode node; 1348 struct acpidisp_vga_softc *asc; 1349 bool val; 1350 int error; 1351 1352 node = *rnode; 1353 asc = node.sysctl_data; 1354 1355 mutex_enter(&asc->sc_mtx); 1356 val = (asc->sc_policy.fmt.output == ACPI_DISP_POLICY_OUTPUT_AUTO); 1357 mutex_exit(&asc->sc_mtx); 1358 1359 node.sysctl_data = &val; 1360 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1361 if (error || newp == NULL) 1362 return error; 1363 1364 mutex_enter(&asc->sc_mtx); 1365 if (val) 1366 asc->sc_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_AUTO; 1367 else 1368 asc->sc_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_NORMAL; 1369 error = acpidisp_set_policy(asc, asc->sc_policy.raw); 1370 mutex_exit(&asc->sc_mtx); 1371 1372 return error; 1373} 1374 1375#ifdef ACPI_DISP_SWITCH_SYSCTLS 1376static int 1377acpidisp_out_sysctl_status(SYSCTLFN_ARGS) 1378{ 1379 struct sysctlnode node; 1380 struct acpidisp_out_softc *osc; 1381 uint32_t val; 1382 int error; 1383 1384 node = *rnode; 1385 osc = node.sysctl_data; 1386 1387 mutex_enter(osc->sc_mtx); 1388 error = acpidisp_get_status(osc, &val); 1389 mutex_exit(osc->sc_mtx); 1390 1391 if (error) 1392 return error; 1393 1394 node.sysctl_data = &val; 1395 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1396 if (error || newp == NULL) 1397 return error; 1398 1399 return 0; 1400} 1401 1402static int 1403acpidisp_out_sysctl_state(SYSCTLFN_ARGS) 1404{ 1405 struct sysctlnode node; 1406 struct acpidisp_out_softc *osc; 1407 uint32_t val; 1408 int error; 1409 1410 node = *rnode; 1411 osc = node.sysctl_data; 1412 1413 mutex_enter(osc->sc_mtx); 1414 error = acpidisp_get_state(osc, &val); 1415 mutex_exit(osc->sc_mtx); 1416 1417 if (error) 1418 return error; 1419 1420 node.sysctl_data = &val; 1421 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1422 if (error || newp == NULL) 1423 return error; 1424 1425 mutex_enter(osc->sc_mtx); 1426 error = acpidisp_set_state(osc, val); 1427 mutex_exit(osc->sc_mtx); 1428 1429 return error; 1430} 1431#endif 1432 1433static int 1434acpidisp_out_sysctl_brightness(SYSCTLFN_ARGS) 1435{ 1436 struct sysctlnode node; 1437 struct acpidisp_out_softc *osc; 1438 struct acpidisp_brctl *bc; 1439 int val, error; 1440 uint8_t lo, up, level; 1441 1442 node = *rnode; 1443 osc = node.sysctl_data; 1444 bc = osc->sc_brctl; 1445 1446 KASSERT(bc != NULL); 1447 1448 mutex_enter(osc->sc_mtx); 1449 (void)acpidisp_get_brightness(osc, &bc->bc_current); 1450 val = (int)bc->bc_current; 1451 mutex_exit(osc->sc_mtx); 1452 1453 node.sysctl_data = &val; 1454 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1455 if (error || newp == NULL) 1456 return error; 1457 1458 acpidisp_array_search(bc->bc_level, bc->bc_level_count, val, &lo, &up); 1459 if ((lo != up) && (val - lo) < (up - val)) 1460 level = lo; 1461 else 1462 level = up; 1463 1464 mutex_enter(osc->sc_mtx); 1465 bc->bc_current = level; 1466 error = acpidisp_set_brightness(osc, bc->bc_current); 1467 mutex_exit(osc->sc_mtx); 1468 1469 return error; 1470} 1471 1472/* 1473 * Initialization of acpidisp_odinfo (_DOD) and acpidisp_brctl (_BCL). 1474 */ 1475 1476/* 1477 * Regarding _DOD (ACPI 4.0a, Sec. B.4.2): 1478 * 1479 * "The _DOD method returns a list of devices attached to the graphics adapter, 1480 * along with device-specific configuration information." 1481 * 1482 * "Every child device enumerated in the ACPI namespace under the graphics 1483 * adapter must be specified in this list of devices. Each display device 1484 * must have its own ID, which is unique with respect to any other attachable 1485 * devices enumerated." 1486 * 1487 * "Return value: a package containing a variable-length list of integers, 1488 * each of which contains the 32-bit device attribute of a child device." 1489 */ 1490 1491static struct acpidisp_odinfo * 1492acpidisp_init_odinfo(const struct acpidisp_vga_softc *asc) 1493{ 1494 ACPI_HANDLE hdl = asc->sc_node->ad_handle; 1495 ACPI_STATUS rv; 1496 ACPI_OBJECT *pkg; 1497 struct acpidisp_odinfo *oi; 1498 struct acpidisp_outdev *devp; 1499 uint32_t count, i; 1500 1501 if (!(asc->sc_caps & ACPI_DISP_VGA_CAP__DOD)) 1502 return NULL; 1503 1504 oi = NULL; 1505 pkg = NULL; 1506 1507 rv = acpidisp_eval_package(hdl, "_DOD", &pkg, 1); 1508 if (ACPI_FAILURE(rv)) 1509 goto fail; 1510 1511 /* 1512 * Allocate and fill the struct acpidisp_odinfo to be returned. 1513 */ 1514 oi = kmem_zalloc(sizeof(*oi), KM_SLEEP); 1515 oi->oi_dev_count = pkg->Package.Count; 1516 oi->oi_dev = kmem_zalloc(oi->oi_dev_count * sizeof(*oi->oi_dev), 1517 KM_SLEEP); 1518 1519 /* 1520 * Fill the array oi->oi_dev. 1521 */ 1522 for (count = 0, i = 0; i < pkg->Package.Count; i++) { 1523 /* List of 32-bit integers (ACPI 4.0a, Sec. B.4.2). */ 1524 if (pkg->Package.Elements[i].Type != ACPI_TYPE_INTEGER || 1525 pkg->Package.Elements[i].Integer.Value > UINT32_MAX) 1526 continue; 1527 1528 oi->oi_dev[count].od_attrs.raw = 1529 (uint32_t)pkg->Package.Elements[i].Integer.Value; 1530 count++; 1531 } 1532 1533 if (count == 0) { 1534 rv = AE_BAD_DATA; 1535 goto fail; 1536 } 1537 1538 ACPI_FREE(pkg); 1539 pkg = NULL; 1540 1541 /* 1542 * Resize the array oi->oi_dev if needed. 1543 */ 1544 if (count < oi->oi_dev_count) { 1545 devp = kmem_alloc(count * sizeof(*devp), KM_SLEEP); 1546 (void)memcpy(devp, oi->oi_dev, count * sizeof(*devp)); 1547 kmem_free(oi->oi_dev, oi->oi_dev_count * sizeof(*oi->oi_dev)); 1548 oi->oi_dev = devp; 1549 oi->oi_dev_count = count; 1550 } 1551 1552 return oi; 1553 1554 fail: 1555 aprint_error_dev(asc->sc_dev, "failed to evaluate %s.%s: %s\n", 1556 acpi_name(hdl), "_DOD", AcpiFormatException(rv)); 1557 if (pkg != NULL) 1558 ACPI_FREE(pkg); 1559 if (oi != NULL) { 1560 if (oi->oi_dev != NULL) 1561 kmem_free(oi->oi_dev, 1562 oi->oi_dev_count * sizeof(*oi->oi_dev)); 1563 kmem_free(oi, sizeof(*oi)); 1564 } 1565 return NULL; 1566} 1567 1568/* 1569 * acpidisp_vga_bind_outdevs: 1570 * 1571 * Bind each acpiout device attached under an acpivga device to the 1572 * corresponding (_DOD enumerated) connected output device. 1573 */ 1574static void 1575acpidisp_vga_bind_outdevs(struct acpidisp_vga_softc *asc) 1576{ 1577 struct acpidisp_odinfo *oi = asc->sc_odinfo; 1578 struct acpidisp_out_softc *osc; 1579 struct acpidisp_outdev *od; 1580 struct acpi_devnode *ad; 1581 ACPI_HANDLE hdl; 1582 ACPI_INTEGER val; 1583 ACPI_STATUS rv; 1584 uint16_t devid; 1585 uint32_t i; 1586 1587 KASSERT(oi != NULL); 1588 1589 /* Reset all bindings. */ 1590 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) 1591 od->od_device = NULL; 1592 1593 /* 1594 * Iterate over all ACPI children that have been attached under this 1595 * acpivga device (as acpiout devices). 1596 */ 1597 SIMPLEQ_FOREACH(ad, &asc->sc_node->ad_child_head, ad_child_list) { 1598 if ((ad->ad_device == NULL) || 1599 (device_parent(ad->ad_device) != asc->sc_dev)) 1600 continue; 1601 1602 KASSERT(device_is_a(ad->ad_device, "acpiout")); 1603 1604 osc = device_private(ad->ad_device); 1605 1606 /* 1607 * For display output devices, the method _ADR returns 1608 * the device's ID (ACPI 4.0a, Sec. B.6.1). We do not 1609 * cache the result of _ADR since it may vary. 1610 */ 1611 hdl = osc->sc_node->ad_handle; 1612 rv = acpi_eval_integer(hdl, "_ADR", &val); 1613 if (ACPI_FAILURE(rv)) { 1614 aprint_error_dev(asc->sc_dev, 1615 "failed to evaluate %s.%s: %s\n", 1616 acpi_name(hdl), "_ADR", AcpiFormatException(rv)); 1617 continue; 1618 } 1619 1620 /* The device ID is a 16-bit integer (ACPI 4.0a, Table B-2). */ 1621 devid = (uint16_t)val; 1622 1623 /* 1624 * The device ID must be unique (among output devices), and must 1625 * appear in the list returned by _DOD (ACPI 4.0a, Sec. B.6.1). 1626 */ 1627 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 1628 if (devid == od->od_attrs.device_id) { 1629 if (od->od_device != NULL) 1630 aprint_error_dev(asc->sc_dev, 1631 "%s has same device ID as %s\n", 1632 device_xname(osc->sc_dev), 1633 device_xname(od->od_device)); 1634 else 1635 od->od_device = osc->sc_dev; 1636 break; 1637 } 1638 } 1639 if (i == oi->oi_dev_count) 1640 aprint_debug_dev(asc->sc_dev, 1641 "output device %s not connected\n", 1642 device_xname(osc->sc_dev)); 1643 } 1644} 1645 1646/* 1647 * Regarding _BCL (ACPI 4.0a, Sec. B.6.2): 1648 * 1649 * "This method allows the OS to query a list of brightness levels supported by 1650 * built-in display output devices." 1651 * 1652 * "Return value: a variable-length package containing a list of integers 1653 * representing the supported brightness levels. Each integer has 8 bits of 1654 * significant data." 1655 */ 1656 1657static struct acpidisp_brctl * 1658acpidisp_init_brctl(const struct acpidisp_out_softc *osc) 1659{ 1660 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1661 ACPI_STATUS rv; 1662 ACPI_OBJECT *pkg; 1663 struct acpidisp_brctl *bc; 1664 uint8_t *levelp; 1665 uint32_t i; 1666 int32_t j; 1667 uint16_t count, k; 1668 uint8_t level; 1669 1670 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BCL)) 1671 return NULL; 1672 1673 bc = NULL; 1674 pkg = NULL; 1675 1676 rv = acpidisp_eval_package(hdl, "_BCL", &pkg, 2); 1677 if (ACPI_FAILURE(rv)) 1678 goto fail; 1679 1680 /* 1681 * Allocate and fill the struct acpidisp_brctl to be returned. 1682 */ 1683 bc = kmem_zalloc(sizeof(*bc), KM_SLEEP); 1684 1685 /* At most 256 brightness levels (8-bit integers). */ 1686 if (pkg->Package.Count > 256) 1687 bc->bc_level_count = 256; 1688 else 1689 bc->bc_level_count = (uint16_t)pkg->Package.Count; 1690 1691 bc->bc_level = kmem_zalloc(bc->bc_level_count * sizeof(*bc->bc_level), 1692 KM_SLEEP); 1693 1694 /* 1695 * Fill the array bc->bc_level with an insertion sort. 1696 */ 1697 for (count = 0, i = 0; i < pkg->Package.Count; i++) { 1698 /* List of 8-bit integers (ACPI 4.0a, Sec. B.6.2). */ 1699 if (pkg->Package.Elements[i].Type != ACPI_TYPE_INTEGER || 1700 pkg->Package.Elements[i].Integer.Value > UINT8_MAX) 1701 continue; 1702 1703 level = (uint8_t)pkg->Package.Elements[i].Integer.Value; 1704 1705 /* Find the correct slot but do not modify the array yet. */ 1706 for (j = count; --j >= 0 && bc->bc_level[j] > level; ); 1707 if (j >= 0 && bc->bc_level[j] == level) 1708 continue; 1709 j++; 1710 1711 /* Make room for the new level. */ 1712 for (k = count; k > j; k--) 1713 bc->bc_level[k] = bc->bc_level[k-1]; 1714 1715 /* Insert the new level. */ 1716 bc->bc_level[j] = level; 1717 count++; 1718 } 1719 1720 if (count == 0) { 1721 rv = AE_BAD_DATA; 1722 goto fail; 1723 } 1724 1725 ACPI_FREE(pkg); 1726 pkg = NULL; 1727 1728 /* 1729 * Resize the array bc->bc_level if needed. 1730 */ 1731 if (count < bc->bc_level_count) { 1732 levelp = kmem_alloc(count * sizeof(*levelp), KM_SLEEP); 1733 (void)memcpy(levelp, bc->bc_level, count * sizeof(*levelp)); 1734 kmem_free(bc->bc_level, 1735 bc->bc_level_count * sizeof(*bc->bc_level)); 1736 bc->bc_level = levelp; 1737 bc->bc_level_count = count; 1738 } 1739 1740 return bc; 1741 1742 fail: 1743 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1744 acpi_name(hdl), "_BCL", AcpiFormatException(rv)); 1745 if (pkg != NULL) 1746 ACPI_FREE(pkg); 1747 if (bc != NULL) { 1748 if (bc->bc_level != NULL) 1749 kmem_free(bc->bc_level, 1750 bc->bc_level_count * sizeof(*bc->bc_level)); 1751 kmem_free(bc, sizeof(*bc)); 1752 } 1753 return NULL; 1754} 1755 1756/* 1757 * Evaluation of simple ACPI display methods. 1758 */ 1759 1760static int 1761acpidisp_set_policy(const struct acpidisp_vga_softc *asc, uint8_t value) 1762{ 1763 ACPI_HANDLE hdl = asc->sc_node->ad_handle; 1764 ACPI_INTEGER val; 1765 ACPI_STATUS rv; 1766 1767 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: 0x%"PRIx8"\n", 1768 device_xname(asc->sc_dev), "policy", value)); 1769 1770 if (!(asc->sc_caps & ACPI_DISP_VGA_CAP__DOS)) 1771 return ENODEV; 1772 1773 val = (ACPI_INTEGER)value; 1774 rv = acpi_eval_set_integer(hdl, "_DOS", val); 1775 if (ACPI_FAILURE(rv)) { 1776 aprint_error_dev(asc->sc_dev, "failed to evaluate %s.%s: %s\n", 1777 acpi_name(hdl), "_DOS", AcpiFormatException(rv)); 1778 return EIO; 1779 } 1780 1781 return 0; 1782} 1783 1784static int 1785acpidisp_get_status(const struct acpidisp_out_softc *osc, uint32_t *valuep) 1786{ 1787 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1788 ACPI_INTEGER val; 1789 ACPI_STATUS rv; 1790 1791 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DCS)) 1792 return ENODEV; 1793 1794 rv = acpi_eval_integer(hdl, "_DCS", &val); 1795 if (ACPI_FAILURE(rv)) { 1796 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1797 acpi_name(hdl), "_DCS", AcpiFormatException(rv)); 1798 return EIO; 1799 } 1800 1801 if (val > UINT32_MAX) 1802 return ERANGE; 1803 1804 *valuep = (uint32_t)val; 1805 1806 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: 0x%"PRIx32"\n", 1807 device_xname(osc->sc_dev), "status", *valuep)); 1808 1809 return 0; 1810} 1811 1812static int 1813acpidisp_get_state(const struct acpidisp_out_softc *osc, uint32_t *valuep) 1814{ 1815 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1816 ACPI_INTEGER val; 1817 ACPI_STATUS rv; 1818 1819 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DGS)) 1820 return ENODEV; 1821 1822 rv = acpi_eval_integer(hdl, "_DGS", &val); 1823 if (ACPI_FAILURE(rv)) { 1824 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1825 acpi_name(hdl), "_DGS", AcpiFormatException(rv)); 1826 return EIO; 1827 } 1828 1829 if (val > UINT32_MAX) 1830 return ERANGE; 1831 1832 *valuep = (uint32_t)val; 1833 1834 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: 0x%"PRIx32"\n", 1835 device_xname(osc->sc_dev), "state", *valuep)); 1836 1837 return 0; 1838} 1839 1840static int 1841acpidisp_set_state(const struct acpidisp_out_softc *osc, uint32_t value) 1842{ 1843 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1844 ACPI_INTEGER val; 1845 ACPI_STATUS rv; 1846 1847 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: 0x%"PRIx32"\n", 1848 device_xname(osc->sc_dev), "state", value)); 1849 1850 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DSS)) 1851 return ENODEV; 1852 1853 val = (ACPI_INTEGER)value; 1854 rv = acpi_eval_set_integer(hdl, "_DSS", val); 1855 if (ACPI_FAILURE(rv)) { 1856 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1857 acpi_name(hdl), "_DSS", AcpiFormatException(rv)); 1858 return EIO; 1859 } 1860 1861 return 0; 1862} 1863 1864static int 1865acpidisp_get_brightness(const struct acpidisp_out_softc *osc, uint8_t *valuep) 1866{ 1867 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1868 ACPI_INTEGER val; 1869 ACPI_STATUS rv; 1870 1871 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BQC)) 1872 return ENODEV; 1873 1874 if (osc->sc_brctl->bc_bqc_broken) { 1875 *valuep = osc->sc_brctl->bc_current; 1876 return 0; 1877 } 1878 1879 rv = acpi_eval_integer(hdl, "_BQC", &val); 1880 if (ACPI_FAILURE(rv)) { 1881 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1882 acpi_name(hdl), "_BQC", AcpiFormatException(rv)); 1883 return EIO; 1884 } 1885 1886 if (val > UINT8_MAX) 1887 return ERANGE; 1888 1889 *valuep = (uint8_t)val; 1890 1891 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: %"PRIu8"\n", 1892 device_xname(osc->sc_dev), "brightness", *valuep)); 1893 1894 return 0; 1895} 1896 1897/* 1898 * Quirk for when getting the brightness value always returns the same 1899 * result, which breaks brightness controls which try to lower the 1900 * brightness by a specific value and then check if it worked. 1901 */ 1902static int 1903acpidisp_quirk_get_brightness(const struct acpidisp_out_softc *osc) 1904{ 1905 struct acpidisp_brctl *bc; 1906 uint8_t original_brightness, test_brightness; 1907 int error; 1908 1909 bc = osc->sc_brctl; 1910 1911 /* Avoid false results if quirk already enabled */ 1912 bc->bc_bqc_broken = false; 1913 1914 error = acpidisp_get_brightness(osc, &bc->bc_current); 1915 if (error) 1916 return error; 1917 original_brightness = bc->bc_current; 1918 1919 /* Find a different brightness value */ 1920 test_brightness = bc->bc_level[bc->bc_level_count - 1]; 1921 if (test_brightness == original_brightness) 1922 test_brightness = bc->bc_level[0]; 1923 1924 if (test_brightness == original_brightness) { 1925 aprint_error_dev(osc->sc_dev, 1926 "couldn't find different brightness levels" 1927 " for _BQC quirk test\n"); 1928 return 0; 1929 } 1930 1931 bc->bc_current = test_brightness; 1932 error = acpidisp_set_brightness(osc, bc->bc_current); 1933 if (error) 1934 return error; 1935 1936 error = acpidisp_get_brightness(osc, &bc->bc_current); 1937 if (error) 1938 return error; 1939 1940 /* We set a different value, but got the original value back */ 1941 if (bc->bc_current == original_brightness) { 1942 aprint_normal_dev(osc->sc_dev, "_BQC broken, enabling quirk\n"); 1943 bc->bc_bqc_broken = true; 1944 } 1945 1946 /* Restore original value */ 1947 bc->bc_current = original_brightness; 1948 return acpidisp_set_brightness(osc, bc->bc_current); 1949} 1950 1951static int 1952acpidisp_set_brightness(const struct acpidisp_out_softc *osc, uint8_t value) 1953{ 1954 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1955 ACPI_INTEGER val; 1956 ACPI_STATUS rv; 1957 1958 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: %"PRIu8"\n", 1959 device_xname(osc->sc_dev), "brightness", value)); 1960 1961 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BCM)) 1962 return ENODEV; 1963 1964 val = (ACPI_INTEGER)value; 1965 rv = acpi_eval_set_integer(hdl, "_BCM", val); 1966 if (ACPI_FAILURE(rv)) { 1967 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1968 acpi_name(hdl), "_BCM", AcpiFormatException(rv)); 1969 return EIO; 1970 } 1971 1972 return 0; 1973} 1974 1975/* 1976 * Pretty printing. 1977 */ 1978 1979static void 1980acpidisp_print_odinfo(device_t self, const struct acpidisp_odinfo *oi) 1981{ 1982 struct acpidisp_outdev *od; 1983 uint32_t i; 1984 1985 KASSERT(oi != NULL); 1986 1987 aprint_verbose_dev(self, "connected output devices:\n"); 1988 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 1989 aprint_verbose_dev(self, " 0x%04"PRIx16, od->od_attrs.device_id); 1990 if (od->od_device != NULL) 1991 aprint_verbose(" (%s)", device_xname(od->od_device)); 1992 aprint_verbose(": "); 1993 acpidisp_print_od_attrs(od->od_attrs); 1994 aprint_verbose("\n"); 1995 } 1996} 1997 1998/* 1999 * general purpose range printing function 2000 * 1 -> 1 2001 * 1 2 4 6 7-> [1-2,4,6-7] 2002 */ 2003static void 2004ranger(uint8_t *a, size_t l, void (*pr)(const char *, ...) __printflike(1, 2)) 2005{ 2006 uint8_t b, e; 2007 2008 if (l > 1) 2009 (*pr)("["); 2010 2011 for (size_t i = 0; i < l; i++) { 2012 for (b = e = a[i]; i + 1 < l && a[i + 1] == e + 1; i++, e++) 2013 continue; 2014 (*pr)("%"PRIu8, b); 2015 if (b != e) 2016 (*pr)("-%"PRIu8, e); 2017 if (i < l - 1) 2018 (*pr)(","); 2019 } 2020 2021 if (l > 1) 2022 (*pr)("]"); 2023} 2024 2025static void 2026acpidisp_print_brctl(device_t self, const struct acpidisp_brctl *bc) 2027{ 2028 KASSERT(bc != NULL); 2029 2030 aprint_verbose_dev(self, "brightness levels: "); 2031 ranger(bc->bc_level, bc->bc_level_count, aprint_verbose); 2032 aprint_verbose("\n"); 2033} 2034 2035static void 2036acpidisp_print_od_attrs(acpidisp_od_attrs_t oda) 2037{ 2038 const char *type; 2039 2040 if (oda.fmt.device_id_scheme == 1) { 2041 /* Uses the device ID scheme introduced in ACPI 3.0. */ 2042 switch (oda.fmt.type) { 2043 case ACPI_DISP_OUT_ATTR_TYPE_OTHER: 2044 type = "Other"; 2045 break; 2046 case ACPI_DISP_OUT_ATTR_TYPE_VGA: 2047 type = "VGA Analog Monitor"; 2048 break; 2049 case ACPI_DISP_OUT_ATTR_TYPE_TV: 2050 type = "TV/HDTV Monitor"; 2051 break; 2052 case ACPI_DISP_OUT_ATTR_TYPE_EXTDIG: 2053 type = "Ext. Digital Monitor"; 2054 break; 2055 case ACPI_DISP_OUT_ATTR_TYPE_INTDFP: 2056 type = "Int. Digital Flat Panel"; 2057 break; 2058 default: 2059 type = "Invalid"; 2060 break; 2061 } 2062 2063 aprint_verbose("%s, index %d, port %d", 2064 type, oda.fmt.index, oda.fmt.port); 2065 } else { 2066 /* Uses vendor-specific device IDs. */ 2067 switch (oda.device_id) { 2068 case ACPI_DISP_OUT_LEGACY_DEVID_MONITOR: 2069 type = "Ext. Monitor"; 2070 break; 2071 case ACPI_DISP_OUT_LEGACY_DEVID_PANEL: 2072 type = "LCD Panel"; 2073 break; 2074 case ACPI_DISP_OUT_LEGACY_DEVID_TV: 2075 type = "TV"; 2076 break; 2077 default: 2078 type = "Unknown Output Device"; 2079 break; 2080 } 2081 2082 aprint_verbose("%s", type); 2083 } 2084 2085 aprint_verbose(", head %d", oda.fmt.head_id); 2086 if (oda.fmt.bios_detect) 2087 aprint_verbose(", bios detect"); 2088 if (oda.fmt.non_vga) 2089 aprint_verbose(", non vga"); 2090} 2091 2092/* 2093 * General-purpose utility functions. 2094 */ 2095 2096/* 2097 * acpidisp_has_method: 2098 * 2099 * Returns true if and only if (a) the object handle.path exists and 2100 * (b) this object is a method or has the given type. 2101 */ 2102static bool 2103acpidisp_has_method(ACPI_HANDLE handle, const char *path, ACPI_OBJECT_TYPE type) 2104{ 2105 ACPI_HANDLE hdl; 2106 ACPI_OBJECT_TYPE typ; 2107 2108 KASSERT(handle != NULL); 2109 2110 if (ACPI_FAILURE(AcpiGetHandle(handle, path, &hdl))) 2111 return false; 2112 2113 if (ACPI_FAILURE(AcpiGetType(hdl, &typ))) 2114 return false; 2115 2116 if (typ != ACPI_TYPE_METHOD && typ != type) 2117 return false; 2118 2119 return true; 2120} 2121 2122/* 2123 * acpidisp_eval_package: 2124 * 2125 * Evaluate a package (with an expected minimum number of elements). 2126 * Caller must free *pkg by ACPI_FREE(). 2127 */ 2128static ACPI_STATUS 2129acpidisp_eval_package(ACPI_HANDLE handle, const char *path, ACPI_OBJECT **pkg, 2130 unsigned int mincount) 2131{ 2132 ACPI_BUFFER buf; 2133 ACPI_OBJECT *obj; 2134 ACPI_STATUS rv; 2135 2136 rv = acpi_eval_struct(handle, path, &buf); 2137 if (ACPI_FAILURE(rv)) 2138 return rv; 2139 2140 if (buf.Length == 0 || buf.Pointer == NULL) 2141 return AE_NULL_OBJECT; 2142 2143 obj = buf.Pointer; 2144 2145 if (obj->Type != ACPI_TYPE_PACKAGE) { 2146 ACPI_FREE(obj); 2147 return AE_TYPE; 2148 } 2149 2150 if (obj->Package.Count < mincount) { 2151 ACPI_FREE(obj); 2152 return AE_BAD_DATA; 2153 } 2154 2155 *pkg = obj; 2156 return rv; 2157} 2158 2159/* 2160 * acpidisp_array_search: 2161 * 2162 * Look for a value v in a sorted array a of n integers (n > 0). Fill *l 2163 * and *u as follows: 2164 * 2165 * *l = Max {a[i] | a[i] <= v or i = 0} 2166 * *u = Min {a[i] | a[i] >= v or i = n-1} 2167 */ 2168static void 2169acpidisp_array_search(const uint8_t *a, uint16_t n, int v, uint8_t *l, uint8_t *u) 2170{ 2171 uint16_t i, j, m; 2172 2173 if (v <= a[0]) { 2174 *l = a[0]; 2175 *u = a[0]; 2176 return; 2177 } 2178 if (v >= a[n-1]) { 2179 *l = a[n-1]; 2180 *u = a[n-1]; 2181 return; 2182 } 2183 2184 for (i = 0, j = n - 1; j - i > 1; ) { 2185 m = (i + j) / 2; 2186 2187 if (a[m] == v) { 2188 *l = v; 2189 *u = v; 2190 return; 2191 } 2192 2193 if (a[m] < v) 2194 i = m; 2195 else 2196 j = m; 2197 } 2198 2199 /* Here a[i] < v < a[j] and j = i + 1. */ 2200 *l = a[i]; 2201 *u = a[j]; 2202 return; 2203} 2204 2205MODULE(MODULE_CLASS_DRIVER, acpivga, NULL); 2206 2207#ifdef _MODULE 2208#include "ioconf.c" 2209#endif 2210 2211static int 2212acpivga_modcmd(modcmd_t cmd, void *aux) 2213{ 2214 int rv = 0; 2215 2216 switch (cmd) { 2217 2218 case MODULE_CMD_INIT: 2219 KASSERT(PSLIST_READER_FIRST(&acpidisp_notifiers.list, 2220 struct acpidisp_notifier, adn_entry) == NULL); 2221 mutex_init(&acpidisp_notifiers.lock, MUTEX_DEFAULT, IPL_NONE); 2222#ifdef _MODULE 2223 rv = config_init_component(cfdriver_ioconf_acpivga, 2224 cfattach_ioconf_acpivga, cfdata_ioconf_acpivga); 2225#endif 2226 break; 2227 2228 case MODULE_CMD_FINI: 2229 2230#ifdef _MODULE 2231 rv = config_fini_component(cfdriver_ioconf_acpivga, 2232 cfattach_ioconf_acpivga, cfdata_ioconf_acpivga); 2233 if (rv) 2234 break; 2235#endif 2236 mutex_destroy(&acpidisp_notifiers.lock); 2237 break; 2238 2239 default: 2240 rv = ENOTTY; 2241 } 2242 2243 return rv; 2244} 2245