asmc.c revision 298955
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 298955 2016-05-03 03:41:25Z pfg $"); 37173426Srpaulo 38173426Srpaulo#include <sys/param.h> 39173426Srpaulo#include <sys/bus.h> 40173426Srpaulo#include <sys/conf.h> 41173426Srpaulo#include <sys/kernel.h> 42173426Srpaulo#include <sys/lock.h> 43173426Srpaulo#include <sys/malloc.h> 44173426Srpaulo#include <sys/module.h> 45173426Srpaulo#include <sys/mutex.h> 46173426Srpaulo#include <sys/sysctl.h> 47173426Srpaulo#include <sys/systm.h> 48173426Srpaulo#include <sys/taskqueue.h> 49173426Srpaulo#include <sys/rman.h> 50178118Srpaulo 51173426Srpaulo#include <machine/resource.h> 52193530Sjkim 53193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 54193530Sjkim 55177972Srpaulo#include <dev/acpica/acpivar.h> 56173426Srpaulo#include <dev/asmc/asmcvar.h> 57173426Srpaulo 58178118Srpaulo#include "opt_intr_filter.h" 59178118Srpaulo 60173426Srpaulo/* 61173426Srpaulo * Device interface. 62173426Srpaulo */ 63173426Srpaulostatic int asmc_probe(device_t dev); 64173426Srpaulostatic int asmc_attach(device_t dev); 65173426Srpaulostatic int asmc_detach(device_t dev); 66298937Sadrianstatic int asmc_resume(device_t dev); 67173426Srpaulo 68173426Srpaulo/* 69173426Srpaulo * SMC functions. 70173426Srpaulo */ 71173426Srpaulostatic int asmc_init(device_t dev); 72195046Srpaulostatic int asmc_command(device_t dev, uint8_t command); 73173426Srpaulostatic int asmc_wait(device_t dev, uint8_t val); 74195046Srpaulostatic int asmc_wait_ack(device_t dev, uint8_t val, int amount); 75173426Srpaulostatic int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 76173426Srpaulo uint8_t len); 77173426Srpaulostatic int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 78173426Srpaulo uint8_t); 79173426Srpaulostatic int asmc_fan_count(device_t dev); 80173426Srpaulostatic int asmc_fan_getvalue(device_t dev, const char *key, int fan); 81271975Srpaulostatic int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed); 82173426Srpaulostatic int asmc_temp_getvalue(device_t dev, const char *key); 83173426Srpaulostatic int asmc_sms_read(device_t, const char *key, int16_t *val); 84173426Srpaulostatic void asmc_sms_calibrate(device_t dev); 85173426Srpaulostatic int asmc_sms_intrfast(void *arg); 86173426Srpaulo#ifdef INTR_FILTER 87173426Srpaulostatic void asmc_sms_handler(void *arg); 88173426Srpaulo#endif 89173426Srpaulostatic void asmc_sms_printintr(device_t dev, uint8_t); 90173426Srpaulostatic void asmc_sms_task(void *arg, int pending); 91197190Srpaulo#ifdef DEBUG 92197190Srpaulovoid asmc_dumpall(device_t); 93197190Srpaulostatic int asmc_key_dump(device_t, int); 94197190Srpaulo#endif 95173426Srpaulo 96173426Srpaulo/* 97173426Srpaulo * Model functions. 98173426Srpaulo */ 99271975Srpaulostatic int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS); 100173426Srpaulostatic int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 101173426Srpaulostatic int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 102173426Srpaulostatic int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 103173426Srpaulostatic int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 104173426Srpaulostatic int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 105173426Srpaulostatic int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 106173426Srpaulostatic int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 107173426Srpaulostatic int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 108173426Srpaulostatic int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 109173426Srpaulostatic int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 110173426Srpaulostatic int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 111195046Srpaulostatic int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); 112173426Srpaulo 113173426Srpaulostruct asmc_model { 114173426Srpaulo const char *smc_model; /* smbios.system.product env var. */ 115173426Srpaulo const char *smc_desc; /* driver description */ 116173426Srpaulo 117173426Srpaulo /* Helper functions */ 118173426Srpaulo int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); 119173426Srpaulo int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); 120173426Srpaulo int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); 121271975Srpaulo int (*smc_fan_id)(SYSCTL_HANDLER_ARGS); 122173426Srpaulo int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); 123173426Srpaulo int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); 124173426Srpaulo int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); 125173426Srpaulo int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); 126173426Srpaulo int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); 127173426Srpaulo int (*smc_light_left)(SYSCTL_HANDLER_ARGS); 128173426Srpaulo int (*smc_light_right)(SYSCTL_HANDLER_ARGS); 129195046Srpaulo int (*smc_light_control)(SYSCTL_HANDLER_ARGS); 130173426Srpaulo 131178145Srpaulo const char *smc_temps[ASMC_TEMP_MAX]; 132178145Srpaulo const char *smc_tempnames[ASMC_TEMP_MAX]; 133178145Srpaulo const char *smc_tempdescs[ASMC_TEMP_MAX]; 134173426Srpaulo}; 135173426Srpaulo 136173426Srpaulostatic struct asmc_model *asmc_match(device_t dev); 137173426Srpaulo 138173426Srpaulo#define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ 139173426Srpaulo asmc_mb_sysctl_sms_z 140173426Srpaulo 141298937Sadrian#define ASMC_SMS_FUNCS_DISABLED NULL,NULL,NULL 142298937Sadrian 143271975Srpaulo#define ASMC_FAN_FUNCS asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ 144173426Srpaulo asmc_mb_sysctl_fanminspeed, \ 145173426Srpaulo asmc_mb_sysctl_fanmaxspeed, \ 146173426Srpaulo asmc_mb_sysctl_fantargetspeed 147298937Sadrian 148298937Sadrian#define ASMC_FAN_FUNCS2 asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \ 149298937Sadrian asmc_mb_sysctl_fanminspeed, \ 150298937Sadrian asmc_mb_sysctl_fanmaxspeed, \ 151298937Sadrian asmc_mb_sysctl_fantargetspeed 152298937Sadrian 153173426Srpaulo#define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ 154195046Srpaulo asmc_mbp_sysctl_light_right, \ 155195046Srpaulo asmc_mbp_sysctl_light_control 156173426Srpaulo 157173426Srpaulostruct asmc_model asmc_models[] = { 158173426Srpaulo { 159173426Srpaulo "MacBook1,1", "Apple SMC MacBook Core Duo", 160195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 161173426Srpaulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 162173426Srpaulo }, 163173426Srpaulo 164173426Srpaulo { 165173426Srpaulo "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 166195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 167173426Srpaulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 168173426Srpaulo }, 169173426Srpaulo 170298937Sadrian { 171298937Sadrian "MacBook3,1", "Apple SMC MacBook Core 2 Duo", 172298937Sadrian ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 173298937Sadrian ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS 174298937Sadrian }, 175298937Sadrian 176173426Srpaulo { 177173426Srpaulo "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 178173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 179173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 180173426Srpaulo }, 181173426Srpaulo 182173426Srpaulo { 183173426Srpaulo "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 184173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 185173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 186173426Srpaulo }, 187173426Srpaulo 188173426Srpaulo { 189173426Srpaulo "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 190173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 191173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 192173426Srpaulo }, 193173426Srpaulo 194173426Srpaulo { 195173426Srpaulo "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 196173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 197173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 198173426Srpaulo }, 199173426Srpaulo 200173426Srpaulo { 201173426Srpaulo "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 202173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 203173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 204173426Srpaulo }, 205173426Srpaulo 206173426Srpaulo { 207173426Srpaulo "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 208173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 209173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 210173426Srpaulo }, 211173426Srpaulo 212195046Srpaulo { 213195046Srpaulo "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)", 214195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 215195046Srpaulo ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS 216195046Srpaulo }, 217271975Srpaulo 218271975Srpaulo { 219271975Srpaulo "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)", 220271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 221271975Srpaulo ASMC_MBP8_TEMPS, ASMC_MBP8_TEMPNAMES, ASMC_MBP8_TEMPDESCS 222271975Srpaulo }, 223271975Srpaulo 224271975Srpaulo { 225271975Srpaulo "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 226271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 227271975Srpaulo ASMC_MBP11_TEMPS, ASMC_MBP11_TEMPNAMES, ASMC_MBP11_TEMPDESCS 228271975Srpaulo }, 229195046Srpaulo 230173426Srpaulo /* The Mac Mini has no SMS */ 231173426Srpaulo { 232173426Srpaulo "Macmini1,1", "Apple SMC Mac Mini", 233173426Srpaulo NULL, NULL, NULL, 234173851Srpaulo ASMC_FAN_FUNCS, 235195046Srpaulo NULL, NULL, NULL, 236173426Srpaulo ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 237173426Srpaulo }, 238173426Srpaulo 239268303Sgavin /* The Mac Mini 3,1 has no SMS */ 240268303Sgavin { 241268303Sgavin "Macmini3,1", "Apple SMC Mac Mini 3,1", 242268303Sgavin NULL, NULL, NULL, 243268303Sgavin ASMC_FAN_FUNCS, 244268303Sgavin NULL, NULL, NULL, 245268303Sgavin ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS 246268303Sgavin }, 247268303Sgavin 248178145Srpaulo /* Idem for the MacPro */ 249178145Srpaulo { 250178145Srpaulo "MacPro2", "Apple SMC Mac Pro (8-core)", 251178145Srpaulo NULL, NULL, NULL, 252178145Srpaulo ASMC_FAN_FUNCS, 253195046Srpaulo NULL, NULL, NULL, 254178145Srpaulo ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS 255178145Srpaulo }, 256182850Srpaulo 257271975Srpaulo /* Idem for the MacPro 2010*/ 258182850Srpaulo { 259271975Srpaulo "MacPro5,1", "Apple SMC MacPro (2010)", 260271975Srpaulo NULL, NULL, NULL, 261271975Srpaulo ASMC_FAN_FUNCS, 262271975Srpaulo NULL, NULL, NULL, 263271975Srpaulo ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS 264271975Srpaulo }, 265271975Srpaulo 266271975Srpaulo { 267182850Srpaulo "MacBookAir1,1", "Apple SMC MacBook Air", 268195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 269182850Srpaulo ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS 270182850Srpaulo }, 271182850Srpaulo 272271975Srpaulo { 273271975Srpaulo "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", 274271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 275271975Srpaulo ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS 276271975Srpaulo }, 277271975Srpaulo 278298937Sadrian { 279298937Sadrian "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)", 280298937Sadrian ASMC_SMS_FUNCS_DISABLED, 281298937Sadrian ASMC_FAN_FUNCS2, 282298937Sadrian ASMC_LIGHT_FUNCS, 283298937Sadrian ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 284298937Sadrian }, 285298937Sadrian 286298937Sadrian { 287298937Sadrian "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)", 288298937Sadrian ASMC_SMS_FUNCS_DISABLED, 289298937Sadrian ASMC_FAN_FUNCS2, 290298937Sadrian ASMC_LIGHT_FUNCS, 291298937Sadrian ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 292298937Sadrian }, 293298937Sadrian 294178145Srpaulo 295173426Srpaulo { NULL, NULL } 296173426Srpaulo}; 297173426Srpaulo 298173426Srpaulo#undef ASMC_SMS_FUNCS 299298937Sadrian#undef ASMC_SMS_FUNCS_DISABLED 300173426Srpaulo#undef ASMC_FAN_FUNCS 301298937Sadrian#undef ASMC_FAN_FUNCS2 302173426Srpaulo#undef ASMC_LIGHT_FUNCS 303173426Srpaulo 304173426Srpaulo/* 305173426Srpaulo * Driver methods. 306173426Srpaulo */ 307173426Srpaulostatic device_method_t asmc_methods[] = { 308173426Srpaulo DEVMETHOD(device_probe, asmc_probe), 309173426Srpaulo DEVMETHOD(device_attach, asmc_attach), 310173426Srpaulo DEVMETHOD(device_detach, asmc_detach), 311298937Sadrian DEVMETHOD(device_resume, asmc_resume), 312173426Srpaulo 313173426Srpaulo { 0, 0 } 314173426Srpaulo}; 315173426Srpaulo 316173426Srpaulostatic driver_t asmc_driver = { 317173426Srpaulo "asmc", 318173426Srpaulo asmc_methods, 319173426Srpaulo sizeof(struct asmc_softc) 320173426Srpaulo}; 321173426Srpaulo 322177972Srpaulo/* 323177972Srpaulo * Debugging 324177972Srpaulo */ 325177972Srpaulo#define _COMPONENT ACPI_OEM 326177972SrpauloACPI_MODULE_NAME("ASMC") 327177972Srpaulo#ifdef DEBUG 328177972Srpaulo#define ASMC_DPRINTF(str) device_printf(dev, str) 329177977Srpaulo#else 330177977Srpaulo#define ASMC_DPRINTF(str) 331177972Srpaulo#endif 332177972Srpaulo 333195046Srpaulo/* NB: can't be const */ 334177972Srpaulostatic char *asmc_ids[] = { "APP0001", NULL }; 335177972Srpaulo 336173426Srpaulostatic devclass_t asmc_devclass; 337173426Srpaulo 338298937Sadrianstatic unsigned int light_control = 0; 339298937Sadrian 340177972SrpauloDRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 341177972SrpauloMODULE_DEPEND(asmc, acpi, 1, 1, 1); 342173426Srpaulo 343173426Srpaulostatic struct asmc_model * 344173426Srpauloasmc_match(device_t dev) 345173426Srpaulo{ 346173426Srpaulo int i; 347173426Srpaulo char *model; 348173426Srpaulo 349273174Sdavide model = kern_getenv("smbios.system.product"); 350185433Srpaulo if (model == NULL) 351185433Srpaulo return (NULL); 352185433Srpaulo 353173426Srpaulo for (i = 0; asmc_models[i].smc_model; i++) { 354173426Srpaulo if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 355173426Srpaulo freeenv(model); 356173426Srpaulo return (&asmc_models[i]); 357173426Srpaulo } 358173426Srpaulo } 359173426Srpaulo freeenv(model); 360173426Srpaulo 361173426Srpaulo return (NULL); 362173426Srpaulo} 363173426Srpaulo 364173426Srpaulostatic int 365173426Srpauloasmc_probe(device_t dev) 366173426Srpaulo{ 367173426Srpaulo struct asmc_model *model; 368173426Srpaulo 369241885Seadler if (resource_disabled("asmc", 0)) 370241885Seadler return (ENXIO); 371177972Srpaulo if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL) 372177972Srpaulo return (ENXIO); 373177972Srpaulo 374173426Srpaulo model = asmc_match(dev); 375177972Srpaulo if (!model) { 376177972Srpaulo device_printf(dev, "model not recognized\n"); 377173426Srpaulo return (ENXIO); 378177972Srpaulo } 379173426Srpaulo device_set_desc(dev, model->smc_desc); 380173426Srpaulo 381173426Srpaulo return (BUS_PROBE_DEFAULT); 382173426Srpaulo} 383173426Srpaulo 384173426Srpaulostatic int 385173426Srpauloasmc_attach(device_t dev) 386173426Srpaulo{ 387173426Srpaulo int i, j; 388173426Srpaulo int ret; 389173426Srpaulo char name[2]; 390173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 391173426Srpaulo struct sysctl_ctx_list *sysctlctx; 392173426Srpaulo struct sysctl_oid *sysctlnode; 393173426Srpaulo struct asmc_model *model; 394173426Srpaulo 395177972Srpaulo sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 396177972Srpaulo &sc->sc_rid_port, RF_ACTIVE); 397177972Srpaulo if (sc->sc_ioport == NULL) { 398177972Srpaulo device_printf(dev, "unable to allocate IO port\n"); 399177972Srpaulo return (ENOMEM); 400177972Srpaulo } 401177972Srpaulo 402173426Srpaulo sysctlctx = device_get_sysctl_ctx(dev); 403173426Srpaulo sysctlnode = device_get_sysctl_tree(dev); 404173426Srpaulo 405173426Srpaulo model = asmc_match(dev); 406173426Srpaulo 407173426Srpaulo mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 408173426Srpaulo 409173426Srpaulo sc->sc_model = model; 410173426Srpaulo asmc_init(dev); 411173426Srpaulo 412173426Srpaulo /* 413173426Srpaulo * dev.asmc.n.fan.* tree. 414173426Srpaulo */ 415173426Srpaulo sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 416173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 417173426Srpaulo CTLFLAG_RD, 0, "Fan Root Tree"); 418173426Srpaulo 419173426Srpaulo for (i = 1; i <= sc->sc_nfan; i++) { 420173426Srpaulo j = i - 1; 421173426Srpaulo name[0] = '0' + j; 422173426Srpaulo name[1] = 0; 423173426Srpaulo sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 424173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 425173426Srpaulo OID_AUTO, name, CTLFLAG_RD, 0, 426173426Srpaulo "Fan Subtree"); 427173426Srpaulo 428173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 429173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 430271975Srpaulo OID_AUTO, "id", CTLTYPE_STRING | CTLFLAG_RD, 431271975Srpaulo dev, j, model->smc_fan_id, "I", 432271975Srpaulo "Fan ID"); 433271975Srpaulo 434271975Srpaulo SYSCTL_ADD_PROC(sysctlctx, 435271975Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 436173426Srpaulo OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD, 437173426Srpaulo dev, j, model->smc_fan_speed, "I", 438173426Srpaulo "Fan speed in RPM"); 439173426Srpaulo 440173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 441173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 442173426Srpaulo OID_AUTO, "safespeed", 443173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 444173426Srpaulo dev, j, model->smc_fan_safespeed, "I", 445173426Srpaulo "Fan safe speed in RPM"); 446173426Srpaulo 447173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 448173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 449173426Srpaulo OID_AUTO, "minspeed", 450271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 451173426Srpaulo dev, j, model->smc_fan_minspeed, "I", 452173426Srpaulo "Fan minimum speed in RPM"); 453173426Srpaulo 454173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 455173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 456173426Srpaulo OID_AUTO, "maxspeed", 457271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 458173426Srpaulo dev, j, model->smc_fan_maxspeed, "I", 459173426Srpaulo "Fan maximum speed in RPM"); 460173426Srpaulo 461173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 462173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 463173426Srpaulo OID_AUTO, "targetspeed", 464271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 465173426Srpaulo dev, j, model->smc_fan_targetspeed, "I", 466173426Srpaulo "Fan target speed in RPM"); 467173426Srpaulo } 468173426Srpaulo 469173426Srpaulo /* 470173426Srpaulo * dev.asmc.n.temp tree. 471173426Srpaulo */ 472173426Srpaulo sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 473173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 474173426Srpaulo CTLFLAG_RD, 0, "Temperature sensors"); 475173426Srpaulo 476173426Srpaulo for (i = 0; model->smc_temps[i]; i++) { 477173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 478173426Srpaulo SYSCTL_CHILDREN(sc->sc_temp_tree), 479173426Srpaulo OID_AUTO, model->smc_tempnames[i], 480173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 481173426Srpaulo dev, i, asmc_temp_sysctl, "I", 482173426Srpaulo model->smc_tempdescs[i]); 483173426Srpaulo } 484173426Srpaulo 485195046Srpaulo /* 486195046Srpaulo * dev.asmc.n.light 487195046Srpaulo */ 488195046Srpaulo if (model->smc_light_left) { 489195046Srpaulo sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 490195046Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 491195046Srpaulo CTLFLAG_RD, 0, "Keyboard backlight sensors"); 492195046Srpaulo 493195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 494195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 495195046Srpaulo OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD, 496195046Srpaulo dev, 0, model->smc_light_left, "I", 497195046Srpaulo "Keyboard backlight left sensor"); 498195046Srpaulo 499195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 500195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 501195046Srpaulo OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD, 502195046Srpaulo dev, 0, model->smc_light_right, "I", 503195046Srpaulo "Keyboard backlight right sensor"); 504195046Srpaulo 505195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 506195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 507196455Srpaulo OID_AUTO, "control", 508196455Srpaulo CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 509195046Srpaulo dev, 0, model->smc_light_control, "I", 510195046Srpaulo "Keyboard backlight brightness control"); 511195046Srpaulo } 512195046Srpaulo 513173426Srpaulo if (model->smc_sms_x == NULL) 514173426Srpaulo goto nosms; 515173426Srpaulo 516173426Srpaulo /* 517173426Srpaulo * dev.asmc.n.sms tree. 518173426Srpaulo */ 519173426Srpaulo sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 520173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 521173426Srpaulo CTLFLAG_RD, 0, "Sudden Motion Sensor"); 522173426Srpaulo 523173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 524173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 525173426Srpaulo OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD, 526173426Srpaulo dev, 0, model->smc_sms_x, "I", 527173426Srpaulo "Sudden Motion Sensor X value"); 528173426Srpaulo 529173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 530173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 531173426Srpaulo OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD, 532173426Srpaulo dev, 0, model->smc_sms_y, "I", 533173426Srpaulo "Sudden Motion Sensor Y value"); 534173426Srpaulo 535173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 536173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 537173426Srpaulo OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD, 538173426Srpaulo dev, 0, model->smc_sms_z, "I", 539173426Srpaulo "Sudden Motion Sensor Z value"); 540173426Srpaulo 541173426Srpaulo /* 542173426Srpaulo * Need a taskqueue to send devctl_notify() events 543173426Srpaulo * when the SMS interrupt us. 544173426Srpaulo * 545173426Srpaulo * PI_REALTIME is used due to the sensitivity of the 546173426Srpaulo * interrupt. An interrupt from the SMS means that the 547173426Srpaulo * disk heads should be turned off as quickly as possible. 548173426Srpaulo * 549173426Srpaulo * We only need to do this for the non INTR_FILTER case. 550173426Srpaulo */ 551173426Srpaulo sc->sc_sms_tq = NULL; 552173426Srpaulo#ifndef INTR_FILTER 553173426Srpaulo TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 554173426Srpaulo sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 555173426Srpaulo taskqueue_thread_enqueue, &sc->sc_sms_tq); 556173426Srpaulo taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 557173426Srpaulo device_get_nameunit(dev)); 558173426Srpaulo#endif 559173426Srpaulo /* 560173426Srpaulo * Allocate an IRQ for the SMS. 561173426Srpaulo */ 562177972Srpaulo sc->sc_rid_irq = 0; 563177972Srpaulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 564177972Srpaulo &sc->sc_rid_irq, RF_ACTIVE); 565177972Srpaulo if (sc->sc_irq == NULL) { 566173426Srpaulo device_printf(dev, "unable to allocate IRQ resource\n"); 567173426Srpaulo ret = ENXIO; 568173426Srpaulo goto err2; 569173426Srpaulo } 570173426Srpaulo 571177972Srpaulo ret = bus_setup_intr(dev, sc->sc_irq, 572173426Srpaulo INTR_TYPE_MISC | INTR_MPSAFE, 573173426Srpaulo#ifdef INTR_FILTER 574173426Srpaulo asmc_sms_intrfast, asmc_sms_handler, 575173426Srpaulo#else 576173426Srpaulo asmc_sms_intrfast, NULL, 577173426Srpaulo#endif 578173426Srpaulo dev, &sc->sc_cookie); 579173426Srpaulo 580173426Srpaulo if (ret) { 581173426Srpaulo device_printf(dev, "unable to setup SMS IRQ\n"); 582173426Srpaulo goto err1; 583173426Srpaulo } 584173426Srpaulonosms: 585173426Srpaulo return (0); 586173426Srpauloerr1: 587177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 588173426Srpauloerr2: 589177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 590177972Srpaulo sc->sc_ioport); 591173426Srpaulo mtx_destroy(&sc->sc_mtx); 592173426Srpaulo if (sc->sc_sms_tq) 593173426Srpaulo taskqueue_free(sc->sc_sms_tq); 594173426Srpaulo 595173426Srpaulo return (ret); 596173426Srpaulo} 597173426Srpaulo 598173426Srpaulostatic int 599173426Srpauloasmc_detach(device_t dev) 600173426Srpaulo{ 601173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 602173426Srpaulo 603173426Srpaulo if (sc->sc_sms_tq) { 604173426Srpaulo taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 605173426Srpaulo taskqueue_free(sc->sc_sms_tq); 606173426Srpaulo } 607173426Srpaulo if (sc->sc_cookie) 608177972Srpaulo bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 609177972Srpaulo if (sc->sc_irq) 610177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 611177972Srpaulo sc->sc_irq); 612177972Srpaulo if (sc->sc_ioport) 613177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 614177972Srpaulo sc->sc_ioport); 615173426Srpaulo mtx_destroy(&sc->sc_mtx); 616173426Srpaulo 617173426Srpaulo return (0); 618173426Srpaulo} 619173426Srpaulo 620298937Sadrianstatic int 621298937Sadrianasmc_resume(device_t dev) 622298937Sadrian{ 623298937Sadrian uint8_t buf[2]; 624298937Sadrian buf[0] = light_control; 625298937Sadrian buf[1] = 0x00; 626298937Sadrian asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 627298937Sadrian return (0); 628298937Sadrian} 629298937Sadrian 630298937Sadrian 631197190Srpaulo#ifdef DEBUG 632197190Srpaulovoid asmc_dumpall(device_t dev) 633197190Srpaulo{ 634197190Srpaulo int i; 635197190Srpaulo 636197190Srpaulo /* XXX magic number */ 637197190Srpaulo for (i=0; i < 0x100; i++) 638197190Srpaulo asmc_key_dump(dev, i); 639197190Srpaulo} 640197190Srpaulo#endif 641197190Srpaulo 642173426Srpaulostatic int 643173426Srpauloasmc_init(device_t dev) 644173426Srpaulo{ 645173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 646173426Srpaulo int i, error = 1; 647173426Srpaulo uint8_t buf[4]; 648173426Srpaulo 649173426Srpaulo if (sc->sc_model->smc_sms_x == NULL) 650173426Srpaulo goto nosms; 651173426Srpaulo 652173426Srpaulo /* 653298955Spfg * We are ready to receive interrupts from the SMS. 654173426Srpaulo */ 655173426Srpaulo buf[0] = 0x01; 656177972Srpaulo ASMC_DPRINTF(("intok key\n")); 657173426Srpaulo asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 658173426Srpaulo DELAY(50); 659173426Srpaulo 660173426Srpaulo /* 661173426Srpaulo * Initiate the polling intervals. 662173426Srpaulo */ 663173426Srpaulo buf[0] = 20; /* msecs */ 664177972Srpaulo ASMC_DPRINTF(("low int key\n")); 665173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 666173426Srpaulo DELAY(200); 667173426Srpaulo 668173426Srpaulo buf[0] = 20; /* msecs */ 669177972Srpaulo ASMC_DPRINTF(("high int key\n")); 670173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 671173426Srpaulo DELAY(200); 672173426Srpaulo 673173426Srpaulo buf[0] = 0x00; 674173426Srpaulo buf[1] = 0x60; 675177972Srpaulo ASMC_DPRINTF(("sms low key\n")); 676173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 677173426Srpaulo DELAY(200); 678173426Srpaulo 679173426Srpaulo buf[0] = 0x01; 680173426Srpaulo buf[1] = 0xc0; 681177972Srpaulo ASMC_DPRINTF(("sms high key\n")); 682173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 683173426Srpaulo DELAY(200); 684173426Srpaulo 685173426Srpaulo /* 686173426Srpaulo * I'm not sure what this key does, but it seems to be 687173426Srpaulo * required. 688173426Srpaulo */ 689173426Srpaulo buf[0] = 0x01; 690177972Srpaulo ASMC_DPRINTF(("sms flag key\n")); 691173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 692177979Srpaulo DELAY(100); 693173426Srpaulo 694197190Srpaulo sc->sc_sms_intr_works = 0; 695197190Srpaulo 696173426Srpaulo /* 697197190Srpaulo * Retry SMS initialization 1000 times 698197190Srpaulo * (takes approx. 2 seconds in worst case) 699173426Srpaulo */ 700197190Srpaulo for (i = 0; i < 1000; i++) { 701173426Srpaulo if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 702197190Srpaulo (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 703173426Srpaulo error = 0; 704197190Srpaulo sc->sc_sms_intr_works = 1; 705177977Srpaulo goto out; 706173426Srpaulo } 707173426Srpaulo buf[0] = ASMC_SMS_INIT1; 708173426Srpaulo buf[1] = ASMC_SMS_INIT2; 709177972Srpaulo ASMC_DPRINTF(("sms key\n")); 710173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 711173426Srpaulo DELAY(50); 712173426Srpaulo } 713177977Srpaulo device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 714173426Srpaulo 715177977Srpauloout: 716173426Srpaulo asmc_sms_calibrate(dev); 717173426Srpaulonosms: 718173426Srpaulo sc->sc_nfan = asmc_fan_count(dev); 719173426Srpaulo if (sc->sc_nfan > ASMC_MAXFANS) { 720173426Srpaulo device_printf(dev, "more than %d fans were detected. Please " 721173426Srpaulo "report this.\n", ASMC_MAXFANS); 722173426Srpaulo sc->sc_nfan = ASMC_MAXFANS; 723173426Srpaulo } 724173426Srpaulo 725173426Srpaulo if (bootverbose) { 726173426Srpaulo /* 727271975Srpaulo * The number of keys is a 32 bit buffer 728173426Srpaulo */ 729173426Srpaulo asmc_key_read(dev, ASMC_NKEYS, buf, 4); 730271975Srpaulo device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf)); 731173426Srpaulo } 732173426Srpaulo 733197190Srpaulo#ifdef DEBUG 734197190Srpaulo asmc_dumpall(dev); 735197190Srpaulo#endif 736197190Srpaulo 737173426Srpaulo return (error); 738173426Srpaulo} 739173426Srpaulo 740173426Srpaulo/* 741173426Srpaulo * We need to make sure that the SMC acks the byte sent. 742195046Srpaulo * Just wait up to (amount * 10) ms. 743173426Srpaulo */ 744173426Srpaulostatic int 745195046Srpauloasmc_wait_ack(device_t dev, uint8_t val, int amount) 746173426Srpaulo{ 747177972Srpaulo struct asmc_softc *sc = device_get_softc(dev); 748173426Srpaulo u_int i; 749173426Srpaulo 750173426Srpaulo val = val & ASMC_STATUS_MASK; 751173426Srpaulo 752195046Srpaulo for (i = 0; i < amount; i++) { 753177972Srpaulo if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 754173426Srpaulo return (0); 755173426Srpaulo DELAY(10); 756173426Srpaulo } 757173426Srpaulo 758195046Srpaulo return (1); 759195046Srpaulo} 760195046Srpaulo 761195046Srpaulo/* 762195046Srpaulo * We need to make sure that the SMC acks the byte sent. 763195046Srpaulo * Just wait up to 100 ms. 764195046Srpaulo */ 765195046Srpaulostatic int 766195046Srpauloasmc_wait(device_t dev, uint8_t val) 767195046Srpaulo{ 768195046Srpaulo struct asmc_softc *sc; 769195046Srpaulo 770195046Srpaulo if (asmc_wait_ack(dev, val, 1000) == 0) 771195046Srpaulo return (0); 772195046Srpaulo 773195046Srpaulo sc = device_get_softc(dev); 774195046Srpaulo val = val & ASMC_STATUS_MASK; 775195046Srpaulo 776195046Srpaulo#ifdef DEBUG 777173426Srpaulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 778177972Srpaulo ASMC_CMDPORT_READ(sc)); 779195046Srpaulo#endif 780195046Srpaulo return (1); 781195046Srpaulo} 782173426Srpaulo 783195046Srpaulo/* 784195046Srpaulo * Send the given command, retrying up to 10 times if 785195046Srpaulo * the acknowledgement fails. 786195046Srpaulo */ 787195046Srpaulostatic int 788195046Srpauloasmc_command(device_t dev, uint8_t command) { 789195046Srpaulo 790195046Srpaulo int i; 791195046Srpaulo struct asmc_softc *sc = device_get_softc(dev); 792195046Srpaulo 793195046Srpaulo for (i=0; i < 10; i++) { 794195046Srpaulo ASMC_CMDPORT_WRITE(sc, command); 795195046Srpaulo if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 796195046Srpaulo return (0); 797195046Srpaulo } 798195046Srpaulo } 799195046Srpaulo 800195046Srpaulo#ifdef DEBUG 801195046Srpaulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 802195046Srpaulo ASMC_CMDPORT_READ(sc)); 803195046Srpaulo#endif 804173426Srpaulo return (1); 805173426Srpaulo} 806173426Srpaulo 807173426Srpaulostatic int 808173426Srpauloasmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 809173426Srpaulo{ 810195046Srpaulo int i, error = 1, try = 0; 811173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 812173426Srpaulo 813173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 814173426Srpaulo 815195046Srpaulobegin: 816195046Srpaulo if (asmc_command(dev, ASMC_CMDREAD)) 817173426Srpaulo goto out; 818173426Srpaulo 819173426Srpaulo for (i = 0; i < 4; i++) { 820177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 821173426Srpaulo if (asmc_wait(dev, 0x04)) 822173426Srpaulo goto out; 823173426Srpaulo } 824173426Srpaulo 825177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 826173426Srpaulo 827173426Srpaulo for (i = 0; i < len; i++) { 828173426Srpaulo if (asmc_wait(dev, 0x05)) 829173426Srpaulo goto out; 830177972Srpaulo buf[i] = ASMC_DATAPORT_READ(sc); 831173426Srpaulo } 832173426Srpaulo 833173426Srpaulo error = 0; 834173426Srpauloout: 835195046Srpaulo if (error) { 836195046Srpaulo if (++try < 10) goto begin; 837195046Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 838195046Srpaulo __func__, key, try); 839195046Srpaulo } 840195046Srpaulo 841173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 842173426Srpaulo 843173426Srpaulo return (error); 844173426Srpaulo} 845173426Srpaulo 846197190Srpaulo#ifdef DEBUG 847173426Srpaulostatic int 848197190Srpauloasmc_key_dump(device_t dev, int number) 849197190Srpaulo{ 850197190Srpaulo struct asmc_softc *sc = device_get_softc(dev); 851197190Srpaulo char key[5] = { 0 }; 852197190Srpaulo char type[7] = { 0 }; 853197190Srpaulo uint8_t index[4]; 854197190Srpaulo uint8_t v[32]; 855197190Srpaulo uint8_t maxlen; 856197190Srpaulo int i, error = 1, try = 0; 857197190Srpaulo 858197190Srpaulo mtx_lock_spin(&sc->sc_mtx); 859197190Srpaulo 860197190Srpaulo index[0] = (number >> 24) & 0xff; 861197190Srpaulo index[1] = (number >> 16) & 0xff; 862197190Srpaulo index[2] = (number >> 8) & 0xff; 863197190Srpaulo index[3] = (number) & 0xff; 864197190Srpaulo 865197190Srpaulobegin: 866197190Srpaulo if (asmc_command(dev, 0x12)) 867197190Srpaulo goto out; 868197190Srpaulo 869197190Srpaulo for (i = 0; i < 4; i++) { 870197190Srpaulo ASMC_DATAPORT_WRITE(sc, index[i]); 871197190Srpaulo if (asmc_wait(dev, 0x04)) 872197190Srpaulo goto out; 873197190Srpaulo } 874197190Srpaulo 875197190Srpaulo ASMC_DATAPORT_WRITE(sc, 4); 876197190Srpaulo 877197190Srpaulo for (i = 0; i < 4; i++) { 878197190Srpaulo if (asmc_wait(dev, 0x05)) 879197190Srpaulo goto out; 880197190Srpaulo key[i] = ASMC_DATAPORT_READ(sc); 881197190Srpaulo } 882197190Srpaulo 883197190Srpaulo /* get type */ 884197190Srpaulo if (asmc_command(dev, 0x13)) 885197190Srpaulo goto out; 886197190Srpaulo 887197190Srpaulo for (i = 0; i < 4; i++) { 888197190Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 889197190Srpaulo if (asmc_wait(dev, 0x04)) 890197190Srpaulo goto out; 891197190Srpaulo } 892197190Srpaulo 893197190Srpaulo ASMC_DATAPORT_WRITE(sc, 6); 894197190Srpaulo 895197190Srpaulo for (i = 0; i < 6; i++) { 896197190Srpaulo if (asmc_wait(dev, 0x05)) 897197190Srpaulo goto out; 898197190Srpaulo type[i] = ASMC_DATAPORT_READ(sc); 899197190Srpaulo } 900197190Srpaulo 901197190Srpaulo error = 0; 902197190Srpauloout: 903197190Srpaulo if (error) { 904197190Srpaulo if (++try < 10) goto begin; 905197190Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 906197190Srpaulo __func__, key, try); 907197190Srpaulo mtx_unlock_spin(&sc->sc_mtx); 908197190Srpaulo } 909197190Srpaulo else { 910197190Srpaulo char buf[1024]; 911197190Srpaulo char buf2[8]; 912197190Srpaulo mtx_unlock_spin(&sc->sc_mtx); 913197190Srpaulo maxlen = type[0]; 914197190Srpaulo type[0] = ' '; 915197190Srpaulo type[5] = 0; 916197190Srpaulo if (maxlen > sizeof(v)) { 917197202Srpaulo device_printf(dev, 918197202Srpaulo "WARNING: cropping maxlen from %d to %zu\n", 919197202Srpaulo maxlen, sizeof(v)); 920197190Srpaulo maxlen = sizeof(v); 921197190Srpaulo } 922197190Srpaulo for (i = 0; i < sizeof(v); i++) { 923197190Srpaulo v[i] = 0; 924197190Srpaulo } 925197190Srpaulo asmc_key_read(dev, key, v, maxlen); 926197190Srpaulo snprintf(buf, sizeof(buf), "key %d is: %s, type %s " 927197190Srpaulo "(len %d), data", number, key, type, maxlen); 928197190Srpaulo for (i = 0; i < maxlen; i++) { 929298937Sadrian snprintf(buf2, sizeof(buf2), " %02x", v[i]); 930197190Srpaulo strlcat(buf, buf2, sizeof(buf)); 931197190Srpaulo } 932197190Srpaulo strlcat(buf, " \n", sizeof(buf)); 933242826Srdivacky device_printf(dev, "%s", buf); 934197190Srpaulo } 935197190Srpaulo 936197190Srpaulo return (error); 937197190Srpaulo} 938197190Srpaulo#endif 939197190Srpaulo 940197190Srpaulostatic int 941173426Srpauloasmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 942173426Srpaulo{ 943195046Srpaulo int i, error = -1, try = 0; 944173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 945173426Srpaulo 946173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 947173426Srpaulo 948195046Srpaulobegin: 949177972Srpaulo ASMC_DPRINTF(("cmd port: cmd write\n")); 950195046Srpaulo if (asmc_command(dev, ASMC_CMDWRITE)) 951173426Srpaulo goto out; 952173426Srpaulo 953177972Srpaulo ASMC_DPRINTF(("data port: key\n")); 954173426Srpaulo for (i = 0; i < 4; i++) { 955177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 956173426Srpaulo if (asmc_wait(dev, 0x04)) 957173426Srpaulo goto out; 958173426Srpaulo } 959177972Srpaulo ASMC_DPRINTF(("data port: length\n")); 960177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 961173426Srpaulo 962177972Srpaulo ASMC_DPRINTF(("data port: buffer\n")); 963173426Srpaulo for (i = 0; i < len; i++) { 964173426Srpaulo if (asmc_wait(dev, 0x04)) 965173426Srpaulo goto out; 966177972Srpaulo ASMC_DATAPORT_WRITE(sc, buf[i]); 967173426Srpaulo } 968173426Srpaulo 969173426Srpaulo error = 0; 970173426Srpauloout: 971195046Srpaulo if (error) { 972195046Srpaulo if (++try < 10) goto begin; 973195046Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 974195046Srpaulo __func__, key, try); 975195046Srpaulo } 976195046Srpaulo 977173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 978173426Srpaulo 979173426Srpaulo return (error); 980173426Srpaulo 981173426Srpaulo} 982173426Srpaulo 983173426Srpaulo/* 984173426Srpaulo * Fan control functions. 985173426Srpaulo */ 986173426Srpaulostatic int 987173426Srpauloasmc_fan_count(device_t dev) 988173426Srpaulo{ 989173426Srpaulo uint8_t buf[1]; 990173426Srpaulo 991271975Srpaulo if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) < 0) 992173426Srpaulo return (-1); 993173426Srpaulo 994173426Srpaulo return (buf[0]); 995173426Srpaulo} 996173426Srpaulo 997173426Srpaulostatic int 998173426Srpauloasmc_fan_getvalue(device_t dev, const char *key, int fan) 999173426Srpaulo{ 1000173426Srpaulo int speed; 1001173426Srpaulo uint8_t buf[2]; 1002173426Srpaulo char fankey[5]; 1003173426Srpaulo 1004173426Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1005271975Srpaulo if (asmc_key_read(dev, fankey, buf, sizeof buf) < 0) 1006173426Srpaulo return (-1); 1007173426Srpaulo speed = (buf[0] << 6) | (buf[1] >> 2); 1008173426Srpaulo 1009173426Srpaulo return (speed); 1010173426Srpaulo} 1011173426Srpaulo 1012271975Srpaulostatic char* 1013293193Suqsasmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen) 1014271975Srpaulo{ 1015271975Srpaulo char fankey[5]; 1016271975Srpaulo char* desc; 1017271975Srpaulo 1018271975Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1019293193Suqs if (asmc_key_read(dev, fankey, buf, buflen) < 0) 1020271975Srpaulo return (NULL); 1021271975Srpaulo desc = buf+4; 1022271975Srpaulo 1023271975Srpaulo return (desc); 1024271975Srpaulo} 1025271975Srpaulo 1026173426Srpaulostatic int 1027271975Srpauloasmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 1028271975Srpaulo{ 1029271975Srpaulo uint8_t buf[2]; 1030271975Srpaulo char fankey[5]; 1031271975Srpaulo 1032271975Srpaulo speed *= 4; 1033271975Srpaulo 1034271975Srpaulo buf[0] = speed>>8; 1035271975Srpaulo buf[1] = speed; 1036271975Srpaulo 1037271975Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1038271975Srpaulo if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0) 1039271975Srpaulo return (-1); 1040271975Srpaulo 1041271975Srpaulo return (0); 1042271975Srpaulo} 1043271975Srpaulo 1044271975Srpaulostatic int 1045173426Srpauloasmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 1046173426Srpaulo{ 1047173426Srpaulo device_t dev = (device_t) arg1; 1048173426Srpaulo int fan = arg2; 1049173426Srpaulo int error; 1050173426Srpaulo int32_t v; 1051173426Srpaulo 1052173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 1053173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1054173426Srpaulo 1055173426Srpaulo return (error); 1056173426Srpaulo} 1057173426Srpaulo 1058173426Srpaulostatic int 1059271975Srpauloasmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 1060271975Srpaulo{ 1061293193Suqs uint8_t buf[16]; 1062271975Srpaulo device_t dev = (device_t) arg1; 1063271975Srpaulo int fan = arg2; 1064271975Srpaulo int error = true; 1065271975Srpaulo char* desc; 1066271975Srpaulo 1067293193Suqs desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); 1068271975Srpaulo 1069271975Srpaulo if (desc != NULL) 1070271975Srpaulo error = sysctl_handle_string(oidp, desc, 0, req); 1071271975Srpaulo 1072271975Srpaulo return (error); 1073271975Srpaulo} 1074271975Srpaulo 1075271975Srpaulostatic int 1076173426Srpauloasmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 1077173426Srpaulo{ 1078173426Srpaulo device_t dev = (device_t) arg1; 1079173426Srpaulo int fan = arg2; 1080173426Srpaulo int error; 1081173426Srpaulo int32_t v; 1082173426Srpaulo 1083173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 1084173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1085173426Srpaulo 1086173426Srpaulo return (error); 1087173426Srpaulo} 1088173426Srpaulo 1089173426Srpaulo 1090173426Srpaulostatic int 1091173426Srpauloasmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 1092173426Srpaulo{ 1093173426Srpaulo device_t dev = (device_t) arg1; 1094173426Srpaulo int fan = arg2; 1095173426Srpaulo int error; 1096173426Srpaulo int32_t v; 1097173426Srpaulo 1098173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 1099173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1100173426Srpaulo 1101271975Srpaulo if (error == 0 && req->newptr != NULL) { 1102273773Shselasky unsigned int newspeed = v; 1103271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 1104271975Srpaulo } 1105271975Srpaulo 1106173426Srpaulo return (error); 1107173426Srpaulo} 1108173426Srpaulo 1109173426Srpaulostatic int 1110173426Srpauloasmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 1111173426Srpaulo{ 1112173426Srpaulo device_t dev = (device_t) arg1; 1113173426Srpaulo int fan = arg2; 1114173426Srpaulo int error; 1115173426Srpaulo int32_t v; 1116173426Srpaulo 1117173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 1118173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1119173426Srpaulo 1120271975Srpaulo if (error == 0 && req->newptr != NULL) { 1121273773Shselasky unsigned int newspeed = v; 1122271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 1123271975Srpaulo } 1124271975Srpaulo 1125173426Srpaulo return (error); 1126173426Srpaulo} 1127173426Srpaulo 1128173426Srpaulostatic int 1129173426Srpauloasmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 1130173426Srpaulo{ 1131173426Srpaulo device_t dev = (device_t) arg1; 1132173426Srpaulo int fan = arg2; 1133173426Srpaulo int error; 1134173426Srpaulo int32_t v; 1135173426Srpaulo 1136173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 1137173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1138173426Srpaulo 1139271975Srpaulo if (error == 0 && req->newptr != NULL) { 1140273773Shselasky unsigned int newspeed = v; 1141271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 1142271975Srpaulo } 1143271975Srpaulo 1144173426Srpaulo return (error); 1145173426Srpaulo} 1146173426Srpaulo 1147173426Srpaulo/* 1148173426Srpaulo * Temperature functions. 1149173426Srpaulo */ 1150173426Srpaulostatic int 1151173426Srpauloasmc_temp_getvalue(device_t dev, const char *key) 1152173426Srpaulo{ 1153173426Srpaulo uint8_t buf[2]; 1154173426Srpaulo 1155173426Srpaulo /* 1156173426Srpaulo * Check for invalid temperatures. 1157173426Srpaulo */ 1158271975Srpaulo if (asmc_key_read(dev, key, buf, sizeof buf) < 0) 1159173426Srpaulo return (-1); 1160173426Srpaulo 1161173426Srpaulo return (buf[0]); 1162173426Srpaulo} 1163173426Srpaulo 1164173426Srpaulostatic int 1165173426Srpauloasmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 1166173426Srpaulo{ 1167173426Srpaulo device_t dev = (device_t) arg1; 1168173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1169173426Srpaulo int error, val; 1170173426Srpaulo 1171173426Srpaulo val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 1172173426Srpaulo error = sysctl_handle_int(oidp, &val, 0, req); 1173173426Srpaulo 1174173426Srpaulo return (error); 1175173426Srpaulo} 1176173426Srpaulo 1177173426Srpaulo/* 1178173426Srpaulo * Sudden Motion Sensor functions. 1179173426Srpaulo */ 1180173426Srpaulostatic int 1181173426Srpauloasmc_sms_read(device_t dev, const char *key, int16_t *val) 1182173426Srpaulo{ 1183173426Srpaulo uint8_t buf[2]; 1184173426Srpaulo int error; 1185173426Srpaulo 1186173426Srpaulo /* no need to do locking here as asmc_key_read() already does it */ 1187173426Srpaulo switch (key[3]) { 1188173426Srpaulo case 'X': 1189173426Srpaulo case 'Y': 1190173426Srpaulo case 'Z': 1191271975Srpaulo error = asmc_key_read(dev, key, buf, sizeof buf); 1192173426Srpaulo break; 1193173426Srpaulo default: 1194173426Srpaulo device_printf(dev, "%s called with invalid argument %s\n", 1195173426Srpaulo __func__, key); 1196173426Srpaulo error = 1; 1197173426Srpaulo goto out; 1198173426Srpaulo } 1199173426Srpaulo *val = ((int16_t)buf[0] << 8) | buf[1]; 1200173426Srpauloout: 1201173426Srpaulo return (error); 1202173426Srpaulo} 1203173426Srpaulo 1204173426Srpaulostatic void 1205173426Srpauloasmc_sms_calibrate(device_t dev) 1206173426Srpaulo{ 1207173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1208173426Srpaulo 1209173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 1210173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 1211173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 1212173426Srpaulo} 1213173426Srpaulo 1214173426Srpaulostatic int 1215173426Srpauloasmc_sms_intrfast(void *arg) 1216173426Srpaulo{ 1217173426Srpaulo uint8_t type; 1218173426Srpaulo device_t dev = (device_t) arg; 1219173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1220197190Srpaulo if (!sc->sc_sms_intr_works) 1221197190Srpaulo return (FILTER_HANDLED); 1222173426Srpaulo 1223173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 1224177972Srpaulo type = ASMC_INTPORT_READ(sc); 1225173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 1226173426Srpaulo 1227173426Srpaulo sc->sc_sms_intrtype = type; 1228173426Srpaulo asmc_sms_printintr(dev, type); 1229173426Srpaulo 1230173426Srpaulo#ifdef INTR_FILTER 1231173426Srpaulo return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED); 1232173426Srpaulo#else 1233173426Srpaulo taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 1234173426Srpaulo#endif 1235173426Srpaulo return (FILTER_HANDLED); 1236173426Srpaulo} 1237173426Srpaulo 1238173426Srpaulo#ifdef INTR_FILTER 1239173426Srpaulostatic void 1240173426Srpauloasmc_sms_handler(void *arg) 1241173426Srpaulo{ 1242173426Srpaulo struct asmc_softc *sc = device_get_softc(arg); 1243173426Srpaulo 1244173426Srpaulo asmc_sms_task(sc, 0); 1245173426Srpaulo} 1246173426Srpaulo#endif 1247173426Srpaulo 1248173426Srpaulo 1249173426Srpaulostatic void 1250173426Srpauloasmc_sms_printintr(device_t dev, uint8_t type) 1251173426Srpaulo{ 1252173426Srpaulo 1253173426Srpaulo switch (type) { 1254173426Srpaulo case ASMC_SMS_INTFF: 1255173426Srpaulo device_printf(dev, "WARNING: possible free fall!\n"); 1256173426Srpaulo break; 1257173426Srpaulo case ASMC_SMS_INTHA: 1258173426Srpaulo device_printf(dev, "WARNING: high acceleration detected!\n"); 1259173426Srpaulo break; 1260173426Srpaulo case ASMC_SMS_INTSH: 1261173426Srpaulo device_printf(dev, "WARNING: possible shock!\n"); 1262173426Srpaulo break; 1263173426Srpaulo default: 1264173426Srpaulo device_printf(dev, "%s unknown interrupt\n", __func__); 1265173426Srpaulo } 1266173426Srpaulo} 1267173426Srpaulo 1268173426Srpaulostatic void 1269173426Srpauloasmc_sms_task(void *arg, int pending) 1270173426Srpaulo{ 1271173426Srpaulo struct asmc_softc *sc = (struct asmc_softc *)arg; 1272173426Srpaulo char notify[16]; 1273173426Srpaulo int type; 1274173426Srpaulo 1275173426Srpaulo switch (sc->sc_sms_intrtype) { 1276173426Srpaulo case ASMC_SMS_INTFF: 1277173426Srpaulo type = 2; 1278173426Srpaulo break; 1279173426Srpaulo case ASMC_SMS_INTHA: 1280173426Srpaulo type = 1; 1281173426Srpaulo break; 1282173426Srpaulo case ASMC_SMS_INTSH: 1283173426Srpaulo type = 0; 1284173426Srpaulo break; 1285173426Srpaulo default: 1286173426Srpaulo type = 255; 1287173426Srpaulo } 1288173426Srpaulo 1289173426Srpaulo snprintf(notify, sizeof(notify), " notify=0x%x", type); 1290177972Srpaulo devctl_notify("ACPI", "asmc", "SMS", notify); 1291173426Srpaulo} 1292173426Srpaulo 1293173426Srpaulostatic int 1294173426Srpauloasmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 1295173426Srpaulo{ 1296173426Srpaulo device_t dev = (device_t) arg1; 1297173426Srpaulo int error; 1298173426Srpaulo int16_t val; 1299173426Srpaulo int32_t v; 1300173426Srpaulo 1301173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 1302173426Srpaulo v = (int32_t) val; 1303173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1304173426Srpaulo 1305173426Srpaulo return (error); 1306173426Srpaulo} 1307173426Srpaulo 1308173426Srpaulostatic int 1309173426Srpauloasmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 1310173426Srpaulo{ 1311173426Srpaulo device_t dev = (device_t) arg1; 1312173426Srpaulo int error; 1313173426Srpaulo int16_t val; 1314173426Srpaulo int32_t v; 1315173426Srpaulo 1316173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 1317173426Srpaulo v = (int32_t) val; 1318173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1319173426Srpaulo 1320173426Srpaulo return (error); 1321173426Srpaulo} 1322173426Srpaulo 1323173426Srpaulostatic int 1324173426Srpauloasmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 1325173426Srpaulo{ 1326173426Srpaulo device_t dev = (device_t) arg1; 1327173426Srpaulo int error; 1328173426Srpaulo int16_t val; 1329173426Srpaulo int32_t v; 1330173426Srpaulo 1331173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 1332173426Srpaulo v = (int32_t) val; 1333273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1334173426Srpaulo 1335173426Srpaulo return (error); 1336173426Srpaulo} 1337173426Srpaulo 1338173426Srpaulostatic int 1339173426Srpauloasmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 1340173426Srpaulo{ 1341173426Srpaulo device_t dev = (device_t) arg1; 1342173426Srpaulo uint8_t buf[6]; 1343173426Srpaulo int error; 1344173426Srpaulo int32_t v; 1345173426Srpaulo 1346271975Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); 1347173426Srpaulo v = buf[2]; 1348273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1349173426Srpaulo 1350173426Srpaulo return (error); 1351173426Srpaulo} 1352173426Srpaulo 1353173426Srpaulostatic int 1354173426Srpauloasmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 1355173426Srpaulo{ 1356173426Srpaulo device_t dev = (device_t) arg1; 1357173426Srpaulo uint8_t buf[6]; 1358173426Srpaulo int error; 1359173426Srpaulo int32_t v; 1360173426Srpaulo 1361271975Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf); 1362173426Srpaulo v = buf[2]; 1363273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1364195046Srpaulo 1365195046Srpaulo return (error); 1366195046Srpaulo} 1367195046Srpaulo 1368195046Srpaulostatic int 1369195046Srpauloasmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 1370195046Srpaulo{ 1371195046Srpaulo device_t dev = (device_t) arg1; 1372195046Srpaulo uint8_t buf[2]; 1373195046Srpaulo int error; 1374273773Shselasky int v; 1375273773Shselasky 1376298937Sadrian v = light_control; 1377273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1378273773Shselasky 1379173426Srpaulo if (error == 0 && req->newptr != NULL) { 1380273773Shselasky if (v < 0 || v > 255) 1381173426Srpaulo return (EINVAL); 1382298937Sadrian light_control = v; 1383298937Sadrian buf[0] = light_control; 1384173426Srpaulo buf[1] = 0x00; 1385271975Srpaulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 1386173426Srpaulo } 1387173426Srpaulo return (error); 1388173426Srpaulo} 1389