1 /* $OpenBSD: atk0110.c,v 1.3 2010/02/26 17:24:11 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> 5 * 6 * Permission to use, copy, modify, and 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 #include <sys/malloc.h> 23 #include <sys/sensors.h> 24 25 #include <dev/acpi/acpireg.h> 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 /* 32 * ASUSTeK AI Booster (ACPI ATK0110). 33 * 34 * The driver was inspired by Takanori Watanabe's acpi_aiboost driver. 35 * http://cvsweb.freebsd.org/src/sys/dev/acpi_support/acpi_aiboost.c 36 * 37 * Special thanks goes to Sam Fourman Jr. for providing access to several 38 * ASUS boxes where the driver could be tested. 39 * 40 * -- cnst.su. 41 */ 42 43 #define AIBS_MORE_SENSORS 44 /* #define AIBS_VERBOSE */ 45 46 struct aibs_sensor { 47 struct ksensor s; 48 int64_t i; 49 int64_t l; 50 int64_t h; 51 }; 52 53 struct aibs_softc { 54 struct device sc_dev; 55 56 struct acpi_softc *sc_acpi; 57 struct aml_node *sc_devnode; 58 59 struct aibs_sensor *sc_asens_volt; 60 struct aibs_sensor *sc_asens_temp; 61 struct aibs_sensor *sc_asens_fan; 62 63 struct ksensordev sc_sensordev; 64 }; 65 66 67 int aibs_match(struct device *, void *, void *); 68 void aibs_attach(struct device *, struct device *, void *); 69 void aibs_refresh(void *); 70 71 void aibs_attach_sif(struct aibs_softc *, enum sensor_type); 72 void aibs_refresh_r(struct aibs_softc *, enum sensor_type); 73 74 75 struct cfattach aibs_ca = { 76 sizeof(struct aibs_softc), aibs_match, aibs_attach 77 }; 78 79 struct cfdriver aibs_cd = { 80 NULL, "aibs", DV_DULL 81 }; 82 83 static const char* aibs_hids[] = { 84 ACPI_DEV_ASUSAIBOOSTER, 85 NULL 86 }; 87 88 int 89 aibs_match(struct device *parent, void *match, void *aux) 90 { 91 struct acpi_attach_args *aa = aux; 92 struct cfdata *cf = match; 93 94 return acpi_matchhids(aa, aibs_hids, cf->cf_driver->cd_name); 95 } 96 97 void 98 aibs_attach(struct device *parent, struct device *self, void *aux) 99 { 100 struct aibs_softc *sc = (struct aibs_softc *)self; 101 struct acpi_attach_args *aa = aux; 102 103 sc->sc_acpi = (struct acpi_softc *)parent; 104 sc->sc_devnode = aa->aaa_node; 105 106 printf("\n"); 107 108 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 109 sizeof(sc->sc_sensordev.xname)); 110 111 aibs_attach_sif(sc, SENSOR_TEMP); 112 aibs_attach_sif(sc, SENSOR_FANRPM); 113 aibs_attach_sif(sc, SENSOR_VOLTS_DC); 114 115 if (sc->sc_sensordev.sensors_count == 0) { 116 printf("%s: no sensors found\n", DEVNAME(sc)); 117 return; 118 } 119 120 if (sensor_task_register(sc, aibs_refresh, 5) == NULL) { 121 printf("%s: unable to register update task\n", DEVNAME(sc)); 122 return; 123 } 124 125 sensordev_install(&sc->sc_sensordev); 126 } 127 128 void 129 aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st) 130 { 131 struct aml_value res; 132 struct aml_value **v; 133 int i, n; 134 char *name = "?SIF"; 135 struct aibs_sensor *as; 136 137 switch (st) { 138 case SENSOR_TEMP: 139 name[0] = 'T'; 140 break; 141 case SENSOR_FANRPM: 142 name[0] = 'F'; 143 break; 144 case SENSOR_VOLTS_DC: 145 name[0] = 'V'; 146 break; 147 default: 148 return; 149 } 150 151 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, name, 0, NULL, &res)) { 152 printf("%s: %s not found\n", DEVNAME(sc), name); 153 aml_freevalue(&res); 154 return; 155 } 156 157 if (res.type != AML_OBJTYPE_PACKAGE) { 158 printf("%s: %s: not a package\n", DEVNAME(sc), name); 159 aml_freevalue(&res); 160 return; 161 } 162 163 v = res.v_package; 164 if (v[0]->type != AML_OBJTYPE_INTEGER) { 165 printf("%s: %s[0]: invalid type\n", DEVNAME(sc), name); 166 aml_freevalue(&res); 167 return; 168 } 169 170 n = v[0]->v_integer; 171 if (res.length - 1 < n) { 172 printf("%s: %s: invalid package\n", DEVNAME(sc), name); 173 aml_freevalue(&res); 174 return; 175 } else if (res.length - 1 > n) { 176 printf("%s: %s: misformed package: %i/%i", 177 DEVNAME(sc), name, n, res.length - 1); 178 #ifdef AIBS_MORE_SENSORS 179 n = res.length - 1; 180 #endif 181 printf(", assume %i\n", n); 182 } 183 if (n < 1) { 184 printf("%s: %s: no members in the package\n", 185 DEVNAME(sc), name); 186 aml_freevalue(&res); 187 return; 188 } 189 190 as = malloc(sizeof(*as) * n, M_DEVBUF, M_NOWAIT | M_ZERO); 191 if (as == NULL) { 192 printf("%s: %s: malloc fail\n", DEVNAME(sc), name); 193 aml_freevalue(&res); 194 return; 195 } 196 197 switch (st) { 198 case SENSOR_TEMP: 199 sc->sc_asens_temp = as; 200 break; 201 case SENSOR_FANRPM: 202 sc->sc_asens_fan = as; 203 break; 204 case SENSOR_VOLTS_DC: 205 sc->sc_asens_volt = as; 206 break; 207 default: 208 /* NOTREACHED */ 209 return; 210 } 211 212 for (i = 0, v++; i < n; i++, v++) { 213 struct aml_value ri; 214 215 if(v[0]->type != AML_OBJTYPE_STRING) { 216 printf("%s: %s: %i: not a string: %i type\n", 217 DEVNAME(sc), name, i, v[0]->type); 218 continue; 219 } 220 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, v[0]->v_string, 221 0, NULL, &ri)) { 222 printf("%s: %s: %i: %s not found\n", 223 DEVNAME(sc), name, i, v[0]->v_string); 224 aml_freevalue(&ri); 225 continue; 226 } 227 if (ri.type != AML_OBJTYPE_PACKAGE) { 228 printf("%s: %s: %i: %s: not a package\n", 229 DEVNAME(sc), name, i, v[0]->v_string); 230 aml_freevalue(&ri); 231 continue; 232 } 233 if (ri.length != 5 || 234 ri.v_package[0]->type != AML_OBJTYPE_INTEGER || 235 ri.v_package[1]->type != AML_OBJTYPE_STRING || 236 ri.v_package[2]->type != AML_OBJTYPE_INTEGER || 237 ri.v_package[3]->type != AML_OBJTYPE_INTEGER || 238 ri.v_package[4]->type != AML_OBJTYPE_INTEGER) { 239 printf("%s: %s: %i: %s: invalid package\n", 240 DEVNAME(sc), name, i, v[0]->v_string); 241 aml_freevalue(&ri); 242 continue; 243 } 244 as[i].i = ri.v_package[0]->v_integer; 245 strlcpy(as[i].s.desc, ri.v_package[1]->v_string, 246 sizeof(as[i].s.desc)); 247 as[i].l = ri.v_package[2]->v_integer; 248 as[i].h = ri.v_package[3]->v_integer; 249 as[i].s.type = st; 250 #ifdef AIBS_VERBOSE 251 printf("%s: %s %2i: %4s: " 252 "0x%08llx %20s %5lli / %5lli 0x%llx\n", 253 DEVNAME(sc), name, i, v[0]->v_string, 254 as[i].i, as[i].s.desc, as[i].l, as[i].h, 255 ri.v_package[4]->v_integer); 256 #endif 257 sensor_attach(&sc->sc_sensordev, &as[i].s); 258 aml_freevalue(&ri); 259 } 260 261 aml_freevalue(&res); 262 return; 263 } 264 265 void 266 aibs_refresh(void *arg) 267 { 268 struct aibs_softc *sc = arg; 269 270 aibs_refresh_r(sc, SENSOR_TEMP); 271 aibs_refresh_r(sc, SENSOR_FANRPM); 272 aibs_refresh_r(sc, SENSOR_VOLTS_DC); 273 } 274 275 void 276 aibs_refresh_r(struct aibs_softc *sc, enum sensor_type st) 277 { 278 struct aml_node *node; 279 int i, n = sc->sc_sensordev.maxnumt[st]; 280 char *name; 281 struct aibs_sensor *as; 282 283 switch (st) { 284 case SENSOR_TEMP: 285 name = "RTMP"; 286 as = sc->sc_asens_temp; 287 break; 288 case SENSOR_FANRPM: 289 name = "RFAN"; 290 as = sc->sc_asens_fan; 291 break; 292 case SENSOR_VOLTS_DC: 293 name = "RVLT"; 294 as = sc->sc_asens_volt; 295 break; 296 default: 297 return; 298 } 299 300 if (as == NULL) 301 return; 302 303 node = aml_searchname(sc->sc_devnode, name); 304 if (node == NULL || node->value == NULL || 305 node->value->type != AML_OBJTYPE_METHOD) { 306 dprintf("%s: %s: method node not found\n", 307 DEVNAME(sc), name); 308 for (i = 0; i < n; i++) 309 as[i].s.flags |= SENSOR_FINVALID; 310 return; 311 } 312 313 for (i = 0; i < n; i++) { 314 struct aml_value req, res; 315 int64_t v; 316 struct ksensor *s = &as[i].s; 317 const int64_t l = as[i].l, h = as[i].h; 318 319 req.type = AML_OBJTYPE_INTEGER; 320 req.v_integer = as[i].i; 321 if (aml_evalnode(sc->sc_acpi, node, 1, &req, &res)) { 322 dprintf("%s: %s: %i: evaluation failed\n", 323 DEVNAME(sc), name, i); 324 aml_freevalue(&res); 325 s->flags |= SENSOR_FINVALID; 326 continue; 327 } 328 if (res.type != AML_OBJTYPE_INTEGER) { 329 dprintf("%s: %s: %i: not an integer: type %i\n", 330 DEVNAME(sc), name, i, res.type); 331 aml_freevalue(&res); 332 s->flags |= SENSOR_FINVALID; 333 continue; 334 } 335 v = res.v_integer; 336 aml_freevalue(&res); 337 338 switch (st) { 339 case SENSOR_TEMP: 340 s->value = v * 100 * 1000 + 273150000; 341 if (v == 0) { 342 s->status = SENSOR_S_UNKNOWN; 343 s->flags |= SENSOR_FINVALID; 344 } else { 345 if (v > h) 346 s->status = SENSOR_S_CRIT; 347 else if (v > l) 348 s->status = SENSOR_S_WARN; 349 else 350 s->status = SENSOR_S_OK; 351 s->flags &= ~SENSOR_FINVALID; 352 } 353 break; 354 case SENSOR_FANRPM: 355 s->value = v; 356 /* some boards have strange limits for fans */ 357 if ((l != 0 && l < v && v < h) || 358 (l == 0 && v > h)) 359 s->status = SENSOR_S_OK; 360 else 361 s->status = SENSOR_S_WARN; 362 s->flags &= ~SENSOR_FINVALID; 363 break; 364 case SENSOR_VOLTS_DC: 365 s->value = v * 1000; 366 if (l < v && v < h) 367 s->status = SENSOR_S_OK; 368 else 369 s->status = SENSOR_S_WARN; 370 s->flags &= ~SENSOR_FINVALID; 371 break; 372 default: 373 /* NOTREACHED */ 374 break; 375 } 376 } 377 378 return; 379 } 380