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/Current/Power sensors */ 1663 static const struct { 1664 const char *range_start; 1665 const char *range_end; 1666 char prefix; 1667 } sensor_ranges[] = { 1668 { "V\0\0\0", "W\0\0\0", 'V' }, /* Voltage */ 1669 { "I\0\0\0", "J\0\0\0", 'I' }, /* Current */ 1670 { "P\0\0\0", "Q\0\0\0", 'P' }, /* Power */ 1671 }; 1672 static const size_t nsensor_ranges = nitems(sensor_ranges); 1673 1674 int *sensor_counts[] = { 1675 &sc->sc_voltage_count, &sc->sc_current_count, 1676 &sc->sc_power_count }; 1677 char **sensor_arrays[] = { 1678 sc->sc_voltage_sensors, sc->sc_current_sensors, 1679 sc->sc_power_sensors }; 1680 1681 for (unsigned int r = 0; r < nsensor_ranges; r++) { 1682 error = asmc_key_search(dev, sensor_ranges[r].range_start, 1683 &start); 1684 if (error == 0) 1685 error = asmc_key_search(dev, 1686 sensor_ranges[r].range_end, &end); 1687 if (error == 0) 1688 asmc_scan_sensor_range(dev, start, end, 1689 sensor_ranges[r].prefix, sensor_counts[r], 1690 sensor_arrays[r], ASMC_MAX_SENSORS); 1691 } 1692 1693 /* Ambient light sensors: AL* in A..B range */ 1694 error = asmc_key_search(dev, "A\0\0\0", &start); 1695 if (error == 0) 1696 error = asmc_key_search(dev, "B\0\0\0", &end); 1697 if (error == 0) { 1698 for (i = start; i < end; i++) { 1699 if (asmc_key_dump_by_index(dev, i, 1700 key, type, &len)) 1701 continue; 1702 if (key[0] != 'A' || key[1] != 'L' || 1703 (key[2] != 'V' && key[2] != 'S') || 1704 len != 2) 1705 continue; 1706 if (!asmc_sensor_type_supported(type)) 1707 continue; 1708 if (sc->sc_light_count >= ASMC_MAX_SENSORS) 1709 break; 1710 sensor_key = malloc(ASMC_KEYLEN + 1, 1711 M_DEVBUF, M_WAITOK); 1712 memcpy(sensor_key, key, ASMC_KEYLEN + 1); 1713 sc->sc_light_sensors[sc->sc_light_count++] = 1714 sensor_key; 1715 } 1716 } 1717 1718 if (bootverbose) 1719 device_printf(dev, 1720 "detected %d temp, %d voltage, %d current, " 1721 "%d power, %d light sensors\n", 1722 sc->sc_temp_count, sc->sc_voltage_count, 1723 sc->sc_current_count, 1724 sc->sc_power_count, sc->sc_light_count); 1725 1726 /* Register sysctls for detected sensors */ 1727 sysctlctx = device_get_sysctl_ctx(dev); 1728 1729 static const struct { 1730 const char *node_name; 1731 const char *node_desc; 1732 char tag; 1733 const char *leaf_desc; 1734 } sensor_sysctl[] = { 1735 { "voltage", "Voltage sensors (millivolts)", 'V', 1736 "Voltage sensor (millivolts)" }, 1737 { "current", "Current sensors (milliamps)", 'I', 1738 "Current sensor (milliamps)" }, 1739 { "power", "Power sensors (milliwatts)", 'P', 1740 "Power sensor (milliwatts)" }, 1741 { "ambient", "Ambient light sensors", 'L', 1742 "Light sensor value" }, 1743 }; 1744 1745 int *sysctl_counts[] = { 1746 &sc->sc_voltage_count, &sc->sc_current_count, 1747 &sc->sc_power_count, &sc->sc_light_count }; 1748 char **sysctl_arrays[] = { 1749 sc->sc_voltage_sensors, sc->sc_current_sensors, 1750 sc->sc_power_sensors, sc->sc_light_sensors }; 1751 1752 for (unsigned int s = 0; s < nitems(sensor_sysctl); s++) { 1753 int count = *sysctl_counts[s]; 1754 if (count <= 0) 1755 continue; 1756 tree_node = SYSCTL_ADD_NODE(sysctlctx, 1757 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 1758 sensor_sysctl[s].node_name, 1759 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 1760 sensor_sysctl[s].node_desc); 1761 for (i = 0; i < count; i++) { 1762 SYSCTL_ADD_PROC(sysctlctx, 1763 SYSCTL_CHILDREN(tree_node), 1764 OID_AUTO, sysctl_arrays[s][i], 1765 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, 1766 dev, (sensor_sysctl[s].tag << 8) | i, 1767 asmc_sensor_sysctl, "I", 1768 sensor_sysctl[s].leaf_desc); 1769 } 1770 } 1771 1772 return (0); 1773 } 1774 1775 /* 1776 * Helper function to get key info by index (for sensor detection). 1777 */ 1778 static int 1779 asmc_key_dump_by_index(device_t dev, int index, char *key_out, 1780 char *type_out, uint8_t *len_out) 1781 { 1782 struct asmc_softc *sc = device_get_softc(dev); 1783 uint8_t index_buf[ASMC_KEYLEN]; 1784 uint8_t key_buf[ASMC_KEYLEN]; 1785 uint8_t info_buf[ASMC_KEYINFO_RESPLEN]; 1786 int error = ENXIO, try = 0; 1787 int i; 1788 1789 if (sc->sc_is_mmio) { 1790 error = asmc_mmio_key_getbyindex(dev, index, key_out); 1791 if (error != 0) 1792 return (error); 1793 return (asmc_mmio_key_getinfo(dev, key_out, len_out, 1794 type_out)); 1795 } 1796 1797 mtx_lock_spin(&sc->sc_mtx); 1798 1799 index_buf[0] = (index >> 24) & 0xff; 1800 index_buf[1] = (index >> 16) & 0xff; 1801 index_buf[2] = (index >> 8) & 0xff; 1802 index_buf[3] = index & 0xff; 1803 1804 begin: 1805 if (asmc_command(dev, ASMC_CMDGETBYINDEX)) 1806 goto out; 1807 1808 for (i = 0; i < ASMC_KEYLEN; i++) { 1809 ASMC_DATAPORT_WRITE(sc, index_buf[i]); 1810 if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) 1811 goto out; 1812 } 1813 1814 ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN); 1815 1816 for (i = 0; i < ASMC_KEYLEN; i++) { 1817 if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) 1818 goto out; 1819 key_buf[i] = ASMC_DATAPORT_READ(sc); 1820 } 1821 1822 if (asmc_command(dev, ASMC_CMDGETINFO)) 1823 goto out; 1824 1825 for (i = 0; i < ASMC_KEYLEN; i++) { 1826 ASMC_DATAPORT_WRITE(sc, key_buf[i]); 1827 if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA)) 1828 goto out; 1829 } 1830 1831 ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN); 1832 1833 for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) { 1834 if (asmc_wait(dev, ASMC_STATUS_DATA_READY)) 1835 goto out; 1836 info_buf[i] = ASMC_DATAPORT_READ(sc); 1837 } 1838 1839 memcpy(key_out, key_buf, ASMC_KEYLEN); 1840 key_out[ASMC_KEYLEN] = '\0'; 1841 *len_out = info_buf[0]; 1842 memcpy(type_out, &info_buf[1], ASMC_TYPELEN); 1843 type_out[ASMC_TYPELEN] = '\0'; 1844 error = 0; 1845 1846 out: 1847 if (error) { 1848 if (++try < ASMC_MAXRETRIES) 1849 goto begin; 1850 } 1851 1852 mtx_unlock_spin(&sc->sc_mtx); 1853 return (error); 1854 } 1855 1856 /* 1857 * Binary search for the first key index >= prefix. 1858 * SMC keys are sorted, so this finds the lower bound efficiently. 1859 */ 1860 static int 1861 asmc_key_search(device_t dev, const char *prefix, unsigned int *idx) 1862 { 1863 struct asmc_softc *sc = device_get_softc(dev); 1864 unsigned int lo, hi, mid; 1865 char key[ASMC_KEYLEN + 1]; 1866 char type[ASMC_TYPELEN + 1]; 1867 uint8_t len; 1868 int error; 1869 1870 lo = 0; 1871 hi = sc->sc_nkeys; 1872 while (lo < hi) { 1873 mid = lo + (hi - lo) / 2; 1874 error = asmc_key_dump_by_index(dev, mid, 1875 key, type, &len); 1876 if (error != 0) 1877 return (error); 1878 if (strncmp(key, prefix, ASMC_KEYLEN) < 0) 1879 lo = mid + 1; 1880 else 1881 hi = mid; 1882 } 1883 *idx = lo; 1884 return (0); 1885 } 1886 1887 static int 1888 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 1889 { 1890 struct asmc_softc *sc = device_get_softc(dev); 1891 int i, error = -1, try = 0; 1892 1893 if (sc->sc_is_mmio) 1894 return (asmc_mmio_key_write(dev, key, buf, len)); 1895 1896 mtx_lock_spin(&sc->sc_mtx); 1897 1898 begin: 1899 ASMC_DPRINTF(("cmd port: cmd write\n")); 1900 if (asmc_command(dev, ASMC_CMDWRITE)) 1901 goto out; 1902 1903 ASMC_DPRINTF(("data port: key\n")); 1904 for (i = 0; i < 4; i++) { 1905 ASMC_DATAPORT_WRITE(sc, key[i]); 1906 if (asmc_wait(dev, 0x04)) 1907 goto out; 1908 } 1909 ASMC_DPRINTF(("data port: length\n")); 1910 ASMC_DATAPORT_WRITE(sc, len); 1911 1912 ASMC_DPRINTF(("data port: buffer\n")); 1913 for (i = 0; i < len; i++) { 1914 if (asmc_wait(dev, 0x04)) 1915 goto out; 1916 ASMC_DATAPORT_WRITE(sc, buf[i]); 1917 } 1918 1919 error = 0; 1920 out: 1921 if (error) { 1922 if (++try < 10) 1923 goto begin; 1924 device_printf(dev, "%s for key %s failed %d times, giving up\n", 1925 __func__, key, try); 1926 } 1927 1928 mtx_unlock_spin(&sc->sc_mtx); 1929 1930 return (error); 1931 } 1932 1933 /* 1934 * Fan control functions. 1935 */ 1936 static int 1937 asmc_fan_count(device_t dev) 1938 { 1939 uint8_t buf[1]; 1940 1941 if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof(buf)) != 0) 1942 return (-1); 1943 1944 return (buf[0]); 1945 } 1946 1947 static int 1948 asmc_fan_getvalue(device_t dev, const char *key, int fan) 1949 { 1950 struct asmc_softc *sc = device_get_softc(dev); 1951 int speed; 1952 uint8_t buf[4]; 1953 char fankey[5]; 1954 char type[ASMC_TYPELEN + 1]; 1955 1956 snprintf(fankey, sizeof(fankey), key, fan); 1957 1958 /* 1959 * T2 Macs use IEEE 754 float ("flt ") for fan speeds, 1960 * stored little-endian in the MMIO data register. 1961 * Standard Macs use s14.2 fixed-point ("fpe2", 2 bytes). 1962 */ 1963 if (sc->sc_is_t2 && 1964 asmc_key_getinfo(dev, fankey, NULL, type) == 0 && 1965 strncmp(type, "flt ", 4) == 0) { 1966 if (asmc_key_read(dev, fankey, buf, 4) != 0) 1967 return (-1); 1968 speed = (int)asmc_float_to_u32(le32dec(buf)); 1969 } else { 1970 if (asmc_key_read(dev, fankey, buf, 2) != 0) 1971 return (-1); 1972 speed = (buf[0] << 6) | (buf[1] >> 2); 1973 } 1974 1975 return (speed); 1976 } 1977 1978 static char * 1979 asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, 1980 uint8_t buflen) 1981 { 1982 char fankey[5]; 1983 char *desc; 1984 1985 snprintf(fankey, sizeof(fankey), key, fan); 1986 if (asmc_key_read(dev, fankey, buf, buflen) != 0) 1987 return (NULL); 1988 desc = buf + 4; 1989 1990 return (desc); 1991 } 1992 1993 static int 1994 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 1995 { 1996 struct asmc_softc *sc = device_get_softc(dev); 1997 uint8_t buf[4]; 1998 char fankey[5]; 1999 char type[ASMC_TYPELEN + 1]; 2000 2001 snprintf(fankey, sizeof(fankey), key, fan); 2002 2003 if (sc->sc_is_t2 && 2004 asmc_key_getinfo(dev, fankey, NULL, type) == 0 && 2005 strncmp(type, "flt ", 4) == 0) { 2006 uint32_t fval; 2007 speed = MAX(speed, 0); 2008 speed = MIN(speed, 65535); 2009 fval = asmc_u32_to_float((uint32_t)speed); 2010 le32enc(buf, fval); 2011 if (asmc_key_write(dev, fankey, buf, 4) != 0) 2012 return (-1); 2013 } else { 2014 speed *= 4; 2015 buf[0] = speed >> 8; 2016 buf[1] = speed; 2017 if (asmc_key_write(dev, fankey, buf, 2) != 0) 2018 return (-1); 2019 } 2020 2021 return (0); 2022 } 2023 2024 static int 2025 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 2026 { 2027 device_t dev = (device_t)arg1; 2028 int fan = arg2; 2029 int error; 2030 int32_t v; 2031 2032 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 2033 error = sysctl_handle_int(oidp, &v, 0, req); 2034 2035 return (error); 2036 } 2037 2038 static int 2039 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 2040 { 2041 uint8_t buf[16]; 2042 device_t dev = (device_t)arg1; 2043 int fan = arg2; 2044 int error = true; 2045 char *desc; 2046 2047 desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); 2048 2049 if (desc != NULL) 2050 error = sysctl_handle_string(oidp, desc, 0, req); 2051 2052 return (error); 2053 } 2054 2055 static int 2056 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 2057 { 2058 device_t dev = (device_t)arg1; 2059 int fan = arg2; 2060 int error; 2061 int32_t v; 2062 2063 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 2064 error = sysctl_handle_int(oidp, &v, 0, req); 2065 2066 return (error); 2067 } 2068 2069 static int 2070 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 2071 { 2072 device_t dev = (device_t)arg1; 2073 int fan = arg2; 2074 int error; 2075 int32_t v; 2076 2077 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 2078 error = sysctl_handle_int(oidp, &v, 0, req); 2079 2080 if (error == 0 && req->newptr != NULL) { 2081 unsigned int newspeed = v; 2082 asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 2083 } 2084 2085 return (error); 2086 } 2087 2088 static int 2089 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 2090 { 2091 device_t dev = (device_t)arg1; 2092 int fan = arg2; 2093 int error; 2094 int32_t v; 2095 2096 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 2097 error = sysctl_handle_int(oidp, &v, 0, req); 2098 2099 if (error == 0 && req->newptr != NULL) { 2100 unsigned int newspeed = v; 2101 asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 2102 } 2103 2104 return (error); 2105 } 2106 2107 static int 2108 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 2109 { 2110 device_t dev = (device_t)arg1; 2111 int fan = arg2; 2112 int error; 2113 int32_t v; 2114 2115 v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 2116 error = sysctl_handle_int(oidp, &v, 0, req); 2117 2118 if (error == 0 && req->newptr != NULL) { 2119 unsigned int newspeed = v; 2120 asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 2121 } 2122 2123 return (error); 2124 } 2125 2126 static int 2127 asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS) 2128 { 2129 device_t dev = (device_t)arg1; 2130 struct asmc_softc *sc = device_get_softc(dev); 2131 int fan = arg2; 2132 int error; 2133 int32_t v; 2134 uint8_t buf[2]; 2135 uint16_t val; 2136 char fmkey[5]; 2137 2138 /* 2139 * T2 Macs use per-fan F%dMd keys (1 byte each). 2140 * Standard Macs use FS! bitmask (2 bytes). 2141 */ 2142 snprintf(fmkey, sizeof(fmkey), ASMC_KEY_FANMANUAL_T2, fan); 2143 if (sc->sc_is_t2 && 2144 asmc_key_getinfo(dev, fmkey, NULL, NULL) == 0) { 2145 error = asmc_key_read(dev, fmkey, buf, 1); 2146 if (error != 0) 2147 return (error); 2148 v = buf[0] ? 1 : 0; 2149 2150 error = sysctl_handle_int(oidp, &v, 0, req); 2151 if (error == 0 && req->newptr != NULL) { 2152 if (v != 0 && v != 1) 2153 return (EINVAL); 2154 buf[0] = (uint8_t)v; 2155 error = asmc_key_write(dev, fmkey, buf, 1); 2156 } 2157 return (error); 2158 } 2159 2160 /* Read current FS! bitmask (asmc_key_read locks internally) */ 2161 error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf)); 2162 if (error != 0) 2163 return (error); 2164 2165 /* Extract manual bit for this fan (big-endian) */ 2166 val = (buf[0] << 8) | buf[1]; 2167 v = (val >> fan) & 0x01; 2168 2169 /* Let sysctl handle the value */ 2170 error = sysctl_handle_int(oidp, &v, 0, req); 2171 2172 if (error == 0 && req->newptr != NULL) { 2173 /* Validate input (0 = auto, 1 = manual) */ 2174 if (v != 0 && v != 1) 2175 return (EINVAL); 2176 /* Read-modify-write of FS! bitmask */ 2177 error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, 2178 sizeof(buf)); 2179 if (error == 0) { 2180 val = (buf[0] << 8) | buf[1]; 2181 2182 /* Modify single bit */ 2183 if (v) 2184 val |= (1 << fan); /* Set to manual */ 2185 else 2186 val &= ~(1 << fan); /* Set to auto */ 2187 2188 /* Write back */ 2189 buf[0] = val >> 8; 2190 buf[1] = val & 0xff; 2191 error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf, 2192 sizeof(buf)); 2193 } 2194 } 2195 2196 return (error); 2197 } 2198 2199 /* 2200 * Temperature functions. 2201 */ 2202 static int 2203 asmc_temp_getvalue(device_t dev, const char *key) 2204 { 2205 uint8_t buf[2]; 2206 2207 /* 2208 * Check for invalid temperatures. 2209 */ 2210 if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0) 2211 return (-1); 2212 2213 return (buf[0]); 2214 } 2215 2216 static int 2217 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 2218 { 2219 device_t dev = (device_t)arg1; 2220 struct asmc_softc *sc = device_get_softc(dev); 2221 int error, val; 2222 2223 if (arg2 < 0 || arg2 >= sc->sc_temp_count) 2224 return (EINVAL); 2225 2226 val = asmc_temp_getvalue(dev, sc->sc_temp_sensors[arg2]); 2227 error = sysctl_handle_int(oidp, &val, 0, req); 2228 2229 return (error); 2230 } 2231 2232 /* 2233 * Sudden Motion Sensor functions. 2234 */ 2235 static int 2236 asmc_sms_read(device_t dev, const char *key, int16_t *val) 2237 { 2238 uint8_t buf[2]; 2239 int error; 2240 2241 /* no need to do locking here as asmc_key_read() already does it */ 2242 switch (key[3]) { 2243 case 'X': 2244 case 'Y': 2245 case 'Z': 2246 error = asmc_key_read(dev, key, buf, sizeof(buf)); 2247 break; 2248 default: 2249 device_printf(dev, "%s called with invalid argument %s\n", 2250 __func__, key); 2251 error = EINVAL; 2252 goto out; 2253 } 2254 *val = ((int16_t)buf[0] << 8) | buf[1]; 2255 out: 2256 return (error); 2257 } 2258 2259 static void 2260 asmc_sms_calibrate(device_t dev) 2261 { 2262 struct asmc_softc *sc = device_get_softc(dev); 2263 2264 asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 2265 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 2266 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 2267 } 2268 2269 static int 2270 asmc_sms_intrfast(void *arg) 2271 { 2272 uint8_t type; 2273 device_t dev = (device_t)arg; 2274 struct asmc_softc *sc = device_get_softc(dev); 2275 if (!sc->sc_sms_intr_works) 2276 return (FILTER_HANDLED); 2277 2278 mtx_lock_spin(&sc->sc_mtx); 2279 type = ASMC_INTPORT_READ(sc); 2280 mtx_unlock_spin(&sc->sc_mtx); 2281 2282 sc->sc_sms_intrtype = type; 2283 asmc_sms_printintr(dev, type); 2284 2285 /* Don't queue SMS task for ambient light interrupts */ 2286 if (type == ASMC_ALSL_INT2A && sc->sc_has_alsl) 2287 return (FILTER_HANDLED); 2288 2289 taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 2290 return (FILTER_HANDLED); 2291 } 2292 2293 static void 2294 asmc_sms_printintr(device_t dev, uint8_t type) 2295 { 2296 struct asmc_softc *sc = device_get_softc(dev); 2297 2298 switch (type) { 2299 case ASMC_SMS_INTFF: 2300 device_printf(dev, "WARNING: possible free fall!\n"); 2301 break; 2302 case ASMC_SMS_INTHA: 2303 device_printf(dev, "WARNING: high acceleration detected!\n"); 2304 break; 2305 case ASMC_SMS_INTSH: 2306 device_printf(dev, "WARNING: possible shock!\n"); 2307 break; 2308 case ASMC_ALSL_INT2A: 2309 /* 2310 * This suppresses console and log messages for the ambient 2311 * light sensor interrupt on models that have ALSL. 2312 */ 2313 if (sc->sc_has_alsl) 2314 break; 2315 /* FALLTHROUGH */ 2316 default: 2317 device_printf(dev, "unknown interrupt: 0x%x\n", type); 2318 } 2319 } 2320 2321 static void 2322 asmc_sms_task(void *arg, int pending) 2323 { 2324 struct asmc_softc *sc = (struct asmc_softc *)arg; 2325 char notify[16]; 2326 int type; 2327 2328 switch (sc->sc_sms_intrtype) { 2329 case ASMC_SMS_INTFF: 2330 type = 2; 2331 break; 2332 case ASMC_SMS_INTHA: 2333 type = 1; 2334 break; 2335 case ASMC_SMS_INTSH: 2336 type = 0; 2337 break; 2338 default: 2339 type = 255; 2340 } 2341 2342 snprintf(notify, sizeof(notify), " notify=0x%x", type); 2343 devctl_notify("ACPI", "asmc", "SMS", notify); 2344 } 2345 2346 static int 2347 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 2348 { 2349 device_t dev = (device_t)arg1; 2350 int error; 2351 int16_t val; 2352 int32_t v; 2353 2354 asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 2355 v = (int32_t)val; 2356 error = sysctl_handle_int(oidp, &v, 0, req); 2357 2358 return (error); 2359 } 2360 2361 static int 2362 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 2363 { 2364 device_t dev = (device_t)arg1; 2365 int error; 2366 int16_t val; 2367 int32_t v; 2368 2369 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 2370 v = (int32_t)val; 2371 error = sysctl_handle_int(oidp, &v, 0, req); 2372 2373 return (error); 2374 } 2375 2376 static int 2377 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 2378 { 2379 device_t dev = (device_t)arg1; 2380 int error; 2381 int16_t val; 2382 int32_t v; 2383 2384 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 2385 v = (int32_t)val; 2386 error = sysctl_handle_int(oidp, &v, 0, req); 2387 2388 return (error); 2389 } 2390 2391 static int 2392 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 2393 { 2394 device_t dev = (device_t)arg1; 2395 uint8_t buf[6]; 2396 int error; 2397 int32_t v; 2398 2399 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf)); 2400 v = buf[2]; 2401 error = sysctl_handle_int(oidp, &v, 0, req); 2402 2403 return (error); 2404 } 2405 2406 static int 2407 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 2408 { 2409 device_t dev = (device_t)arg1; 2410 uint8_t buf[6]; 2411 int error; 2412 int32_t v; 2413 2414 asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof(buf)); 2415 v = buf[2]; 2416 error = sysctl_handle_int(oidp, &v, 0, req); 2417 2418 return (error); 2419 } 2420 2421 static int 2422 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 2423 { 2424 device_t dev = (device_t)arg1; 2425 struct asmc_softc *sc = device_get_softc(dev); 2426 uint8_t buf[2]; 2427 int error; 2428 int v; 2429 2430 v = light_control; 2431 error = sysctl_handle_int(oidp, &v, 0, req); 2432 2433 if (error == 0 && req->newptr != NULL) { 2434 if (v < 0 || v > 255) 2435 return (EINVAL); 2436 light_control = v; 2437 sc->sc_kbd_bkl_level = v * 100 / 255; 2438 buf[0] = light_control; 2439 buf[1] = 0x00; 2440 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); 2441 } 2442 return (error); 2443 } 2444 2445 static int 2446 asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS) 2447 { 2448 device_t dev = (device_t)arg1; 2449 uint8_t buf[10]; 2450 int error; 2451 uint32_t v; 2452 2453 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf)); 2454 2455 /* 2456 * This seems to be a 32 bit big endian value from buf[6] -> buf[9]. 2457 * 2458 * Extract it out manually here, then shift/clamp it. 2459 */ 2460 v = be32dec(&buf[6]); 2461 2462 /* 2463 * Shift out, clamp at 255; that way it looks like the 2464 * earlier SMC firmware version responses. 2465 */ 2466 v = v >> 8; 2467 if (v > 255) 2468 v = 255; 2469 2470 error = sysctl_handle_int(oidp, &v, 0, req); 2471 2472 return (error); 2473 } 2474 2475 /* 2476 * Auto power-on after AC power loss (AUPO key). 2477 * When non-zero the machine boots automatically when AC is restored 2478 * after an unclean power loss. Useful for always-on servers / home labs. 2479 */ 2480 static int 2481 asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS) 2482 { 2483 device_t dev = (device_t)arg1; 2484 uint8_t aupo; 2485 int val, error; 2486 2487 if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) 2488 return (EIO); 2489 2490 val = (aupo != 0) ? 1 : 0; 2491 error = sysctl_handle_int(oidp, &val, 0, req); 2492 if (error != 0 || req->newptr == NULL) 2493 return (error); 2494 2495 aupo = (val != 0) ? 1 : 0; 2496 if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) 2497 return (EIO); 2498 2499 return (0); 2500 } 2501 2502 static int 2503 asmc_backlight_update_status(device_t dev, struct backlight_props *props) 2504 { 2505 struct asmc_softc *sc = device_get_softc(dev); 2506 uint8_t buf[2]; 2507 2508 sc->sc_kbd_bkl_level = props->brightness; 2509 light_control = props->brightness * 255 / 100; 2510 buf[0] = light_control; 2511 buf[1] = 0x00; 2512 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); 2513 2514 return (0); 2515 } 2516 2517 static int 2518 asmc_backlight_get_status(device_t dev, struct backlight_props *props) 2519 { 2520 struct asmc_softc *sc = device_get_softc(dev); 2521 2522 props->brightness = sc->sc_kbd_bkl_level; 2523 props->nlevels = 0; 2524 2525 return (0); 2526 } 2527 2528 static int 2529 asmc_backlight_get_info(device_t dev, struct backlight_info *info) 2530 { 2531 info->type = BACKLIGHT_TYPE_KEYBOARD; 2532 strlcpy(info->name, "Apple MacBook Keyboard", BACKLIGHTMAXNAMELENGTH); 2533 2534 return (0); 2535 } 2536