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