xref: /openbsd-src/sys/dev/acpi/acpidock.c (revision 9108e412bd3927bbb0cb663c132f152da551254b)
1*9108e412Spatrick /* $OpenBSD: acpidock.c,v 1.46 2022/08/10 16:58:16 patrick Exp $ */
2f2f7c420Smk /*
3f2f7c420Smk  * Copyright (c) 2006,2007 Michael Knudsen <mk@openbsd.org>
4f2f7c420Smk  *
5f2f7c420Smk  * Permission to use, copy, modify, and distribute this software for any
6f2f7c420Smk  * purpose with or without fee is hereby granted, provided that the above
7f2f7c420Smk  * copyright notice and this permission notice appear in all copies.
8f2f7c420Smk  *
9f2f7c420Smk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10f2f7c420Smk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11f2f7c420Smk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12f2f7c420Smk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13f2f7c420Smk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14f2f7c420Smk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15f2f7c420Smk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16f2f7c420Smk  */
17f2f7c420Smk 
18f2f7c420Smk #include <sys/param.h>
19f2f7c420Smk #include <sys/systm.h>
20f2f7c420Smk #include <sys/device.h>
21f2f7c420Smk #include <sys/malloc.h>
22eee1d4f9Smk #include <sys/sensors.h>
23f2f7c420Smk 
24f2f7c420Smk #include <machine/bus.h>
25f2f7c420Smk 
26f2f7c420Smk #include <dev/acpi/acpivar.h>
27f2f7c420Smk #include <dev/acpi/acpidev.h>
28f2f7c420Smk #include <dev/acpi/amltypes.h>
29f2f7c420Smk #include <dev/acpi/dsdt.h>
30f2f7c420Smk 
312b11adf0Smk struct aml_nodelist {
322b11adf0Smk 	struct aml_node *node;
332b11adf0Smk 	TAILQ_ENTRY(aml_nodelist) entries;
342b11adf0Smk };
352b11adf0Smk 
36f2f7c420Smk int	acpidock_match(struct device *, void *, void *);
37f2f7c420Smk void	acpidock_attach(struct device *, struct device *, void *);
38f2f7c420Smk 
39471aeecfSnaddy const struct cfattach acpidock_ca = {
40f2f7c420Smk 	sizeof(struct acpidock_softc), acpidock_match, acpidock_attach
41f2f7c420Smk };
42f2f7c420Smk 
43f2f7c420Smk struct cfdriver acpidock_cd = {
44f2f7c420Smk 	NULL, "acpidock", DV_DULL
45f2f7c420Smk };
46f2f7c420Smk 
47f2f7c420Smk int	acpidock_docklock(struct acpidock_softc *, int);
48f2f7c420Smk int	acpidock_dockctl(struct acpidock_softc *, int);
49ac52191eSmk int	acpidock_eject(struct acpidock_softc *, struct aml_node *);
50f2f7c420Smk int	acpidock_notify(struct aml_node *, int, void *);
51f2f7c420Smk int	acpidock_status(struct acpidock_softc *);
52f402adeaSjordan int	acpidock_walkchildren(struct aml_node *, void *);
53f2f7c420Smk 
547979ca52Sweingart int	acpidock_foundejd(struct aml_node *, void *);
552b11adf0Smk 
56f2f7c420Smk int
acpidock_match(struct device * parent,void * match,void * aux)57f2f7c420Smk acpidock_match(struct device *parent, void *match, void *aux)
58f2f7c420Smk {
59f2f7c420Smk 	struct acpi_attach_args	 *aaa = aux;
60f2f7c420Smk 	struct cfdata		 *cf = match;
61f2f7c420Smk 
62f2f7c420Smk 	/* sanity */
63f2f7c420Smk 	if (aaa->aaa_name == NULL ||
64f2f7c420Smk 	    strcmp(aaa->aaa_name, cf->cf_driver->cd_name) != 0 ||
65f2f7c420Smk 	    aaa->aaa_table != NULL)
66f2f7c420Smk 		return (0);
67f2f7c420Smk 
68f2f7c420Smk 	return (1);
69f2f7c420Smk }
70f2f7c420Smk 
71f2f7c420Smk void
acpidock_attach(struct device * parent,struct device * self,void * aux)72f2f7c420Smk acpidock_attach(struct device *parent, struct device *self, void *aux)
73f2f7c420Smk {
74f2f7c420Smk 	struct acpidock_softc	*sc = (struct acpidock_softc *)self;
75f2f7c420Smk 	struct acpi_attach_args *aa = aux;
76f2f7c420Smk 
77f2f7c420Smk 	sc->sc_acpi = (struct acpi_softc *)parent;
783b455a03Smarco 	sc->sc_devnode = aa->aaa_node;
79f2f7c420Smk 
803b455a03Smarco 	printf(": %s", sc->sc_devnode->name);
81f2f7c420Smk 
8202694a45Smk 	acpidock_status(sc);
8302694a45Smk 	if (sc->sc_docked == ACPIDOCK_STATUS_DOCKED) {
84f2f7c420Smk 		acpidock_docklock(sc, 1);
85f2f7c420Smk 		acpidock_dockctl(sc, 1);
86f2f7c420Smk 	}
87f2f7c420Smk 
88b5c69d4aSmk 	acpidock_status(sc);
89bdc52224Sderaadt 	printf("%s docked (%d)\n",
90b5c69d4aSmk 	    sc->sc_docked == ACPIDOCK_STATUS_DOCKED ? "" : " not",
91b5c69d4aSmk 	    sc->sc_sta);
92b5c69d4aSmk 
93eee1d4f9Smk 	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
94eee1d4f9Smk 	    sizeof(sc->sc_sensdev.xname));
953ff55dfeSmk 	if (sc->sc_docked)
964ee99e23Smk 		strlcpy(sc->sc_sens.desc, "docked",
974ee99e23Smk 		    sizeof(sc->sc_sens.desc));
983ff55dfeSmk 	else
994ee99e23Smk 		strlcpy(sc->sc_sens.desc, "not docked",
1004ee99e23Smk 		    sizeof(sc->sc_sens.desc));
1013ff55dfeSmk 
1024ee99e23Smk 	sc->sc_sens.type = SENSOR_INDICATOR;
1034ee99e23Smk 	sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED;
1043cb04c65Skspillner 	sc->sc_sens.status = sc->sc_docked ? SENSOR_S_OK : SENSOR_S_UNKNOWN;
1054ee99e23Smk 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
106eee1d4f9Smk 	sensordev_install(&sc->sc_sensdev);
107eee1d4f9Smk 
1082b11adf0Smk 	TAILQ_INIT(&sc->sc_deps_h);
109*9108e412Spatrick 	aml_find_node(sc->sc_acpi->sc_root, "_EJD", acpidock_foundejd, sc);
1102b11adf0Smk 
1113b455a03Smarco 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
112f2f7c420Smk 	    acpidock_notify, sc, ACPIDEV_NOPOLL);
113f2f7c420Smk }
114f2f7c420Smk 
115f2f7c420Smk int
acpidock_status(struct acpidock_softc * sc)116f2f7c420Smk acpidock_status(struct acpidock_softc *sc)
117f2f7c420Smk {
118a95d1b72Sjordan 	int64_t			sta;
119ffd69664Smk 	int			rv;
120f2f7c420Smk 
121fd421835Sjordan 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL,
122a95d1b72Sjordan 	    &sta) != 0) {
123a95d1b72Sjordan 		sta = 0;
124f2f7c420Smk 		rv = 0;
12507675d65Sjordan 	} else
126f2f7c420Smk 		rv = 1;
127f2f7c420Smk 
128a95d1b72Sjordan 	sc->sc_sta = sta;
129ffd69664Smk 	sc->sc_docked = sc->sc_sta & STA_PRESENT;
130f2f7c420Smk 
131f2f7c420Smk 	return (rv);
132f2f7c420Smk }
133f2f7c420Smk 
134f2f7c420Smk int
acpidock_docklock(struct acpidock_softc * sc,int lock)135f2f7c420Smk acpidock_docklock(struct acpidock_softc *sc, int lock)
136f2f7c420Smk {
137f2f7c420Smk 	struct aml_value	cmd;
138f2f7c420Smk 	struct aml_value	res;
1395cc6ff0cSmk 	int			rv;
140f2f7c420Smk 
141f2f7c420Smk 	memset(&cmd, 0, sizeof cmd);
142f2f7c420Smk 	cmd.v_integer = lock;
143f2f7c420Smk 	cmd.type = AML_OBJTYPE_INTEGER;
144fe16b7bbSmk 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_LCK", 1, &cmd,
145f2f7c420Smk 	    &res) != 0) {
1463ebb5e6bSmk 		dnprintf(20, "%s: _LCK %d failed\n", DEVNAME(sc), lock);
1475cc6ff0cSmk 		rv = 0;
148f2f7c420Smk 	} else {
149ba930d8dSmk 		dnprintf(20, "%s: _LCK %d successful\n", DEVNAME(sc), lock);
1505cc6ff0cSmk 		rv = 1;
151f2f7c420Smk 	}
152f2f7c420Smk 
1535cc6ff0cSmk 	aml_freevalue(&res);
1545cc6ff0cSmk 
15507675d65Sjordan 	return (rv);
156f2f7c420Smk }
157f2f7c420Smk 
158f2f7c420Smk int
acpidock_dockctl(struct acpidock_softc * sc,int dock)159f2f7c420Smk acpidock_dockctl(struct acpidock_softc *sc, int dock)
160f2f7c420Smk {
161f2f7c420Smk 	struct aml_value	cmd;
162f2f7c420Smk 	struct aml_value	res;
1635cc6ff0cSmk 	int			rv;
164f2f7c420Smk 
165f2f7c420Smk 	memset(&cmd, 0, sizeof cmd);
166435849e6Smk 	cmd.v_integer = dock;
167f2f7c420Smk 	cmd.type = AML_OBJTYPE_INTEGER;
168fe16b7bbSmk 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_DCK", 1, &cmd,
169f2f7c420Smk 	    &res) != 0) {
170b100133bSmk 		dnprintf(15, "%s: _DCK %d failed\n", DEVNAME(sc), dock);
1715cc6ff0cSmk 		rv = 0;
172f2f7c420Smk 	} else {
173b100133bSmk 		dnprintf(15, "%s: _DCK %d successful\n", DEVNAME(sc), dock);
1745cc6ff0cSmk 		rv = 1;
175f2f7c420Smk 	}
176f2f7c420Smk 
1775cc6ff0cSmk 	aml_freevalue(&res);
1785cc6ff0cSmk 
17907675d65Sjordan 	return (rv);
180f2f7c420Smk }
181f2f7c420Smk 
182f2f7c420Smk int
acpidock_eject(struct acpidock_softc * sc,struct aml_node * node)183ac52191eSmk acpidock_eject(struct acpidock_softc *sc, struct aml_node *node)
184f2f7c420Smk {
185f2f7c420Smk 	struct aml_value	cmd;
186f2f7c420Smk 	struct aml_value	res;
1875cc6ff0cSmk 	int			rv;
188f2f7c420Smk 
189f402adeaSjordan 	if (node != sc->sc_devnode)
190f402adeaSjordan 		aml_notify(node, 3);
19107675d65Sjordan 
192f2f7c420Smk 	memset(&cmd, 0, sizeof cmd);
193f2f7c420Smk 	cmd.v_integer = 1;
194f2f7c420Smk 	cmd.type = AML_OBJTYPE_INTEGER;
195ac52191eSmk 	if (aml_evalname(sc->sc_acpi, node, "_EJ0", 1, &cmd,
196f2f7c420Smk 	    &res) != 0) {
197e22ebbd4Smk 		dnprintf(15, "%s: _EJ0 failed\n", DEVNAME(sc));
1985cc6ff0cSmk 		rv = 0;
199f2f7c420Smk 	} else {
200e22ebbd4Smk 		dnprintf(15, "%s: _EJ0 successful\n", DEVNAME(sc));
2015cc6ff0cSmk 		rv = 1;
202f2f7c420Smk 	}
203f2f7c420Smk 
2045cc6ff0cSmk 	aml_freevalue(&res);
2055cc6ff0cSmk 
20607675d65Sjordan 	return (rv);
207f2f7c420Smk }
208f2f7c420Smk 
209f2f7c420Smk int
acpidock_notify(struct aml_node * node,int notify_type,void * arg)210f2f7c420Smk acpidock_notify(struct aml_node *node, int notify_type, void *arg)
211f2f7c420Smk {
212f2f7c420Smk 	struct acpidock_softc	*sc = arg;
213f402adeaSjordan 	struct aml_nodelist	*n;
214f2f7c420Smk 
215ac028446Smk 	dnprintf(5, "%s: acpidock_notify: notify %d\n", DEVNAME(sc),
216ac028446Smk 	    notify_type);
217ac028446Smk 
218f2f7c420Smk 	switch (notify_type) {
219f2f7c420Smk 	case ACPIDOCK_EVENT_INSERT:
220f2f7c420Smk 		acpidock_docklock(sc, 1);
221f2f7c420Smk 		acpidock_dockctl(sc, 1);
222ac028446Smk 
22307675d65Sjordan 		TAILQ_FOREACH_REVERSE(n, &sc->sc_deps_h, aml_nodelisth, entries)
224f402adeaSjordan 			aml_notify(n->node, 0x00);
225f2f7c420Smk 		break;
22677d6f5e3Smk 
22707675d65Sjordan 	case ACPIDOCK_EVENT_EJECT:
228e097d8aaSjordan 	case ACPIDOCK_EVENT_DEVCHECK:
229e097d8aaSjordan 		/* ACPI Spec says eject button press generates
230e097d8aaSjordan 		 * a Notify(Device, 1); */
23177d6f5e3Smk 		TAILQ_FOREACH(n, &sc->sc_deps_h, entries)
23277d6f5e3Smk 			acpidock_eject(sc, n->node);
233f2f7c420Smk 		acpidock_dockctl(sc, 0);
234f2f7c420Smk 		acpidock_docklock(sc, 0);
235f2f7c420Smk 
236f2f7c420Smk 		/* now actually undock */
237ac52191eSmk 		acpidock_eject(sc, sc->sc_devnode);
238f2f7c420Smk 		break;
239f2f7c420Smk 	}
240f2f7c420Smk 
241f2f7c420Smk 	acpidock_status(sc);
2424ee99e23Smk 	sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED;
2433cb04c65Skspillner 	sc->sc_sens.status = sc->sc_docked ? SENSOR_S_OK : SENSOR_S_UNKNOWN;
2443ff55dfeSmk 	if (sc->sc_docked)
2454ee99e23Smk 		strlcpy(sc->sc_sens.desc, "docked",
2464ee99e23Smk 		    sizeof(sc->sc_sens.desc));
2473ff55dfeSmk 	else
2484ee99e23Smk 		strlcpy(sc->sc_sens.desc, "not docked",
2494ee99e23Smk 		    sizeof(sc->sc_sens.desc));
2503ff55dfeSmk 
25107675d65Sjordan 	printf("%s: %s\n",
25207675d65Sjordan 	    DEVNAME(sc), sc->sc_docked == ACPIDOCK_STATUS_DOCKED ?
25307675d65Sjordan 	    "docked" : "undocked");
254f2f7c420Smk 
255f2f7c420Smk 	return (0);
256f2f7c420Smk }
257f2f7c420Smk 
258106fb80aSjordan int
acpidock_walkchildren(struct aml_node * node,void * arg)259106fb80aSjordan acpidock_walkchildren(struct aml_node *node, void *arg)
260f402adeaSjordan {
261f402adeaSjordan 	struct acpidock_softc	*sc = arg;
262f402adeaSjordan 	struct aml_nodelist	*n;
263f402adeaSjordan 
264f402adeaSjordan 	if (node && node->value && node->value->type == AML_OBJTYPE_DEVICE) {
265f402adeaSjordan 		n = malloc(sizeof *n, M_DEVBUF, M_WAITOK | M_ZERO);
266f402adeaSjordan 		n->node = node;
267f402adeaSjordan 		dnprintf(10,"%s depends on", aml_nodename(node));
268f402adeaSjordan 		dnprintf(10,"%s\n", aml_nodename(sc->sc_devnode));
269f402adeaSjordan 		TAILQ_INSERT_TAIL(&sc->sc_deps_h, n, entries);
270f402adeaSjordan 	}
27107675d65Sjordan 
27207675d65Sjordan 	return (0);
273f402adeaSjordan }
274f402adeaSjordan 
2757979ca52Sweingart int
acpidock_foundejd(struct aml_node * node,void * arg)2762b11adf0Smk acpidock_foundejd(struct aml_node *node, void *arg)
2772b11adf0Smk {
2782b11adf0Smk 	struct acpidock_softc	*sc = (struct acpidock_softc *)arg;
2792b11adf0Smk 	struct aml_value	res;
280f402adeaSjordan 	struct aml_node		*dock;
2812b11adf0Smk 
2823b455a03Smarco 	dnprintf(15, "%s: %s", DEVNAME(sc), node->name);
2832b11adf0Smk 
28407675d65Sjordan 	if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1)
2852b11adf0Smk 		printf(": error\n");
28607675d65Sjordan 	else {
287*9108e412Spatrick 		dock = aml_searchname(sc->sc_acpi->sc_root, res.v_string);
28807675d65Sjordan 
28907675d65Sjordan 		if (dock == sc->sc_devnode)
290f402adeaSjordan 			/* Add all children devices of Device containing _EJD */
29107675d65Sjordan 			aml_walknodes(node->parent, AML_WALK_POST,
29207675d65Sjordan 			    acpidock_walkchildren, sc);
2932b11adf0Smk 		aml_freevalue(&res);
294f402adeaSjordan 	}
2957979ca52Sweingart 
29607675d65Sjordan 	return (0);
2972b11adf0Smk }
298