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