Line data Source code
1 : /* $OpenBSD: acpidock.c,v 1.44 2015/03/14 03:38:46 jsg Exp $ */
2 : /*
3 : * Copyright (c) 2006,2007 Michael Knudsen <mk@openbsd.org>
4 : *
5 : * Permission to use, copy, modify, and distribute this software for any
6 : * purpose with or without fee is hereby granted, provided that the above
7 : * copyright notice and this permission notice appear in all copies.
8 : *
9 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 : */
17 :
18 : #include <sys/param.h>
19 : #include <sys/systm.h>
20 : #include <sys/device.h>
21 : #include <sys/malloc.h>
22 : #include <sys/sensors.h>
23 :
24 : #include <machine/bus.h>
25 :
26 : #include <dev/acpi/acpivar.h>
27 : #include <dev/acpi/acpidev.h>
28 : #include <dev/acpi/amltypes.h>
29 : #include <dev/acpi/dsdt.h>
30 :
31 : struct aml_nodelist {
32 : struct aml_node *node;
33 : TAILQ_ENTRY(aml_nodelist) entries;
34 : };
35 :
36 : int acpidock_match(struct device *, void *, void *);
37 : void acpidock_attach(struct device *, struct device *, void *);
38 :
39 : struct cfattach acpidock_ca = {
40 : sizeof(struct acpidock_softc), acpidock_match, acpidock_attach
41 : };
42 :
43 : struct cfdriver acpidock_cd = {
44 : NULL, "acpidock", DV_DULL
45 : };
46 :
47 : int acpidock_docklock(struct acpidock_softc *, int);
48 : int acpidock_dockctl(struct acpidock_softc *, int);
49 : int acpidock_eject(struct acpidock_softc *, struct aml_node *);
50 : int acpidock_notify(struct aml_node *, int, void *);
51 : int acpidock_status(struct acpidock_softc *);
52 : int acpidock_walkchildren(struct aml_node *, void *);
53 :
54 : int acpidock_foundejd(struct aml_node *, void *);
55 :
56 : int
57 0 : acpidock_match(struct device *parent, void *match, void *aux)
58 : {
59 0 : struct acpi_attach_args *aaa = aux;
60 0 : struct cfdata *cf = match;
61 :
62 : /* sanity */
63 0 : if (aaa->aaa_name == NULL ||
64 0 : strcmp(aaa->aaa_name, cf->cf_driver->cd_name) != 0 ||
65 0 : aaa->aaa_table != NULL)
66 0 : return (0);
67 :
68 0 : return (1);
69 0 : }
70 :
71 : void
72 0 : acpidock_attach(struct device *parent, struct device *self, void *aux)
73 : {
74 0 : struct acpidock_softc *sc = (struct acpidock_softc *)self;
75 0 : struct acpi_attach_args *aa = aux;
76 : extern struct aml_node aml_root;
77 :
78 0 : sc->sc_acpi = (struct acpi_softc *)parent;
79 0 : sc->sc_devnode = aa->aaa_node;
80 :
81 0 : printf(": %s", sc->sc_devnode->name);
82 :
83 0 : acpidock_status(sc);
84 0 : if (sc->sc_docked == ACPIDOCK_STATUS_DOCKED) {
85 0 : acpidock_docklock(sc, 1);
86 0 : acpidock_dockctl(sc, 1);
87 0 : }
88 :
89 0 : acpidock_status(sc);
90 0 : printf("%s docked (%d)\n",
91 0 : sc->sc_docked == ACPIDOCK_STATUS_DOCKED ? "" : " not",
92 0 : sc->sc_sta);
93 :
94 0 : strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
95 : sizeof(sc->sc_sensdev.xname));
96 0 : if (sc->sc_docked)
97 0 : strlcpy(sc->sc_sens.desc, "docked",
98 : sizeof(sc->sc_sens.desc));
99 : else
100 0 : strlcpy(sc->sc_sens.desc, "not docked",
101 : sizeof(sc->sc_sens.desc));
102 :
103 0 : sc->sc_sens.type = SENSOR_INDICATOR;
104 0 : sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED;
105 0 : sc->sc_sens.status = sc->sc_docked ? SENSOR_S_OK : SENSOR_S_UNKNOWN;
106 0 : sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
107 0 : sensordev_install(&sc->sc_sensdev);
108 :
109 0 : TAILQ_INIT(&sc->sc_deps_h);
110 0 : aml_find_node(&aml_root, "_EJD", acpidock_foundejd, sc);
111 :
112 0 : aml_register_notify(sc->sc_devnode, aa->aaa_dev,
113 : acpidock_notify, sc, ACPIDEV_NOPOLL);
114 0 : }
115 :
116 : int
117 0 : acpidock_status(struct acpidock_softc *sc)
118 : {
119 0 : int64_t sta;
120 : int rv;
121 :
122 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL,
123 0 : &sta) != 0) {
124 0 : sta = 0;
125 : rv = 0;
126 0 : } else
127 : rv = 1;
128 :
129 0 : sc->sc_sta = sta;
130 0 : sc->sc_docked = sc->sc_sta & STA_PRESENT;
131 :
132 0 : return (rv);
133 0 : }
134 :
135 : int
136 0 : acpidock_docklock(struct acpidock_softc *sc, int lock)
137 : {
138 0 : struct aml_value cmd;
139 0 : struct aml_value res;
140 : int rv;
141 :
142 0 : memset(&cmd, 0, sizeof cmd);
143 0 : cmd.v_integer = lock;
144 0 : cmd.type = AML_OBJTYPE_INTEGER;
145 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_LCK", 1, &cmd,
146 0 : &res) != 0) {
147 : dnprintf(20, "%s: _LCK %d failed\n", DEVNAME(sc), lock);
148 : rv = 0;
149 0 : } else {
150 : dnprintf(20, "%s: _LCK %d successful\n", DEVNAME(sc), lock);
151 : rv = 1;
152 : }
153 :
154 0 : aml_freevalue(&res);
155 :
156 0 : return (rv);
157 0 : }
158 :
159 : int
160 0 : acpidock_dockctl(struct acpidock_softc *sc, int dock)
161 : {
162 0 : struct aml_value cmd;
163 0 : struct aml_value res;
164 : int rv;
165 :
166 0 : memset(&cmd, 0, sizeof cmd);
167 0 : cmd.v_integer = dock;
168 0 : cmd.type = AML_OBJTYPE_INTEGER;
169 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_DCK", 1, &cmd,
170 0 : &res) != 0) {
171 : dnprintf(15, "%s: _DCK %d failed\n", DEVNAME(sc), dock);
172 : rv = 0;
173 0 : } else {
174 : dnprintf(15, "%s: _DCK %d successful\n", DEVNAME(sc), dock);
175 : rv = 1;
176 : }
177 :
178 0 : aml_freevalue(&res);
179 :
180 0 : return (rv);
181 0 : }
182 :
183 : int
184 0 : acpidock_eject(struct acpidock_softc *sc, struct aml_node *node)
185 : {
186 0 : struct aml_value cmd;
187 0 : struct aml_value res;
188 : int rv;
189 :
190 0 : if (node != sc->sc_devnode)
191 0 : aml_notify(node, 3);
192 :
193 0 : memset(&cmd, 0, sizeof cmd);
194 0 : cmd.v_integer = 1;
195 0 : cmd.type = AML_OBJTYPE_INTEGER;
196 0 : if (aml_evalname(sc->sc_acpi, node, "_EJ0", 1, &cmd,
197 0 : &res) != 0) {
198 : dnprintf(15, "%s: _EJ0 failed\n", DEVNAME(sc));
199 : rv = 0;
200 0 : } else {
201 : dnprintf(15, "%s: _EJ0 successful\n", DEVNAME(sc));
202 : rv = 1;
203 : }
204 :
205 0 : aml_freevalue(&res);
206 :
207 0 : return (rv);
208 0 : }
209 :
210 : int
211 0 : acpidock_notify(struct aml_node *node, int notify_type, void *arg)
212 : {
213 0 : struct acpidock_softc *sc = arg;
214 : struct aml_nodelist *n;
215 :
216 : dnprintf(5, "%s: acpidock_notify: notify %d\n", DEVNAME(sc),
217 : notify_type);
218 :
219 0 : switch (notify_type) {
220 : case ACPIDOCK_EVENT_INSERT:
221 0 : acpidock_docklock(sc, 1);
222 0 : acpidock_dockctl(sc, 1);
223 :
224 0 : TAILQ_FOREACH_REVERSE(n, &sc->sc_deps_h, aml_nodelisth, entries)
225 0 : aml_notify(n->node, 0x00);
226 : break;
227 :
228 : case ACPIDOCK_EVENT_EJECT:
229 : case ACPIDOCK_EVENT_DEVCHECK:
230 : /* ACPI Spec says eject button press generates
231 : * a Notify(Device, 1); */
232 0 : TAILQ_FOREACH(n, &sc->sc_deps_h, entries)
233 0 : acpidock_eject(sc, n->node);
234 0 : acpidock_dockctl(sc, 0);
235 0 : acpidock_docklock(sc, 0);
236 :
237 : /* now actually undock */
238 0 : acpidock_eject(sc, sc->sc_devnode);
239 0 : break;
240 : }
241 :
242 0 : acpidock_status(sc);
243 0 : sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED;
244 0 : sc->sc_sens.status = sc->sc_docked ? SENSOR_S_OK : SENSOR_S_UNKNOWN;
245 0 : if (sc->sc_docked)
246 0 : strlcpy(sc->sc_sens.desc, "docked",
247 : sizeof(sc->sc_sens.desc));
248 : else
249 0 : strlcpy(sc->sc_sens.desc, "not docked",
250 : sizeof(sc->sc_sens.desc));
251 :
252 0 : printf("%s: %s\n",
253 0 : DEVNAME(sc), sc->sc_docked == ACPIDOCK_STATUS_DOCKED ?
254 : "docked" : "undocked");
255 :
256 0 : return (0);
257 : }
258 :
259 : int
260 0 : acpidock_walkchildren(struct aml_node *node, void *arg)
261 : {
262 0 : struct acpidock_softc *sc = arg;
263 : struct aml_nodelist *n;
264 :
265 0 : if (node && node->value && node->value->type == AML_OBJTYPE_DEVICE) {
266 0 : n = malloc(sizeof *n, M_DEVBUF, M_WAITOK | M_ZERO);
267 0 : n->node = node;
268 : dnprintf(10,"%s depends on", aml_nodename(node));
269 : dnprintf(10,"%s\n", aml_nodename(sc->sc_devnode));
270 0 : TAILQ_INSERT_TAIL(&sc->sc_deps_h, n, entries);
271 0 : }
272 :
273 0 : return (0);
274 : }
275 :
276 : int
277 0 : acpidock_foundejd(struct aml_node *node, void *arg)
278 : {
279 0 : struct acpidock_softc *sc = (struct acpidock_softc *)arg;
280 0 : struct aml_value res;
281 : struct aml_node *dock;
282 : extern struct aml_node aml_root;
283 :
284 : dnprintf(15, "%s: %s", DEVNAME(sc), node->name);
285 :
286 0 : if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1)
287 0 : printf(": error\n");
288 : else {
289 0 : dock = aml_searchname(&aml_root, res.v_string);
290 :
291 0 : if (dock == sc->sc_devnode)
292 : /* Add all children devices of Device containing _EJD */
293 0 : aml_walknodes(node->parent, AML_WALK_POST,
294 : acpidock_walkchildren, sc);
295 0 : aml_freevalue(&res);
296 : }
297 :
298 0 : return (0);
299 0 : }
|