1 /*- 2 * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 28 /* 29 * Driver for Apple's System Management Console (SMC). 30 * SMC can be found on the MacBook, MacBook Pro and Mac Mini. 31 * 32 * Inspired by the Linux applesmc driver. 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/bus.h> 40 #include <sys/conf.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/malloc.h> 44 #include <sys/module.h> 45 #include <sys/mutex.h> 46 #include <sys/sysctl.h> 47 #include <sys/systm.h> 48 #include <sys/taskqueue.h> 49 #include <sys/rman.h> 50 51 #include <machine/resource.h> 52 #include <contrib/dev/acpica/acpi.h> 53 #include <dev/acpica/acpivar.h> 54 #include <dev/asmc/asmcvar.h> 55 56 #include "opt_intr_filter.h" 57 58 /* 59 * Device interface. 60 */ 61 static int asmc_probe(device_t dev); 62 static int asmc_attach(device_t dev); 63 static int asmc_detach(device_t dev); 64 65 /* 66 * SMC functions. 67 */ 68 static int asmc_init(device_t dev); 69 static int asmc_wait(device_t dev, uint8_t val); 70 static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 71 uint8_t len); 72 static int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 73 uint8_t); 74 static int asmc_fan_count(device_t dev); 75 static int asmc_fan_getvalue(device_t dev, const char *key, int fan); 76 static int asmc_temp_getvalue(device_t dev, const char *key); 77 static int asmc_sms_read(device_t, const char *key, int16_t *val); 78 static void asmc_sms_calibrate(device_t dev); 79 static int asmc_sms_intrfast(void *arg); 80 #ifdef INTR_FILTER 81 static void asmc_sms_handler(void *arg); 82 #endif 83 static void asmc_sms_printintr(device_t dev, uint8_t); 84 static void asmc_sms_task(void *arg, int pending); 85 86 /* 87 * Model functions. 88 */ 89 static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 90 static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 91 static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 92 static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 93 static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 94 static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 95 static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 96 static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 97 static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 98 static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 99 static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 100 101 struct asmc_model { 102 const char *smc_model; /* smbios.system.product env var. */ 103 const char *smc_desc; /* driver description */ 104 105 /* Helper functions */ 106 int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); 107 int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); 108 int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); 109 int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); 110 int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); 111 int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); 112 int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); 113 int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); 114 int (*smc_light_left)(SYSCTL_HANDLER_ARGS); 115 int (*smc_light_right)(SYSCTL_HANDLER_ARGS); 116 117 const char *smc_temps[ASMC_TEMP_MAX]; 118 const char *smc_tempnames[ASMC_TEMP_MAX]; 119 const char *smc_tempdescs[ASMC_TEMP_MAX]; 120 }; 121 122 static struct asmc_model *asmc_match(device_t dev); 123 124 #define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ 125 asmc_mb_sysctl_sms_z 126 127 #define ASMC_FAN_FUNCS asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ 128 asmc_mb_sysctl_fanminspeed, \ 129 asmc_mb_sysctl_fanmaxspeed, \ 130 asmc_mb_sysctl_fantargetspeed 131 #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ 132 asmc_mbp_sysctl_light_right 133 134 struct asmc_model asmc_models[] = { 135 { 136 "MacBook1,1", "Apple SMC MacBook Core Duo", 137 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, 138 ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 139 }, 140 141 { 142 "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 143 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, 144 ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 145 }, 146 147 { 148 "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 149 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 150 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 151 }, 152 153 { 154 "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 155 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 156 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 157 }, 158 159 { 160 "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 161 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 162 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 163 }, 164 165 { 166 "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 167 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 168 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 169 }, 170 171 { 172 "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 173 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 174 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 175 }, 176 177 { 178 "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 179 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 180 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 181 }, 182 183 /* The Mac Mini has no SMS */ 184 { 185 "Macmini1,1", "Apple SMC Mac Mini", 186 NULL, NULL, NULL, 187 ASMC_FAN_FUNCS, 188 NULL, NULL, 189 ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 190 }, 191 192 /* Idem for the MacPro */ 193 { 194 "MacPro2", "Apple SMC Mac Pro (8-core)", 195 NULL, NULL, NULL, 196 ASMC_FAN_FUNCS, 197 NULL, NULL, 198 ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS 199 }, 200 201 { NULL, NULL } 202 }; 203 204 #undef ASMC_SMS_FUNCS 205 #undef ASMC_FAN_FUNCS 206 #undef ASMC_LIGHT_FUNCS 207 208 /* 209 * Driver methods. 210 */ 211 static device_method_t asmc_methods[] = { 212 DEVMETHOD(device_probe, asmc_probe), 213 DEVMETHOD(device_attach, asmc_attach), 214 DEVMETHOD(device_detach, asmc_detach), 215 216 { 0, 0 } 217 }; 218 219 static driver_t asmc_driver = { 220 "asmc", 221 asmc_methods, 222 sizeof(struct asmc_softc) 223 }; 224 225 /* 226 * Debugging 227 */ 228 #define _COMPONENT ACPI_OEM 229 ACPI_MODULE_NAME("ASMC") 230 #ifdef DEBUG 231 #define ASMC_DPRINTF(str) device_printf(dev, str) 232 #else 233 #define ASMC_DPRINTF(str) 234 #endif 235 236 static char *asmc_ids[] = { "APP0001", NULL }; 237 238 static devclass_t asmc_devclass; 239 240 DRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 241 MODULE_DEPEND(asmc, acpi, 1, 1, 1); 242 243 static struct asmc_model * 244 asmc_match(device_t dev) 245 { 246 int i; 247 char *model; 248 249 model = getenv("smbios.system.product"); 250 for (i = 0; asmc_models[i].smc_model; i++) { 251 if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 252 freeenv(model); 253 return (&asmc_models[i]); 254 } 255 } 256 freeenv(model); 257 258 return (NULL); 259 } 260 261 static int 262 asmc_probe(device_t dev) 263 { 264 struct asmc_model *model; 265 266 if (resource_disabled("asmc", 0)) 267 return (ENXIO); 268 if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL) 269 return (ENXIO); 270 271 model = asmc_match(dev); 272 if (!model) { 273 device_printf(dev, "model not recognized\n"); 274 return (ENXIO); 275 } 276 device_set_desc(dev, model->smc_desc); 277 278 return (BUS_PROBE_DEFAULT); 279 } 280 281 static int 282 asmc_attach(device_t dev) 283 { 284 int i, j; 285 int ret; 286 char name[2]; 287 struct asmc_softc *sc = device_get_softc(dev); 288 struct sysctl_ctx_list *sysctlctx; 289 struct sysctl_oid *sysctlnode; 290 struct asmc_model *model; 291 292 sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 293 &sc->sc_rid_port, RF_ACTIVE); 294 if (sc->sc_ioport == NULL) { 295 device_printf(dev, "unable to allocate IO port\n"); 296 return (ENOMEM); 297 } 298 299 sysctlctx = device_get_sysctl_ctx(dev); 300 sysctlnode = device_get_sysctl_tree(dev); 301 302 model = asmc_match(dev); 303 304 mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 305 306 sc->sc_model = model; 307 asmc_init(dev); 308 309 /* 310 * dev.asmc.n.fan.* tree. 311 */ 312 sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 313 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 314 CTLFLAG_RD, 0, "Fan Root Tree"); 315 316 for (i = 1; i <= sc->sc_nfan; i++) { 317 j = i - 1; 318 name[0] = '0' + j; 319 name[1] = 0; 320 sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 321 SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 322 OID_AUTO, name, CTLFLAG_RD, 0, 323 "Fan Subtree"); 324 325 SYSCTL_ADD_PROC(sysctlctx, 326 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 327 OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD, 328 dev, j, model->smc_fan_speed, "I", 329 "Fan speed in RPM"); 330 331 SYSCTL_ADD_PROC(sysctlctx, 332 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 333 OID_AUTO, "safespeed", 334 CTLTYPE_INT | CTLFLAG_RD, 335 dev, j, model->smc_fan_safespeed, "I", 336 "Fan safe speed in RPM"); 337 338 SYSCTL_ADD_PROC(sysctlctx, 339 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 340 OID_AUTO, "minspeed", 341 CTLTYPE_INT | CTLFLAG_RD, 342 dev, j, model->smc_fan_minspeed, "I", 343 "Fan minimum speed in RPM"); 344 345 SYSCTL_ADD_PROC(sysctlctx, 346 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 347 OID_AUTO, "maxspeed", 348 CTLTYPE_INT | CTLFLAG_RD, 349 dev, j, model->smc_fan_maxspeed, "I", 350 "Fan maximum speed in RPM"); 351 352 SYSCTL_ADD_PROC(sysctlctx, 353 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 354 OID_AUTO, "targetspeed", 355 CTLTYPE_INT | CTLFLAG_RD, 356 dev, j, model->smc_fan_targetspeed, "I", 357 "Fan target speed in RPM"); 358 } 359 360 /* 361 * dev.asmc.n.temp tree. 362 */ 363 sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 364 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 365 CTLFLAG_RD, 0, "Temperature sensors"); 366 367 for (i = 0; model->smc_temps[i]; i++) { 368 SYSCTL_ADD_PROC(sysctlctx, 369 SYSCTL_CHILDREN(sc->sc_temp_tree), 370 OID_AUTO, model->smc_tempnames[i], 371 CTLTYPE_INT | CTLFLAG_RD, 372 dev, i, asmc_temp_sysctl, "I", 373 model->smc_tempdescs[i]); 374 } 375 376 if (model->smc_sms_x == NULL) 377 goto nosms; 378 379 /* 380 * dev.asmc.n.sms tree. 381 */ 382 sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 383 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 384 CTLFLAG_RD, 0, "Sudden Motion Sensor"); 385 386 SYSCTL_ADD_PROC(sysctlctx, 387 SYSCTL_CHILDREN(sc->sc_sms_tree), 388 OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD, 389 dev, 0, model->smc_sms_x, "I", 390 "Sudden Motion Sensor X value"); 391 392 SYSCTL_ADD_PROC(sysctlctx, 393 SYSCTL_CHILDREN(sc->sc_sms_tree), 394 OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD, 395 dev, 0, model->smc_sms_y, "I", 396 "Sudden Motion Sensor Y value"); 397 398 SYSCTL_ADD_PROC(sysctlctx, 399 SYSCTL_CHILDREN(sc->sc_sms_tree), 400 OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD, 401 dev, 0, model->smc_sms_z, "I", 402 "Sudden Motion Sensor Z value"); 403 404 /* 405 * dev.asmc.n.light 406 */ 407 if (model->smc_light_left) { 408 sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 409 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 410 CTLFLAG_RD, 0, "Keyboard backlight sensors"); 411 412 SYSCTL_ADD_PROC(sysctlctx, 413 SYSCTL_CHILDREN(sc->sc_light_tree), 414 OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RW, 415 dev, 0, model->smc_light_left, "I", 416 "Keyboard backlight left sensor"); 417 418 SYSCTL_ADD_PROC(sysctlctx, 419 SYSCTL_CHILDREN(sc->sc_light_tree), 420 OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RW, 421 dev, 0, model->smc_light_right, "I", 422 "Keyboard backlight right sensor"); 423 } 424 425 /* 426 * Need a taskqueue to send devctl_notify() events 427 * when the SMS interrupt us. 428 * 429 * PI_REALTIME is used due to the sensitivity of the 430 * interrupt. An interrupt from the SMS means that the 431 * disk heads should be turned off as quickly as possible. 432 * 433 * We only need to do this for the non INTR_FILTER case. 434 */ 435 sc->sc_sms_tq = NULL; 436 #ifndef INTR_FILTER 437 TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 438 sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 439 taskqueue_thread_enqueue, &sc->sc_sms_tq); 440 taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 441 device_get_nameunit(dev)); 442 #endif 443 /* 444 * Allocate an IRQ for the SMS. 445 */ 446 sc->sc_rid_irq = 0; 447 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 448 &sc->sc_rid_irq, RF_ACTIVE); 449 if (sc->sc_irq == NULL) { 450 device_printf(dev, "unable to allocate IRQ resource\n"); 451 ret = ENXIO; 452 goto err2; 453 } 454 455 ret = bus_setup_intr(dev, sc->sc_irq, 456 INTR_TYPE_MISC | INTR_MPSAFE, 457 #ifdef INTR_FILTER 458 asmc_sms_intrfast, asmc_sms_handler, 459 #else 460 asmc_sms_intrfast, NULL, 461 #endif 462 dev, &sc->sc_cookie); 463 464 if (ret) { 465 device_printf(dev, "unable to setup SMS IRQ\n"); 466 goto err1; 467 } 468 nosms: 469 return (0); 470 err1: 471 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 472 err2: 473 bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 474 sc->sc_ioport); 475 mtx_destroy(&sc->sc_mtx); 476 if (sc->sc_sms_tq) 477 taskqueue_free(sc->sc_sms_tq); 478 479 return (ret); 480 } 481 482 static int 483 asmc_detach(device_t dev) 484 { 485 struct asmc_softc *sc = device_get_softc(dev); 486 487 if (sc->sc_sms_tq) { 488 taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 489 taskqueue_free(sc->sc_sms_tq); 490 } 491 if (sc->sc_cookie) 492 bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 493 if (sc->sc_irq) 494 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 495 sc->sc_irq); 496 if (sc->sc_ioport) 497 bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 498 sc->sc_ioport); 499 mtx_destroy(&sc->sc_mtx); 500 501 return (0); 502 } 503 504 static int 505 asmc_init(device_t dev) 506 { 507 struct asmc_softc *sc = device_get_softc(dev); 508 int i, error = 1; 509 uint8_t buf[4]; 510 511 if (sc->sc_model->smc_sms_x == NULL) 512 goto nosms; 513 514 /* 515 * We are ready to recieve interrupts from the SMS. 516 */ 517 buf[0] = 0x01; 518 ASMC_DPRINTF(("intok key\n")); 519 asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 520 DELAY(50); 521 522 /* 523 * Initiate the polling intervals. 524 */ 525 buf[0] = 20; /* msecs */ 526 ASMC_DPRINTF(("low int key\n")); 527 asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 528 DELAY(200); 529 530 buf[0] = 20; /* msecs */ 531 ASMC_DPRINTF(("high int key\n")); 532 asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 533 DELAY(200); 534 535 buf[0] = 0x00; 536 buf[1] = 0x60; 537 ASMC_DPRINTF(("sms low key\n")); 538 asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 539 DELAY(200); 540 541 buf[0] = 0x01; 542 buf[1] = 0xc0; 543 ASMC_DPRINTF(("sms high key\n")); 544 asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 545 DELAY(200); 546 547 /* 548 * I'm not sure what this key does, but it seems to be 549 * required. 550 */ 551 buf[0] = 0x01; 552 ASMC_DPRINTF(("sms flag key\n")); 553 asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 554 DELAY(100); 555 556 /* 557 * Wait up to 5 seconds for SMS initialization. 558 */ 559 for (i = 0; i < 10000; i++) { 560 if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 561 (buf[0] != 0x00 || buf[1] != 0x00)) { 562 error = 0; 563 goto out; 564 } 565 buf[0] = ASMC_SMS_INIT1; 566 buf[1] = ASMC_SMS_INIT2; 567 ASMC_DPRINTF(("sms key\n")); 568 asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 569 DELAY(50); 570 } 571 device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 572 573 out: 574 asmc_sms_calibrate(dev); 575 nosms: 576 sc->sc_nfan = asmc_fan_count(dev); 577 if (sc->sc_nfan > ASMC_MAXFANS) { 578 device_printf(dev, "more than %d fans were detected. Please " 579 "report this.\n", ASMC_MAXFANS); 580 sc->sc_nfan = ASMC_MAXFANS; 581 } 582 583 if (bootverbose) { 584 /* 585 * XXX: The number of keys is a 32 bit buffer, but 586 * right now Apple only uses the last 8 bit. 587 */ 588 asmc_key_read(dev, ASMC_NKEYS, buf, 4); 589 device_printf(dev, "number of keys: %d\n", buf[3]); 590 } 591 592 return (error); 593 } 594 595 /* 596 * We need to make sure that the SMC acks the byte sent. 597 * Just wait up to 100 ms. 598 */ 599 static int 600 asmc_wait(device_t dev, uint8_t val) 601 { 602 struct asmc_softc *sc = device_get_softc(dev); 603 u_int i; 604 605 val = val & ASMC_STATUS_MASK; 606 607 for (i = 0; i < 1000; i++) { 608 if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 609 return (0); 610 DELAY(10); 611 } 612 613 device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 614 ASMC_CMDPORT_READ(sc)); 615 616 return (1); 617 } 618 619 static int 620 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 621 { 622 int i, error = 1; 623 struct asmc_softc *sc = device_get_softc(dev); 624 625 mtx_lock_spin(&sc->sc_mtx); 626 627 ASMC_CMDPORT_WRITE(sc, ASMC_CMDREAD); 628 if (asmc_wait(dev, 0x0c)) 629 goto out; 630 631 for (i = 0; i < 4; i++) { 632 ASMC_DATAPORT_WRITE(sc, key[i]); 633 if (asmc_wait(dev, 0x04)) 634 goto out; 635 } 636 637 ASMC_DATAPORT_WRITE(sc, len); 638 639 for (i = 0; i < len; i++) { 640 if (asmc_wait(dev, 0x05)) 641 goto out; 642 buf[i] = ASMC_DATAPORT_READ(sc); 643 } 644 645 error = 0; 646 out: 647 mtx_unlock_spin(&sc->sc_mtx); 648 649 return (error); 650 } 651 652 static int 653 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 654 { 655 int i, error = -1; 656 struct asmc_softc *sc = device_get_softc(dev); 657 658 mtx_lock_spin(&sc->sc_mtx); 659 660 ASMC_DPRINTF(("cmd port: cmd write\n")); 661 ASMC_CMDPORT_WRITE(sc, ASMC_CMDWRITE); 662 if (asmc_wait(dev, 0x0c)) 663 goto out; 664 665 ASMC_DPRINTF(("data port: key\n")); 666 for (i = 0; i < 4; i++) { 667 ASMC_DATAPORT_WRITE(sc, key[i]); 668 if (asmc_wait(dev, 0x04)) 669 goto out; 670 } 671 ASMC_DPRINTF(("data port: length\n")); 672 ASMC_DATAPORT_WRITE(sc, len); 673 674 ASMC_DPRINTF(("data port: buffer\n")); 675 for (i = 0; i < len; i++) { 676 if (asmc_wait(dev, 0x04)) 677 goto out; 678 ASMC_DATAPORT_WRITE(sc, buf[i]); 679 } 680 681 error = 0; 682 out: 683 mtx_unlock_spin(&sc->sc_mtx); 684 685 return (error); 686 687 } 688 689 /* 690 * Fan control functions. 691 */ 692 static int 693 asmc_fan_count(device_t dev) 694 { 695 uint8_t buf[1]; 696 697 if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, 1) < 0) 698 return (-1); 699 700 return (buf[0]); 701 } 702 703 static int 704 asmc_fan_getvalue(device_t dev, const char *key, int fan) 705 { 706 int speed; 707 uint8_t buf[2]; 708 char fankey[5]; 709 710 snprintf(fankey, sizeof(fankey), key, fan); 711 if (asmc_key_read(dev, fankey, buf, 2) < 0) 712 return (-1); 713 speed = (buf[0] << 6) | (buf[1] >> 2); 714 715 return (speed); 716 } 717 718 static int 719 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 720 { 721 device_t dev = (device_t) arg1; 722 int fan = arg2; 723 int error; 724 int32_t v; 725 726 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 727 error = sysctl_handle_int(oidp, &v, 0, req); 728 729 return (error); 730 } 731 732 static int 733 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 734 { 735 device_t dev = (device_t) arg1; 736 int fan = arg2; 737 int error; 738 int32_t v; 739 740 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 741 error = sysctl_handle_int(oidp, &v, 0, req); 742 743 return (error); 744 } 745 746 747 static int 748 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 749 { 750 device_t dev = (device_t) arg1; 751 int fan = arg2; 752 int error; 753 int32_t v; 754 755 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 756 error = sysctl_handle_int(oidp, &v, 0, req); 757 758 return (error); 759 } 760 761 static int 762 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 763 { 764 device_t dev = (device_t) arg1; 765 int fan = arg2; 766 int error; 767 int32_t v; 768 769 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 770 error = sysctl_handle_int(oidp, &v, 0, req); 771 772 return (error); 773 } 774 775 static int 776 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 777 { 778 device_t dev = (device_t) arg1; 779 int fan = arg2; 780 int error; 781 int32_t v; 782 783 v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 784 error = sysctl_handle_int(oidp, &v, 0, req); 785 786 return (error); 787 } 788 789 /* 790 * Temperature functions. 791 */ 792 static int 793 asmc_temp_getvalue(device_t dev, const char *key) 794 { 795 uint8_t buf[2]; 796 797 /* 798 * Check for invalid temperatures. 799 */ 800 if (asmc_key_read(dev, key, buf, 2) < 0) 801 return (-1); 802 803 return (buf[0]); 804 } 805 806 static int 807 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 808 { 809 device_t dev = (device_t) arg1; 810 struct asmc_softc *sc = device_get_softc(dev); 811 int error, val; 812 813 val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 814 error = sysctl_handle_int(oidp, &val, 0, req); 815 816 return (error); 817 } 818 819 /* 820 * Sudden Motion Sensor functions. 821 */ 822 static int 823 asmc_sms_read(device_t dev, const char *key, int16_t *val) 824 { 825 uint8_t buf[2]; 826 int error; 827 828 /* no need to do locking here as asmc_key_read() already does it */ 829 switch (key[3]) { 830 case 'X': 831 case 'Y': 832 case 'Z': 833 error = asmc_key_read(dev, key, buf, 2); 834 break; 835 default: 836 device_printf(dev, "%s called with invalid argument %s\n", 837 __func__, key); 838 error = 1; 839 goto out; 840 } 841 *val = ((int16_t)buf[0] << 8) | buf[1]; 842 out: 843 return (error); 844 } 845 846 static void 847 asmc_sms_calibrate(device_t dev) 848 { 849 struct asmc_softc *sc = device_get_softc(dev); 850 851 asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 852 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 853 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 854 } 855 856 static int 857 asmc_sms_intrfast(void *arg) 858 { 859 uint8_t type; 860 device_t dev = (device_t) arg; 861 struct asmc_softc *sc = device_get_softc(dev); 862 863 mtx_lock_spin(&sc->sc_mtx); 864 type = ASMC_INTPORT_READ(sc); 865 mtx_unlock_spin(&sc->sc_mtx); 866 867 sc->sc_sms_intrtype = type; 868 asmc_sms_printintr(dev, type); 869 870 #ifdef INTR_FILTER 871 return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED); 872 #else 873 taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 874 #endif 875 return (FILTER_HANDLED); 876 } 877 878 #ifdef INTR_FILTER 879 static void 880 asmc_sms_handler(void *arg) 881 { 882 struct asmc_softc *sc = device_get_softc(arg); 883 884 asmc_sms_task(sc, 0); 885 } 886 #endif 887 888 889 static void 890 asmc_sms_printintr(device_t dev, uint8_t type) 891 { 892 893 switch (type) { 894 case ASMC_SMS_INTFF: 895 device_printf(dev, "WARNING: possible free fall!\n"); 896 break; 897 case ASMC_SMS_INTHA: 898 device_printf(dev, "WARNING: high acceleration detected!\n"); 899 break; 900 case ASMC_SMS_INTSH: 901 device_printf(dev, "WARNING: possible shock!\n"); 902 break; 903 default: 904 device_printf(dev, "%s unknown interrupt\n", __func__); 905 } 906 } 907 908 static void 909 asmc_sms_task(void *arg, int pending) 910 { 911 struct asmc_softc *sc = (struct asmc_softc *)arg; 912 char notify[16]; 913 int type; 914 915 switch (sc->sc_sms_intrtype) { 916 case ASMC_SMS_INTFF: 917 type = 2; 918 break; 919 case ASMC_SMS_INTHA: 920 type = 1; 921 break; 922 case ASMC_SMS_INTSH: 923 type = 0; 924 break; 925 default: 926 type = 255; 927 } 928 929 snprintf(notify, sizeof(notify), " notify=0x%x", type); 930 devctl_notify("ACPI", "asmc", "SMS", notify); 931 } 932 933 static int 934 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 935 { 936 device_t dev = (device_t) arg1; 937 int error; 938 int16_t val; 939 int32_t v; 940 941 asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 942 v = (int32_t) val; 943 error = sysctl_handle_int(oidp, &v, 0, req); 944 945 return (error); 946 } 947 948 static int 949 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 950 { 951 device_t dev = (device_t) arg1; 952 int error; 953 int16_t val; 954 int32_t v; 955 956 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 957 v = (int32_t) val; 958 error = sysctl_handle_int(oidp, &v, 0, req); 959 960 return (error); 961 } 962 963 static int 964 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 965 { 966 device_t dev = (device_t) arg1; 967 int error; 968 int16_t val; 969 int32_t v; 970 971 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 972 v = (int32_t) val; 973 error = sysctl_handle_int(oidp, &v, sizeof(v), req); 974 975 return (error); 976 } 977 978 static int 979 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 980 { 981 device_t dev = (device_t) arg1; 982 uint8_t buf[6]; 983 int error; 984 unsigned int level; 985 int32_t v; 986 987 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, 6); 988 v = buf[2]; 989 error = sysctl_handle_int(oidp, &v, sizeof(v), req); 990 if (error == 0 && req->newptr != NULL) { 991 level = *(unsigned int *)req->newptr; 992 if (level > 255) 993 return (EINVAL); 994 buf[0] = level; 995 buf[1] = 0x00; 996 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2); 997 } 998 999 return (error); 1000 } 1001 1002 static int 1003 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 1004 { 1005 device_t dev = (device_t) arg1; 1006 uint8_t buf[6]; 1007 int error; 1008 unsigned int level; 1009 int32_t v; 1010 1011 asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, 6); 1012 v = buf[2]; 1013 error = sysctl_handle_int(oidp, &v, sizeof(v), req); 1014 if (error == 0 && req->newptr != NULL) { 1015 level = *(unsigned int *)req->newptr; 1016 if (level > 255) 1017 return (EINVAL); 1018 buf[0] = level; 1019 buf[1] = 0x00; 1020 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2); 1021 } 1022 1023 return (error); 1024 } 1025