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