1 /* $NetBSD: acpi_display.c,v 1.11 2014/02/25 18:30:09 pooka 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.11 2014/02/25 18:30:09 pooka 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 (void)acpidisp_get_brightness(osc, &bc->bc_current); 651 if (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 if (acpidisp_has_method(ad->ad_handle, "_BCL", ACPI_TYPE_PACKAGE)) 789 cap |= ACPI_DISP_OUT_CAP__BCL; 790 791 if (acpidisp_has_method(ad->ad_handle, "_BCM", ACPI_TYPE_METHOD)) 792 cap |= ACPI_DISP_OUT_CAP__BCM; 793 794 if (acpidisp_has_method(ad->ad_handle, "_BQC", ACPI_TYPE_INTEGER)) 795 cap |= ACPI_DISP_OUT_CAP__BQC; 796 797 if (acpidisp_has_method(ad->ad_handle, "_DDC", ACPI_TYPE_METHOD)) 798 cap |= ACPI_DISP_OUT_CAP__DDC; 799 800 if (acpidisp_has_method(ad->ad_handle, "_DCS", ACPI_TYPE_INTEGER)) 801 cap |= ACPI_DISP_OUT_CAP__DCS; 802 803 if (acpidisp_has_method(ad->ad_handle, "_DGS", ACPI_TYPE_INTEGER)) 804 cap |= ACPI_DISP_OUT_CAP__DGS; 805 806 if (acpidisp_has_method(ad->ad_handle, "_DSS", ACPI_TYPE_METHOD)) 807 cap |= ACPI_DISP_OUT_CAP__DSS; 808 809 return cap; 810 } 811 812 static void 813 acpidisp_out_print_capabilities(device_t self, uint16_t cap) 814 { 815 aprint_debug_dev(self, "capabilities:%s%s%s%s%s%s%s\n", 816 (cap & ACPI_DISP_OUT_CAP__BCL) ? " _BCL" : "", 817 (cap & ACPI_DISP_OUT_CAP__BCM) ? " _BCM" : "", 818 (cap & ACPI_DISP_OUT_CAP__BQC) ? " _BQC" : "", 819 (cap & ACPI_DISP_OUT_CAP__DDC) ? " _DDC" : "", 820 (cap & ACPI_DISP_OUT_CAP__DCS) ? " _DCS" : "", 821 (cap & ACPI_DISP_OUT_CAP__DGS) ? " _DGS" : "", 822 (cap & ACPI_DISP_OUT_CAP__DSS) ? " _DSS" : ""); 823 } 824 825 /* 826 * ACPI notify handlers. 827 */ 828 829 static void 830 acpidisp_vga_notify_handler(ACPI_HANDLE handle, uint32_t notify, 831 void *context) 832 { 833 struct acpidisp_vga_softc *asc = device_private(context); 834 ACPI_OSD_EXEC_CALLBACK callback; 835 836 callback = NULL; 837 838 switch (notify) { 839 case ACPI_NOTIFY_CycleOutputDevice: 840 callback = acpidisp_vga_cycle_output_device_callback; 841 break; 842 case ACPI_NOTIFY_OutputDeviceStatusChange: 843 callback = acpidisp_vga_output_device_change_callback; 844 break; 845 case ACPI_NOTIFY_CycleDisplayOutputHotkeyPressed: 846 case ACPI_NOTIFY_NextDisplayOutputHotkeyPressed: 847 case ACPI_NOTIFY_PreviousDisplayOutputHotkeyPressed: 848 aprint_debug_dev(asc->sc_dev, 849 "unhandled notify: 0x%"PRIx32"\n", notify); 850 return; 851 default: 852 aprint_error_dev(asc->sc_dev, 853 "unknown notify: 0x%"PRIx32"\n", notify); 854 return; 855 } 856 857 KASSERT(callback != NULL); 858 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, callback, asc); 859 } 860 861 static void 862 acpidisp_out_notify_handler(ACPI_HANDLE handle, uint32_t notify, 863 void *context) 864 { 865 struct acpidisp_out_softc *osc = device_private(context); 866 ACPI_OSD_EXEC_CALLBACK callback; 867 868 callback = NULL; 869 870 switch (notify) { 871 case ACPI_NOTIFY_IncreaseBrightness: 872 callback = acpidisp_out_increase_brightness_callback; 873 break; 874 case ACPI_NOTIFY_DecreaseBrightness: 875 callback = acpidisp_out_decrease_brightness_callback; 876 break; 877 case ACPI_NOTIFY_CycleBrightness: 878 callback = acpidisp_out_cycle_brightness_callback; 879 break; 880 case ACPI_NOTIFY_ZeroBrightness: 881 callback = acpidisp_out_zero_brightness_callback; 882 break; 883 case ACPI_NOTIFY_DisplayDeviceOff: 884 aprint_debug_dev(osc->sc_dev, 885 "unhandled notify: 0x%"PRIx32"\n", notify); 886 return; 887 default: 888 aprint_error_dev(osc->sc_dev, 889 "unknown notify: 0x%"PRIx32"\n", notify); 890 return; 891 } 892 893 KASSERT(callback != NULL); 894 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, callback, osc); 895 } 896 897 /* 898 * ACPI notify callbacks. 899 * 900 * Exclusive access to the sc_odinfo field of struct acpidisp_vga_softc is 901 * guaranteed since: 902 * 903 * (a) this field is only used in ACPI display notify callbacks, 904 * (b) ACPI display notify callbacks are scheduled with AcpiOsExecute, 905 * (c) callbacks scheduled with AcpiOsExecute are executed sequentially. 906 */ 907 908 static void 909 acpidisp_vga_cycle_output_device_callback(void *arg) 910 { 911 struct acpidisp_vga_softc *asc = arg; 912 struct acpidisp_odinfo *oi = asc->sc_odinfo; 913 struct acpidisp_outdev *od; 914 struct acpidisp_out_softc *osc, *last_osc; 915 acpidisp_od_state_t state, last_state; 916 acpidisp_od_status_t status; 917 acpidisp_bios_policy_t lock_policy; 918 uint32_t i; 919 920 if (oi == NULL) 921 return; 922 923 /* Mutual exclusion with callbacks of connected output devices. */ 924 mutex_enter(&asc->sc_mtx); 925 926 /* Lock the _DGS values. */ 927 lock_policy = asc->sc_policy; 928 lock_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_LOCKED; 929 (void)acpidisp_set_policy(asc, lock_policy.raw); 930 931 last_osc = NULL; 932 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 933 if (od->od_device == NULL) 934 continue; 935 osc = device_private(od->od_device); 936 937 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DSS)) 938 continue; 939 if (acpidisp_get_state(osc, &state.raw)) 940 continue; 941 942 if (acpidisp_get_status(osc, &status.raw)) { 943 state.fmt.no_switch = 0; 944 } else { 945 state.fmt.active &= status.fmt.ready; 946 947 if (state.fmt.active == status.fmt.activated) 948 state.fmt.no_switch = 1; 949 else 950 state.fmt.no_switch = 0; 951 } 952 953 state.fmt.commit = 0; 954 955 if (last_osc != NULL) 956 (void)acpidisp_set_state(last_osc, last_state.raw); 957 958 last_osc = osc; 959 last_state = state; 960 } 961 962 if (last_osc != NULL) { 963 last_state.fmt.commit = 1; 964 (void)acpidisp_set_state(last_osc, last_state.raw); 965 } 966 967 /* Restore the original BIOS policy. */ 968 (void)acpidisp_set_policy(asc, asc->sc_policy.raw); 969 970 mutex_exit(&asc->sc_mtx); 971 } 972 973 static void 974 acpidisp_vga_output_device_change_callback(void *arg) 975 { 976 struct acpidisp_vga_softc *asc = arg; 977 struct acpidisp_odinfo *oi = asc->sc_odinfo; 978 bool switch_outputs; 979 980 if (oi != NULL) { 981 kmem_free(oi->oi_dev, 982 oi->oi_dev_count * sizeof(*oi->oi_dev)); 983 kmem_free(oi, sizeof(*oi)); 984 } 985 986 asc->sc_odinfo = acpidisp_init_odinfo(asc); 987 if (asc->sc_odinfo != NULL) { 988 acpidisp_vga_bind_outdevs(asc); 989 acpidisp_print_odinfo(asc->sc_dev, asc->sc_odinfo); 990 } 991 992 /* Perform display output switch if needed. */ 993 mutex_enter(&asc->sc_mtx); 994 switch_outputs = 995 (asc->sc_policy.fmt.output == ACPI_DISP_POLICY_OUTPUT_NORMAL); 996 mutex_exit(&asc->sc_mtx); 997 if (switch_outputs) 998 acpidisp_vga_cycle_output_device_callback(arg); 999 } 1000 1001 static void 1002 acpidisp_out_increase_brightness_callback(void *arg) 1003 { 1004 struct acpidisp_out_softc *osc = arg; 1005 struct acpidisp_brctl *bc = osc->sc_brctl; 1006 uint8_t lo, up; 1007 1008 if (bc == NULL) { 1009 /* Fallback to pmf(9). */ 1010 pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP); 1011 return; 1012 } 1013 1014 mutex_enter(osc->sc_mtx); 1015 1016 (void)acpidisp_get_brightness(osc, &bc->bc_current); 1017 1018 acpidisp_array_search(bc->bc_level, bc->bc_level_count, 1019 bc->bc_current + ACPI_DISP_BRCTL_STEP, &lo, &up); 1020 1021 bc->bc_current = up; 1022 (void)acpidisp_set_brightness(osc, bc->bc_current); 1023 1024 mutex_exit(osc->sc_mtx); 1025 } 1026 1027 static void 1028 acpidisp_out_decrease_brightness_callback(void *arg) 1029 { 1030 struct acpidisp_out_softc *osc = arg; 1031 struct acpidisp_brctl *bc = osc->sc_brctl; 1032 uint8_t lo, up; 1033 1034 if (bc == NULL) { 1035 /* Fallback to pmf(9). */ 1036 pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN); 1037 return; 1038 } 1039 1040 mutex_enter(osc->sc_mtx); 1041 1042 (void)acpidisp_get_brightness(osc, &bc->bc_current); 1043 1044 acpidisp_array_search(bc->bc_level, bc->bc_level_count, 1045 bc->bc_current - ACPI_DISP_BRCTL_STEP, &lo, &up); 1046 1047 bc->bc_current = lo; 1048 (void)acpidisp_set_brightness(osc, bc->bc_current); 1049 1050 mutex_exit(osc->sc_mtx); 1051 } 1052 1053 static void 1054 acpidisp_out_cycle_brightness_callback(void *arg) 1055 { 1056 struct acpidisp_out_softc *osc = arg; 1057 struct acpidisp_brctl *bc = osc->sc_brctl; 1058 uint8_t lo, up; 1059 1060 if (bc == NULL) { 1061 /* No fallback. */ 1062 return; 1063 } 1064 1065 mutex_enter(osc->sc_mtx); 1066 1067 (void)acpidisp_get_brightness(osc, &bc->bc_current); 1068 1069 if (bc->bc_current >= bc->bc_level[bc->bc_level_count - 1]) { 1070 bc->bc_current = bc->bc_level[0]; 1071 } else { 1072 acpidisp_array_search(bc->bc_level, bc->bc_level_count, 1073 bc->bc_current + 1, &lo, &up); 1074 bc->bc_current = up; 1075 } 1076 1077 (void)acpidisp_set_brightness(osc, bc->bc_current); 1078 1079 mutex_exit(osc->sc_mtx); 1080 } 1081 1082 static void 1083 acpidisp_out_zero_brightness_callback(void *arg) 1084 { 1085 struct acpidisp_out_softc *osc = arg; 1086 struct acpidisp_brctl *bc = osc->sc_brctl; 1087 1088 if (bc == NULL) { 1089 /* Fallback to pmf(9). */ 1090 /* XXX Is this the intended meaning of PMFE_DISPLAY_REDUCED? */ 1091 pmf_event_inject(NULL, PMFE_DISPLAY_REDUCED); 1092 return; 1093 } 1094 1095 mutex_enter(osc->sc_mtx); 1096 1097 bc->bc_current = bc->bc_level[0]; 1098 (void)acpidisp_set_brightness(osc, bc->bc_current); 1099 1100 mutex_exit(osc->sc_mtx); 1101 } 1102 1103 /* 1104 * Sysctl setup. 1105 */ 1106 1107 static void 1108 acpidisp_vga_sysctl_setup(struct acpidisp_vga_softc *asc) 1109 { 1110 const struct sysctlnode *rnode; 1111 1112 if (asc->sc_caps & ACPI_DISP_VGA_CAP__DOS) { 1113 if ((sysctl_createv(&asc->sc_log, 0, NULL, &rnode, 1114 0, CTLTYPE_NODE, "acpi", NULL, 1115 NULL, 0, NULL, 0, 1116 CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 1117 goto fail; 1118 1119 if ((sysctl_createv(&asc->sc_log, 0, &rnode, &rnode, 1120 0, CTLTYPE_NODE, device_xname(asc->sc_dev), 1121 SYSCTL_DESCR("ACPI display adapter controls"), 1122 NULL, 0, NULL, 0, 1123 CTL_CREATE, CTL_EOL)) != 0) 1124 goto fail; 1125 1126 #ifdef ACPI_DEBUG 1127 (void)sysctl_createv(&asc->sc_log, 0, &rnode, NULL, 1128 CTLFLAG_READWRITE | CTLFLAG_HEX, CTLTYPE_INT, "bios_policy", 1129 SYSCTL_DESCR("Current BIOS switch policies (debug)"), 1130 acpidisp_vga_sysctl_policy, 0, (void *)asc, 0, 1131 CTL_CREATE, CTL_EOL); 1132 #endif 1133 1134 (void)sysctl_createv(&asc->sc_log, 0, &rnode, NULL, 1135 CTLFLAG_READWRITE, CTLTYPE_BOOL, "bios_switch", 1136 SYSCTL_DESCR("Current BIOS output switching policy"), 1137 acpidisp_vga_sysctl_policy_output, 0, (void *)asc, 0, 1138 CTL_CREATE, CTL_EOL); 1139 } 1140 1141 return; 1142 1143 fail: 1144 aprint_error_dev(asc->sc_dev, "couldn't add sysctl nodes\n"); 1145 } 1146 1147 static void 1148 acpidisp_out_sysctl_setup(struct acpidisp_out_softc *osc) 1149 { 1150 const struct sysctlnode *rnode; 1151 1152 #ifdef ACPI_DISP_SWITCH_SYSCTLS 1153 if ((osc->sc_brctl != NULL) || 1154 (osc->sc_caps & ACPI_DISP_OUT_CAP__DCS) || 1155 (osc->sc_caps & ACPI_DISP_OUT_CAP__DGS)) { 1156 #else 1157 if (osc->sc_brctl != NULL) { 1158 #endif 1159 if ((sysctl_createv(&osc->sc_log, 0, NULL, &rnode, 1160 0, CTLTYPE_NODE, "acpi", NULL, 1161 NULL, 0, NULL, 0, 1162 CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 1163 goto fail; 1164 1165 if ((sysctl_createv(&osc->sc_log, 0, &rnode, &rnode, 1166 0, CTLTYPE_NODE, device_xname(osc->sc_dev), 1167 SYSCTL_DESCR("ACPI display output device controls"), 1168 NULL, 0, NULL, 0, 1169 CTL_CREATE, CTL_EOL)) != 0) 1170 goto fail; 1171 } 1172 1173 if (osc->sc_brctl != NULL) { 1174 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1175 CTLFLAG_READWRITE, CTLTYPE_INT, "brightness", 1176 SYSCTL_DESCR("Current brightness level"), 1177 acpidisp_out_sysctl_brightness, 0, (void *)osc, 0, 1178 CTL_CREATE, CTL_EOL); 1179 } 1180 1181 #ifdef ACPI_DISP_SWITCH_SYSCTLS 1182 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DCS) { 1183 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1184 CTLFLAG_READONLY | CTLFLAG_HEX, CTLTYPE_INT, "status", 1185 SYSCTL_DESCR("Current status"), 1186 acpidisp_out_sysctl_status, 0, (void *)osc, 0, 1187 CTL_CREATE, CTL_EOL); 1188 } 1189 1190 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DGS) { 1191 int access; 1192 1193 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DSS) 1194 access = CTLFLAG_READWRITE; 1195 else 1196 access = CTLFLAG_READONLY; 1197 1198 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1199 access | CTLFLAG_HEX, CTLTYPE_INT, "state", 1200 SYSCTL_DESCR("Next state (active or inactive)"), 1201 acpidisp_out_sysctl_state, 0, (void *)osc, 0, 1202 CTL_CREATE, CTL_EOL); 1203 } 1204 #endif 1205 1206 return; 1207 1208 fail: 1209 aprint_error_dev(osc->sc_dev, "couldn't add sysctl nodes\n"); 1210 } 1211 1212 /* 1213 * Sysctl callbacks. 1214 */ 1215 1216 #ifdef ACPI_DEBUG 1217 static int 1218 acpidisp_vga_sysctl_policy(SYSCTLFN_ARGS) 1219 { 1220 struct sysctlnode node; 1221 struct acpidisp_vga_softc *asc; 1222 uint32_t val; 1223 int error; 1224 1225 node = *rnode; 1226 asc = node.sysctl_data; 1227 1228 mutex_enter(&asc->sc_mtx); 1229 val = (uint32_t)asc->sc_policy.raw; 1230 mutex_exit(&asc->sc_mtx); 1231 1232 node.sysctl_data = &val; 1233 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1234 if (error || newp == NULL) 1235 return error; 1236 1237 if (val > 0x7) 1238 return EINVAL; 1239 1240 mutex_enter(&asc->sc_mtx); 1241 asc->sc_policy.raw = (uint8_t)val; 1242 error = acpidisp_set_policy(asc, asc->sc_policy.raw); 1243 mutex_exit(&asc->sc_mtx); 1244 1245 return error; 1246 } 1247 #endif 1248 1249 static int 1250 acpidisp_vga_sysctl_policy_output(SYSCTLFN_ARGS) 1251 { 1252 struct sysctlnode node; 1253 struct acpidisp_vga_softc *asc; 1254 bool val; 1255 int error; 1256 1257 node = *rnode; 1258 asc = node.sysctl_data; 1259 1260 mutex_enter(&asc->sc_mtx); 1261 val = (asc->sc_policy.fmt.output == ACPI_DISP_POLICY_OUTPUT_AUTO); 1262 mutex_exit(&asc->sc_mtx); 1263 1264 node.sysctl_data = &val; 1265 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1266 if (error || newp == NULL) 1267 return error; 1268 1269 mutex_enter(&asc->sc_mtx); 1270 if (val) 1271 asc->sc_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_AUTO; 1272 else 1273 asc->sc_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_NORMAL; 1274 error = acpidisp_set_policy(asc, asc->sc_policy.raw); 1275 mutex_exit(&asc->sc_mtx); 1276 1277 return error; 1278 } 1279 1280 #ifdef ACPI_DISP_SWITCH_SYSCTLS 1281 static int 1282 acpidisp_out_sysctl_status(SYSCTLFN_ARGS) 1283 { 1284 struct sysctlnode node; 1285 struct acpidisp_out_softc *osc; 1286 uint32_t val; 1287 int error; 1288 1289 node = *rnode; 1290 osc = node.sysctl_data; 1291 1292 mutex_enter(osc->sc_mtx); 1293 error = acpidisp_get_status(osc, &val); 1294 mutex_exit(osc->sc_mtx); 1295 1296 if (error) 1297 return error; 1298 1299 node.sysctl_data = &val; 1300 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1301 if (error || newp == NULL) 1302 return error; 1303 1304 return 0; 1305 } 1306 1307 static int 1308 acpidisp_out_sysctl_state(SYSCTLFN_ARGS) 1309 { 1310 struct sysctlnode node; 1311 struct acpidisp_out_softc *osc; 1312 uint32_t val; 1313 int error; 1314 1315 node = *rnode; 1316 osc = node.sysctl_data; 1317 1318 mutex_enter(osc->sc_mtx); 1319 error = acpidisp_get_state(osc, &val); 1320 mutex_exit(osc->sc_mtx); 1321 1322 if (error) 1323 return error; 1324 1325 node.sysctl_data = &val; 1326 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1327 if (error || newp == NULL) 1328 return error; 1329 1330 mutex_enter(osc->sc_mtx); 1331 error = acpidisp_set_state(osc, val); 1332 mutex_exit(osc->sc_mtx); 1333 1334 return error; 1335 } 1336 #endif 1337 1338 static int 1339 acpidisp_out_sysctl_brightness(SYSCTLFN_ARGS) 1340 { 1341 struct sysctlnode node; 1342 struct acpidisp_out_softc *osc; 1343 struct acpidisp_brctl *bc; 1344 int val, error; 1345 uint8_t lo, up, level; 1346 1347 node = *rnode; 1348 osc = node.sysctl_data; 1349 bc = osc->sc_brctl; 1350 1351 KASSERT(bc != NULL); 1352 1353 mutex_enter(osc->sc_mtx); 1354 (void)acpidisp_get_brightness(osc, &bc->bc_current); 1355 val = (int)bc->bc_current; 1356 mutex_exit(osc->sc_mtx); 1357 1358 node.sysctl_data = &val; 1359 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1360 if (error || newp == NULL) 1361 return error; 1362 1363 acpidisp_array_search(bc->bc_level, bc->bc_level_count, val, &lo, &up); 1364 if ((lo != up) && (val - lo) < (up - val)) 1365 level = lo; 1366 else 1367 level = up; 1368 1369 mutex_enter(osc->sc_mtx); 1370 bc->bc_current = level; 1371 error = acpidisp_set_brightness(osc, bc->bc_current); 1372 mutex_exit(osc->sc_mtx); 1373 1374 return error; 1375 } 1376 1377 /* 1378 * Initialization of acpidisp_odinfo (_DOD) and acpidisp_brctl (_BCL). 1379 */ 1380 1381 /* 1382 * Regarding _DOD (ACPI 4.0a, Sec. B.4.2): 1383 * 1384 * "The _DOD method returns a list of devices attached to the graphics adapter, 1385 * along with device-specific configuration information." 1386 * 1387 * "Every child device enumerated in the ACPI namespace under the graphics 1388 * adapter must be specified in this list of devices. Each display device 1389 * must have its own ID, which is unique with respect to any other attachable 1390 * devices enumerated." 1391 * 1392 * "Return value: a package containing a variable-length list of integers, 1393 * each of which contains the 32-bit device attribute of a child device." 1394 */ 1395 1396 static struct acpidisp_odinfo * 1397 acpidisp_init_odinfo(const struct acpidisp_vga_softc *asc) 1398 { 1399 ACPI_HANDLE hdl = asc->sc_node->ad_handle; 1400 ACPI_STATUS rv; 1401 ACPI_OBJECT *pkg; 1402 struct acpidisp_odinfo *oi; 1403 struct acpidisp_outdev *devp; 1404 uint32_t count, i; 1405 1406 if (!(asc->sc_caps & ACPI_DISP_VGA_CAP__DOD)) 1407 return NULL; 1408 1409 oi = NULL; 1410 pkg = NULL; 1411 1412 rv = acpidisp_eval_package(hdl, "_DOD", &pkg, 1); 1413 if (ACPI_FAILURE(rv)) 1414 goto fail; 1415 1416 /* 1417 * Allocate and fill the struct acpidisp_odinfo to be returned. 1418 */ 1419 oi = kmem_zalloc(sizeof(*oi), KM_SLEEP); 1420 if (oi == NULL) { 1421 rv = AE_NO_MEMORY; 1422 goto fail; 1423 } 1424 1425 oi->oi_dev_count = pkg->Package.Count; 1426 1427 oi->oi_dev = kmem_zalloc(oi->oi_dev_count * sizeof(*oi->oi_dev), 1428 KM_SLEEP); 1429 if (oi->oi_dev == NULL) { 1430 rv = AE_NO_MEMORY; 1431 goto fail; 1432 } 1433 1434 /* 1435 * Fill the array oi->oi_dev. 1436 */ 1437 for (count = 0, i = 0; i < pkg->Package.Count; i++) { 1438 /* List of 32-bit integers (ACPI 4.0a, Sec. B.4.2). */ 1439 if (pkg->Package.Elements[i].Type != ACPI_TYPE_INTEGER || 1440 pkg->Package.Elements[i].Integer.Value > UINT32_MAX) 1441 continue; 1442 1443 oi->oi_dev[count].od_attrs.raw = 1444 (uint32_t)pkg->Package.Elements[i].Integer.Value; 1445 count++; 1446 } 1447 1448 if (count == 0) { 1449 rv = AE_BAD_DATA; 1450 goto fail; 1451 } 1452 1453 ACPI_FREE(pkg); 1454 pkg = NULL; 1455 1456 /* 1457 * Resize the array oi->oi_dev if needed. 1458 */ 1459 if (count < oi->oi_dev_count) { 1460 devp = kmem_alloc(count * sizeof(*devp), KM_SLEEP); 1461 if (devp == NULL) { 1462 rv = AE_NO_MEMORY; 1463 goto fail; 1464 } 1465 1466 (void)memcpy(devp, oi->oi_dev, count * sizeof(*devp)); 1467 kmem_free(oi->oi_dev, oi->oi_dev_count * sizeof(*oi->oi_dev)); 1468 1469 oi->oi_dev = devp; 1470 oi->oi_dev_count = count; 1471 } 1472 1473 return oi; 1474 1475 fail: 1476 aprint_error_dev(asc->sc_dev, "failed to evaluate %s.%s: %s\n", 1477 acpi_name(hdl), "_DOD", AcpiFormatException(rv)); 1478 if (pkg != NULL) 1479 ACPI_FREE(pkg); 1480 if (oi != NULL) { 1481 if (oi->oi_dev != NULL) 1482 kmem_free(oi->oi_dev, 1483 oi->oi_dev_count * sizeof(*oi->oi_dev)); 1484 kmem_free(oi, sizeof(*oi)); 1485 } 1486 return NULL; 1487 } 1488 1489 /* 1490 * acpidisp_vga_bind_outdevs: 1491 * 1492 * Bind each acpiout device attached under an acpivga device to the 1493 * corresponding (_DOD enumerated) connected output device. 1494 */ 1495 static void 1496 acpidisp_vga_bind_outdevs(struct acpidisp_vga_softc *asc) 1497 { 1498 struct acpidisp_odinfo *oi = asc->sc_odinfo; 1499 struct acpidisp_out_softc *osc; 1500 struct acpidisp_outdev *od; 1501 struct acpi_devnode *ad; 1502 ACPI_HANDLE hdl; 1503 ACPI_INTEGER val; 1504 ACPI_STATUS rv; 1505 uint16_t devid; 1506 uint32_t i; 1507 1508 KASSERT(oi != NULL); 1509 1510 /* Reset all bindings. */ 1511 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) 1512 od->od_device = NULL; 1513 1514 /* 1515 * Iterate over all ACPI children that have been attached under this 1516 * acpivga device (as acpiout devices). 1517 */ 1518 SIMPLEQ_FOREACH(ad, &asc->sc_node->ad_child_head, ad_child_list) { 1519 if ((ad->ad_device == NULL) || 1520 (device_parent(ad->ad_device) != asc->sc_dev)) 1521 continue; 1522 1523 KASSERT(device_is_a(ad->ad_device, "acpiout")); 1524 1525 osc = device_private(ad->ad_device); 1526 1527 /* 1528 * For display output devices, the method _ADR returns 1529 * the device's ID (ACPI 4.0a, Sec. B.6.1). We do not 1530 * cache the result of _ADR since it may vary. 1531 */ 1532 hdl = osc->sc_node->ad_handle; 1533 rv = acpi_eval_integer(hdl, "_ADR", &val); 1534 if (ACPI_FAILURE(rv)) { 1535 aprint_error_dev(asc->sc_dev, 1536 "failed to evaluate %s.%s: %s\n", 1537 acpi_name(hdl), "_ADR", AcpiFormatException(rv)); 1538 continue; 1539 } 1540 1541 /* The device ID is a 16-bit integer (ACPI 4.0a, Table B-2). */ 1542 devid = (uint16_t)val; 1543 1544 /* 1545 * The device ID must be unique (among output devices), and must 1546 * appear in the list returned by _DOD (ACPI 4.0a, Sec. B.6.1). 1547 */ 1548 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 1549 if (devid == od->od_attrs.device_id) { 1550 if (od->od_device != NULL) 1551 aprint_error_dev(asc->sc_dev, 1552 "%s has same device ID as %s\n", 1553 device_xname(osc->sc_dev), 1554 device_xname(od->od_device)); 1555 else 1556 od->od_device = osc->sc_dev; 1557 break; 1558 } 1559 } 1560 if (i == oi->oi_dev_count) 1561 aprint_error_dev(asc->sc_dev, 1562 "unknown output device %s\n", 1563 device_xname(osc->sc_dev)); 1564 } 1565 } 1566 1567 /* 1568 * Regarding _BCL (ACPI 4.0a, Sec. B.6.2): 1569 * 1570 * "This method allows the OS to query a list of brightness levels supported by 1571 * built-in display output devices." 1572 * 1573 * "Return value: a variable-length package containing a list of integers 1574 * representing the supported brightness levels. Each integer has 8 bits of 1575 * significant data." 1576 */ 1577 1578 static struct acpidisp_brctl * 1579 acpidisp_init_brctl(const struct acpidisp_out_softc *osc) 1580 { 1581 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1582 ACPI_STATUS rv; 1583 ACPI_OBJECT *pkg; 1584 struct acpidisp_brctl *bc; 1585 uint8_t *levelp; 1586 uint32_t i; 1587 int32_t j; 1588 uint16_t count, k; 1589 uint8_t level; 1590 1591 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BCL)) 1592 return NULL; 1593 1594 bc = NULL; 1595 pkg = NULL; 1596 1597 rv = acpidisp_eval_package(hdl, "_BCL", &pkg, 2); 1598 if (ACPI_FAILURE(rv)) 1599 goto fail; 1600 1601 /* 1602 * Allocate and fill the struct acpidisp_brctl to be returned. 1603 */ 1604 bc = kmem_zalloc(sizeof(*bc), KM_SLEEP); 1605 if (bc == NULL) { 1606 rv = AE_NO_MEMORY; 1607 goto fail; 1608 } 1609 1610 /* At most 256 brightness levels (8-bit integers). */ 1611 if (pkg->Package.Count > 256) 1612 bc->bc_level_count = 256; 1613 else 1614 bc->bc_level_count = (uint16_t)pkg->Package.Count; 1615 1616 bc->bc_level = kmem_zalloc(bc->bc_level_count * sizeof(*bc->bc_level), 1617 KM_SLEEP); 1618 if (bc->bc_level == NULL) { 1619 rv = AE_NO_MEMORY; 1620 goto fail; 1621 } 1622 1623 /* 1624 * Fill the array bc->bc_level with an insertion sort. 1625 */ 1626 for (count = 0, i = 0; i < pkg->Package.Count; i++) { 1627 /* List of 8-bit integers (ACPI 4.0a, Sec. B.6.2). */ 1628 if (pkg->Package.Elements[i].Type != ACPI_TYPE_INTEGER || 1629 pkg->Package.Elements[i].Integer.Value > UINT8_MAX) 1630 continue; 1631 1632 level = (uint8_t)pkg->Package.Elements[i].Integer.Value; 1633 1634 /* Find the correct slot but do not modify the array yet. */ 1635 for (j = count; --j >= 0 && bc->bc_level[j] > level; ); 1636 if (j >= 0 && bc->bc_level[j] == level) 1637 continue; 1638 j++; 1639 1640 /* Make room for the new level. */ 1641 for (k = count; k > j; k--) 1642 bc->bc_level[k] = bc->bc_level[k-1]; 1643 1644 /* Insert the new level. */ 1645 bc->bc_level[j] = level; 1646 count++; 1647 } 1648 1649 if (count == 0) { 1650 rv = AE_BAD_DATA; 1651 goto fail; 1652 } 1653 1654 ACPI_FREE(pkg); 1655 pkg = NULL; 1656 1657 /* 1658 * Resize the array bc->bc_level if needed. 1659 */ 1660 if (count < bc->bc_level_count) { 1661 levelp = kmem_alloc(count * sizeof(*levelp), KM_SLEEP); 1662 if (levelp == NULL) { 1663 rv = AE_NO_MEMORY; 1664 goto fail; 1665 } 1666 1667 (void)memcpy(levelp, bc->bc_level, count * sizeof(*levelp)); 1668 kmem_free(bc->bc_level, 1669 bc->bc_level_count * sizeof(*bc->bc_level)); 1670 1671 bc->bc_level = levelp; 1672 bc->bc_level_count = count; 1673 } 1674 1675 return bc; 1676 1677 fail: 1678 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1679 acpi_name(hdl), "_BCL", AcpiFormatException(rv)); 1680 if (pkg != NULL) 1681 ACPI_FREE(pkg); 1682 if (bc != NULL) { 1683 if (bc->bc_level != NULL) 1684 kmem_free(bc->bc_level, 1685 bc->bc_level_count * sizeof(*bc->bc_level)); 1686 kmem_free(bc, sizeof(*bc)); 1687 } 1688 return NULL; 1689 } 1690 1691 /* 1692 * Evaluation of simple ACPI display methods. 1693 */ 1694 1695 static int 1696 acpidisp_set_policy(const struct acpidisp_vga_softc *asc, uint8_t value) 1697 { 1698 ACPI_HANDLE hdl = asc->sc_node->ad_handle; 1699 ACPI_INTEGER val; 1700 ACPI_STATUS rv; 1701 1702 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: 0x%"PRIx8"\n", 1703 device_xname(asc->sc_dev), "policy", value)); 1704 1705 if (!(asc->sc_caps & ACPI_DISP_VGA_CAP__DOS)) 1706 return ENODEV; 1707 1708 val = (ACPI_INTEGER)value; 1709 rv = acpi_eval_set_integer(hdl, "_DOS", val); 1710 if (ACPI_FAILURE(rv)) { 1711 aprint_error_dev(asc->sc_dev, "failed to evaluate %s.%s: %s\n", 1712 acpi_name(hdl), "_DOS", AcpiFormatException(rv)); 1713 return EIO; 1714 } 1715 1716 return 0; 1717 } 1718 1719 static int 1720 acpidisp_get_status(const struct acpidisp_out_softc *osc, uint32_t *valuep) 1721 { 1722 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1723 ACPI_INTEGER val; 1724 ACPI_STATUS rv; 1725 1726 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DCS)) 1727 return ENODEV; 1728 1729 rv = acpi_eval_integer(hdl, "_DCS", &val); 1730 if (ACPI_FAILURE(rv)) { 1731 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1732 acpi_name(hdl), "_DCS", AcpiFormatException(rv)); 1733 return EIO; 1734 } 1735 1736 if (val > UINT32_MAX) 1737 return ERANGE; 1738 1739 *valuep = (uint32_t)val; 1740 1741 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: 0x%"PRIx32"\n", 1742 device_xname(osc->sc_dev), "status", *valuep)); 1743 1744 return 0; 1745 } 1746 1747 static int 1748 acpidisp_get_state(const struct acpidisp_out_softc *osc, uint32_t *valuep) 1749 { 1750 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1751 ACPI_INTEGER val; 1752 ACPI_STATUS rv; 1753 1754 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DGS)) 1755 return ENODEV; 1756 1757 rv = acpi_eval_integer(hdl, "_DGS", &val); 1758 if (ACPI_FAILURE(rv)) { 1759 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1760 acpi_name(hdl), "_DGS", AcpiFormatException(rv)); 1761 return EIO; 1762 } 1763 1764 if (val > UINT32_MAX) 1765 return ERANGE; 1766 1767 *valuep = (uint32_t)val; 1768 1769 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: 0x%"PRIx32"\n", 1770 device_xname(osc->sc_dev), "state", *valuep)); 1771 1772 return 0; 1773 } 1774 1775 static int 1776 acpidisp_set_state(const struct acpidisp_out_softc *osc, uint32_t value) 1777 { 1778 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1779 ACPI_INTEGER val; 1780 ACPI_STATUS rv; 1781 1782 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: 0x%"PRIx32"\n", 1783 device_xname(osc->sc_dev), "state", value)); 1784 1785 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DSS)) 1786 return ENODEV; 1787 1788 val = (ACPI_INTEGER)value; 1789 rv = acpi_eval_set_integer(hdl, "_DSS", val); 1790 if (ACPI_FAILURE(rv)) { 1791 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1792 acpi_name(hdl), "_DSS", AcpiFormatException(rv)); 1793 return EIO; 1794 } 1795 1796 return 0; 1797 } 1798 1799 static int 1800 acpidisp_get_brightness(const struct acpidisp_out_softc *osc, uint8_t *valuep) 1801 { 1802 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1803 ACPI_INTEGER val; 1804 ACPI_STATUS rv; 1805 1806 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BQC)) 1807 return ENODEV; 1808 1809 rv = acpi_eval_integer(hdl, "_BQC", &val); 1810 if (ACPI_FAILURE(rv)) { 1811 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1812 acpi_name(hdl), "_BQC", AcpiFormatException(rv)); 1813 return EIO; 1814 } 1815 1816 if (val > UINT8_MAX) 1817 return ERANGE; 1818 1819 *valuep = (uint8_t)val; 1820 1821 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: %"PRIu8"\n", 1822 device_xname(osc->sc_dev), "brightness", *valuep)); 1823 1824 return 0; 1825 } 1826 1827 static int 1828 acpidisp_set_brightness(const struct acpidisp_out_softc *osc, uint8_t value) 1829 { 1830 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1831 ACPI_INTEGER val; 1832 ACPI_STATUS rv; 1833 1834 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: %"PRIu8"\n", 1835 device_xname(osc->sc_dev), "brightness", value)); 1836 1837 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BCM)) 1838 return ENODEV; 1839 1840 val = (ACPI_INTEGER)value; 1841 rv = acpi_eval_set_integer(hdl, "_BCM", val); 1842 if (ACPI_FAILURE(rv)) { 1843 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1844 acpi_name(hdl), "_BCM", AcpiFormatException(rv)); 1845 return EIO; 1846 } 1847 1848 return 0; 1849 } 1850 1851 /* 1852 * Pretty printing. 1853 */ 1854 1855 static void 1856 acpidisp_print_odinfo(device_t self, const struct acpidisp_odinfo *oi) 1857 { 1858 struct acpidisp_outdev *od; 1859 uint32_t i; 1860 1861 KASSERT(oi != NULL); 1862 1863 aprint_verbose_dev(self, "connected output devices:\n"); 1864 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 1865 aprint_verbose_dev(self, " 0x%04"PRIx16, od->od_attrs.device_id); 1866 if (od->od_device != NULL) 1867 aprint_verbose(" (%s)", device_xname(od->od_device)); 1868 aprint_verbose(": "); 1869 acpidisp_print_od_attrs(od->od_attrs); 1870 aprint_verbose("\n"); 1871 } 1872 } 1873 1874 static void 1875 acpidisp_print_brctl(device_t self, const struct acpidisp_brctl *bc) 1876 { 1877 uint16_t i; 1878 1879 KASSERT(bc != NULL); 1880 1881 aprint_verbose_dev(self, "brightness levels:"); 1882 for (i = 0; i < bc->bc_level_count; i++) 1883 aprint_verbose(" %"PRIu8, bc->bc_level[i]); 1884 aprint_verbose("\n"); 1885 } 1886 1887 static void 1888 acpidisp_print_od_attrs(acpidisp_od_attrs_t oda) 1889 { 1890 const char *type; 1891 1892 if (oda.fmt.device_id_scheme == 1) { 1893 /* Uses the device ID scheme introduced in ACPI 3.0. */ 1894 switch (oda.fmt.type) { 1895 case ACPI_DISP_OUT_ATTR_TYPE_OTHER: 1896 type = "Other"; 1897 break; 1898 case ACPI_DISP_OUT_ATTR_TYPE_VGA: 1899 type = "VGA Analog Monitor"; 1900 break; 1901 case ACPI_DISP_OUT_ATTR_TYPE_TV: 1902 type = "TV/HDTV Monitor"; 1903 break; 1904 case ACPI_DISP_OUT_ATTR_TYPE_EXTDIG: 1905 type = "Ext. Digital Monitor"; 1906 break; 1907 case ACPI_DISP_OUT_ATTR_TYPE_INTDFP: 1908 type = "Int. Digital Flat Panel"; 1909 break; 1910 default: 1911 type = "Invalid"; 1912 break; 1913 } 1914 1915 aprint_verbose("%s, index %d, port %d", 1916 type, oda.fmt.index, oda.fmt.port); 1917 } else { 1918 /* Uses vendor-specific device IDs. */ 1919 switch (oda.device_id) { 1920 case ACPI_DISP_OUT_LEGACY_DEVID_MONITOR: 1921 type = "Ext. Monitor"; 1922 break; 1923 case ACPI_DISP_OUT_LEGACY_DEVID_PANEL: 1924 type = "LCD Panel"; 1925 break; 1926 case ACPI_DISP_OUT_LEGACY_DEVID_TV: 1927 type = "TV"; 1928 break; 1929 default: 1930 type = "Unknown Output Device"; 1931 break; 1932 } 1933 1934 aprint_verbose("%s", type); 1935 } 1936 1937 aprint_verbose(", head %d", oda.fmt.head_id); 1938 if (oda.fmt.bios_detect) 1939 aprint_verbose(", bios detect"); 1940 if (oda.fmt.non_vga) 1941 aprint_verbose(", non vga"); 1942 } 1943 1944 /* 1945 * General-purpose utility functions. 1946 */ 1947 1948 /* 1949 * acpidisp_has_method: 1950 * 1951 * Returns true if and only if (a) the object handle.path exists and 1952 * (b) this object is a method or has the given type. 1953 */ 1954 static bool 1955 acpidisp_has_method(ACPI_HANDLE handle, const char *path, ACPI_OBJECT_TYPE type) 1956 { 1957 ACPI_HANDLE hdl; 1958 ACPI_OBJECT_TYPE typ; 1959 1960 KASSERT(handle != NULL); 1961 1962 if (ACPI_FAILURE(AcpiGetHandle(handle, path, &hdl))) 1963 return false; 1964 1965 if (ACPI_FAILURE(AcpiGetType(hdl, &typ))) 1966 return false; 1967 1968 if (typ != ACPI_TYPE_METHOD && typ != type) 1969 return false; 1970 1971 return true; 1972 } 1973 1974 /* 1975 * acpidisp_eval_package: 1976 * 1977 * Evaluate a package (with an expected minimum number of elements). 1978 * Caller must free *pkg by ACPI_FREE(). 1979 */ 1980 static ACPI_STATUS 1981 acpidisp_eval_package(ACPI_HANDLE handle, const char *path, ACPI_OBJECT **pkg, 1982 unsigned int mincount) 1983 { 1984 ACPI_BUFFER buf; 1985 ACPI_OBJECT *obj; 1986 ACPI_STATUS rv; 1987 1988 rv = acpi_eval_struct(handle, path, &buf); 1989 if (ACPI_FAILURE(rv)) 1990 return rv; 1991 1992 if (buf.Length == 0 || buf.Pointer == NULL) 1993 return AE_NULL_OBJECT; 1994 1995 obj = buf.Pointer; 1996 1997 if (obj->Type != ACPI_TYPE_PACKAGE) { 1998 ACPI_FREE(obj); 1999 return AE_TYPE; 2000 } 2001 2002 if (obj->Package.Count < mincount) { 2003 ACPI_FREE(obj); 2004 return AE_BAD_DATA; 2005 } 2006 2007 *pkg = obj; 2008 return rv; 2009 } 2010 2011 /* 2012 * acpidisp_array_search: 2013 * 2014 * Look for a value v in a sorted array a of n integers (n > 0). Fill *l 2015 * and *u as follows: 2016 * 2017 * *l = Max {a[i] | a[i] <= v or i = 0} 2018 * *u = Min {a[i] | a[i] >= v or i = n-1} 2019 */ 2020 static void 2021 acpidisp_array_search(const uint8_t *a, uint16_t n, int v, uint8_t *l, uint8_t *u) 2022 { 2023 uint16_t i, j, m; 2024 2025 if (v <= a[0]) { 2026 *l = a[0]; 2027 *u = a[0]; 2028 return; 2029 } 2030 if (v >= a[n-1]) { 2031 *l = a[n-1]; 2032 *u = a[n-1]; 2033 return; 2034 } 2035 2036 for (i = 0, j = n - 1; j - i > 1; ) { 2037 m = (i + j) / 2; 2038 2039 if (a[m] == v) { 2040 *l = v; 2041 *u = v; 2042 return; 2043 } 2044 2045 if (a[m] < v) 2046 i = m; 2047 else 2048 j = m; 2049 } 2050 2051 /* Here a[i] < v < a[j] and j = i + 1. */ 2052 *l = a[i]; 2053 *u = a[j]; 2054 return; 2055 } 2056 2057 MODULE(MODULE_CLASS_DRIVER, acpivga, NULL); 2058 2059 #ifdef _MODULE 2060 #include "ioconf.c" 2061 #endif 2062 2063 static int 2064 acpivga_modcmd(modcmd_t cmd, void *aux) 2065 { 2066 int rv = 0; 2067 2068 switch (cmd) { 2069 2070 case MODULE_CMD_INIT: 2071 2072 #ifdef _MODULE 2073 rv = config_init_component(cfdriver_ioconf_acpivga, 2074 cfattach_ioconf_acpivga, cfdata_ioconf_acpivga); 2075 #endif 2076 break; 2077 2078 case MODULE_CMD_FINI: 2079 2080 #ifdef _MODULE 2081 rv = config_fini_component(cfdriver_ioconf_acpivga, 2082 cfattach_ioconf_acpivga, cfdata_ioconf_acpivga); 2083 #endif 2084 break; 2085 2086 default: 2087 rv = ENOTTY; 2088 } 2089 2090 return rv; 2091 } 2092