Line data Source code
1 : /* $OpenBSD: acpivideo.c,v 1.11 2017/06/30 06:25:29 mlarkin Exp $ */
2 : /*
3 : * Copyright (c) 2008 Federico G. Schwindt <fgsch@openbsd.org>
4 : * Copyright (c) 2009 Paul Irofti <pirofti@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and/or distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : #include <sys/param.h>
20 : #include <sys/systm.h>
21 : #include <sys/device.h>
22 :
23 : #include <machine/bus.h>
24 :
25 : #include <dev/acpi/acpivar.h>
26 : #include <dev/acpi/acpidev.h>
27 : #include <dev/acpi/amltypes.h>
28 : #include <dev/acpi/dsdt.h>
29 :
30 : #ifdef ACPIVIDEO_DEBUG
31 : #define DPRINTF(x) printf x
32 : #else
33 : #define DPRINTF(x)
34 : #endif
35 :
36 : /* _DOS Enable/Disable Output Switching */
37 : #define DOS_SWITCH_BY_OSPM 0
38 : #define DOS_SWITCH_BY_BIOS 1
39 : #define DOS_SWITCH_LOCKED 2
40 : #define DOS_SWITCH_BY_OSPM_EXT 3
41 : #define DOS_BRIGHTNESS_BY_OSPM 4
42 :
43 : /* Notifications for Displays Devices */
44 : #define NOTIFY_OUTPUT_SWITCHED 0x80
45 : #define NOTIFY_OUTPUT_CHANGED 0x81
46 : #define NOTIFY_OUTPUT_CYCLE_KEY 0x82
47 : #define NOTIFY_OUTPUT_NEXT_KEY 0x83
48 : #define NOTIFY_OUTPUT_PREV_KEY 0x84
49 :
50 : int acpivideo_match(struct device *, void *, void *);
51 : void acpivideo_attach(struct device *, struct device *, void *);
52 : int acpivideo_notify(struct aml_node *, int, void *);
53 :
54 : void acpivideo_set_policy(struct acpivideo_softc *, int);
55 : int acpi_foundvout(struct aml_node *, void *);
56 : int acpivideo_print(void *, const char *);
57 :
58 : int acpivideo_getpcibus(struct acpivideo_softc *, struct aml_node *);
59 :
60 : struct cfattach acpivideo_ca = {
61 : sizeof(struct acpivideo_softc), acpivideo_match, acpivideo_attach
62 : };
63 :
64 : struct cfdriver acpivideo_cd = {
65 : NULL, "acpivideo", DV_DULL
66 : };
67 :
68 : int
69 0 : acpivideo_match(struct device *parent, void *match, void *aux)
70 : {
71 0 : struct acpi_attach_args *aaa = aux;
72 0 : struct cfdata *cf = match;
73 :
74 0 : if (aaa->aaa_name == NULL || strcmp(aaa->aaa_name,
75 0 : cf->cf_driver->cd_name) != 0 || aaa->aaa_table != NULL)
76 0 : return (0);
77 :
78 0 : return (1);
79 0 : }
80 :
81 : void
82 0 : acpivideo_attach(struct device *parent, struct device *self, void *aux)
83 : {
84 0 : struct acpivideo_softc *sc = (struct acpivideo_softc *)self;
85 0 : struct acpi_attach_args *aaa = aux;
86 :
87 0 : sc->sc_acpi = (struct acpi_softc *)parent;
88 0 : sc->sc_devnode = aaa->aaa_node;
89 :
90 0 : printf(": %s\n", sc->sc_devnode->name);
91 :
92 0 : if (acpivideo_getpcibus(sc, sc->sc_devnode) == -1)
93 0 : return;
94 :
95 0 : aml_register_notify(sc->sc_devnode, aaa->aaa_dev,
96 0 : acpivideo_notify, sc, ACPIDEV_NOPOLL);
97 :
98 0 : acpivideo_set_policy(sc,
99 : DOS_SWITCH_BY_OSPM | DOS_BRIGHTNESS_BY_OSPM);
100 :
101 0 : aml_find_node(aaa->aaa_node, "_BCL", acpi_foundvout, sc);
102 0 : }
103 :
104 : int
105 0 : acpivideo_notify(struct aml_node *node, int notify, void *arg)
106 : {
107 0 : struct acpivideo_softc *sc = arg;
108 :
109 0 : switch (notify) {
110 : case NOTIFY_OUTPUT_SWITCHED:
111 : case NOTIFY_OUTPUT_CHANGED:
112 : case NOTIFY_OUTPUT_CYCLE_KEY:
113 : case NOTIFY_OUTPUT_NEXT_KEY:
114 : case NOTIFY_OUTPUT_PREV_KEY:
115 : DPRINTF(("%s: event 0x%02x\n", DEVNAME(sc), notify));
116 : break;
117 : default:
118 0 : printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
119 0 : break;
120 : }
121 :
122 0 : return (0);
123 : }
124 :
125 : void
126 0 : acpivideo_set_policy(struct acpivideo_softc *sc, int policy)
127 : {
128 0 : struct aml_value args, res;
129 :
130 0 : memset(&args, 0, sizeof(args));
131 0 : args.v_integer = policy;
132 0 : args.type = AML_OBJTYPE_INTEGER;
133 :
134 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "_DOS", 1, &args, &res);
135 : DPRINTF(("%s: set policy to %lld\n", DEVNAME(sc), aml_val2int(&res)));
136 :
137 0 : aml_freevalue(&res);
138 0 : }
139 :
140 : int
141 0 : acpi_foundvout(struct aml_node *node, void *arg)
142 : {
143 0 : struct acpivideo_softc *sc = (struct acpivideo_softc *)arg;
144 0 : struct device *self = (struct device *)arg;
145 0 : struct acpi_attach_args aaa;
146 0 : node = node->parent;
147 :
148 : DPRINTF(("Inside acpi_foundvout()\n"));
149 0 : if (node->parent != sc->sc_devnode)
150 0 : return (0);
151 :
152 0 : if (aml_searchname(node, "_BCM") && aml_searchname(node, "_BQC")) {
153 0 : memset(&aaa, 0, sizeof(aaa));
154 0 : aaa.aaa_iot = sc->sc_acpi->sc_iot;
155 0 : aaa.aaa_memt = sc->sc_acpi->sc_memt;
156 0 : aaa.aaa_node = node;
157 0 : aaa.aaa_name = "acpivout";
158 :
159 0 : config_found(self, &aaa, acpivideo_print);
160 0 : }
161 :
162 0 : return (0);
163 0 : }
164 :
165 : int
166 0 : acpivideo_print(void *aux, const char *pnp)
167 : {
168 0 : struct acpi_attach_args *aa = aux;
169 :
170 0 : if (pnp) {
171 0 : if (aa->aaa_name)
172 0 : printf("%s at %s", aa->aaa_name, pnp);
173 : else
174 0 : return (QUIET);
175 0 : }
176 :
177 0 : return (UNCONF);
178 0 : }
179 :
180 : int
181 0 : acpivideo_getpcibus(struct acpivideo_softc *sc, struct aml_node *node)
182 : {
183 : /* Check if parent device has PCI mapping */
184 0 : return (node->parent && node->parent->pci) ?
185 0 : node->parent->pci->sub : -1;
186 : }
|