asmc.c revision 177979
1173426Srpaulo/*- 2177972Srpaulo * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org> 3173426Srpaulo * All rights reserved. 4173426Srpaulo * 5173426Srpaulo * Redistribution and use in source and binary forms, with or without 6173426Srpaulo * modification, are permitted provided that the following conditions 7173426Srpaulo * are met: 8173426Srpaulo * 1. Redistributions of source code must retain the above copyright 9173426Srpaulo * notice, this list of conditions and the following disclaimer. 10173426Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11173426Srpaulo * notice, this list of conditions and the following disclaimer in the 12173426Srpaulo * documentation and/or other materials provided with the distribution. 13173426Srpaulo * 14173426Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15173426Srpaulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16173426Srpaulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17173426Srpaulo * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18173426Srpaulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19173426Srpaulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20173426Srpaulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21173426Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22173426Srpaulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23173426Srpaulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24173426Srpaulo * POSSIBILITY OF SUCH DAMAGE. 25173426Srpaulo * 26173426Srpaulo */ 27173426Srpaulo 28173426Srpaulo/* 29173426Srpaulo * Driver for Apple's System Management Console (SMC). 30173426Srpaulo * SMC can be found on the MacBook, MacBook Pro and Mac Mini. 31173426Srpaulo * 32173426Srpaulo * Inspired by the Linux applesmc driver. 33173426Srpaulo */ 34173426Srpaulo 35173426Srpaulo#include <sys/cdefs.h> 36173426Srpaulo__FBSDID("$FreeBSD: head/sys/dev/asmc/asmc.c 177979 2008-04-07 12:58:43Z rpaulo $"); 37173426Srpaulo 38177941Sjhb#include "opt_intr_filter.h" 39177941Sjhb 40173426Srpaulo#include <sys/param.h> 41173426Srpaulo#include <sys/bus.h> 42173426Srpaulo#include <sys/conf.h> 43173426Srpaulo#include <sys/kernel.h> 44173426Srpaulo#include <sys/lock.h> 45173426Srpaulo#include <sys/malloc.h> 46173426Srpaulo#include <sys/module.h> 47173426Srpaulo#include <sys/mutex.h> 48173426Srpaulo#include <sys/sysctl.h> 49173426Srpaulo#include <sys/systm.h> 50173426Srpaulo#include <sys/taskqueue.h> 51173426Srpaulo#include <sys/rman.h> 52173426Srpaulo#include <machine/resource.h> 53177972Srpaulo#include <contrib/dev/acpica/acpi.h> 54177972Srpaulo#include <dev/acpica/acpivar.h> 55173426Srpaulo#include <dev/asmc/asmcvar.h> 56173426Srpaulo 57173426Srpaulo/* 58173426Srpaulo * Device interface. 59173426Srpaulo */ 60173426Srpaulostatic int asmc_probe(device_t dev); 61173426Srpaulostatic int asmc_attach(device_t dev); 62173426Srpaulostatic int asmc_detach(device_t dev); 63173426Srpaulo 64173426Srpaulo/* 65173426Srpaulo * SMC functions. 66173426Srpaulo */ 67173426Srpaulostatic int asmc_init(device_t dev); 68173426Srpaulostatic int asmc_wait(device_t dev, uint8_t val); 69173426Srpaulostatic int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 70173426Srpaulo uint8_t len); 71173426Srpaulostatic int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 72173426Srpaulo uint8_t); 73173426Srpaulostatic int asmc_fan_count(device_t dev); 74173426Srpaulostatic int asmc_fan_getvalue(device_t dev, const char *key, int fan); 75173426Srpaulostatic int asmc_temp_getvalue(device_t dev, const char *key); 76173426Srpaulostatic int asmc_sms_read(device_t, const char *key, int16_t *val); 77173426Srpaulostatic void asmc_sms_calibrate(device_t dev); 78173426Srpaulostatic int asmc_sms_intrfast(void *arg); 79173426Srpaulo#ifdef INTR_FILTER 80173426Srpaulostatic void asmc_sms_handler(void *arg); 81173426Srpaulo#endif 82173426Srpaulostatic void asmc_sms_printintr(device_t dev, uint8_t); 83173426Srpaulostatic void asmc_sms_task(void *arg, int pending); 84173426Srpaulo 85173426Srpaulo/* 86173426Srpaulo * Model functions. 87173426Srpaulo */ 88173426Srpaulostatic int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 89173426Srpaulostatic int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 90173426Srpaulostatic int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 91173426Srpaulostatic int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 92173426Srpaulostatic int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 93173426Srpaulostatic int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 94173426Srpaulostatic int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 95173426Srpaulostatic int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 96173426Srpaulostatic int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 97173426Srpaulostatic int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 98173426Srpaulostatic int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 99173426Srpaulo 100173426Srpaulostruct asmc_model { 101173426Srpaulo const char *smc_model; /* smbios.system.product env var. */ 102173426Srpaulo const char *smc_desc; /* driver description */ 103173426Srpaulo 104173426Srpaulo /* Helper functions */ 105173426Srpaulo int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); 106173426Srpaulo int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); 107173426Srpaulo int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); 108173426Srpaulo int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); 109173426Srpaulo int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); 110173426Srpaulo int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); 111173426Srpaulo int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); 112173426Srpaulo int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); 113173426Srpaulo int (*smc_light_left)(SYSCTL_HANDLER_ARGS); 114173426Srpaulo int (*smc_light_right)(SYSCTL_HANDLER_ARGS); 115173426Srpaulo 116173426Srpaulo const char *smc_temps[8]; 117173426Srpaulo const char *smc_tempnames[8]; 118173426Srpaulo const char *smc_tempdescs[8]; 119173426Srpaulo}; 120173426Srpaulo 121173426Srpaulostatic struct asmc_model *asmc_match(device_t dev); 122173426Srpaulo 123173426Srpaulo#define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ 124173426Srpaulo asmc_mb_sysctl_sms_z 125173426Srpaulo 126173426Srpaulo#define ASMC_FAN_FUNCS asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ 127173426Srpaulo asmc_mb_sysctl_fanminspeed, \ 128173426Srpaulo asmc_mb_sysctl_fanmaxspeed, \ 129173426Srpaulo asmc_mb_sysctl_fantargetspeed 130173426Srpaulo#define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ 131173426Srpaulo asmc_mbp_sysctl_light_right 132173426Srpaulo 133173426Srpaulostruct asmc_model asmc_models[] = { 134173426Srpaulo { 135173426Srpaulo "MacBook1,1", "Apple SMC MacBook Core Duo", 136173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, 137173426Srpaulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 138173426Srpaulo }, 139173426Srpaulo 140173426Srpaulo { 141173426Srpaulo "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 142173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, 143173426Srpaulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 144173426Srpaulo }, 145173426Srpaulo 146173426Srpaulo { 147173426Srpaulo "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 148173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 149173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 150173426Srpaulo }, 151173426Srpaulo 152173426Srpaulo { 153173426Srpaulo "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 154173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 155173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 156173426Srpaulo }, 157173426Srpaulo 158173426Srpaulo { 159173426Srpaulo "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 160173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 161173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 162173426Srpaulo }, 163173426Srpaulo 164173426Srpaulo { 165173426Srpaulo "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 166173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 167173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 168173426Srpaulo }, 169173426Srpaulo 170173426Srpaulo { 171173426Srpaulo "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 172173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 173173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 174173426Srpaulo }, 175173426Srpaulo 176173426Srpaulo { 177173426Srpaulo "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 178173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 179173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 180173426Srpaulo }, 181173426Srpaulo 182173426Srpaulo /* The Mac Mini has no SMS */ 183173426Srpaulo { 184173426Srpaulo "Macmini1,1", "Apple SMC Mac Mini", 185173426Srpaulo NULL, NULL, NULL, 186173851Srpaulo ASMC_FAN_FUNCS, 187173426Srpaulo NULL, NULL, 188173426Srpaulo ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 189173426Srpaulo }, 190173426Srpaulo 191173426Srpaulo { NULL, NULL } 192173426Srpaulo}; 193173426Srpaulo 194173426Srpaulo#undef ASMC_SMS_FUNCS 195173426Srpaulo#undef ASMC_FAN_FUNCS 196173426Srpaulo#undef ASMC_LIGHT_FUNCS 197173426Srpaulo 198173426Srpaulo/* 199173426Srpaulo * Driver methods. 200173426Srpaulo */ 201173426Srpaulostatic device_method_t asmc_methods[] = { 202173426Srpaulo DEVMETHOD(device_probe, asmc_probe), 203173426Srpaulo DEVMETHOD(device_attach, asmc_attach), 204173426Srpaulo DEVMETHOD(device_detach, asmc_detach), 205173426Srpaulo 206173426Srpaulo { 0, 0 } 207173426Srpaulo}; 208173426Srpaulo 209173426Srpaulostatic driver_t asmc_driver = { 210173426Srpaulo "asmc", 211173426Srpaulo asmc_methods, 212173426Srpaulo sizeof(struct asmc_softc) 213173426Srpaulo}; 214173426Srpaulo 215177972Srpaulo/* 216177972Srpaulo * Debugging 217177972Srpaulo */ 218177972Srpaulo#define _COMPONENT ACPI_OEM 219177972SrpauloACPI_MODULE_NAME("ASMC") 220177972Srpaulo#ifdef DEBUG 221177972Srpaulo#define ASMC_DPRINTF(str) device_printf(dev, str) 222177977Srpaulo#else 223177977Srpaulo#define ASMC_DPRINTF(str) 224177972Srpaulo#endif 225177972Srpaulo 226177972Srpaulostatic char *asmc_ids[] = { "APP0001", NULL }; 227177972Srpaulo 228173426Srpaulostatic devclass_t asmc_devclass; 229173426Srpaulo 230177972SrpauloDRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 231177972SrpauloMODULE_DEPEND(asmc, acpi, 1, 1, 1); 232173426Srpaulo 233173426Srpaulostatic struct asmc_model * 234173426Srpauloasmc_match(device_t dev) 235173426Srpaulo{ 236173426Srpaulo int i; 237173426Srpaulo char *model; 238173426Srpaulo 239173426Srpaulo model = getenv("smbios.system.product"); 240173426Srpaulo for (i = 0; asmc_models[i].smc_model; i++) { 241173426Srpaulo if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 242173426Srpaulo freeenv(model); 243173426Srpaulo return (&asmc_models[i]); 244173426Srpaulo } 245173426Srpaulo } 246173426Srpaulo freeenv(model); 247173426Srpaulo 248173426Srpaulo return (NULL); 249173426Srpaulo} 250173426Srpaulo 251173426Srpaulostatic int 252173426Srpauloasmc_probe(device_t dev) 253173426Srpaulo{ 254173426Srpaulo struct asmc_model *model; 255173426Srpaulo 256177972Srpaulo if (acpi_disabled("asmc")) 257173426Srpaulo return (ENXIO); 258177972Srpaulo if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL) 259177972Srpaulo return (ENXIO); 260177972Srpaulo 261173426Srpaulo model = asmc_match(dev); 262177972Srpaulo if (!model) { 263177972Srpaulo device_printf(dev, "model not recognized\n"); 264173426Srpaulo return (ENXIO); 265177972Srpaulo } 266173426Srpaulo device_set_desc(dev, model->smc_desc); 267173426Srpaulo 268173426Srpaulo return (BUS_PROBE_DEFAULT); 269173426Srpaulo} 270173426Srpaulo 271173426Srpaulostatic int 272173426Srpauloasmc_attach(device_t dev) 273173426Srpaulo{ 274173426Srpaulo int i, j; 275173426Srpaulo int ret; 276173426Srpaulo char name[2]; 277173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 278173426Srpaulo struct sysctl_ctx_list *sysctlctx; 279173426Srpaulo struct sysctl_oid *sysctlnode; 280173426Srpaulo struct asmc_model *model; 281173426Srpaulo 282177972Srpaulo sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 283177972Srpaulo &sc->sc_rid_port, RF_ACTIVE); 284177972Srpaulo if (sc->sc_ioport == NULL) { 285177972Srpaulo device_printf(dev, "unable to allocate IO port\n"); 286177972Srpaulo return (ENOMEM); 287177972Srpaulo } 288177972Srpaulo 289173426Srpaulo sysctlctx = device_get_sysctl_ctx(dev); 290173426Srpaulo sysctlnode = device_get_sysctl_tree(dev); 291173426Srpaulo 292173426Srpaulo model = asmc_match(dev); 293173426Srpaulo 294173426Srpaulo mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 295173426Srpaulo 296173426Srpaulo sc->sc_model = model; 297173426Srpaulo asmc_init(dev); 298173426Srpaulo 299173426Srpaulo /* 300173426Srpaulo * dev.asmc.n.fan.* tree. 301173426Srpaulo */ 302173426Srpaulo sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 303173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 304173426Srpaulo CTLFLAG_RD, 0, "Fan Root Tree"); 305173426Srpaulo 306173426Srpaulo for (i = 1; i <= sc->sc_nfan; i++) { 307173426Srpaulo j = i - 1; 308173426Srpaulo name[0] = '0' + j; 309173426Srpaulo name[1] = 0; 310173426Srpaulo sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 311173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 312173426Srpaulo OID_AUTO, name, CTLFLAG_RD, 0, 313173426Srpaulo "Fan Subtree"); 314173426Srpaulo 315173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 316173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 317173426Srpaulo OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD, 318173426Srpaulo dev, j, model->smc_fan_speed, "I", 319173426Srpaulo "Fan speed in RPM"); 320173426Srpaulo 321173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 322173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 323173426Srpaulo OID_AUTO, "safespeed", 324173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 325173426Srpaulo dev, j, model->smc_fan_safespeed, "I", 326173426Srpaulo "Fan safe speed in RPM"); 327173426Srpaulo 328173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 329173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 330173426Srpaulo OID_AUTO, "minspeed", 331173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 332173426Srpaulo dev, j, model->smc_fan_minspeed, "I", 333173426Srpaulo "Fan minimum speed in RPM"); 334173426Srpaulo 335173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 336173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 337173426Srpaulo OID_AUTO, "maxspeed", 338173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 339173426Srpaulo dev, j, model->smc_fan_maxspeed, "I", 340173426Srpaulo "Fan maximum speed in RPM"); 341173426Srpaulo 342173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 343173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 344173426Srpaulo OID_AUTO, "targetspeed", 345173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 346173426Srpaulo dev, j, model->smc_fan_targetspeed, "I", 347173426Srpaulo "Fan target speed in RPM"); 348173426Srpaulo } 349173426Srpaulo 350173426Srpaulo /* 351173426Srpaulo * dev.asmc.n.temp tree. 352173426Srpaulo */ 353173426Srpaulo sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 354173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 355173426Srpaulo CTLFLAG_RD, 0, "Temperature sensors"); 356173426Srpaulo 357173426Srpaulo for (i = 0; model->smc_temps[i]; i++) { 358173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 359173426Srpaulo SYSCTL_CHILDREN(sc->sc_temp_tree), 360173426Srpaulo OID_AUTO, model->smc_tempnames[i], 361173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 362173426Srpaulo dev, i, asmc_temp_sysctl, "I", 363173426Srpaulo model->smc_tempdescs[i]); 364173426Srpaulo } 365173426Srpaulo 366173426Srpaulo if (model->smc_sms_x == NULL) 367173426Srpaulo goto nosms; 368173426Srpaulo 369173426Srpaulo /* 370173426Srpaulo * dev.asmc.n.sms tree. 371173426Srpaulo */ 372173426Srpaulo sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 373173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 374173426Srpaulo CTLFLAG_RD, 0, "Sudden Motion Sensor"); 375173426Srpaulo 376173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 377173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 378173426Srpaulo OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD, 379173426Srpaulo dev, 0, model->smc_sms_x, "I", 380173426Srpaulo "Sudden Motion Sensor X value"); 381173426Srpaulo 382173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 383173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 384173426Srpaulo OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD, 385173426Srpaulo dev, 0, model->smc_sms_y, "I", 386173426Srpaulo "Sudden Motion Sensor Y value"); 387173426Srpaulo 388173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 389173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 390173426Srpaulo OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD, 391173426Srpaulo dev, 0, model->smc_sms_z, "I", 392173426Srpaulo "Sudden Motion Sensor Z value"); 393173426Srpaulo 394173426Srpaulo /* 395173426Srpaulo * dev.asmc.n.light 396173426Srpaulo */ 397173426Srpaulo if (model->smc_light_left) { 398173426Srpaulo sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 399173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 400173426Srpaulo CTLFLAG_RD, 0, "Keyboard backlight sensors"); 401173426Srpaulo 402173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 403173426Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 404173426Srpaulo OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RW, 405173426Srpaulo dev, 0, model->smc_light_left, "I", 406173426Srpaulo "Keyboard backlight left sensor"); 407173426Srpaulo 408173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 409173426Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 410173426Srpaulo OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RW, 411173426Srpaulo dev, 0, model->smc_light_right, "I", 412173426Srpaulo "Keyboard backlight right sensor"); 413173426Srpaulo } 414173426Srpaulo 415173426Srpaulo /* 416173426Srpaulo * Need a taskqueue to send devctl_notify() events 417173426Srpaulo * when the SMS interrupt us. 418173426Srpaulo * 419173426Srpaulo * PI_REALTIME is used due to the sensitivity of the 420173426Srpaulo * interrupt. An interrupt from the SMS means that the 421173426Srpaulo * disk heads should be turned off as quickly as possible. 422173426Srpaulo * 423173426Srpaulo * We only need to do this for the non INTR_FILTER case. 424173426Srpaulo */ 425173426Srpaulo sc->sc_sms_tq = NULL; 426173426Srpaulo#ifndef INTR_FILTER 427173426Srpaulo TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 428173426Srpaulo sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 429173426Srpaulo taskqueue_thread_enqueue, &sc->sc_sms_tq); 430173426Srpaulo taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 431173426Srpaulo device_get_nameunit(dev)); 432173426Srpaulo#endif 433173426Srpaulo /* 434173426Srpaulo * Allocate an IRQ for the SMS. 435173426Srpaulo */ 436177972Srpaulo sc->sc_rid_irq = 0; 437177972Srpaulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 438177972Srpaulo &sc->sc_rid_irq, RF_ACTIVE); 439177972Srpaulo if (sc->sc_irq == NULL) { 440173426Srpaulo device_printf(dev, "unable to allocate IRQ resource\n"); 441173426Srpaulo ret = ENXIO; 442173426Srpaulo goto err2; 443173426Srpaulo } 444173426Srpaulo 445177972Srpaulo ret = bus_setup_intr(dev, sc->sc_irq, 446173426Srpaulo INTR_TYPE_MISC | INTR_MPSAFE, 447173426Srpaulo#ifdef INTR_FILTER 448173426Srpaulo asmc_sms_intrfast, asmc_sms_handler, 449173426Srpaulo#else 450173426Srpaulo asmc_sms_intrfast, NULL, 451173426Srpaulo#endif 452173426Srpaulo dev, &sc->sc_cookie); 453173426Srpaulo 454173426Srpaulo if (ret) { 455173426Srpaulo device_printf(dev, "unable to setup SMS IRQ\n"); 456173426Srpaulo goto err1; 457173426Srpaulo } 458173426Srpaulonosms: 459173426Srpaulo return (0); 460173426Srpauloerr1: 461177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 462173426Srpauloerr2: 463177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 464177972Srpaulo sc->sc_ioport); 465173426Srpaulo mtx_destroy(&sc->sc_mtx); 466173426Srpaulo if (sc->sc_sms_tq) 467173426Srpaulo taskqueue_free(sc->sc_sms_tq); 468173426Srpaulo 469173426Srpaulo return (ret); 470173426Srpaulo} 471173426Srpaulo 472173426Srpaulostatic int 473173426Srpauloasmc_detach(device_t dev) 474173426Srpaulo{ 475173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 476173426Srpaulo 477173426Srpaulo if (sc->sc_sms_tq) { 478173426Srpaulo taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 479173426Srpaulo taskqueue_free(sc->sc_sms_tq); 480173426Srpaulo } 481173426Srpaulo if (sc->sc_cookie) 482177972Srpaulo bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 483177972Srpaulo if (sc->sc_irq) 484177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 485177972Srpaulo sc->sc_irq); 486177972Srpaulo if (sc->sc_ioport) 487177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 488177972Srpaulo sc->sc_ioport); 489173426Srpaulo mtx_destroy(&sc->sc_mtx); 490173426Srpaulo 491173426Srpaulo return (0); 492173426Srpaulo} 493173426Srpaulo 494173426Srpaulostatic int 495173426Srpauloasmc_init(device_t dev) 496173426Srpaulo{ 497173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 498173426Srpaulo int i, error = 1; 499173426Srpaulo uint8_t buf[4]; 500173426Srpaulo 501173426Srpaulo if (sc->sc_model->smc_sms_x == NULL) 502173426Srpaulo goto nosms; 503173426Srpaulo 504173426Srpaulo /* 505173426Srpaulo * We are ready to recieve interrupts from the SMS. 506173426Srpaulo */ 507173426Srpaulo buf[0] = 0x01; 508177972Srpaulo ASMC_DPRINTF(("intok key\n")); 509173426Srpaulo asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 510173426Srpaulo DELAY(50); 511173426Srpaulo 512173426Srpaulo /* 513173426Srpaulo * Initiate the polling intervals. 514173426Srpaulo */ 515173426Srpaulo buf[0] = 20; /* msecs */ 516177972Srpaulo ASMC_DPRINTF(("low int key\n")); 517173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 518173426Srpaulo DELAY(200); 519173426Srpaulo 520173426Srpaulo buf[0] = 20; /* msecs */ 521177972Srpaulo ASMC_DPRINTF(("high int key\n")); 522173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 523173426Srpaulo DELAY(200); 524173426Srpaulo 525173426Srpaulo buf[0] = 0x00; 526173426Srpaulo buf[1] = 0x60; 527177972Srpaulo ASMC_DPRINTF(("sms low key\n")); 528173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 529173426Srpaulo DELAY(200); 530173426Srpaulo 531173426Srpaulo buf[0] = 0x01; 532173426Srpaulo buf[1] = 0xc0; 533177972Srpaulo ASMC_DPRINTF(("sms high key\n")); 534173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 535173426Srpaulo DELAY(200); 536173426Srpaulo 537173426Srpaulo /* 538173426Srpaulo * I'm not sure what this key does, but it seems to be 539173426Srpaulo * required. 540173426Srpaulo */ 541173426Srpaulo buf[0] = 0x01; 542177972Srpaulo ASMC_DPRINTF(("sms flag key\n")); 543173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 544177979Srpaulo DELAY(100); 545173426Srpaulo 546173426Srpaulo /* 547173426Srpaulo * Wait up to 5 seconds for SMS initialization. 548173426Srpaulo */ 549173426Srpaulo for (i = 0; i < 10000; i++) { 550173426Srpaulo if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 551173426Srpaulo (buf[0] != 0x00 || buf[1] != 0x00)) { 552173426Srpaulo error = 0; 553177977Srpaulo goto out; 554173426Srpaulo } 555173426Srpaulo buf[0] = ASMC_SMS_INIT1; 556173426Srpaulo buf[1] = ASMC_SMS_INIT2; 557177972Srpaulo ASMC_DPRINTF(("sms key\n")); 558173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 559173426Srpaulo DELAY(50); 560173426Srpaulo } 561177977Srpaulo device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 562173426Srpaulo 563177977Srpauloout: 564173426Srpaulo asmc_sms_calibrate(dev); 565173426Srpaulonosms: 566173426Srpaulo sc->sc_nfan = asmc_fan_count(dev); 567173426Srpaulo if (sc->sc_nfan > ASMC_MAXFANS) { 568173426Srpaulo device_printf(dev, "more than %d fans were detected. Please " 569173426Srpaulo "report this.\n", ASMC_MAXFANS); 570173426Srpaulo sc->sc_nfan = ASMC_MAXFANS; 571173426Srpaulo } 572173426Srpaulo 573173426Srpaulo if (bootverbose) { 574173426Srpaulo /* 575173426Srpaulo * XXX: The number of keys is a 32 bit buffer, but 576173426Srpaulo * right now Apple only uses the last 8 bit. 577173426Srpaulo */ 578173426Srpaulo asmc_key_read(dev, ASMC_NKEYS, buf, 4); 579173426Srpaulo device_printf(dev, "number of keys: %d\n", buf[3]); 580173426Srpaulo } 581173426Srpaulo 582173426Srpaulo return (error); 583173426Srpaulo} 584173426Srpaulo 585173426Srpaulo/* 586173426Srpaulo * We need to make sure that the SMC acks the byte sent. 587173426Srpaulo * Just wait up to 100 ms. 588173426Srpaulo */ 589173426Srpaulostatic int 590173426Srpauloasmc_wait(device_t dev, uint8_t val) 591173426Srpaulo{ 592177972Srpaulo struct asmc_softc *sc = device_get_softc(dev); 593173426Srpaulo u_int i; 594173426Srpaulo 595173426Srpaulo val = val & ASMC_STATUS_MASK; 596173426Srpaulo 597173426Srpaulo for (i = 0; i < 1000; i++) { 598177972Srpaulo if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 599173426Srpaulo return (0); 600173426Srpaulo DELAY(10); 601173426Srpaulo } 602173426Srpaulo 603173426Srpaulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 604177972Srpaulo ASMC_CMDPORT_READ(sc)); 605173426Srpaulo 606173426Srpaulo return (1); 607173426Srpaulo} 608173426Srpaulo 609173426Srpaulostatic int 610173426Srpauloasmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 611173426Srpaulo{ 612173426Srpaulo int i, error = 1; 613173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 614173426Srpaulo 615173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 616173426Srpaulo 617177972Srpaulo ASMC_CMDPORT_WRITE(sc, ASMC_CMDREAD); 618173426Srpaulo if (asmc_wait(dev, 0x0c)) 619173426Srpaulo goto out; 620173426Srpaulo 621173426Srpaulo for (i = 0; i < 4; i++) { 622177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 623173426Srpaulo if (asmc_wait(dev, 0x04)) 624173426Srpaulo goto out; 625173426Srpaulo } 626173426Srpaulo 627177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 628173426Srpaulo 629173426Srpaulo for (i = 0; i < len; i++) { 630173426Srpaulo if (asmc_wait(dev, 0x05)) 631173426Srpaulo goto out; 632177972Srpaulo buf[i] = ASMC_DATAPORT_READ(sc); 633173426Srpaulo } 634173426Srpaulo 635173426Srpaulo error = 0; 636173426Srpauloout: 637173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 638173426Srpaulo 639173426Srpaulo return (error); 640173426Srpaulo} 641173426Srpaulo 642173426Srpaulostatic int 643173426Srpauloasmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 644173426Srpaulo{ 645173426Srpaulo int i, error = -1; 646173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 647173426Srpaulo 648173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 649173426Srpaulo 650177972Srpaulo ASMC_DPRINTF(("cmd port: cmd write\n")); 651177972Srpaulo ASMC_CMDPORT_WRITE(sc, ASMC_CMDWRITE); 652173426Srpaulo if (asmc_wait(dev, 0x0c)) 653173426Srpaulo goto out; 654173426Srpaulo 655177972Srpaulo ASMC_DPRINTF(("data port: key\n")); 656173426Srpaulo for (i = 0; i < 4; i++) { 657177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 658173426Srpaulo if (asmc_wait(dev, 0x04)) 659173426Srpaulo goto out; 660173426Srpaulo } 661177972Srpaulo ASMC_DPRINTF(("data port: length\n")); 662177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 663173426Srpaulo 664177972Srpaulo ASMC_DPRINTF(("data port: buffer\n")); 665173426Srpaulo for (i = 0; i < len; i++) { 666173426Srpaulo if (asmc_wait(dev, 0x04)) 667173426Srpaulo goto out; 668177972Srpaulo ASMC_DATAPORT_WRITE(sc, buf[i]); 669173426Srpaulo } 670173426Srpaulo 671173426Srpaulo error = 0; 672173426Srpauloout: 673173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 674173426Srpaulo 675173426Srpaulo return (error); 676173426Srpaulo 677173426Srpaulo} 678173426Srpaulo 679173426Srpaulo/* 680173426Srpaulo * Fan control functions. 681173426Srpaulo */ 682173426Srpaulostatic int 683173426Srpauloasmc_fan_count(device_t dev) 684173426Srpaulo{ 685173426Srpaulo uint8_t buf[1]; 686173426Srpaulo 687173426Srpaulo if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, 1) < 0) 688173426Srpaulo return (-1); 689173426Srpaulo 690173426Srpaulo return (buf[0]); 691173426Srpaulo} 692173426Srpaulo 693173426Srpaulostatic int 694173426Srpauloasmc_fan_getvalue(device_t dev, const char *key, int fan) 695173426Srpaulo{ 696173426Srpaulo int speed; 697173426Srpaulo uint8_t buf[2]; 698173426Srpaulo char fankey[5]; 699173426Srpaulo 700173426Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 701173426Srpaulo if (asmc_key_read(dev, fankey, buf, 2) < 0) 702173426Srpaulo return (-1); 703173426Srpaulo speed = (buf[0] << 6) | (buf[1] >> 2); 704173426Srpaulo 705173426Srpaulo return (speed); 706173426Srpaulo} 707173426Srpaulo 708173426Srpaulostatic int 709173426Srpauloasmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 710173426Srpaulo{ 711173426Srpaulo device_t dev = (device_t) arg1; 712173426Srpaulo int fan = arg2; 713173426Srpaulo int error; 714173426Srpaulo int32_t v; 715173426Srpaulo 716173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 717173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 718173426Srpaulo 719173426Srpaulo return (error); 720173426Srpaulo} 721173426Srpaulo 722173426Srpaulostatic int 723173426Srpauloasmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 724173426Srpaulo{ 725173426Srpaulo device_t dev = (device_t) arg1; 726173426Srpaulo int fan = arg2; 727173426Srpaulo int error; 728173426Srpaulo int32_t v; 729173426Srpaulo 730173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 731173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 732173426Srpaulo 733173426Srpaulo return (error); 734173426Srpaulo} 735173426Srpaulo 736173426Srpaulo 737173426Srpaulostatic int 738173426Srpauloasmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 739173426Srpaulo{ 740173426Srpaulo device_t dev = (device_t) arg1; 741173426Srpaulo int fan = arg2; 742173426Srpaulo int error; 743173426Srpaulo int32_t v; 744173426Srpaulo 745173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 746173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 747173426Srpaulo 748173426Srpaulo return (error); 749173426Srpaulo} 750173426Srpaulo 751173426Srpaulostatic int 752173426Srpauloasmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 753173426Srpaulo{ 754173426Srpaulo device_t dev = (device_t) arg1; 755173426Srpaulo int fan = arg2; 756173426Srpaulo int error; 757173426Srpaulo int32_t v; 758173426Srpaulo 759173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 760173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 761173426Srpaulo 762173426Srpaulo return (error); 763173426Srpaulo} 764173426Srpaulo 765173426Srpaulostatic int 766173426Srpauloasmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 767173426Srpaulo{ 768173426Srpaulo device_t dev = (device_t) arg1; 769173426Srpaulo int fan = arg2; 770173426Srpaulo int error; 771173426Srpaulo int32_t v; 772173426Srpaulo 773173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 774173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 775173426Srpaulo 776173426Srpaulo return (error); 777173426Srpaulo} 778173426Srpaulo 779173426Srpaulo/* 780173426Srpaulo * Temperature functions. 781173426Srpaulo */ 782173426Srpaulostatic int 783173426Srpauloasmc_temp_getvalue(device_t dev, const char *key) 784173426Srpaulo{ 785173426Srpaulo uint8_t buf[2]; 786173426Srpaulo 787173426Srpaulo /* 788173426Srpaulo * Check for invalid temperatures. 789173426Srpaulo */ 790173426Srpaulo if (asmc_key_read(dev, key, buf, 2) < 0) 791173426Srpaulo return (-1); 792173426Srpaulo 793173426Srpaulo return (buf[0]); 794173426Srpaulo} 795173426Srpaulo 796173426Srpaulostatic int 797173426Srpauloasmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 798173426Srpaulo{ 799173426Srpaulo device_t dev = (device_t) arg1; 800173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 801173426Srpaulo int error, val; 802173426Srpaulo 803173426Srpaulo val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 804173426Srpaulo error = sysctl_handle_int(oidp, &val, 0, req); 805173426Srpaulo 806173426Srpaulo return (error); 807173426Srpaulo} 808173426Srpaulo 809173426Srpaulo/* 810173426Srpaulo * Sudden Motion Sensor functions. 811173426Srpaulo */ 812173426Srpaulostatic int 813173426Srpauloasmc_sms_read(device_t dev, const char *key, int16_t *val) 814173426Srpaulo{ 815173426Srpaulo uint8_t buf[2]; 816173426Srpaulo int error; 817173426Srpaulo 818173426Srpaulo /* no need to do locking here as asmc_key_read() already does it */ 819173426Srpaulo switch (key[3]) { 820173426Srpaulo case 'X': 821173426Srpaulo case 'Y': 822173426Srpaulo case 'Z': 823173426Srpaulo error = asmc_key_read(dev, key, buf, 2); 824173426Srpaulo break; 825173426Srpaulo default: 826173426Srpaulo device_printf(dev, "%s called with invalid argument %s\n", 827173426Srpaulo __func__, key); 828173426Srpaulo error = 1; 829173426Srpaulo goto out; 830173426Srpaulo } 831173426Srpaulo *val = ((int16_t)buf[0] << 8) | buf[1]; 832173426Srpauloout: 833173426Srpaulo return (error); 834173426Srpaulo} 835173426Srpaulo 836173426Srpaulostatic void 837173426Srpauloasmc_sms_calibrate(device_t dev) 838173426Srpaulo{ 839173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 840173426Srpaulo 841173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 842173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 843173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 844173426Srpaulo} 845173426Srpaulo 846173426Srpaulostatic int 847173426Srpauloasmc_sms_intrfast(void *arg) 848173426Srpaulo{ 849173426Srpaulo uint8_t type; 850173426Srpaulo device_t dev = (device_t) arg; 851173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 852173426Srpaulo 853173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 854177972Srpaulo type = ASMC_INTPORT_READ(sc); 855173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 856173426Srpaulo 857173426Srpaulo sc->sc_sms_intrtype = type; 858173426Srpaulo asmc_sms_printintr(dev, type); 859173426Srpaulo 860173426Srpaulo#ifdef INTR_FILTER 861173426Srpaulo return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED); 862173426Srpaulo#else 863173426Srpaulo taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 864173426Srpaulo#endif 865173426Srpaulo return (FILTER_HANDLED); 866173426Srpaulo} 867173426Srpaulo 868173426Srpaulo#ifdef INTR_FILTER 869173426Srpaulostatic void 870173426Srpauloasmc_sms_handler(void *arg) 871173426Srpaulo{ 872173426Srpaulo struct asmc_softc *sc = device_get_softc(arg); 873173426Srpaulo 874173426Srpaulo asmc_sms_task(sc, 0); 875173426Srpaulo} 876173426Srpaulo#endif 877173426Srpaulo 878173426Srpaulo 879173426Srpaulostatic void 880173426Srpauloasmc_sms_printintr(device_t dev, uint8_t type) 881173426Srpaulo{ 882173426Srpaulo 883173426Srpaulo switch (type) { 884173426Srpaulo case ASMC_SMS_INTFF: 885173426Srpaulo device_printf(dev, "WARNING: possible free fall!\n"); 886173426Srpaulo break; 887173426Srpaulo case ASMC_SMS_INTHA: 888173426Srpaulo device_printf(dev, "WARNING: high acceleration detected!\n"); 889173426Srpaulo break; 890173426Srpaulo case ASMC_SMS_INTSH: 891173426Srpaulo device_printf(dev, "WARNING: possible shock!\n"); 892173426Srpaulo break; 893173426Srpaulo default: 894173426Srpaulo device_printf(dev, "%s unknown interrupt\n", __func__); 895173426Srpaulo } 896173426Srpaulo} 897173426Srpaulo 898173426Srpaulostatic void 899173426Srpauloasmc_sms_task(void *arg, int pending) 900173426Srpaulo{ 901173426Srpaulo struct asmc_softc *sc = (struct asmc_softc *)arg; 902173426Srpaulo char notify[16]; 903173426Srpaulo int type; 904173426Srpaulo 905173426Srpaulo switch (sc->sc_sms_intrtype) { 906173426Srpaulo case ASMC_SMS_INTFF: 907173426Srpaulo type = 2; 908173426Srpaulo break; 909173426Srpaulo case ASMC_SMS_INTHA: 910173426Srpaulo type = 1; 911173426Srpaulo break; 912173426Srpaulo case ASMC_SMS_INTSH: 913173426Srpaulo type = 0; 914173426Srpaulo break; 915173426Srpaulo default: 916173426Srpaulo type = 255; 917173426Srpaulo } 918173426Srpaulo 919173426Srpaulo snprintf(notify, sizeof(notify), " notify=0x%x", type); 920177972Srpaulo devctl_notify("ACPI", "asmc", "SMS", notify); 921173426Srpaulo} 922173426Srpaulo 923173426Srpaulostatic int 924173426Srpauloasmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 925173426Srpaulo{ 926173426Srpaulo device_t dev = (device_t) arg1; 927173426Srpaulo int error; 928173426Srpaulo int16_t val; 929173426Srpaulo int32_t v; 930173426Srpaulo 931173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 932173426Srpaulo v = (int32_t) val; 933173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 934173426Srpaulo 935173426Srpaulo return (error); 936173426Srpaulo} 937173426Srpaulo 938173426Srpaulostatic int 939173426Srpauloasmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 940173426Srpaulo{ 941173426Srpaulo device_t dev = (device_t) arg1; 942173426Srpaulo int error; 943173426Srpaulo int16_t val; 944173426Srpaulo int32_t v; 945173426Srpaulo 946173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 947173426Srpaulo v = (int32_t) val; 948173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 949173426Srpaulo 950173426Srpaulo return (error); 951173426Srpaulo} 952173426Srpaulo 953173426Srpaulostatic int 954173426Srpauloasmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 955173426Srpaulo{ 956173426Srpaulo device_t dev = (device_t) arg1; 957173426Srpaulo int error; 958173426Srpaulo int16_t val; 959173426Srpaulo int32_t v; 960173426Srpaulo 961173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 962173426Srpaulo v = (int32_t) val; 963173426Srpaulo error = sysctl_handle_int(oidp, &v, sizeof(v), req); 964173426Srpaulo 965173426Srpaulo return (error); 966173426Srpaulo} 967173426Srpaulo 968173426Srpaulostatic int 969173426Srpauloasmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 970173426Srpaulo{ 971173426Srpaulo device_t dev = (device_t) arg1; 972173426Srpaulo uint8_t buf[6]; 973173426Srpaulo int error; 974173426Srpaulo unsigned int level; 975173426Srpaulo int32_t v; 976173426Srpaulo 977173426Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, 6); 978173426Srpaulo v = buf[2]; 979173426Srpaulo error = sysctl_handle_int(oidp, &v, sizeof(v), req); 980173426Srpaulo if (error == 0 && req->newptr != NULL) { 981173426Srpaulo level = *(unsigned int *)req->newptr; 982173426Srpaulo if (level > 255) 983173426Srpaulo return (EINVAL); 984173426Srpaulo buf[0] = level; 985173426Srpaulo buf[1] = 0x00; 986173426Srpaulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2); 987173426Srpaulo } 988173426Srpaulo 989173426Srpaulo return (error); 990173426Srpaulo} 991173426Srpaulo 992173426Srpaulostatic int 993173426Srpauloasmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 994173426Srpaulo{ 995173426Srpaulo device_t dev = (device_t) arg1; 996173426Srpaulo uint8_t buf[6]; 997173426Srpaulo int error; 998173426Srpaulo unsigned int level; 999173426Srpaulo int32_t v; 1000173426Srpaulo 1001173426Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, 6); 1002173426Srpaulo v = buf[2]; 1003173426Srpaulo error = sysctl_handle_int(oidp, &v, sizeof(v), req); 1004173426Srpaulo if (error == 0 && req->newptr != NULL) { 1005173426Srpaulo level = *(unsigned int *)req->newptr; 1006173426Srpaulo if (level > 255) 1007173426Srpaulo return (EINVAL); 1008173426Srpaulo buf[0] = level; 1009173426Srpaulo buf[1] = 0x00; 1010173426Srpaulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2); 1011173426Srpaulo } 1012173426Srpaulo 1013173426Srpaulo return (error); 1014173426Srpaulo} 1015