1 /* $OpenBSD: acpivideo.c,v 1.14 2022/04/06 18:59:27 naddy Exp $ */
2 /*
3 * Copyright (c) 2008 Federico G. Schwindt <fgsch@openbsd.org>
4 * Copyright (c) 2009 Paul Irofti <paul@irofti.net>
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 const 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
acpivideo_match(struct device * parent,void * match,void * aux)69 acpivideo_match(struct device *parent, void *match, void *aux)
70 {
71 struct acpi_attach_args *aaa = aux;
72 struct cfdata *cf = match;
73
74 if (aaa->aaa_name == NULL || strcmp(aaa->aaa_name,
75 cf->cf_driver->cd_name) != 0 || aaa->aaa_table != NULL)
76 return (0);
77
78 return (1);
79 }
80
81 void
acpivideo_attach(struct device * parent,struct device * self,void * aux)82 acpivideo_attach(struct device *parent, struct device *self, void *aux)
83 {
84 struct acpivideo_softc *sc = (struct acpivideo_softc *)self;
85 struct acpi_attach_args *aaa = aux;
86
87 sc->sc_acpi = (struct acpi_softc *)parent;
88 sc->sc_devnode = aaa->aaa_node;
89
90 printf(": %s\n", sc->sc_devnode->name);
91
92 if (acpivideo_getpcibus(sc, sc->sc_devnode) == -1)
93 return;
94
95 aml_register_notify(sc->sc_devnode, aaa->aaa_dev,
96 acpivideo_notify, sc, ACPIDEV_NOPOLL);
97
98 acpivideo_set_policy(sc,
99 DOS_SWITCH_BY_OSPM | DOS_BRIGHTNESS_BY_OSPM);
100
101 aml_find_node(aaa->aaa_node, "_BCL", acpi_foundvout, sc);
102 }
103
104 int
acpivideo_notify(struct aml_node * node,int notify,void * arg)105 acpivideo_notify(struct aml_node *node, int notify, void *arg)
106 {
107 struct acpivideo_softc *sc = arg;
108
109 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 printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
119 break;
120 }
121
122 return (0);
123 }
124
125 void
acpivideo_set_policy(struct acpivideo_softc * sc,int policy)126 acpivideo_set_policy(struct acpivideo_softc *sc, int policy)
127 {
128 struct aml_value args, res;
129
130 memset(&args, 0, sizeof(args));
131 args.v_integer = policy;
132 args.type = AML_OBJTYPE_INTEGER;
133
134 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 aml_freevalue(&res);
138 }
139
140 int
acpi_foundvout(struct aml_node * node,void * arg)141 acpi_foundvout(struct aml_node *node, void *arg)
142 {
143 struct acpivideo_softc *sc = (struct acpivideo_softc *)arg;
144 struct device *self = (struct device *)arg;
145 struct acpi_attach_args aaa;
146 node = node->parent;
147
148 DPRINTF(("Inside acpi_foundvout()\n"));
149 if (node->parent != sc->sc_devnode)
150 return (0);
151
152 if (aml_searchname(node, "_BCM")) {
153 memset(&aaa, 0, sizeof(aaa));
154 aaa.aaa_iot = sc->sc_acpi->sc_iot;
155 aaa.aaa_memt = sc->sc_acpi->sc_memt;
156 aaa.aaa_node = node;
157 aaa.aaa_name = "acpivout";
158
159 config_found(self, &aaa, acpivideo_print);
160 }
161
162 return (0);
163 }
164
165 int
acpivideo_print(void * aux,const char * pnp)166 acpivideo_print(void *aux, const char *pnp)
167 {
168 struct acpi_attach_args *aa = aux;
169
170 if (pnp) {
171 if (aa->aaa_name)
172 printf("%s at %s", aa->aaa_name, pnp);
173 else
174 return (QUIET);
175 }
176
177 return (UNCONF);
178 }
179
180 int
acpivideo_getpcibus(struct acpivideo_softc * sc,struct aml_node * node)181 acpivideo_getpcibus(struct acpivideo_softc *sc, struct aml_node *node)
182 {
183 /* Check if parent device has PCI mapping */
184 return (node->parent && node->parent->pci) ?
185 node->parent->pci->sub : -1;
186 }
187