1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 /* 31 * Driver for Apple's System Management Console (SMC). 32 * SMC can be found on the MacBook, MacBook Pro and Mac Mini. 33 * 34 * Inspired by the Linux applesmc driver. 35 */ 36 37 #include "opt_asmc.h" 38 39 #include <sys/param.h> 40 #include <sys/bus.h> 41 #include <sys/conf.h> 42 #include <sys/endian.h> 43 #include <sys/kernel.h> 44 #include <sys/lock.h> 45 #include <sys/malloc.h> 46 #include <sys/module.h> 47 #include <sys/mutex.h> 48 #include <sys/sbuf.h> 49 #include <sys/sysctl.h> 50 #include <sys/systm.h> 51 #include <sys/taskqueue.h> 52 #include <sys/rman.h> 53 54 #include <machine/resource.h> 55 #include <netinet/in.h> 56 57 #include <contrib/dev/acpica/include/acpi.h> 58 59 #include <dev/acpica/acpivar.h> 60 #include <dev/asmc/asmcvar.h> 61 62 #include <dev/backlight/backlight.h> 63 #include "backlight_if.h" 64 65 /* 66 * Device interface. 67 */ 68 static int asmc_probe(device_t dev); 69 static int asmc_attach(device_t dev); 70 static int asmc_detach(device_t dev); 71 static int asmc_resume(device_t dev); 72 73 /* 74 * Backlight interface. 75 */ 76 static int asmc_backlight_update_status(device_t dev, 77 struct backlight_props *props); 78 static int asmc_backlight_get_status(device_t dev, 79 struct backlight_props *props); 80 static int asmc_backlight_get_info(device_t dev, struct backlight_info *info); 81 82 /* 83 * SMC functions. 84 */ 85 static int asmc_init(device_t dev); 86 static int asmc_command(device_t dev, uint8_t command); 87 static int asmc_wait(device_t dev, uint8_t val); 88 static int asmc_wait_ack(device_t dev, uint8_t val, int amount); 89 static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 90 uint8_t len); 91 static int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 92 uint8_t); 93 static int asmc_fan_count(device_t dev); 94 static int asmc_fan_getvalue(device_t dev, const char *key, int fan); 95 static int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed); 96 static int asmc_temp_getvalue(device_t dev, const char *key); 97 static int asmc_sms_read(device_t, const char *key, int16_t *val); 98 static void asmc_sms_calibrate(device_t dev); 99 static int asmc_sms_intrfast(void *arg); 100 static void asmc_sms_printintr(device_t dev, uint8_t); 101 static void asmc_sms_task(void *arg, int pending); 102 static void asmc_sms_init(device_t dev); 103 static void asmc_detect_capabilities(device_t dev); 104 #ifdef ASMC_DEBUG 105 void asmc_dumpall(device_t); 106 static int asmc_key_dump(device_t, int); 107 #endif 108 109 /* 110 * Sysctl handlers. 111 */ 112 static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS); 113 static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 114 static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 115 static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 116 static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 117 static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 118 static int asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS); 119 static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 120 static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 121 static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 122 static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 123 static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 124 static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 125 static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); 126 static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS); 127 static int asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS); 128 129 static int asmc_key_getinfo(device_t, const char *, uint8_t *, char *); 130 131 #ifdef ASMC_DEBUG 132 /* Raw key access */ 133 static int asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS); 134 static int asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS); 135 static int asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS); 136 static int asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS); 137 #endif 138 139 /* Voltage/Current/Power/Light sensor support */ 140 static int asmc_sensor_read(device_t, const char *, int *); 141 static int asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS); 142 static int asmc_detect_sensors(device_t); 143 static int asmc_key_dump_by_index(device_t, int, char *, char *, uint8_t *); 144 static int asmc_key_search(device_t, const char *, unsigned int *); 145 static const char *asmc_temp_desc(const char *key); 146 147 /* 148 * SMC temperature key descriptions. 149 * These are universal across all Intel Apple hardware. 150 */ 151 static const struct { 152 const char *key; 153 const char *desc; 154 } asmc_temp_descs[] = { 155 /* Ambient / airflow */ 156 { "TA0P", "Ambient" }, 157 { "TA0S", "PCIe Slot 1 Ambient" }, 158 { "TA0p", "Ambient Air" }, 159 { "TA1P", "Ambient 2" }, 160 { "TA1S", "PCIe Slot 1 PCB" }, 161 { "TA1p", "Ambient Air 2" }, 162 { "TA2P", "Ambient 3" }, 163 { "TA2S", "PCIe Slot 2 Ambient" }, 164 { "TA3S", "PCIe Slot 2 PCB" }, 165 { "TA0V", "Ambient" }, 166 { "TALP", "Ambient Light Proximity" }, 167 { "TaLC", "Airflow Left" }, 168 { "TaRC", "Airflow Right" }, 169 { "Ta0P", "Airflow Proximity" }, 170 /* Battery / enclosure */ 171 { "TB0T", "Enclosure Bottom" }, 172 { "TB1T", "Battery 1" }, 173 { "TB2T", "Battery 2" }, 174 { "TB3T", "Battery 3" }, 175 { "TBXT", "Battery" }, 176 { "Tb0P", "BLC Proximity" }, 177 /* CPU */ 178 { "TC0C", "CPU Core 1" }, 179 { "TC0D", "CPU Die" }, 180 { "TC0E", "CPU 1" }, 181 { "TC0F", "CPU 2" }, 182 { "TC0G", "CPU Package GPU" }, 183 { "TC0H", "CPU Heatsink" }, 184 { "TC0h", "CPU Heatsink" }, 185 { "TC0J", "CPU" }, 186 { "TC0P", "CPU Proximity" }, 187 { "TC0c", "CPU Core 1 PECI" }, 188 { "TC0d", "CPU Die PECI" }, 189 { "TC0p", "CPU Proximity" }, 190 { "TC1C", "CPU Core 2" }, 191 { "TC1c", "CPU Core 2 PECI" }, 192 { "TC1P", "CPU Proximity 2" }, 193 { "TC2C", "CPU Core 3" }, 194 { "TC2P", "CPU Proximity 3" }, 195 { "TC2c", "CPU Core 3 PECI" }, 196 { "TC3C", "CPU Core 4" }, 197 { "TC3P", "CPU Proximity 4" }, 198 { "TC3c", "CPU Core 4 PECI" }, 199 { "TC4C", "CPU Core 5" }, 200 { "TC5C", "CPU Core 6" }, 201 { "TC6C", "CPU Core 7" }, 202 { "TC7C", "CPU Core 8" }, 203 { "TC8C", "CPU Core 9" }, 204 { "TCGC", "PECI GPU" }, 205 { "TCGc", "PECI GPU" }, 206 { "TCHP", "Charger Proximity" }, 207 { "TCSA", "PECI SA" }, 208 { "TCSC", "PECI SA" }, 209 { "TCSc", "PECI SA" }, 210 { "TCTD", "CPU DTS" }, 211 { "TCXC", "PECI CPU" }, 212 { "TCXc", "PECI CPU" }, 213 { "TCPG", "CPU Package GPU" }, 214 { "TCXR", "CPU PECI DTS" }, 215 /* CPU dual-socket (Mac Pro) */ 216 { "TCAG", "CPU A Package" }, 217 { "TCAH", "CPU A Heatsink" }, 218 { "TCBG", "CPU B Package" }, 219 { "TCBH", "CPU B Heatsink" }, 220 /* GPU */ 221 { "TG0C", "GPU Core" }, 222 { "TG0D", "GPU Diode" }, 223 { "TG0H", "GPU Heatsink" }, 224 { "TG0M", "GPU Memory" }, 225 { "TG0P", "GPU Proximity" }, 226 { "TG0T", "GPU Diode" }, 227 { "TG0V", "GPU" }, 228 { "TG0d", "GPU Die" }, 229 { "TG0h", "GPU Heatsink" }, 230 { "TG0p", "GPU Proximity" }, 231 { "TGTV", "GPU" }, 232 { "TG1D", "GPU 2 Diode" }, 233 { "TG1H", "GPU 2 Heatsink" }, 234 { "TG1P", "GPU 2 Proximity" }, 235 { "TG1d", "GPU 2 Die" }, 236 { "TGVP", "GPU Memory Proximity" }, 237 /* Storage */ 238 { "TH0A", "SSD A" }, 239 { "TH0B", "SSD B" }, 240 { "TH0C", "SSD C" }, 241 { "TH0F", "SSD" }, 242 { "TH0O", "HDD" }, 243 { "TH0P", "HDD Proximity" }, 244 { "TH0R", "SSD" }, 245 { "TH0V", "SSD" }, 246 { "TH0a", "SSD A" }, 247 { "TH0b", "SSD B" }, 248 { "TH0c", "SSD C" }, 249 { "TH1O", "HDD 2" }, 250 { "TH1P", "HDD Bay 2" }, 251 { "TH2P", "HDD Bay 3" }, 252 { "TH3P", "HDD Bay 4" }, 253 { "Th0H", "Heatpipe 1" }, 254 { "Th0N", "SSD" }, 255 { "Th1H", "Heatpipe 2" }, 256 { "Th2H", "Heatpipe 3" }, 257 /* Thunderbolt */ 258 { "THSP", "Thunderbolt Proximity" }, 259 { "TI0P", "Thunderbolt 1" }, 260 { "TI0p", "Thunderbolt 1" }, 261 { "TI1P", "Thunderbolt 2" }, 262 { "TI1p", "Thunderbolt 2" }, 263 { "TTLD", "Thunderbolt Left" }, 264 { "TTRD", "Thunderbolt Right" }, 265 { "Te0T", "Thunderbolt Diode" }, 266 { "Te0t", "Thunderbolt Diode" }, 267 /* LCD */ 268 { "TL0P", "LCD Proximity" }, 269 { "TL0V", "LCD" }, 270 { "TL0p", "LCD Proximity" }, 271 { "TL1P", "LCD Panel 1" }, 272 { "TL1V", "LCD 1" }, 273 { "TL1p", "LCD Panel 1" }, 274 { "TL1v", "LCD 1" }, 275 { "TL2V", "LCD 2" }, 276 { "TLAV", "LCD" }, 277 { "TLBV", "LCD" }, 278 { "TLCV", "LCD" }, 279 /* Memory */ 280 { "TM0P", "Memory Proximity" }, 281 { "TM0S", "Memory Slot 1" }, 282 { "TM0p", "Memory Proximity" }, 283 { "TM1P", "Memory Riser A 2" }, 284 { "TM1S", "Memory Slot 2" }, 285 { "Tm0P", "Memory Proximity" }, 286 { "Tm0p", "Memory Proximity" }, 287 { "Tm1P", "Memory Proximity 2" }, 288 { "TMBS", "Memory Bank" }, 289 { "TMCD", "Memory DIMM" }, 290 /* Northbridge / MCH */ 291 { "TN0C", "Northbridge Core" }, 292 { "TN0D", "Northbridge Diode" }, 293 { "TN0H", "MCH Heatsink" }, 294 { "TN0P", "Northbridge Proximity" }, 295 { "TN1D", "MCH Die 2" }, 296 { "TN1P", "Northbridge Proximity 2" }, 297 /* PCH */ 298 { "TP0P", "PCH Proximity" }, 299 { "TP0p", "PCH Proximity" }, 300 { "TPCD", "PCH Die" }, 301 { "TPCd", "PCH Die" }, 302 /* Optical drive */ 303 { "TO0P", "Optical Drive" }, 304 { "TO0p", "Optical Drive" }, 305 /* Power supply */ 306 { "Tp0C", "Power Supply" }, 307 { "Tp0P", "Power Supply Proximity" }, 308 { "Tp1C", "Power Supply 2" }, 309 { "Tp1P", "Power Supply Component" }, 310 { "Tp1p", "Power Supply Component" }, 311 { "Tp2P", "Power Supply 2" }, 312 { "Tp2h", "Power Supply 2" }, 313 { "Tp2H", "Power Supply 2" }, 314 { "Tp3P", "Power Supply 3 Inlet" }, 315 { "Tp3h", "Power Supply 3" }, 316 { "Tp3H", "Power Supply 3" }, 317 { "Tp4P", "Power Supply 4" }, 318 { "Tp5P", "Power Supply 5" }, 319 /* Palm rest / trackpad */ 320 { "Ts0P", "Palm Rest" }, 321 { "Ts0S", "Memory Proximity" }, 322 { "Ts1P", "Palm Rest 2" }, 323 { "Ts1S", "Palm Rest 2" }, 324 /* Wireless */ 325 { "TW0P", "Wireless Proximity" }, 326 { "TW0p", "Wireless Proximity" }, 327 { "TBLR", "Bluetooth" }, 328 /* Camera */ 329 { "TS2P", "Camera Proximity" }, 330 { "TS2V", "Camera" }, 331 { "TS2p", "Camera Proximity" }, 332 /* Expansion */ 333 { "TS0C", "Expansion Slots" }, 334 { "TS0P", "Expansion Proximity" }, 335 { "TS0V", "Expansion" }, 336 { "TS0p", "Expansion Proximity" }, 337 /* Air vent */ 338 { "TV0P", "Air Vent" }, 339 /* VRM */ 340 { "Tv0S", "VRM 1" }, 341 { "Tv1S", "VRM 2" }, 342 /* Misc */ 343 { "TTF0", "Fan" }, 344 { "TMLB", "Logic Board" }, 345 }; 346 347 static const char * 348 asmc_temp_desc(const char *key) 349 { 350 unsigned int i; 351 352 for (i = 0; i < nitems(asmc_temp_descs); i++) { 353 if (strcmp(asmc_temp_descs[i].key, key) == 0) 354 return (asmc_temp_descs[i].desc); 355 } 356 return ("Temperature"); 357 } 358 359 /* 360 * Driver methods. 361 */ 362 static device_method_t asmc_methods[] = { 363 DEVMETHOD(device_probe, asmc_probe), 364 DEVMETHOD(device_attach, asmc_attach), 365 DEVMETHOD(device_detach, asmc_detach), 366 DEVMETHOD(device_resume, asmc_resume), 367 368 /* Backlight interface */ 369 DEVMETHOD(backlight_update_status, asmc_backlight_update_status), 370 DEVMETHOD(backlight_get_status, asmc_backlight_get_status), 371 DEVMETHOD(backlight_get_info, asmc_backlight_get_info), 372 373 DEVMETHOD_END 374 }; 375 376 static driver_t asmc_driver = { 377 "asmc", 378 asmc_methods, 379 sizeof(struct asmc_softc) 380 }; 381 382 /* 383 * Debugging 384 */ 385 #define _COMPONENT ACPI_OEM 386 ACPI_MODULE_NAME("ASMC") 387 #ifdef ASMC_DEBUG 388 #define ASMC_DPRINTF(str, ...) device_printf(dev, str, ##__VA_ARGS__) 389 #else 390 #define ASMC_DPRINTF(str, ...) 391 #endif 392 393 /* NB: can't be const */ 394 static char *asmc_ids[] = { "APP0001", NULL }; 395 396 static unsigned int light_control = 0; 397 398 ACPI_PNP_INFO(asmc_ids); 399 DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL); 400 MODULE_DEPEND(asmc, acpi, 1, 1, 1); 401 MODULE_DEPEND(asmc, backlight, 1, 1, 1); 402 403 static int 404 asmc_probe(device_t dev) 405 { 406 char *product; 407 int rv; 408 409 if (resource_disabled("asmc", 0)) 410 return (ENXIO); 411 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL); 412 if (rv > 0) 413 return (rv); 414 product = kern_getenv("smbios.system.product"); 415 device_set_descf(dev, "Apple %s", product ? product : "SMC"); 416 freeenv(product); 417 return (rv); 418 } 419 420 static int 421 asmc_attach(device_t dev) 422 { 423 int i, j; 424 int ret; 425 char name[2]; 426 struct asmc_softc *sc = device_get_softc(dev); 427 struct sysctl_ctx_list *sysctlctx; 428 struct sysctl_oid *sysctlnode; 429 430 sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 431 &sc->sc_rid_port, RF_ACTIVE); 432 if (sc->sc_ioport == NULL) { 433 device_printf(dev, "unable to allocate IO port\n"); 434 return (ENOMEM); 435 } 436 437 sysctlctx = device_get_sysctl_ctx(dev); 438 sysctlnode = device_get_sysctl_tree(dev); 439 440 mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 441 442 /* Read SMC revision, key count, fan count */ 443 ret = asmc_init(dev); 444 if (ret != 0) { 445 device_printf(dev, "SMC not responding\n"); 446 goto err; 447 } 448 449 /* Probe SMC keys to detect capabilities */ 450 asmc_detect_capabilities(dev); 451 452 /* Auto-detect and register voltage/current/power/ambient/temp sensors */ 453 asmc_detect_sensors(dev); 454 455 /* 456 * dev.asmc.n.fan.* tree. 457 */ 458 sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 459 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 460 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree"); 461 462 for (i = 1; i <= sc->sc_nfan; i++) { 463 j = i - 1; 464 name[0] = '0' + j; 465 name[1] = 0; 466 sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 467 SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name, 468 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree"); 469 470 SYSCTL_ADD_PROC(sysctlctx, 471 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 472 OID_AUTO, "id", 473 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, 474 asmc_mb_sysctl_fanid, "I", "Fan ID"); 475 476 SYSCTL_ADD_PROC(sysctlctx, 477 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 478 OID_AUTO, "speed", 479 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, 480 asmc_mb_sysctl_fanspeed, "I", "Fan speed in RPM"); 481 482 if (sc->sc_has_safespeed) { 483 SYSCTL_ADD_PROC(sysctlctx, 484 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 485 OID_AUTO, "safespeed", 486 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, 487 asmc_mb_sysctl_fansafespeed, "I", 488 "Fan safe speed in RPM"); 489 } 490 491 SYSCTL_ADD_PROC(sysctlctx, 492 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 493 OID_AUTO, "minspeed", 494 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, 495 asmc_mb_sysctl_fanminspeed, "I", 496 "Fan minimum speed in RPM"); 497 498 SYSCTL_ADD_PROC(sysctlctx, 499 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 500 OID_AUTO, "maxspeed", 501 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, 502 asmc_mb_sysctl_fanmaxspeed, "I", 503 "Fan maximum speed in RPM"); 504 505 SYSCTL_ADD_PROC(sysctlctx, 506 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 507 OID_AUTO, "targetspeed", 508 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, 509 asmc_mb_sysctl_fantargetspeed, "I", 510 "Fan target speed in RPM"); 511 512 SYSCTL_ADD_PROC(sysctlctx, 513 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 514 OID_AUTO, "manual", 515 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, 516 asmc_mb_sysctl_fanmanual, "I", 517 "Fan manual mode (0=auto, 1=manual)"); 518 } 519 520 /* 521 * dev.asmc.n.temp tree. 522 */ 523 sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 524 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 525 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors"); 526 527 for (i = 0; i < sc->sc_temp_count; i++) { 528 SYSCTL_ADD_PROC(sysctlctx, 529 SYSCTL_CHILDREN(sc->sc_temp_tree), 530 OID_AUTO, sc->sc_temp_sensors[i], 531 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, i, 532 asmc_temp_sysctl, "I", 533 asmc_temp_desc(sc->sc_temp_sensors[i])); 534 } 535 536 /* 537 * dev.asmc.n.light 538 */ 539 if (sc->sc_has_light) { 540 sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 541 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 542 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 543 "Keyboard backlight sensors"); 544 545 SYSCTL_ADD_PROC(sysctlctx, 546 SYSCTL_CHILDREN(sc->sc_light_tree), 547 OID_AUTO, "left", 548 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 549 dev, 0, 550 sc->sc_light_len == ASMC_LIGHT_LONGLEN ? 551 asmc_mbp_sysctl_light_left_10byte : 552 asmc_mbp_sysctl_light_left, 553 "I", "Keyboard backlight left sensor"); 554 555 if (sc->sc_light_len != ASMC_LIGHT_LONGLEN && 556 asmc_key_getinfo(dev, ASMC_KEY_LIGHTRIGHT, 557 NULL, NULL) == 0) { 558 SYSCTL_ADD_PROC(sysctlctx, 559 SYSCTL_CHILDREN(sc->sc_light_tree), 560 OID_AUTO, "right", 561 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 562 dev, 0, 563 asmc_mbp_sysctl_light_right, "I", 564 "Keyboard backlight right sensor"); 565 } 566 567 SYSCTL_ADD_PROC(sysctlctx, 568 SYSCTL_CHILDREN(sc->sc_light_tree), 569 OID_AUTO, "control", 570 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, 571 dev, 0, asmc_mbp_sysctl_light_control, "I", 572 "Keyboard backlight brightness control"); 573 574 sc->sc_kbd_bkl = backlight_register("asmc", dev); 575 if (sc->sc_kbd_bkl == NULL) { 576 device_printf(dev, "Can not register backlight\n"); 577 ret = ENXIO; 578 goto err; 579 } 580 } 581 582 #ifdef ASMC_DEBUG 583 /* 584 * Raw SMC key access for debugging. 585 */ 586 sc->sc_raw_tree = SYSCTL_ADD_NODE(sysctlctx, 587 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 588 "raw", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Raw SMC key access"); 589 590 SYSCTL_ADD_PROC(sysctlctx, 591 SYSCTL_CHILDREN(sc->sc_raw_tree), 592 OID_AUTO, "key", 593 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 594 dev, 0, asmc_raw_key_sysctl, "A", 595 "SMC key name (4 chars)"); 596 597 SYSCTL_ADD_PROC(sysctlctx, 598 SYSCTL_CHILDREN(sc->sc_raw_tree), 599 OID_AUTO, "value", 600 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 601 dev, 0, asmc_raw_value_sysctl, "A", 602 "SMC key value (hex string)"); 603 604 SYSCTL_ADD_PROC(sysctlctx, 605 SYSCTL_CHILDREN(sc->sc_raw_tree), 606 OID_AUTO, "len", 607 CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE, 608 dev, 0, asmc_raw_len_sysctl, "CU", 609 "SMC key value length"); 610 611 SYSCTL_ADD_PROC(sysctlctx, 612 SYSCTL_CHILDREN(sc->sc_raw_tree), 613 OID_AUTO, "type", 614 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 615 dev, 0, asmc_raw_type_sysctl, "A", 616 "SMC key type (4 chars)"); 617 #endif 618 619 if (!sc->sc_has_sms) 620 goto nosms; 621 622 /* 623 * Initialize SMS hardware. 624 */ 625 asmc_sms_init(dev); 626 627 /* 628 * dev.asmc.n.sms tree. 629 */ 630 sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 631 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 632 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor"); 633 634 SYSCTL_ADD_PROC(sysctlctx, 635 SYSCTL_CHILDREN(sc->sc_sms_tree), 636 OID_AUTO, "x", 637 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 638 dev, 0, asmc_mb_sysctl_sms_x, "I", 639 "Sudden Motion Sensor X value"); 640 641 SYSCTL_ADD_PROC(sysctlctx, 642 SYSCTL_CHILDREN(sc->sc_sms_tree), 643 OID_AUTO, "y", 644 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 645 dev, 0, asmc_mb_sysctl_sms_y, "I", 646 "Sudden Motion Sensor Y value"); 647 648 SYSCTL_ADD_PROC(sysctlctx, 649 SYSCTL_CHILDREN(sc->sc_sms_tree), 650 OID_AUTO, "z", 651 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 652 dev, 0, asmc_mb_sysctl_sms_z, "I", 653 "Sudden Motion Sensor Z value"); 654 655 /* 656 * Need a taskqueue to send devctl_notify() events 657 * when the SMS interrupt us. 658 * 659 * PI_REALTIME is used due to the sensitivity of the 660 * interrupt. An interrupt from the SMS means that the 661 * disk heads should be turned off as quickly as possible. 662 * 663 * We only need to do this for the non INTR_FILTER case. 664 */ 665 sc->sc_sms_tq = NULL; 666 TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 667 sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 668 taskqueue_thread_enqueue, &sc->sc_sms_tq); 669 taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 670 device_get_nameunit(dev)); 671 /* 672 * Allocate an IRQ for the SMS. 673 */ 674 sc->sc_rid_irq = 0; 675 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq, 676 RF_ACTIVE); 677 if (sc->sc_irq == NULL) { 678 device_printf(dev, "unable to allocate IRQ resource\n"); 679 ret = ENXIO; 680 goto err; 681 } 682 683 ret = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, 684 asmc_sms_intrfast, NULL, dev, &sc->sc_cookie); 685 if (ret) { 686 device_printf(dev, "unable to setup SMS IRQ\n"); 687 goto err; 688 } 689 690 nosms: 691 return (0); 692 693 err: 694 asmc_detach(dev); 695 696 return (ret); 697 } 698 699 static int 700 asmc_detach(device_t dev) 701 { 702 struct asmc_softc *sc = device_get_softc(dev); 703 704 if (sc->sc_kbd_bkl != NULL) 705 backlight_destroy(sc->sc_kbd_bkl); 706 707 /* Free temperature sensor key arrays */ 708 for (int i = 0; i < sc->sc_temp_count; i++) 709 free(sc->sc_temp_sensors[i], M_DEVBUF); 710 711 /* Free sensor key arrays */ 712 for (int i = 0; i < sc->sc_voltage_count; i++) 713 free(sc->sc_voltage_sensors[i], M_DEVBUF); 714 for (int i = 0; i < sc->sc_current_count; i++) 715 free(sc->sc_current_sensors[i], M_DEVBUF); 716 for (int i = 0; i < sc->sc_power_count; i++) 717 free(sc->sc_power_sensors[i], M_DEVBUF); 718 for (int i = 0; i < sc->sc_light_count; i++) 719 free(sc->sc_light_sensors[i], M_DEVBUF); 720 721 if (sc->sc_sms_tq) { 722 taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 723 taskqueue_free(sc->sc_sms_tq); 724 sc->sc_sms_tq = NULL; 725 } 726 if (sc->sc_cookie) { 727 bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 728 sc->sc_cookie = NULL; 729 } 730 if (sc->sc_irq) { 731 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 732 sc->sc_irq); 733 sc->sc_irq = NULL; 734 } 735 if (sc->sc_ioport) { 736 bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 737 sc->sc_ioport); 738 sc->sc_ioport = NULL; 739 } 740 if (mtx_initialized(&sc->sc_mtx)) { 741 mtx_destroy(&sc->sc_mtx); 742 } 743 744 return (0); 745 } 746 747 static int 748 asmc_resume(device_t dev) 749 { 750 uint8_t buf[2]; 751 752 buf[0] = light_control; 753 buf[1] = 0x00; 754 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); 755 756 return (0); 757 } 758 759 #ifdef ASMC_DEBUG 760 void 761 asmc_dumpall(device_t dev) 762 { 763 struct asmc_softc *sc = device_get_softc(dev); 764 int i; 765 766 if (sc->sc_nkeys == 0) { 767 device_printf(dev, "asmc_dumpall: key count not available\n"); 768 return; 769 } 770 771 device_printf(dev, "asmc_dumpall: dumping %d keys\n", sc->sc_nkeys); 772 for (i = 0; i < sc->sc_nkeys; i++) 773 asmc_key_dump(dev, i); 774 } 775 #endif 776 777 /* 778 * Initialize SMC: read revision, key count, fan count. 779 * SMS initialization is handled separately in asmc_sms_init(). 780 */ 781 static int 782 asmc_init(device_t dev) 783 { 784 struct asmc_softc *sc = device_get_softc(dev); 785 struct sysctl_ctx_list *sysctlctx; 786 uint8_t buf[6]; 787 int error; 788 789 sysctlctx = device_get_sysctl_ctx(dev); 790 791 error = asmc_key_read(dev, ASMC_KEY_REV, buf, 6); 792 if (error != 0) 793 goto out; 794 device_printf(dev, "SMC revision: %x.%x%x%x\n", buf[0], buf[1], buf[2], 795 ntohs(*(uint16_t *)buf + 4)); 796 797 /* Auto power-on after AC power loss (AUPO). */ 798 if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) { 799 SYSCTL_ADD_PROC(sysctlctx, 800 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 801 OID_AUTO, "auto_poweron", 802 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 803 dev, 0, asmc_aupo_sysctl, "I", 804 "Auto power-on after AC power loss (0=off, 1=on)"); 805 } 806 807 sc->sc_nfan = asmc_fan_count(dev); 808 if (sc->sc_nfan > ASMC_MAXFANS) { 809 device_printf(dev, 810 "more than %d fans were detected. Please report this.\n", 811 ASMC_MAXFANS); 812 sc->sc_nfan = ASMC_MAXFANS; 813 } 814 815 /* 816 * Read and cache the number of SMC keys (32 bit buffer) 817 */ 818 if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) { 819 sc->sc_nkeys = be32dec(buf); 820 if (bootverbose) 821 device_printf(dev, "number of keys: %d\n", 822 sc->sc_nkeys); 823 } else { 824 sc->sc_nkeys = 0; 825 } 826 827 out: 828 #ifdef ASMC_DEBUG 829 asmc_dumpall(dev); 830 #endif 831 return (error); 832 } 833 834 /* 835 * Initialize the Sudden Motion Sensor hardware. 836 * Called from asmc_attach() after capabilities are detected. 837 */ 838 static void 839 asmc_sms_init(device_t dev) 840 { 841 struct asmc_softc *sc = device_get_softc(dev); 842 uint8_t buf[2]; 843 int i; 844 845 /* 846 * We are ready to receive interrupts from the SMS. 847 */ 848 buf[0] = 0x01; 849 ASMC_DPRINTF(("intok key\n")); 850 asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 851 DELAY(50); 852 853 /* 854 * Initiate the polling intervals. 855 */ 856 buf[0] = 20; /* msecs */ 857 ASMC_DPRINTF(("low int key\n")); 858 asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 859 DELAY(200); 860 861 buf[0] = 20; /* msecs */ 862 ASMC_DPRINTF(("high int key\n")); 863 asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 864 DELAY(200); 865 866 buf[0] = 0x00; 867 buf[1] = 0x60; 868 ASMC_DPRINTF(("sms low key\n")); 869 asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 870 DELAY(200); 871 872 buf[0] = 0x01; 873 buf[1] = 0xc0; 874 ASMC_DPRINTF(("sms high key\n")); 875 asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 876 DELAY(200); 877 878 /* 879 * I'm not sure what this key does, but it seems to be 880 * required. 881 */ 882 buf[0] = 0x01; 883 ASMC_DPRINTF(("sms flag key\n")); 884 asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 885 DELAY(100); 886 887 sc->sc_sms_intr_works = 0; 888 889 /* 890 * Retry SMS initialization 1000 times 891 * (takes approx. 2 seconds in worst case) 892 */ 893 for (i = 0; i < 1000; i++) { 894 if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 895 (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 896 sc->sc_sms_intr_works = 1; 897 goto done; 898 } 899 buf[0] = ASMC_SMS_INIT1; 900 buf[1] = ASMC_SMS_INIT2; 901 ASMC_DPRINTF(("sms key\n")); 902 asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 903 DELAY(50); 904 } 905 device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 906 907 done: 908 asmc_sms_calibrate(dev); 909 } 910 911 /* 912 * Probe SMC keys to detect hardware capabilities. 913 */ 914 static void 915 asmc_detect_capabilities(device_t dev) 916 { 917 struct asmc_softc *sc = device_get_softc(dev); 918 uint8_t len; 919 char type[ASMC_TYPELEN + 1]; 920 921 /* SMS: require all keys used by asmc_sms_init() */ 922 sc->sc_has_sms = 923 (asmc_key_getinfo(dev, ASMC_KEY_SMS, 924 &len, type) == 0 && 925 asmc_key_getinfo(dev, ASMC_KEY_SMS_X, 926 &len, type) == 0 && 927 asmc_key_getinfo(dev, ASMC_KEY_SMS_Y, 928 &len, type) == 0 && 929 asmc_key_getinfo(dev, ASMC_KEY_SMS_Z, 930 &len, type) == 0 && 931 asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW, 932 &len, type) == 0 && 933 asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH, 934 &len, type) == 0 && 935 asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW_INT, 936 &len, type) == 0 && 937 asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH_INT, 938 &len, type) == 0 && 939 asmc_key_getinfo(dev, ASMC_KEY_SMS_FLAG, 940 &len, type) == 0 && 941 asmc_key_getinfo(dev, ASMC_KEY_INTOK, 942 &len, type) == 0); 943 944 /* Light sensor: require ALV0 (len 6 or 10) and LKSB */ 945 if (asmc_key_getinfo(dev, ASMC_KEY_LIGHTLEFT, 946 &len, type) == 0 && 947 (len == ASMC_LIGHT_SHORTLEN || len == ASMC_LIGHT_LONGLEN) && 948 asmc_key_getinfo(dev, ASMC_KEY_LIGHTVALUE, 949 NULL, NULL) == 0) { 950 sc->sc_has_light = 1; 951 sc->sc_light_len = len; 952 } else { 953 sc->sc_has_light = 0; 954 sc->sc_light_len = 0; 955 } 956 957 /* Fan safe speed */ 958 sc->sc_has_safespeed = 959 (asmc_key_getinfo(dev, ASMC_KEY_FANSAFESPEED0, 960 &len, type) == 0); 961 962 /* Ambient light interrupt source */ 963 sc->sc_has_alsl = 964 (asmc_key_getinfo(dev, ASMC_KEY_LIGHTSRC, 965 &len, type) == 0); 966 967 if (bootverbose) 968 device_printf(dev, 969 "capabilities: sms=%d light=%d (len=%d) safespeed=%d alsl=%d\n", 970 sc->sc_has_sms, sc->sc_has_light, sc->sc_light_len, 971 sc->sc_has_safespeed, sc->sc_has_alsl); 972 } 973 974 /* 975 * We need to make sure that the SMC acks the byte sent. 976 * Just wait up to (amount * 10) ms. 977 */ 978 static int 979 asmc_wait_ack(device_t dev, uint8_t val, int amount) 980 { 981 struct asmc_softc *sc = device_get_softc(dev); 982 u_int i; 983 984 val = val & ASMC_STATUS_MASK; 985 986 for (i = 0; i < amount; i++) { 987 if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 988 return (0); 989 DELAY(10); 990 } 991 992 return (1); 993 } 994 995 /* 996 * We need to make sure that the SMC acks the byte sent. 997 * Just wait up to 100 ms. 998 */ 999 static int 1000 asmc_wait(device_t dev, uint8_t val) 1001 { 1002 #ifdef ASMC_DEBUG 1003 struct asmc_softc *sc; 1004 #endif 1005 1006 if (asmc_wait_ack(dev, val, 1000) == 0) 1007 return (0); 1008 1009 #ifdef ASMC_DEBUG 1010 sc = device_get_softc(dev); 1011 1012 device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, 1013 val & ASMC_STATUS_MASK, ASMC_CMDPORT_READ(sc)); 1014 #endif 1015 return (1); 1016 } 1017 1018 /* 1019 * Send the given command, retrying up to 10 times if 1020 * the acknowledgement fails. 1021 */ 1022 static int 1023 asmc_command(device_t dev, uint8_t command) 1024 { 1025 int i; 1026 struct asmc_softc *sc = device_get_softc(dev); 1027 1028 for (i = 0; i < 10; i++) { 1029 ASMC_CMDPORT_WRITE(sc, command); 1030 if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 1031 return (0); 1032 } 1033 } 1034 1035 #ifdef ASMC_DEBUG 1036 device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 1037 ASMC_CMDPORT_READ(sc)); 1038 #endif 1039 return (1); 1040 } 1041 1042 static int 1043 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 1044 { 1045 int i, error = 1, try = 0; 1046 struct asmc_softc *sc = device_get_softc(dev); 1047 1048 mtx_lock_spin(&sc->sc_mtx); 1049 1050 begin: 1051 if (asmc_command(dev, ASMC_CMDREAD)) 1052 goto out; 1053 1054 for (i = 0; i < 4; i++) { 1055 ASMC_DATAPORT_WRITE(sc, key[i]); 1056 if (asmc_wait(dev, 0x04)) 1057 goto out; 1058 } 1059 1060 ASMC_DATAPORT_WRITE(sc, len); 1061 1062 for (i = 0; i < len; i++) { 1063 if (asmc_wait(dev, 0x05)) 1064 goto out; 1065 buf[i] = ASMC_DATAPORT_READ(sc); 1066 } 1067 1068 error = 0; 1069 out: 1070 if (error) { 1071 if (++try < 10) 1072 goto begin; 1073 device_printf(dev, "%s for key %s failed %d times, giving up\n", 1074 __func__, key, try); 1075 } 1076 1077 mtx_unlock_spin(&sc->sc_mtx); 1078 1079 return (error); 1080 } 1081 1082 #ifdef ASMC_DEBUG 1083 static int 1084 asmc_key_dump(device_t dev, int number) 1085 { 1086 struct asmc_softc *sc = device_get_softc(dev); 1087 char key[ASMC_KEYLEN + 1] = { 0 }; 1088 char type[ASMC_KEYINFO_RESPLEN + 1] = { 0 }; 1089 uint8_t index[4]; 1090 uint8_t v[ASMC_MAXVAL]; 1091 uint8_t maxlen; 1092 int i, error = 1, try = 0; 1093 1094 if (sc->sc_is_mmio) { 1095 uint8_t len = 0; 1096 char mmio_type[ASMC_TYPELEN + 1] = { 0 }; 1097 if (asmc_key_dump_by_index(dev, number, key, mmio_type, &len)) 1098 return (1); 1099 memset(v, 0, sizeof(v)); 1100 len = MIN(len, sizeof(v)); 1101 asmc_key_read(dev, key, v, len); 1102 struct sbuf sb; 1103 char buf[128]; 1104 sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); 1105 sbuf_printf(&sb, "key %d: %s, type %s (len %d), data", 1106 number, key, mmio_type, len); 1107 for (i = 0; i < len; i++) 1108 sbuf_printf(&sb, " %02x", v[i]); 1109 sbuf_finish(&sb); 1110 device_printf(dev, "%s\n", sbuf_data(&sb)); 1111 sbuf_delete(&sb); 1112 return (0); 1113 } 1114 1115 mtx_lock_spin(&sc->sc_mtx); 1116 1117 index[0] = (number >> 24) & 0xff; 1118 index[1] = (number >> 16) & 0xff; 1119 index[2] = (number >> 8) & 0xff; 1120 index[3] = number & 0xff; 1121 1122 begin: 1123 if (asmc_command(dev, ASMC_CMDGETBYINDEX)) 1124 goto out; 1125 1126 for (i = 0; i < ASMC_KEYLEN; i++) { 1127 ASMC_DATAPORT_WRITE(sc, index[i]); 1128 if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) 1129 goto out; 1130 } 1131 1132 ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN); 1133 1134 for (i = 0; i < ASMC_KEYLEN; i++) { 1135 if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) 1136 goto out; 1137 key[i] = ASMC_DATAPORT_READ(sc); 1138 } 1139 1140 /* Get key info (length + type). */ 1141 if (asmc_command(dev, ASMC_CMDGETINFO)) 1142 goto out; 1143 1144 for (i = 0; i < ASMC_KEYLEN; i++) { 1145 ASMC_DATAPORT_WRITE(sc, key[i]); 1146 if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) 1147 goto out; 1148 } 1149 1150 ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN); 1151 1152 for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) { 1153 if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) 1154 goto out; 1155 type[i] = ASMC_DATAPORT_READ(sc); 1156 } 1157 1158 error = 0; 1159 out: 1160 if (error) { 1161 if (++try < ASMC_MAXRETRIES) 1162 goto begin; 1163 device_printf(dev, 1164 "%s for key %d failed %d times, giving up\n", 1165 __func__, number, try); 1166 } 1167 mtx_unlock_spin(&sc->sc_mtx); 1168 1169 if (error) 1170 return (error); 1171 1172 maxlen = type[0]; 1173 type[0] = ' '; 1174 type[5] = '\0'; 1175 maxlen = MIN(maxlen, sizeof(v)); 1176 1177 memset(v, 0, sizeof(v)); 1178 error = asmc_key_read(dev, key, v, maxlen); 1179 if (error) 1180 return (error); 1181 1182 struct sbuf sb; 1183 char buf[128]; 1184 sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN); 1185 sbuf_printf(&sb, "key %d: %s, type%s (len %d), data", 1186 number, key, type, maxlen); 1187 for (i = 0; i < maxlen; i++) 1188 sbuf_printf(&sb, " %02x", v[i]); 1189 sbuf_finish(&sb); 1190 device_printf(dev, "%s\n", sbuf_data(&sb)); 1191 sbuf_delete(&sb); 1192 1193 return (0); 1194 } 1195 #endif /* ASMC_DEBUG */ 1196 1197 /* 1198 * Get key info (length and type) from SMC using command 0x13. 1199 * If len is non-NULL, stores the key's value length. 1200 * If type is non-NULL, stores the 4-char type string (must be at least 5 bytes). 1201 */ 1202 static int 1203 asmc_key_getinfo(device_t dev, const char *key, uint8_t *len, char *type) 1204 { 1205 struct asmc_softc *sc = device_get_softc(dev); 1206 uint8_t info[ASMC_KEYINFO_RESPLEN]; 1207 int i, error = -1, try = 0; 1208 1209 mtx_lock_spin(&sc->sc_mtx); 1210 1211 begin: 1212 if (asmc_command(dev, ASMC_CMDGETINFO)) 1213 goto out; 1214 1215 for (i = 0; i < ASMC_KEYLEN; i++) { 1216 ASMC_DATAPORT_WRITE(sc, key[i]); 1217 if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) 1218 goto out; 1219 } 1220 1221 ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN); 1222 1223 for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) { 1224 if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) 1225 goto out; 1226 info[i] = ASMC_DATAPORT_READ(sc); 1227 } 1228 1229 error = 0; 1230 out: 1231 if (error && ++try < ASMC_MAXRETRIES) 1232 goto begin; 1233 mtx_unlock_spin(&sc->sc_mtx); 1234 1235 if (error == 0) { 1236 if (len != NULL) 1237 *len = info[0]; 1238 if (type != NULL) { 1239 for (i = 0; i < ASMC_TYPELEN; i++) 1240 type[i] = info[i + 1]; 1241 type[ASMC_TYPELEN] = '\0'; 1242 } 1243 } 1244 return (error); 1245 } 1246 1247 #ifdef ASMC_DEBUG 1248 /* 1249 * Raw SMC key access sysctls - enables reading/writing any SMC key by name 1250 * Usage: 1251 * sysctl dev.asmc.0.raw.key=TC0P # Set key, auto-detects length 1252 * sysctl dev.asmc.0.raw.value # Read current value (hex bytes) 1253 * sysctl dev.asmc.0.raw.value=01 # Write new value 1254 */ 1255 static int 1256 asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS) 1257 { 1258 device_t dev = (device_t) arg1; 1259 struct asmc_softc *sc = device_get_softc(dev); 1260 char newkey[ASMC_KEYLEN + 1]; 1261 uint8_t keylen; 1262 int error; 1263 1264 strlcpy(newkey, sc->sc_rawkey, sizeof(newkey)); 1265 error = sysctl_handle_string(oidp, newkey, sizeof(newkey), req); 1266 if (error || req->newptr == NULL) 1267 return (error); 1268 1269 if (strlen(newkey) != ASMC_KEYLEN) 1270 return (EINVAL); 1271 1272 /* Get key info to auto-detect length and type */ 1273 if (asmc_key_getinfo(dev, newkey, &keylen, sc->sc_rawtype) != 0) 1274 return (ENOENT); 1275 1276 if (keylen > ASMC_MAXVAL) 1277 keylen = ASMC_MAXVAL; 1278 1279 strlcpy(sc->sc_rawkey, newkey, sizeof(sc->sc_rawkey)); 1280 sc->sc_rawlen = keylen; 1281 memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval)); 1282 1283 /* Read the key value */ 1284 asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen); 1285 1286 return (0); 1287 } 1288 1289 static int 1290 asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS) 1291 { 1292 device_t dev = (device_t) arg1; 1293 struct asmc_softc *sc = device_get_softc(dev); 1294 char hexbuf[ASMC_MAXVAL * 2 + 1]; 1295 int error, i; 1296 1297 /* Refresh from SMC if a key has been selected. */ 1298 if (sc->sc_rawkey[0] != '\0') { 1299 asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval, 1300 sc->sc_rawlen > 0 ? sc->sc_rawlen : ASMC_MAXVAL); 1301 } 1302 1303 /* Format as hex string */ 1304 for (i = 0; i < sc->sc_rawlen && i < ASMC_MAXVAL; i++) 1305 snprintf(hexbuf + i * 2, 3, "%02x", sc->sc_rawval[i]); 1306 hexbuf[i * 2] = '\0'; 1307 1308 error = sysctl_handle_string(oidp, hexbuf, sizeof(hexbuf), req); 1309 if (error || req->newptr == NULL) 1310 return (error); 1311 1312 /* Reject writes until a key is selected via raw.key. */ 1313 if (sc->sc_rawkey[0] == '\0') 1314 return (EINVAL); 1315 1316 memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval)); 1317 for (i = 0; i < sc->sc_rawlen && hexbuf[i*2] && hexbuf[i*2+1]; i++) { 1318 unsigned int val; 1319 char tmp[3] = { hexbuf[i*2], hexbuf[i*2+1], 0 }; 1320 if (sscanf(tmp, "%02x", &val) == 1) 1321 sc->sc_rawval[i] = (uint8_t)val; 1322 } 1323 1324 if (asmc_key_write(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen) != 0) 1325 return (EIO); 1326 1327 return (0); 1328 } 1329 1330 static int 1331 asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS) 1332 { 1333 device_t dev = (device_t) arg1; 1334 struct asmc_softc *sc = device_get_softc(dev); 1335 1336 return (sysctl_handle_8(oidp, &sc->sc_rawlen, 0, req)); 1337 } 1338 1339 static int 1340 asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS) 1341 { 1342 device_t dev = (device_t) arg1; 1343 struct asmc_softc *sc = device_get_softc(dev); 1344 1345 return (sysctl_handle_string(oidp, sc->sc_rawtype, 1346 sizeof(sc->sc_rawtype), req)); 1347 } 1348 #endif 1349 1350 /* 1351 * Convert signed fixed-point SMC values to milli-units. 1352 * Format "spXY" means signed with X integer bits and Y fraction bits. 1353 */ 1354 static int 1355 asmc_sp78_to_milli(const uint8_t *buf) 1356 { 1357 int16_t val = (int16_t)be16dec(buf); 1358 1359 return ((int)val * 1000) / 256; 1360 } 1361 1362 static int 1363 asmc_sp87_to_milli(const uint8_t *buf) 1364 { 1365 int16_t val = (int16_t)be16dec(buf); 1366 1367 return ((int)val * 1000) / 128; 1368 } 1369 1370 static int 1371 asmc_sp4b_to_milli(const uint8_t *buf) 1372 { 1373 int16_t val = (int16_t)be16dec(buf); 1374 1375 return ((int)val * 1000) / 2048; 1376 } 1377 1378 static int 1379 asmc_sp5a_to_milli(const uint8_t *buf) 1380 { 1381 int16_t val = (int16_t)be16dec(buf); 1382 1383 return ((int)val * 1000) / 1024; 1384 } 1385 1386 static int 1387 asmc_sp69_to_milli(const uint8_t *buf) 1388 { 1389 int16_t val = (int16_t)be16dec(buf); 1390 1391 return ((int)val * 1000) / 512; 1392 } 1393 1394 static int 1395 asmc_sp96_to_milli(const uint8_t *buf) 1396 { 1397 int16_t val = (int16_t)be16dec(buf); 1398 1399 return ((int)val * 1000) / 64; 1400 } 1401 1402 static int 1403 asmc_sp2d_to_milli(const uint8_t *buf) 1404 { 1405 int16_t val = (int16_t)be16dec(buf); 1406 1407 return ((int)val * 1000) / 8192; 1408 } 1409 1410 static bool 1411 asmc_sensor_type_supported(const char *type) 1412 { 1413 1414 return (strncmp(type, "sp78", 4) == 0 || 1415 strncmp(type, "sp87", 4) == 0 || 1416 strncmp(type, "sp4b", 4) == 0 || 1417 strncmp(type, "sp5a", 4) == 0 || 1418 strncmp(type, "sp69", 4) == 0 || 1419 strncmp(type, "sp96", 4) == 0 || 1420 strncmp(type, "sp2d", 4) == 0 || 1421 strncmp(type, "ui16", 4) == 0); 1422 } 1423 1424 /* 1425 * Generic sensor value reader with automatic type conversion. 1426 * Reads an SMC key, detects its type, and converts to millivalue. 1427 */ 1428 static int 1429 asmc_sensor_read(device_t dev, const char *key, int *millivalue) 1430 { 1431 uint8_t buf[2]; 1432 char type[ASMC_TYPELEN + 1]; 1433 uint8_t len; 1434 int error; 1435 1436 error = asmc_key_getinfo(dev, key, &len, type); 1437 if (error != 0) 1438 return (error); 1439 1440 if (len != 2) { 1441 if (bootverbose) 1442 device_printf(dev, 1443 "%s: key %s unexpected length %d\n", 1444 __func__, key, len); 1445 return (ENXIO); 1446 } 1447 1448 error = asmc_key_read(dev, key, buf, sizeof(buf)); 1449 if (error != 0) 1450 return (error); 1451 1452 if (strncmp(type, "sp78", 4) == 0) { 1453 *millivalue = asmc_sp78_to_milli(buf); 1454 } else if (strncmp(type, "sp87", 4) == 0) { 1455 *millivalue = asmc_sp87_to_milli(buf); 1456 } else if (strncmp(type, "sp4b", 4) == 0) { 1457 *millivalue = asmc_sp4b_to_milli(buf); 1458 } else if (strncmp(type, "sp5a", 4) == 0) { 1459 *millivalue = asmc_sp5a_to_milli(buf); 1460 } else if (strncmp(type, "sp69", 4) == 0) { 1461 *millivalue = asmc_sp69_to_milli(buf); 1462 } else if (strncmp(type, "sp96", 4) == 0) { 1463 *millivalue = asmc_sp96_to_milli(buf); 1464 } else if (strncmp(type, "sp2d", 4) == 0) { 1465 *millivalue = asmc_sp2d_to_milli(buf); 1466 } else if (strncmp(type, "ui16", 4) == 0) { 1467 *millivalue = be16dec(buf); 1468 } else { 1469 if (bootverbose) 1470 device_printf(dev, 1471 "%s: unknown type '%s' for key %s\n", 1472 __func__, type, key); 1473 return (ENXIO); 1474 } 1475 1476 return (0); 1477 } 1478 1479 /* 1480 * Generic sensor sysctl handler for voltage/current/power/light sensors. 1481 * arg2 encodes: sensor_type (high byte) | sensor_index (low byte) 1482 * Sensor types: 'V'=voltage, 'I'=current, 'P'=power, 'L'=light 1483 */ 1484 static int 1485 asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS) 1486 { 1487 device_t dev = (device_t) arg1; 1488 struct asmc_softc *sc = device_get_softc(dev); 1489 int error, val; 1490 int sensor_type = (arg2 >> 8) & 0xFF; 1491 int sensor_idx = arg2 & 0xFF; 1492 const char *key = NULL; 1493 1494 /* Select sensor based on type and index */ 1495 switch (sensor_type) { 1496 case 'V': /* Voltage */ 1497 if (sensor_idx < sc->sc_voltage_count) 1498 key = sc->sc_voltage_sensors[sensor_idx]; 1499 break; 1500 case 'I': /* Current */ 1501 if (sensor_idx < sc->sc_current_count) 1502 key = sc->sc_current_sensors[sensor_idx]; 1503 break; 1504 case 'P': /* Power */ 1505 if (sensor_idx < sc->sc_power_count) 1506 key = sc->sc_power_sensors[sensor_idx]; 1507 break; 1508 case 'L': /* Light */ 1509 if (sensor_idx < sc->sc_light_count) 1510 key = sc->sc_light_sensors[sensor_idx]; 1511 break; 1512 default: 1513 return (EINVAL); 1514 } 1515 1516 if (key == NULL) 1517 return (ENOENT); 1518 1519 error = asmc_sensor_read(dev, key, &val); 1520 if (error != 0) 1521 return (error); 1522 1523 return (sysctl_handle_int(oidp, &val, 0, req)); 1524 } 1525 1526 /* 1527 * Scan a range of SMC key indices, adding matching sensors. 1528 * Only considers 2-byte keys with a supported type. 1529 */ 1530 static void 1531 asmc_scan_sensor_range(device_t dev, unsigned int start, 1532 unsigned int end, char prefix, int *countp, char **sensors, 1533 int maxcount) 1534 { 1535 char key[ASMC_KEYLEN + 1]; 1536 char type[ASMC_TYPELEN + 1]; 1537 uint8_t len; 1538 unsigned int i; 1539 char *sensor_key; 1540 1541 for (i = start; i < end; i++) { 1542 if (asmc_key_dump_by_index(dev, i, key, type, &len)) 1543 continue; 1544 if (key[0] != prefix || len != 2) 1545 continue; 1546 if (!asmc_sensor_type_supported(type)) 1547 continue; 1548 if (*countp >= maxcount) 1549 break; 1550 sensor_key = malloc(ASMC_KEYLEN + 1, 1551 M_DEVBUF, M_WAITOK); 1552 memcpy(sensor_key, key, ASMC_KEYLEN + 1); 1553 sensors[(*countp)++] = sensor_key; 1554 } 1555 } 1556 1557 static int 1558 asmc_detect_sensors(device_t dev) 1559 { 1560 struct asmc_softc *sc = device_get_softc(dev); 1561 struct sysctl_ctx_list *sysctlctx; 1562 struct sysctl_oid *tree_node; 1563 char key[ASMC_KEYLEN + 1]; 1564 char type[ASMC_TYPELEN + 1]; 1565 uint8_t len; 1566 unsigned int start, end, i; 1567 int error; 1568 char *sensor_key; 1569 1570 sc->sc_voltage_count = 0; 1571 sc->sc_current_count = 0; 1572 sc->sc_power_count = 0; 1573 sc->sc_light_count = 0; 1574 sc->sc_temp_count = 0; 1575 1576 if (sc->sc_nkeys == 0) 1577 return (0); 1578 1579 /* 1580 * Temperature sensors: binary search for T..U range, 1581 * then filter by type sp78. 1582 */ 1583 error = asmc_key_search(dev, "T\0\0\0", &start); 1584 if (error == 0) 1585 error = asmc_key_search(dev, "U\0\0\0", &end); 1586 if (error == 0) { 1587 for (i = start; i < end; i++) { 1588 if (asmc_key_dump_by_index(dev, i, 1589 key, type, &len)) 1590 continue; 1591 if (len != 2 || 1592 strncmp(type, "sp78", 4) != 0) 1593 continue; 1594 if (sc->sc_temp_count >= ASMC_TEMP_MAX) 1595 break; 1596 sensor_key = malloc(ASMC_KEYLEN + 1, 1597 M_DEVBUF, M_WAITOK); 1598 memcpy(sensor_key, key, ASMC_KEYLEN + 1); 1599 sc->sc_temp_sensors[sc->sc_temp_count++] = 1600 sensor_key; 1601 } 1602 } 1603 1604 /* Voltage sensors: V..W range */ 1605 error = asmc_key_search(dev, "V\0\0\0", &start); 1606 if (error == 0) 1607 error = asmc_key_search(dev, "W\0\0\0", &end); 1608 if (error == 0) 1609 asmc_scan_sensor_range(dev, start, end, 'V', 1610 &sc->sc_voltage_count, sc->sc_voltage_sensors, 1611 ASMC_MAX_SENSORS); 1612 1613 /* Current sensors: I..J range */ 1614 error = asmc_key_search(dev, "I\0\0\0", &start); 1615 if (error == 0) 1616 error = asmc_key_search(dev, "J\0\0\0", &end); 1617 if (error == 0) 1618 asmc_scan_sensor_range(dev, start, end, 'I', 1619 &sc->sc_current_count, sc->sc_current_sensors, 1620 ASMC_MAX_SENSORS); 1621 1622 /* Power sensors: P..Q range */ 1623 error = asmc_key_search(dev, "P\0\0\0", &start); 1624 if (error == 0) 1625 error = asmc_key_search(dev, "Q\0\0\0", &end); 1626 if (error == 0) 1627 asmc_scan_sensor_range(dev, start, end, 'P', 1628 &sc->sc_power_count, sc->sc_power_sensors, 1629 ASMC_MAX_SENSORS); 1630 1631 /* Ambient light sensors: AL* in A..B range */ 1632 error = asmc_key_search(dev, "A\0\0\0", &start); 1633 if (error == 0) 1634 error = asmc_key_search(dev, "B\0\0\0", &end); 1635 if (error == 0) { 1636 for (i = start; i < end; i++) { 1637 if (asmc_key_dump_by_index(dev, i, 1638 key, type, &len)) 1639 continue; 1640 if (key[0] != 'A' || key[1] != 'L' || 1641 (key[2] != 'V' && key[2] != 'S') || 1642 len != 2) 1643 continue; 1644 if (!asmc_sensor_type_supported(type)) 1645 continue; 1646 if (sc->sc_light_count >= ASMC_MAX_SENSORS) 1647 break; 1648 sensor_key = malloc(ASMC_KEYLEN + 1, 1649 M_DEVBUF, M_WAITOK); 1650 memcpy(sensor_key, key, ASMC_KEYLEN + 1); 1651 sc->sc_light_sensors[sc->sc_light_count++] = 1652 sensor_key; 1653 } 1654 } 1655 1656 if (bootverbose) 1657 device_printf(dev, 1658 "detected %d temp, %d voltage, %d current, " 1659 "%d power, %d light sensors\n", 1660 sc->sc_temp_count, sc->sc_voltage_count, 1661 sc->sc_current_count, 1662 sc->sc_power_count, sc->sc_light_count); 1663 1664 /* Register sysctls for detected sensors */ 1665 sysctlctx = device_get_sysctl_ctx(dev); 1666 1667 /* Voltage sensors */ 1668 if (sc->sc_voltage_count > 0) { 1669 tree_node = SYSCTL_ADD_NODE(sysctlctx, 1670 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1671 "voltage", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Voltage sensors (millivolts)"); 1672 1673 for (i = 0; i < sc->sc_voltage_count; i++) { 1674 SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), 1675 OID_AUTO, sc->sc_voltage_sensors[i], 1676 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 1677 dev, ('V' << 8) | i, asmc_sensor_sysctl, "I", 1678 "Voltage sensor (millivolts)"); 1679 } 1680 } 1681 1682 /* Current sensors */ 1683 if (sc->sc_current_count > 0) { 1684 tree_node = SYSCTL_ADD_NODE(sysctlctx, 1685 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1686 "current", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Current sensors (milliamps)"); 1687 1688 for (i = 0; i < sc->sc_current_count; i++) { 1689 SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), 1690 OID_AUTO, sc->sc_current_sensors[i], 1691 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 1692 dev, ('I' << 8) | i, asmc_sensor_sysctl, "I", 1693 "Current sensor (milliamps)"); 1694 } 1695 } 1696 1697 /* Power sensors */ 1698 if (sc->sc_power_count > 0) { 1699 tree_node = SYSCTL_ADD_NODE(sysctlctx, 1700 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1701 "power", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Power sensors (milliwatts)"); 1702 1703 for (i = 0; i < sc->sc_power_count; i++) { 1704 SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), 1705 OID_AUTO, sc->sc_power_sensors[i], 1706 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 1707 dev, ('P' << 8) | i, asmc_sensor_sysctl, "I", 1708 "Power sensor (milliwatts)"); 1709 } 1710 } 1711 1712 /* Ambient light sensors */ 1713 if (sc->sc_light_count > 0) { 1714 tree_node = SYSCTL_ADD_NODE(sysctlctx, 1715 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1716 "ambient", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Ambient light sensors"); 1717 1718 for (i = 0; i < sc->sc_light_count; i++) { 1719 SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node), 1720 OID_AUTO, sc->sc_light_sensors[i], 1721 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 1722 dev, ('L' << 8) | i, asmc_sensor_sysctl, "I", 1723 "Light sensor value"); 1724 } 1725 } 1726 1727 return (0); 1728 } 1729 1730 /* 1731 * Helper function to get key info by index (for sensor detection). 1732 */ 1733 static int 1734 asmc_key_dump_by_index(device_t dev, int index, char *key_out, 1735 char *type_out, uint8_t *len_out) 1736 { 1737 struct asmc_softc *sc = device_get_softc(dev); 1738 uint8_t index_buf[ASMC_KEYLEN]; 1739 uint8_t key_buf[ASMC_KEYLEN]; 1740 uint8_t info_buf[ASMC_KEYINFO_RESPLEN]; 1741 int error = ENXIO, try = 0; 1742 int i; 1743 1744 mtx_lock_spin(&sc->sc_mtx); 1745 1746 index_buf[0] = (index >> 24) & 0xff; 1747 index_buf[1] = (index >> 16) & 0xff; 1748 index_buf[2] = (index >> 8) & 0xff; 1749 index_buf[3] = index & 0xff; 1750 1751 begin: 1752 if (asmc_command(dev, ASMC_CMDGETBYINDEX)) 1753 goto out; 1754 1755 for (i = 0; i < ASMC_KEYLEN; i++) { 1756 ASMC_DATAPORT_WRITE(sc, index_buf[i]); 1757 if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) 1758 goto out; 1759 } 1760 1761 ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN); 1762 1763 for (i = 0; i < ASMC_KEYLEN; i++) { 1764 if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) 1765 goto out; 1766 key_buf[i] = ASMC_DATAPORT_READ(sc); 1767 } 1768 1769 if (asmc_command(dev, ASMC_CMDGETINFO)) 1770 goto out; 1771 1772 for (i = 0; i < ASMC_KEYLEN; i++) { 1773 ASMC_DATAPORT_WRITE(sc, key_buf[i]); 1774 if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) 1775 goto out; 1776 } 1777 1778 ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN); 1779 1780 for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) { 1781 if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) 1782 goto out; 1783 info_buf[i] = ASMC_DATAPORT_READ(sc); 1784 } 1785 1786 memcpy(key_out, key_buf, ASMC_KEYLEN); 1787 key_out[ASMC_KEYLEN] = '\0'; 1788 *len_out = info_buf[0]; 1789 memcpy(type_out, &info_buf[1], ASMC_TYPELEN); 1790 type_out[ASMC_TYPELEN] = '\0'; 1791 error = 0; 1792 1793 out: 1794 if (error) { 1795 if (++try < ASMC_MAXRETRIES) 1796 goto begin; 1797 } 1798 1799 mtx_unlock_spin(&sc->sc_mtx); 1800 return (error); 1801 } 1802 1803 /* 1804 * Binary search for the first key index >= prefix. 1805 * SMC keys are sorted, so this finds the lower bound efficiently. 1806 */ 1807 static int 1808 asmc_key_search(device_t dev, const char *prefix, unsigned int *idx) 1809 { 1810 struct asmc_softc *sc = device_get_softc(dev); 1811 unsigned int lo, hi, mid; 1812 char key[ASMC_KEYLEN + 1]; 1813 char type[ASMC_TYPELEN + 1]; 1814 uint8_t len; 1815 int error; 1816 1817 lo = 0; 1818 hi = sc->sc_nkeys; 1819 while (lo < hi) { 1820 mid = lo + (hi - lo) / 2; 1821 error = asmc_key_dump_by_index(dev, mid, 1822 key, type, &len); 1823 if (error != 0) 1824 return (error); 1825 if (strncmp(key, prefix, ASMC_KEYLEN) < 0) 1826 lo = mid + 1; 1827 else 1828 hi = mid; 1829 } 1830 *idx = lo; 1831 return (0); 1832 } 1833 1834 static int 1835 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 1836 { 1837 int i, error = -1, try = 0; 1838 struct asmc_softc *sc = device_get_softc(dev); 1839 1840 mtx_lock_spin(&sc->sc_mtx); 1841 1842 begin: 1843 ASMC_DPRINTF(("cmd port: cmd write\n")); 1844 if (asmc_command(dev, ASMC_CMDWRITE)) 1845 goto out; 1846 1847 ASMC_DPRINTF(("data port: key\n")); 1848 for (i = 0; i < 4; i++) { 1849 ASMC_DATAPORT_WRITE(sc, key[i]); 1850 if (asmc_wait(dev, 0x04)) 1851 goto out; 1852 } 1853 ASMC_DPRINTF(("data port: length\n")); 1854 ASMC_DATAPORT_WRITE(sc, len); 1855 1856 ASMC_DPRINTF(("data port: buffer\n")); 1857 for (i = 0; i < len; i++) { 1858 if (asmc_wait(dev, 0x04)) 1859 goto out; 1860 ASMC_DATAPORT_WRITE(sc, buf[i]); 1861 } 1862 1863 error = 0; 1864 out: 1865 if (error) { 1866 if (++try < 10) 1867 goto begin; 1868 device_printf(dev, "%s for key %s failed %d times, giving up\n", 1869 __func__, key, try); 1870 } 1871 1872 mtx_unlock_spin(&sc->sc_mtx); 1873 1874 return (error); 1875 } 1876 1877 /* 1878 * Fan control functions. 1879 */ 1880 static int 1881 asmc_fan_count(device_t dev) 1882 { 1883 uint8_t buf[1]; 1884 1885 if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof(buf)) != 0) 1886 return (-1); 1887 1888 return (buf[0]); 1889 } 1890 1891 static int 1892 asmc_fan_getvalue(device_t dev, const char *key, int fan) 1893 { 1894 int speed; 1895 uint8_t buf[2]; 1896 char fankey[5]; 1897 1898 snprintf(fankey, sizeof(fankey), key, fan); 1899 if (asmc_key_read(dev, fankey, buf, sizeof(buf)) != 0) 1900 return (-1); 1901 speed = (buf[0] << 6) | (buf[1] >> 2); 1902 1903 return (speed); 1904 } 1905 1906 static char * 1907 asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, 1908 uint8_t buflen) 1909 { 1910 char fankey[5]; 1911 char *desc; 1912 1913 snprintf(fankey, sizeof(fankey), key, fan); 1914 if (asmc_key_read(dev, fankey, buf, buflen) != 0) 1915 return (NULL); 1916 desc = buf + 4; 1917 1918 return (desc); 1919 } 1920 1921 static int 1922 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 1923 { 1924 uint8_t buf[2]; 1925 char fankey[5]; 1926 1927 speed *= 4; 1928 1929 buf[0] = speed >> 8; 1930 buf[1] = speed; 1931 1932 snprintf(fankey, sizeof(fankey), key, fan); 1933 if (asmc_key_write(dev, fankey, buf, sizeof(buf)) < 0) 1934 return (-1); 1935 1936 return (0); 1937 } 1938 1939 static int 1940 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 1941 { 1942 device_t dev = (device_t)arg1; 1943 int fan = arg2; 1944 int error; 1945 int32_t v; 1946 1947 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 1948 error = sysctl_handle_int(oidp, &v, 0, req); 1949 1950 return (error); 1951 } 1952 1953 static int 1954 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 1955 { 1956 uint8_t buf[16]; 1957 device_t dev = (device_t)arg1; 1958 int fan = arg2; 1959 int error = true; 1960 char *desc; 1961 1962 desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); 1963 1964 if (desc != NULL) 1965 error = sysctl_handle_string(oidp, desc, 0, req); 1966 1967 return (error); 1968 } 1969 1970 static int 1971 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 1972 { 1973 device_t dev = (device_t)arg1; 1974 int fan = arg2; 1975 int error; 1976 int32_t v; 1977 1978 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 1979 error = sysctl_handle_int(oidp, &v, 0, req); 1980 1981 return (error); 1982 } 1983 1984 static int 1985 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 1986 { 1987 device_t dev = (device_t)arg1; 1988 int fan = arg2; 1989 int error; 1990 int32_t v; 1991 1992 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 1993 error = sysctl_handle_int(oidp, &v, 0, req); 1994 1995 if (error == 0 && req->newptr != NULL) { 1996 unsigned int newspeed = v; 1997 asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 1998 } 1999 2000 return (error); 2001 } 2002 2003 static int 2004 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 2005 { 2006 device_t dev = (device_t)arg1; 2007 int fan = arg2; 2008 int error; 2009 int32_t v; 2010 2011 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 2012 error = sysctl_handle_int(oidp, &v, 0, req); 2013 2014 if (error == 0 && req->newptr != NULL) { 2015 unsigned int newspeed = v; 2016 asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 2017 } 2018 2019 return (error); 2020 } 2021 2022 static int 2023 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 2024 { 2025 device_t dev = (device_t)arg1; 2026 int fan = arg2; 2027 int error; 2028 int32_t v; 2029 2030 v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 2031 error = sysctl_handle_int(oidp, &v, 0, req); 2032 2033 if (error == 0 && req->newptr != NULL) { 2034 unsigned int newspeed = v; 2035 asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 2036 } 2037 2038 return (error); 2039 } 2040 2041 static int 2042 asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS) 2043 { 2044 device_t dev = (device_t)arg1; 2045 int fan = arg2; 2046 int error; 2047 int32_t v; 2048 uint8_t buf[2]; 2049 uint16_t val; 2050 2051 /* Read current FS! bitmask (asmc_key_read locks internally) */ 2052 error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf)); 2053 if (error != 0) 2054 return (error); 2055 2056 /* Extract manual bit for this fan (big-endian) */ 2057 val = (buf[0] << 8) | buf[1]; 2058 v = (val >> fan) & 0x01; 2059 2060 /* Let sysctl handle the value */ 2061 error = sysctl_handle_int(oidp, &v, 0, req); 2062 2063 if (error == 0 && req->newptr != NULL) { 2064 /* Validate input (0 = auto, 1 = manual) */ 2065 if (v != 0 && v != 1) 2066 return (EINVAL); 2067 /* Read-modify-write of FS! bitmask */ 2068 error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, 2069 sizeof(buf)); 2070 if (error == 0) { 2071 val = (buf[0] << 8) | buf[1]; 2072 2073 /* Modify single bit */ 2074 if (v) 2075 val |= (1 << fan); /* Set to manual */ 2076 else 2077 val &= ~(1 << fan); /* Set to auto */ 2078 2079 /* Write back */ 2080 buf[0] = val >> 8; 2081 buf[1] = val & 0xff; 2082 error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf, 2083 sizeof(buf)); 2084 } 2085 } 2086 2087 return (error); 2088 } 2089 2090 /* 2091 * Temperature functions. 2092 */ 2093 static int 2094 asmc_temp_getvalue(device_t dev, const char *key) 2095 { 2096 uint8_t buf[2]; 2097 2098 /* 2099 * Check for invalid temperatures. 2100 */ 2101 if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0) 2102 return (-1); 2103 2104 return (buf[0]); 2105 } 2106 2107 static int 2108 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 2109 { 2110 device_t dev = (device_t)arg1; 2111 struct asmc_softc *sc = device_get_softc(dev); 2112 int error, val; 2113 2114 if (arg2 < 0 || arg2 >= sc->sc_temp_count) 2115 return (EINVAL); 2116 2117 val = asmc_temp_getvalue(dev, sc->sc_temp_sensors[arg2]); 2118 error = sysctl_handle_int(oidp, &val, 0, req); 2119 2120 return (error); 2121 } 2122 2123 /* 2124 * Sudden Motion Sensor functions. 2125 */ 2126 static int 2127 asmc_sms_read(device_t dev, const char *key, int16_t *val) 2128 { 2129 uint8_t buf[2]; 2130 int error; 2131 2132 /* no need to do locking here as asmc_key_read() already does it */ 2133 switch (key[3]) { 2134 case 'X': 2135 case 'Y': 2136 case 'Z': 2137 error = asmc_key_read(dev, key, buf, sizeof(buf)); 2138 break; 2139 default: 2140 device_printf(dev, "%s called with invalid argument %s\n", 2141 __func__, key); 2142 error = EINVAL; 2143 goto out; 2144 } 2145 *val = ((int16_t)buf[0] << 8) | buf[1]; 2146 out: 2147 return (error); 2148 } 2149 2150 static void 2151 asmc_sms_calibrate(device_t dev) 2152 { 2153 struct asmc_softc *sc = device_get_softc(dev); 2154 2155 asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 2156 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 2157 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 2158 } 2159 2160 static int 2161 asmc_sms_intrfast(void *arg) 2162 { 2163 uint8_t type; 2164 device_t dev = (device_t)arg; 2165 struct asmc_softc *sc = device_get_softc(dev); 2166 if (!sc->sc_sms_intr_works) 2167 return (FILTER_HANDLED); 2168 2169 mtx_lock_spin(&sc->sc_mtx); 2170 type = ASMC_INTPORT_READ(sc); 2171 mtx_unlock_spin(&sc->sc_mtx); 2172 2173 sc->sc_sms_intrtype = type; 2174 asmc_sms_printintr(dev, type); 2175 2176 /* Don't queue SMS task for ambient light interrupts */ 2177 if (type == ASMC_ALSL_INT2A && sc->sc_has_alsl) 2178 return (FILTER_HANDLED); 2179 2180 taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 2181 return (FILTER_HANDLED); 2182 } 2183 2184 static void 2185 asmc_sms_printintr(device_t dev, uint8_t type) 2186 { 2187 struct asmc_softc *sc = device_get_softc(dev); 2188 2189 switch (type) { 2190 case ASMC_SMS_INTFF: 2191 device_printf(dev, "WARNING: possible free fall!\n"); 2192 break; 2193 case ASMC_SMS_INTHA: 2194 device_printf(dev, "WARNING: high acceleration detected!\n"); 2195 break; 2196 case ASMC_SMS_INTSH: 2197 device_printf(dev, "WARNING: possible shock!\n"); 2198 break; 2199 case ASMC_ALSL_INT2A: 2200 /* 2201 * This suppresses console and log messages for the ambient 2202 * light sensor interrupt on models that have ALSL. 2203 */ 2204 if (sc->sc_has_alsl) 2205 break; 2206 /* FALLTHROUGH */ 2207 default: 2208 device_printf(dev, "unknown interrupt: 0x%x\n", type); 2209 } 2210 } 2211 2212 static void 2213 asmc_sms_task(void *arg, int pending) 2214 { 2215 struct asmc_softc *sc = (struct asmc_softc *)arg; 2216 char notify[16]; 2217 int type; 2218 2219 switch (sc->sc_sms_intrtype) { 2220 case ASMC_SMS_INTFF: 2221 type = 2; 2222 break; 2223 case ASMC_SMS_INTHA: 2224 type = 1; 2225 break; 2226 case ASMC_SMS_INTSH: 2227 type = 0; 2228 break; 2229 default: 2230 type = 255; 2231 } 2232 2233 snprintf(notify, sizeof(notify), " notify=0x%x", type); 2234 devctl_notify("ACPI", "asmc", "SMS", notify); 2235 } 2236 2237 static int 2238 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 2239 { 2240 device_t dev = (device_t)arg1; 2241 int error; 2242 int16_t val; 2243 int32_t v; 2244 2245 asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 2246 v = (int32_t)val; 2247 error = sysctl_handle_int(oidp, &v, 0, req); 2248 2249 return (error); 2250 } 2251 2252 static int 2253 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 2254 { 2255 device_t dev = (device_t)arg1; 2256 int error; 2257 int16_t val; 2258 int32_t v; 2259 2260 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 2261 v = (int32_t)val; 2262 error = sysctl_handle_int(oidp, &v, 0, req); 2263 2264 return (error); 2265 } 2266 2267 static int 2268 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 2269 { 2270 device_t dev = (device_t)arg1; 2271 int error; 2272 int16_t val; 2273 int32_t v; 2274 2275 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 2276 v = (int32_t)val; 2277 error = sysctl_handle_int(oidp, &v, 0, req); 2278 2279 return (error); 2280 } 2281 2282 static int 2283 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 2284 { 2285 device_t dev = (device_t)arg1; 2286 uint8_t buf[6]; 2287 int error; 2288 int32_t v; 2289 2290 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf)); 2291 v = buf[2]; 2292 error = sysctl_handle_int(oidp, &v, 0, req); 2293 2294 return (error); 2295 } 2296 2297 static int 2298 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 2299 { 2300 device_t dev = (device_t)arg1; 2301 uint8_t buf[6]; 2302 int error; 2303 int32_t v; 2304 2305 asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof(buf)); 2306 v = buf[2]; 2307 error = sysctl_handle_int(oidp, &v, 0, req); 2308 2309 return (error); 2310 } 2311 2312 static int 2313 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 2314 { 2315 device_t dev = (device_t)arg1; 2316 struct asmc_softc *sc = device_get_softc(dev); 2317 uint8_t buf[2]; 2318 int error; 2319 int v; 2320 2321 v = light_control; 2322 error = sysctl_handle_int(oidp, &v, 0, req); 2323 2324 if (error == 0 && req->newptr != NULL) { 2325 if (v < 0 || v > 255) 2326 return (EINVAL); 2327 light_control = v; 2328 sc->sc_kbd_bkl_level = v * 100 / 255; 2329 buf[0] = light_control; 2330 buf[1] = 0x00; 2331 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); 2332 } 2333 return (error); 2334 } 2335 2336 static int 2337 asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS) 2338 { 2339 device_t dev = (device_t)arg1; 2340 uint8_t buf[10]; 2341 int error; 2342 uint32_t v; 2343 2344 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf)); 2345 2346 /* 2347 * This seems to be a 32 bit big endian value from buf[6] -> buf[9]. 2348 * 2349 * Extract it out manually here, then shift/clamp it. 2350 */ 2351 v = be32dec(&buf[6]); 2352 2353 /* 2354 * Shift out, clamp at 255; that way it looks like the 2355 * earlier SMC firmware version responses. 2356 */ 2357 v = v >> 8; 2358 if (v > 255) 2359 v = 255; 2360 2361 error = sysctl_handle_int(oidp, &v, 0, req); 2362 2363 return (error); 2364 } 2365 2366 /* 2367 * Auto power-on after AC power loss (AUPO key). 2368 * When non-zero the machine boots automatically when AC is restored 2369 * after an unclean power loss. Useful for always-on servers / home labs. 2370 */ 2371 static int 2372 asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS) 2373 { 2374 device_t dev = (device_t)arg1; 2375 uint8_t aupo; 2376 int val, error; 2377 2378 if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) 2379 return (EIO); 2380 2381 val = (aupo != 0) ? 1 : 0; 2382 error = sysctl_handle_int(oidp, &val, 0, req); 2383 if (error != 0 || req->newptr == NULL) 2384 return (error); 2385 2386 aupo = (val != 0) ? 1 : 0; 2387 if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) 2388 return (EIO); 2389 2390 return (0); 2391 } 2392 2393 static int 2394 asmc_backlight_update_status(device_t dev, struct backlight_props *props) 2395 { 2396 struct asmc_softc *sc = device_get_softc(dev); 2397 uint8_t buf[2]; 2398 2399 sc->sc_kbd_bkl_level = props->brightness; 2400 light_control = props->brightness * 255 / 100; 2401 buf[0] = light_control; 2402 buf[1] = 0x00; 2403 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); 2404 2405 return (0); 2406 } 2407 2408 static int 2409 asmc_backlight_get_status(device_t dev, struct backlight_props *props) 2410 { 2411 struct asmc_softc *sc = device_get_softc(dev); 2412 2413 props->brightness = sc->sc_kbd_bkl_level; 2414 props->nlevels = 0; 2415 2416 return (0); 2417 } 2418 2419 static int 2420 asmc_backlight_get_info(device_t dev, struct backlight_info *info) 2421 { 2422 info->type = BACKLIGHT_TYPE_KEYBOARD; 2423 strlcpy(info->name, "Apple MacBook Keyboard", BACKLIGHTMAXNAMELENGTH); 2424 2425 return (0); 2426 } 2427