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