1 /* $OpenBSD: acpidock.c,v 1.32 2009/03/13 18:53:50 jordan 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/acpireg.h> 27 #include <dev/acpi/acpivar.h> 28 #include <dev/acpi/acpidev.h> 29 #include <dev/acpi/amltypes.h> 30 #include <dev/acpi/dsdt.h> 31 32 struct aml_nodelist { 33 struct aml_node *node; 34 TAILQ_ENTRY(aml_nodelist) entries; 35 }; 36 37 int acpidock_match(struct device *, void *, void *); 38 void acpidock_attach(struct device *, struct device *, void *); 39 40 struct cfattach acpidock_ca = { 41 sizeof(struct acpidock_softc), acpidock_match, acpidock_attach 42 }; 43 44 struct cfdriver acpidock_cd = { 45 NULL, "acpidock", DV_DULL 46 }; 47 48 int acpidock_docklock(struct acpidock_softc *, int); 49 int acpidock_dockctl(struct acpidock_softc *, int); 50 int acpidock_eject(struct acpidock_softc *, struct aml_node *); 51 int acpidock_notify(struct aml_node *, int, void *); 52 int acpidock_status(struct acpidock_softc *); 53 54 int acpidock_foundejd(struct aml_node *, void *); 55 56 int 57 acpidock_match(struct device *parent, void *match, void *aux) 58 { 59 struct acpi_attach_args *aaa = aux; 60 struct cfdata *cf = match; 61 62 /* sanity */ 63 if (aaa->aaa_name == NULL || 64 strcmp(aaa->aaa_name, cf->cf_driver->cd_name) != 0 || 65 aaa->aaa_table != NULL) 66 return (0); 67 68 return (1); 69 } 70 71 void 72 acpidock_attach(struct device *parent, struct device *self, void *aux) 73 { 74 struct acpidock_softc *sc = (struct acpidock_softc *)self; 75 struct acpi_attach_args *aa = aux; 76 extern struct aml_node aml_root; 77 78 sc->sc_acpi = (struct acpi_softc *)parent; 79 sc->sc_devnode = aa->aaa_node; 80 81 printf(": %s", sc->sc_devnode->name); 82 83 acpidock_status(sc); 84 if (sc->sc_docked == ACPIDOCK_STATUS_DOCKED) { 85 acpidock_docklock(sc, 1); 86 acpidock_dockctl(sc, 1); 87 } else { 88 acpidock_dockctl(sc, 0); 89 acpidock_docklock(sc, 0); 90 } 91 92 acpidock_status(sc); 93 printf(":%s docked (%d)\n", 94 sc->sc_docked == ACPIDOCK_STATUS_DOCKED ? "" : " not", 95 sc->sc_sta); 96 97 strlcpy(sc->sc_sensdev.xname, DEVNAME(sc), 98 sizeof(sc->sc_sensdev.xname)); 99 if (sc->sc_docked) 100 strlcpy(sc->sc_sens.desc, "docked", 101 sizeof(sc->sc_sens.desc)); 102 else 103 strlcpy(sc->sc_sens.desc, "not docked", 104 sizeof(sc->sc_sens.desc)); 105 106 sc->sc_sens.type = SENSOR_INDICATOR; 107 sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED; 108 sensor_attach(&sc->sc_sensdev, &sc->sc_sens); 109 sensordev_install(&sc->sc_sensdev); 110 111 TAILQ_INIT(&sc->sc_deps_h); 112 aml_find_node(aml_root.child, "_EJD", acpidock_foundejd, sc); 113 114 aml_register_notify(sc->sc_devnode, aa->aaa_dev, 115 acpidock_notify, sc, ACPIDEV_NOPOLL); 116 } 117 118 int 119 acpidock_status(struct acpidock_softc *sc) 120 { 121 int64_t sta; 122 int rv; 123 124 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, 125 &sta) != 0) { 126 sta = 0; 127 rv = 0; 128 } 129 else 130 rv = 1; 131 132 sc->sc_sta = sta; 133 134 sc->sc_docked = sc->sc_sta & STA_PRESENT; 135 136 return (rv); 137 } 138 139 int 140 acpidock_docklock(struct acpidock_softc *sc, int lock) 141 { 142 struct aml_value cmd; 143 struct aml_value res; 144 int rv; 145 146 memset(&cmd, 0, sizeof cmd); 147 cmd.v_integer = lock; 148 cmd.type = AML_OBJTYPE_INTEGER; 149 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_LCK", 1, &cmd, 150 &res) != 0) { 151 dnprintf(20, "%s: _LCK %d failed\n", DEVNAME(sc), lock); 152 153 rv = 0; 154 } else { 155 dnprintf(20, "%s: _LCK %d successful\n", DEVNAME(sc), lock); 156 157 rv = 1; 158 } 159 160 aml_freevalue(&res); 161 162 return rv; 163 } 164 165 int 166 acpidock_dockctl(struct acpidock_softc *sc, int dock) 167 { 168 struct aml_value cmd; 169 struct aml_value res; 170 int rv; 171 172 memset(&cmd, 0, sizeof cmd); 173 cmd.v_integer = dock; 174 cmd.type = AML_OBJTYPE_INTEGER; 175 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_DCK", 1, &cmd, 176 &res) != 0) { 177 /* XXX */ 178 dnprintf(15, "%s: _DCK %d failed\n", DEVNAME(sc), dock); 179 180 rv = 0; 181 } else { 182 dnprintf(15, "%s: _DCK %d successful\n", DEVNAME(sc), dock); 183 184 rv = 1; 185 } 186 187 aml_freevalue(&res); 188 189 return rv; 190 } 191 192 int 193 acpidock_eject(struct acpidock_softc *sc, struct aml_node *node) 194 { 195 struct aml_value cmd; 196 struct aml_value res; 197 int rv; 198 199 memset(&cmd, 0, sizeof cmd); 200 cmd.v_integer = 1; 201 cmd.type = AML_OBJTYPE_INTEGER; 202 if (aml_evalname(sc->sc_acpi, node, "_EJ0", 1, &cmd, 203 &res) != 0) { 204 /* XXX */ 205 dnprintf(15, "%s: _EJ0 failed\n", DEVNAME(sc)); 206 207 rv = 0; 208 } else { 209 dnprintf(15, "%s: _EJ0 successful\n", DEVNAME(sc)); 210 211 rv = 1; 212 } 213 214 aml_freevalue(&res); 215 216 return rv; 217 } 218 219 int 220 acpidock_notify(struct aml_node *node, int notify_type, void *arg) 221 { 222 struct acpidock_softc *sc = arg; 223 224 dnprintf(5, "%s: acpidock_notify: notify %d\n", DEVNAME(sc), 225 notify_type); 226 227 switch (notify_type) { 228 case ACPIDOCK_EVENT_INSERT: 229 printf("%s: dock", DEVNAME(sc)); 230 acpidock_docklock(sc, 1); 231 acpidock_dockctl(sc, 1); 232 233 break; 234 case ACPIDOCK_EVENT_EJECT: { 235 struct aml_nodelist *n; 236 237 TAILQ_FOREACH(n, &sc->sc_deps_h, entries) 238 acpidock_eject(sc, n->node); 239 240 acpidock_dockctl(sc, 0); 241 acpidock_docklock(sc, 0); 242 243 /* now actually undock */ 244 acpidock_eject(sc, sc->sc_devnode); 245 246 printf("%s: undock", DEVNAME(sc)); 247 248 break; 249 } 250 } 251 252 acpidock_status(sc); 253 sc->sc_sens.value = sc->sc_docked == ACPIDOCK_STATUS_DOCKED; 254 if (sc->sc_docked) 255 strlcpy(sc->sc_sens.desc, "docked", 256 sizeof(sc->sc_sens.desc)); 257 else 258 strlcpy(sc->sc_sens.desc, "not docked", 259 sizeof(sc->sc_sens.desc)); 260 261 printf(": status %s\n", 262 sc->sc_docked == ACPIDOCK_STATUS_DOCKED ? "docked" : "undocked"); 263 264 return (0); 265 } 266 267 int 268 acpidock_foundejd(struct aml_node *node, void *arg) 269 { 270 struct acpidock_softc *sc = (struct acpidock_softc *)arg; 271 struct aml_value res; 272 273 dnprintf(15, "%s: %s", DEVNAME(sc), node->name); 274 275 if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1) { 276 printf(": error\n"); 277 } else { 278 struct aml_nodelist *n; 279 280 /* XXX debug */ 281 dnprintf(10, "%s: %s depends on %s\n", DEVNAME(sc), 282 node->name, res.v_string); 283 284 /* XXX more than one dock? */ 285 n = malloc(sizeof(struct aml_nodelist), M_DEVBUF, M_WAITOK); 286 n->node = node; 287 288 TAILQ_INSERT_TAIL(&sc->sc_deps_h, n, entries); 289 } 290 291 aml_freevalue(&res); 292 293 return 0; 294 } 295