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