1 /* $NetBSD: acpi_display.c,v 1.10 2012/06/02 21:36:43 dsl 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.10 2012/06/02 21:36:43 dsl 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, "hw", NULL, 1115 NULL, 0, NULL, 0, 1116 CTL_HW, CTL_EOL)) != 0) 1117 goto fail; 1118 1119 if ((sysctl_createv(&asc->sc_log, 0, &rnode, &rnode, 1120 0, CTLTYPE_NODE, "acpi", NULL, 1121 NULL, 0, NULL, 0, 1122 CTL_CREATE, CTL_EOL)) != 0) 1123 goto fail; 1124 1125 if ((sysctl_createv(&asc->sc_log, 0, &rnode, &rnode, 1126 0, CTLTYPE_NODE, device_xname(asc->sc_dev), 1127 SYSCTL_DESCR("ACPI display adapter controls"), 1128 NULL, 0, NULL, 0, 1129 CTL_CREATE, CTL_EOL)) != 0) 1130 goto fail; 1131 1132 #ifdef ACPI_DEBUG 1133 (void)sysctl_createv(&asc->sc_log, 0, &rnode, NULL, 1134 CTLFLAG_READWRITE | CTLFLAG_HEX, CTLTYPE_INT, "bios_policy", 1135 SYSCTL_DESCR("Current BIOS switch policies (debug)"), 1136 acpidisp_vga_sysctl_policy, 0, (void *)asc, 0, 1137 CTL_CREATE, CTL_EOL); 1138 #endif 1139 1140 (void)sysctl_createv(&asc->sc_log, 0, &rnode, NULL, 1141 CTLFLAG_READWRITE, CTLTYPE_BOOL, "bios_switch", 1142 SYSCTL_DESCR("Current BIOS output switching policy"), 1143 acpidisp_vga_sysctl_policy_output, 0, (void *)asc, 0, 1144 CTL_CREATE, CTL_EOL); 1145 } 1146 1147 return; 1148 1149 fail: 1150 aprint_error_dev(asc->sc_dev, "couldn't add sysctl nodes\n"); 1151 } 1152 1153 static void 1154 acpidisp_out_sysctl_setup(struct acpidisp_out_softc *osc) 1155 { 1156 const struct sysctlnode *rnode; 1157 1158 #ifdef ACPI_DISP_SWITCH_SYSCTLS 1159 if ((osc->sc_brctl != NULL) || 1160 (osc->sc_caps & ACPI_DISP_OUT_CAP__DCS) || 1161 (osc->sc_caps & ACPI_DISP_OUT_CAP__DGS)) { 1162 #else 1163 if (osc->sc_brctl != NULL) { 1164 #endif 1165 if ((sysctl_createv(&osc->sc_log, 0, NULL, &rnode, 1166 0, CTLTYPE_NODE, "hw", NULL, 1167 NULL, 0, NULL, 0, 1168 CTL_HW, CTL_EOL)) != 0) 1169 goto fail; 1170 1171 if ((sysctl_createv(&osc->sc_log, 0, &rnode, &rnode, 1172 0, CTLTYPE_NODE, "acpi", NULL, 1173 NULL, 0, NULL, 0, 1174 CTL_CREATE, CTL_EOL)) != 0) 1175 goto fail; 1176 1177 if ((sysctl_createv(&osc->sc_log, 0, &rnode, &rnode, 1178 0, CTLTYPE_NODE, device_xname(osc->sc_dev), 1179 SYSCTL_DESCR("ACPI display output device controls"), 1180 NULL, 0, NULL, 0, 1181 CTL_CREATE, CTL_EOL)) != 0) 1182 goto fail; 1183 } 1184 1185 if (osc->sc_brctl != NULL) { 1186 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1187 CTLFLAG_READWRITE, CTLTYPE_INT, "brightness", 1188 SYSCTL_DESCR("Current brightness level"), 1189 acpidisp_out_sysctl_brightness, 0, (void *)osc, 0, 1190 CTL_CREATE, CTL_EOL); 1191 } 1192 1193 #ifdef ACPI_DISP_SWITCH_SYSCTLS 1194 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DCS) { 1195 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1196 CTLFLAG_READONLY | CTLFLAG_HEX, CTLTYPE_INT, "status", 1197 SYSCTL_DESCR("Current status"), 1198 acpidisp_out_sysctl_status, 0, (void *)osc, 0, 1199 CTL_CREATE, CTL_EOL); 1200 } 1201 1202 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DGS) { 1203 int access; 1204 1205 if (osc->sc_caps & ACPI_DISP_OUT_CAP__DSS) 1206 access = CTLFLAG_READWRITE; 1207 else 1208 access = CTLFLAG_READONLY; 1209 1210 (void)sysctl_createv(&osc->sc_log, 0, &rnode, NULL, 1211 access | CTLFLAG_HEX, CTLTYPE_INT, "state", 1212 SYSCTL_DESCR("Next state (active or inactive)"), 1213 acpidisp_out_sysctl_state, 0, (void *)osc, 0, 1214 CTL_CREATE, CTL_EOL); 1215 } 1216 #endif 1217 1218 return; 1219 1220 fail: 1221 aprint_error_dev(osc->sc_dev, "couldn't add sysctl nodes\n"); 1222 } 1223 1224 /* 1225 * Sysctl callbacks. 1226 */ 1227 1228 #ifdef ACPI_DEBUG 1229 static int 1230 acpidisp_vga_sysctl_policy(SYSCTLFN_ARGS) 1231 { 1232 struct sysctlnode node; 1233 struct acpidisp_vga_softc *asc; 1234 uint32_t val; 1235 int error; 1236 1237 node = *rnode; 1238 asc = node.sysctl_data; 1239 1240 mutex_enter(&asc->sc_mtx); 1241 val = (uint32_t)asc->sc_policy.raw; 1242 mutex_exit(&asc->sc_mtx); 1243 1244 node.sysctl_data = &val; 1245 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1246 if (error || newp == NULL) 1247 return error; 1248 1249 if (val > 0x7) 1250 return EINVAL; 1251 1252 mutex_enter(&asc->sc_mtx); 1253 asc->sc_policy.raw = (uint8_t)val; 1254 error = acpidisp_set_policy(asc, asc->sc_policy.raw); 1255 mutex_exit(&asc->sc_mtx); 1256 1257 return error; 1258 } 1259 #endif 1260 1261 static int 1262 acpidisp_vga_sysctl_policy_output(SYSCTLFN_ARGS) 1263 { 1264 struct sysctlnode node; 1265 struct acpidisp_vga_softc *asc; 1266 bool val; 1267 int error; 1268 1269 node = *rnode; 1270 asc = node.sysctl_data; 1271 1272 mutex_enter(&asc->sc_mtx); 1273 val = (asc->sc_policy.fmt.output == ACPI_DISP_POLICY_OUTPUT_AUTO); 1274 mutex_exit(&asc->sc_mtx); 1275 1276 node.sysctl_data = &val; 1277 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1278 if (error || newp == NULL) 1279 return error; 1280 1281 mutex_enter(&asc->sc_mtx); 1282 if (val) 1283 asc->sc_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_AUTO; 1284 else 1285 asc->sc_policy.fmt.output = ACPI_DISP_POLICY_OUTPUT_NORMAL; 1286 error = acpidisp_set_policy(asc, asc->sc_policy.raw); 1287 mutex_exit(&asc->sc_mtx); 1288 1289 return error; 1290 } 1291 1292 #ifdef ACPI_DISP_SWITCH_SYSCTLS 1293 static int 1294 acpidisp_out_sysctl_status(SYSCTLFN_ARGS) 1295 { 1296 struct sysctlnode node; 1297 struct acpidisp_out_softc *osc; 1298 uint32_t val; 1299 int error; 1300 1301 node = *rnode; 1302 osc = node.sysctl_data; 1303 1304 mutex_enter(osc->sc_mtx); 1305 error = acpidisp_get_status(osc, &val); 1306 mutex_exit(osc->sc_mtx); 1307 1308 if (error) 1309 return error; 1310 1311 node.sysctl_data = &val; 1312 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1313 if (error || newp == NULL) 1314 return error; 1315 1316 return 0; 1317 } 1318 1319 static int 1320 acpidisp_out_sysctl_state(SYSCTLFN_ARGS) 1321 { 1322 struct sysctlnode node; 1323 struct acpidisp_out_softc *osc; 1324 uint32_t val; 1325 int error; 1326 1327 node = *rnode; 1328 osc = node.sysctl_data; 1329 1330 mutex_enter(osc->sc_mtx); 1331 error = acpidisp_get_state(osc, &val); 1332 mutex_exit(osc->sc_mtx); 1333 1334 if (error) 1335 return error; 1336 1337 node.sysctl_data = &val; 1338 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1339 if (error || newp == NULL) 1340 return error; 1341 1342 mutex_enter(osc->sc_mtx); 1343 error = acpidisp_set_state(osc, val); 1344 mutex_exit(osc->sc_mtx); 1345 1346 return error; 1347 } 1348 #endif 1349 1350 static int 1351 acpidisp_out_sysctl_brightness(SYSCTLFN_ARGS) 1352 { 1353 struct sysctlnode node; 1354 struct acpidisp_out_softc *osc; 1355 struct acpidisp_brctl *bc; 1356 int val, error; 1357 uint8_t lo, up, level; 1358 1359 node = *rnode; 1360 osc = node.sysctl_data; 1361 bc = osc->sc_brctl; 1362 1363 KASSERT(bc != NULL); 1364 1365 mutex_enter(osc->sc_mtx); 1366 (void)acpidisp_get_brightness(osc, &bc->bc_current); 1367 val = (int)bc->bc_current; 1368 mutex_exit(osc->sc_mtx); 1369 1370 node.sysctl_data = &val; 1371 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1372 if (error || newp == NULL) 1373 return error; 1374 1375 acpidisp_array_search(bc->bc_level, bc->bc_level_count, val, &lo, &up); 1376 if ((lo != up) && (val - lo) < (up - val)) 1377 level = lo; 1378 else 1379 level = up; 1380 1381 mutex_enter(osc->sc_mtx); 1382 bc->bc_current = level; 1383 error = acpidisp_set_brightness(osc, bc->bc_current); 1384 mutex_exit(osc->sc_mtx); 1385 1386 return error; 1387 } 1388 1389 /* 1390 * Initialization of acpidisp_odinfo (_DOD) and acpidisp_brctl (_BCL). 1391 */ 1392 1393 /* 1394 * Regarding _DOD (ACPI 4.0a, Sec. B.4.2): 1395 * 1396 * "The _DOD method returns a list of devices attached to the graphics adapter, 1397 * along with device-specific configuration information." 1398 * 1399 * "Every child device enumerated in the ACPI namespace under the graphics 1400 * adapter must be specified in this list of devices. Each display device 1401 * must have its own ID, which is unique with respect to any other attachable 1402 * devices enumerated." 1403 * 1404 * "Return value: a package containing a variable-length list of integers, 1405 * each of which contains the 32-bit device attribute of a child device." 1406 */ 1407 1408 static struct acpidisp_odinfo * 1409 acpidisp_init_odinfo(const struct acpidisp_vga_softc *asc) 1410 { 1411 ACPI_HANDLE hdl = asc->sc_node->ad_handle; 1412 ACPI_STATUS rv; 1413 ACPI_OBJECT *pkg; 1414 struct acpidisp_odinfo *oi; 1415 struct acpidisp_outdev *devp; 1416 uint32_t count, i; 1417 1418 if (!(asc->sc_caps & ACPI_DISP_VGA_CAP__DOD)) 1419 return NULL; 1420 1421 oi = NULL; 1422 pkg = NULL; 1423 1424 rv = acpidisp_eval_package(hdl, "_DOD", &pkg, 1); 1425 if (ACPI_FAILURE(rv)) 1426 goto fail; 1427 1428 /* 1429 * Allocate and fill the struct acpidisp_odinfo to be returned. 1430 */ 1431 oi = kmem_zalloc(sizeof(*oi), KM_SLEEP); 1432 if (oi == NULL) { 1433 rv = AE_NO_MEMORY; 1434 goto fail; 1435 } 1436 1437 oi->oi_dev_count = pkg->Package.Count; 1438 1439 oi->oi_dev = kmem_zalloc(oi->oi_dev_count * sizeof(*oi->oi_dev), 1440 KM_SLEEP); 1441 if (oi->oi_dev == NULL) { 1442 rv = AE_NO_MEMORY; 1443 goto fail; 1444 } 1445 1446 /* 1447 * Fill the array oi->oi_dev. 1448 */ 1449 for (count = 0, i = 0; i < pkg->Package.Count; i++) { 1450 /* List of 32-bit integers (ACPI 4.0a, Sec. B.4.2). */ 1451 if (pkg->Package.Elements[i].Type != ACPI_TYPE_INTEGER || 1452 pkg->Package.Elements[i].Integer.Value > UINT32_MAX) 1453 continue; 1454 1455 oi->oi_dev[count].od_attrs.raw = 1456 (uint32_t)pkg->Package.Elements[i].Integer.Value; 1457 count++; 1458 } 1459 1460 if (count == 0) { 1461 rv = AE_BAD_DATA; 1462 goto fail; 1463 } 1464 1465 ACPI_FREE(pkg); 1466 pkg = NULL; 1467 1468 /* 1469 * Resize the array oi->oi_dev if needed. 1470 */ 1471 if (count < oi->oi_dev_count) { 1472 devp = kmem_alloc(count * sizeof(*devp), KM_SLEEP); 1473 if (devp == NULL) { 1474 rv = AE_NO_MEMORY; 1475 goto fail; 1476 } 1477 1478 (void)memcpy(devp, oi->oi_dev, count * sizeof(*devp)); 1479 kmem_free(oi->oi_dev, oi->oi_dev_count * sizeof(*oi->oi_dev)); 1480 1481 oi->oi_dev = devp; 1482 oi->oi_dev_count = count; 1483 } 1484 1485 return oi; 1486 1487 fail: 1488 aprint_error_dev(asc->sc_dev, "failed to evaluate %s.%s: %s\n", 1489 acpi_name(hdl), "_DOD", AcpiFormatException(rv)); 1490 if (pkg != NULL) 1491 ACPI_FREE(pkg); 1492 if (oi != NULL) { 1493 if (oi->oi_dev != NULL) 1494 kmem_free(oi->oi_dev, 1495 oi->oi_dev_count * sizeof(*oi->oi_dev)); 1496 kmem_free(oi, sizeof(*oi)); 1497 } 1498 return NULL; 1499 } 1500 1501 /* 1502 * acpidisp_vga_bind_outdevs: 1503 * 1504 * Bind each acpiout device attached under an acpivga device to the 1505 * corresponding (_DOD enumerated) connected output device. 1506 */ 1507 static void 1508 acpidisp_vga_bind_outdevs(struct acpidisp_vga_softc *asc) 1509 { 1510 struct acpidisp_odinfo *oi = asc->sc_odinfo; 1511 struct acpidisp_out_softc *osc; 1512 struct acpidisp_outdev *od; 1513 struct acpi_devnode *ad; 1514 ACPI_HANDLE hdl; 1515 ACPI_INTEGER val; 1516 ACPI_STATUS rv; 1517 uint16_t devid; 1518 uint32_t i; 1519 1520 KASSERT(oi != NULL); 1521 1522 /* Reset all bindings. */ 1523 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) 1524 od->od_device = NULL; 1525 1526 /* 1527 * Iterate over all ACPI children that have been attached under this 1528 * acpivga device (as acpiout devices). 1529 */ 1530 SIMPLEQ_FOREACH(ad, &asc->sc_node->ad_child_head, ad_child_list) { 1531 if ((ad->ad_device == NULL) || 1532 (device_parent(ad->ad_device) != asc->sc_dev)) 1533 continue; 1534 1535 KASSERT(device_is_a(ad->ad_device, "acpiout")); 1536 1537 osc = device_private(ad->ad_device); 1538 1539 /* 1540 * For display output devices, the method _ADR returns 1541 * the device's ID (ACPI 4.0a, Sec. B.6.1). We do not 1542 * cache the result of _ADR since it may vary. 1543 */ 1544 hdl = osc->sc_node->ad_handle; 1545 rv = acpi_eval_integer(hdl, "_ADR", &val); 1546 if (ACPI_FAILURE(rv)) { 1547 aprint_error_dev(asc->sc_dev, 1548 "failed to evaluate %s.%s: %s\n", 1549 acpi_name(hdl), "_ADR", AcpiFormatException(rv)); 1550 continue; 1551 } 1552 1553 /* The device ID is a 16-bit integer (ACPI 4.0a, Table B-2). */ 1554 devid = (uint16_t)val; 1555 1556 /* 1557 * The device ID must be unique (among output devices), and must 1558 * appear in the list returned by _DOD (ACPI 4.0a, Sec. B.6.1). 1559 */ 1560 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 1561 if (devid == od->od_attrs.device_id) { 1562 if (od->od_device != NULL) 1563 aprint_error_dev(asc->sc_dev, 1564 "%s has same device ID as %s\n", 1565 device_xname(osc->sc_dev), 1566 device_xname(od->od_device)); 1567 else 1568 od->od_device = osc->sc_dev; 1569 break; 1570 } 1571 } 1572 if (i == oi->oi_dev_count) 1573 aprint_error_dev(asc->sc_dev, 1574 "unknown output device %s\n", 1575 device_xname(osc->sc_dev)); 1576 } 1577 } 1578 1579 /* 1580 * Regarding _BCL (ACPI 4.0a, Sec. B.6.2): 1581 * 1582 * "This method allows the OS to query a list of brightness levels supported by 1583 * built-in display output devices." 1584 * 1585 * "Return value: a variable-length package containing a list of integers 1586 * representing the supported brightness levels. Each integer has 8 bits of 1587 * significant data." 1588 */ 1589 1590 static struct acpidisp_brctl * 1591 acpidisp_init_brctl(const struct acpidisp_out_softc *osc) 1592 { 1593 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1594 ACPI_STATUS rv; 1595 ACPI_OBJECT *pkg; 1596 struct acpidisp_brctl *bc; 1597 uint8_t *levelp; 1598 uint32_t i; 1599 int32_t j; 1600 uint16_t count, k; 1601 uint8_t level; 1602 1603 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BCL)) 1604 return NULL; 1605 1606 bc = NULL; 1607 pkg = NULL; 1608 1609 rv = acpidisp_eval_package(hdl, "_BCL", &pkg, 2); 1610 if (ACPI_FAILURE(rv)) 1611 goto fail; 1612 1613 /* 1614 * Allocate and fill the struct acpidisp_brctl to be returned. 1615 */ 1616 bc = kmem_zalloc(sizeof(*bc), KM_SLEEP); 1617 if (bc == NULL) { 1618 rv = AE_NO_MEMORY; 1619 goto fail; 1620 } 1621 1622 /* At most 256 brightness levels (8-bit integers). */ 1623 if (pkg->Package.Count > 256) 1624 bc->bc_level_count = 256; 1625 else 1626 bc->bc_level_count = (uint16_t)pkg->Package.Count; 1627 1628 bc->bc_level = kmem_zalloc(bc->bc_level_count * sizeof(*bc->bc_level), 1629 KM_SLEEP); 1630 if (bc->bc_level == NULL) { 1631 rv = AE_NO_MEMORY; 1632 goto fail; 1633 } 1634 1635 /* 1636 * Fill the array bc->bc_level with an insertion sort. 1637 */ 1638 for (count = 0, i = 0; i < pkg->Package.Count; i++) { 1639 /* List of 8-bit integers (ACPI 4.0a, Sec. B.6.2). */ 1640 if (pkg->Package.Elements[i].Type != ACPI_TYPE_INTEGER || 1641 pkg->Package.Elements[i].Integer.Value > UINT8_MAX) 1642 continue; 1643 1644 level = (uint8_t)pkg->Package.Elements[i].Integer.Value; 1645 1646 /* Find the correct slot but do not modify the array yet. */ 1647 for (j = count; --j >= 0 && bc->bc_level[j] > level; ); 1648 if (j >= 0 && bc->bc_level[j] == level) 1649 continue; 1650 j++; 1651 1652 /* Make room for the new level. */ 1653 for (k = count; k > j; k--) 1654 bc->bc_level[k] = bc->bc_level[k-1]; 1655 1656 /* Insert the new level. */ 1657 bc->bc_level[j] = level; 1658 count++; 1659 } 1660 1661 if (count == 0) { 1662 rv = AE_BAD_DATA; 1663 goto fail; 1664 } 1665 1666 ACPI_FREE(pkg); 1667 pkg = NULL; 1668 1669 /* 1670 * Resize the array bc->bc_level if needed. 1671 */ 1672 if (count < bc->bc_level_count) { 1673 levelp = kmem_alloc(count * sizeof(*levelp), KM_SLEEP); 1674 if (levelp == NULL) { 1675 rv = AE_NO_MEMORY; 1676 goto fail; 1677 } 1678 1679 (void)memcpy(levelp, bc->bc_level, count * sizeof(*levelp)); 1680 kmem_free(bc->bc_level, 1681 bc->bc_level_count * sizeof(*bc->bc_level)); 1682 1683 bc->bc_level = levelp; 1684 bc->bc_level_count = count; 1685 } 1686 1687 return bc; 1688 1689 fail: 1690 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1691 acpi_name(hdl), "_BCL", AcpiFormatException(rv)); 1692 if (pkg != NULL) 1693 ACPI_FREE(pkg); 1694 if (bc != NULL) { 1695 if (bc->bc_level != NULL) 1696 kmem_free(bc->bc_level, 1697 bc->bc_level_count * sizeof(*bc->bc_level)); 1698 kmem_free(bc, sizeof(*bc)); 1699 } 1700 return NULL; 1701 } 1702 1703 /* 1704 * Evaluation of simple ACPI display methods. 1705 */ 1706 1707 static int 1708 acpidisp_set_policy(const struct acpidisp_vga_softc *asc, uint8_t value) 1709 { 1710 ACPI_HANDLE hdl = asc->sc_node->ad_handle; 1711 ACPI_INTEGER val; 1712 ACPI_STATUS rv; 1713 1714 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: 0x%"PRIx8"\n", 1715 device_xname(asc->sc_dev), "policy", value)); 1716 1717 if (!(asc->sc_caps & ACPI_DISP_VGA_CAP__DOS)) 1718 return ENODEV; 1719 1720 val = (ACPI_INTEGER)value; 1721 rv = acpi_eval_set_integer(hdl, "_DOS", val); 1722 if (ACPI_FAILURE(rv)) { 1723 aprint_error_dev(asc->sc_dev, "failed to evaluate %s.%s: %s\n", 1724 acpi_name(hdl), "_DOS", AcpiFormatException(rv)); 1725 return EIO; 1726 } 1727 1728 return 0; 1729 } 1730 1731 static int 1732 acpidisp_get_status(const struct acpidisp_out_softc *osc, uint32_t *valuep) 1733 { 1734 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1735 ACPI_INTEGER val; 1736 ACPI_STATUS rv; 1737 1738 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DCS)) 1739 return ENODEV; 1740 1741 rv = acpi_eval_integer(hdl, "_DCS", &val); 1742 if (ACPI_FAILURE(rv)) { 1743 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1744 acpi_name(hdl), "_DCS", AcpiFormatException(rv)); 1745 return EIO; 1746 } 1747 1748 if (val > UINT32_MAX) 1749 return ERANGE; 1750 1751 *valuep = (uint32_t)val; 1752 1753 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: 0x%"PRIx32"\n", 1754 device_xname(osc->sc_dev), "status", *valuep)); 1755 1756 return 0; 1757 } 1758 1759 static int 1760 acpidisp_get_state(const struct acpidisp_out_softc *osc, uint32_t *valuep) 1761 { 1762 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1763 ACPI_INTEGER val; 1764 ACPI_STATUS rv; 1765 1766 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DGS)) 1767 return ENODEV; 1768 1769 rv = acpi_eval_integer(hdl, "_DGS", &val); 1770 if (ACPI_FAILURE(rv)) { 1771 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1772 acpi_name(hdl), "_DGS", AcpiFormatException(rv)); 1773 return EIO; 1774 } 1775 1776 if (val > UINT32_MAX) 1777 return ERANGE; 1778 1779 *valuep = (uint32_t)val; 1780 1781 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: 0x%"PRIx32"\n", 1782 device_xname(osc->sc_dev), "state", *valuep)); 1783 1784 return 0; 1785 } 1786 1787 static int 1788 acpidisp_set_state(const struct acpidisp_out_softc *osc, uint32_t value) 1789 { 1790 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1791 ACPI_INTEGER val; 1792 ACPI_STATUS rv; 1793 1794 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: 0x%"PRIx32"\n", 1795 device_xname(osc->sc_dev), "state", value)); 1796 1797 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__DSS)) 1798 return ENODEV; 1799 1800 val = (ACPI_INTEGER)value; 1801 rv = acpi_eval_set_integer(hdl, "_DSS", val); 1802 if (ACPI_FAILURE(rv)) { 1803 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1804 acpi_name(hdl), "_DSS", AcpiFormatException(rv)); 1805 return EIO; 1806 } 1807 1808 return 0; 1809 } 1810 1811 static int 1812 acpidisp_get_brightness(const struct acpidisp_out_softc *osc, uint8_t *valuep) 1813 { 1814 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1815 ACPI_INTEGER val; 1816 ACPI_STATUS rv; 1817 1818 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BQC)) 1819 return ENODEV; 1820 1821 rv = acpi_eval_integer(hdl, "_BQC", &val); 1822 if (ACPI_FAILURE(rv)) { 1823 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1824 acpi_name(hdl), "_BQC", AcpiFormatException(rv)); 1825 return EIO; 1826 } 1827 1828 if (val > UINT8_MAX) 1829 return ERANGE; 1830 1831 *valuep = (uint8_t)val; 1832 1833 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: get %s: %"PRIu8"\n", 1834 device_xname(osc->sc_dev), "brightness", *valuep)); 1835 1836 return 0; 1837 } 1838 1839 static int 1840 acpidisp_set_brightness(const struct acpidisp_out_softc *osc, uint8_t value) 1841 { 1842 ACPI_HANDLE hdl = osc->sc_node->ad_handle; 1843 ACPI_INTEGER val; 1844 ACPI_STATUS rv; 1845 1846 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: set %s: %"PRIu8"\n", 1847 device_xname(osc->sc_dev), "brightness", value)); 1848 1849 if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BCM)) 1850 return ENODEV; 1851 1852 val = (ACPI_INTEGER)value; 1853 rv = acpi_eval_set_integer(hdl, "_BCM", val); 1854 if (ACPI_FAILURE(rv)) { 1855 aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n", 1856 acpi_name(hdl), "_BCM", AcpiFormatException(rv)); 1857 return EIO; 1858 } 1859 1860 return 0; 1861 } 1862 1863 /* 1864 * Pretty printing. 1865 */ 1866 1867 static void 1868 acpidisp_print_odinfo(device_t self, const struct acpidisp_odinfo *oi) 1869 { 1870 struct acpidisp_outdev *od; 1871 uint32_t i; 1872 1873 KASSERT(oi != NULL); 1874 1875 aprint_verbose_dev(self, "connected output devices:\n"); 1876 for (i = 0, od = oi->oi_dev; i < oi->oi_dev_count; i++, od++) { 1877 aprint_verbose_dev(self, " 0x%04"PRIx16, od->od_attrs.device_id); 1878 if (od->od_device != NULL) 1879 aprint_verbose(" (%s)", device_xname(od->od_device)); 1880 aprint_verbose(": "); 1881 acpidisp_print_od_attrs(od->od_attrs); 1882 aprint_verbose("\n"); 1883 } 1884 } 1885 1886 static void 1887 acpidisp_print_brctl(device_t self, const struct acpidisp_brctl *bc) 1888 { 1889 uint16_t i; 1890 1891 KASSERT(bc != NULL); 1892 1893 aprint_verbose_dev(self, "brightness levels:"); 1894 for (i = 0; i < bc->bc_level_count; i++) 1895 aprint_verbose(" %"PRIu8, bc->bc_level[i]); 1896 aprint_verbose("\n"); 1897 } 1898 1899 static void 1900 acpidisp_print_od_attrs(acpidisp_od_attrs_t oda) 1901 { 1902 const char *type; 1903 1904 if (oda.fmt.device_id_scheme == 1) { 1905 /* Uses the device ID scheme introduced in ACPI 3.0. */ 1906 switch (oda.fmt.type) { 1907 case ACPI_DISP_OUT_ATTR_TYPE_OTHER: 1908 type = "Other"; 1909 break; 1910 case ACPI_DISP_OUT_ATTR_TYPE_VGA: 1911 type = "VGA Analog Monitor"; 1912 break; 1913 case ACPI_DISP_OUT_ATTR_TYPE_TV: 1914 type = "TV/HDTV Monitor"; 1915 break; 1916 case ACPI_DISP_OUT_ATTR_TYPE_EXTDIG: 1917 type = "Ext. Digital Monitor"; 1918 break; 1919 case ACPI_DISP_OUT_ATTR_TYPE_INTDFP: 1920 type = "Int. Digital Flat Panel"; 1921 break; 1922 default: 1923 type = "Invalid"; 1924 break; 1925 } 1926 1927 aprint_verbose("%s, index %d, port %d", 1928 type, oda.fmt.index, oda.fmt.port); 1929 } else { 1930 /* Uses vendor-specific device IDs. */ 1931 switch (oda.device_id) { 1932 case ACPI_DISP_OUT_LEGACY_DEVID_MONITOR: 1933 type = "Ext. Monitor"; 1934 break; 1935 case ACPI_DISP_OUT_LEGACY_DEVID_PANEL: 1936 type = "LCD Panel"; 1937 break; 1938 case ACPI_DISP_OUT_LEGACY_DEVID_TV: 1939 type = "TV"; 1940 break; 1941 default: 1942 type = "Unknown Output Device"; 1943 break; 1944 } 1945 1946 aprint_verbose("%s", type); 1947 } 1948 1949 aprint_verbose(", head %d", oda.fmt.head_id); 1950 if (oda.fmt.bios_detect) 1951 aprint_verbose(", bios detect"); 1952 if (oda.fmt.non_vga) 1953 aprint_verbose(", non vga"); 1954 } 1955 1956 /* 1957 * General-purpose utility functions. 1958 */ 1959 1960 /* 1961 * acpidisp_has_method: 1962 * 1963 * Returns true if and only if (a) the object handle.path exists and 1964 * (b) this object is a method or has the given type. 1965 */ 1966 static bool 1967 acpidisp_has_method(ACPI_HANDLE handle, const char *path, ACPI_OBJECT_TYPE type) 1968 { 1969 ACPI_HANDLE hdl; 1970 ACPI_OBJECT_TYPE typ; 1971 1972 KASSERT(handle != NULL); 1973 1974 if (ACPI_FAILURE(AcpiGetHandle(handle, path, &hdl))) 1975 return false; 1976 1977 if (ACPI_FAILURE(AcpiGetType(hdl, &typ))) 1978 return false; 1979 1980 if (typ != ACPI_TYPE_METHOD && typ != type) 1981 return false; 1982 1983 return true; 1984 } 1985 1986 /* 1987 * acpidisp_eval_package: 1988 * 1989 * Evaluate a package (with an expected minimum number of elements). 1990 * Caller must free *pkg by ACPI_FREE(). 1991 */ 1992 static ACPI_STATUS 1993 acpidisp_eval_package(ACPI_HANDLE handle, const char *path, ACPI_OBJECT **pkg, 1994 unsigned int mincount) 1995 { 1996 ACPI_BUFFER buf; 1997 ACPI_OBJECT *obj; 1998 ACPI_STATUS rv; 1999 2000 rv = acpi_eval_struct(handle, path, &buf); 2001 if (ACPI_FAILURE(rv)) 2002 return rv; 2003 2004 if (buf.Length == 0 || buf.Pointer == NULL) 2005 return AE_NULL_OBJECT; 2006 2007 obj = buf.Pointer; 2008 2009 if (obj->Type != ACPI_TYPE_PACKAGE) { 2010 ACPI_FREE(obj); 2011 return AE_TYPE; 2012 } 2013 2014 if (obj->Package.Count < mincount) { 2015 ACPI_FREE(obj); 2016 return AE_BAD_DATA; 2017 } 2018 2019 *pkg = obj; 2020 return rv; 2021 } 2022 2023 /* 2024 * acpidisp_array_search: 2025 * 2026 * Look for a value v in a sorted array a of n integers (n > 0). Fill *l 2027 * and *u as follows: 2028 * 2029 * *l = Max {a[i] | a[i] <= v or i = 0} 2030 * *u = Min {a[i] | a[i] >= v or i = n-1} 2031 */ 2032 static void 2033 acpidisp_array_search(const uint8_t *a, uint16_t n, int v, uint8_t *l, uint8_t *u) 2034 { 2035 uint16_t i, j, m; 2036 2037 if (v <= a[0]) { 2038 *l = a[0]; 2039 *u = a[0]; 2040 return; 2041 } 2042 if (v >= a[n-1]) { 2043 *l = a[n-1]; 2044 *u = a[n-1]; 2045 return; 2046 } 2047 2048 for (i = 0, j = n - 1; j - i > 1; ) { 2049 m = (i + j) / 2; 2050 2051 if (a[m] == v) { 2052 *l = v; 2053 *u = v; 2054 return; 2055 } 2056 2057 if (a[m] < v) 2058 i = m; 2059 else 2060 j = m; 2061 } 2062 2063 /* Here a[i] < v < a[j] and j = i + 1. */ 2064 *l = a[i]; 2065 *u = a[j]; 2066 return; 2067 } 2068 2069 MODULE(MODULE_CLASS_DRIVER, acpivga, NULL); 2070 2071 #ifdef _MODULE 2072 #include "ioconf.c" 2073 #endif 2074 2075 static int 2076 acpivga_modcmd(modcmd_t cmd, void *aux) 2077 { 2078 int rv = 0; 2079 2080 switch (cmd) { 2081 2082 case MODULE_CMD_INIT: 2083 2084 #ifdef _MODULE 2085 rv = config_init_component(cfdriver_ioconf_acpivga, 2086 cfattach_ioconf_acpivga, cfdata_ioconf_acpivga); 2087 #endif 2088 break; 2089 2090 case MODULE_CMD_FINI: 2091 2092 #ifdef _MODULE 2093 rv = config_fini_component(cfdriver_ioconf_acpivga, 2094 cfattach_ioconf_acpivga, cfdata_ioconf_acpivga); 2095 #endif 2096 break; 2097 2098 default: 2099 rv = ENOTTY; 2100 } 2101 2102 return rv; 2103 } 2104