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 344889 2019-03-07 15:31:32Z 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 157343151Sdab#define ASMC_LIGHT_FUNCS_DISABLED NULL, NULL, NULL 158343151Sdab 159173426Srpaulostruct asmc_model asmc_models[] = { 160330467Seadler { 161173426Srpaulo "MacBook1,1", "Apple SMC MacBook Core Duo", 162195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 163173426Srpaulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 164173426Srpaulo }, 165173426Srpaulo 166330467Seadler { 167173426Srpaulo "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 168195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 169173426Srpaulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 170173426Srpaulo }, 171173426Srpaulo 172298937Sadrian { 173298937Sadrian "MacBook3,1", "Apple SMC MacBook Core 2 Duo", 174298937Sadrian ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 175298937Sadrian ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS 176298937Sadrian }, 177298937Sadrian 178330467Seadler { 179173426Srpaulo "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 180173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 181173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 182173426Srpaulo }, 183173426Srpaulo 184330467Seadler { 185173426Srpaulo "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 186173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 187173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 188173426Srpaulo }, 189173426Srpaulo 190330467Seadler { 191173426Srpaulo "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 192173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 193173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 194173426Srpaulo }, 195173426Srpaulo 196330467Seadler { 197173426Srpaulo "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 198173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 199173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 200173426Srpaulo }, 201173426Srpaulo 202330467Seadler { 203173426Srpaulo "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 204173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 205173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 206173426Srpaulo }, 207173426Srpaulo 208330467Seadler { 209173426Srpaulo "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 210173426Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 211173426Srpaulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 212173426Srpaulo }, 213330467Seadler 214330467Seadler { 215195046Srpaulo "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)", 216195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 217195046Srpaulo ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS 218195046Srpaulo }, 219271975Srpaulo 220330467Seadler { 221298990Sadrian "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)", 222298990Sadrian ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 223298990Sadrian ASMC_MBP5_TEMPS, ASMC_MBP5_TEMPNAMES, ASMC_MBP5_TEMPDESCS 224298990Sadrian }, 225298990Sadrian 226330467Seadler { 227342269Sdab "MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)", 228342269Sdab ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 229342269Sdab ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS 230342269Sdab }, 231342269Sdab 232342269Sdab { 233271975Srpaulo "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)", 234271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 235342269Sdab ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS 236271975Srpaulo }, 237271975Srpaulo 238330467Seadler { 239343149Sdab "MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012)", 240343149Sdab ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 241343149Sdab ASMC_MBP9_TEMPS, ASMC_MBP9_TEMPNAMES, ASMC_MBP9_TEMPDESCS 242343149Sdab }, 243343149Sdab 244343149Sdab { 245330467Seadler "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 246330467Seadler ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 247330467Seadler ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS 248330467Seadler }, 249330467Seadler 250330467Seadler { 251271975Srpaulo "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 252271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 253330467Seadler ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS 254271975Srpaulo }, 255330467Seadler 256173426Srpaulo /* The Mac Mini has no SMS */ 257330467Seadler { 258173426Srpaulo "Macmini1,1", "Apple SMC Mac Mini", 259173426Srpaulo NULL, NULL, NULL, 260173851Srpaulo ASMC_FAN_FUNCS, 261195046Srpaulo NULL, NULL, NULL, 262173426Srpaulo ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 263173426Srpaulo }, 264173426Srpaulo 265344889Sdab /* The Mac Mini 2,1 has no SMS */ 266344889Sdab { 267344889Sdab "Macmini2,1", "Apple SMC Mac Mini 2,1", 268344889Sdab ASMC_SMS_FUNCS_DISABLED, 269344889Sdab ASMC_FAN_FUNCS, 270344889Sdab ASMC_LIGHT_FUNCS_DISABLED, 271344889Sdab ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS 272344889Sdab }, 273344889Sdab 274268303Sgavin /* The Mac Mini 3,1 has no SMS */ 275330467Seadler { 276268303Sgavin "Macmini3,1", "Apple SMC Mac Mini 3,1", 277268303Sgavin NULL, NULL, NULL, 278268303Sgavin ASMC_FAN_FUNCS, 279268303Sgavin NULL, NULL, NULL, 280268303Sgavin ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS 281268303Sgavin }, 282268303Sgavin 283343151Sdab /* The Mac Mini 4,1 (Mid-2010) has no SMS */ 284343151Sdab { 285343151Sdab "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)", 286343151Sdab ASMC_SMS_FUNCS_DISABLED, 287343151Sdab ASMC_FAN_FUNCS, 288343151Sdab ASMC_LIGHT_FUNCS_DISABLED, 289343151Sdab ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS 290343151Sdab }, 291343151Sdab 292342752Sdab /* The Mac Mini 5,2 has no SMS */ 293342752Sdab { 294342752Sdab "Macmini5,2", "Apple SMC Mac Mini 5,2", 295342752Sdab NULL, NULL, NULL, 296342752Sdab ASMC_FAN_FUNCS2, 297342752Sdab NULL, NULL, NULL, 298342752Sdab ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS 299342752Sdab }, 300342752Sdab 301342755Sdab /* Idem for the Mac Pro "Quad Core" (original) */ 302178145Srpaulo { 303342755Sdab "MacPro1,1", "Apple SMC Mac Pro (Quad Core)", 304342755Sdab NULL, NULL, NULL, 305342755Sdab ASMC_FAN_FUNCS, 306342755Sdab NULL, NULL, NULL, 307342755Sdab ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS 308342755Sdab }, 309342755Sdab 310342755Sdab /* Idem for the Mac Pro (8-core) */ 311342755Sdab { 312178145Srpaulo "MacPro2", "Apple SMC Mac Pro (8-core)", 313178145Srpaulo NULL, NULL, NULL, 314178145Srpaulo ASMC_FAN_FUNCS, 315195046Srpaulo NULL, NULL, NULL, 316342755Sdab ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS 317178145Srpaulo }, 318182850Srpaulo 319271975Srpaulo /* Idem for the MacPro 2010*/ 320182850Srpaulo { 321271975Srpaulo "MacPro5,1", "Apple SMC MacPro (2010)", 322271975Srpaulo NULL, NULL, NULL, 323271975Srpaulo ASMC_FAN_FUNCS, 324271975Srpaulo NULL, NULL, NULL, 325271975Srpaulo ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS 326271975Srpaulo }, 327271975Srpaulo 328271975Srpaulo { 329182850Srpaulo "MacBookAir1,1", "Apple SMC MacBook Air", 330195046Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 331182850Srpaulo ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS 332330467Seadler }, 333182850Srpaulo 334271975Srpaulo { 335271975Srpaulo "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", 336271975Srpaulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 337271975Srpaulo ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS 338330467Seadler }, 339271975Srpaulo 340298937Sadrian { 341298937Sadrian "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)", 342298937Sadrian ASMC_SMS_FUNCS_DISABLED, 343330467Seadler ASMC_FAN_FUNCS2, 344298937Sadrian ASMC_LIGHT_FUNCS, 345298937Sadrian ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 346330467Seadler }, 347298937Sadrian 348298937Sadrian { 349298937Sadrian "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)", 350298937Sadrian ASMC_SMS_FUNCS_DISABLED, 351330467Seadler ASMC_FAN_FUNCS2, 352298937Sadrian ASMC_LIGHT_FUNCS, 353298937Sadrian ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 354330467Seadler }, 355298937Sadrian 356342246Sdab { 357342246Sdab "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)", 358342246Sdab ASMC_SMS_FUNCS_DISABLED, 359342246Sdab ASMC_FAN_FUNCS2, 360342246Sdab ASMC_LIGHT_FUNCS, 361342246Sdab ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 362342246Sdab }, 363330467Seadler 364342246Sdab { 365342246Sdab "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)", 366342246Sdab ASMC_SMS_FUNCS_DISABLED, 367342246Sdab ASMC_FAN_FUNCS2, 368342246Sdab ASMC_LIGHT_FUNCS, 369342246Sdab ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 370342246Sdab }, 371342246Sdab 372173426Srpaulo { NULL, NULL } 373173426Srpaulo}; 374173426Srpaulo 375173426Srpaulo#undef ASMC_SMS_FUNCS 376298937Sadrian#undef ASMC_SMS_FUNCS_DISABLED 377173426Srpaulo#undef ASMC_FAN_FUNCS 378298937Sadrian#undef ASMC_FAN_FUNCS2 379173426Srpaulo#undef ASMC_LIGHT_FUNCS 380173426Srpaulo 381173426Srpaulo/* 382173426Srpaulo * Driver methods. 383173426Srpaulo */ 384173426Srpaulostatic device_method_t asmc_methods[] = { 385173426Srpaulo DEVMETHOD(device_probe, asmc_probe), 386173426Srpaulo DEVMETHOD(device_attach, asmc_attach), 387173426Srpaulo DEVMETHOD(device_detach, asmc_detach), 388298937Sadrian DEVMETHOD(device_resume, asmc_resume), 389173426Srpaulo 390173426Srpaulo { 0, 0 } 391173426Srpaulo}; 392173426Srpaulo 393173426Srpaulostatic driver_t asmc_driver = { 394173426Srpaulo "asmc", 395173426Srpaulo asmc_methods, 396173426Srpaulo sizeof(struct asmc_softc) 397173426Srpaulo}; 398173426Srpaulo 399177972Srpaulo/* 400177972Srpaulo * Debugging 401177972Srpaulo */ 402177972Srpaulo#define _COMPONENT ACPI_OEM 403177972SrpauloACPI_MODULE_NAME("ASMC") 404177972Srpaulo#ifdef DEBUG 405177972Srpaulo#define ASMC_DPRINTF(str) device_printf(dev, str) 406177977Srpaulo#else 407330467Seadler#define ASMC_DPRINTF(str) 408177972Srpaulo#endif 409177972Srpaulo 410195046Srpaulo/* NB: can't be const */ 411177972Srpaulostatic char *asmc_ids[] = { "APP0001", NULL }; 412177972Srpaulo 413173426Srpaulostatic devclass_t asmc_devclass; 414173426Srpaulo 415298937Sadrianstatic unsigned int light_control = 0; 416298937Sadrian 417177972SrpauloDRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 418177972SrpauloMODULE_DEPEND(asmc, acpi, 1, 1, 1); 419173426Srpaulo 420173426Srpaulostatic struct asmc_model * 421173426Srpauloasmc_match(device_t dev) 422173426Srpaulo{ 423173426Srpaulo int i; 424173426Srpaulo char *model; 425173426Srpaulo 426273174Sdavide model = kern_getenv("smbios.system.product"); 427185433Srpaulo if (model == NULL) 428185433Srpaulo return (NULL); 429185433Srpaulo 430173426Srpaulo for (i = 0; asmc_models[i].smc_model; i++) { 431173426Srpaulo if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 432173426Srpaulo freeenv(model); 433173426Srpaulo return (&asmc_models[i]); 434173426Srpaulo } 435173426Srpaulo } 436173426Srpaulo freeenv(model); 437173426Srpaulo 438173426Srpaulo return (NULL); 439173426Srpaulo} 440173426Srpaulo 441173426Srpaulostatic int 442173426Srpauloasmc_probe(device_t dev) 443173426Srpaulo{ 444173426Srpaulo struct asmc_model *model; 445173426Srpaulo 446241885Seadler if (resource_disabled("asmc", 0)) 447241885Seadler return (ENXIO); 448177972Srpaulo if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL) 449177972Srpaulo return (ENXIO); 450330467Seadler 451173426Srpaulo model = asmc_match(dev); 452177972Srpaulo if (!model) { 453177972Srpaulo device_printf(dev, "model not recognized\n"); 454173426Srpaulo return (ENXIO); 455177972Srpaulo } 456173426Srpaulo device_set_desc(dev, model->smc_desc); 457173426Srpaulo 458173426Srpaulo return (BUS_PROBE_DEFAULT); 459173426Srpaulo} 460173426Srpaulo 461173426Srpaulostatic int 462173426Srpauloasmc_attach(device_t dev) 463173426Srpaulo{ 464173426Srpaulo int i, j; 465173426Srpaulo int ret; 466173426Srpaulo char name[2]; 467173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 468173426Srpaulo struct sysctl_ctx_list *sysctlctx; 469173426Srpaulo struct sysctl_oid *sysctlnode; 470173426Srpaulo struct asmc_model *model; 471173426Srpaulo 472177972Srpaulo sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 473177972Srpaulo &sc->sc_rid_port, RF_ACTIVE); 474177972Srpaulo if (sc->sc_ioport == NULL) { 475177972Srpaulo device_printf(dev, "unable to allocate IO port\n"); 476177972Srpaulo return (ENOMEM); 477177972Srpaulo } 478330467Seadler 479173426Srpaulo sysctlctx = device_get_sysctl_ctx(dev); 480173426Srpaulo sysctlnode = device_get_sysctl_tree(dev); 481330467Seadler 482173426Srpaulo model = asmc_match(dev); 483173426Srpaulo 484173426Srpaulo mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 485173426Srpaulo 486173426Srpaulo sc->sc_model = model; 487173426Srpaulo asmc_init(dev); 488173426Srpaulo 489173426Srpaulo /* 490173426Srpaulo * dev.asmc.n.fan.* tree. 491173426Srpaulo */ 492173426Srpaulo sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 493173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 494173426Srpaulo CTLFLAG_RD, 0, "Fan Root Tree"); 495173426Srpaulo 496173426Srpaulo for (i = 1; i <= sc->sc_nfan; i++) { 497173426Srpaulo j = i - 1; 498173426Srpaulo name[0] = '0' + j; 499173426Srpaulo name[1] = 0; 500173426Srpaulo sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 501173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 502173426Srpaulo OID_AUTO, name, CTLFLAG_RD, 0, 503173426Srpaulo "Fan Subtree"); 504173426Srpaulo 505173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 506173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 507271975Srpaulo OID_AUTO, "id", CTLTYPE_STRING | CTLFLAG_RD, 508271975Srpaulo dev, j, model->smc_fan_id, "I", 509271975Srpaulo "Fan ID"); 510271975Srpaulo 511271975Srpaulo SYSCTL_ADD_PROC(sysctlctx, 512271975Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 513173426Srpaulo OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD, 514173426Srpaulo dev, j, model->smc_fan_speed, "I", 515173426Srpaulo "Fan speed in RPM"); 516173426Srpaulo 517173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 518173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 519173426Srpaulo OID_AUTO, "safespeed", 520173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 521173426Srpaulo dev, j, model->smc_fan_safespeed, "I", 522173426Srpaulo "Fan safe speed in RPM"); 523173426Srpaulo 524173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 525173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 526173426Srpaulo OID_AUTO, "minspeed", 527271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 528173426Srpaulo dev, j, model->smc_fan_minspeed, "I", 529173426Srpaulo "Fan minimum speed in RPM"); 530173426Srpaulo 531173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 532173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 533173426Srpaulo OID_AUTO, "maxspeed", 534271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 535173426Srpaulo dev, j, model->smc_fan_maxspeed, "I", 536173426Srpaulo "Fan maximum speed in RPM"); 537173426Srpaulo 538173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 539173426Srpaulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 540173426Srpaulo OID_AUTO, "targetspeed", 541271975Srpaulo CTLTYPE_INT | CTLFLAG_RW, 542173426Srpaulo dev, j, model->smc_fan_targetspeed, "I", 543173426Srpaulo "Fan target speed in RPM"); 544173426Srpaulo } 545173426Srpaulo 546173426Srpaulo /* 547173426Srpaulo * dev.asmc.n.temp tree. 548173426Srpaulo */ 549173426Srpaulo sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 550173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 551173426Srpaulo CTLFLAG_RD, 0, "Temperature sensors"); 552173426Srpaulo 553173426Srpaulo for (i = 0; model->smc_temps[i]; i++) { 554173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 555173426Srpaulo SYSCTL_CHILDREN(sc->sc_temp_tree), 556173426Srpaulo OID_AUTO, model->smc_tempnames[i], 557173426Srpaulo CTLTYPE_INT | CTLFLAG_RD, 558173426Srpaulo dev, i, asmc_temp_sysctl, "I", 559173426Srpaulo model->smc_tempdescs[i]); 560173426Srpaulo } 561173426Srpaulo 562195046Srpaulo /* 563195046Srpaulo * dev.asmc.n.light 564195046Srpaulo */ 565195046Srpaulo if (model->smc_light_left) { 566195046Srpaulo sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 567195046Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 568195046Srpaulo CTLFLAG_RD, 0, "Keyboard backlight sensors"); 569330467Seadler 570195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 571195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 572195046Srpaulo OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD, 573195046Srpaulo dev, 0, model->smc_light_left, "I", 574195046Srpaulo "Keyboard backlight left sensor"); 575330467Seadler 576195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 577195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 578195046Srpaulo OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD, 579195046Srpaulo dev, 0, model->smc_light_right, "I", 580195046Srpaulo "Keyboard backlight right sensor"); 581195046Srpaulo 582195046Srpaulo SYSCTL_ADD_PROC(sysctlctx, 583195046Srpaulo SYSCTL_CHILDREN(sc->sc_light_tree), 584196455Srpaulo OID_AUTO, "control", 585196455Srpaulo CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 586195046Srpaulo dev, 0, model->smc_light_control, "I", 587195046Srpaulo "Keyboard backlight brightness control"); 588195046Srpaulo } 589195046Srpaulo 590173426Srpaulo if (model->smc_sms_x == NULL) 591173426Srpaulo goto nosms; 592173426Srpaulo 593173426Srpaulo /* 594173426Srpaulo * dev.asmc.n.sms tree. 595173426Srpaulo */ 596173426Srpaulo sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 597173426Srpaulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 598173426Srpaulo CTLFLAG_RD, 0, "Sudden Motion Sensor"); 599173426Srpaulo 600173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 601173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 602173426Srpaulo OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD, 603173426Srpaulo dev, 0, model->smc_sms_x, "I", 604173426Srpaulo "Sudden Motion Sensor X value"); 605173426Srpaulo 606173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 607173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 608173426Srpaulo OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD, 609173426Srpaulo dev, 0, model->smc_sms_y, "I", 610173426Srpaulo "Sudden Motion Sensor Y value"); 611173426Srpaulo 612173426Srpaulo SYSCTL_ADD_PROC(sysctlctx, 613173426Srpaulo SYSCTL_CHILDREN(sc->sc_sms_tree), 614173426Srpaulo OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD, 615173426Srpaulo dev, 0, model->smc_sms_z, "I", 616173426Srpaulo "Sudden Motion Sensor Z value"); 617173426Srpaulo 618173426Srpaulo /* 619173426Srpaulo * Need a taskqueue to send devctl_notify() events 620173426Srpaulo * when the SMS interrupt us. 621173426Srpaulo * 622173426Srpaulo * PI_REALTIME is used due to the sensitivity of the 623173426Srpaulo * interrupt. An interrupt from the SMS means that the 624173426Srpaulo * disk heads should be turned off as quickly as possible. 625173426Srpaulo * 626173426Srpaulo * We only need to do this for the non INTR_FILTER case. 627173426Srpaulo */ 628173426Srpaulo sc->sc_sms_tq = NULL; 629173426Srpaulo#ifndef INTR_FILTER 630173426Srpaulo TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 631173426Srpaulo sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 632173426Srpaulo taskqueue_thread_enqueue, &sc->sc_sms_tq); 633173426Srpaulo taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 634173426Srpaulo device_get_nameunit(dev)); 635173426Srpaulo#endif 636173426Srpaulo /* 637173426Srpaulo * Allocate an IRQ for the SMS. 638173426Srpaulo */ 639177972Srpaulo sc->sc_rid_irq = 0; 640177972Srpaulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 641177972Srpaulo &sc->sc_rid_irq, RF_ACTIVE); 642177972Srpaulo if (sc->sc_irq == NULL) { 643173426Srpaulo device_printf(dev, "unable to allocate IRQ resource\n"); 644173426Srpaulo ret = ENXIO; 645173426Srpaulo goto err2; 646173426Srpaulo } 647173426Srpaulo 648330467Seadler ret = bus_setup_intr(dev, sc->sc_irq, 649173426Srpaulo INTR_TYPE_MISC | INTR_MPSAFE, 650173426Srpaulo#ifdef INTR_FILTER 651173426Srpaulo asmc_sms_intrfast, asmc_sms_handler, 652173426Srpaulo#else 653173426Srpaulo asmc_sms_intrfast, NULL, 654173426Srpaulo#endif 655173426Srpaulo dev, &sc->sc_cookie); 656173426Srpaulo 657173426Srpaulo if (ret) { 658173426Srpaulo device_printf(dev, "unable to setup SMS IRQ\n"); 659173426Srpaulo goto err1; 660173426Srpaulo } 661173426Srpaulonosms: 662173426Srpaulo return (0); 663173426Srpauloerr1: 664177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 665173426Srpauloerr2: 666177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 667177972Srpaulo sc->sc_ioport); 668173426Srpaulo mtx_destroy(&sc->sc_mtx); 669173426Srpaulo if (sc->sc_sms_tq) 670173426Srpaulo taskqueue_free(sc->sc_sms_tq); 671173426Srpaulo 672173426Srpaulo return (ret); 673173426Srpaulo} 674173426Srpaulo 675173426Srpaulostatic int 676173426Srpauloasmc_detach(device_t dev) 677173426Srpaulo{ 678173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 679173426Srpaulo 680173426Srpaulo if (sc->sc_sms_tq) { 681173426Srpaulo taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 682173426Srpaulo taskqueue_free(sc->sc_sms_tq); 683173426Srpaulo } 684173426Srpaulo if (sc->sc_cookie) 685177972Srpaulo bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 686177972Srpaulo if (sc->sc_irq) 687177972Srpaulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 688177972Srpaulo sc->sc_irq); 689177972Srpaulo if (sc->sc_ioport) 690177972Srpaulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 691177972Srpaulo sc->sc_ioport); 692173426Srpaulo mtx_destroy(&sc->sc_mtx); 693173426Srpaulo 694173426Srpaulo return (0); 695173426Srpaulo} 696173426Srpaulo 697298937Sadrianstatic int 698298937Sadrianasmc_resume(device_t dev) 699298937Sadrian{ 700298937Sadrian uint8_t buf[2]; 701298937Sadrian buf[0] = light_control; 702298937Sadrian buf[1] = 0x00; 703298937Sadrian asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 704298937Sadrian return (0); 705298937Sadrian} 706298937Sadrian 707298937Sadrian 708197190Srpaulo#ifdef DEBUG 709197190Srpaulovoid asmc_dumpall(device_t dev) 710197190Srpaulo{ 711197190Srpaulo int i; 712197190Srpaulo 713197190Srpaulo /* XXX magic number */ 714197190Srpaulo for (i=0; i < 0x100; i++) 715197190Srpaulo asmc_key_dump(dev, i); 716197190Srpaulo} 717197190Srpaulo#endif 718197190Srpaulo 719173426Srpaulostatic int 720173426Srpauloasmc_init(device_t dev) 721173426Srpaulo{ 722173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 723173426Srpaulo int i, error = 1; 724173426Srpaulo uint8_t buf[4]; 725173426Srpaulo 726173426Srpaulo if (sc->sc_model->smc_sms_x == NULL) 727173426Srpaulo goto nosms; 728173426Srpaulo 729173426Srpaulo /* 730298955Spfg * We are ready to receive interrupts from the SMS. 731173426Srpaulo */ 732173426Srpaulo buf[0] = 0x01; 733177972Srpaulo ASMC_DPRINTF(("intok key\n")); 734173426Srpaulo asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 735173426Srpaulo DELAY(50); 736173426Srpaulo 737330467Seadler /* 738173426Srpaulo * Initiate the polling intervals. 739173426Srpaulo */ 740173426Srpaulo buf[0] = 20; /* msecs */ 741177972Srpaulo ASMC_DPRINTF(("low int key\n")); 742173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 743173426Srpaulo DELAY(200); 744173426Srpaulo 745173426Srpaulo buf[0] = 20; /* msecs */ 746177972Srpaulo ASMC_DPRINTF(("high int key\n")); 747173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 748173426Srpaulo DELAY(200); 749173426Srpaulo 750173426Srpaulo buf[0] = 0x00; 751173426Srpaulo buf[1] = 0x60; 752177972Srpaulo ASMC_DPRINTF(("sms low key\n")); 753173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 754173426Srpaulo DELAY(200); 755173426Srpaulo 756173426Srpaulo buf[0] = 0x01; 757173426Srpaulo buf[1] = 0xc0; 758177972Srpaulo ASMC_DPRINTF(("sms high key\n")); 759173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 760173426Srpaulo DELAY(200); 761173426Srpaulo 762173426Srpaulo /* 763173426Srpaulo * I'm not sure what this key does, but it seems to be 764173426Srpaulo * required. 765173426Srpaulo */ 766173426Srpaulo buf[0] = 0x01; 767177972Srpaulo ASMC_DPRINTF(("sms flag key\n")); 768173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 769177979Srpaulo DELAY(100); 770173426Srpaulo 771197190Srpaulo sc->sc_sms_intr_works = 0; 772330467Seadler 773173426Srpaulo /* 774197190Srpaulo * Retry SMS initialization 1000 times 775197190Srpaulo * (takes approx. 2 seconds in worst case) 776173426Srpaulo */ 777197190Srpaulo for (i = 0; i < 1000; i++) { 778330467Seadler if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 779197190Srpaulo (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 780173426Srpaulo error = 0; 781197190Srpaulo sc->sc_sms_intr_works = 1; 782177977Srpaulo goto out; 783173426Srpaulo } 784173426Srpaulo buf[0] = ASMC_SMS_INIT1; 785173426Srpaulo buf[1] = ASMC_SMS_INIT2; 786177972Srpaulo ASMC_DPRINTF(("sms key\n")); 787173426Srpaulo asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 788173426Srpaulo DELAY(50); 789173426Srpaulo } 790177977Srpaulo device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 791173426Srpaulo 792177977Srpauloout: 793173426Srpaulo asmc_sms_calibrate(dev); 794173426Srpaulonosms: 795173426Srpaulo sc->sc_nfan = asmc_fan_count(dev); 796173426Srpaulo if (sc->sc_nfan > ASMC_MAXFANS) { 797173426Srpaulo device_printf(dev, "more than %d fans were detected. Please " 798173426Srpaulo "report this.\n", ASMC_MAXFANS); 799173426Srpaulo sc->sc_nfan = ASMC_MAXFANS; 800173426Srpaulo } 801173426Srpaulo 802173426Srpaulo if (bootverbose) { 803173426Srpaulo /* 804271975Srpaulo * The number of keys is a 32 bit buffer 805173426Srpaulo */ 806173426Srpaulo asmc_key_read(dev, ASMC_NKEYS, buf, 4); 807271975Srpaulo device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf)); 808330467Seadler } 809173426Srpaulo 810197190Srpaulo#ifdef DEBUG 811197190Srpaulo asmc_dumpall(dev); 812197190Srpaulo#endif 813197190Srpaulo 814173426Srpaulo return (error); 815173426Srpaulo} 816173426Srpaulo 817173426Srpaulo/* 818173426Srpaulo * We need to make sure that the SMC acks the byte sent. 819195046Srpaulo * Just wait up to (amount * 10) ms. 820173426Srpaulo */ 821173426Srpaulostatic int 822195046Srpauloasmc_wait_ack(device_t dev, uint8_t val, int amount) 823173426Srpaulo{ 824177972Srpaulo struct asmc_softc *sc = device_get_softc(dev); 825173426Srpaulo u_int i; 826173426Srpaulo 827173426Srpaulo val = val & ASMC_STATUS_MASK; 828173426Srpaulo 829195046Srpaulo for (i = 0; i < amount; i++) { 830177972Srpaulo if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 831173426Srpaulo return (0); 832173426Srpaulo DELAY(10); 833173426Srpaulo } 834173426Srpaulo 835195046Srpaulo return (1); 836195046Srpaulo} 837195046Srpaulo 838195046Srpaulo/* 839195046Srpaulo * We need to make sure that the SMC acks the byte sent. 840195046Srpaulo * Just wait up to 100 ms. 841195046Srpaulo */ 842195046Srpaulostatic int 843195046Srpauloasmc_wait(device_t dev, uint8_t val) 844195046Srpaulo{ 845195046Srpaulo struct asmc_softc *sc; 846195046Srpaulo 847195046Srpaulo if (asmc_wait_ack(dev, val, 1000) == 0) 848195046Srpaulo return (0); 849195046Srpaulo 850195046Srpaulo sc = device_get_softc(dev); 851195046Srpaulo val = val & ASMC_STATUS_MASK; 852195046Srpaulo 853195046Srpaulo#ifdef DEBUG 854173426Srpaulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 855177972Srpaulo ASMC_CMDPORT_READ(sc)); 856330467Seadler#endif 857195046Srpaulo return (1); 858195046Srpaulo} 859330467Seadler 860195046Srpaulo/* 861195046Srpaulo * Send the given command, retrying up to 10 times if 862195046Srpaulo * the acknowledgement fails. 863195046Srpaulo */ 864195046Srpaulostatic int 865195046Srpauloasmc_command(device_t dev, uint8_t command) { 866195046Srpaulo 867195046Srpaulo int i; 868195046Srpaulo struct asmc_softc *sc = device_get_softc(dev); 869195046Srpaulo 870195046Srpaulo for (i=0; i < 10; i++) { 871195046Srpaulo ASMC_CMDPORT_WRITE(sc, command); 872195046Srpaulo if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 873195046Srpaulo return (0); 874195046Srpaulo } 875195046Srpaulo } 876195046Srpaulo 877195046Srpaulo#ifdef DEBUG 878195046Srpaulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 879195046Srpaulo ASMC_CMDPORT_READ(sc)); 880195046Srpaulo#endif 881173426Srpaulo return (1); 882173426Srpaulo} 883173426Srpaulo 884173426Srpaulostatic int 885173426Srpauloasmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 886173426Srpaulo{ 887195046Srpaulo int i, error = 1, try = 0; 888173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 889173426Srpaulo 890173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 891173426Srpaulo 892195046Srpaulobegin: 893195046Srpaulo if (asmc_command(dev, ASMC_CMDREAD)) 894173426Srpaulo goto out; 895173426Srpaulo 896173426Srpaulo for (i = 0; i < 4; i++) { 897177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 898173426Srpaulo if (asmc_wait(dev, 0x04)) 899173426Srpaulo goto out; 900173426Srpaulo } 901173426Srpaulo 902177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 903173426Srpaulo 904173426Srpaulo for (i = 0; i < len; i++) { 905173426Srpaulo if (asmc_wait(dev, 0x05)) 906173426Srpaulo goto out; 907177972Srpaulo buf[i] = ASMC_DATAPORT_READ(sc); 908173426Srpaulo } 909173426Srpaulo 910173426Srpaulo error = 0; 911173426Srpauloout: 912195046Srpaulo if (error) { 913195046Srpaulo if (++try < 10) goto begin; 914195046Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 915195046Srpaulo __func__, key, try); 916195046Srpaulo } 917195046Srpaulo 918173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 919173426Srpaulo 920173426Srpaulo return (error); 921173426Srpaulo} 922173426Srpaulo 923197190Srpaulo#ifdef DEBUG 924173426Srpaulostatic int 925197190Srpauloasmc_key_dump(device_t dev, int number) 926197190Srpaulo{ 927197190Srpaulo struct asmc_softc *sc = device_get_softc(dev); 928197190Srpaulo char key[5] = { 0 }; 929197190Srpaulo char type[7] = { 0 }; 930197190Srpaulo uint8_t index[4]; 931197190Srpaulo uint8_t v[32]; 932197190Srpaulo uint8_t maxlen; 933197190Srpaulo int i, error = 1, try = 0; 934197190Srpaulo 935197190Srpaulo mtx_lock_spin(&sc->sc_mtx); 936197190Srpaulo 937197190Srpaulo index[0] = (number >> 24) & 0xff; 938197190Srpaulo index[1] = (number >> 16) & 0xff; 939197190Srpaulo index[2] = (number >> 8) & 0xff; 940197190Srpaulo index[3] = (number) & 0xff; 941197190Srpaulo 942197190Srpaulobegin: 943197190Srpaulo if (asmc_command(dev, 0x12)) 944197190Srpaulo goto out; 945197190Srpaulo 946197190Srpaulo for (i = 0; i < 4; i++) { 947197190Srpaulo ASMC_DATAPORT_WRITE(sc, index[i]); 948197190Srpaulo if (asmc_wait(dev, 0x04)) 949197190Srpaulo goto out; 950197190Srpaulo } 951197190Srpaulo 952197190Srpaulo ASMC_DATAPORT_WRITE(sc, 4); 953197190Srpaulo 954197190Srpaulo for (i = 0; i < 4; i++) { 955197190Srpaulo if (asmc_wait(dev, 0x05)) 956197190Srpaulo goto out; 957197190Srpaulo key[i] = ASMC_DATAPORT_READ(sc); 958197190Srpaulo } 959197190Srpaulo 960197190Srpaulo /* get type */ 961197190Srpaulo if (asmc_command(dev, 0x13)) 962197190Srpaulo goto out; 963197190Srpaulo 964197190Srpaulo for (i = 0; i < 4; i++) { 965197190Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 966197190Srpaulo if (asmc_wait(dev, 0x04)) 967197190Srpaulo goto out; 968197190Srpaulo } 969197190Srpaulo 970197190Srpaulo ASMC_DATAPORT_WRITE(sc, 6); 971197190Srpaulo 972197190Srpaulo for (i = 0; i < 6; i++) { 973197190Srpaulo if (asmc_wait(dev, 0x05)) 974197190Srpaulo goto out; 975197190Srpaulo type[i] = ASMC_DATAPORT_READ(sc); 976197190Srpaulo } 977197190Srpaulo 978197190Srpaulo error = 0; 979197190Srpauloout: 980197190Srpaulo if (error) { 981197190Srpaulo if (++try < 10) goto begin; 982197190Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 983197190Srpaulo __func__, key, try); 984197190Srpaulo mtx_unlock_spin(&sc->sc_mtx); 985197190Srpaulo } 986197190Srpaulo else { 987197190Srpaulo char buf[1024]; 988197190Srpaulo char buf2[8]; 989197190Srpaulo mtx_unlock_spin(&sc->sc_mtx); 990197190Srpaulo maxlen = type[0]; 991197190Srpaulo type[0] = ' '; 992197190Srpaulo type[5] = 0; 993330467Seadler if (maxlen > sizeof(v)) { 994197202Srpaulo device_printf(dev, 995197202Srpaulo "WARNING: cropping maxlen from %d to %zu\n", 996197202Srpaulo maxlen, sizeof(v)); 997197190Srpaulo maxlen = sizeof(v); 998197190Srpaulo } 999197190Srpaulo for (i = 0; i < sizeof(v); i++) { 1000197190Srpaulo v[i] = 0; 1001197190Srpaulo } 1002197190Srpaulo asmc_key_read(dev, key, v, maxlen); 1003197190Srpaulo snprintf(buf, sizeof(buf), "key %d is: %s, type %s " 1004197190Srpaulo "(len %d), data", number, key, type, maxlen); 1005197190Srpaulo for (i = 0; i < maxlen; i++) { 1006298937Sadrian snprintf(buf2, sizeof(buf2), " %02x", v[i]); 1007197190Srpaulo strlcat(buf, buf2, sizeof(buf)); 1008197190Srpaulo } 1009197190Srpaulo strlcat(buf, " \n", sizeof(buf)); 1010242826Srdivacky device_printf(dev, "%s", buf); 1011197190Srpaulo } 1012197190Srpaulo 1013197190Srpaulo return (error); 1014197190Srpaulo} 1015197190Srpaulo#endif 1016197190Srpaulo 1017197190Srpaulostatic int 1018173426Srpauloasmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 1019173426Srpaulo{ 1020195046Srpaulo int i, error = -1, try = 0; 1021173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1022173426Srpaulo 1023173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 1024173426Srpaulo 1025195046Srpaulobegin: 1026177972Srpaulo ASMC_DPRINTF(("cmd port: cmd write\n")); 1027195046Srpaulo if (asmc_command(dev, ASMC_CMDWRITE)) 1028173426Srpaulo goto out; 1029173426Srpaulo 1030177972Srpaulo ASMC_DPRINTF(("data port: key\n")); 1031173426Srpaulo for (i = 0; i < 4; i++) { 1032177972Srpaulo ASMC_DATAPORT_WRITE(sc, key[i]); 1033173426Srpaulo if (asmc_wait(dev, 0x04)) 1034173426Srpaulo goto out; 1035173426Srpaulo } 1036177972Srpaulo ASMC_DPRINTF(("data port: length\n")); 1037177972Srpaulo ASMC_DATAPORT_WRITE(sc, len); 1038173426Srpaulo 1039177972Srpaulo ASMC_DPRINTF(("data port: buffer\n")); 1040173426Srpaulo for (i = 0; i < len; i++) { 1041173426Srpaulo if (asmc_wait(dev, 0x04)) 1042173426Srpaulo goto out; 1043177972Srpaulo ASMC_DATAPORT_WRITE(sc, buf[i]); 1044173426Srpaulo } 1045173426Srpaulo 1046173426Srpaulo error = 0; 1047173426Srpauloout: 1048195046Srpaulo if (error) { 1049195046Srpaulo if (++try < 10) goto begin; 1050195046Srpaulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 1051195046Srpaulo __func__, key, try); 1052195046Srpaulo } 1053195046Srpaulo 1054173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 1055173426Srpaulo 1056173426Srpaulo return (error); 1057173426Srpaulo 1058173426Srpaulo} 1059173426Srpaulo 1060173426Srpaulo/* 1061173426Srpaulo * Fan control functions. 1062173426Srpaulo */ 1063173426Srpaulostatic int 1064173426Srpauloasmc_fan_count(device_t dev) 1065173426Srpaulo{ 1066173426Srpaulo uint8_t buf[1]; 1067173426Srpaulo 1068271975Srpaulo if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) < 0) 1069173426Srpaulo return (-1); 1070173426Srpaulo 1071173426Srpaulo return (buf[0]); 1072173426Srpaulo} 1073173426Srpaulo 1074173426Srpaulostatic int 1075173426Srpauloasmc_fan_getvalue(device_t dev, const char *key, int fan) 1076173426Srpaulo{ 1077173426Srpaulo int speed; 1078173426Srpaulo uint8_t buf[2]; 1079173426Srpaulo char fankey[5]; 1080173426Srpaulo 1081173426Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1082271975Srpaulo if (asmc_key_read(dev, fankey, buf, sizeof buf) < 0) 1083173426Srpaulo return (-1); 1084173426Srpaulo speed = (buf[0] << 6) | (buf[1] >> 2); 1085173426Srpaulo 1086173426Srpaulo return (speed); 1087173426Srpaulo} 1088173426Srpaulo 1089271975Srpaulostatic char* 1090293193Suqsasmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen) 1091271975Srpaulo{ 1092271975Srpaulo char fankey[5]; 1093271975Srpaulo char* desc; 1094271975Srpaulo 1095271975Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1096293193Suqs if (asmc_key_read(dev, fankey, buf, buflen) < 0) 1097271975Srpaulo return (NULL); 1098271975Srpaulo desc = buf+4; 1099271975Srpaulo 1100271975Srpaulo return (desc); 1101271975Srpaulo} 1102271975Srpaulo 1103173426Srpaulostatic int 1104271975Srpauloasmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 1105271975Srpaulo{ 1106271975Srpaulo uint8_t buf[2]; 1107271975Srpaulo char fankey[5]; 1108271975Srpaulo 1109271975Srpaulo speed *= 4; 1110271975Srpaulo 1111271975Srpaulo buf[0] = speed>>8; 1112271975Srpaulo buf[1] = speed; 1113271975Srpaulo 1114271975Srpaulo snprintf(fankey, sizeof(fankey), key, fan); 1115271975Srpaulo if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0) 1116271975Srpaulo return (-1); 1117271975Srpaulo 1118271975Srpaulo return (0); 1119271975Srpaulo} 1120271975Srpaulo 1121271975Srpaulostatic int 1122173426Srpauloasmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 1123173426Srpaulo{ 1124173426Srpaulo device_t dev = (device_t) arg1; 1125173426Srpaulo int fan = arg2; 1126173426Srpaulo int error; 1127173426Srpaulo int32_t v; 1128173426Srpaulo 1129173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 1130173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1131173426Srpaulo 1132173426Srpaulo return (error); 1133173426Srpaulo} 1134173426Srpaulo 1135173426Srpaulostatic int 1136271975Srpauloasmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 1137271975Srpaulo{ 1138293193Suqs uint8_t buf[16]; 1139271975Srpaulo device_t dev = (device_t) arg1; 1140271975Srpaulo int fan = arg2; 1141271975Srpaulo int error = true; 1142271975Srpaulo char* desc; 1143271975Srpaulo 1144293193Suqs desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); 1145271975Srpaulo 1146271975Srpaulo if (desc != NULL) 1147271975Srpaulo error = sysctl_handle_string(oidp, desc, 0, req); 1148271975Srpaulo 1149271975Srpaulo return (error); 1150271975Srpaulo} 1151271975Srpaulo 1152271975Srpaulostatic int 1153173426Srpauloasmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 1154173426Srpaulo{ 1155173426Srpaulo device_t dev = (device_t) arg1; 1156173426Srpaulo int fan = arg2; 1157173426Srpaulo int error; 1158173426Srpaulo int32_t v; 1159173426Srpaulo 1160173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 1161173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1162173426Srpaulo 1163173426Srpaulo return (error); 1164173426Srpaulo} 1165173426Srpaulo 1166173426Srpaulo 1167173426Srpaulostatic int 1168173426Srpauloasmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 1169173426Srpaulo{ 1170173426Srpaulo device_t dev = (device_t) arg1; 1171173426Srpaulo int fan = arg2; 1172173426Srpaulo int error; 1173173426Srpaulo int32_t v; 1174173426Srpaulo 1175173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 1176173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1177173426Srpaulo 1178271975Srpaulo if (error == 0 && req->newptr != NULL) { 1179273773Shselasky unsigned int newspeed = v; 1180271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 1181271975Srpaulo } 1182271975Srpaulo 1183173426Srpaulo return (error); 1184173426Srpaulo} 1185173426Srpaulo 1186173426Srpaulostatic int 1187173426Srpauloasmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 1188173426Srpaulo{ 1189173426Srpaulo device_t dev = (device_t) arg1; 1190173426Srpaulo int fan = arg2; 1191173426Srpaulo int error; 1192173426Srpaulo int32_t v; 1193173426Srpaulo 1194173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 1195173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1196173426Srpaulo 1197271975Srpaulo if (error == 0 && req->newptr != NULL) { 1198273773Shselasky unsigned int newspeed = v; 1199271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 1200271975Srpaulo } 1201271975Srpaulo 1202173426Srpaulo return (error); 1203173426Srpaulo} 1204173426Srpaulo 1205173426Srpaulostatic int 1206173426Srpauloasmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 1207173426Srpaulo{ 1208173426Srpaulo device_t dev = (device_t) arg1; 1209173426Srpaulo int fan = arg2; 1210173426Srpaulo int error; 1211173426Srpaulo int32_t v; 1212173426Srpaulo 1213173426Srpaulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 1214173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1215173426Srpaulo 1216271975Srpaulo if (error == 0 && req->newptr != NULL) { 1217273773Shselasky unsigned int newspeed = v; 1218271975Srpaulo asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 1219271975Srpaulo } 1220271975Srpaulo 1221173426Srpaulo return (error); 1222173426Srpaulo} 1223173426Srpaulo 1224173426Srpaulo/* 1225173426Srpaulo * Temperature functions. 1226173426Srpaulo */ 1227173426Srpaulostatic int 1228173426Srpauloasmc_temp_getvalue(device_t dev, const char *key) 1229173426Srpaulo{ 1230173426Srpaulo uint8_t buf[2]; 1231173426Srpaulo 1232173426Srpaulo /* 1233173426Srpaulo * Check for invalid temperatures. 1234173426Srpaulo */ 1235271975Srpaulo if (asmc_key_read(dev, key, buf, sizeof buf) < 0) 1236173426Srpaulo return (-1); 1237173426Srpaulo 1238173426Srpaulo return (buf[0]); 1239173426Srpaulo} 1240173426Srpaulo 1241173426Srpaulostatic int 1242173426Srpauloasmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 1243173426Srpaulo{ 1244173426Srpaulo device_t dev = (device_t) arg1; 1245173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1246173426Srpaulo int error, val; 1247173426Srpaulo 1248173426Srpaulo val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 1249173426Srpaulo error = sysctl_handle_int(oidp, &val, 0, req); 1250173426Srpaulo 1251173426Srpaulo return (error); 1252173426Srpaulo} 1253173426Srpaulo 1254173426Srpaulo/* 1255173426Srpaulo * Sudden Motion Sensor functions. 1256173426Srpaulo */ 1257173426Srpaulostatic int 1258173426Srpauloasmc_sms_read(device_t dev, const char *key, int16_t *val) 1259173426Srpaulo{ 1260173426Srpaulo uint8_t buf[2]; 1261173426Srpaulo int error; 1262173426Srpaulo 1263330467Seadler /* no need to do locking here as asmc_key_read() already does it */ 1264173426Srpaulo switch (key[3]) { 1265173426Srpaulo case 'X': 1266173426Srpaulo case 'Y': 1267173426Srpaulo case 'Z': 1268271975Srpaulo error = asmc_key_read(dev, key, buf, sizeof buf); 1269173426Srpaulo break; 1270173426Srpaulo default: 1271173426Srpaulo device_printf(dev, "%s called with invalid argument %s\n", 1272173426Srpaulo __func__, key); 1273173426Srpaulo error = 1; 1274173426Srpaulo goto out; 1275173426Srpaulo } 1276173426Srpaulo *val = ((int16_t)buf[0] << 8) | buf[1]; 1277173426Srpauloout: 1278173426Srpaulo return (error); 1279173426Srpaulo} 1280173426Srpaulo 1281173426Srpaulostatic void 1282173426Srpauloasmc_sms_calibrate(device_t dev) 1283173426Srpaulo{ 1284173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1285173426Srpaulo 1286173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 1287173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 1288173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 1289173426Srpaulo} 1290173426Srpaulo 1291173426Srpaulostatic int 1292173426Srpauloasmc_sms_intrfast(void *arg) 1293173426Srpaulo{ 1294173426Srpaulo uint8_t type; 1295173426Srpaulo device_t dev = (device_t) arg; 1296173426Srpaulo struct asmc_softc *sc = device_get_softc(dev); 1297197190Srpaulo if (!sc->sc_sms_intr_works) 1298197190Srpaulo return (FILTER_HANDLED); 1299173426Srpaulo 1300173426Srpaulo mtx_lock_spin(&sc->sc_mtx); 1301177972Srpaulo type = ASMC_INTPORT_READ(sc); 1302173426Srpaulo mtx_unlock_spin(&sc->sc_mtx); 1303173426Srpaulo 1304173426Srpaulo sc->sc_sms_intrtype = type; 1305173426Srpaulo asmc_sms_printintr(dev, type); 1306173426Srpaulo 1307173426Srpaulo#ifdef INTR_FILTER 1308173426Srpaulo return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED); 1309173426Srpaulo#else 1310173426Srpaulo taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 1311173426Srpaulo#endif 1312173426Srpaulo return (FILTER_HANDLED); 1313173426Srpaulo} 1314173426Srpaulo 1315173426Srpaulo#ifdef INTR_FILTER 1316173426Srpaulostatic void 1317173426Srpauloasmc_sms_handler(void *arg) 1318173426Srpaulo{ 1319173426Srpaulo struct asmc_softc *sc = device_get_softc(arg); 1320330467Seadler 1321173426Srpaulo asmc_sms_task(sc, 0); 1322173426Srpaulo} 1323173426Srpaulo#endif 1324173426Srpaulo 1325173426Srpaulo 1326173426Srpaulostatic void 1327173426Srpauloasmc_sms_printintr(device_t dev, uint8_t type) 1328173426Srpaulo{ 1329173426Srpaulo 1330173426Srpaulo switch (type) { 1331173426Srpaulo case ASMC_SMS_INTFF: 1332173426Srpaulo device_printf(dev, "WARNING: possible free fall!\n"); 1333173426Srpaulo break; 1334173426Srpaulo case ASMC_SMS_INTHA: 1335173426Srpaulo device_printf(dev, "WARNING: high acceleration detected!\n"); 1336173426Srpaulo break; 1337173426Srpaulo case ASMC_SMS_INTSH: 1338173426Srpaulo device_printf(dev, "WARNING: possible shock!\n"); 1339173426Srpaulo break; 1340173426Srpaulo default: 1341173426Srpaulo device_printf(dev, "%s unknown interrupt\n", __func__); 1342173426Srpaulo } 1343173426Srpaulo} 1344173426Srpaulo 1345173426Srpaulostatic void 1346173426Srpauloasmc_sms_task(void *arg, int pending) 1347173426Srpaulo{ 1348173426Srpaulo struct asmc_softc *sc = (struct asmc_softc *)arg; 1349173426Srpaulo char notify[16]; 1350173426Srpaulo int type; 1351173426Srpaulo 1352173426Srpaulo switch (sc->sc_sms_intrtype) { 1353173426Srpaulo case ASMC_SMS_INTFF: 1354173426Srpaulo type = 2; 1355173426Srpaulo break; 1356173426Srpaulo case ASMC_SMS_INTHA: 1357173426Srpaulo type = 1; 1358173426Srpaulo break; 1359173426Srpaulo case ASMC_SMS_INTSH: 1360173426Srpaulo type = 0; 1361173426Srpaulo break; 1362173426Srpaulo default: 1363173426Srpaulo type = 255; 1364173426Srpaulo } 1365173426Srpaulo 1366173426Srpaulo snprintf(notify, sizeof(notify), " notify=0x%x", type); 1367330467Seadler devctl_notify("ACPI", "asmc", "SMS", notify); 1368173426Srpaulo} 1369173426Srpaulo 1370173426Srpaulostatic int 1371173426Srpauloasmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 1372173426Srpaulo{ 1373173426Srpaulo device_t dev = (device_t) arg1; 1374173426Srpaulo int error; 1375173426Srpaulo int16_t val; 1376173426Srpaulo int32_t v; 1377173426Srpaulo 1378173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 1379173426Srpaulo v = (int32_t) val; 1380173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1381173426Srpaulo 1382173426Srpaulo return (error); 1383173426Srpaulo} 1384173426Srpaulo 1385173426Srpaulostatic int 1386173426Srpauloasmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 1387173426Srpaulo{ 1388173426Srpaulo device_t dev = (device_t) arg1; 1389173426Srpaulo int error; 1390173426Srpaulo int16_t val; 1391173426Srpaulo int32_t v; 1392173426Srpaulo 1393173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 1394173426Srpaulo v = (int32_t) val; 1395173426Srpaulo error = sysctl_handle_int(oidp, &v, 0, req); 1396173426Srpaulo 1397173426Srpaulo return (error); 1398173426Srpaulo} 1399173426Srpaulo 1400173426Srpaulostatic int 1401173426Srpauloasmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 1402173426Srpaulo{ 1403173426Srpaulo device_t dev = (device_t) arg1; 1404173426Srpaulo int error; 1405173426Srpaulo int16_t val; 1406173426Srpaulo int32_t v; 1407173426Srpaulo 1408173426Srpaulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 1409173426Srpaulo v = (int32_t) val; 1410273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1411173426Srpaulo 1412173426Srpaulo return (error); 1413173426Srpaulo} 1414173426Srpaulo 1415173426Srpaulostatic int 1416173426Srpauloasmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 1417173426Srpaulo{ 1418173426Srpaulo device_t dev = (device_t) arg1; 1419173426Srpaulo uint8_t buf[6]; 1420173426Srpaulo int error; 1421173426Srpaulo int32_t v; 1422173426Srpaulo 1423271975Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); 1424173426Srpaulo v = buf[2]; 1425273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1426173426Srpaulo 1427173426Srpaulo return (error); 1428173426Srpaulo} 1429173426Srpaulo 1430173426Srpaulostatic int 1431173426Srpauloasmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 1432173426Srpaulo{ 1433173426Srpaulo device_t dev = (device_t) arg1; 1434173426Srpaulo uint8_t buf[6]; 1435173426Srpaulo int error; 1436173426Srpaulo int32_t v; 1437330467Seadler 1438271975Srpaulo asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf); 1439173426Srpaulo v = buf[2]; 1440273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1441330467Seadler 1442195046Srpaulo return (error); 1443195046Srpaulo} 1444195046Srpaulo 1445195046Srpaulostatic int 1446195046Srpauloasmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 1447195046Srpaulo{ 1448195046Srpaulo device_t dev = (device_t) arg1; 1449195046Srpaulo uint8_t buf[2]; 1450195046Srpaulo int error; 1451273773Shselasky int v; 1452273773Shselasky 1453298937Sadrian v = light_control; 1454273773Shselasky error = sysctl_handle_int(oidp, &v, 0, req); 1455273773Shselasky 1456173426Srpaulo if (error == 0 && req->newptr != NULL) { 1457273773Shselasky if (v < 0 || v > 255) 1458173426Srpaulo return (EINVAL); 1459298937Sadrian light_control = v; 1460298937Sadrian buf[0] = light_control; 1461173426Srpaulo buf[1] = 0x00; 1462271975Srpaulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 1463173426Srpaulo } 1464173426Srpaulo return (error); 1465173426Srpaulo} 1466