132a8088fSRui Paulo /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 44470f0f3SRui Paulo * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org> 532a8088fSRui Paulo * All rights reserved. 632a8088fSRui Paulo * 732a8088fSRui Paulo * Redistribution and use in source and binary forms, with or without 832a8088fSRui Paulo * modification, are permitted provided that the following conditions 932a8088fSRui Paulo * are met: 1032a8088fSRui Paulo * 1. Redistributions of source code must retain the above copyright 1132a8088fSRui Paulo * notice, this list of conditions and the following disclaimer. 1232a8088fSRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 1332a8088fSRui Paulo * notice, this list of conditions and the following disclaimer in the 1432a8088fSRui Paulo * documentation and/or other materials provided with the distribution. 1532a8088fSRui Paulo * 1632a8088fSRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1732a8088fSRui Paulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1832a8088fSRui Paulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1932a8088fSRui Paulo * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2032a8088fSRui Paulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2132a8088fSRui Paulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2232a8088fSRui Paulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2332a8088fSRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2432a8088fSRui Paulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2532a8088fSRui Paulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2632a8088fSRui Paulo * POSSIBILITY OF SUCH DAMAGE. 2732a8088fSRui Paulo * 2832a8088fSRui Paulo */ 2932a8088fSRui Paulo 3032a8088fSRui Paulo /* 3132a8088fSRui Paulo * Driver for Apple's System Management Console (SMC). 3232a8088fSRui Paulo * SMC can be found on the MacBook, MacBook Pro and Mac Mini. 3332a8088fSRui Paulo * 3432a8088fSRui Paulo * Inspired by the Linux applesmc driver. 3532a8088fSRui Paulo */ 3632a8088fSRui Paulo 3732a8088fSRui Paulo #include <sys/param.h> 3832a8088fSRui Paulo #include <sys/bus.h> 3932a8088fSRui Paulo #include <sys/conf.h> 402e9d05fdSAdrian Chadd #include <sys/endian.h> 4132a8088fSRui Paulo #include <sys/kernel.h> 4232a8088fSRui Paulo #include <sys/lock.h> 4332a8088fSRui Paulo #include <sys/malloc.h> 4432a8088fSRui Paulo #include <sys/module.h> 4532a8088fSRui Paulo #include <sys/mutex.h> 4632a8088fSRui Paulo #include <sys/sysctl.h> 4732a8088fSRui Paulo #include <sys/systm.h> 4832a8088fSRui Paulo #include <sys/taskqueue.h> 4932a8088fSRui Paulo #include <sys/rman.h> 504c061448SRui Paulo 5132a8088fSRui Paulo #include <machine/resource.h> 52129d3046SJung-uk Kim 53129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h> 54129d3046SJung-uk Kim 554470f0f3SRui Paulo #include <dev/acpica/acpivar.h> 5632a8088fSRui Paulo #include <dev/asmc/asmcvar.h> 5732a8088fSRui Paulo 5832a8088fSRui Paulo /* 5932a8088fSRui Paulo * Device interface. 6032a8088fSRui Paulo */ 6132a8088fSRui Paulo static int asmc_probe(device_t dev); 6232a8088fSRui Paulo static int asmc_attach(device_t dev); 6332a8088fSRui Paulo static int asmc_detach(device_t dev); 64108e3076SAdrian Chadd static int asmc_resume(device_t dev); 6532a8088fSRui Paulo 6632a8088fSRui Paulo /* 6732a8088fSRui Paulo * SMC functions. 6832a8088fSRui Paulo */ 6932a8088fSRui Paulo static int asmc_init(device_t dev); 70be80e49aSRui Paulo static int asmc_command(device_t dev, uint8_t command); 7132a8088fSRui Paulo static int asmc_wait(device_t dev, uint8_t val); 72be80e49aSRui Paulo static int asmc_wait_ack(device_t dev, uint8_t val, int amount); 7332a8088fSRui Paulo static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 7432a8088fSRui Paulo uint8_t len); 7532a8088fSRui Paulo static int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 7632a8088fSRui Paulo uint8_t); 7732a8088fSRui Paulo static int asmc_fan_count(device_t dev); 7832a8088fSRui Paulo static int asmc_fan_getvalue(device_t dev, const char *key, int fan); 79447666f0SRui Paulo static int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed); 8032a8088fSRui Paulo static int asmc_temp_getvalue(device_t dev, const char *key); 8132a8088fSRui Paulo static int asmc_sms_read(device_t, const char *key, int16_t *val); 8232a8088fSRui Paulo static void asmc_sms_calibrate(device_t dev); 8332a8088fSRui Paulo static int asmc_sms_intrfast(void *arg); 8432a8088fSRui Paulo static void asmc_sms_printintr(device_t dev, uint8_t); 8532a8088fSRui Paulo static void asmc_sms_task(void *arg, int pending); 861269f4d4SRui Paulo #ifdef DEBUG 871269f4d4SRui Paulo void asmc_dumpall(device_t); 881269f4d4SRui Paulo static int asmc_key_dump(device_t, int); 891269f4d4SRui Paulo #endif 9032a8088fSRui Paulo 9132a8088fSRui Paulo /* 9232a8088fSRui Paulo * Model functions. 9332a8088fSRui Paulo */ 94447666f0SRui Paulo static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS); 9532a8088fSRui Paulo static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 9632a8088fSRui Paulo static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 9732a8088fSRui Paulo static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 9832a8088fSRui Paulo static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 9932a8088fSRui Paulo static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 10032a8088fSRui Paulo static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 10132a8088fSRui Paulo static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 10232a8088fSRui Paulo static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 10332a8088fSRui Paulo static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 10432a8088fSRui Paulo static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 10532a8088fSRui Paulo static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 106be80e49aSRui Paulo static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); 1072e9d05fdSAdrian Chadd static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS); 10832a8088fSRui Paulo 10932a8088fSRui Paulo struct asmc_model { 11032a8088fSRui Paulo const char *smc_model; /* smbios.system.product env var. */ 11132a8088fSRui Paulo const char *smc_desc; /* driver description */ 11232a8088fSRui Paulo 11332a8088fSRui Paulo /* Helper functions */ 11432a8088fSRui Paulo int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); 11532a8088fSRui Paulo int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); 11632a8088fSRui Paulo int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); 117447666f0SRui Paulo int (*smc_fan_id)(SYSCTL_HANDLER_ARGS); 11832a8088fSRui Paulo int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); 11932a8088fSRui Paulo int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); 12032a8088fSRui Paulo int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); 12132a8088fSRui Paulo int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); 12232a8088fSRui Paulo int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); 12332a8088fSRui Paulo int (*smc_light_left)(SYSCTL_HANDLER_ARGS); 12432a8088fSRui Paulo int (*smc_light_right)(SYSCTL_HANDLER_ARGS); 125be80e49aSRui Paulo int (*smc_light_control)(SYSCTL_HANDLER_ARGS); 12632a8088fSRui Paulo 127d8246db0SRui Paulo const char *smc_temps[ASMC_TEMP_MAX]; 128d8246db0SRui Paulo const char *smc_tempnames[ASMC_TEMP_MAX]; 129d8246db0SRui Paulo const char *smc_tempdescs[ASMC_TEMP_MAX]; 13032a8088fSRui Paulo }; 13132a8088fSRui Paulo 13227d4c6f8SMark Johnston static const struct asmc_model *asmc_match(device_t dev); 13332a8088fSRui Paulo 13432a8088fSRui Paulo #define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ 13532a8088fSRui Paulo asmc_mb_sysctl_sms_z 13632a8088fSRui Paulo 137108e3076SAdrian Chadd #define ASMC_SMS_FUNCS_DISABLED NULL,NULL,NULL 138108e3076SAdrian Chadd 139447666f0SRui Paulo #define ASMC_FAN_FUNCS asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ 14032a8088fSRui Paulo asmc_mb_sysctl_fanminspeed, \ 14132a8088fSRui Paulo asmc_mb_sysctl_fanmaxspeed, \ 14232a8088fSRui Paulo asmc_mb_sysctl_fantargetspeed 143108e3076SAdrian Chadd 144108e3076SAdrian Chadd #define ASMC_FAN_FUNCS2 asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \ 145108e3076SAdrian Chadd asmc_mb_sysctl_fanminspeed, \ 146108e3076SAdrian Chadd asmc_mb_sysctl_fanmaxspeed, \ 147108e3076SAdrian Chadd asmc_mb_sysctl_fantargetspeed 148108e3076SAdrian Chadd 14932a8088fSRui Paulo #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ 150be80e49aSRui Paulo asmc_mbp_sysctl_light_right, \ 151be80e49aSRui Paulo asmc_mbp_sysctl_light_control 15232a8088fSRui Paulo 1532e9d05fdSAdrian Chadd #define ASMC_LIGHT_FUNCS_10BYTE \ 1542e9d05fdSAdrian Chadd asmc_mbp_sysctl_light_left_10byte, \ 1552e9d05fdSAdrian Chadd NULL, \ 1562e9d05fdSAdrian Chadd asmc_mbp_sysctl_light_control 1572e9d05fdSAdrian Chadd 1589f0bfc51SDavid Bright #define ASMC_LIGHT_FUNCS_DISABLED NULL, NULL, NULL 1599f0bfc51SDavid Bright 16027d4c6f8SMark Johnston static const struct asmc_model asmc_models[] = { 16132a8088fSRui Paulo { 16232a8088fSRui Paulo "MacBook1,1", "Apple SMC MacBook Core Duo", 163be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 16432a8088fSRui Paulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 16532a8088fSRui Paulo }, 16632a8088fSRui Paulo 16732a8088fSRui Paulo { 16832a8088fSRui Paulo "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 169be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 17032a8088fSRui Paulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 17132a8088fSRui Paulo }, 17232a8088fSRui Paulo 17332a8088fSRui Paulo { 174108e3076SAdrian Chadd "MacBook3,1", "Apple SMC MacBook Core 2 Duo", 175108e3076SAdrian Chadd ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 176108e3076SAdrian Chadd ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS 177108e3076SAdrian Chadd }, 178108e3076SAdrian Chadd 179108e3076SAdrian Chadd { 180e4a14ce7SMark Johnston "MacBook7,1", "Apple SMC MacBook Core 2 Duo (mid 2010)", 181e4a14ce7SMark Johnston ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED, 182e4a14ce7SMark Johnston ASMC_MB71_TEMPS, ASMC_MB71_TEMPNAMES, ASMC_MB71_TEMPDESCS 183e4a14ce7SMark Johnston }, 184e4a14ce7SMark Johnston 185e4a14ce7SMark Johnston { 18632a8088fSRui Paulo "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 18732a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 18832a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 18932a8088fSRui Paulo }, 19032a8088fSRui Paulo 19132a8088fSRui Paulo { 19232a8088fSRui Paulo "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 19332a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 19432a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 19532a8088fSRui Paulo }, 19632a8088fSRui Paulo 19732a8088fSRui Paulo { 19832a8088fSRui Paulo "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 19932a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 20032a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 20132a8088fSRui Paulo }, 20232a8088fSRui Paulo 20332a8088fSRui Paulo { 20432a8088fSRui Paulo "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 20532a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 20632a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 20732a8088fSRui Paulo }, 20832a8088fSRui Paulo 20932a8088fSRui Paulo { 21032a8088fSRui Paulo "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 21132a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 21232a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 21332a8088fSRui Paulo }, 21432a8088fSRui Paulo 21532a8088fSRui Paulo { 21632a8088fSRui Paulo "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 21732a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 21832a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 21932a8088fSRui Paulo }, 22032a8088fSRui Paulo 221be80e49aSRui Paulo { 222be80e49aSRui Paulo "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)", 223be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 224be80e49aSRui Paulo ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS 225be80e49aSRui Paulo }, 226be80e49aSRui Paulo 227447666f0SRui Paulo { 22831ae3b07SAdrian Chadd "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)", 22931ae3b07SAdrian Chadd ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 230638937d4SMichael Gmelin ASMC_MBP51_TEMPS, ASMC_MBP51_TEMPNAMES, ASMC_MBP51_TEMPDESCS 231638937d4SMichael Gmelin }, 232638937d4SMichael Gmelin 233638937d4SMichael Gmelin { 234638937d4SMichael Gmelin "MacBookPro5,5", "Apple SMC MacBook Pro Core 2 Duo (Mid 2009)", 235638937d4SMichael Gmelin ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 236638937d4SMichael Gmelin ASMC_MBP55_TEMPS, ASMC_MBP55_TEMPNAMES, ASMC_MBP55_TEMPDESCS 23731ae3b07SAdrian Chadd }, 23831ae3b07SAdrian Chadd 23931ae3b07SAdrian Chadd { 2403416f5cdSed crowe "MacBookPro6,2", "Apple SMC MacBook Pro (Mid 2010, 15-inch)", 2413416f5cdSed crowe ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 2423416f5cdSed crowe ASMC_MBP62_TEMPS, ASMC_MBP62_TEMPNAMES, ASMC_MBP62_TEMPDESCS 2433416f5cdSed crowe }, 2443416f5cdSed crowe 2453416f5cdSed crowe { 24609ff71d3SDavid Bright "MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)", 24709ff71d3SDavid Bright ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 24809ff71d3SDavid Bright ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS 24909ff71d3SDavid Bright }, 25009ff71d3SDavid Bright 25109ff71d3SDavid Bright { 252447666f0SRui Paulo "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)", 253447666f0SRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 25409ff71d3SDavid Bright ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS 255447666f0SRui Paulo }, 256447666f0SRui Paulo 257447666f0SRui Paulo { 25879291c9bSDaniel W. Delâtre "MacBookPro9,1", "Apple SMC MacBook Pro (mid 2012, 15-inch)", 25998ae4866SDavid Bright ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 26079291c9bSDaniel W. Delâtre ASMC_MBP91_TEMPS, ASMC_MBP91_TEMPNAMES, ASMC_MBP91_TEMPDESCS 26179291c9bSDaniel W. Delâtre }, 26279291c9bSDaniel W. Delâtre 26379291c9bSDaniel W. Delâtre { 26479291c9bSDaniel W. Delâtre "MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012, 13-inch)", 26579291c9bSDaniel W. Delâtre ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 26679291c9bSDaniel W. Delâtre ASMC_MBP92_TEMPS, ASMC_MBP92_TEMPNAMES, ASMC_MBP92_TEMPDESCS 26798ae4866SDavid Bright }, 26898ae4866SDavid Bright 26998ae4866SDavid Bright { 270109e2d29SAdrian Chadd "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 271109e2d29SAdrian Chadd ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 272109e2d29SAdrian Chadd ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS 273109e2d29SAdrian Chadd }, 274109e2d29SAdrian Chadd 275109e2d29SAdrian Chadd { 276447666f0SRui Paulo "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 277447666f0SRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 278109e2d29SAdrian Chadd ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS 279447666f0SRui Paulo }, 280447666f0SRui Paulo 281*49a5fe1aSJoshua Rogers { 282*49a5fe1aSJoshua Rogers "MacBookPro11,4", "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch)", 283*49a5fe1aSJoshua Rogers ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 284*49a5fe1aSJoshua Rogers ASMC_MBP114_TEMPS, ASMC_MBP114_TEMPNAMES, ASMC_MBP114_TEMPDESCS 285*49a5fe1aSJoshua Rogers }, 286*49a5fe1aSJoshua Rogers 28732a8088fSRui Paulo /* The Mac Mini has no SMS */ 28832a8088fSRui Paulo { 28932a8088fSRui Paulo "Macmini1,1", "Apple SMC Mac Mini", 29032a8088fSRui Paulo NULL, NULL, NULL, 29132a8088fSRui Paulo ASMC_FAN_FUNCS, 292be80e49aSRui Paulo NULL, NULL, NULL, 29332a8088fSRui Paulo ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 29432a8088fSRui Paulo }, 29532a8088fSRui Paulo 2969e33968bSDavid Bright /* The Mac Mini 2,1 has no SMS */ 2979e33968bSDavid Bright { 2989e33968bSDavid Bright "Macmini2,1", "Apple SMC Mac Mini 2,1", 2999e33968bSDavid Bright ASMC_SMS_FUNCS_DISABLED, 3009e33968bSDavid Bright ASMC_FAN_FUNCS, 3019e33968bSDavid Bright ASMC_LIGHT_FUNCS_DISABLED, 3029e33968bSDavid Bright ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS 3039e33968bSDavid Bright }, 3049e33968bSDavid Bright 305764442e0SGavin Atkinson /* The Mac Mini 3,1 has no SMS */ 306764442e0SGavin Atkinson { 307764442e0SGavin Atkinson "Macmini3,1", "Apple SMC Mac Mini 3,1", 308764442e0SGavin Atkinson NULL, NULL, NULL, 309764442e0SGavin Atkinson ASMC_FAN_FUNCS, 310764442e0SGavin Atkinson NULL, NULL, NULL, 311764442e0SGavin Atkinson ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS 312764442e0SGavin Atkinson }, 313764442e0SGavin Atkinson 3149f0bfc51SDavid Bright /* The Mac Mini 4,1 (Mid-2010) has no SMS */ 3159f0bfc51SDavid Bright { 3169f0bfc51SDavid Bright "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)", 3179f0bfc51SDavid Bright ASMC_SMS_FUNCS_DISABLED, 3189f0bfc51SDavid Bright ASMC_FAN_FUNCS, 3199f0bfc51SDavid Bright ASMC_LIGHT_FUNCS_DISABLED, 3209f0bfc51SDavid Bright ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS 3219f0bfc51SDavid Bright }, 3229f0bfc51SDavid Bright 323601abb30STrev /* The Mac Mini 5,1 has no SMS */ 324601abb30STrev /* - same sensors as Mac Mini 5,2 */ 325601abb30STrev { 326601abb30STrev "Macmini5,1", "Apple SMC Mac Mini 5,1", 327601abb30STrev NULL, NULL, NULL, 328601abb30STrev ASMC_FAN_FUNCS2, 329601abb30STrev NULL, NULL, NULL, 330601abb30STrev ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS 331601abb30STrev }, 332601abb30STrev 33371b475e7SDavid Bright /* The Mac Mini 5,2 has no SMS */ 33471b475e7SDavid Bright { 33571b475e7SDavid Bright "Macmini5,2", "Apple SMC Mac Mini 5,2", 33671b475e7SDavid Bright NULL, NULL, NULL, 33771b475e7SDavid Bright ASMC_FAN_FUNCS2, 33871b475e7SDavid Bright NULL, NULL, NULL, 33971b475e7SDavid Bright ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS 34071b475e7SDavid Bright }, 34171b475e7SDavid Bright 342601abb30STrev /* The Mac Mini 5,3 has no SMS */ 343601abb30STrev /* - same sensors as Mac Mini 5,2 */ 344601abb30STrev { 345601abb30STrev "Macmini5,3", "Apple SMC Mac Mini 5,3", 346601abb30STrev NULL, NULL, NULL, 347601abb30STrev ASMC_FAN_FUNCS2, 348601abb30STrev NULL, NULL, NULL, 349601abb30STrev ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS 350601abb30STrev }, 351601abb30STrev 352601abb30STrev /* The Mac Mini 7,1 has no SMS */ 353601abb30STrev { 354601abb30STrev "Macmini7,1", "Apple SMC Mac Mini 7,1", 355601abb30STrev NULL, NULL, NULL, 356601abb30STrev ASMC_FAN_FUNCS2, 357601abb30STrev NULL, NULL, NULL, 358601abb30STrev ASMC_MM71_TEMPS, ASMC_MM71_TEMPNAMES, ASMC_MM71_TEMPDESCS 359601abb30STrev }, 360601abb30STrev 36139a8ee13SDavid Bright /* Idem for the Mac Pro "Quad Core" (original) */ 36239a8ee13SDavid Bright { 36339a8ee13SDavid Bright "MacPro1,1", "Apple SMC Mac Pro (Quad Core)", 36439a8ee13SDavid Bright NULL, NULL, NULL, 36539a8ee13SDavid Bright ASMC_FAN_FUNCS, 36639a8ee13SDavid Bright NULL, NULL, NULL, 36739a8ee13SDavid Bright ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS 36839a8ee13SDavid Bright }, 36939a8ee13SDavid Bright 37039a8ee13SDavid Bright /* Idem for the Mac Pro (8-core) */ 371d8246db0SRui Paulo { 372d8246db0SRui Paulo "MacPro2", "Apple SMC Mac Pro (8-core)", 373d8246db0SRui Paulo NULL, NULL, NULL, 374d8246db0SRui Paulo ASMC_FAN_FUNCS, 375be80e49aSRui Paulo NULL, NULL, NULL, 37639a8ee13SDavid Bright ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS 377d8246db0SRui Paulo }, 378941f9f10SRui Paulo 379447666f0SRui Paulo /* Idem for the MacPro 2010*/ 380447666f0SRui Paulo { 381447666f0SRui Paulo "MacPro5,1", "Apple SMC MacPro (2010)", 382447666f0SRui Paulo NULL, NULL, NULL, 383447666f0SRui Paulo ASMC_FAN_FUNCS, 384447666f0SRui Paulo NULL, NULL, NULL, 385447666f0SRui Paulo ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS 386447666f0SRui Paulo }, 387447666f0SRui Paulo 3887d5fef18SAdam S /* Idem for the Mac Pro 2013 (cylinder) */ 3897d5fef18SAdam S { 3907d5fef18SAdam S "MacPro6,1", "Apple SMC Mac Pro (2013)", 3917d5fef18SAdam S ASMC_SMS_FUNCS_DISABLED, 392dc484aedSAdam S ASMC_FAN_FUNCS2, 3937d5fef18SAdam S ASMC_LIGHT_FUNCS_DISABLED, 3947d5fef18SAdam S ASMC_MP6_TEMPS, ASMC_MP6_TEMPNAMES, ASMC_MP6_TEMPDESCS 3957d5fef18SAdam S }, 3967d5fef18SAdam S 397941f9f10SRui Paulo { 398941f9f10SRui Paulo "MacBookAir1,1", "Apple SMC MacBook Air", 399be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 400941f9f10SRui Paulo ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS 401941f9f10SRui Paulo }, 402941f9f10SRui Paulo 403447666f0SRui Paulo { 404447666f0SRui Paulo "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", 405447666f0SRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 406447666f0SRui Paulo ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS 407447666f0SRui Paulo }, 408447666f0SRui Paulo 409108e3076SAdrian Chadd { 410308340ccSMark Johnston "MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)", 411308340ccSMark Johnston ASMC_SMS_FUNCS_DISABLED, 412308340ccSMark Johnston ASMC_FAN_FUNCS2, 413308340ccSMark Johnston ASMC_LIGHT_FUNCS, 414308340ccSMark Johnston ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS 415308340ccSMark Johnston }, 416308340ccSMark Johnston 417308340ccSMark Johnston { 418308340ccSMark Johnston "MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)", 419308340ccSMark Johnston ASMC_SMS_FUNCS_DISABLED, 420308340ccSMark Johnston ASMC_FAN_FUNCS2, 421308340ccSMark Johnston ASMC_LIGHT_FUNCS, 422308340ccSMark Johnston ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS 423308340ccSMark Johnston }, 424308340ccSMark Johnston 425308340ccSMark Johnston { 426108e3076SAdrian Chadd "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)", 427108e3076SAdrian Chadd ASMC_SMS_FUNCS_DISABLED, 428108e3076SAdrian Chadd ASMC_FAN_FUNCS2, 429108e3076SAdrian Chadd ASMC_LIGHT_FUNCS, 430108e3076SAdrian Chadd ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 431108e3076SAdrian Chadd }, 432108e3076SAdrian Chadd 433108e3076SAdrian Chadd { 434108e3076SAdrian Chadd "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)", 435108e3076SAdrian Chadd ASMC_SMS_FUNCS_DISABLED, 436108e3076SAdrian Chadd ASMC_FAN_FUNCS2, 437108e3076SAdrian Chadd ASMC_LIGHT_FUNCS, 438108e3076SAdrian Chadd ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 439108e3076SAdrian Chadd }, 440ffc58e2cSAdrian Chadd { 4412e9d05fdSAdrian Chadd "MacBookAir6,1", "Apple SMC MacBook Air 11-inch (Early 2013)", 4422e9d05fdSAdrian Chadd ASMC_SMS_FUNCS_DISABLED, 4432e9d05fdSAdrian Chadd ASMC_FAN_FUNCS2, 4442e9d05fdSAdrian Chadd ASMC_LIGHT_FUNCS_10BYTE, 4452e9d05fdSAdrian Chadd ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS 4462e9d05fdSAdrian Chadd }, 4472e9d05fdSAdrian Chadd { 448ffc58e2cSAdrian Chadd "MacBookAir6,2", "Apple SMC MacBook Air 13-inch (Early 2013)", 449ffc58e2cSAdrian Chadd ASMC_SMS_FUNCS_DISABLED, 450ffc58e2cSAdrian Chadd ASMC_FAN_FUNCS2, 4512e9d05fdSAdrian Chadd ASMC_LIGHT_FUNCS_10BYTE, 452ffc58e2cSAdrian Chadd ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS 453ffc58e2cSAdrian Chadd }, 454081954d3SDavid Bright { 455081954d3SDavid Bright "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)", 456081954d3SDavid Bright ASMC_SMS_FUNCS_DISABLED, 457081954d3SDavid Bright ASMC_FAN_FUNCS2, 458081954d3SDavid Bright ASMC_LIGHT_FUNCS, 459081954d3SDavid Bright ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 460081954d3SDavid Bright }, 461081954d3SDavid Bright { 462081954d3SDavid Bright "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)", 463081954d3SDavid Bright ASMC_SMS_FUNCS_DISABLED, 464081954d3SDavid Bright ASMC_FAN_FUNCS2, 465081954d3SDavid Bright ASMC_LIGHT_FUNCS, 466081954d3SDavid Bright ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 467081954d3SDavid Bright }, 46832a8088fSRui Paulo { NULL, NULL } 46932a8088fSRui Paulo }; 47032a8088fSRui Paulo 47132a8088fSRui Paulo #undef ASMC_SMS_FUNCS 472108e3076SAdrian Chadd #undef ASMC_SMS_FUNCS_DISABLED 47332a8088fSRui Paulo #undef ASMC_FAN_FUNCS 474108e3076SAdrian Chadd #undef ASMC_FAN_FUNCS2 47532a8088fSRui Paulo #undef ASMC_LIGHT_FUNCS 47632a8088fSRui Paulo 47732a8088fSRui Paulo /* 47832a8088fSRui Paulo * Driver methods. 47932a8088fSRui Paulo */ 48032a8088fSRui Paulo static device_method_t asmc_methods[] = { 48132a8088fSRui Paulo DEVMETHOD(device_probe, asmc_probe), 48232a8088fSRui Paulo DEVMETHOD(device_attach, asmc_attach), 48332a8088fSRui Paulo DEVMETHOD(device_detach, asmc_detach), 484108e3076SAdrian Chadd DEVMETHOD(device_resume, asmc_resume), 48532a8088fSRui Paulo { 0, 0 } 48632a8088fSRui Paulo }; 48732a8088fSRui Paulo 48832a8088fSRui Paulo static driver_t asmc_driver = { 48932a8088fSRui Paulo "asmc", 49032a8088fSRui Paulo asmc_methods, 49132a8088fSRui Paulo sizeof(struct asmc_softc) 49232a8088fSRui Paulo }; 49332a8088fSRui Paulo 4944470f0f3SRui Paulo /* 4954470f0f3SRui Paulo * Debugging 4964470f0f3SRui Paulo */ 4974470f0f3SRui Paulo #define _COMPONENT ACPI_OEM 4984470f0f3SRui Paulo ACPI_MODULE_NAME("ASMC") 4994470f0f3SRui Paulo #ifdef DEBUG 5004470f0f3SRui Paulo #define ASMC_DPRINTF(str) device_printf(dev, str) 5014fb9bf66SRui Paulo #else 5024fb9bf66SRui Paulo #define ASMC_DPRINTF(str) 5034470f0f3SRui Paulo #endif 5044470f0f3SRui Paulo 505be80e49aSRui Paulo /* NB: can't be const */ 5064470f0f3SRui Paulo static char *asmc_ids[] = { "APP0001", NULL }; 5074470f0f3SRui Paulo 508108e3076SAdrian Chadd static unsigned int light_control = 0; 509108e3076SAdrian Chadd 510867864a2SJohn Baldwin DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL); 5114470f0f3SRui Paulo MODULE_DEPEND(asmc, acpi, 1, 1, 1); 51232a8088fSRui Paulo 51327d4c6f8SMark Johnston static const struct asmc_model * 51432a8088fSRui Paulo asmc_match(device_t dev) 51532a8088fSRui Paulo { 51632a8088fSRui Paulo int i; 51732a8088fSRui Paulo char *model; 51832a8088fSRui Paulo 5192be111bfSDavide Italiano model = kern_getenv("smbios.system.product"); 52047105877SRui Paulo if (model == NULL) 52147105877SRui Paulo return (NULL); 52247105877SRui Paulo 52332a8088fSRui Paulo for (i = 0; asmc_models[i].smc_model; i++) { 52432a8088fSRui Paulo if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 52532a8088fSRui Paulo freeenv(model); 52632a8088fSRui Paulo return (&asmc_models[i]); 52732a8088fSRui Paulo } 52832a8088fSRui Paulo } 52932a8088fSRui Paulo freeenv(model); 53032a8088fSRui Paulo 53132a8088fSRui Paulo return (NULL); 53232a8088fSRui Paulo } 53332a8088fSRui Paulo 53432a8088fSRui Paulo static int 53532a8088fSRui Paulo asmc_probe(device_t dev) 53632a8088fSRui Paulo { 53727d4c6f8SMark Johnston const struct asmc_model *model; 5385efca36fSTakanori Watanabe int rv; 53932a8088fSRui Paulo 540a8de37b0SEitan Adler if (resource_disabled("asmc", 0)) 541a8de37b0SEitan Adler return (ENXIO); 5425efca36fSTakanori Watanabe rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL); 5435efca36fSTakanori Watanabe if (rv > 0) 5445efca36fSTakanori Watanabe return (rv); 5454470f0f3SRui Paulo 54632a8088fSRui Paulo model = asmc_match(dev); 5474470f0f3SRui Paulo if (!model) { 5484470f0f3SRui Paulo device_printf(dev, "model not recognized\n"); 54932a8088fSRui Paulo return (ENXIO); 5504470f0f3SRui Paulo } 55132a8088fSRui Paulo device_set_desc(dev, model->smc_desc); 55232a8088fSRui Paulo 5535efca36fSTakanori Watanabe return (rv); 55432a8088fSRui Paulo } 55532a8088fSRui Paulo 55632a8088fSRui Paulo static int 55732a8088fSRui Paulo asmc_attach(device_t dev) 55832a8088fSRui Paulo { 55932a8088fSRui Paulo int i, j; 56032a8088fSRui Paulo int ret; 56132a8088fSRui Paulo char name[2]; 56232a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 56332a8088fSRui Paulo struct sysctl_ctx_list *sysctlctx; 56432a8088fSRui Paulo struct sysctl_oid *sysctlnode; 56527d4c6f8SMark Johnston const struct asmc_model *model; 56632a8088fSRui Paulo 5674470f0f3SRui Paulo sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 5684470f0f3SRui Paulo &sc->sc_rid_port, RF_ACTIVE); 5694470f0f3SRui Paulo if (sc->sc_ioport == NULL) { 5704470f0f3SRui Paulo device_printf(dev, "unable to allocate IO port\n"); 5714470f0f3SRui Paulo return (ENOMEM); 5724470f0f3SRui Paulo } 5734470f0f3SRui Paulo 57432a8088fSRui Paulo sysctlctx = device_get_sysctl_ctx(dev); 57532a8088fSRui Paulo sysctlnode = device_get_sysctl_tree(dev); 57632a8088fSRui Paulo 57732a8088fSRui Paulo model = asmc_match(dev); 57832a8088fSRui Paulo 57932a8088fSRui Paulo mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 58032a8088fSRui Paulo 58132a8088fSRui Paulo sc->sc_model = model; 58232a8088fSRui Paulo asmc_init(dev); 58332a8088fSRui Paulo 58432a8088fSRui Paulo /* 58532a8088fSRui Paulo * dev.asmc.n.fan.* tree. 58632a8088fSRui Paulo */ 58732a8088fSRui Paulo sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 58832a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 5897029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree"); 59032a8088fSRui Paulo 59132a8088fSRui Paulo for (i = 1; i <= sc->sc_nfan; i++) { 59232a8088fSRui Paulo j = i - 1; 59332a8088fSRui Paulo name[0] = '0' + j; 59432a8088fSRui Paulo name[1] = 0; 59532a8088fSRui Paulo sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 59632a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 5977029da5cSPawel Biernacki OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 59832a8088fSRui Paulo "Fan Subtree"); 59932a8088fSRui Paulo 60032a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 60132a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 6027029da5cSPawel Biernacki OID_AUTO, "id", 6037029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 604447666f0SRui Paulo dev, j, model->smc_fan_id, "I", 605447666f0SRui Paulo "Fan ID"); 606447666f0SRui Paulo 607447666f0SRui Paulo SYSCTL_ADD_PROC(sysctlctx, 608447666f0SRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 6097029da5cSPawel Biernacki OID_AUTO, "speed", 6107029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 61132a8088fSRui Paulo dev, j, model->smc_fan_speed, "I", 61232a8088fSRui Paulo "Fan speed in RPM"); 61332a8088fSRui Paulo 61432a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 61532a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 61632a8088fSRui Paulo OID_AUTO, "safespeed", 6177029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 61832a8088fSRui Paulo dev, j, model->smc_fan_safespeed, "I", 61932a8088fSRui Paulo "Fan safe speed in RPM"); 62032a8088fSRui Paulo 62132a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 62232a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 62332a8088fSRui Paulo OID_AUTO, "minspeed", 6247029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 62532a8088fSRui Paulo dev, j, model->smc_fan_minspeed, "I", 62632a8088fSRui Paulo "Fan minimum speed in RPM"); 62732a8088fSRui Paulo 62832a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 62932a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 63032a8088fSRui Paulo OID_AUTO, "maxspeed", 6317029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 63232a8088fSRui Paulo dev, j, model->smc_fan_maxspeed, "I", 63332a8088fSRui Paulo "Fan maximum speed in RPM"); 63432a8088fSRui Paulo 63532a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 63632a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 63732a8088fSRui Paulo OID_AUTO, "targetspeed", 6387029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 63932a8088fSRui Paulo dev, j, model->smc_fan_targetspeed, "I", 64032a8088fSRui Paulo "Fan target speed in RPM"); 64132a8088fSRui Paulo } 64232a8088fSRui Paulo 64332a8088fSRui Paulo /* 64432a8088fSRui Paulo * dev.asmc.n.temp tree. 64532a8088fSRui Paulo */ 64632a8088fSRui Paulo sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 64732a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 6487029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors"); 64932a8088fSRui Paulo 65032a8088fSRui Paulo for (i = 0; model->smc_temps[i]; i++) { 65132a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 65232a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_temp_tree), 65332a8088fSRui Paulo OID_AUTO, model->smc_tempnames[i], 6547029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 65532a8088fSRui Paulo dev, i, asmc_temp_sysctl, "I", 65632a8088fSRui Paulo model->smc_tempdescs[i]); 65732a8088fSRui Paulo } 65832a8088fSRui Paulo 659be80e49aSRui Paulo /* 660be80e49aSRui Paulo * dev.asmc.n.light 661be80e49aSRui Paulo */ 662be80e49aSRui Paulo if (model->smc_light_left) { 663be80e49aSRui Paulo sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 664be80e49aSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 6657029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 6667029da5cSPawel Biernacki "Keyboard backlight sensors"); 667be80e49aSRui Paulo 668be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 669be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 6707029da5cSPawel Biernacki OID_AUTO, "left", 6717029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 672be80e49aSRui Paulo dev, 0, model->smc_light_left, "I", 673be80e49aSRui Paulo "Keyboard backlight left sensor"); 674be80e49aSRui Paulo 675be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 676be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 6777029da5cSPawel Biernacki OID_AUTO, "right", 6787029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 679be80e49aSRui Paulo dev, 0, model->smc_light_right, "I", 680be80e49aSRui Paulo "Keyboard backlight right sensor"); 681be80e49aSRui Paulo 682be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 683be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 6843471c35dSRui Paulo OID_AUTO, "control", 6857029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | 6867029da5cSPawel Biernacki CTLFLAG_NEEDGIANT, dev, 0, 6877029da5cSPawel Biernacki model->smc_light_control, "I", 688be80e49aSRui Paulo "Keyboard backlight brightness control"); 689be80e49aSRui Paulo } 690be80e49aSRui Paulo 69132a8088fSRui Paulo if (model->smc_sms_x == NULL) 69232a8088fSRui Paulo goto nosms; 69332a8088fSRui Paulo 69432a8088fSRui Paulo /* 69532a8088fSRui Paulo * dev.asmc.n.sms tree. 69632a8088fSRui Paulo */ 69732a8088fSRui Paulo sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 69832a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 6997029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor"); 70032a8088fSRui Paulo 70132a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 70232a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 7037029da5cSPawel Biernacki OID_AUTO, "x", 7047029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 70532a8088fSRui Paulo dev, 0, model->smc_sms_x, "I", 70632a8088fSRui Paulo "Sudden Motion Sensor X value"); 70732a8088fSRui Paulo 70832a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 70932a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 7107029da5cSPawel Biernacki OID_AUTO, "y", 7117029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 71232a8088fSRui Paulo dev, 0, model->smc_sms_y, "I", 71332a8088fSRui Paulo "Sudden Motion Sensor Y value"); 71432a8088fSRui Paulo 71532a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 71632a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 7177029da5cSPawel Biernacki OID_AUTO, "z", 7187029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 71932a8088fSRui Paulo dev, 0, model->smc_sms_z, "I", 72032a8088fSRui Paulo "Sudden Motion Sensor Z value"); 72132a8088fSRui Paulo 72232a8088fSRui Paulo /* 72332a8088fSRui Paulo * Need a taskqueue to send devctl_notify() events 72432a8088fSRui Paulo * when the SMS interrupt us. 72532a8088fSRui Paulo * 72632a8088fSRui Paulo * PI_REALTIME is used due to the sensitivity of the 72732a8088fSRui Paulo * interrupt. An interrupt from the SMS means that the 72832a8088fSRui Paulo * disk heads should be turned off as quickly as possible. 72932a8088fSRui Paulo * 73032a8088fSRui Paulo * We only need to do this for the non INTR_FILTER case. 73132a8088fSRui Paulo */ 73232a8088fSRui Paulo sc->sc_sms_tq = NULL; 73332a8088fSRui Paulo TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 73432a8088fSRui Paulo sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 73532a8088fSRui Paulo taskqueue_thread_enqueue, &sc->sc_sms_tq); 73632a8088fSRui Paulo taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 73732a8088fSRui Paulo device_get_nameunit(dev)); 73832a8088fSRui Paulo /* 73932a8088fSRui Paulo * Allocate an IRQ for the SMS. 74032a8088fSRui Paulo */ 7414470f0f3SRui Paulo sc->sc_rid_irq = 0; 7424470f0f3SRui Paulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 7434470f0f3SRui Paulo &sc->sc_rid_irq, RF_ACTIVE); 7444470f0f3SRui Paulo if (sc->sc_irq == NULL) { 74532a8088fSRui Paulo device_printf(dev, "unable to allocate IRQ resource\n"); 74632a8088fSRui Paulo ret = ENXIO; 74732a8088fSRui Paulo goto err2; 74832a8088fSRui Paulo } 74932a8088fSRui Paulo 7504470f0f3SRui Paulo ret = bus_setup_intr(dev, sc->sc_irq, 75132a8088fSRui Paulo INTR_TYPE_MISC | INTR_MPSAFE, 75232a8088fSRui Paulo asmc_sms_intrfast, NULL, 75332a8088fSRui Paulo dev, &sc->sc_cookie); 75432a8088fSRui Paulo 75532a8088fSRui Paulo if (ret) { 75632a8088fSRui Paulo device_printf(dev, "unable to setup SMS IRQ\n"); 75732a8088fSRui Paulo goto err1; 75832a8088fSRui Paulo } 75932a8088fSRui Paulo nosms: 76032a8088fSRui Paulo return (0); 76132a8088fSRui Paulo err1: 7624470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 76332a8088fSRui Paulo err2: 7644470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 7654470f0f3SRui Paulo sc->sc_ioport); 76632a8088fSRui Paulo mtx_destroy(&sc->sc_mtx); 76732a8088fSRui Paulo if (sc->sc_sms_tq) 76832a8088fSRui Paulo taskqueue_free(sc->sc_sms_tq); 76932a8088fSRui Paulo 77032a8088fSRui Paulo return (ret); 77132a8088fSRui Paulo } 77232a8088fSRui Paulo 77332a8088fSRui Paulo static int 77432a8088fSRui Paulo asmc_detach(device_t dev) 77532a8088fSRui Paulo { 77632a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 77732a8088fSRui Paulo 77832a8088fSRui Paulo if (sc->sc_sms_tq) { 77932a8088fSRui Paulo taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 78032a8088fSRui Paulo taskqueue_free(sc->sc_sms_tq); 78132a8088fSRui Paulo } 78232a8088fSRui Paulo if (sc->sc_cookie) 7834470f0f3SRui Paulo bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 7844470f0f3SRui Paulo if (sc->sc_irq) 7854470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 7864470f0f3SRui Paulo sc->sc_irq); 7874470f0f3SRui Paulo if (sc->sc_ioport) 7884470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 7894470f0f3SRui Paulo sc->sc_ioport); 79032a8088fSRui Paulo mtx_destroy(&sc->sc_mtx); 79132a8088fSRui Paulo 79232a8088fSRui Paulo return (0); 79332a8088fSRui Paulo } 79432a8088fSRui Paulo 795108e3076SAdrian Chadd static int 796108e3076SAdrian Chadd asmc_resume(device_t dev) 797108e3076SAdrian Chadd { 798108e3076SAdrian Chadd uint8_t buf[2]; 799108e3076SAdrian Chadd buf[0] = light_control; 800108e3076SAdrian Chadd buf[1] = 0x00; 801108e3076SAdrian Chadd asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 802108e3076SAdrian Chadd return (0); 803108e3076SAdrian Chadd } 804108e3076SAdrian Chadd 8051269f4d4SRui Paulo #ifdef DEBUG 8061269f4d4SRui Paulo void asmc_dumpall(device_t dev) 8071269f4d4SRui Paulo { 8081269f4d4SRui Paulo int i; 8091269f4d4SRui Paulo 8101269f4d4SRui Paulo /* XXX magic number */ 8111269f4d4SRui Paulo for (i=0; i < 0x100; i++) 8121269f4d4SRui Paulo asmc_key_dump(dev, i); 8131269f4d4SRui Paulo } 8141269f4d4SRui Paulo #endif 8151269f4d4SRui Paulo 81632a8088fSRui Paulo static int 81732a8088fSRui Paulo asmc_init(device_t dev) 81832a8088fSRui Paulo { 81932a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 82032a8088fSRui Paulo int i, error = 1; 82132a8088fSRui Paulo uint8_t buf[4]; 82232a8088fSRui Paulo 82332a8088fSRui Paulo if (sc->sc_model->smc_sms_x == NULL) 82432a8088fSRui Paulo goto nosms; 82532a8088fSRui Paulo 82632a8088fSRui Paulo /* 827453130d9SPedro F. Giffuni * We are ready to receive interrupts from the SMS. 82832a8088fSRui Paulo */ 82932a8088fSRui Paulo buf[0] = 0x01; 8304470f0f3SRui Paulo ASMC_DPRINTF(("intok key\n")); 83132a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 83232a8088fSRui Paulo DELAY(50); 83332a8088fSRui Paulo 83432a8088fSRui Paulo /* 83532a8088fSRui Paulo * Initiate the polling intervals. 83632a8088fSRui Paulo */ 83732a8088fSRui Paulo buf[0] = 20; /* msecs */ 8384470f0f3SRui Paulo ASMC_DPRINTF(("low int key\n")); 83932a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 84032a8088fSRui Paulo DELAY(200); 84132a8088fSRui Paulo 84232a8088fSRui Paulo buf[0] = 20; /* msecs */ 8434470f0f3SRui Paulo ASMC_DPRINTF(("high int key\n")); 84432a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 84532a8088fSRui Paulo DELAY(200); 84632a8088fSRui Paulo 84732a8088fSRui Paulo buf[0] = 0x00; 84832a8088fSRui Paulo buf[1] = 0x60; 8494470f0f3SRui Paulo ASMC_DPRINTF(("sms low key\n")); 85032a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 85132a8088fSRui Paulo DELAY(200); 85232a8088fSRui Paulo 85332a8088fSRui Paulo buf[0] = 0x01; 85432a8088fSRui Paulo buf[1] = 0xc0; 8554470f0f3SRui Paulo ASMC_DPRINTF(("sms high key\n")); 85632a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 85732a8088fSRui Paulo DELAY(200); 85832a8088fSRui Paulo 85932a8088fSRui Paulo /* 86032a8088fSRui Paulo * I'm not sure what this key does, but it seems to be 86132a8088fSRui Paulo * required. 86232a8088fSRui Paulo */ 86332a8088fSRui Paulo buf[0] = 0x01; 8644470f0f3SRui Paulo ASMC_DPRINTF(("sms flag key\n")); 86532a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 866b75dfbe8SRui Paulo DELAY(100); 86732a8088fSRui Paulo 8681269f4d4SRui Paulo sc->sc_sms_intr_works = 0; 8691269f4d4SRui Paulo 87032a8088fSRui Paulo /* 8711269f4d4SRui Paulo * Retry SMS initialization 1000 times 8721269f4d4SRui Paulo * (takes approx. 2 seconds in worst case) 87332a8088fSRui Paulo */ 8741269f4d4SRui Paulo for (i = 0; i < 1000; i++) { 87532a8088fSRui Paulo if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 8761269f4d4SRui Paulo (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 87732a8088fSRui Paulo error = 0; 8781269f4d4SRui Paulo sc->sc_sms_intr_works = 1; 8794fb9bf66SRui Paulo goto out; 88032a8088fSRui Paulo } 88132a8088fSRui Paulo buf[0] = ASMC_SMS_INIT1; 88232a8088fSRui Paulo buf[1] = ASMC_SMS_INIT2; 8834470f0f3SRui Paulo ASMC_DPRINTF(("sms key\n")); 88432a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 88532a8088fSRui Paulo DELAY(50); 88632a8088fSRui Paulo } 8874fb9bf66SRui Paulo device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 88832a8088fSRui Paulo 8894fb9bf66SRui Paulo out: 89032a8088fSRui Paulo asmc_sms_calibrate(dev); 89132a8088fSRui Paulo nosms: 89232a8088fSRui Paulo sc->sc_nfan = asmc_fan_count(dev); 89332a8088fSRui Paulo if (sc->sc_nfan > ASMC_MAXFANS) { 89432a8088fSRui Paulo device_printf(dev, "more than %d fans were detected. Please " 89532a8088fSRui Paulo "report this.\n", ASMC_MAXFANS); 89632a8088fSRui Paulo sc->sc_nfan = ASMC_MAXFANS; 89732a8088fSRui Paulo } 89832a8088fSRui Paulo 89932a8088fSRui Paulo if (bootverbose) { 90032a8088fSRui Paulo /* 901447666f0SRui Paulo * The number of keys is a 32 bit buffer 90232a8088fSRui Paulo */ 90332a8088fSRui Paulo asmc_key_read(dev, ASMC_NKEYS, buf, 4); 904447666f0SRui Paulo device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf)); 90532a8088fSRui Paulo } 90632a8088fSRui Paulo 9071269f4d4SRui Paulo #ifdef DEBUG 9081269f4d4SRui Paulo asmc_dumpall(dev); 9091269f4d4SRui Paulo #endif 9101269f4d4SRui Paulo 91132a8088fSRui Paulo return (error); 91232a8088fSRui Paulo } 91332a8088fSRui Paulo 91432a8088fSRui Paulo /* 91532a8088fSRui Paulo * We need to make sure that the SMC acks the byte sent. 916be80e49aSRui Paulo * Just wait up to (amount * 10) ms. 91732a8088fSRui Paulo */ 91832a8088fSRui Paulo static int 919be80e49aSRui Paulo asmc_wait_ack(device_t dev, uint8_t val, int amount) 92032a8088fSRui Paulo { 9214470f0f3SRui Paulo struct asmc_softc *sc = device_get_softc(dev); 92232a8088fSRui Paulo u_int i; 92332a8088fSRui Paulo 92432a8088fSRui Paulo val = val & ASMC_STATUS_MASK; 92532a8088fSRui Paulo 926be80e49aSRui Paulo for (i = 0; i < amount; i++) { 9274470f0f3SRui Paulo if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 92832a8088fSRui Paulo return (0); 92932a8088fSRui Paulo DELAY(10); 93032a8088fSRui Paulo } 93132a8088fSRui Paulo 932be80e49aSRui Paulo return (1); 933be80e49aSRui Paulo } 934be80e49aSRui Paulo 935be80e49aSRui Paulo /* 936be80e49aSRui Paulo * We need to make sure that the SMC acks the byte sent. 937be80e49aSRui Paulo * Just wait up to 100 ms. 938be80e49aSRui Paulo */ 939be80e49aSRui Paulo static int 940be80e49aSRui Paulo asmc_wait(device_t dev, uint8_t val) 941be80e49aSRui Paulo { 942e02d0cabSMateusz Guzik #ifdef DEBUG 943be80e49aSRui Paulo struct asmc_softc *sc; 944e02d0cabSMateusz Guzik #endif 945be80e49aSRui Paulo 946be80e49aSRui Paulo if (asmc_wait_ack(dev, val, 1000) == 0) 947be80e49aSRui Paulo return (0); 948be80e49aSRui Paulo 949e02d0cabSMateusz Guzik #ifdef DEBUG 950be80e49aSRui Paulo sc = device_get_softc(dev); 951e02d0cabSMateusz Guzik #endif 952be80e49aSRui Paulo val = val & ASMC_STATUS_MASK; 953be80e49aSRui Paulo 954be80e49aSRui Paulo #ifdef DEBUG 95532a8088fSRui Paulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 9564470f0f3SRui Paulo ASMC_CMDPORT_READ(sc)); 957be80e49aSRui Paulo #endif 958be80e49aSRui Paulo return (1); 959be80e49aSRui Paulo } 96032a8088fSRui Paulo 961be80e49aSRui Paulo /* 962be80e49aSRui Paulo * Send the given command, retrying up to 10 times if 963be80e49aSRui Paulo * the acknowledgement fails. 964be80e49aSRui Paulo */ 965be80e49aSRui Paulo static int 966be80e49aSRui Paulo asmc_command(device_t dev, uint8_t command) { 967be80e49aSRui Paulo int i; 968be80e49aSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 969be80e49aSRui Paulo 970be80e49aSRui Paulo for (i=0; i < 10; i++) { 971be80e49aSRui Paulo ASMC_CMDPORT_WRITE(sc, command); 972be80e49aSRui Paulo if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 973be80e49aSRui Paulo return (0); 974be80e49aSRui Paulo } 975be80e49aSRui Paulo } 976be80e49aSRui Paulo 977be80e49aSRui Paulo #ifdef DEBUG 978be80e49aSRui Paulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 979be80e49aSRui Paulo ASMC_CMDPORT_READ(sc)); 980be80e49aSRui Paulo #endif 98132a8088fSRui Paulo return (1); 98232a8088fSRui Paulo } 98332a8088fSRui Paulo 98432a8088fSRui Paulo static int 98532a8088fSRui Paulo asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 98632a8088fSRui Paulo { 987be80e49aSRui Paulo int i, error = 1, try = 0; 98832a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 98932a8088fSRui Paulo 99032a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 99132a8088fSRui Paulo 992be80e49aSRui Paulo begin: 993be80e49aSRui Paulo if (asmc_command(dev, ASMC_CMDREAD)) 99432a8088fSRui Paulo goto out; 99532a8088fSRui Paulo 99632a8088fSRui Paulo for (i = 0; i < 4; i++) { 9974470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 99832a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 99932a8088fSRui Paulo goto out; 100032a8088fSRui Paulo } 100132a8088fSRui Paulo 10024470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, len); 100332a8088fSRui Paulo 100432a8088fSRui Paulo for (i = 0; i < len; i++) { 100532a8088fSRui Paulo if (asmc_wait(dev, 0x05)) 100632a8088fSRui Paulo goto out; 10074470f0f3SRui Paulo buf[i] = ASMC_DATAPORT_READ(sc); 100832a8088fSRui Paulo } 100932a8088fSRui Paulo 101032a8088fSRui Paulo error = 0; 101132a8088fSRui Paulo out: 1012be80e49aSRui Paulo if (error) { 1013be80e49aSRui Paulo if (++try < 10) goto begin; 1014be80e49aSRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 1015be80e49aSRui Paulo __func__, key, try); 1016be80e49aSRui Paulo } 1017be80e49aSRui Paulo 101832a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 101932a8088fSRui Paulo 102032a8088fSRui Paulo return (error); 102132a8088fSRui Paulo } 102232a8088fSRui Paulo 10231269f4d4SRui Paulo #ifdef DEBUG 10241269f4d4SRui Paulo static int 10251269f4d4SRui Paulo asmc_key_dump(device_t dev, int number) 10261269f4d4SRui Paulo { 10271269f4d4SRui Paulo struct asmc_softc *sc = device_get_softc(dev); 10281269f4d4SRui Paulo char key[5] = { 0 }; 10291269f4d4SRui Paulo char type[7] = { 0 }; 10301269f4d4SRui Paulo uint8_t index[4]; 10311269f4d4SRui Paulo uint8_t v[32]; 10321269f4d4SRui Paulo uint8_t maxlen; 10331269f4d4SRui Paulo int i, error = 1, try = 0; 10341269f4d4SRui Paulo 10351269f4d4SRui Paulo mtx_lock_spin(&sc->sc_mtx); 10361269f4d4SRui Paulo 10371269f4d4SRui Paulo index[0] = (number >> 24) & 0xff; 10381269f4d4SRui Paulo index[1] = (number >> 16) & 0xff; 10391269f4d4SRui Paulo index[2] = (number >> 8) & 0xff; 10401269f4d4SRui Paulo index[3] = (number) & 0xff; 10411269f4d4SRui Paulo 10421269f4d4SRui Paulo begin: 10431269f4d4SRui Paulo if (asmc_command(dev, 0x12)) 10441269f4d4SRui Paulo goto out; 10451269f4d4SRui Paulo 10461269f4d4SRui Paulo for (i = 0; i < 4; i++) { 10471269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, index[i]); 10481269f4d4SRui Paulo if (asmc_wait(dev, 0x04)) 10491269f4d4SRui Paulo goto out; 10501269f4d4SRui Paulo } 10511269f4d4SRui Paulo 10521269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, 4); 10531269f4d4SRui Paulo 10541269f4d4SRui Paulo for (i = 0; i < 4; i++) { 10551269f4d4SRui Paulo if (asmc_wait(dev, 0x05)) 10561269f4d4SRui Paulo goto out; 10571269f4d4SRui Paulo key[i] = ASMC_DATAPORT_READ(sc); 10581269f4d4SRui Paulo } 10591269f4d4SRui Paulo 10601269f4d4SRui Paulo /* get type */ 10611269f4d4SRui Paulo if (asmc_command(dev, 0x13)) 10621269f4d4SRui Paulo goto out; 10631269f4d4SRui Paulo 10641269f4d4SRui Paulo for (i = 0; i < 4; i++) { 10651269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 10661269f4d4SRui Paulo if (asmc_wait(dev, 0x04)) 10671269f4d4SRui Paulo goto out; 10681269f4d4SRui Paulo } 10691269f4d4SRui Paulo 10701269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, 6); 10711269f4d4SRui Paulo 10721269f4d4SRui Paulo for (i = 0; i < 6; i++) { 10731269f4d4SRui Paulo if (asmc_wait(dev, 0x05)) 10741269f4d4SRui Paulo goto out; 10751269f4d4SRui Paulo type[i] = ASMC_DATAPORT_READ(sc); 10761269f4d4SRui Paulo } 10771269f4d4SRui Paulo 10781269f4d4SRui Paulo error = 0; 10791269f4d4SRui Paulo out: 10801269f4d4SRui Paulo if (error) { 10811269f4d4SRui Paulo if (++try < 10) goto begin; 10821269f4d4SRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 10831269f4d4SRui Paulo __func__, key, try); 10841269f4d4SRui Paulo mtx_unlock_spin(&sc->sc_mtx); 10851269f4d4SRui Paulo } 10861269f4d4SRui Paulo else { 10871269f4d4SRui Paulo char buf[1024]; 10881269f4d4SRui Paulo char buf2[8]; 10891269f4d4SRui Paulo mtx_unlock_spin(&sc->sc_mtx); 10901269f4d4SRui Paulo maxlen = type[0]; 10911269f4d4SRui Paulo type[0] = ' '; 10921269f4d4SRui Paulo type[5] = 0; 10931269f4d4SRui Paulo if (maxlen > sizeof(v)) { 1094f17bca82SRui Paulo device_printf(dev, 1095f17bca82SRui Paulo "WARNING: cropping maxlen from %d to %zu\n", 1096f17bca82SRui Paulo maxlen, sizeof(v)); 10971269f4d4SRui Paulo maxlen = sizeof(v); 10981269f4d4SRui Paulo } 10991269f4d4SRui Paulo for (i = 0; i < sizeof(v); i++) { 11001269f4d4SRui Paulo v[i] = 0; 11011269f4d4SRui Paulo } 11021269f4d4SRui Paulo asmc_key_read(dev, key, v, maxlen); 11031269f4d4SRui Paulo snprintf(buf, sizeof(buf), "key %d is: %s, type %s " 11041269f4d4SRui Paulo "(len %d), data", number, key, type, maxlen); 11051269f4d4SRui Paulo for (i = 0; i < maxlen; i++) { 1106108e3076SAdrian Chadd snprintf(buf2, sizeof(buf2), " %02x", v[i]); 11071269f4d4SRui Paulo strlcat(buf, buf2, sizeof(buf)); 11081269f4d4SRui Paulo } 11091269f4d4SRui Paulo strlcat(buf, " \n", sizeof(buf)); 111046c76550SRoman Divacky device_printf(dev, "%s", buf); 11111269f4d4SRui Paulo } 11121269f4d4SRui Paulo 11131269f4d4SRui Paulo return (error); 11141269f4d4SRui Paulo } 11151269f4d4SRui Paulo #endif 11161269f4d4SRui Paulo 111732a8088fSRui Paulo static int 111832a8088fSRui Paulo asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 111932a8088fSRui Paulo { 1120be80e49aSRui Paulo int i, error = -1, try = 0; 112132a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 112232a8088fSRui Paulo 112332a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 112432a8088fSRui Paulo 1125be80e49aSRui Paulo begin: 11264470f0f3SRui Paulo ASMC_DPRINTF(("cmd port: cmd write\n")); 1127be80e49aSRui Paulo if (asmc_command(dev, ASMC_CMDWRITE)) 112832a8088fSRui Paulo goto out; 112932a8088fSRui Paulo 11304470f0f3SRui Paulo ASMC_DPRINTF(("data port: key\n")); 113132a8088fSRui Paulo for (i = 0; i < 4; i++) { 11324470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 113332a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 113432a8088fSRui Paulo goto out; 113532a8088fSRui Paulo } 11364470f0f3SRui Paulo ASMC_DPRINTF(("data port: length\n")); 11374470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, len); 113832a8088fSRui Paulo 11394470f0f3SRui Paulo ASMC_DPRINTF(("data port: buffer\n")); 114032a8088fSRui Paulo for (i = 0; i < len; i++) { 114132a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 114232a8088fSRui Paulo goto out; 11434470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, buf[i]); 114432a8088fSRui Paulo } 114532a8088fSRui Paulo 114632a8088fSRui Paulo error = 0; 114732a8088fSRui Paulo out: 1148be80e49aSRui Paulo if (error) { 1149be80e49aSRui Paulo if (++try < 10) goto begin; 1150be80e49aSRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 1151be80e49aSRui Paulo __func__, key, try); 1152be80e49aSRui Paulo } 1153be80e49aSRui Paulo 115432a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 115532a8088fSRui Paulo 115632a8088fSRui Paulo return (error); 115732a8088fSRui Paulo 115832a8088fSRui Paulo } 115932a8088fSRui Paulo 116032a8088fSRui Paulo /* 116132a8088fSRui Paulo * Fan control functions. 116232a8088fSRui Paulo */ 116332a8088fSRui Paulo static int 116432a8088fSRui Paulo asmc_fan_count(device_t dev) 116532a8088fSRui Paulo { 116632a8088fSRui Paulo uint8_t buf[1]; 116732a8088fSRui Paulo 11689c325393SMark Johnston if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) != 0) 116932a8088fSRui Paulo return (-1); 117032a8088fSRui Paulo 117132a8088fSRui Paulo return (buf[0]); 117232a8088fSRui Paulo } 117332a8088fSRui Paulo 117432a8088fSRui Paulo static int 117532a8088fSRui Paulo asmc_fan_getvalue(device_t dev, const char *key, int fan) 117632a8088fSRui Paulo { 117732a8088fSRui Paulo int speed; 117832a8088fSRui Paulo uint8_t buf[2]; 117932a8088fSRui Paulo char fankey[5]; 118032a8088fSRui Paulo 118132a8088fSRui Paulo snprintf(fankey, sizeof(fankey), key, fan); 11829c325393SMark Johnston if (asmc_key_read(dev, fankey, buf, sizeof buf) != 0) 118332a8088fSRui Paulo return (-1); 118432a8088fSRui Paulo speed = (buf[0] << 6) | (buf[1] >> 2); 118532a8088fSRui Paulo 118632a8088fSRui Paulo return (speed); 118732a8088fSRui Paulo } 118832a8088fSRui Paulo 1189447666f0SRui Paulo static char* 1190623534d6SUlrich Spörlein asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen) 1191447666f0SRui Paulo { 1192447666f0SRui Paulo char fankey[5]; 1193447666f0SRui Paulo char* desc; 1194447666f0SRui Paulo 1195447666f0SRui Paulo snprintf(fankey, sizeof(fankey), key, fan); 11969c325393SMark Johnston if (asmc_key_read(dev, fankey, buf, buflen) != 0) 1197447666f0SRui Paulo return (NULL); 1198447666f0SRui Paulo desc = buf+4; 1199447666f0SRui Paulo 1200447666f0SRui Paulo return (desc); 1201447666f0SRui Paulo } 1202447666f0SRui Paulo 1203447666f0SRui Paulo static int 1204447666f0SRui Paulo asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 1205447666f0SRui Paulo { 1206447666f0SRui Paulo uint8_t buf[2]; 1207447666f0SRui Paulo char fankey[5]; 1208447666f0SRui Paulo 1209447666f0SRui Paulo speed *= 4; 1210447666f0SRui Paulo 1211447666f0SRui Paulo buf[0] = speed>>8; 1212447666f0SRui Paulo buf[1] = speed; 1213447666f0SRui Paulo 1214447666f0SRui Paulo snprintf(fankey, sizeof(fankey), key, fan); 1215447666f0SRui Paulo if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0) 1216447666f0SRui Paulo return (-1); 1217447666f0SRui Paulo 1218447666f0SRui Paulo return (0); 1219447666f0SRui Paulo } 1220447666f0SRui Paulo 122132a8088fSRui Paulo static int 122232a8088fSRui Paulo asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 122332a8088fSRui Paulo { 122432a8088fSRui Paulo device_t dev = (device_t) arg1; 122532a8088fSRui Paulo int fan = arg2; 122632a8088fSRui Paulo int error; 122732a8088fSRui Paulo int32_t v; 122832a8088fSRui Paulo 122932a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 123032a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 123132a8088fSRui Paulo 123232a8088fSRui Paulo return (error); 123332a8088fSRui Paulo } 123432a8088fSRui Paulo 123532a8088fSRui Paulo static int 1236447666f0SRui Paulo asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 1237447666f0SRui Paulo { 1238623534d6SUlrich Spörlein uint8_t buf[16]; 1239447666f0SRui Paulo device_t dev = (device_t) arg1; 1240447666f0SRui Paulo int fan = arg2; 1241447666f0SRui Paulo int error = true; 1242447666f0SRui Paulo char* desc; 1243447666f0SRui Paulo 1244623534d6SUlrich Spörlein desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); 1245447666f0SRui Paulo 1246447666f0SRui Paulo if (desc != NULL) 1247447666f0SRui Paulo error = sysctl_handle_string(oidp, desc, 0, req); 1248447666f0SRui Paulo 1249447666f0SRui Paulo return (error); 1250447666f0SRui Paulo } 1251447666f0SRui Paulo 1252447666f0SRui Paulo static int 125332a8088fSRui Paulo asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 125432a8088fSRui Paulo { 125532a8088fSRui Paulo device_t dev = (device_t) arg1; 125632a8088fSRui Paulo int fan = arg2; 125732a8088fSRui Paulo int error; 125832a8088fSRui Paulo int32_t v; 125932a8088fSRui Paulo 126032a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 126132a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 126232a8088fSRui Paulo 126332a8088fSRui Paulo return (error); 126432a8088fSRui Paulo } 126532a8088fSRui Paulo 126632a8088fSRui Paulo static int 126732a8088fSRui Paulo asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 126832a8088fSRui Paulo { 126932a8088fSRui Paulo device_t dev = (device_t) arg1; 127032a8088fSRui Paulo int fan = arg2; 127132a8088fSRui Paulo int error; 127232a8088fSRui Paulo int32_t v; 127332a8088fSRui Paulo 127432a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 127532a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 127632a8088fSRui Paulo 1277447666f0SRui Paulo if (error == 0 && req->newptr != NULL) { 12780e1152fcSHans Petter Selasky unsigned int newspeed = v; 1279447666f0SRui Paulo asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 1280447666f0SRui Paulo } 1281447666f0SRui Paulo 128232a8088fSRui Paulo return (error); 128332a8088fSRui Paulo } 128432a8088fSRui Paulo 128532a8088fSRui Paulo static int 128632a8088fSRui Paulo asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 128732a8088fSRui Paulo { 128832a8088fSRui Paulo device_t dev = (device_t) arg1; 128932a8088fSRui Paulo int fan = arg2; 129032a8088fSRui Paulo int error; 129132a8088fSRui Paulo int32_t v; 129232a8088fSRui Paulo 129332a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 129432a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 129532a8088fSRui Paulo 1296447666f0SRui Paulo if (error == 0 && req->newptr != NULL) { 12970e1152fcSHans Petter Selasky unsigned int newspeed = v; 1298447666f0SRui Paulo asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 1299447666f0SRui Paulo } 1300447666f0SRui Paulo 130132a8088fSRui Paulo return (error); 130232a8088fSRui Paulo } 130332a8088fSRui Paulo 130432a8088fSRui Paulo static int 130532a8088fSRui Paulo asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 130632a8088fSRui Paulo { 130732a8088fSRui Paulo device_t dev = (device_t) arg1; 130832a8088fSRui Paulo int fan = arg2; 130932a8088fSRui Paulo int error; 131032a8088fSRui Paulo int32_t v; 131132a8088fSRui Paulo 131232a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 131332a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 131432a8088fSRui Paulo 1315447666f0SRui Paulo if (error == 0 && req->newptr != NULL) { 13160e1152fcSHans Petter Selasky unsigned int newspeed = v; 1317447666f0SRui Paulo asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 1318447666f0SRui Paulo } 1319447666f0SRui Paulo 132032a8088fSRui Paulo return (error); 132132a8088fSRui Paulo } 132232a8088fSRui Paulo 132332a8088fSRui Paulo /* 132432a8088fSRui Paulo * Temperature functions. 132532a8088fSRui Paulo */ 132632a8088fSRui Paulo static int 132732a8088fSRui Paulo asmc_temp_getvalue(device_t dev, const char *key) 132832a8088fSRui Paulo { 132932a8088fSRui Paulo uint8_t buf[2]; 133032a8088fSRui Paulo 133132a8088fSRui Paulo /* 133232a8088fSRui Paulo * Check for invalid temperatures. 133332a8088fSRui Paulo */ 13349c325393SMark Johnston if (asmc_key_read(dev, key, buf, sizeof buf) != 0) 133532a8088fSRui Paulo return (-1); 133632a8088fSRui Paulo 133732a8088fSRui Paulo return (buf[0]); 133832a8088fSRui Paulo } 133932a8088fSRui Paulo 134032a8088fSRui Paulo static int 134132a8088fSRui Paulo asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 134232a8088fSRui Paulo { 134332a8088fSRui Paulo device_t dev = (device_t) arg1; 134432a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 134532a8088fSRui Paulo int error, val; 134632a8088fSRui Paulo 134732a8088fSRui Paulo val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 134832a8088fSRui Paulo error = sysctl_handle_int(oidp, &val, 0, req); 134932a8088fSRui Paulo 135032a8088fSRui Paulo return (error); 135132a8088fSRui Paulo } 135232a8088fSRui Paulo 135332a8088fSRui Paulo /* 135432a8088fSRui Paulo * Sudden Motion Sensor functions. 135532a8088fSRui Paulo */ 135632a8088fSRui Paulo static int 135732a8088fSRui Paulo asmc_sms_read(device_t dev, const char *key, int16_t *val) 135832a8088fSRui Paulo { 135932a8088fSRui Paulo uint8_t buf[2]; 136032a8088fSRui Paulo int error; 136132a8088fSRui Paulo 136232a8088fSRui Paulo /* no need to do locking here as asmc_key_read() already does it */ 136332a8088fSRui Paulo switch (key[3]) { 136432a8088fSRui Paulo case 'X': 136532a8088fSRui Paulo case 'Y': 136632a8088fSRui Paulo case 'Z': 1367447666f0SRui Paulo error = asmc_key_read(dev, key, buf, sizeof buf); 136832a8088fSRui Paulo break; 136932a8088fSRui Paulo default: 137032a8088fSRui Paulo device_printf(dev, "%s called with invalid argument %s\n", 137132a8088fSRui Paulo __func__, key); 137232a8088fSRui Paulo error = 1; 137332a8088fSRui Paulo goto out; 137432a8088fSRui Paulo } 137532a8088fSRui Paulo *val = ((int16_t)buf[0] << 8) | buf[1]; 137632a8088fSRui Paulo out: 137732a8088fSRui Paulo return (error); 137832a8088fSRui Paulo } 137932a8088fSRui Paulo 138032a8088fSRui Paulo static void 138132a8088fSRui Paulo asmc_sms_calibrate(device_t dev) 138232a8088fSRui Paulo { 138332a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 138432a8088fSRui Paulo 138532a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 138632a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 138732a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 138832a8088fSRui Paulo } 138932a8088fSRui Paulo 139032a8088fSRui Paulo static int 139132a8088fSRui Paulo asmc_sms_intrfast(void *arg) 139232a8088fSRui Paulo { 139332a8088fSRui Paulo uint8_t type; 139432a8088fSRui Paulo device_t dev = (device_t) arg; 139532a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 13961269f4d4SRui Paulo if (!sc->sc_sms_intr_works) 13971269f4d4SRui Paulo return (FILTER_HANDLED); 139832a8088fSRui Paulo 139932a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 14004470f0f3SRui Paulo type = ASMC_INTPORT_READ(sc); 140132a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 140232a8088fSRui Paulo 140332a8088fSRui Paulo sc->sc_sms_intrtype = type; 140432a8088fSRui Paulo asmc_sms_printintr(dev, type); 140532a8088fSRui Paulo 140632a8088fSRui Paulo taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 140732a8088fSRui Paulo return (FILTER_HANDLED); 140832a8088fSRui Paulo } 140932a8088fSRui Paulo 141032a8088fSRui Paulo static void 141132a8088fSRui Paulo asmc_sms_printintr(device_t dev, uint8_t type) 141232a8088fSRui Paulo { 14133416f5cdSed crowe struct asmc_softc *sc = device_get_softc(dev); 141432a8088fSRui Paulo 141532a8088fSRui Paulo switch (type) { 141632a8088fSRui Paulo case ASMC_SMS_INTFF: 141732a8088fSRui Paulo device_printf(dev, "WARNING: possible free fall!\n"); 141832a8088fSRui Paulo break; 141932a8088fSRui Paulo case ASMC_SMS_INTHA: 142032a8088fSRui Paulo device_printf(dev, "WARNING: high acceleration detected!\n"); 142132a8088fSRui Paulo break; 142232a8088fSRui Paulo case ASMC_SMS_INTSH: 142332a8088fSRui Paulo device_printf(dev, "WARNING: possible shock!\n"); 142432a8088fSRui Paulo break; 14253416f5cdSed crowe case ASMC_ALSL_INT2A: 14263416f5cdSed crowe /* 14273416f5cdSed crowe * This suppresses console and log messages for the ambient 1428638937d4SMichael Gmelin * light sensor for models known to generate this interrupt. 14293416f5cdSed crowe */ 1430638937d4SMichael Gmelin if (strcmp(sc->sc_model->smc_model, "MacBookPro5,5") == 0 || 1431638937d4SMichael Gmelin strcmp(sc->sc_model->smc_model, "MacBookPro6,2") == 0) 14323416f5cdSed crowe break; 14333416f5cdSed crowe /* FALLTHROUGH */ 143432a8088fSRui Paulo default: 14353416f5cdSed crowe device_printf(dev, "unknown interrupt: 0x%x\n", type); 143632a8088fSRui Paulo } 143732a8088fSRui Paulo } 143832a8088fSRui Paulo 143932a8088fSRui Paulo static void 144032a8088fSRui Paulo asmc_sms_task(void *arg, int pending) 144132a8088fSRui Paulo { 144232a8088fSRui Paulo struct asmc_softc *sc = (struct asmc_softc *)arg; 144332a8088fSRui Paulo char notify[16]; 144432a8088fSRui Paulo int type; 144532a8088fSRui Paulo 144632a8088fSRui Paulo switch (sc->sc_sms_intrtype) { 144732a8088fSRui Paulo case ASMC_SMS_INTFF: 144832a8088fSRui Paulo type = 2; 144932a8088fSRui Paulo break; 145032a8088fSRui Paulo case ASMC_SMS_INTHA: 145132a8088fSRui Paulo type = 1; 145232a8088fSRui Paulo break; 145332a8088fSRui Paulo case ASMC_SMS_INTSH: 145432a8088fSRui Paulo type = 0; 145532a8088fSRui Paulo break; 145632a8088fSRui Paulo default: 145732a8088fSRui Paulo type = 255; 145832a8088fSRui Paulo } 145932a8088fSRui Paulo 146032a8088fSRui Paulo snprintf(notify, sizeof(notify), " notify=0x%x", type); 14614470f0f3SRui Paulo devctl_notify("ACPI", "asmc", "SMS", notify); 146232a8088fSRui Paulo } 146332a8088fSRui Paulo 146432a8088fSRui Paulo static int 146532a8088fSRui Paulo asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 146632a8088fSRui Paulo { 146732a8088fSRui Paulo device_t dev = (device_t) arg1; 146832a8088fSRui Paulo int error; 146932a8088fSRui Paulo int16_t val; 147032a8088fSRui Paulo int32_t v; 147132a8088fSRui Paulo 147232a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 147332a8088fSRui Paulo v = (int32_t) val; 147432a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 147532a8088fSRui Paulo 147632a8088fSRui Paulo return (error); 147732a8088fSRui Paulo } 147832a8088fSRui Paulo 147932a8088fSRui Paulo static int 148032a8088fSRui Paulo asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 148132a8088fSRui Paulo { 148232a8088fSRui Paulo device_t dev = (device_t) arg1; 148332a8088fSRui Paulo int error; 148432a8088fSRui Paulo int16_t val; 148532a8088fSRui Paulo int32_t v; 148632a8088fSRui Paulo 148732a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 148832a8088fSRui Paulo v = (int32_t) val; 148932a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 149032a8088fSRui Paulo 149132a8088fSRui Paulo return (error); 149232a8088fSRui Paulo } 149332a8088fSRui Paulo 149432a8088fSRui Paulo static int 149532a8088fSRui Paulo asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 149632a8088fSRui Paulo { 149732a8088fSRui Paulo device_t dev = (device_t) arg1; 149832a8088fSRui Paulo int error; 149932a8088fSRui Paulo int16_t val; 150032a8088fSRui Paulo int32_t v; 150132a8088fSRui Paulo 150232a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 150332a8088fSRui Paulo v = (int32_t) val; 15040e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 150532a8088fSRui Paulo 150632a8088fSRui Paulo return (error); 150732a8088fSRui Paulo } 150832a8088fSRui Paulo 150932a8088fSRui Paulo static int 151032a8088fSRui Paulo asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 151132a8088fSRui Paulo { 151232a8088fSRui Paulo device_t dev = (device_t) arg1; 151332a8088fSRui Paulo uint8_t buf[6]; 151432a8088fSRui Paulo int error; 151532a8088fSRui Paulo int32_t v; 151632a8088fSRui Paulo 1517447666f0SRui Paulo asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); 151832a8088fSRui Paulo v = buf[2]; 15190e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 152032a8088fSRui Paulo 152132a8088fSRui Paulo return (error); 152232a8088fSRui Paulo } 152332a8088fSRui Paulo 152432a8088fSRui Paulo static int 152532a8088fSRui Paulo asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 152632a8088fSRui Paulo { 152732a8088fSRui Paulo device_t dev = (device_t) arg1; 152832a8088fSRui Paulo uint8_t buf[6]; 152932a8088fSRui Paulo int error; 153032a8088fSRui Paulo int32_t v; 153132a8088fSRui Paulo 1532447666f0SRui Paulo asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf); 153332a8088fSRui Paulo v = buf[2]; 15340e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 1535be80e49aSRui Paulo 1536be80e49aSRui Paulo return (error); 1537be80e49aSRui Paulo } 1538be80e49aSRui Paulo 1539be80e49aSRui Paulo static int 1540be80e49aSRui Paulo asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 1541be80e49aSRui Paulo { 1542be80e49aSRui Paulo device_t dev = (device_t) arg1; 1543be80e49aSRui Paulo uint8_t buf[2]; 1544be80e49aSRui Paulo int error; 15450e1152fcSHans Petter Selasky int v; 1546be80e49aSRui Paulo 1547108e3076SAdrian Chadd v = light_control; 15480e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 15490e1152fcSHans Petter Selasky 15500e1152fcSHans Petter Selasky if (error == 0 && req->newptr != NULL) { 15510e1152fcSHans Petter Selasky if (v < 0 || v > 255) 15520e1152fcSHans Petter Selasky return (EINVAL); 1553108e3076SAdrian Chadd light_control = v; 1554108e3076SAdrian Chadd buf[0] = light_control; 155532a8088fSRui Paulo buf[1] = 0x00; 1556447666f0SRui Paulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 155732a8088fSRui Paulo } 155832a8088fSRui Paulo return (error); 155932a8088fSRui Paulo } 15602e9d05fdSAdrian Chadd 15612e9d05fdSAdrian Chadd static int 15622e9d05fdSAdrian Chadd asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS) 15632e9d05fdSAdrian Chadd { 15642e9d05fdSAdrian Chadd device_t dev = (device_t) arg1; 15652e9d05fdSAdrian Chadd uint8_t buf[10]; 15662e9d05fdSAdrian Chadd int error; 15672e9d05fdSAdrian Chadd uint32_t v; 15682e9d05fdSAdrian Chadd 15692e9d05fdSAdrian Chadd asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); 15702e9d05fdSAdrian Chadd 15712e9d05fdSAdrian Chadd /* 15722e9d05fdSAdrian Chadd * This seems to be a 32 bit big endian value from buf[6] -> buf[9]. 15732e9d05fdSAdrian Chadd * 15742e9d05fdSAdrian Chadd * Extract it out manually here, then shift/clamp it. 15752e9d05fdSAdrian Chadd */ 15762e9d05fdSAdrian Chadd v = be32dec(&buf[6]); 15772e9d05fdSAdrian Chadd 15782e9d05fdSAdrian Chadd /* 15792e9d05fdSAdrian Chadd * Shift out, clamp at 255; that way it looks like the 15802e9d05fdSAdrian Chadd * earlier SMC firmware version responses. 15812e9d05fdSAdrian Chadd */ 15822e9d05fdSAdrian Chadd v = v >> 8; 15832e9d05fdSAdrian Chadd if (v > 255) 15842e9d05fdSAdrian Chadd v = 255; 15852e9d05fdSAdrian Chadd 15862e9d05fdSAdrian Chadd error = sysctl_handle_int(oidp, &v, 0, req); 15872e9d05fdSAdrian Chadd 15882e9d05fdSAdrian Chadd return (error); 15892e9d05fdSAdrian Chadd } 1590