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