xref: /openbsd/sys/dev/acpi/acpivideo.c (revision 471aeecf)
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