asmc.c revision 342246
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: stable/11/sys/dev/asmc/asmc.c 342246 2018-12-19 22:17:24Z dab $"); 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[] = { 158330467Seadler { 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 164330467Seadler { 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 176330467Seadler { 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 182330467Seadler { 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 188330467Seadler { 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 194330467Seadler { 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 200330467Seadler { 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 206330467Seadler { 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 }, 211330467Seadler 212330467Seadler { 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 218330467Seadler { 219298990Sadrian "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)", 220298990Sadrian ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 221298990Sadrian ASMC_MBP5_TEMPS, ASMC_MBP5_TEMPNAMES, ASMC_MBP5_TEMPDESCS 222298990Sadrian }, 223298990Sadrian 224330467Seadler { 225271975Srpaulo "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)", 226271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 227271975Srpaulo ASMC_MBP8_TEMPS, ASMC_MBP8_TEMPNAMES, ASMC_MBP8_TEMPDESCS 228271975Srpaulo }, 229271975Srpaulo 230330467Seadler { 231330467Seadler "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 232330467Seadler ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 233330467Seadler ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS 234330467Seadler }, 235330467Seadler 236330467Seadler { 237271975Srpaulo "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 238271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 239330467Seadler ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS 240271975Srpaulo }, 241330467Seadler 242173426Srpaulo /* The Mac Mini has no SMS */ 243330467Seadler { 244173426Srpaulo "Macmini1,1", "Apple SMC Mac Mini", 245173426Srpaulo NULL, NULL, NULL, 246173851Srpaulo ASMC_FAN_FUNCS, 247195046Srpaulo NULL, NULL, NULL, 248173426Srpaulo ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 249173426Srpaulo }, 250173426Srpaulo 251268303Sgavin /* The Mac Mini 3,1 has no SMS */ 252330467Seadler { 253268303Sgavin "Macmini3,1", "Apple SMC Mac Mini 3,1", 254268303Sgavin NULL, NULL, NULL, 255268303Sgavin ASMC_FAN_FUNCS, 256268303Sgavin NULL, NULL, NULL, 257268303Sgavin ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS 258268303Sgavin }, 259268303Sgavin 260178145Srpaulo /* Idem for the MacPro */ 261178145Srpaulo { 262178145Srpaulo "MacPro2", "Apple SMC Mac Pro (8-core)", 263178145Srpaulo NULL, NULL, NULL, 264178145Srpaulo ASMC_FAN_FUNCS, 265195046Srpaulo NULL, NULL, NULL, 266178145Srpaulo ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS 267178145Srpaulo }, 268182850Srpaulo 269271975Srpaulo /* Idem for the MacPro 2010*/ 270182850Srpaulo { 271271975Srpaulo "MacPro5,1", "Apple SMC MacPro (2010)", 272271975Srpaulo NULL, NULL, NULL, 273271975Srpaulo ASMC_FAN_FUNCS, 274271975Srpaulo NULL, NULL, NULL, 275271975Srpaulo ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS 276271975Srpaulo }, 277271975Srpaulo 278271975Srpaulo { 279182850Srpaulo "MacBookAir1,1", "Apple SMC MacBook Air", 280195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 281182850Srpaulo ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS 282330467Seadler }, 283182850Srpaulo 284271975Srpaulo { 285271975Srpaulo "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", 286271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 287271975Srpaulo ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS 288330467Seadler }, 289271975Srpaulo 290298937Sadrian { 291298937Sadrian "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)", 292298937Sadrian ASMC_SMS_FUNCS_DISABLED, 293330467Seadler ASMC_FAN_FUNCS2, 294298937Sadrian ASMC_LIGHT_FUNCS, 295298937Sadrian ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 296330467Seadler }, 297298937Sadrian 298298937Sadrian { 299298937Sadrian "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)", 300298937Sadrian ASMC_SMS_FUNCS_DISABLED, 301330467Seadler ASMC_FAN_FUNCS2, 302298937Sadrian ASMC_LIGHT_FUNCS, 303298937Sadrian ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 304330467Seadler }, 305298937Sadrian 306342246Sdab { 307342246Sdab "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)", 308342246Sdab ASMC_SMS_FUNCS_DISABLED, 309342246Sdab ASMC_FAN_FUNCS2, 310342246Sdab ASMC_LIGHT_FUNCS, 311342246Sdab ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 312342246Sdab }, 313330467Seadler 314342246Sdab { 315342246Sdab "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)", 316342246Sdab ASMC_SMS_FUNCS_DISABLED, 317342246Sdab ASMC_FAN_FUNCS2, 318342246Sdab ASMC_LIGHT_FUNCS, 319342246Sdab ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 320342246Sdab }, 321342246Sdab 322173426Srpaulo { NULL, NULL } 323173426Srpaulo}; 324173426Srpaulo 325173426Srpaulo#undef ASMC_SMS_FUNCS 326298937Sadrian#undef ASMC_SMS_FUNCS_DISABLED 327173426Srpaulo#undef ASMC_FAN_FUNCS 328298937Sadrian#undef ASMC_FAN_FUNCS2 329173426Srpaulo#undef ASMC_LIGHT_FUNCS 330173426Srpaulo 331173426Srpaulo/* 332173426Srpaulo * Driver methods. 333173426Srpaulo */ 334173426Srpaulostatic device_method_t asmc_methods[] = { 335173426Srpaulo DEVMETHOD(device_probe, asmc_probe), 336173426Srpaulo DEVMETHOD(device_attach, asmc_attach), 337173426Srpaulo DEVMETHOD(device_detach, asmc_detach), 338298937Sadrian DEVMETHOD(device_resume, asmc_resume), 339173426Srpaulo 340173426Srpaulo { 0, 0 } 341173426Srpaulo}; 342173426Srpaulo 343173426Srpaulostatic driver_t asmc_driver = { 344173426Srpaulo "asmc", 345173426Srpaulo asmc_methods, 346173426Srpaulo sizeof(struct asmc_softc) 347173426Srpaulo}; 348173426Srpaulo 349177972Srpaulo/* 350177972Srpaulo * Debugging 351177972Srpaulo */ 352177972Srpaulo#define _COMPONENT ACPI_OEM 353177972SrpauloACPI_MODULE_NAME("ASMC") 354177972Srpaulo#ifdef DEBUG 355177972Srpaulo#define ASMC_DPRINTF(str) device_printf(dev, str) 356177977Srpaulo#else 357330467Seadler#define ASMC_DPRINTF(str) 358177972Srpaulo#endif 359177972Srpaulo 360195046Srpaulo/* NB: can't be const */ 361177972Srpaulostatic char *asmc_ids[] = { "APP0001", NULL }; 362177972Srpaulo 363173426Srpaulostatic devclass_t asmc_devclass; 364173426Srpaulo 365298937Sadrianstatic unsigned int light_control = 0; 366298937Sadrian 367177972SrpauloDRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 368177972SrpauloMODULE_DEPEND(asmc, acpi, 1, 1, 1); 369173426Srpaulo 370173426Srpaulostatic struct asmc_model * 371173426Srpauloasmc_match(device_t dev) 372173426Srpaulo{ 373173426Srpaulo int i; 374173426Srpaulo char *model; 375173426Srpaulo 376273174Sdavide model = kern_getenv("smbios.system.product"); 377185433Srpaulo if (model == NULL) 378185433Srpaulo return (NULL); 379185433Srpaulo 380173426Srpaulo for (i = 0; asmc_models[i].smc_model; i++) { 381173426Srpaulo if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 382173426Srpaulo freeenv(model); 383173426Srpaulo return (&asmc_models[i]); 384173426Srpaulo } 385173426Srpaulo } 386173426Srpaulo freeenv(model); 387173426Srpaulo 388173426Srpaulo return (NULL); 389173426Srpaulo} 390173426Srpaulo 391173426Srpaulostatic int 392173426Srpauloasmc_probe(device_t dev) 393173426Srpaulo{ 394173426Srpaulo struct asmc_model *model; 395173426Srpaulo 396241885Seadler if (resource_disabled("asmc", 0)) 397241885Seadler return (ENXIO); 398177972Srpaulo if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL) 399177972Srpaulo return (ENXIO); 400330467Seadler 401173426Srpaulo model = asmc_match(dev); 402177972Srpaulo if (!model) { 403177972Srpaulo device_printf(dev, "model not recognized\n"); 404173426Srpaulo return (ENXIO); 405177972Srpaulo } 406173426Srpaulo device_set_desc(dev, model->smc_desc); 407173426Srpaulo 408173426Srpaulo return (BUS_PROBE_DEFAULT); 409173426Srpaulo} 410173426Srpaulo 411173426Srpaulostatic int 412173426Srpauloasmc_attach(device_t dev) 413173426Srpaulo{ 414173426Srpaulo int i, j; 415173426Srpaulo int ret; 416173426Srpaulo char name[2]; 417173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 418173426Srpaulo struct sysctl_ctx_list *sysctlctx; 419173426Srpaulo struct sysctl_oid *sysctlnode; 420173426Srpaulo struct asmc_model *model; 421173426Srpaulo 422177972Srpaulo sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 423177972Srpaulo &sc->sc_rid_port, RF_ACTIVE); 424177972Srpaulo if (sc->sc_ioport == NULL) { 425177972Srpaulo device_printf(dev, "unable to allocate IO port\n"); 426177972Srpaulo return (ENOMEM); 427177972Srpaulo } 428330467Seadler 429173426Srpaulo sysctlctx = device_get_sysctl_ctx(dev); 430173426Srpaulo sysctlnode = device_get_sysctl_tree(dev); 431330467Seadler 432173426Srpaulo model = asmc_match(dev); 433173426Srpaulo 434173426Srpaulo mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 435173426Srpaulo 436173426Srpaulo sc->sc_model = model; 437173426Srpaulo asmc_init(dev); 438173426Srpaulo 439173426Srpaulo /* 440173426Srpaulo * dev.asmc.n.fan.* tree. 441173426Srpaulo */ 442173426Srpaulo sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 443173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 444173426Srpaulo CTLFLAG_RD, 0, "Fan Root Tree"); 445173426Srpaulo 446173426Srpaulo for (i = 1; i <= sc->sc_nfan; i++) { 447173426Srpaulo j = i - 1; 448173426Srpaulo name[0] = '0' + j; 449173426Srpaulo name[1] = 0; 450173426Srpaulo sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 451173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 452173426Srpaulo OID_AUTO, name, CTLFLAG_RD, 0, 453173426Srpaulo "Fan Subtree"); 454173426Srpaulo 455173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 456173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 457271975Srpaulo OID_AUTO, "id", CTLTYPE_STRING | CTLFLAG_RD, 458271975Srpaulo dev, j, model->smc_fan_id, "I", 459271975Srpaulo "Fan ID"); 460271975Srpaulo 461271975Srpaulo SYSCTL_ADD_PROC(sysctlctx, 462271975Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 463173426Srpaulo OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD, 464173426Srpaulo dev, j, model->smc_fan_speed, "I", 465173426Srpaulo "Fan speed in RPM"); 466173426Srpaulo 467173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 468173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 469173426Srpaulo OID_AUTO, "safespeed", 470173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 471173426Srpaulo dev, j, model->smc_fan_safespeed, "I", 472173426Srpaulo "Fan safe speed in RPM"); 473173426Srpaulo 474173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 475173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 476173426Srpaulo OID_AUTO, "minspeed", 477271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 478173426Srpaulo dev, j, model->smc_fan_minspeed, "I", 479173426Srpaulo "Fan minimum speed in RPM"); 480173426Srpaulo 481173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 482173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 483173426Srpaulo OID_AUTO, "maxspeed", 484271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 485173426Srpaulo dev, j, model->smc_fan_maxspeed, "I", 486173426Srpaulo "Fan maximum speed in RPM"); 487173426Srpaulo 488173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 489173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 490173426Srpaulo OID_AUTO, "targetspeed", 491271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 492173426Srpaulo dev, j, model->smc_fan_targetspeed, "I", 493173426Srpaulo "Fan target speed in RPM"); 494173426Srpaulo } 495173426Srpaulo 496173426Srpaulo /* 497173426Srpaulo * dev.asmc.n.temp tree. 498173426Srpaulo */ 499173426Srpaulo sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 500173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 501173426Srpaulo CTLFLAG_RD, 0, "Temperature sensors"); 502173426Srpaulo 503173426Srpaulo for (i = 0; model->smc_temps[i]; i++) { 504173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 505173426Srpaulo SYSCTL_CHILDREN(sc->sc_temp_tree), 506173426Srpaulo OID_AUTO, model->smc_tempnames[i], 507173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 508173426Srpaulo dev, i, asmc_temp_sysctl, "I", 509173426Srpaulo model->smc_tempdescs[i]); 510173426Srpaulo } 511173426Srpaulo 512195046Srpaulo /* 513195046Srpaulo * dev.asmc.n.light 514195046Srpaulo */ 515195046Srpaulo if (model->smc_light_left) { 516195046Srpaulo sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 517195046Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 518195046Srpaulo CTLFLAG_RD, 0, "Keyboard backlight sensors"); 519330467Seadler 520195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 521195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 522195046Srpaulo OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD, 523195046Srpaulo dev, 0, model->smc_light_left, "I", 524195046Srpaulo "Keyboard backlight left sensor"); 525330467Seadler 526195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 527195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 528195046Srpaulo OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD, 529195046Srpaulo dev, 0, model->smc_light_right, "I", 530195046Srpaulo "Keyboard backlight right sensor"); 531195046Srpaulo 532195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 533195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 534196455Srpaulo OID_AUTO, "control", 535196455Srpaulo CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 536195046Srpaulo dev, 0, model->smc_light_control, "I", 537195046Srpaulo "Keyboard backlight brightness control"); 538195046Srpaulo } 539195046Srpaulo 540173426Srpaulo if (model->smc_sms_x == NULL) 541173426Srpaulo goto nosms; 542173426Srpaulo 543173426Srpaulo /* 544173426Srpaulo * dev.asmc.n.sms tree. 545173426Srpaulo */ 546173426Srpaulo sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 547173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 548173426Srpaulo CTLFLAG_RD, 0, "Sudden Motion Sensor"); 549173426Srpaulo 550173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 551173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 552173426Srpaulo OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD, 553173426Srpaulo dev, 0, model->smc_sms_x, "I", 554173426Srpaulo "Sudden Motion Sensor X value"); 555173426Srpaulo 556173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 557173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 558173426Srpaulo OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD, 559173426Srpaulo dev, 0, model->smc_sms_y, "I", 560173426Srpaulo "Sudden Motion Sensor Y value"); 561173426Srpaulo 562173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 563173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 564173426Srpaulo OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD, 565173426Srpaulo dev, 0, model->smc_sms_z, "I", 566173426Srpaulo "Sudden Motion Sensor Z value"); 567173426Srpaulo 568173426Srpaulo /* 569173426Srpaulo * Need a taskqueue to send devctl_notify() events 570173426Srpaulo * when the SMS interrupt us. 571173426Srpaulo * 572173426Srpaulo * PI_REALTIME is used due to the sensitivity of the 573173426Srpaulo * interrupt. An interrupt from the SMS means that the 574173426Srpaulo * disk heads should be turned off as quickly as possible. 575173426Srpaulo * 576173426Srpaulo * We only need to do this for the non INTR_FILTER case. 577173426Srpaulo */ 578173426Srpaulo sc->sc_sms_tq = NULL; 579173426Srpaulo#ifndef INTR_FILTER 580173426Srpaulo TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 581173426Srpaulo sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 582173426Srpaulo taskqueue_thread_enqueue, &sc->sc_sms_tq); 583173426Srpaulo taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 584173426Srpaulo device_get_nameunit(dev)); 585173426Srpaulo#endif 586173426Srpaulo /* 587173426Srpaulo * Allocate an IRQ for the SMS. 588173426Srpaulo */ 589177972Srpaulo sc->sc_rid_irq = 0; 590177972Srpaulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 591177972Srpaulo &sc->sc_rid_irq, RF_ACTIVE); 592177972Srpaulo if (sc->sc_irq == NULL) { 593173426Srpaulo device_printf(dev, "unable to allocate IRQ resource\n"); 594173426Srpaulo ret = ENXIO; 595173426Srpaulo goto err2; 596173426Srpaulo } 597173426Srpaulo 598330467Seadler ret = bus_setup_intr(dev, sc->sc_irq, 599173426Srpaulo INTR_TYPE_MISC | INTR_MPSAFE, 600173426Srpaulo#ifdef INTR_FILTER 601173426Srpaulo asmc_sms_intrfast, asmc_sms_handler, 602173426Srpaulo#else 603173426Srpaulo asmc_sms_intrfast, NULL, 604173426Srpaulo#endif 605173426Srpaulo dev, &sc->sc_cookie); 606173426Srpaulo 607173426Srpaulo if (ret) { 608173426Srpaulo device_printf(dev, "unable to setup SMS IRQ\n"); 609173426Srpaulo goto err1; 610173426Srpaulo } 611173426Srpaulonosms: 612173426Srpaulo return (0); 613173426Srpauloerr1: 614177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 615173426Srpauloerr2: 616177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 617177972Srpaulo sc->sc_ioport); 618173426Srpaulo mtx_destroy(&sc->sc_mtx); 619173426Srpaulo if (sc->sc_sms_tq) 620173426Srpaulo taskqueue_free(sc->sc_sms_tq); 621173426Srpaulo 622173426Srpaulo return (ret); 623173426Srpaulo} 624173426Srpaulo 625173426Srpaulostatic int 626173426Srpauloasmc_detach(device_t dev) 627173426Srpaulo{ 628173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 629173426Srpaulo 630173426Srpaulo if (sc->sc_sms_tq) { 631173426Srpaulo taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 632173426Srpaulo taskqueue_free(sc->sc_sms_tq); 633173426Srpaulo } 634173426Srpaulo if (sc->sc_cookie) 635177972Srpaulo bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 636177972Srpaulo if (sc->sc_irq) 637177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 638177972Srpaulo sc->sc_irq); 639177972Srpaulo if (sc->sc_ioport) 640177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 641177972Srpaulo sc->sc_ioport); 642173426Srpaulo mtx_destroy(&sc->sc_mtx); 643173426Srpaulo 644173426Srpaulo return (0); 645173426Srpaulo} 646173426Srpaulo 647298937Sadrianstatic int 648298937Sadrianasmc_resume(device_t dev) 649298937Sadrian{ 650298937Sadrian uint8_t buf[2]; 651298937Sadrian buf[0] = light_control; 652298937Sadrian buf[1] = 0x00; 653298937Sadrian asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 654298937Sadrian return (0); 655298937Sadrian} 656298937Sadrian 657298937Sadrian 658197190Srpaulo#ifdef DEBUG 659197190Srpaulovoid asmc_dumpall(device_t dev) 660197190Srpaulo{ 661197190Srpaulo int i; 662197190Srpaulo 663197190Srpaulo /* XXX magic number */ 664197190Srpaulo for (i=0; i < 0x100; i++) 665197190Srpaulo asmc_key_dump(dev, i); 666197190Srpaulo} 667197190Srpaulo#endif 668197190Srpaulo 669173426Srpaulostatic int 670173426Srpauloasmc_init(device_t dev) 671173426Srpaulo{ 672173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 673173426Srpaulo int i, error = 1; 674173426Srpaulo uint8_t buf[4]; 675173426Srpaulo 676173426Srpaulo if (sc->sc_model->smc_sms_x == NULL) 677173426Srpaulo goto nosms; 678173426Srpaulo 679173426Srpaulo /* 680298955Spfg * We are ready to receive interrupts from the SMS. 681173426Srpaulo */ 682173426Srpaulo buf[0] = 0x01; 683177972Srpaulo ASMC_DPRINTF(("intok key\n")); 684173426Srpaulo asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 685173426Srpaulo DELAY(50); 686173426Srpaulo 687330467Seadler /* 688173426Srpaulo * Initiate the polling intervals. 689173426Srpaulo */ 690173426Srpaulo buf[0] = 20; /* msecs */ 691177972Srpaulo ASMC_DPRINTF(("low int key\n")); 692173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 693173426Srpaulo DELAY(200); 694173426Srpaulo 695173426Srpaulo buf[0] = 20; /* msecs */ 696177972Srpaulo ASMC_DPRINTF(("high int key\n")); 697173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 698173426Srpaulo DELAY(200); 699173426Srpaulo 700173426Srpaulo buf[0] = 0x00; 701173426Srpaulo buf[1] = 0x60; 702177972Srpaulo ASMC_DPRINTF(("sms low key\n")); 703173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 704173426Srpaulo DELAY(200); 705173426Srpaulo 706173426Srpaulo buf[0] = 0x01; 707173426Srpaulo buf[1] = 0xc0; 708177972Srpaulo ASMC_DPRINTF(("sms high key\n")); 709173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 710173426Srpaulo DELAY(200); 711173426Srpaulo 712173426Srpaulo /* 713173426Srpaulo * I'm not sure what this key does, but it seems to be 714173426Srpaulo * required. 715173426Srpaulo */ 716173426Srpaulo buf[0] = 0x01; 717177972Srpaulo ASMC_DPRINTF(("sms flag key\n")); 718173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 719177979Srpaulo DELAY(100); 720173426Srpaulo 721197190Srpaulo sc->sc_sms_intr_works = 0; 722330467Seadler 723173426Srpaulo /* 724197190Srpaulo * Retry SMS initialization 1000 times 725197190Srpaulo * (takes approx. 2 seconds in worst case) 726173426Srpaulo */ 727197190Srpaulo for (i = 0; i < 1000; i++) { 728330467Seadler if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 729197190Srpaulo (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 730173426Srpaulo error = 0; 731197190Srpaulo sc->sc_sms_intr_works = 1; 732177977Srpaulo goto out; 733173426Srpaulo } 734173426Srpaulo buf[0] = ASMC_SMS_INIT1; 735173426Srpaulo buf[1] = ASMC_SMS_INIT2; 736177972Srpaulo ASMC_DPRINTF(("sms key\n")); 737173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 738173426Srpaulo DELAY(50); 739173426Srpaulo } 740177977Srpaulo device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 741173426Srpaulo 742177977Srpauloout: 743173426Srpaulo asmc_sms_calibrate(dev); 744173426Srpaulonosms: 745173426Srpaulo sc->sc_nfan = asmc_fan_count(dev); 746173426Srpaulo if (sc->sc_nfan > ASMC_MAXFANS) { 747173426Srpaulo device_printf(dev, "more than %d fans were detected. Please " 748173426Srpaulo "report this.\n", ASMC_MAXFANS); 749173426Srpaulo sc->sc_nfan = ASMC_MAXFANS; 750173426Srpaulo } 751173426Srpaulo 752173426Srpaulo if (bootverbose) { 753173426Srpaulo /* 754271975Srpaulo * The number of keys is a 32 bit buffer 755173426Srpaulo */ 756173426Srpaulo asmc_key_read(dev, ASMC_NKEYS, buf, 4); 757271975Srpaulo device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf)); 758330467Seadler } 759173426Srpaulo 760197190Srpaulo#ifdef DEBUG 761197190Srpaulo asmc_dumpall(dev); 762197190Srpaulo#endif 763197190Srpaulo 764173426Srpaulo return (error); 765173426Srpaulo} 766173426Srpaulo 767173426Srpaulo/* 768173426Srpaulo * We need to make sure that the SMC acks the byte sent. 769195046Srpaulo * Just wait up to (amount * 10) ms. 770173426Srpaulo */ 771173426Srpaulostatic int 772195046Srpauloasmc_wait_ack(device_t dev, uint8_t val, int amount) 773173426Srpaulo{ 774177972Srpaulo struct asmc_softc *sc = device_get_softc(dev); 775173426Srpaulo u_int i; 776173426Srpaulo 777173426Srpaulo val = val & ASMC_STATUS_MASK; 778173426Srpaulo 779195046Srpaulo for (i = 0; i < amount; i++) { 780177972Srpaulo if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 781173426Srpaulo return (0); 782173426Srpaulo DELAY(10); 783173426Srpaulo } 784173426Srpaulo 785195046Srpaulo return (1); 786195046Srpaulo} 787195046Srpaulo 788195046Srpaulo/* 789195046Srpaulo * We need to make sure that the SMC acks the byte sent. 790195046Srpaulo * Just wait up to 100 ms. 791195046Srpaulo */ 792195046Srpaulostatic int 793195046Srpauloasmc_wait(device_t dev, uint8_t val) 794195046Srpaulo{ 795195046Srpaulo struct asmc_softc *sc; 796195046Srpaulo 797195046Srpaulo if (asmc_wait_ack(dev, val, 1000) == 0) 798195046Srpaulo return (0); 799195046Srpaulo 800195046Srpaulo sc = device_get_softc(dev); 801195046Srpaulo val = val & ASMC_STATUS_MASK; 802195046Srpaulo 803195046Srpaulo#ifdef DEBUG 804173426Srpaulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 805177972Srpaulo ASMC_CMDPORT_READ(sc)); 806330467Seadler#endif 807195046Srpaulo return (1); 808195046Srpaulo} 809330467Seadler 810195046Srpaulo/* 811195046Srpaulo * Send the given command, retrying up to 10 times if 812195046Srpaulo * the acknowledgement fails. 813195046Srpaulo */ 814195046Srpaulostatic int 815195046Srpauloasmc_command(device_t dev, uint8_t command) { 816195046Srpaulo 817195046Srpaulo int i; 818195046Srpaulo struct asmc_softc *sc = device_get_softc(dev); 819195046Srpaulo 820195046Srpaulo for (i=0; i < 10; i++) { 821195046Srpaulo ASMC_CMDPORT_WRITE(sc, command); 822195046Srpaulo if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 823195046Srpaulo return (0); 824195046Srpaulo } 825195046Srpaulo } 826195046Srpaulo 827195046Srpaulo#ifdef DEBUG 828195046Srpaulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 829195046Srpaulo ASMC_CMDPORT_READ(sc)); 830195046Srpaulo#endif 831173426Srpaulo return (1); 832173426Srpaulo} 833173426Srpaulo 834173426Srpaulostatic int 835173426Srpauloasmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 836173426Srpaulo{ 837195046Srpaulo int i, error = 1, try = 0; 838173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 839173426Srpaulo 840173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 841173426Srpaulo 842195046Srpaulobegin: 843195046Srpaulo if (asmc_command(dev, ASMC_CMDREAD)) 844173426Srpaulo goto out; 845173426Srpaulo 846173426Srpaulo for (i = 0; i < 4; i++) { 847177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 848173426Srpaulo if (asmc_wait(dev, 0x04)) 849173426Srpaulo goto out; 850173426Srpaulo } 851173426Srpaulo 852177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 853173426Srpaulo 854173426Srpaulo for (i = 0; i < len; i++) { 855173426Srpaulo if (asmc_wait(dev, 0x05)) 856173426Srpaulo goto out; 857177972Srpaulo buf[i] = ASMC_DATAPORT_READ(sc); 858173426Srpaulo } 859173426Srpaulo 860173426Srpaulo error = 0; 861173426Srpauloout: 862195046Srpaulo if (error) { 863195046Srpaulo if (++try < 10) goto begin; 864195046Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 865195046Srpaulo __func__, key, try); 866195046Srpaulo } 867195046Srpaulo 868173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 869173426Srpaulo 870173426Srpaulo return (error); 871173426Srpaulo} 872173426Srpaulo 873197190Srpaulo#ifdef DEBUG 874173426Srpaulostatic int 875197190Srpauloasmc_key_dump(device_t dev, int number) 876197190Srpaulo{ 877197190Srpaulo struct asmc_softc *sc = device_get_softc(dev); 878197190Srpaulo char key[5] = { 0 }; 879197190Srpaulo char type[7] = { 0 }; 880197190Srpaulo uint8_t index[4]; 881197190Srpaulo uint8_t v[32]; 882197190Srpaulo uint8_t maxlen; 883197190Srpaulo int i, error = 1, try = 0; 884197190Srpaulo 885197190Srpaulo mtx_lock_spin(&sc->sc_mtx); 886197190Srpaulo 887197190Srpaulo index[0] = (number >> 24) & 0xff; 888197190Srpaulo index[1] = (number >> 16) & 0xff; 889197190Srpaulo index[2] = (number >> 8) & 0xff; 890197190Srpaulo index[3] = (number) & 0xff; 891197190Srpaulo 892197190Srpaulobegin: 893197190Srpaulo if (asmc_command(dev, 0x12)) 894197190Srpaulo goto out; 895197190Srpaulo 896197190Srpaulo for (i = 0; i < 4; i++) { 897197190Srpaulo ASMC_DATAPORT_WRITE(sc, index[i]); 898197190Srpaulo if (asmc_wait(dev, 0x04)) 899197190Srpaulo goto out; 900197190Srpaulo } 901197190Srpaulo 902197190Srpaulo ASMC_DATAPORT_WRITE(sc, 4); 903197190Srpaulo 904197190Srpaulo for (i = 0; i < 4; i++) { 905197190Srpaulo if (asmc_wait(dev, 0x05)) 906197190Srpaulo goto out; 907197190Srpaulo key[i] = ASMC_DATAPORT_READ(sc); 908197190Srpaulo } 909197190Srpaulo 910197190Srpaulo /* get type */ 911197190Srpaulo if (asmc_command(dev, 0x13)) 912197190Srpaulo goto out; 913197190Srpaulo 914197190Srpaulo for (i = 0; i < 4; i++) { 915197190Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 916197190Srpaulo if (asmc_wait(dev, 0x04)) 917197190Srpaulo goto out; 918197190Srpaulo } 919197190Srpaulo 920197190Srpaulo ASMC_DATAPORT_WRITE(sc, 6); 921197190Srpaulo 922197190Srpaulo for (i = 0; i < 6; i++) { 923197190Srpaulo if (asmc_wait(dev, 0x05)) 924197190Srpaulo goto out; 925197190Srpaulo type[i] = ASMC_DATAPORT_READ(sc); 926197190Srpaulo } 927197190Srpaulo 928197190Srpaulo error = 0; 929197190Srpauloout: 930197190Srpaulo if (error) { 931197190Srpaulo if (++try < 10) goto begin; 932197190Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 933197190Srpaulo __func__, key, try); 934197190Srpaulo mtx_unlock_spin(&sc->sc_mtx); 935197190Srpaulo } 936197190Srpaulo else { 937197190Srpaulo char buf[1024]; 938197190Srpaulo char buf2[8]; 939197190Srpaulo mtx_unlock_spin(&sc->sc_mtx); 940197190Srpaulo maxlen = type[0]; 941197190Srpaulo type[0] = ' '; 942197190Srpaulo type[5] = 0; 943330467Seadler if (maxlen > sizeof(v)) { 944197202Srpaulo device_printf(dev, 945197202Srpaulo "WARNING: cropping maxlen from %d to %zu\n", 946197202Srpaulo maxlen, sizeof(v)); 947197190Srpaulo maxlen = sizeof(v); 948197190Srpaulo } 949197190Srpaulo for (i = 0; i < sizeof(v); i++) { 950197190Srpaulo v[i] = 0; 951197190Srpaulo } 952197190Srpaulo asmc_key_read(dev, key, v, maxlen); 953197190Srpaulo snprintf(buf, sizeof(buf), "key %d is: %s, type %s " 954197190Srpaulo "(len %d), data", number, key, type, maxlen); 955197190Srpaulo for (i = 0; i < maxlen; i++) { 956298937Sadrian snprintf(buf2, sizeof(buf2), " %02x", v[i]); 957197190Srpaulo strlcat(buf, buf2, sizeof(buf)); 958197190Srpaulo } 959197190Srpaulo strlcat(buf, " \n", sizeof(buf)); 960242826Srdivacky device_printf(dev, "%s", buf); 961197190Srpaulo } 962197190Srpaulo 963197190Srpaulo return (error); 964197190Srpaulo} 965197190Srpaulo#endif 966197190Srpaulo 967197190Srpaulostatic int 968173426Srpauloasmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 969173426Srpaulo{ 970195046Srpaulo int i, error = -1, try = 0; 971173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 972173426Srpaulo 973173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 974173426Srpaulo 975195046Srpaulobegin: 976177972Srpaulo ASMC_DPRINTF(("cmd port: cmd write\n")); 977195046Srpaulo if (asmc_command(dev, ASMC_CMDWRITE)) 978173426Srpaulo goto out; 979173426Srpaulo 980177972Srpaulo ASMC_DPRINTF(("data port: key\n")); 981173426Srpaulo for (i = 0; i < 4; i++) { 982177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 983173426Srpaulo if (asmc_wait(dev, 0x04)) 984173426Srpaulo goto out; 985173426Srpaulo } 986177972Srpaulo ASMC_DPRINTF(("data port: length\n")); 987177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 988173426Srpaulo 989177972Srpaulo ASMC_DPRINTF(("data port: buffer\n")); 990173426Srpaulo for (i = 0; i < len; i++) { 991173426Srpaulo if (asmc_wait(dev, 0x04)) 992173426Srpaulo goto out; 993177972Srpaulo ASMC_DATAPORT_WRITE(sc, buf[i]); 994173426Srpaulo } 995173426Srpaulo 996173426Srpaulo error = 0; 997173426Srpauloout: 998195046Srpaulo if (error) { 999195046Srpaulo if (++try < 10) goto begin; 1000195046Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 1001195046Srpaulo __func__, key, try); 1002195046Srpaulo } 1003195046Srpaulo 1004173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 1005173426Srpaulo 1006173426Srpaulo return (error); 1007173426Srpaulo 1008173426Srpaulo} 1009173426Srpaulo 1010173426Srpaulo/* 1011173426Srpaulo * Fan control functions. 1012173426Srpaulo */ 1013173426Srpaulostatic int 1014173426Srpauloasmc_fan_count(device_t dev) 1015173426Srpaulo{ 1016173426Srpaulo uint8_t buf[1]; 1017173426Srpaulo 1018271975Srpaulo if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) < 0) 1019173426Srpaulo return (-1); 1020173426Srpaulo 1021173426Srpaulo return (buf[0]); 1022173426Srpaulo} 1023173426Srpaulo 1024173426Srpaulostatic int 1025173426Srpauloasmc_fan_getvalue(device_t dev, const char *key, int fan) 1026173426Srpaulo{ 1027173426Srpaulo int speed; 1028173426Srpaulo uint8_t buf[2]; 1029173426Srpaulo char fankey[5]; 1030173426Srpaulo 1031173426Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1032271975Srpaulo if (asmc_key_read(dev, fankey, buf, sizeof buf) < 0) 1033173426Srpaulo return (-1); 1034173426Srpaulo speed = (buf[0] << 6) | (buf[1] >> 2); 1035173426Srpaulo 1036173426Srpaulo return (speed); 1037173426Srpaulo} 1038173426Srpaulo 1039271975Srpaulostatic char* 1040293193Suqsasmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen) 1041271975Srpaulo{ 1042271975Srpaulo char fankey[5]; 1043271975Srpaulo char* desc; 1044271975Srpaulo 1045271975Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1046293193Suqs if (asmc_key_read(dev, fankey, buf, buflen) < 0) 1047271975Srpaulo return (NULL); 1048271975Srpaulo desc = buf+4; 1049271975Srpaulo 1050271975Srpaulo return (desc); 1051271975Srpaulo} 1052271975Srpaulo 1053173426Srpaulostatic int 1054271975Srpauloasmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 1055271975Srpaulo{ 1056271975Srpaulo uint8_t buf[2]; 1057271975Srpaulo char fankey[5]; 1058271975Srpaulo 1059271975Srpaulo speed *= 4; 1060271975Srpaulo 1061271975Srpaulo buf[0] = speed>>8; 1062271975Srpaulo buf[1] = speed; 1063271975Srpaulo 1064271975Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1065271975Srpaulo if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0) 1066271975Srpaulo return (-1); 1067271975Srpaulo 1068271975Srpaulo return (0); 1069271975Srpaulo} 1070271975Srpaulo 1071271975Srpaulostatic int 1072173426Srpauloasmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 1073173426Srpaulo{ 1074173426Srpaulo device_t dev = (device_t) arg1; 1075173426Srpaulo int fan = arg2; 1076173426Srpaulo int error; 1077173426Srpaulo int32_t v; 1078173426Srpaulo 1079173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 1080173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1081173426Srpaulo 1082173426Srpaulo return (error); 1083173426Srpaulo} 1084173426Srpaulo 1085173426Srpaulostatic int 1086271975Srpauloasmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 1087271975Srpaulo{ 1088293193Suqs uint8_t buf[16]; 1089271975Srpaulo device_t dev = (device_t) arg1; 1090271975Srpaulo int fan = arg2; 1091271975Srpaulo int error = true; 1092271975Srpaulo char* desc; 1093271975Srpaulo 1094293193Suqs desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); 1095271975Srpaulo 1096271975Srpaulo if (desc != NULL) 1097271975Srpaulo error = sysctl_handle_string(oidp, desc, 0, req); 1098271975Srpaulo 1099271975Srpaulo return (error); 1100271975Srpaulo} 1101271975Srpaulo 1102271975Srpaulostatic int 1103173426Srpauloasmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 1104173426Srpaulo{ 1105173426Srpaulo device_t dev = (device_t) arg1; 1106173426Srpaulo int fan = arg2; 1107173426Srpaulo int error; 1108173426Srpaulo int32_t v; 1109173426Srpaulo 1110173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 1111173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1112173426Srpaulo 1113173426Srpaulo return (error); 1114173426Srpaulo} 1115173426Srpaulo 1116173426Srpaulo 1117173426Srpaulostatic int 1118173426Srpauloasmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 1119173426Srpaulo{ 1120173426Srpaulo device_t dev = (device_t) arg1; 1121173426Srpaulo int fan = arg2; 1122173426Srpaulo int error; 1123173426Srpaulo int32_t v; 1124173426Srpaulo 1125173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 1126173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1127173426Srpaulo 1128271975Srpaulo if (error == 0 && req->newptr != NULL) { 1129273773Shselasky unsigned int newspeed = v; 1130271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 1131271975Srpaulo } 1132271975Srpaulo 1133173426Srpaulo return (error); 1134173426Srpaulo} 1135173426Srpaulo 1136173426Srpaulostatic int 1137173426Srpauloasmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 1138173426Srpaulo{ 1139173426Srpaulo device_t dev = (device_t) arg1; 1140173426Srpaulo int fan = arg2; 1141173426Srpaulo int error; 1142173426Srpaulo int32_t v; 1143173426Srpaulo 1144173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 1145173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1146173426Srpaulo 1147271975Srpaulo if (error == 0 && req->newptr != NULL) { 1148273773Shselasky unsigned int newspeed = v; 1149271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 1150271975Srpaulo } 1151271975Srpaulo 1152173426Srpaulo return (error); 1153173426Srpaulo} 1154173426Srpaulo 1155173426Srpaulostatic int 1156173426Srpauloasmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 1157173426Srpaulo{ 1158173426Srpaulo device_t dev = (device_t) arg1; 1159173426Srpaulo int fan = arg2; 1160173426Srpaulo int error; 1161173426Srpaulo int32_t v; 1162173426Srpaulo 1163173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 1164173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1165173426Srpaulo 1166271975Srpaulo if (error == 0 && req->newptr != NULL) { 1167273773Shselasky unsigned int newspeed = v; 1168271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 1169271975Srpaulo } 1170271975Srpaulo 1171173426Srpaulo return (error); 1172173426Srpaulo} 1173173426Srpaulo 1174173426Srpaulo/* 1175173426Srpaulo * Temperature functions. 1176173426Srpaulo */ 1177173426Srpaulostatic int 1178173426Srpauloasmc_temp_getvalue(device_t dev, const char *key) 1179173426Srpaulo{ 1180173426Srpaulo uint8_t buf[2]; 1181173426Srpaulo 1182173426Srpaulo /* 1183173426Srpaulo * Check for invalid temperatures. 1184173426Srpaulo */ 1185271975Srpaulo if (asmc_key_read(dev, key, buf, sizeof buf) < 0) 1186173426Srpaulo return (-1); 1187173426Srpaulo 1188173426Srpaulo return (buf[0]); 1189173426Srpaulo} 1190173426Srpaulo 1191173426Srpaulostatic int 1192173426Srpauloasmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 1193173426Srpaulo{ 1194173426Srpaulo device_t dev = (device_t) arg1; 1195173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1196173426Srpaulo int error, val; 1197173426Srpaulo 1198173426Srpaulo val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 1199173426Srpaulo error = sysctl_handle_int(oidp, &val, 0, req); 1200173426Srpaulo 1201173426Srpaulo return (error); 1202173426Srpaulo} 1203173426Srpaulo 1204173426Srpaulo/* 1205173426Srpaulo * Sudden Motion Sensor functions. 1206173426Srpaulo */ 1207173426Srpaulostatic int 1208173426Srpauloasmc_sms_read(device_t dev, const char *key, int16_t *val) 1209173426Srpaulo{ 1210173426Srpaulo uint8_t buf[2]; 1211173426Srpaulo int error; 1212173426Srpaulo 1213330467Seadler /* no need to do locking here as asmc_key_read() already does it */ 1214173426Srpaulo switch (key[3]) { 1215173426Srpaulo case 'X': 1216173426Srpaulo case 'Y': 1217173426Srpaulo case 'Z': 1218271975Srpaulo error = asmc_key_read(dev, key, buf, sizeof buf); 1219173426Srpaulo break; 1220173426Srpaulo default: 1221173426Srpaulo device_printf(dev, "%s called with invalid argument %s\n", 1222173426Srpaulo __func__, key); 1223173426Srpaulo error = 1; 1224173426Srpaulo goto out; 1225173426Srpaulo } 1226173426Srpaulo *val = ((int16_t)buf[0] << 8) | buf[1]; 1227173426Srpauloout: 1228173426Srpaulo return (error); 1229173426Srpaulo} 1230173426Srpaulo 1231173426Srpaulostatic void 1232173426Srpauloasmc_sms_calibrate(device_t dev) 1233173426Srpaulo{ 1234173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1235173426Srpaulo 1236173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 1237173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 1238173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 1239173426Srpaulo} 1240173426Srpaulo 1241173426Srpaulostatic int 1242173426Srpauloasmc_sms_intrfast(void *arg) 1243173426Srpaulo{ 1244173426Srpaulo uint8_t type; 1245173426Srpaulo device_t dev = (device_t) arg; 1246173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1247197190Srpaulo if (!sc->sc_sms_intr_works) 1248197190Srpaulo return (FILTER_HANDLED); 1249173426Srpaulo 1250173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 1251177972Srpaulo type = ASMC_INTPORT_READ(sc); 1252173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 1253173426Srpaulo 1254173426Srpaulo sc->sc_sms_intrtype = type; 1255173426Srpaulo asmc_sms_printintr(dev, type); 1256173426Srpaulo 1257173426Srpaulo#ifdef INTR_FILTER 1258173426Srpaulo return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED); 1259173426Srpaulo#else 1260173426Srpaulo taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 1261173426Srpaulo#endif 1262173426Srpaulo return (FILTER_HANDLED); 1263173426Srpaulo} 1264173426Srpaulo 1265173426Srpaulo#ifdef INTR_FILTER 1266173426Srpaulostatic void 1267173426Srpauloasmc_sms_handler(void *arg) 1268173426Srpaulo{ 1269173426Srpaulo struct asmc_softc *sc = device_get_softc(arg); 1270330467Seadler 1271173426Srpaulo asmc_sms_task(sc, 0); 1272173426Srpaulo} 1273173426Srpaulo#endif 1274173426Srpaulo 1275173426Srpaulo 1276173426Srpaulostatic void 1277173426Srpauloasmc_sms_printintr(device_t dev, uint8_t type) 1278173426Srpaulo{ 1279173426Srpaulo 1280173426Srpaulo switch (type) { 1281173426Srpaulo case ASMC_SMS_INTFF: 1282173426Srpaulo device_printf(dev, "WARNING: possible free fall!\n"); 1283173426Srpaulo break; 1284173426Srpaulo case ASMC_SMS_INTHA: 1285173426Srpaulo device_printf(dev, "WARNING: high acceleration detected!\n"); 1286173426Srpaulo break; 1287173426Srpaulo case ASMC_SMS_INTSH: 1288173426Srpaulo device_printf(dev, "WARNING: possible shock!\n"); 1289173426Srpaulo break; 1290173426Srpaulo default: 1291173426Srpaulo device_printf(dev, "%s unknown interrupt\n", __func__); 1292173426Srpaulo } 1293173426Srpaulo} 1294173426Srpaulo 1295173426Srpaulostatic void 1296173426Srpauloasmc_sms_task(void *arg, int pending) 1297173426Srpaulo{ 1298173426Srpaulo struct asmc_softc *sc = (struct asmc_softc *)arg; 1299173426Srpaulo char notify[16]; 1300173426Srpaulo int type; 1301173426Srpaulo 1302173426Srpaulo switch (sc->sc_sms_intrtype) { 1303173426Srpaulo case ASMC_SMS_INTFF: 1304173426Srpaulo type = 2; 1305173426Srpaulo break; 1306173426Srpaulo case ASMC_SMS_INTHA: 1307173426Srpaulo type = 1; 1308173426Srpaulo break; 1309173426Srpaulo case ASMC_SMS_INTSH: 1310173426Srpaulo type = 0; 1311173426Srpaulo break; 1312173426Srpaulo default: 1313173426Srpaulo type = 255; 1314173426Srpaulo } 1315173426Srpaulo 1316173426Srpaulo snprintf(notify, sizeof(notify), " notify=0x%x", type); 1317330467Seadler devctl_notify("ACPI", "asmc", "SMS", notify); 1318173426Srpaulo} 1319173426Srpaulo 1320173426Srpaulostatic int 1321173426Srpauloasmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 1322173426Srpaulo{ 1323173426Srpaulo device_t dev = (device_t) arg1; 1324173426Srpaulo int error; 1325173426Srpaulo int16_t val; 1326173426Srpaulo int32_t v; 1327173426Srpaulo 1328173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 1329173426Srpaulo v = (int32_t) val; 1330173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1331173426Srpaulo 1332173426Srpaulo return (error); 1333173426Srpaulo} 1334173426Srpaulo 1335173426Srpaulostatic int 1336173426Srpauloasmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 1337173426Srpaulo{ 1338173426Srpaulo device_t dev = (device_t) arg1; 1339173426Srpaulo int error; 1340173426Srpaulo int16_t val; 1341173426Srpaulo int32_t v; 1342173426Srpaulo 1343173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 1344173426Srpaulo v = (int32_t) val; 1345173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1346173426Srpaulo 1347173426Srpaulo return (error); 1348173426Srpaulo} 1349173426Srpaulo 1350173426Srpaulostatic int 1351173426Srpauloasmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 1352173426Srpaulo{ 1353173426Srpaulo device_t dev = (device_t) arg1; 1354173426Srpaulo int error; 1355173426Srpaulo int16_t val; 1356173426Srpaulo int32_t v; 1357173426Srpaulo 1358173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 1359173426Srpaulo v = (int32_t) val; 1360273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1361173426Srpaulo 1362173426Srpaulo return (error); 1363173426Srpaulo} 1364173426Srpaulo 1365173426Srpaulostatic int 1366173426Srpauloasmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 1367173426Srpaulo{ 1368173426Srpaulo device_t dev = (device_t) arg1; 1369173426Srpaulo uint8_t buf[6]; 1370173426Srpaulo int error; 1371173426Srpaulo int32_t v; 1372173426Srpaulo 1373271975Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); 1374173426Srpaulo v = buf[2]; 1375273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1376173426Srpaulo 1377173426Srpaulo return (error); 1378173426Srpaulo} 1379173426Srpaulo 1380173426Srpaulostatic int 1381173426Srpauloasmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 1382173426Srpaulo{ 1383173426Srpaulo device_t dev = (device_t) arg1; 1384173426Srpaulo uint8_t buf[6]; 1385173426Srpaulo int error; 1386173426Srpaulo int32_t v; 1387330467Seadler 1388271975Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf); 1389173426Srpaulo v = buf[2]; 1390273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1391330467Seadler 1392195046Srpaulo return (error); 1393195046Srpaulo} 1394195046Srpaulo 1395195046Srpaulostatic int 1396195046Srpauloasmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 1397195046Srpaulo{ 1398195046Srpaulo device_t dev = (device_t) arg1; 1399195046Srpaulo uint8_t buf[2]; 1400195046Srpaulo int error; 1401273773Shselasky int v; 1402273773Shselasky 1403298937Sadrian v = light_control; 1404273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1405273773Shselasky 1406173426Srpaulo if (error == 0 && req->newptr != NULL) { 1407273773Shselasky if (v < 0 || v > 255) 1408173426Srpaulo return (EINVAL); 1409298937Sadrian light_control = v; 1410298937Sadrian buf[0] = light_control; 1411173426Srpaulo buf[1] = 0x00; 1412271975Srpaulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 1413173426Srpaulo } 1414173426Srpaulo return (error); 1415173426Srpaulo} 1416