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