1 1.7 thorpej /* $NetBSD: aibs_acpi.c,v 1.7 2021/01/29 15:49:55 thorpej Exp $ */ 2 1.1 jruoho 3 1.1 jruoho /*- 4 1.1 jruoho * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 1.1 jruoho * All rights reserved. 6 1.1 jruoho * 7 1.1 jruoho * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jruoho * by Jukka Ruohonen. 9 1.1 jruoho * 10 1.1 jruoho * Redistribution and use in source and binary forms, with or without 11 1.1 jruoho * modification, are permitted provided that the following conditions 12 1.1 jruoho * are met: 13 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 14 1.1 jruoho * notice, this list of conditions and the following disclaimer. 15 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 17 1.1 jruoho * documentation and/or other materials provided with the distribution. 18 1.1 jruoho * 19 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jruoho * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jruoho */ 31 1.1 jruoho 32 1.1 jruoho /* $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $ */ 33 1.1 jruoho /* 34 1.1 jruoho * Copyright (c) 2009 Constantine A. Murenin <cnst+netbsd (at) bugmail.mojo.ru> 35 1.1 jruoho * 36 1.1 jruoho * Permission to use, copy, modify, and distribute this software for any 37 1.1 jruoho * purpose with or without fee is hereby granted, provided that the above 38 1.1 jruoho * copyright notice and this permission notice appear in all copies. 39 1.1 jruoho * 40 1.1 jruoho * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 41 1.1 jruoho * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 42 1.1 jruoho * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 43 1.1 jruoho * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 44 1.1 jruoho * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 45 1.1 jruoho * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 46 1.1 jruoho * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 47 1.1 jruoho */ 48 1.1 jruoho 49 1.1 jruoho #include <sys/cdefs.h> 50 1.7 thorpej __KERNEL_RCSID(0, "$NetBSD: aibs_acpi.c,v 1.7 2021/01/29 15:49:55 thorpej Exp $"); 51 1.1 jruoho 52 1.1 jruoho #include <sys/param.h> 53 1.1 jruoho #include <sys/kmem.h> 54 1.1 jruoho #include <sys/module.h> 55 1.1 jruoho 56 1.1 jruoho #include <dev/acpi/acpireg.h> 57 1.1 jruoho #include <dev/acpi/acpivar.h> 58 1.1 jruoho 59 1.1 jruoho /* 60 1.1 jruoho * ASUSTeK AI Booster (ACPI ASOC ATK0110). 61 1.1 jruoho * 62 1.1 jruoho * This code was originally written for OpenBSD after the techniques 63 1.1 jruoho * described in the Linux's asus_atk0110.c and FreeBSD's acpi_aiboost.c 64 1.1 jruoho * were verified to be accurate on the actual hardware kindly provided by 65 1.1 jruoho * Sam Fourman Jr. It was subsequently ported from OpenBSD to DragonFly BSD, 66 1.1 jruoho * and then to the NetBSD's sysmon_envsys(9) framework. 67 1.1 jruoho * 68 1.1 jruoho * -- Constantine A. Murenin <http://cnst.su/> 69 1.1 jruoho */ 70 1.1 jruoho 71 1.1 jruoho #define _COMPONENT ACPI_RESOURCE_COMPONENT 72 1.1 jruoho ACPI_MODULE_NAME ("acpi_aibs") 73 1.1 jruoho 74 1.1 jruoho #define AIBS_MUX_HWMON 0x00000006 75 1.1 jruoho #define AIBS_MUX_MGMT 0x00000011 76 1.1 jruoho 77 1.1 jruoho #define AIBS_TYPE(x) (((x) >> 16) & 0xff) 78 1.1 jruoho #define AIBS_TYPE_VOLT 2 79 1.1 jruoho #define AIBS_TYPE_TEMP 3 80 1.1 jruoho #define AIBS_TYPE_FAN 4 81 1.1 jruoho 82 1.1 jruoho struct aibs_sensor { 83 1.1 jruoho envsys_data_t as_sensor; 84 1.1 jruoho uint64_t as_type; 85 1.1 jruoho uint64_t as_liml; 86 1.1 jruoho uint64_t as_limh; 87 1.1 jruoho 88 1.1 jruoho SIMPLEQ_ENTRY(aibs_sensor) as_list; 89 1.1 jruoho }; 90 1.1 jruoho 91 1.1 jruoho struct aibs_softc { 92 1.1 jruoho device_t sc_dev; 93 1.1 jruoho struct acpi_devnode *sc_node; 94 1.1 jruoho struct sysmon_envsys *sc_sme; 95 1.1 jruoho bool sc_model; /* new model = true */ 96 1.1 jruoho 97 1.1 jruoho SIMPLEQ_HEAD(, aibs_sensor) as_head; 98 1.1 jruoho }; 99 1.1 jruoho 100 1.1 jruoho static int aibs_match(device_t, cfdata_t, void *); 101 1.1 jruoho static void aibs_attach(device_t, device_t, void *); 102 1.1 jruoho static int aibs_detach(device_t, int); 103 1.1 jruoho 104 1.1 jruoho static void aibs_init(device_t); 105 1.1 jruoho static void aibs_init_new(device_t); 106 1.1 jruoho static void aibs_init_old(device_t, int); 107 1.1 jruoho 108 1.1 jruoho static void aibs_sensor_add(device_t, ACPI_OBJECT *); 109 1.1 jruoho static bool aibs_sensor_value(device_t, struct aibs_sensor *, uint64_t *); 110 1.1 jruoho static void aibs_sensor_refresh(struct sysmon_envsys *, envsys_data_t *); 111 1.1 jruoho static void aibs_sensor_limits(struct sysmon_envsys *, envsys_data_t *, 112 1.1 jruoho sysmon_envsys_lim_t *, uint32_t *); 113 1.1 jruoho 114 1.1 jruoho CFATTACH_DECL_NEW(aibs, sizeof(struct aibs_softc), 115 1.1 jruoho aibs_match, aibs_attach, aibs_detach, NULL); 116 1.1 jruoho 117 1.7 thorpej static const struct device_compatible_entry compat_data[] = { 118 1.7 thorpej { .compat = "ATK0110" }, 119 1.7 thorpej DEVICE_COMPAT_EOL 120 1.1 jruoho }; 121 1.1 jruoho 122 1.1 jruoho static int 123 1.1 jruoho aibs_match(device_t parent, cfdata_t match, void *aux) 124 1.1 jruoho { 125 1.1 jruoho struct acpi_attach_args *aa = aux; 126 1.1 jruoho 127 1.7 thorpej return acpi_compatible_match(aa, compat_data); 128 1.1 jruoho } 129 1.1 jruoho 130 1.1 jruoho static void 131 1.1 jruoho aibs_attach(device_t parent, device_t self, void *aux) 132 1.1 jruoho { 133 1.1 jruoho struct aibs_softc *sc = device_private(self); 134 1.1 jruoho struct acpi_attach_args *aa = aux; 135 1.1 jruoho 136 1.1 jruoho sc->sc_dev = self; 137 1.1 jruoho sc->sc_node = aa->aa_node; 138 1.1 jruoho 139 1.1 jruoho aprint_naive("\n"); 140 1.1 jruoho aprint_normal(": ASUSTeK AI Booster\n"); 141 1.1 jruoho 142 1.1 jruoho sc->sc_sme = sysmon_envsys_create(); 143 1.1 jruoho 144 1.1 jruoho sc->sc_sme->sme_cookie = sc; 145 1.1 jruoho sc->sc_sme->sme_name = device_xname(self); 146 1.1 jruoho sc->sc_sme->sme_refresh = aibs_sensor_refresh; 147 1.1 jruoho sc->sc_sme->sme_get_limits = aibs_sensor_limits; 148 1.1 jruoho 149 1.1 jruoho aibs_init(self); 150 1.1 jruoho SIMPLEQ_INIT(&sc->as_head); 151 1.1 jruoho 152 1.1 jruoho if (sc->sc_model != false) 153 1.1 jruoho aibs_init_new(self); 154 1.1 jruoho else { 155 1.1 jruoho aibs_init_old(self, AIBS_TYPE_FAN); 156 1.1 jruoho aibs_init_old(self, AIBS_TYPE_TEMP); 157 1.1 jruoho aibs_init_old(self, AIBS_TYPE_VOLT); 158 1.1 jruoho } 159 1.1 jruoho 160 1.1 jruoho (void)pmf_device_register(self, NULL, NULL); 161 1.1 jruoho 162 1.1 jruoho if (sc->sc_sme->sme_nsensors == 0) { 163 1.1 jruoho aprint_error_dev(self, "no sensors found\n"); 164 1.1 jruoho sysmon_envsys_destroy(sc->sc_sme); 165 1.1 jruoho sc->sc_sme = NULL; 166 1.1 jruoho return; 167 1.1 jruoho } 168 1.1 jruoho 169 1.1 jruoho if (sysmon_envsys_register(sc->sc_sme) != 0) 170 1.1 jruoho aprint_error_dev(self, "failed to register with sysmon\n"); 171 1.1 jruoho } 172 1.1 jruoho 173 1.1 jruoho static int 174 1.1 jruoho aibs_detach(device_t self, int flags) 175 1.1 jruoho { 176 1.1 jruoho struct aibs_softc *sc = device_private(self); 177 1.1 jruoho struct aibs_sensor *as; 178 1.1 jruoho 179 1.1 jruoho pmf_device_deregister(self); 180 1.1 jruoho 181 1.1 jruoho if (sc->sc_sme != NULL) 182 1.1 jruoho sysmon_envsys_unregister(sc->sc_sme); 183 1.1 jruoho 184 1.1 jruoho while (SIMPLEQ_FIRST(&sc->as_head) != NULL) { 185 1.1 jruoho as = SIMPLEQ_FIRST(&sc->as_head); 186 1.1 jruoho SIMPLEQ_REMOVE_HEAD(&sc->as_head, as_list); 187 1.1 jruoho kmem_free(as, sizeof(*as)); 188 1.1 jruoho } 189 1.1 jruoho 190 1.1 jruoho return 0; 191 1.1 jruoho } 192 1.1 jruoho 193 1.1 jruoho static void 194 1.1 jruoho aibs_init(device_t self) 195 1.1 jruoho { 196 1.1 jruoho struct aibs_softc *sc = device_private(self); 197 1.1 jruoho ACPI_HANDLE tmp; 198 1.1 jruoho ACPI_STATUS rv; 199 1.1 jruoho 200 1.1 jruoho /* 201 1.1 jruoho * Old model uses the tuple { TSIF, VSIF, FSIF } to 202 1.1 jruoho * enumerate the sensors and { RTMP, RVLT, RFAN } 203 1.1 jruoho * to obtain the values. New mode uses GGRP for the 204 1.1 jruoho * enumeration and { GITM, SITM } as accessors. 205 1.1 jruoho */ 206 1.1 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "GGRP", &tmp); 207 1.1 jruoho 208 1.1 jruoho if (ACPI_FAILURE(rv)) { 209 1.1 jruoho sc->sc_model = false; 210 1.1 jruoho return; 211 1.1 jruoho } 212 1.1 jruoho 213 1.1 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "GITM", &tmp); 214 1.1 jruoho 215 1.1 jruoho if (ACPI_FAILURE(rv)) { 216 1.1 jruoho sc->sc_model = false; 217 1.1 jruoho return; 218 1.1 jruoho } 219 1.1 jruoho 220 1.1 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "SITM", &tmp); 221 1.1 jruoho 222 1.1 jruoho if (ACPI_FAILURE(rv)) { 223 1.1 jruoho sc->sc_model = false; 224 1.1 jruoho return; 225 1.1 jruoho } 226 1.1 jruoho 227 1.1 jruoho sc->sc_model = true; 228 1.3 jruoho 229 1.3 jruoho /* 230 1.3 jruoho * If both the new and the old methods are present, prefer 231 1.3 jruoho * the old one; GGRP/GITM may not be functional in this case. 232 1.3 jruoho */ 233 1.3 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "FSIF", &tmp); 234 1.3 jruoho 235 1.3 jruoho if (ACPI_FAILURE(rv)) 236 1.3 jruoho return; 237 1.3 jruoho 238 1.3 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "TSIF", &tmp); 239 1.3 jruoho 240 1.3 jruoho if (ACPI_FAILURE(rv)) 241 1.3 jruoho return; 242 1.3 jruoho 243 1.3 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "VSIF", &tmp); 244 1.3 jruoho 245 1.3 jruoho if (ACPI_FAILURE(rv)) 246 1.3 jruoho return; 247 1.3 jruoho 248 1.3 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "RFAN", &tmp); 249 1.3 jruoho 250 1.3 jruoho if (ACPI_FAILURE(rv)) 251 1.3 jruoho return; 252 1.3 jruoho 253 1.3 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "RTMP", &tmp); 254 1.3 jruoho 255 1.3 jruoho if (ACPI_FAILURE(rv)) 256 1.3 jruoho return; 257 1.3 jruoho 258 1.3 jruoho rv = AcpiGetHandle(sc->sc_node->ad_handle, "RVLT", &tmp); 259 1.3 jruoho 260 1.3 jruoho if (ACPI_FAILURE(rv)) 261 1.3 jruoho return; 262 1.3 jruoho 263 1.3 jruoho sc->sc_model = false; 264 1.1 jruoho } 265 1.1 jruoho 266 1.1 jruoho static void 267 1.1 jruoho aibs_init_new(device_t self) 268 1.1 jruoho { 269 1.1 jruoho struct aibs_softc *sc = device_private(self); 270 1.1 jruoho ACPI_OBJECT_LIST arg; 271 1.1 jruoho ACPI_OBJECT id, *obj; 272 1.1 jruoho ACPI_BUFFER buf; 273 1.1 jruoho ACPI_STATUS rv; 274 1.1 jruoho uint32_t i, n; 275 1.1 jruoho 276 1.1 jruoho arg.Count = 1; 277 1.1 jruoho arg.Pointer = &id; 278 1.1 jruoho 279 1.1 jruoho id.Type = ACPI_TYPE_INTEGER; 280 1.1 jruoho id.Integer.Value = AIBS_MUX_HWMON; 281 1.1 jruoho 282 1.1 jruoho buf.Pointer = NULL; 283 1.1 jruoho buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 284 1.1 jruoho 285 1.1 jruoho rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "GGRP", &arg, &buf); 286 1.1 jruoho 287 1.1 jruoho if (ACPI_FAILURE(rv)) 288 1.1 jruoho goto out; 289 1.1 jruoho 290 1.1 jruoho obj = buf.Pointer; 291 1.1 jruoho 292 1.1 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 293 1.1 jruoho rv = AE_TYPE; 294 1.1 jruoho goto out; 295 1.1 jruoho } 296 1.1 jruoho 297 1.1 jruoho if (obj->Package.Count > UINT32_MAX) { 298 1.1 jruoho rv = AE_AML_NUMERIC_OVERFLOW; 299 1.1 jruoho goto out; 300 1.1 jruoho } 301 1.1 jruoho 302 1.1 jruoho n = obj->Package.Count; 303 1.1 jruoho 304 1.1 jruoho if (n == 0) { 305 1.1 jruoho rv = AE_NOT_EXIST; 306 1.1 jruoho goto out; 307 1.1 jruoho } 308 1.1 jruoho 309 1.1 jruoho for (i = 0; i < n; i++) 310 1.1 jruoho aibs_sensor_add(self, &obj->Package.Elements[i]); 311 1.1 jruoho 312 1.1 jruoho out: 313 1.1 jruoho if (buf.Pointer != NULL) 314 1.1 jruoho ACPI_FREE(buf.Pointer); 315 1.1 jruoho 316 1.1 jruoho if (ACPI_FAILURE(rv)) { 317 1.1 jruoho 318 1.1 jruoho aprint_error_dev(self, "failed to evaluate " 319 1.1 jruoho "GGRP: %s\n", AcpiFormatException(rv)); 320 1.1 jruoho } 321 1.1 jruoho } 322 1.1 jruoho 323 1.1 jruoho static void 324 1.1 jruoho aibs_init_old(device_t self, int type) 325 1.1 jruoho { 326 1.1 jruoho struct aibs_softc *sc = device_private(self); 327 1.1 jruoho char path[] = "?SIF"; 328 1.1 jruoho ACPI_OBJECT *elm, *obj; 329 1.1 jruoho ACPI_BUFFER buf; 330 1.1 jruoho ACPI_STATUS rv; 331 1.1 jruoho uint32_t i, n; 332 1.1 jruoho 333 1.1 jruoho switch (type) { 334 1.1 jruoho 335 1.1 jruoho case AIBS_TYPE_FAN: 336 1.1 jruoho path[0] = 'F'; 337 1.1 jruoho break; 338 1.1 jruoho 339 1.1 jruoho case AIBS_TYPE_TEMP: 340 1.1 jruoho path[0] = 'T'; 341 1.1 jruoho break; 342 1.1 jruoho 343 1.1 jruoho case AIBS_TYPE_VOLT: 344 1.1 jruoho path[0] = 'V'; 345 1.1 jruoho break; 346 1.1 jruoho 347 1.1 jruoho default: 348 1.1 jruoho return; 349 1.1 jruoho } 350 1.1 jruoho 351 1.1 jruoho rv = acpi_eval_struct(sc->sc_node->ad_handle, path, &buf); 352 1.1 jruoho 353 1.1 jruoho if (ACPI_FAILURE(rv)) 354 1.1 jruoho goto out; 355 1.1 jruoho 356 1.1 jruoho obj = buf.Pointer; 357 1.1 jruoho 358 1.1 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 359 1.1 jruoho rv = AE_TYPE; 360 1.1 jruoho goto out; 361 1.1 jruoho } 362 1.1 jruoho 363 1.1 jruoho elm = obj->Package.Elements; 364 1.1 jruoho 365 1.1 jruoho if (elm[0].Type != ACPI_TYPE_INTEGER) { 366 1.1 jruoho rv = AE_TYPE; 367 1.1 jruoho goto out; 368 1.1 jruoho } 369 1.1 jruoho 370 1.1 jruoho if (elm[0].Integer.Value > UINT32_MAX) { 371 1.1 jruoho rv = AE_AML_NUMERIC_OVERFLOW; 372 1.1 jruoho goto out; 373 1.1 jruoho } 374 1.1 jruoho 375 1.1 jruoho n = elm[0].Integer.Value; 376 1.1 jruoho 377 1.1 jruoho if (n == 0) { 378 1.1 jruoho rv = AE_NOT_EXIST; 379 1.1 jruoho goto out; 380 1.1 jruoho } 381 1.1 jruoho 382 1.1 jruoho if (obj->Package.Count - 1 != n) { 383 1.1 jruoho rv = AE_BAD_VALUE; 384 1.1 jruoho goto out; 385 1.1 jruoho } 386 1.1 jruoho 387 1.1 jruoho for (i = 1; i < obj->Package.Count; i++) { 388 1.1 jruoho 389 1.1 jruoho if (elm[i].Type != ACPI_TYPE_PACKAGE) 390 1.1 jruoho continue; 391 1.1 jruoho 392 1.1 jruoho aibs_sensor_add(self, &elm[i]); 393 1.1 jruoho } 394 1.1 jruoho 395 1.1 jruoho out: 396 1.1 jruoho if (buf.Pointer != NULL) 397 1.1 jruoho ACPI_FREE(buf.Pointer); 398 1.1 jruoho 399 1.1 jruoho if (ACPI_FAILURE(rv)) { 400 1.1 jruoho 401 1.1 jruoho aprint_error_dev(self, "failed to evaluate " 402 1.1 jruoho "%s: %s\n", path, AcpiFormatException(rv)); 403 1.1 jruoho } 404 1.1 jruoho } 405 1.1 jruoho 406 1.1 jruoho static void 407 1.1 jruoho aibs_sensor_add(device_t self, ACPI_OBJECT *obj) 408 1.1 jruoho { 409 1.1 jruoho struct aibs_softc *sc = device_private(self); 410 1.1 jruoho struct aibs_sensor *as; 411 1.1 jruoho int ena, len, lhi, llo; 412 1.1 jruoho const char *name; 413 1.1 jruoho ACPI_STATUS rv; 414 1.1 jruoho 415 1.1 jruoho as = NULL; 416 1.1 jruoho rv = AE_OK; 417 1.1 jruoho 418 1.1 jruoho if (obj->Type != ACPI_TYPE_PACKAGE) { 419 1.1 jruoho rv = AE_TYPE; 420 1.1 jruoho goto out; 421 1.1 jruoho } 422 1.1 jruoho 423 1.1 jruoho /* 424 1.1 jruoho * The known formats are: 425 1.1 jruoho * 426 1.1 jruoho * index type old new 427 1.1 jruoho * ----- ---- --- --- 428 1.1 jruoho * 0 integer flags flags 429 1.1 jruoho * 1 string name name 430 1.1 jruoho * 2 integer limit1 unknown 431 1.1 jruoho * 3 integer limit2 unknown 432 1.1 jruoho * 4 integer enable limit1 433 1.1 jruoho * 5 integer - limit2 434 1.1 jruoho * 6 integer - enable 435 1.1 jruoho */ 436 1.1 jruoho if (sc->sc_model != false) { 437 1.1 jruoho len = 7; 438 1.1 jruoho llo = 4; 439 1.1 jruoho lhi = 5; 440 1.1 jruoho ena = 6; 441 1.1 jruoho } else { 442 1.1 jruoho len = 5; 443 1.1 jruoho llo = 2; 444 1.1 jruoho lhi = 3; 445 1.1 jruoho ena = 4; 446 1.1 jruoho } 447 1.1 jruoho 448 1.1 jruoho if (obj->Package.Count != (uint32_t)len) { 449 1.1 jruoho rv = AE_LIMIT; 450 1.1 jruoho goto out; 451 1.1 jruoho } 452 1.1 jruoho 453 1.1 jruoho if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER || 454 1.1 jruoho obj->Package.Elements[1].Type != ACPI_TYPE_STRING || 455 1.1 jruoho obj->Package.Elements[llo].Type != ACPI_TYPE_INTEGER || 456 1.1 jruoho obj->Package.Elements[lhi].Type != ACPI_TYPE_INTEGER || 457 1.1 jruoho obj->Package.Elements[ena].Type != ACPI_TYPE_INTEGER) { 458 1.1 jruoho rv = AE_TYPE; 459 1.1 jruoho goto out; 460 1.1 jruoho } 461 1.1 jruoho 462 1.1 jruoho as = kmem_zalloc(sizeof(*as), KM_SLEEP); 463 1.1 jruoho 464 1.1 jruoho name = obj->Package.Elements[1].String.Pointer; 465 1.1 jruoho 466 1.1 jruoho as->as_type = obj->Package.Elements[0].Integer.Value; 467 1.1 jruoho as->as_liml = obj->Package.Elements[llo].Integer.Value; 468 1.1 jruoho as->as_limh = obj->Package.Elements[lhi].Integer.Value; 469 1.1 jruoho 470 1.1 jruoho if (sc->sc_model != false) 471 1.1 jruoho as->as_limh += as->as_liml; /* A range in the new model. */ 472 1.1 jruoho 473 1.4 jruoho as->as_sensor.state = ENVSYS_SINVALID; 474 1.4 jruoho 475 1.1 jruoho switch (AIBS_TYPE(as->as_type)) { 476 1.1 jruoho 477 1.1 jruoho case AIBS_TYPE_FAN: 478 1.1 jruoho as->as_sensor.units = ENVSYS_SFANRPM; 479 1.4 jruoho as->as_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY; 480 1.1 jruoho break; 481 1.1 jruoho 482 1.1 jruoho case AIBS_TYPE_TEMP: 483 1.1 jruoho as->as_sensor.units = ENVSYS_STEMP; 484 1.4 jruoho as->as_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY; 485 1.1 jruoho break; 486 1.1 jruoho 487 1.1 jruoho case AIBS_TYPE_VOLT: 488 1.1 jruoho as->as_sensor.units = ENVSYS_SVOLTS_DC; 489 1.4 jruoho as->as_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY; 490 1.1 jruoho break; 491 1.1 jruoho 492 1.1 jruoho default: 493 1.1 jruoho rv = AE_TYPE; 494 1.1 jruoho goto out; 495 1.1 jruoho } 496 1.1 jruoho 497 1.1 jruoho (void)strlcpy(as->as_sensor.desc, name, sizeof(as->as_sensor.desc)); 498 1.1 jruoho 499 1.1 jruoho if (sysmon_envsys_sensor_attach(sc->sc_sme, &as->as_sensor) != 0) { 500 1.1 jruoho rv = AE_AML_INTERNAL; 501 1.1 jruoho goto out; 502 1.1 jruoho } 503 1.1 jruoho 504 1.1 jruoho SIMPLEQ_INSERT_TAIL(&sc->as_head, as, as_list); 505 1.1 jruoho 506 1.1 jruoho out: 507 1.1 jruoho if (ACPI_FAILURE(rv)) { 508 1.1 jruoho 509 1.1 jruoho if (as != NULL) 510 1.1 jruoho kmem_free(as, sizeof(*as)); 511 1.1 jruoho 512 1.1 jruoho aprint_error_dev(self, "failed to add " 513 1.1 jruoho "sensor: %s\n", AcpiFormatException(rv)); 514 1.1 jruoho } 515 1.1 jruoho } 516 1.1 jruoho 517 1.1 jruoho static bool 518 1.1 jruoho aibs_sensor_value(device_t self, struct aibs_sensor *as, uint64_t *val) 519 1.1 jruoho { 520 1.1 jruoho struct aibs_softc *sc = device_private(self); 521 1.1 jruoho uint32_t type, *ret, cmb[3]; 522 1.1 jruoho ACPI_OBJECT_LIST arg; 523 1.1 jruoho ACPI_OBJECT cmi, tmp; 524 1.1 jruoho ACPI_OBJECT *obj; 525 1.1 jruoho ACPI_BUFFER buf; 526 1.1 jruoho ACPI_STATUS rv; 527 1.1 jruoho const char *path; 528 1.1 jruoho 529 1.1 jruoho if (sc->sc_model != false) { 530 1.1 jruoho 531 1.1 jruoho path = "GITM"; 532 1.1 jruoho 533 1.1 jruoho cmb[0] = as->as_type; 534 1.1 jruoho cmb[1] = 0; 535 1.1 jruoho cmb[2] = 0; 536 1.1 jruoho 537 1.1 jruoho arg.Count = 1; 538 1.1 jruoho arg.Pointer = &tmp; 539 1.1 jruoho 540 1.1 jruoho tmp.Buffer.Length = sizeof(cmb); 541 1.1 jruoho tmp.Buffer.Pointer = (uint8_t *)cmb; 542 1.1 jruoho tmp.Type = type = ACPI_TYPE_BUFFER; 543 1.1 jruoho 544 1.1 jruoho } else { 545 1.1 jruoho 546 1.1 jruoho arg.Count = 1; 547 1.1 jruoho arg.Pointer = &cmi; 548 1.1 jruoho 549 1.1 jruoho cmi.Integer.Value = as->as_type; 550 1.1 jruoho cmi.Type = type = ACPI_TYPE_INTEGER; 551 1.1 jruoho 552 1.1 jruoho switch (AIBS_TYPE(as->as_type)) { 553 1.1 jruoho 554 1.1 jruoho case AIBS_TYPE_FAN: 555 1.1 jruoho path = "RFAN"; 556 1.1 jruoho break; 557 1.1 jruoho 558 1.1 jruoho case AIBS_TYPE_TEMP: 559 1.1 jruoho path = "RTMP"; 560 1.1 jruoho break; 561 1.1 jruoho 562 1.1 jruoho case AIBS_TYPE_VOLT: 563 1.1 jruoho path = "RVLT"; 564 1.1 jruoho break; 565 1.1 jruoho 566 1.1 jruoho default: 567 1.1 jruoho return false; 568 1.1 jruoho } 569 1.1 jruoho } 570 1.1 jruoho 571 1.1 jruoho buf.Pointer = NULL; 572 1.1 jruoho buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER; 573 1.1 jruoho 574 1.1 jruoho rv = AcpiEvaluateObject(sc->sc_node->ad_handle, path, &arg, &buf); 575 1.1 jruoho 576 1.1 jruoho if (ACPI_FAILURE(rv)) 577 1.1 jruoho goto out; 578 1.1 jruoho 579 1.1 jruoho obj = buf.Pointer; 580 1.1 jruoho 581 1.1 jruoho if (obj->Type != type) { 582 1.1 jruoho rv = AE_TYPE; 583 1.1 jruoho goto out; 584 1.1 jruoho } 585 1.1 jruoho 586 1.1 jruoho if (sc->sc_model != true) 587 1.1 jruoho *val = obj->Integer.Value; 588 1.1 jruoho else { 589 1.1 jruoho /* 590 1.1 jruoho * The return buffer contains at least: 591 1.1 jruoho * 592 1.1 jruoho * uint32_t buf[0] flags 593 1.1 jruoho * uint32_t buf[1] return value 594 1.1 jruoho * uint8_t buf[2-] unknown 595 1.1 jruoho */ 596 1.1 jruoho if (obj->Buffer.Length < 8) { 597 1.1 jruoho rv = AE_BUFFER_OVERFLOW; 598 1.1 jruoho goto out; 599 1.1 jruoho } 600 1.1 jruoho 601 1.1 jruoho ret = (uint32_t *)obj->Buffer.Pointer; 602 1.1 jruoho 603 1.1 jruoho if (ret[0] == 0) { 604 1.1 jruoho rv = AE_BAD_VALUE; 605 1.1 jruoho goto out; 606 1.1 jruoho } 607 1.1 jruoho 608 1.1 jruoho *val = ret[1]; 609 1.1 jruoho } 610 1.1 jruoho 611 1.1 jruoho out: 612 1.1 jruoho if (buf.Pointer != NULL) 613 1.1 jruoho ACPI_FREE(buf.Pointer); 614 1.1 jruoho 615 1.1 jruoho if (ACPI_FAILURE(rv)) { 616 1.1 jruoho 617 1.1 jruoho aprint_error_dev(self, "failed to evaluate " 618 1.1 jruoho "%s: %s\n", path, AcpiFormatException(rv)); 619 1.1 jruoho 620 1.1 jruoho return false; 621 1.1 jruoho } 622 1.1 jruoho 623 1.1 jruoho return true; 624 1.1 jruoho } 625 1.1 jruoho 626 1.1 jruoho static void 627 1.1 jruoho aibs_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 628 1.1 jruoho { 629 1.1 jruoho struct aibs_softc *sc = sme->sme_cookie; 630 1.1 jruoho struct aibs_sensor *tmp, *as = NULL; 631 1.1 jruoho envsys_data_t *s = edata; 632 1.1 jruoho uint64_t val = 0; 633 1.1 jruoho 634 1.1 jruoho SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) { 635 1.1 jruoho 636 1.1 jruoho if (tmp->as_sensor.sensor == s->sensor) { 637 1.1 jruoho as = tmp; 638 1.1 jruoho break; 639 1.1 jruoho } 640 1.1 jruoho } 641 1.1 jruoho 642 1.1 jruoho if (as == NULL) { 643 1.1 jruoho aprint_debug_dev(sc->sc_dev, "failed to find sensor\n"); 644 1.1 jruoho return; 645 1.1 jruoho } 646 1.1 jruoho 647 1.1 jruoho as->as_sensor.state = ENVSYS_SINVALID; 648 1.1 jruoho as->as_sensor.flags |= ENVSYS_FMONNOTSUPP; 649 1.1 jruoho 650 1.1 jruoho if (aibs_sensor_value(sc->sc_dev, as, &val) != true) 651 1.1 jruoho return; 652 1.1 jruoho 653 1.1 jruoho switch (as->as_sensor.units) { 654 1.1 jruoho 655 1.1 jruoho case ENVSYS_SFANRPM: 656 1.1 jruoho as->as_sensor.value_cur = val; 657 1.1 jruoho break; 658 1.1 jruoho 659 1.1 jruoho case ENVSYS_STEMP: 660 1.1 jruoho 661 1.1 jruoho if (val == 0) 662 1.1 jruoho return; 663 1.1 jruoho 664 1.1 jruoho as->as_sensor.value_cur = val * 100 * 1000 + 273150000; 665 1.1 jruoho break; 666 1.1 jruoho 667 1.1 jruoho case ENVSYS_SVOLTS_DC: 668 1.1 jruoho as->as_sensor.value_cur = val * 1000; 669 1.1 jruoho break; 670 1.1 jruoho 671 1.1 jruoho default: 672 1.1 jruoho return; 673 1.1 jruoho } 674 1.1 jruoho 675 1.1 jruoho as->as_sensor.state = ENVSYS_SVALID; 676 1.1 jruoho as->as_sensor.flags &= ~ENVSYS_FMONNOTSUPP; 677 1.1 jruoho } 678 1.1 jruoho 679 1.1 jruoho static void 680 1.1 jruoho aibs_sensor_limits(struct sysmon_envsys *sme, envsys_data_t *edata, 681 1.1 jruoho sysmon_envsys_lim_t *limits, uint32_t *props) 682 1.1 jruoho { 683 1.1 jruoho struct aibs_softc *sc = sme->sme_cookie; 684 1.1 jruoho struct aibs_sensor *tmp, *as = NULL; 685 1.1 jruoho sysmon_envsys_lim_t *lim = limits; 686 1.1 jruoho envsys_data_t *s = edata; 687 1.1 jruoho 688 1.1 jruoho SIMPLEQ_FOREACH(tmp, &sc->as_head, as_list) { 689 1.1 jruoho 690 1.1 jruoho if (tmp->as_sensor.sensor == s->sensor) { 691 1.1 jruoho as = tmp; 692 1.1 jruoho break; 693 1.1 jruoho } 694 1.1 jruoho } 695 1.1 jruoho 696 1.1 jruoho if (as == NULL) { 697 1.1 jruoho aprint_debug_dev(sc->sc_dev, "failed to find sensor\n"); 698 1.1 jruoho return; 699 1.1 jruoho } 700 1.1 jruoho 701 1.1 jruoho switch (as->as_sensor.units) { 702 1.1 jruoho 703 1.1 jruoho case ENVSYS_SFANRPM: 704 1.1 jruoho 705 1.1 jruoho /* 706 1.1 jruoho * Some boards have strange limits for fans. 707 1.1 jruoho */ 708 1.1 jruoho if (as->as_liml == 0) { 709 1.1 jruoho lim->sel_warnmin = as->as_limh; 710 1.1 jruoho *props = PROP_WARNMIN; 711 1.1 jruoho 712 1.1 jruoho } else { 713 1.1 jruoho lim->sel_warnmin = as->as_liml; 714 1.1 jruoho lim->sel_warnmax = as->as_limh; 715 1.1 jruoho *props = PROP_WARNMIN | PROP_WARNMAX; 716 1.1 jruoho } 717 1.1 jruoho 718 1.1 jruoho break; 719 1.1 jruoho 720 1.1 jruoho case ENVSYS_STEMP: 721 1.1 jruoho lim->sel_critmax = as->as_limh * 100 * 1000 + 273150000; 722 1.1 jruoho lim->sel_warnmax = as->as_liml * 100 * 1000 + 273150000; 723 1.1 jruoho 724 1.1 jruoho *props = PROP_CRITMAX | PROP_WARNMAX; 725 1.1 jruoho break; 726 1.1 jruoho 727 1.1 jruoho case ENVSYS_SVOLTS_DC: 728 1.1 jruoho lim->sel_critmin = as->as_liml * 1000; 729 1.1 jruoho lim->sel_critmax = as->as_limh * 1000; 730 1.1 jruoho *props = PROP_CRITMIN | PROP_CRITMAX; 731 1.1 jruoho break; 732 1.1 jruoho 733 1.1 jruoho default: 734 1.1 jruoho return; 735 1.1 jruoho } 736 1.1 jruoho } 737 1.1 jruoho 738 1.5 pgoyette MODULE(MODULE_CLASS_DRIVER, aibs, "sysmon_envsys"); 739 1.1 jruoho 740 1.1 jruoho #ifdef _MODULE 741 1.1 jruoho #include "ioconf.c" 742 1.1 jruoho #endif 743 1.1 jruoho 744 1.1 jruoho static int 745 1.1 jruoho aibs_modcmd(modcmd_t cmd, void *aux) 746 1.1 jruoho { 747 1.1 jruoho int rv = 0; 748 1.1 jruoho 749 1.1 jruoho switch (cmd) { 750 1.1 jruoho 751 1.1 jruoho case MODULE_CMD_INIT: 752 1.1 jruoho 753 1.1 jruoho #ifdef _MODULE 754 1.1 jruoho rv = config_init_component(cfdriver_ioconf_aibs, 755 1.1 jruoho cfattach_ioconf_aibs, cfdata_ioconf_aibs); 756 1.1 jruoho #endif 757 1.1 jruoho break; 758 1.1 jruoho 759 1.1 jruoho case MODULE_CMD_FINI: 760 1.1 jruoho 761 1.1 jruoho #ifdef _MODULE 762 1.1 jruoho rv = config_fini_component(cfdriver_ioconf_aibs, 763 1.1 jruoho cfattach_ioconf_aibs, cfdata_ioconf_aibs); 764 1.1 jruoho #endif 765 1.1 jruoho break; 766 1.1 jruoho 767 1.1 jruoho default: 768 1.1 jruoho rv = ENOTTY; 769 1.1 jruoho } 770 1.1 jruoho 771 1.1 jruoho return rv; 772 1.1 jruoho } 773