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 53 #include <contrib/dev/acpica/include/acpi.h> 54 55 #include <dev/acpica/acpivar.h> 56 #include <dev/asmc/asmcvar.h> 57 58 #include "opt_intr_filter.h" 59 60 /* 61 * Device interface. 62 */ 63 static int asmc_probe(device_t dev); 64 static int asmc_attach(device_t dev); 65 static int asmc_detach(device_t dev); 66 67 /* 68 * SMC functions. 69 */ 70 static int asmc_init(device_t dev); 71 static int asmc_command(device_t dev, uint8_t command); 72 static int asmc_wait(device_t dev, uint8_t val); 73 static int asmc_wait_ack(device_t dev, uint8_t val, int amount); 74 static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 75 uint8_t len); 76 static int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 77 uint8_t); 78 static int asmc_fan_count(device_t dev); 79 static int asmc_fan_getvalue(device_t dev, const char *key, int fan); 80 static int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed); 81 static int asmc_temp_getvalue(device_t dev, const char *key); 82 static int asmc_sms_read(device_t, const char *key, int16_t *val); 83 static void asmc_sms_calibrate(device_t dev); 84 static int asmc_sms_intrfast(void *arg); 85 #ifdef INTR_FILTER 86 static void asmc_sms_handler(void *arg); 87 #endif 88 static void asmc_sms_printintr(device_t dev, uint8_t); 89 static void asmc_sms_task(void *arg, int pending); 90 #ifdef DEBUG 91 void asmc_dumpall(device_t); 92 static int asmc_key_dump(device_t, int); 93 #endif 94 95 /* 96 * Model functions. 97 */ 98 static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS); 99 static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 100 static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 101 static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 102 static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 103 static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 104 static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 105 static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 106 static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 107 static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 108 static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 109 static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 110 static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); 111 112 struct asmc_model { 113 const char *smc_model; /* smbios.system.product env var. */ 114 const char *smc_desc; /* driver description */ 115 116 /* Helper functions */ 117 int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); 118 int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); 119 int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); 120 int (*smc_fan_id)(SYSCTL_HANDLER_ARGS); 121 int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); 122 int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); 123 int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); 124 int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); 125 int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); 126 int (*smc_light_left)(SYSCTL_HANDLER_ARGS); 127 int (*smc_light_right)(SYSCTL_HANDLER_ARGS); 128 int (*smc_light_control)(SYSCTL_HANDLER_ARGS); 129 130 const char *smc_temps[ASMC_TEMP_MAX]; 131 const char *smc_tempnames[ASMC_TEMP_MAX]; 132 const char *smc_tempdescs[ASMC_TEMP_MAX]; 133 }; 134 135 static struct asmc_model *asmc_match(device_t dev); 136 137 #define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ 138 asmc_mb_sysctl_sms_z 139 140 #define ASMC_FAN_FUNCS asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ 141 asmc_mb_sysctl_fanminspeed, \ 142 asmc_mb_sysctl_fanmaxspeed, \ 143 asmc_mb_sysctl_fantargetspeed 144 #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ 145 asmc_mbp_sysctl_light_right, \ 146 asmc_mbp_sysctl_light_control 147 148 struct asmc_model asmc_models[] = { 149 { 150 "MacBook1,1", "Apple SMC MacBook Core Duo", 151 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 152 ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 153 }, 154 155 { 156 "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 157 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 158 ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 159 }, 160 161 { 162 "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 163 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 164 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 165 }, 166 167 { 168 "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 169 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 170 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 171 }, 172 173 { 174 "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 175 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 176 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 177 }, 178 179 { 180 "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 181 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 182 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 183 }, 184 185 { 186 "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 187 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 188 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 189 }, 190 191 { 192 "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 193 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 194 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 195 }, 196 197 { 198 "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)", 199 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 200 ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS 201 }, 202 203 { 204 "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)", 205 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 206 ASMC_MBP8_TEMPS, ASMC_MBP8_TEMPNAMES, ASMC_MBP8_TEMPDESCS 207 }, 208 209 { 210 "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 211 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 212 ASMC_MBP11_TEMPS, ASMC_MBP11_TEMPNAMES, ASMC_MBP11_TEMPDESCS 213 }, 214 215 /* The Mac Mini has no SMS */ 216 { 217 "Macmini1,1", "Apple SMC Mac Mini", 218 NULL, NULL, NULL, 219 ASMC_FAN_FUNCS, 220 NULL, NULL, NULL, 221 ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 222 }, 223 224 /* The Mac Mini 3,1 has no SMS */ 225 { 226 "Macmini3,1", "Apple SMC Mac Mini 3,1", 227 NULL, NULL, NULL, 228 ASMC_FAN_FUNCS, 229 NULL, NULL, NULL, 230 ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS 231 }, 232 233 /* Idem for the MacPro */ 234 { 235 "MacPro2", "Apple SMC Mac Pro (8-core)", 236 NULL, NULL, NULL, 237 ASMC_FAN_FUNCS, 238 NULL, NULL, NULL, 239 ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS 240 }, 241 242 /* Idem for the MacPro 2010*/ 243 { 244 "MacPro5,1", "Apple SMC MacPro (2010)", 245 NULL, NULL, NULL, 246 ASMC_FAN_FUNCS, 247 NULL, NULL, NULL, 248 ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS 249 }, 250 251 { 252 "MacBookAir1,1", "Apple SMC MacBook Air", 253 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 254 ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS 255 }, 256 257 { 258 "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", 259 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 260 ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS 261 }, 262 263 264 { NULL, NULL } 265 }; 266 267 #undef ASMC_SMS_FUNCS 268 #undef ASMC_FAN_FUNCS 269 #undef ASMC_LIGHT_FUNCS 270 271 /* 272 * Driver methods. 273 */ 274 static device_method_t asmc_methods[] = { 275 DEVMETHOD(device_probe, asmc_probe), 276 DEVMETHOD(device_attach, asmc_attach), 277 DEVMETHOD(device_detach, asmc_detach), 278 279 { 0, 0 } 280 }; 281 282 static driver_t asmc_driver = { 283 "asmc", 284 asmc_methods, 285 sizeof(struct asmc_softc) 286 }; 287 288 /* 289 * Debugging 290 */ 291 #define _COMPONENT ACPI_OEM 292 ACPI_MODULE_NAME("ASMC") 293 #ifdef DEBUG 294 #define ASMC_DPRINTF(str) device_printf(dev, str) 295 #else 296 #define ASMC_DPRINTF(str) 297 #endif 298 299 /* NB: can't be const */ 300 static char *asmc_ids[] = { "APP0001", NULL }; 301 302 static devclass_t asmc_devclass; 303 304 DRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 305 MODULE_DEPEND(asmc, acpi, 1, 1, 1); 306 307 static struct asmc_model * 308 asmc_match(device_t dev) 309 { 310 int i; 311 char *model; 312 313 model = kern_getenv("smbios.system.product"); 314 if (model == NULL) 315 return (NULL); 316 317 for (i = 0; asmc_models[i].smc_model; i++) { 318 if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 319 freeenv(model); 320 return (&asmc_models[i]); 321 } 322 } 323 freeenv(model); 324 325 return (NULL); 326 } 327 328 static int 329 asmc_probe(device_t dev) 330 { 331 struct asmc_model *model; 332 333 if (resource_disabled("asmc", 0)) 334 return (ENXIO); 335 if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL) 336 return (ENXIO); 337 338 model = asmc_match(dev); 339 if (!model) { 340 device_printf(dev, "model not recognized\n"); 341 return (ENXIO); 342 } 343 device_set_desc(dev, model->smc_desc); 344 345 return (BUS_PROBE_DEFAULT); 346 } 347 348 static int 349 asmc_attach(device_t dev) 350 { 351 int i, j; 352 int ret; 353 char name[2]; 354 struct asmc_softc *sc = device_get_softc(dev); 355 struct sysctl_ctx_list *sysctlctx; 356 struct sysctl_oid *sysctlnode; 357 struct asmc_model *model; 358 359 sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 360 &sc->sc_rid_port, RF_ACTIVE); 361 if (sc->sc_ioport == NULL) { 362 device_printf(dev, "unable to allocate IO port\n"); 363 return (ENOMEM); 364 } 365 366 sysctlctx = device_get_sysctl_ctx(dev); 367 sysctlnode = device_get_sysctl_tree(dev); 368 369 model = asmc_match(dev); 370 371 mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 372 373 sc->sc_model = model; 374 asmc_init(dev); 375 376 /* 377 * dev.asmc.n.fan.* tree. 378 */ 379 sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 380 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 381 CTLFLAG_RD, 0, "Fan Root Tree"); 382 383 for (i = 1; i <= sc->sc_nfan; i++) { 384 j = i - 1; 385 name[0] = '0' + j; 386 name[1] = 0; 387 sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 388 SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 389 OID_AUTO, name, CTLFLAG_RD, 0, 390 "Fan Subtree"); 391 392 SYSCTL_ADD_PROC(sysctlctx, 393 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 394 OID_AUTO, "id", CTLTYPE_STRING | CTLFLAG_RD, 395 dev, j, model->smc_fan_id, "I", 396 "Fan ID"); 397 398 SYSCTL_ADD_PROC(sysctlctx, 399 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 400 OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD, 401 dev, j, model->smc_fan_speed, "I", 402 "Fan speed in RPM"); 403 404 SYSCTL_ADD_PROC(sysctlctx, 405 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 406 OID_AUTO, "safespeed", 407 CTLTYPE_INT | CTLFLAG_RD, 408 dev, j, model->smc_fan_safespeed, "I", 409 "Fan safe speed in RPM"); 410 411 SYSCTL_ADD_PROC(sysctlctx, 412 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 413 OID_AUTO, "minspeed", 414 CTLTYPE_INT | CTLFLAG_RW, 415 dev, j, model->smc_fan_minspeed, "I", 416 "Fan minimum speed in RPM"); 417 418 SYSCTL_ADD_PROC(sysctlctx, 419 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 420 OID_AUTO, "maxspeed", 421 CTLTYPE_INT | CTLFLAG_RW, 422 dev, j, model->smc_fan_maxspeed, "I", 423 "Fan maximum speed in RPM"); 424 425 SYSCTL_ADD_PROC(sysctlctx, 426 SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 427 OID_AUTO, "targetspeed", 428 CTLTYPE_INT | CTLFLAG_RW, 429 dev, j, model->smc_fan_targetspeed, "I", 430 "Fan target speed in RPM"); 431 } 432 433 /* 434 * dev.asmc.n.temp tree. 435 */ 436 sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 437 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 438 CTLFLAG_RD, 0, "Temperature sensors"); 439 440 for (i = 0; model->smc_temps[i]; i++) { 441 SYSCTL_ADD_PROC(sysctlctx, 442 SYSCTL_CHILDREN(sc->sc_temp_tree), 443 OID_AUTO, model->smc_tempnames[i], 444 CTLTYPE_INT | CTLFLAG_RD, 445 dev, i, asmc_temp_sysctl, "I", 446 model->smc_tempdescs[i]); 447 } 448 449 /* 450 * dev.asmc.n.light 451 */ 452 if (model->smc_light_left) { 453 sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 454 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 455 CTLFLAG_RD, 0, "Keyboard backlight sensors"); 456 457 SYSCTL_ADD_PROC(sysctlctx, 458 SYSCTL_CHILDREN(sc->sc_light_tree), 459 OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD, 460 dev, 0, model->smc_light_left, "I", 461 "Keyboard backlight left sensor"); 462 463 SYSCTL_ADD_PROC(sysctlctx, 464 SYSCTL_CHILDREN(sc->sc_light_tree), 465 OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD, 466 dev, 0, model->smc_light_right, "I", 467 "Keyboard backlight right sensor"); 468 469 SYSCTL_ADD_PROC(sysctlctx, 470 SYSCTL_CHILDREN(sc->sc_light_tree), 471 OID_AUTO, "control", 472 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 473 dev, 0, model->smc_light_control, "I", 474 "Keyboard backlight brightness control"); 475 } 476 477 if (model->smc_sms_x == NULL) 478 goto nosms; 479 480 /* 481 * dev.asmc.n.sms tree. 482 */ 483 sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 484 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 485 CTLFLAG_RD, 0, "Sudden Motion Sensor"); 486 487 SYSCTL_ADD_PROC(sysctlctx, 488 SYSCTL_CHILDREN(sc->sc_sms_tree), 489 OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD, 490 dev, 0, model->smc_sms_x, "I", 491 "Sudden Motion Sensor X value"); 492 493 SYSCTL_ADD_PROC(sysctlctx, 494 SYSCTL_CHILDREN(sc->sc_sms_tree), 495 OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD, 496 dev, 0, model->smc_sms_y, "I", 497 "Sudden Motion Sensor Y value"); 498 499 SYSCTL_ADD_PROC(sysctlctx, 500 SYSCTL_CHILDREN(sc->sc_sms_tree), 501 OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD, 502 dev, 0, model->smc_sms_z, "I", 503 "Sudden Motion Sensor Z value"); 504 505 /* 506 * Need a taskqueue to send devctl_notify() events 507 * when the SMS interrupt us. 508 * 509 * PI_REALTIME is used due to the sensitivity of the 510 * interrupt. An interrupt from the SMS means that the 511 * disk heads should be turned off as quickly as possible. 512 * 513 * We only need to do this for the non INTR_FILTER case. 514 */ 515 sc->sc_sms_tq = NULL; 516 #ifndef INTR_FILTER 517 TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 518 sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 519 taskqueue_thread_enqueue, &sc->sc_sms_tq); 520 taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 521 device_get_nameunit(dev)); 522 #endif 523 /* 524 * Allocate an IRQ for the SMS. 525 */ 526 sc->sc_rid_irq = 0; 527 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 528 &sc->sc_rid_irq, RF_ACTIVE); 529 if (sc->sc_irq == NULL) { 530 device_printf(dev, "unable to allocate IRQ resource\n"); 531 ret = ENXIO; 532 goto err2; 533 } 534 535 ret = bus_setup_intr(dev, sc->sc_irq, 536 INTR_TYPE_MISC | INTR_MPSAFE, 537 #ifdef INTR_FILTER 538 asmc_sms_intrfast, asmc_sms_handler, 539 #else 540 asmc_sms_intrfast, NULL, 541 #endif 542 dev, &sc->sc_cookie); 543 544 if (ret) { 545 device_printf(dev, "unable to setup SMS IRQ\n"); 546 goto err1; 547 } 548 nosms: 549 return (0); 550 err1: 551 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 552 err2: 553 bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 554 sc->sc_ioport); 555 mtx_destroy(&sc->sc_mtx); 556 if (sc->sc_sms_tq) 557 taskqueue_free(sc->sc_sms_tq); 558 559 return (ret); 560 } 561 562 static int 563 asmc_detach(device_t dev) 564 { 565 struct asmc_softc *sc = device_get_softc(dev); 566 567 if (sc->sc_sms_tq) { 568 taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 569 taskqueue_free(sc->sc_sms_tq); 570 } 571 if (sc->sc_cookie) 572 bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 573 if (sc->sc_irq) 574 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 575 sc->sc_irq); 576 if (sc->sc_ioport) 577 bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 578 sc->sc_ioport); 579 mtx_destroy(&sc->sc_mtx); 580 581 return (0); 582 } 583 584 #ifdef DEBUG 585 void asmc_dumpall(device_t dev) 586 { 587 int i; 588 589 /* XXX magic number */ 590 for (i=0; i < 0x100; i++) 591 asmc_key_dump(dev, i); 592 } 593 #endif 594 595 static int 596 asmc_init(device_t dev) 597 { 598 struct asmc_softc *sc = device_get_softc(dev); 599 int i, error = 1; 600 uint8_t buf[4]; 601 602 if (sc->sc_model->smc_sms_x == NULL) 603 goto nosms; 604 605 /* 606 * We are ready to recieve interrupts from the SMS. 607 */ 608 buf[0] = 0x01; 609 ASMC_DPRINTF(("intok key\n")); 610 asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 611 DELAY(50); 612 613 /* 614 * Initiate the polling intervals. 615 */ 616 buf[0] = 20; /* msecs */ 617 ASMC_DPRINTF(("low int key\n")); 618 asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 619 DELAY(200); 620 621 buf[0] = 20; /* msecs */ 622 ASMC_DPRINTF(("high int key\n")); 623 asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 624 DELAY(200); 625 626 buf[0] = 0x00; 627 buf[1] = 0x60; 628 ASMC_DPRINTF(("sms low key\n")); 629 asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 630 DELAY(200); 631 632 buf[0] = 0x01; 633 buf[1] = 0xc0; 634 ASMC_DPRINTF(("sms high key\n")); 635 asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 636 DELAY(200); 637 638 /* 639 * I'm not sure what this key does, but it seems to be 640 * required. 641 */ 642 buf[0] = 0x01; 643 ASMC_DPRINTF(("sms flag key\n")); 644 asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 645 DELAY(100); 646 647 sc->sc_sms_intr_works = 0; 648 649 /* 650 * Retry SMS initialization 1000 times 651 * (takes approx. 2 seconds in worst case) 652 */ 653 for (i = 0; i < 1000; i++) { 654 if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 655 (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 656 error = 0; 657 sc->sc_sms_intr_works = 1; 658 goto out; 659 } 660 buf[0] = ASMC_SMS_INIT1; 661 buf[1] = ASMC_SMS_INIT2; 662 ASMC_DPRINTF(("sms key\n")); 663 asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 664 DELAY(50); 665 } 666 device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 667 668 out: 669 asmc_sms_calibrate(dev); 670 nosms: 671 sc->sc_nfan = asmc_fan_count(dev); 672 if (sc->sc_nfan > ASMC_MAXFANS) { 673 device_printf(dev, "more than %d fans were detected. Please " 674 "report this.\n", ASMC_MAXFANS); 675 sc->sc_nfan = ASMC_MAXFANS; 676 } 677 678 if (bootverbose) { 679 /* 680 * The number of keys is a 32 bit buffer 681 */ 682 asmc_key_read(dev, ASMC_NKEYS, buf, 4); 683 device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf)); 684 } 685 686 #ifdef DEBUG 687 asmc_dumpall(dev); 688 #endif 689 690 return (error); 691 } 692 693 /* 694 * We need to make sure that the SMC acks the byte sent. 695 * Just wait up to (amount * 10) ms. 696 */ 697 static int 698 asmc_wait_ack(device_t dev, uint8_t val, int amount) 699 { 700 struct asmc_softc *sc = device_get_softc(dev); 701 u_int i; 702 703 val = val & ASMC_STATUS_MASK; 704 705 for (i = 0; i < amount; i++) { 706 if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 707 return (0); 708 DELAY(10); 709 } 710 711 return (1); 712 } 713 714 /* 715 * We need to make sure that the SMC acks the byte sent. 716 * Just wait up to 100 ms. 717 */ 718 static int 719 asmc_wait(device_t dev, uint8_t val) 720 { 721 struct asmc_softc *sc; 722 723 if (asmc_wait_ack(dev, val, 1000) == 0) 724 return (0); 725 726 sc = device_get_softc(dev); 727 val = val & ASMC_STATUS_MASK; 728 729 #ifdef DEBUG 730 device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 731 ASMC_CMDPORT_READ(sc)); 732 #endif 733 return (1); 734 } 735 736 /* 737 * Send the given command, retrying up to 10 times if 738 * the acknowledgement fails. 739 */ 740 static int 741 asmc_command(device_t dev, uint8_t command) { 742 743 int i; 744 struct asmc_softc *sc = device_get_softc(dev); 745 746 for (i=0; i < 10; i++) { 747 ASMC_CMDPORT_WRITE(sc, command); 748 if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 749 return (0); 750 } 751 } 752 753 #ifdef DEBUG 754 device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 755 ASMC_CMDPORT_READ(sc)); 756 #endif 757 return (1); 758 } 759 760 static int 761 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 762 { 763 int i, error = 1, try = 0; 764 struct asmc_softc *sc = device_get_softc(dev); 765 766 mtx_lock_spin(&sc->sc_mtx); 767 768 begin: 769 if (asmc_command(dev, ASMC_CMDREAD)) 770 goto out; 771 772 for (i = 0; i < 4; i++) { 773 ASMC_DATAPORT_WRITE(sc, key[i]); 774 if (asmc_wait(dev, 0x04)) 775 goto out; 776 } 777 778 ASMC_DATAPORT_WRITE(sc, len); 779 780 for (i = 0; i < len; i++) { 781 if (asmc_wait(dev, 0x05)) 782 goto out; 783 buf[i] = ASMC_DATAPORT_READ(sc); 784 } 785 786 error = 0; 787 out: 788 if (error) { 789 if (++try < 10) goto begin; 790 device_printf(dev,"%s for key %s failed %d times, giving up\n", 791 __func__, key, try); 792 } 793 794 mtx_unlock_spin(&sc->sc_mtx); 795 796 return (error); 797 } 798 799 #ifdef DEBUG 800 static int 801 asmc_key_dump(device_t dev, int number) 802 { 803 struct asmc_softc *sc = device_get_softc(dev); 804 char key[5] = { 0 }; 805 char type[7] = { 0 }; 806 uint8_t index[4]; 807 uint8_t v[32]; 808 uint8_t maxlen; 809 int i, error = 1, try = 0; 810 811 mtx_lock_spin(&sc->sc_mtx); 812 813 index[0] = (number >> 24) & 0xff; 814 index[1] = (number >> 16) & 0xff; 815 index[2] = (number >> 8) & 0xff; 816 index[3] = (number) & 0xff; 817 818 begin: 819 if (asmc_command(dev, 0x12)) 820 goto out; 821 822 for (i = 0; i < 4; i++) { 823 ASMC_DATAPORT_WRITE(sc, index[i]); 824 if (asmc_wait(dev, 0x04)) 825 goto out; 826 } 827 828 ASMC_DATAPORT_WRITE(sc, 4); 829 830 for (i = 0; i < 4; i++) { 831 if (asmc_wait(dev, 0x05)) 832 goto out; 833 key[i] = ASMC_DATAPORT_READ(sc); 834 } 835 836 /* get type */ 837 if (asmc_command(dev, 0x13)) 838 goto out; 839 840 for (i = 0; i < 4; i++) { 841 ASMC_DATAPORT_WRITE(sc, key[i]); 842 if (asmc_wait(dev, 0x04)) 843 goto out; 844 } 845 846 ASMC_DATAPORT_WRITE(sc, 6); 847 848 for (i = 0; i < 6; i++) { 849 if (asmc_wait(dev, 0x05)) 850 goto out; 851 type[i] = ASMC_DATAPORT_READ(sc); 852 } 853 854 error = 0; 855 out: 856 if (error) { 857 if (++try < 10) goto begin; 858 device_printf(dev,"%s for key %s failed %d times, giving up\n", 859 __func__, key, try); 860 mtx_unlock_spin(&sc->sc_mtx); 861 } 862 else { 863 char buf[1024]; 864 char buf2[8]; 865 mtx_unlock_spin(&sc->sc_mtx); 866 maxlen = type[0]; 867 type[0] = ' '; 868 type[5] = 0; 869 if (maxlen > sizeof(v)) { 870 device_printf(dev, 871 "WARNING: cropping maxlen from %d to %zu\n", 872 maxlen, sizeof(v)); 873 maxlen = sizeof(v); 874 } 875 for (i = 0; i < sizeof(v); i++) { 876 v[i] = 0; 877 } 878 asmc_key_read(dev, key, v, maxlen); 879 snprintf(buf, sizeof(buf), "key %d is: %s, type %s " 880 "(len %d), data", number, key, type, maxlen); 881 for (i = 0; i < maxlen; i++) { 882 snprintf(buf2, sizeof(buf), " %02x", v[i]); 883 strlcat(buf, buf2, sizeof(buf)); 884 } 885 strlcat(buf, " \n", sizeof(buf)); 886 device_printf(dev, "%s", buf); 887 } 888 889 return (error); 890 } 891 #endif 892 893 static int 894 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 895 { 896 int i, error = -1, try = 0; 897 struct asmc_softc *sc = device_get_softc(dev); 898 899 mtx_lock_spin(&sc->sc_mtx); 900 901 begin: 902 ASMC_DPRINTF(("cmd port: cmd write\n")); 903 if (asmc_command(dev, ASMC_CMDWRITE)) 904 goto out; 905 906 ASMC_DPRINTF(("data port: key\n")); 907 for (i = 0; i < 4; i++) { 908 ASMC_DATAPORT_WRITE(sc, key[i]); 909 if (asmc_wait(dev, 0x04)) 910 goto out; 911 } 912 ASMC_DPRINTF(("data port: length\n")); 913 ASMC_DATAPORT_WRITE(sc, len); 914 915 ASMC_DPRINTF(("data port: buffer\n")); 916 for (i = 0; i < len; i++) { 917 if (asmc_wait(dev, 0x04)) 918 goto out; 919 ASMC_DATAPORT_WRITE(sc, buf[i]); 920 } 921 922 error = 0; 923 out: 924 if (error) { 925 if (++try < 10) goto begin; 926 device_printf(dev,"%s for key %s failed %d times, giving up\n", 927 __func__, key, try); 928 } 929 930 mtx_unlock_spin(&sc->sc_mtx); 931 932 return (error); 933 934 } 935 936 /* 937 * Fan control functions. 938 */ 939 static int 940 asmc_fan_count(device_t dev) 941 { 942 uint8_t buf[1]; 943 944 if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) < 0) 945 return (-1); 946 947 return (buf[0]); 948 } 949 950 static int 951 asmc_fan_getvalue(device_t dev, const char *key, int fan) 952 { 953 int speed; 954 uint8_t buf[2]; 955 char fankey[5]; 956 957 snprintf(fankey, sizeof(fankey), key, fan); 958 if (asmc_key_read(dev, fankey, buf, sizeof buf) < 0) 959 return (-1); 960 speed = (buf[0] << 6) | (buf[1] >> 2); 961 962 return (speed); 963 } 964 965 static char* 966 asmc_fan_getstring(device_t dev, const char *key, int fan) 967 { 968 uint8_t buf[16]; 969 char fankey[5]; 970 char* desc; 971 972 snprintf(fankey, sizeof(fankey), key, fan); 973 if (asmc_key_read(dev, fankey, buf, sizeof buf) < 0) 974 return (NULL); 975 desc = buf+4; 976 977 return (desc); 978 } 979 980 static int 981 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 982 { 983 uint8_t buf[2]; 984 char fankey[5]; 985 986 speed *= 4; 987 988 buf[0] = speed>>8; 989 buf[1] = speed; 990 991 snprintf(fankey, sizeof(fankey), key, fan); 992 if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0) 993 return (-1); 994 995 return (0); 996 } 997 998 static int 999 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 1000 { 1001 device_t dev = (device_t) arg1; 1002 int fan = arg2; 1003 int error; 1004 int32_t v; 1005 1006 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 1007 error = sysctl_handle_int(oidp, &v, 0, req); 1008 1009 return (error); 1010 } 1011 1012 static int 1013 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 1014 { 1015 device_t dev = (device_t) arg1; 1016 int fan = arg2; 1017 int error = true; 1018 char* desc; 1019 1020 desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan); 1021 1022 if (desc != NULL) 1023 error = sysctl_handle_string(oidp, desc, 0, req); 1024 1025 return (error); 1026 } 1027 1028 static int 1029 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 1030 { 1031 device_t dev = (device_t) arg1; 1032 int fan = arg2; 1033 int error; 1034 int32_t v; 1035 1036 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 1037 error = sysctl_handle_int(oidp, &v, 0, req); 1038 1039 return (error); 1040 } 1041 1042 1043 static int 1044 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 1045 { 1046 device_t dev = (device_t) arg1; 1047 int fan = arg2; 1048 int error; 1049 int32_t v; 1050 1051 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 1052 error = sysctl_handle_int(oidp, &v, 0, req); 1053 1054 if (error == 0 && req->newptr != NULL) { 1055 unsigned int newspeed = v; 1056 asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 1057 } 1058 1059 return (error); 1060 } 1061 1062 static int 1063 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 1064 { 1065 device_t dev = (device_t) arg1; 1066 int fan = arg2; 1067 int error; 1068 int32_t v; 1069 1070 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 1071 error = sysctl_handle_int(oidp, &v, 0, req); 1072 1073 if (error == 0 && req->newptr != NULL) { 1074 unsigned int newspeed = v; 1075 asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 1076 } 1077 1078 return (error); 1079 } 1080 1081 static int 1082 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 1083 { 1084 device_t dev = (device_t) arg1; 1085 int fan = arg2; 1086 int error; 1087 int32_t v; 1088 1089 v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 1090 error = sysctl_handle_int(oidp, &v, 0, req); 1091 1092 if (error == 0 && req->newptr != NULL) { 1093 unsigned int newspeed = v; 1094 asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 1095 } 1096 1097 return (error); 1098 } 1099 1100 /* 1101 * Temperature functions. 1102 */ 1103 static int 1104 asmc_temp_getvalue(device_t dev, const char *key) 1105 { 1106 uint8_t buf[2]; 1107 1108 /* 1109 * Check for invalid temperatures. 1110 */ 1111 if (asmc_key_read(dev, key, buf, sizeof buf) < 0) 1112 return (-1); 1113 1114 return (buf[0]); 1115 } 1116 1117 static int 1118 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 1119 { 1120 device_t dev = (device_t) arg1; 1121 struct asmc_softc *sc = device_get_softc(dev); 1122 int error, val; 1123 1124 val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 1125 error = sysctl_handle_int(oidp, &val, 0, req); 1126 1127 return (error); 1128 } 1129 1130 /* 1131 * Sudden Motion Sensor functions. 1132 */ 1133 static int 1134 asmc_sms_read(device_t dev, const char *key, int16_t *val) 1135 { 1136 uint8_t buf[2]; 1137 int error; 1138 1139 /* no need to do locking here as asmc_key_read() already does it */ 1140 switch (key[3]) { 1141 case 'X': 1142 case 'Y': 1143 case 'Z': 1144 error = asmc_key_read(dev, key, buf, sizeof buf); 1145 break; 1146 default: 1147 device_printf(dev, "%s called with invalid argument %s\n", 1148 __func__, key); 1149 error = 1; 1150 goto out; 1151 } 1152 *val = ((int16_t)buf[0] << 8) | buf[1]; 1153 out: 1154 return (error); 1155 } 1156 1157 static void 1158 asmc_sms_calibrate(device_t dev) 1159 { 1160 struct asmc_softc *sc = device_get_softc(dev); 1161 1162 asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 1163 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 1164 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 1165 } 1166 1167 static int 1168 asmc_sms_intrfast(void *arg) 1169 { 1170 uint8_t type; 1171 device_t dev = (device_t) arg; 1172 struct asmc_softc *sc = device_get_softc(dev); 1173 if (!sc->sc_sms_intr_works) 1174 return (FILTER_HANDLED); 1175 1176 mtx_lock_spin(&sc->sc_mtx); 1177 type = ASMC_INTPORT_READ(sc); 1178 mtx_unlock_spin(&sc->sc_mtx); 1179 1180 sc->sc_sms_intrtype = type; 1181 asmc_sms_printintr(dev, type); 1182 1183 #ifdef INTR_FILTER 1184 return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED); 1185 #else 1186 taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 1187 #endif 1188 return (FILTER_HANDLED); 1189 } 1190 1191 #ifdef INTR_FILTER 1192 static void 1193 asmc_sms_handler(void *arg) 1194 { 1195 struct asmc_softc *sc = device_get_softc(arg); 1196 1197 asmc_sms_task(sc, 0); 1198 } 1199 #endif 1200 1201 1202 static void 1203 asmc_sms_printintr(device_t dev, uint8_t type) 1204 { 1205 1206 switch (type) { 1207 case ASMC_SMS_INTFF: 1208 device_printf(dev, "WARNING: possible free fall!\n"); 1209 break; 1210 case ASMC_SMS_INTHA: 1211 device_printf(dev, "WARNING: high acceleration detected!\n"); 1212 break; 1213 case ASMC_SMS_INTSH: 1214 device_printf(dev, "WARNING: possible shock!\n"); 1215 break; 1216 default: 1217 device_printf(dev, "%s unknown interrupt\n", __func__); 1218 } 1219 } 1220 1221 static void 1222 asmc_sms_task(void *arg, int pending) 1223 { 1224 struct asmc_softc *sc = (struct asmc_softc *)arg; 1225 char notify[16]; 1226 int type; 1227 1228 switch (sc->sc_sms_intrtype) { 1229 case ASMC_SMS_INTFF: 1230 type = 2; 1231 break; 1232 case ASMC_SMS_INTHA: 1233 type = 1; 1234 break; 1235 case ASMC_SMS_INTSH: 1236 type = 0; 1237 break; 1238 default: 1239 type = 255; 1240 } 1241 1242 snprintf(notify, sizeof(notify), " notify=0x%x", type); 1243 devctl_notify("ACPI", "asmc", "SMS", notify); 1244 } 1245 1246 static int 1247 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 1248 { 1249 device_t dev = (device_t) arg1; 1250 int error; 1251 int16_t val; 1252 int32_t v; 1253 1254 asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 1255 v = (int32_t) val; 1256 error = sysctl_handle_int(oidp, &v, 0, req); 1257 1258 return (error); 1259 } 1260 1261 static int 1262 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 1263 { 1264 device_t dev = (device_t) arg1; 1265 int error; 1266 int16_t val; 1267 int32_t v; 1268 1269 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 1270 v = (int32_t) val; 1271 error = sysctl_handle_int(oidp, &v, 0, req); 1272 1273 return (error); 1274 } 1275 1276 static int 1277 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 1278 { 1279 device_t dev = (device_t) arg1; 1280 int error; 1281 int16_t val; 1282 int32_t v; 1283 1284 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 1285 v = (int32_t) val; 1286 error = sysctl_handle_int(oidp, &v, 0, req); 1287 1288 return (error); 1289 } 1290 1291 static int 1292 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 1293 { 1294 device_t dev = (device_t) arg1; 1295 uint8_t buf[6]; 1296 int error; 1297 int32_t v; 1298 1299 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); 1300 v = buf[2]; 1301 error = sysctl_handle_int(oidp, &v, 0, req); 1302 1303 return (error); 1304 } 1305 1306 static int 1307 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 1308 { 1309 device_t dev = (device_t) arg1; 1310 uint8_t buf[6]; 1311 int error; 1312 int32_t v; 1313 1314 asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf); 1315 v = buf[2]; 1316 error = sysctl_handle_int(oidp, &v, 0, req); 1317 1318 return (error); 1319 } 1320 1321 static int 1322 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 1323 { 1324 device_t dev = (device_t) arg1; 1325 uint8_t buf[2]; 1326 int error; 1327 static unsigned int level; 1328 int v; 1329 1330 v = level; 1331 error = sysctl_handle_int(oidp, &v, 0, req); 1332 1333 if (error == 0 && req->newptr != NULL) { 1334 if (v < 0 || v > 255) 1335 return (EINVAL); 1336 level = v; 1337 buf[0] = level; 1338 buf[1] = 0x00; 1339 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 1340 } 1341 return (error); 1342 } 1343