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