132a8088fSRui Paulo /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 3832a8088fSRui Paulo __FBSDID("$FreeBSD$"); 3932a8088fSRui Paulo 4032a8088fSRui Paulo #include <sys/param.h> 4132a8088fSRui Paulo #include <sys/bus.h> 4232a8088fSRui Paulo #include <sys/conf.h> 4332a8088fSRui Paulo #include <sys/kernel.h> 4432a8088fSRui Paulo #include <sys/lock.h> 4532a8088fSRui Paulo #include <sys/malloc.h> 4632a8088fSRui Paulo #include <sys/module.h> 4732a8088fSRui Paulo #include <sys/mutex.h> 4832a8088fSRui Paulo #include <sys/sysctl.h> 4932a8088fSRui Paulo #include <sys/systm.h> 5032a8088fSRui Paulo #include <sys/taskqueue.h> 5132a8088fSRui Paulo #include <sys/rman.h> 524c061448SRui Paulo 5332a8088fSRui Paulo #include <machine/resource.h> 54129d3046SJung-uk Kim 55129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h> 56129d3046SJung-uk Kim 574470f0f3SRui Paulo #include <dev/acpica/acpivar.h> 5832a8088fSRui Paulo #include <dev/asmc/asmcvar.h> 5932a8088fSRui Paulo 6032a8088fSRui Paulo /* 6132a8088fSRui Paulo * Device interface. 6232a8088fSRui Paulo */ 6332a8088fSRui Paulo static int asmc_probe(device_t dev); 6432a8088fSRui Paulo static int asmc_attach(device_t dev); 6532a8088fSRui Paulo static int asmc_detach(device_t dev); 66108e3076SAdrian Chadd static int asmc_resume(device_t dev); 6732a8088fSRui Paulo 6832a8088fSRui Paulo /* 6932a8088fSRui Paulo * SMC functions. 7032a8088fSRui Paulo */ 7132a8088fSRui Paulo static int asmc_init(device_t dev); 72be80e49aSRui Paulo static int asmc_command(device_t dev, uint8_t command); 7332a8088fSRui Paulo static int asmc_wait(device_t dev, uint8_t val); 74be80e49aSRui Paulo static int asmc_wait_ack(device_t dev, uint8_t val, int amount); 7532a8088fSRui Paulo static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 7632a8088fSRui Paulo uint8_t len); 7732a8088fSRui Paulo static int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 7832a8088fSRui Paulo uint8_t); 7932a8088fSRui Paulo static int asmc_fan_count(device_t dev); 8032a8088fSRui Paulo static int asmc_fan_getvalue(device_t dev, const char *key, int fan); 81447666f0SRui Paulo static int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed); 8232a8088fSRui Paulo static int asmc_temp_getvalue(device_t dev, const char *key); 8332a8088fSRui Paulo static int asmc_sms_read(device_t, const char *key, int16_t *val); 8432a8088fSRui Paulo static void asmc_sms_calibrate(device_t dev); 8532a8088fSRui Paulo static int asmc_sms_intrfast(void *arg); 8632a8088fSRui Paulo static void asmc_sms_printintr(device_t dev, uint8_t); 8732a8088fSRui Paulo static void asmc_sms_task(void *arg, int pending); 881269f4d4SRui Paulo #ifdef DEBUG 891269f4d4SRui Paulo void asmc_dumpall(device_t); 901269f4d4SRui Paulo static int asmc_key_dump(device_t, int); 911269f4d4SRui Paulo #endif 9232a8088fSRui Paulo 9332a8088fSRui Paulo /* 9432a8088fSRui Paulo * Model functions. 9532a8088fSRui Paulo */ 96447666f0SRui Paulo static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS); 9732a8088fSRui Paulo static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 9832a8088fSRui Paulo static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 9932a8088fSRui Paulo static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 10032a8088fSRui Paulo static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 10132a8088fSRui Paulo static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 10232a8088fSRui Paulo static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 10332a8088fSRui Paulo static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 10432a8088fSRui Paulo static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 10532a8088fSRui Paulo static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 10632a8088fSRui Paulo static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 10732a8088fSRui Paulo static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 108be80e49aSRui Paulo static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); 10932a8088fSRui Paulo 11032a8088fSRui Paulo struct asmc_model { 11132a8088fSRui Paulo const char *smc_model; /* smbios.system.product env var. */ 11232a8088fSRui Paulo const char *smc_desc; /* driver description */ 11332a8088fSRui Paulo 11432a8088fSRui Paulo /* Helper functions */ 11532a8088fSRui Paulo int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); 11632a8088fSRui Paulo int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); 11732a8088fSRui Paulo int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); 118447666f0SRui Paulo int (*smc_fan_id)(SYSCTL_HANDLER_ARGS); 11932a8088fSRui Paulo int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); 12032a8088fSRui Paulo int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); 12132a8088fSRui Paulo int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); 12232a8088fSRui Paulo int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); 12332a8088fSRui Paulo int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); 12432a8088fSRui Paulo int (*smc_light_left)(SYSCTL_HANDLER_ARGS); 12532a8088fSRui Paulo int (*smc_light_right)(SYSCTL_HANDLER_ARGS); 126be80e49aSRui Paulo int (*smc_light_control)(SYSCTL_HANDLER_ARGS); 12732a8088fSRui Paulo 128d8246db0SRui Paulo const char *smc_temps[ASMC_TEMP_MAX]; 129d8246db0SRui Paulo const char *smc_tempnames[ASMC_TEMP_MAX]; 130d8246db0SRui Paulo const char *smc_tempdescs[ASMC_TEMP_MAX]; 13132a8088fSRui Paulo }; 13232a8088fSRui Paulo 13332a8088fSRui Paulo static struct asmc_model *asmc_match(device_t dev); 13432a8088fSRui Paulo 13532a8088fSRui Paulo #define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ 13632a8088fSRui Paulo asmc_mb_sysctl_sms_z 13732a8088fSRui Paulo 138108e3076SAdrian Chadd #define ASMC_SMS_FUNCS_DISABLED NULL,NULL,NULL 139108e3076SAdrian Chadd 140447666f0SRui Paulo #define ASMC_FAN_FUNCS asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ 14132a8088fSRui Paulo asmc_mb_sysctl_fanminspeed, \ 14232a8088fSRui Paulo asmc_mb_sysctl_fanmaxspeed, \ 14332a8088fSRui Paulo asmc_mb_sysctl_fantargetspeed 144108e3076SAdrian Chadd 145108e3076SAdrian Chadd #define ASMC_FAN_FUNCS2 asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \ 146108e3076SAdrian Chadd asmc_mb_sysctl_fanminspeed, \ 147108e3076SAdrian Chadd asmc_mb_sysctl_fanmaxspeed, \ 148108e3076SAdrian Chadd asmc_mb_sysctl_fantargetspeed 149108e3076SAdrian Chadd 15032a8088fSRui Paulo #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ 151be80e49aSRui Paulo asmc_mbp_sysctl_light_right, \ 152be80e49aSRui Paulo asmc_mbp_sysctl_light_control 15332a8088fSRui Paulo 1549f0bfc51SDavid Bright #define ASMC_LIGHT_FUNCS_DISABLED NULL, NULL, NULL 1559f0bfc51SDavid Bright 15632a8088fSRui Paulo struct asmc_model asmc_models[] = { 15732a8088fSRui Paulo { 15832a8088fSRui Paulo "MacBook1,1", "Apple SMC MacBook Core Duo", 159be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 16032a8088fSRui Paulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 16132a8088fSRui Paulo }, 16232a8088fSRui Paulo 16332a8088fSRui Paulo { 16432a8088fSRui Paulo "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 165be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 16632a8088fSRui Paulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 16732a8088fSRui Paulo }, 16832a8088fSRui Paulo 16932a8088fSRui Paulo { 170108e3076SAdrian Chadd "MacBook3,1", "Apple SMC MacBook Core 2 Duo", 171108e3076SAdrian Chadd ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 172108e3076SAdrian Chadd ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS 173108e3076SAdrian Chadd }, 174108e3076SAdrian Chadd 175108e3076SAdrian Chadd { 176e4a14ce7SMark Johnston "MacBook7,1", "Apple SMC MacBook Core 2 Duo (mid 2010)", 177e4a14ce7SMark Johnston ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED, 178e4a14ce7SMark Johnston ASMC_MB71_TEMPS, ASMC_MB71_TEMPNAMES, ASMC_MB71_TEMPDESCS 179e4a14ce7SMark Johnston }, 180e4a14ce7SMark Johnston 181e4a14ce7SMark Johnston { 18232a8088fSRui Paulo "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 18332a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 18432a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 18532a8088fSRui Paulo }, 18632a8088fSRui Paulo 18732a8088fSRui Paulo { 18832a8088fSRui Paulo "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 18932a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 19032a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 19132a8088fSRui Paulo }, 19232a8088fSRui Paulo 19332a8088fSRui Paulo { 19432a8088fSRui Paulo "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 19532a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 19632a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 19732a8088fSRui Paulo }, 19832a8088fSRui Paulo 19932a8088fSRui Paulo { 20032a8088fSRui Paulo "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 20132a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 20232a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 20332a8088fSRui Paulo }, 20432a8088fSRui Paulo 20532a8088fSRui Paulo { 20632a8088fSRui Paulo "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 20732a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 20832a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 20932a8088fSRui Paulo }, 21032a8088fSRui Paulo 21132a8088fSRui Paulo { 21232a8088fSRui Paulo "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 21332a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 21432a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 21532a8088fSRui Paulo }, 21632a8088fSRui Paulo 217be80e49aSRui Paulo { 218be80e49aSRui Paulo "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)", 219be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 220be80e49aSRui Paulo ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS 221be80e49aSRui Paulo }, 222be80e49aSRui Paulo 223447666f0SRui Paulo { 22431ae3b07SAdrian Chadd "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)", 22531ae3b07SAdrian Chadd ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 22631ae3b07SAdrian Chadd ASMC_MBP5_TEMPS, ASMC_MBP5_TEMPNAMES, ASMC_MBP5_TEMPDESCS 22731ae3b07SAdrian Chadd }, 22831ae3b07SAdrian Chadd 22931ae3b07SAdrian Chadd { 23009ff71d3SDavid Bright "MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)", 23109ff71d3SDavid Bright ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 23209ff71d3SDavid Bright ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS 23309ff71d3SDavid Bright }, 23409ff71d3SDavid Bright 23509ff71d3SDavid Bright { 236447666f0SRui Paulo "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)", 237447666f0SRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 23809ff71d3SDavid Bright ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS 239447666f0SRui Paulo }, 240447666f0SRui Paulo 241447666f0SRui Paulo { 24298ae4866SDavid Bright "MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012)", 24398ae4866SDavid Bright ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 24498ae4866SDavid Bright ASMC_MBP9_TEMPS, ASMC_MBP9_TEMPNAMES, ASMC_MBP9_TEMPDESCS 24598ae4866SDavid Bright }, 24698ae4866SDavid Bright 24798ae4866SDavid Bright { 248109e2d29SAdrian Chadd "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 249109e2d29SAdrian Chadd ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, 250109e2d29SAdrian Chadd ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS 251109e2d29SAdrian Chadd }, 252109e2d29SAdrian Chadd 253109e2d29SAdrian Chadd { 254447666f0SRui Paulo "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", 255447666f0SRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 256109e2d29SAdrian Chadd ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS 257447666f0SRui Paulo }, 258447666f0SRui Paulo 25932a8088fSRui Paulo /* The Mac Mini has no SMS */ 26032a8088fSRui Paulo { 26132a8088fSRui Paulo "Macmini1,1", "Apple SMC Mac Mini", 26232a8088fSRui Paulo NULL, NULL, NULL, 26332a8088fSRui Paulo ASMC_FAN_FUNCS, 264be80e49aSRui Paulo NULL, NULL, NULL, 26532a8088fSRui Paulo ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 26632a8088fSRui Paulo }, 26732a8088fSRui Paulo 2689e33968bSDavid Bright /* The Mac Mini 2,1 has no SMS */ 2699e33968bSDavid Bright { 2709e33968bSDavid Bright "Macmini2,1", "Apple SMC Mac Mini 2,1", 2719e33968bSDavid Bright ASMC_SMS_FUNCS_DISABLED, 2729e33968bSDavid Bright ASMC_FAN_FUNCS, 2739e33968bSDavid Bright ASMC_LIGHT_FUNCS_DISABLED, 2749e33968bSDavid Bright ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS 2759e33968bSDavid Bright }, 2769e33968bSDavid Bright 277764442e0SGavin Atkinson /* The Mac Mini 3,1 has no SMS */ 278764442e0SGavin Atkinson { 279764442e0SGavin Atkinson "Macmini3,1", "Apple SMC Mac Mini 3,1", 280764442e0SGavin Atkinson NULL, NULL, NULL, 281764442e0SGavin Atkinson ASMC_FAN_FUNCS, 282764442e0SGavin Atkinson NULL, NULL, NULL, 283764442e0SGavin Atkinson ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS 284764442e0SGavin Atkinson }, 285764442e0SGavin Atkinson 2869f0bfc51SDavid Bright /* The Mac Mini 4,1 (Mid-2010) has no SMS */ 2879f0bfc51SDavid Bright { 2889f0bfc51SDavid Bright "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)", 2899f0bfc51SDavid Bright ASMC_SMS_FUNCS_DISABLED, 2909f0bfc51SDavid Bright ASMC_FAN_FUNCS, 2919f0bfc51SDavid Bright ASMC_LIGHT_FUNCS_DISABLED, 2929f0bfc51SDavid Bright ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS 2939f0bfc51SDavid Bright }, 2949f0bfc51SDavid Bright 29571b475e7SDavid Bright /* The Mac Mini 5,2 has no SMS */ 29671b475e7SDavid Bright { 29771b475e7SDavid Bright "Macmini5,2", "Apple SMC Mac Mini 5,2", 29871b475e7SDavid Bright NULL, NULL, NULL, 29971b475e7SDavid Bright ASMC_FAN_FUNCS2, 30071b475e7SDavid Bright NULL, NULL, NULL, 30171b475e7SDavid Bright ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS 30271b475e7SDavid Bright }, 30371b475e7SDavid Bright 30439a8ee13SDavid Bright /* Idem for the Mac Pro "Quad Core" (original) */ 30539a8ee13SDavid Bright { 30639a8ee13SDavid Bright "MacPro1,1", "Apple SMC Mac Pro (Quad Core)", 30739a8ee13SDavid Bright NULL, NULL, NULL, 30839a8ee13SDavid Bright ASMC_FAN_FUNCS, 30939a8ee13SDavid Bright NULL, NULL, NULL, 31039a8ee13SDavid Bright ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS 31139a8ee13SDavid Bright }, 31239a8ee13SDavid Bright 31339a8ee13SDavid Bright /* Idem for the Mac Pro (8-core) */ 314d8246db0SRui Paulo { 315d8246db0SRui Paulo "MacPro2", "Apple SMC Mac Pro (8-core)", 316d8246db0SRui Paulo NULL, NULL, NULL, 317d8246db0SRui Paulo ASMC_FAN_FUNCS, 318be80e49aSRui Paulo NULL, NULL, NULL, 31939a8ee13SDavid Bright ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS 320d8246db0SRui Paulo }, 321941f9f10SRui Paulo 322447666f0SRui Paulo /* Idem for the MacPro 2010*/ 323447666f0SRui Paulo { 324447666f0SRui Paulo "MacPro5,1", "Apple SMC MacPro (2010)", 325447666f0SRui Paulo NULL, NULL, NULL, 326447666f0SRui Paulo ASMC_FAN_FUNCS, 327447666f0SRui Paulo NULL, NULL, NULL, 328447666f0SRui Paulo ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS 329447666f0SRui Paulo }, 330447666f0SRui Paulo 331*7d5fef18SAdam S /* Idem for the MacPro 2013 (cylinder) */ 332*7d5fef18SAdam S { 333*7d5fef18SAdam S "MacPro6,1", "Apple SMC MacPro (2013)", 334*7d5fef18SAdam S ASMC_SMS_FUNCS_DISABLED, 335*7d5fef18SAdam S ASMC_FAN_FUNCS, 336*7d5fef18SAdam S ASMC_LIGHT_FUNCS_DISABLED, 337*7d5fef18SAdam S ASMC_MP6_TEMPS, ASMC_MP6_TEMPNAMES, ASMC_MP6_TEMPDESCS 338*7d5fef18SAdam S }, 339*7d5fef18SAdam S 340941f9f10SRui Paulo { 341941f9f10SRui Paulo "MacBookAir1,1", "Apple SMC MacBook Air", 342be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 343941f9f10SRui Paulo ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS 344941f9f10SRui Paulo }, 345941f9f10SRui Paulo 346447666f0SRui Paulo { 347447666f0SRui Paulo "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", 348447666f0SRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 349447666f0SRui Paulo ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS 350447666f0SRui Paulo }, 351447666f0SRui Paulo 352108e3076SAdrian Chadd { 353308340ccSMark Johnston "MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)", 354308340ccSMark Johnston ASMC_SMS_FUNCS_DISABLED, 355308340ccSMark Johnston ASMC_FAN_FUNCS2, 356308340ccSMark Johnston ASMC_LIGHT_FUNCS, 357308340ccSMark Johnston ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS 358308340ccSMark Johnston }, 359308340ccSMark Johnston 360308340ccSMark Johnston { 361308340ccSMark Johnston "MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)", 362308340ccSMark Johnston ASMC_SMS_FUNCS_DISABLED, 363308340ccSMark Johnston ASMC_FAN_FUNCS2, 364308340ccSMark Johnston ASMC_LIGHT_FUNCS, 365308340ccSMark Johnston ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS 366308340ccSMark Johnston }, 367308340ccSMark Johnston 368308340ccSMark Johnston { 369108e3076SAdrian Chadd "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)", 370108e3076SAdrian Chadd ASMC_SMS_FUNCS_DISABLED, 371108e3076SAdrian Chadd ASMC_FAN_FUNCS2, 372108e3076SAdrian Chadd ASMC_LIGHT_FUNCS, 373108e3076SAdrian Chadd ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 374108e3076SAdrian Chadd }, 375108e3076SAdrian Chadd 376108e3076SAdrian Chadd { 377108e3076SAdrian Chadd "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)", 378108e3076SAdrian Chadd ASMC_SMS_FUNCS_DISABLED, 379108e3076SAdrian Chadd ASMC_FAN_FUNCS2, 380108e3076SAdrian Chadd ASMC_LIGHT_FUNCS, 381108e3076SAdrian Chadd ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS 382108e3076SAdrian Chadd }, 383108e3076SAdrian Chadd 384081954d3SDavid Bright { 385081954d3SDavid Bright "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)", 386081954d3SDavid Bright ASMC_SMS_FUNCS_DISABLED, 387081954d3SDavid Bright ASMC_FAN_FUNCS2, 388081954d3SDavid Bright ASMC_LIGHT_FUNCS, 389081954d3SDavid Bright ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 390081954d3SDavid Bright }, 391081954d3SDavid Bright 392081954d3SDavid Bright { 393081954d3SDavid Bright "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)", 394081954d3SDavid Bright ASMC_SMS_FUNCS_DISABLED, 395081954d3SDavid Bright ASMC_FAN_FUNCS2, 396081954d3SDavid Bright ASMC_LIGHT_FUNCS, 397081954d3SDavid Bright ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS 398081954d3SDavid Bright }, 39932a8088fSRui Paulo { NULL, NULL } 40032a8088fSRui Paulo }; 40132a8088fSRui Paulo 40232a8088fSRui Paulo #undef ASMC_SMS_FUNCS 403108e3076SAdrian Chadd #undef ASMC_SMS_FUNCS_DISABLED 40432a8088fSRui Paulo #undef ASMC_FAN_FUNCS 405108e3076SAdrian Chadd #undef ASMC_FAN_FUNCS2 40632a8088fSRui Paulo #undef ASMC_LIGHT_FUNCS 40732a8088fSRui Paulo 40832a8088fSRui Paulo /* 40932a8088fSRui Paulo * Driver methods. 41032a8088fSRui Paulo */ 41132a8088fSRui Paulo static device_method_t asmc_methods[] = { 41232a8088fSRui Paulo DEVMETHOD(device_probe, asmc_probe), 41332a8088fSRui Paulo DEVMETHOD(device_attach, asmc_attach), 41432a8088fSRui Paulo DEVMETHOD(device_detach, asmc_detach), 415108e3076SAdrian Chadd DEVMETHOD(device_resume, asmc_resume), 41632a8088fSRui Paulo { 0, 0 } 41732a8088fSRui Paulo }; 41832a8088fSRui Paulo 41932a8088fSRui Paulo static driver_t asmc_driver = { 42032a8088fSRui Paulo "asmc", 42132a8088fSRui Paulo asmc_methods, 42232a8088fSRui Paulo sizeof(struct asmc_softc) 42332a8088fSRui Paulo }; 42432a8088fSRui Paulo 4254470f0f3SRui Paulo /* 4264470f0f3SRui Paulo * Debugging 4274470f0f3SRui Paulo */ 4284470f0f3SRui Paulo #define _COMPONENT ACPI_OEM 4294470f0f3SRui Paulo ACPI_MODULE_NAME("ASMC") 4304470f0f3SRui Paulo #ifdef DEBUG 4314470f0f3SRui Paulo #define ASMC_DPRINTF(str) device_printf(dev, str) 4324fb9bf66SRui Paulo #else 4334fb9bf66SRui Paulo #define ASMC_DPRINTF(str) 4344470f0f3SRui Paulo #endif 4354470f0f3SRui Paulo 436be80e49aSRui Paulo /* NB: can't be const */ 4374470f0f3SRui Paulo static char *asmc_ids[] = { "APP0001", NULL }; 4384470f0f3SRui Paulo 43932a8088fSRui Paulo static devclass_t asmc_devclass; 44032a8088fSRui Paulo 441108e3076SAdrian Chadd static unsigned int light_control = 0; 442108e3076SAdrian Chadd 4434470f0f3SRui Paulo DRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 4444470f0f3SRui Paulo MODULE_DEPEND(asmc, acpi, 1, 1, 1); 44532a8088fSRui Paulo 44632a8088fSRui Paulo static struct asmc_model * 44732a8088fSRui Paulo asmc_match(device_t dev) 44832a8088fSRui Paulo { 44932a8088fSRui Paulo int i; 45032a8088fSRui Paulo char *model; 45132a8088fSRui Paulo 4522be111bfSDavide Italiano model = kern_getenv("smbios.system.product"); 45347105877SRui Paulo if (model == NULL) 45447105877SRui Paulo return (NULL); 45547105877SRui Paulo 45632a8088fSRui Paulo for (i = 0; asmc_models[i].smc_model; i++) { 45732a8088fSRui Paulo if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 45832a8088fSRui Paulo freeenv(model); 45932a8088fSRui Paulo return (&asmc_models[i]); 46032a8088fSRui Paulo } 46132a8088fSRui Paulo } 46232a8088fSRui Paulo freeenv(model); 46332a8088fSRui Paulo 46432a8088fSRui Paulo return (NULL); 46532a8088fSRui Paulo } 46632a8088fSRui Paulo 46732a8088fSRui Paulo static int 46832a8088fSRui Paulo asmc_probe(device_t dev) 46932a8088fSRui Paulo { 47032a8088fSRui Paulo struct asmc_model *model; 4715efca36fSTakanori Watanabe int rv; 47232a8088fSRui Paulo 473a8de37b0SEitan Adler if (resource_disabled("asmc", 0)) 474a8de37b0SEitan Adler return (ENXIO); 4755efca36fSTakanori Watanabe rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL); 4765efca36fSTakanori Watanabe if (rv > 0) 4775efca36fSTakanori Watanabe return (rv); 4784470f0f3SRui Paulo 47932a8088fSRui Paulo model = asmc_match(dev); 4804470f0f3SRui Paulo if (!model) { 4814470f0f3SRui Paulo device_printf(dev, "model not recognized\n"); 48232a8088fSRui Paulo return (ENXIO); 4834470f0f3SRui Paulo } 48432a8088fSRui Paulo device_set_desc(dev, model->smc_desc); 48532a8088fSRui Paulo 4865efca36fSTakanori Watanabe return (rv); 48732a8088fSRui Paulo } 48832a8088fSRui Paulo 48932a8088fSRui Paulo static int 49032a8088fSRui Paulo asmc_attach(device_t dev) 49132a8088fSRui Paulo { 49232a8088fSRui Paulo int i, j; 49332a8088fSRui Paulo int ret; 49432a8088fSRui Paulo char name[2]; 49532a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 49632a8088fSRui Paulo struct sysctl_ctx_list *sysctlctx; 49732a8088fSRui Paulo struct sysctl_oid *sysctlnode; 49832a8088fSRui Paulo struct asmc_model *model; 49932a8088fSRui Paulo 5004470f0f3SRui Paulo sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 5014470f0f3SRui Paulo &sc->sc_rid_port, RF_ACTIVE); 5024470f0f3SRui Paulo if (sc->sc_ioport == NULL) { 5034470f0f3SRui Paulo device_printf(dev, "unable to allocate IO port\n"); 5044470f0f3SRui Paulo return (ENOMEM); 5054470f0f3SRui Paulo } 5064470f0f3SRui Paulo 50732a8088fSRui Paulo sysctlctx = device_get_sysctl_ctx(dev); 50832a8088fSRui Paulo sysctlnode = device_get_sysctl_tree(dev); 50932a8088fSRui Paulo 51032a8088fSRui Paulo model = asmc_match(dev); 51132a8088fSRui Paulo 51232a8088fSRui Paulo mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 51332a8088fSRui Paulo 51432a8088fSRui Paulo sc->sc_model = model; 51532a8088fSRui Paulo asmc_init(dev); 51632a8088fSRui Paulo 51732a8088fSRui Paulo /* 51832a8088fSRui Paulo * dev.asmc.n.fan.* tree. 51932a8088fSRui Paulo */ 52032a8088fSRui Paulo sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 52132a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 5227029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree"); 52332a8088fSRui Paulo 52432a8088fSRui Paulo for (i = 1; i <= sc->sc_nfan; i++) { 52532a8088fSRui Paulo j = i - 1; 52632a8088fSRui Paulo name[0] = '0' + j; 52732a8088fSRui Paulo name[1] = 0; 52832a8088fSRui Paulo sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 52932a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 5307029da5cSPawel Biernacki OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 53132a8088fSRui Paulo "Fan Subtree"); 53232a8088fSRui Paulo 53332a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 53432a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 5357029da5cSPawel Biernacki OID_AUTO, "id", 5367029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 537447666f0SRui Paulo dev, j, model->smc_fan_id, "I", 538447666f0SRui Paulo "Fan ID"); 539447666f0SRui Paulo 540447666f0SRui Paulo SYSCTL_ADD_PROC(sysctlctx, 541447666f0SRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 5427029da5cSPawel Biernacki OID_AUTO, "speed", 5437029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 54432a8088fSRui Paulo dev, j, model->smc_fan_speed, "I", 54532a8088fSRui Paulo "Fan speed in RPM"); 54632a8088fSRui Paulo 54732a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 54832a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 54932a8088fSRui Paulo OID_AUTO, "safespeed", 5507029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 55132a8088fSRui Paulo dev, j, model->smc_fan_safespeed, "I", 55232a8088fSRui Paulo "Fan safe speed in RPM"); 55332a8088fSRui Paulo 55432a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 55532a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 55632a8088fSRui Paulo OID_AUTO, "minspeed", 5577029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 55832a8088fSRui Paulo dev, j, model->smc_fan_minspeed, "I", 55932a8088fSRui Paulo "Fan minimum speed in RPM"); 56032a8088fSRui Paulo 56132a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 56232a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 56332a8088fSRui Paulo OID_AUTO, "maxspeed", 5647029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 56532a8088fSRui Paulo dev, j, model->smc_fan_maxspeed, "I", 56632a8088fSRui Paulo "Fan maximum speed in RPM"); 56732a8088fSRui Paulo 56832a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 56932a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 57032a8088fSRui Paulo OID_AUTO, "targetspeed", 5717029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 57232a8088fSRui Paulo dev, j, model->smc_fan_targetspeed, "I", 57332a8088fSRui Paulo "Fan target speed in RPM"); 57432a8088fSRui Paulo } 57532a8088fSRui Paulo 57632a8088fSRui Paulo /* 57732a8088fSRui Paulo * dev.asmc.n.temp tree. 57832a8088fSRui Paulo */ 57932a8088fSRui Paulo sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 58032a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 5817029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors"); 58232a8088fSRui Paulo 58332a8088fSRui Paulo for (i = 0; model->smc_temps[i]; i++) { 58432a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 58532a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_temp_tree), 58632a8088fSRui Paulo OID_AUTO, model->smc_tempnames[i], 5877029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 58832a8088fSRui Paulo dev, i, asmc_temp_sysctl, "I", 58932a8088fSRui Paulo model->smc_tempdescs[i]); 59032a8088fSRui Paulo } 59132a8088fSRui Paulo 592be80e49aSRui Paulo /* 593be80e49aSRui Paulo * dev.asmc.n.light 594be80e49aSRui Paulo */ 595be80e49aSRui Paulo if (model->smc_light_left) { 596be80e49aSRui Paulo sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 597be80e49aSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 5987029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 5997029da5cSPawel Biernacki "Keyboard backlight sensors"); 600be80e49aSRui Paulo 601be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 602be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 6037029da5cSPawel Biernacki OID_AUTO, "left", 6047029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 605be80e49aSRui Paulo dev, 0, model->smc_light_left, "I", 606be80e49aSRui Paulo "Keyboard backlight left sensor"); 607be80e49aSRui Paulo 608be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 609be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 6107029da5cSPawel Biernacki OID_AUTO, "right", 6117029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 612be80e49aSRui Paulo dev, 0, model->smc_light_right, "I", 613be80e49aSRui Paulo "Keyboard backlight right sensor"); 614be80e49aSRui Paulo 615be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 616be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 6173471c35dSRui Paulo OID_AUTO, "control", 6187029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | 6197029da5cSPawel Biernacki CTLFLAG_NEEDGIANT, dev, 0, 6207029da5cSPawel Biernacki model->smc_light_control, "I", 621be80e49aSRui Paulo "Keyboard backlight brightness control"); 622be80e49aSRui Paulo } 623be80e49aSRui Paulo 62432a8088fSRui Paulo if (model->smc_sms_x == NULL) 62532a8088fSRui Paulo goto nosms; 62632a8088fSRui Paulo 62732a8088fSRui Paulo /* 62832a8088fSRui Paulo * dev.asmc.n.sms tree. 62932a8088fSRui Paulo */ 63032a8088fSRui Paulo sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 63132a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 6327029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor"); 63332a8088fSRui Paulo 63432a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 63532a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 6367029da5cSPawel Biernacki OID_AUTO, "x", 6377029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 63832a8088fSRui Paulo dev, 0, model->smc_sms_x, "I", 63932a8088fSRui Paulo "Sudden Motion Sensor X value"); 64032a8088fSRui Paulo 64132a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 64232a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 6437029da5cSPawel Biernacki OID_AUTO, "y", 6447029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 64532a8088fSRui Paulo dev, 0, model->smc_sms_y, "I", 64632a8088fSRui Paulo "Sudden Motion Sensor Y value"); 64732a8088fSRui Paulo 64832a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 64932a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 6507029da5cSPawel Biernacki OID_AUTO, "z", 6517029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 65232a8088fSRui Paulo dev, 0, model->smc_sms_z, "I", 65332a8088fSRui Paulo "Sudden Motion Sensor Z value"); 65432a8088fSRui Paulo 65532a8088fSRui Paulo /* 65632a8088fSRui Paulo * Need a taskqueue to send devctl_notify() events 65732a8088fSRui Paulo * when the SMS interrupt us. 65832a8088fSRui Paulo * 65932a8088fSRui Paulo * PI_REALTIME is used due to the sensitivity of the 66032a8088fSRui Paulo * interrupt. An interrupt from the SMS means that the 66132a8088fSRui Paulo * disk heads should be turned off as quickly as possible. 66232a8088fSRui Paulo * 66332a8088fSRui Paulo * We only need to do this for the non INTR_FILTER case. 66432a8088fSRui Paulo */ 66532a8088fSRui Paulo sc->sc_sms_tq = NULL; 66632a8088fSRui Paulo TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 66732a8088fSRui Paulo sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 66832a8088fSRui Paulo taskqueue_thread_enqueue, &sc->sc_sms_tq); 66932a8088fSRui Paulo taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 67032a8088fSRui Paulo device_get_nameunit(dev)); 67132a8088fSRui Paulo /* 67232a8088fSRui Paulo * Allocate an IRQ for the SMS. 67332a8088fSRui Paulo */ 6744470f0f3SRui Paulo sc->sc_rid_irq = 0; 6754470f0f3SRui Paulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 6764470f0f3SRui Paulo &sc->sc_rid_irq, RF_ACTIVE); 6774470f0f3SRui Paulo if (sc->sc_irq == NULL) { 67832a8088fSRui Paulo device_printf(dev, "unable to allocate IRQ resource\n"); 67932a8088fSRui Paulo ret = ENXIO; 68032a8088fSRui Paulo goto err2; 68132a8088fSRui Paulo } 68232a8088fSRui Paulo 6834470f0f3SRui Paulo ret = bus_setup_intr(dev, sc->sc_irq, 68432a8088fSRui Paulo INTR_TYPE_MISC | INTR_MPSAFE, 68532a8088fSRui Paulo asmc_sms_intrfast, NULL, 68632a8088fSRui Paulo dev, &sc->sc_cookie); 68732a8088fSRui Paulo 68832a8088fSRui Paulo if (ret) { 68932a8088fSRui Paulo device_printf(dev, "unable to setup SMS IRQ\n"); 69032a8088fSRui Paulo goto err1; 69132a8088fSRui Paulo } 69232a8088fSRui Paulo nosms: 69332a8088fSRui Paulo return (0); 69432a8088fSRui Paulo err1: 6954470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 69632a8088fSRui Paulo err2: 6974470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 6984470f0f3SRui Paulo sc->sc_ioport); 69932a8088fSRui Paulo mtx_destroy(&sc->sc_mtx); 70032a8088fSRui Paulo if (sc->sc_sms_tq) 70132a8088fSRui Paulo taskqueue_free(sc->sc_sms_tq); 70232a8088fSRui Paulo 70332a8088fSRui Paulo return (ret); 70432a8088fSRui Paulo } 70532a8088fSRui Paulo 70632a8088fSRui Paulo static int 70732a8088fSRui Paulo asmc_detach(device_t dev) 70832a8088fSRui Paulo { 70932a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 71032a8088fSRui Paulo 71132a8088fSRui Paulo if (sc->sc_sms_tq) { 71232a8088fSRui Paulo taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 71332a8088fSRui Paulo taskqueue_free(sc->sc_sms_tq); 71432a8088fSRui Paulo } 71532a8088fSRui Paulo if (sc->sc_cookie) 7164470f0f3SRui Paulo bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 7174470f0f3SRui Paulo if (sc->sc_irq) 7184470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 7194470f0f3SRui Paulo sc->sc_irq); 7204470f0f3SRui Paulo if (sc->sc_ioport) 7214470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 7224470f0f3SRui Paulo sc->sc_ioport); 72332a8088fSRui Paulo mtx_destroy(&sc->sc_mtx); 72432a8088fSRui Paulo 72532a8088fSRui Paulo return (0); 72632a8088fSRui Paulo } 72732a8088fSRui Paulo 728108e3076SAdrian Chadd static int 729108e3076SAdrian Chadd asmc_resume(device_t dev) 730108e3076SAdrian Chadd { 731108e3076SAdrian Chadd uint8_t buf[2]; 732108e3076SAdrian Chadd buf[0] = light_control; 733108e3076SAdrian Chadd buf[1] = 0x00; 734108e3076SAdrian Chadd asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 735108e3076SAdrian Chadd return (0); 736108e3076SAdrian Chadd } 737108e3076SAdrian Chadd 7381269f4d4SRui Paulo #ifdef DEBUG 7391269f4d4SRui Paulo void asmc_dumpall(device_t dev) 7401269f4d4SRui Paulo { 7411269f4d4SRui Paulo int i; 7421269f4d4SRui Paulo 7431269f4d4SRui Paulo /* XXX magic number */ 7441269f4d4SRui Paulo for (i=0; i < 0x100; i++) 7451269f4d4SRui Paulo asmc_key_dump(dev, i); 7461269f4d4SRui Paulo } 7471269f4d4SRui Paulo #endif 7481269f4d4SRui Paulo 74932a8088fSRui Paulo static int 75032a8088fSRui Paulo asmc_init(device_t dev) 75132a8088fSRui Paulo { 75232a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 75332a8088fSRui Paulo int i, error = 1; 75432a8088fSRui Paulo uint8_t buf[4]; 75532a8088fSRui Paulo 75632a8088fSRui Paulo if (sc->sc_model->smc_sms_x == NULL) 75732a8088fSRui Paulo goto nosms; 75832a8088fSRui Paulo 75932a8088fSRui Paulo /* 760453130d9SPedro F. Giffuni * We are ready to receive interrupts from the SMS. 76132a8088fSRui Paulo */ 76232a8088fSRui Paulo buf[0] = 0x01; 7634470f0f3SRui Paulo ASMC_DPRINTF(("intok key\n")); 76432a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 76532a8088fSRui Paulo DELAY(50); 76632a8088fSRui Paulo 76732a8088fSRui Paulo /* 76832a8088fSRui Paulo * Initiate the polling intervals. 76932a8088fSRui Paulo */ 77032a8088fSRui Paulo buf[0] = 20; /* msecs */ 7714470f0f3SRui Paulo ASMC_DPRINTF(("low int key\n")); 77232a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 77332a8088fSRui Paulo DELAY(200); 77432a8088fSRui Paulo 77532a8088fSRui Paulo buf[0] = 20; /* msecs */ 7764470f0f3SRui Paulo ASMC_DPRINTF(("high int key\n")); 77732a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 77832a8088fSRui Paulo DELAY(200); 77932a8088fSRui Paulo 78032a8088fSRui Paulo buf[0] = 0x00; 78132a8088fSRui Paulo buf[1] = 0x60; 7824470f0f3SRui Paulo ASMC_DPRINTF(("sms low key\n")); 78332a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 78432a8088fSRui Paulo DELAY(200); 78532a8088fSRui Paulo 78632a8088fSRui Paulo buf[0] = 0x01; 78732a8088fSRui Paulo buf[1] = 0xc0; 7884470f0f3SRui Paulo ASMC_DPRINTF(("sms high key\n")); 78932a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 79032a8088fSRui Paulo DELAY(200); 79132a8088fSRui Paulo 79232a8088fSRui Paulo /* 79332a8088fSRui Paulo * I'm not sure what this key does, but it seems to be 79432a8088fSRui Paulo * required. 79532a8088fSRui Paulo */ 79632a8088fSRui Paulo buf[0] = 0x01; 7974470f0f3SRui Paulo ASMC_DPRINTF(("sms flag key\n")); 79832a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 799b75dfbe8SRui Paulo DELAY(100); 80032a8088fSRui Paulo 8011269f4d4SRui Paulo sc->sc_sms_intr_works = 0; 8021269f4d4SRui Paulo 80332a8088fSRui Paulo /* 8041269f4d4SRui Paulo * Retry SMS initialization 1000 times 8051269f4d4SRui Paulo * (takes approx. 2 seconds in worst case) 80632a8088fSRui Paulo */ 8071269f4d4SRui Paulo for (i = 0; i < 1000; i++) { 80832a8088fSRui Paulo if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 8091269f4d4SRui Paulo (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 81032a8088fSRui Paulo error = 0; 8111269f4d4SRui Paulo sc->sc_sms_intr_works = 1; 8124fb9bf66SRui Paulo goto out; 81332a8088fSRui Paulo } 81432a8088fSRui Paulo buf[0] = ASMC_SMS_INIT1; 81532a8088fSRui Paulo buf[1] = ASMC_SMS_INIT2; 8164470f0f3SRui Paulo ASMC_DPRINTF(("sms key\n")); 81732a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 81832a8088fSRui Paulo DELAY(50); 81932a8088fSRui Paulo } 8204fb9bf66SRui Paulo device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 82132a8088fSRui Paulo 8224fb9bf66SRui Paulo out: 82332a8088fSRui Paulo asmc_sms_calibrate(dev); 82432a8088fSRui Paulo nosms: 82532a8088fSRui Paulo sc->sc_nfan = asmc_fan_count(dev); 82632a8088fSRui Paulo if (sc->sc_nfan > ASMC_MAXFANS) { 82732a8088fSRui Paulo device_printf(dev, "more than %d fans were detected. Please " 82832a8088fSRui Paulo "report this.\n", ASMC_MAXFANS); 82932a8088fSRui Paulo sc->sc_nfan = ASMC_MAXFANS; 83032a8088fSRui Paulo } 83132a8088fSRui Paulo 83232a8088fSRui Paulo if (bootverbose) { 83332a8088fSRui Paulo /* 834447666f0SRui Paulo * The number of keys is a 32 bit buffer 83532a8088fSRui Paulo */ 83632a8088fSRui Paulo asmc_key_read(dev, ASMC_NKEYS, buf, 4); 837447666f0SRui Paulo device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf)); 83832a8088fSRui Paulo } 83932a8088fSRui Paulo 8401269f4d4SRui Paulo #ifdef DEBUG 8411269f4d4SRui Paulo asmc_dumpall(dev); 8421269f4d4SRui Paulo #endif 8431269f4d4SRui Paulo 84432a8088fSRui Paulo return (error); 84532a8088fSRui Paulo } 84632a8088fSRui Paulo 84732a8088fSRui Paulo /* 84832a8088fSRui Paulo * We need to make sure that the SMC acks the byte sent. 849be80e49aSRui Paulo * Just wait up to (amount * 10) ms. 85032a8088fSRui Paulo */ 85132a8088fSRui Paulo static int 852be80e49aSRui Paulo asmc_wait_ack(device_t dev, uint8_t val, int amount) 85332a8088fSRui Paulo { 8544470f0f3SRui Paulo struct asmc_softc *sc = device_get_softc(dev); 85532a8088fSRui Paulo u_int i; 85632a8088fSRui Paulo 85732a8088fSRui Paulo val = val & ASMC_STATUS_MASK; 85832a8088fSRui Paulo 859be80e49aSRui Paulo for (i = 0; i < amount; i++) { 8604470f0f3SRui Paulo if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 86132a8088fSRui Paulo return (0); 86232a8088fSRui Paulo DELAY(10); 86332a8088fSRui Paulo } 86432a8088fSRui Paulo 865be80e49aSRui Paulo return (1); 866be80e49aSRui Paulo } 867be80e49aSRui Paulo 868be80e49aSRui Paulo /* 869be80e49aSRui Paulo * We need to make sure that the SMC acks the byte sent. 870be80e49aSRui Paulo * Just wait up to 100 ms. 871be80e49aSRui Paulo */ 872be80e49aSRui Paulo static int 873be80e49aSRui Paulo asmc_wait(device_t dev, uint8_t val) 874be80e49aSRui Paulo { 875e02d0cabSMateusz Guzik #ifdef DEBUG 876be80e49aSRui Paulo struct asmc_softc *sc; 877e02d0cabSMateusz Guzik #endif 878be80e49aSRui Paulo 879be80e49aSRui Paulo if (asmc_wait_ack(dev, val, 1000) == 0) 880be80e49aSRui Paulo return (0); 881be80e49aSRui Paulo 882e02d0cabSMateusz Guzik #ifdef DEBUG 883be80e49aSRui Paulo sc = device_get_softc(dev); 884e02d0cabSMateusz Guzik #endif 885be80e49aSRui Paulo val = val & ASMC_STATUS_MASK; 886be80e49aSRui Paulo 887be80e49aSRui Paulo #ifdef DEBUG 88832a8088fSRui Paulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 8894470f0f3SRui Paulo ASMC_CMDPORT_READ(sc)); 890be80e49aSRui Paulo #endif 891be80e49aSRui Paulo return (1); 892be80e49aSRui Paulo } 89332a8088fSRui Paulo 894be80e49aSRui Paulo /* 895be80e49aSRui Paulo * Send the given command, retrying up to 10 times if 896be80e49aSRui Paulo * the acknowledgement fails. 897be80e49aSRui Paulo */ 898be80e49aSRui Paulo static int 899be80e49aSRui Paulo asmc_command(device_t dev, uint8_t command) { 900be80e49aSRui Paulo int i; 901be80e49aSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 902be80e49aSRui Paulo 903be80e49aSRui Paulo for (i=0; i < 10; i++) { 904be80e49aSRui Paulo ASMC_CMDPORT_WRITE(sc, command); 905be80e49aSRui Paulo if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 906be80e49aSRui Paulo return (0); 907be80e49aSRui Paulo } 908be80e49aSRui Paulo } 909be80e49aSRui Paulo 910be80e49aSRui Paulo #ifdef DEBUG 911be80e49aSRui Paulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 912be80e49aSRui Paulo ASMC_CMDPORT_READ(sc)); 913be80e49aSRui Paulo #endif 91432a8088fSRui Paulo return (1); 91532a8088fSRui Paulo } 91632a8088fSRui Paulo 91732a8088fSRui Paulo static int 91832a8088fSRui Paulo asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 91932a8088fSRui Paulo { 920be80e49aSRui Paulo int i, error = 1, try = 0; 92132a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 92232a8088fSRui Paulo 92332a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 92432a8088fSRui Paulo 925be80e49aSRui Paulo begin: 926be80e49aSRui Paulo if (asmc_command(dev, ASMC_CMDREAD)) 92732a8088fSRui Paulo goto out; 92832a8088fSRui Paulo 92932a8088fSRui Paulo for (i = 0; i < 4; i++) { 9304470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 93132a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 93232a8088fSRui Paulo goto out; 93332a8088fSRui Paulo } 93432a8088fSRui Paulo 9354470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, len); 93632a8088fSRui Paulo 93732a8088fSRui Paulo for (i = 0; i < len; i++) { 93832a8088fSRui Paulo if (asmc_wait(dev, 0x05)) 93932a8088fSRui Paulo goto out; 9404470f0f3SRui Paulo buf[i] = ASMC_DATAPORT_READ(sc); 94132a8088fSRui Paulo } 94232a8088fSRui Paulo 94332a8088fSRui Paulo error = 0; 94432a8088fSRui Paulo out: 945be80e49aSRui Paulo if (error) { 946be80e49aSRui Paulo if (++try < 10) goto begin; 947be80e49aSRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 948be80e49aSRui Paulo __func__, key, try); 949be80e49aSRui Paulo } 950be80e49aSRui Paulo 95132a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 95232a8088fSRui Paulo 95332a8088fSRui Paulo return (error); 95432a8088fSRui Paulo } 95532a8088fSRui Paulo 9561269f4d4SRui Paulo #ifdef DEBUG 9571269f4d4SRui Paulo static int 9581269f4d4SRui Paulo asmc_key_dump(device_t dev, int number) 9591269f4d4SRui Paulo { 9601269f4d4SRui Paulo struct asmc_softc *sc = device_get_softc(dev); 9611269f4d4SRui Paulo char key[5] = { 0 }; 9621269f4d4SRui Paulo char type[7] = { 0 }; 9631269f4d4SRui Paulo uint8_t index[4]; 9641269f4d4SRui Paulo uint8_t v[32]; 9651269f4d4SRui Paulo uint8_t maxlen; 9661269f4d4SRui Paulo int i, error = 1, try = 0; 9671269f4d4SRui Paulo 9681269f4d4SRui Paulo mtx_lock_spin(&sc->sc_mtx); 9691269f4d4SRui Paulo 9701269f4d4SRui Paulo index[0] = (number >> 24) & 0xff; 9711269f4d4SRui Paulo index[1] = (number >> 16) & 0xff; 9721269f4d4SRui Paulo index[2] = (number >> 8) & 0xff; 9731269f4d4SRui Paulo index[3] = (number) & 0xff; 9741269f4d4SRui Paulo 9751269f4d4SRui Paulo begin: 9761269f4d4SRui Paulo if (asmc_command(dev, 0x12)) 9771269f4d4SRui Paulo goto out; 9781269f4d4SRui Paulo 9791269f4d4SRui Paulo for (i = 0; i < 4; i++) { 9801269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, index[i]); 9811269f4d4SRui Paulo if (asmc_wait(dev, 0x04)) 9821269f4d4SRui Paulo goto out; 9831269f4d4SRui Paulo } 9841269f4d4SRui Paulo 9851269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, 4); 9861269f4d4SRui Paulo 9871269f4d4SRui Paulo for (i = 0; i < 4; i++) { 9881269f4d4SRui Paulo if (asmc_wait(dev, 0x05)) 9891269f4d4SRui Paulo goto out; 9901269f4d4SRui Paulo key[i] = ASMC_DATAPORT_READ(sc); 9911269f4d4SRui Paulo } 9921269f4d4SRui Paulo 9931269f4d4SRui Paulo /* get type */ 9941269f4d4SRui Paulo if (asmc_command(dev, 0x13)) 9951269f4d4SRui Paulo goto out; 9961269f4d4SRui Paulo 9971269f4d4SRui Paulo for (i = 0; i < 4; i++) { 9981269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 9991269f4d4SRui Paulo if (asmc_wait(dev, 0x04)) 10001269f4d4SRui Paulo goto out; 10011269f4d4SRui Paulo } 10021269f4d4SRui Paulo 10031269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, 6); 10041269f4d4SRui Paulo 10051269f4d4SRui Paulo for (i = 0; i < 6; i++) { 10061269f4d4SRui Paulo if (asmc_wait(dev, 0x05)) 10071269f4d4SRui Paulo goto out; 10081269f4d4SRui Paulo type[i] = ASMC_DATAPORT_READ(sc); 10091269f4d4SRui Paulo } 10101269f4d4SRui Paulo 10111269f4d4SRui Paulo error = 0; 10121269f4d4SRui Paulo out: 10131269f4d4SRui Paulo if (error) { 10141269f4d4SRui Paulo if (++try < 10) goto begin; 10151269f4d4SRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 10161269f4d4SRui Paulo __func__, key, try); 10171269f4d4SRui Paulo mtx_unlock_spin(&sc->sc_mtx); 10181269f4d4SRui Paulo } 10191269f4d4SRui Paulo else { 10201269f4d4SRui Paulo char buf[1024]; 10211269f4d4SRui Paulo char buf2[8]; 10221269f4d4SRui Paulo mtx_unlock_spin(&sc->sc_mtx); 10231269f4d4SRui Paulo maxlen = type[0]; 10241269f4d4SRui Paulo type[0] = ' '; 10251269f4d4SRui Paulo type[5] = 0; 10261269f4d4SRui Paulo if (maxlen > sizeof(v)) { 1027f17bca82SRui Paulo device_printf(dev, 1028f17bca82SRui Paulo "WARNING: cropping maxlen from %d to %zu\n", 1029f17bca82SRui Paulo maxlen, sizeof(v)); 10301269f4d4SRui Paulo maxlen = sizeof(v); 10311269f4d4SRui Paulo } 10321269f4d4SRui Paulo for (i = 0; i < sizeof(v); i++) { 10331269f4d4SRui Paulo v[i] = 0; 10341269f4d4SRui Paulo } 10351269f4d4SRui Paulo asmc_key_read(dev, key, v, maxlen); 10361269f4d4SRui Paulo snprintf(buf, sizeof(buf), "key %d is: %s, type %s " 10371269f4d4SRui Paulo "(len %d), data", number, key, type, maxlen); 10381269f4d4SRui Paulo for (i = 0; i < maxlen; i++) { 1039108e3076SAdrian Chadd snprintf(buf2, sizeof(buf2), " %02x", v[i]); 10401269f4d4SRui Paulo strlcat(buf, buf2, sizeof(buf)); 10411269f4d4SRui Paulo } 10421269f4d4SRui Paulo strlcat(buf, " \n", sizeof(buf)); 104346c76550SRoman Divacky device_printf(dev, "%s", buf); 10441269f4d4SRui Paulo } 10451269f4d4SRui Paulo 10461269f4d4SRui Paulo return (error); 10471269f4d4SRui Paulo } 10481269f4d4SRui Paulo #endif 10491269f4d4SRui Paulo 105032a8088fSRui Paulo static int 105132a8088fSRui Paulo asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 105232a8088fSRui Paulo { 1053be80e49aSRui Paulo int i, error = -1, try = 0; 105432a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 105532a8088fSRui Paulo 105632a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 105732a8088fSRui Paulo 1058be80e49aSRui Paulo begin: 10594470f0f3SRui Paulo ASMC_DPRINTF(("cmd port: cmd write\n")); 1060be80e49aSRui Paulo if (asmc_command(dev, ASMC_CMDWRITE)) 106132a8088fSRui Paulo goto out; 106232a8088fSRui Paulo 10634470f0f3SRui Paulo ASMC_DPRINTF(("data port: key\n")); 106432a8088fSRui Paulo for (i = 0; i < 4; i++) { 10654470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 106632a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 106732a8088fSRui Paulo goto out; 106832a8088fSRui Paulo } 10694470f0f3SRui Paulo ASMC_DPRINTF(("data port: length\n")); 10704470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, len); 107132a8088fSRui Paulo 10724470f0f3SRui Paulo ASMC_DPRINTF(("data port: buffer\n")); 107332a8088fSRui Paulo for (i = 0; i < len; i++) { 107432a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 107532a8088fSRui Paulo goto out; 10764470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, buf[i]); 107732a8088fSRui Paulo } 107832a8088fSRui Paulo 107932a8088fSRui Paulo error = 0; 108032a8088fSRui Paulo out: 1081be80e49aSRui Paulo if (error) { 1082be80e49aSRui Paulo if (++try < 10) goto begin; 1083be80e49aSRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 1084be80e49aSRui Paulo __func__, key, try); 1085be80e49aSRui Paulo } 1086be80e49aSRui Paulo 108732a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 108832a8088fSRui Paulo 108932a8088fSRui Paulo return (error); 109032a8088fSRui Paulo 109132a8088fSRui Paulo } 109232a8088fSRui Paulo 109332a8088fSRui Paulo /* 109432a8088fSRui Paulo * Fan control functions. 109532a8088fSRui Paulo */ 109632a8088fSRui Paulo static int 109732a8088fSRui Paulo asmc_fan_count(device_t dev) 109832a8088fSRui Paulo { 109932a8088fSRui Paulo uint8_t buf[1]; 110032a8088fSRui Paulo 11019c325393SMark Johnston if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) != 0) 110232a8088fSRui Paulo return (-1); 110332a8088fSRui Paulo 110432a8088fSRui Paulo return (buf[0]); 110532a8088fSRui Paulo } 110632a8088fSRui Paulo 110732a8088fSRui Paulo static int 110832a8088fSRui Paulo asmc_fan_getvalue(device_t dev, const char *key, int fan) 110932a8088fSRui Paulo { 111032a8088fSRui Paulo int speed; 111132a8088fSRui Paulo uint8_t buf[2]; 111232a8088fSRui Paulo char fankey[5]; 111332a8088fSRui Paulo 111432a8088fSRui Paulo snprintf(fankey, sizeof(fankey), key, fan); 11159c325393SMark Johnston if (asmc_key_read(dev, fankey, buf, sizeof buf) != 0) 111632a8088fSRui Paulo return (-1); 111732a8088fSRui Paulo speed = (buf[0] << 6) | (buf[1] >> 2); 111832a8088fSRui Paulo 111932a8088fSRui Paulo return (speed); 112032a8088fSRui Paulo } 112132a8088fSRui Paulo 1122447666f0SRui Paulo static char* 1123623534d6SUlrich Spörlein asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen) 1124447666f0SRui Paulo { 1125447666f0SRui Paulo char fankey[5]; 1126447666f0SRui Paulo char* desc; 1127447666f0SRui Paulo 1128447666f0SRui Paulo snprintf(fankey, sizeof(fankey), key, fan); 11299c325393SMark Johnston if (asmc_key_read(dev, fankey, buf, buflen) != 0) 1130447666f0SRui Paulo return (NULL); 1131447666f0SRui Paulo desc = buf+4; 1132447666f0SRui Paulo 1133447666f0SRui Paulo return (desc); 1134447666f0SRui Paulo } 1135447666f0SRui Paulo 1136447666f0SRui Paulo static int 1137447666f0SRui Paulo asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) 1138447666f0SRui Paulo { 1139447666f0SRui Paulo uint8_t buf[2]; 1140447666f0SRui Paulo char fankey[5]; 1141447666f0SRui Paulo 1142447666f0SRui Paulo speed *= 4; 1143447666f0SRui Paulo 1144447666f0SRui Paulo buf[0] = speed>>8; 1145447666f0SRui Paulo buf[1] = speed; 1146447666f0SRui Paulo 1147447666f0SRui Paulo snprintf(fankey, sizeof(fankey), key, fan); 1148447666f0SRui Paulo if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0) 1149447666f0SRui Paulo return (-1); 1150447666f0SRui Paulo 1151447666f0SRui Paulo return (0); 1152447666f0SRui Paulo } 1153447666f0SRui Paulo 115432a8088fSRui Paulo static int 115532a8088fSRui Paulo asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 115632a8088fSRui Paulo { 115732a8088fSRui Paulo device_t dev = (device_t) arg1; 115832a8088fSRui Paulo int fan = arg2; 115932a8088fSRui Paulo int error; 116032a8088fSRui Paulo int32_t v; 116132a8088fSRui Paulo 116232a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 116332a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 116432a8088fSRui Paulo 116532a8088fSRui Paulo return (error); 116632a8088fSRui Paulo } 116732a8088fSRui Paulo 116832a8088fSRui Paulo static int 1169447666f0SRui Paulo asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) 1170447666f0SRui Paulo { 1171623534d6SUlrich Spörlein uint8_t buf[16]; 1172447666f0SRui Paulo device_t dev = (device_t) arg1; 1173447666f0SRui Paulo int fan = arg2; 1174447666f0SRui Paulo int error = true; 1175447666f0SRui Paulo char* desc; 1176447666f0SRui Paulo 1177623534d6SUlrich Spörlein desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); 1178447666f0SRui Paulo 1179447666f0SRui Paulo if (desc != NULL) 1180447666f0SRui Paulo error = sysctl_handle_string(oidp, desc, 0, req); 1181447666f0SRui Paulo 1182447666f0SRui Paulo return (error); 1183447666f0SRui Paulo } 1184447666f0SRui Paulo 1185447666f0SRui Paulo static int 118632a8088fSRui Paulo asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 118732a8088fSRui Paulo { 118832a8088fSRui Paulo device_t dev = (device_t) arg1; 118932a8088fSRui Paulo int fan = arg2; 119032a8088fSRui Paulo int error; 119132a8088fSRui Paulo int32_t v; 119232a8088fSRui Paulo 119332a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 119432a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 119532a8088fSRui Paulo 119632a8088fSRui Paulo return (error); 119732a8088fSRui Paulo } 119832a8088fSRui Paulo 119932a8088fSRui Paulo static int 120032a8088fSRui Paulo asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 120132a8088fSRui Paulo { 120232a8088fSRui Paulo device_t dev = (device_t) arg1; 120332a8088fSRui Paulo int fan = arg2; 120432a8088fSRui Paulo int error; 120532a8088fSRui Paulo int32_t v; 120632a8088fSRui Paulo 120732a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 120832a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 120932a8088fSRui Paulo 1210447666f0SRui Paulo if (error == 0 && req->newptr != NULL) { 12110e1152fcSHans Petter Selasky unsigned int newspeed = v; 1212447666f0SRui Paulo asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed); 1213447666f0SRui Paulo } 1214447666f0SRui Paulo 121532a8088fSRui Paulo return (error); 121632a8088fSRui Paulo } 121732a8088fSRui Paulo 121832a8088fSRui Paulo static int 121932a8088fSRui Paulo asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 122032a8088fSRui Paulo { 122132a8088fSRui Paulo device_t dev = (device_t) arg1; 122232a8088fSRui Paulo int fan = arg2; 122332a8088fSRui Paulo int error; 122432a8088fSRui Paulo int32_t v; 122532a8088fSRui Paulo 122632a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 122732a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 122832a8088fSRui Paulo 1229447666f0SRui Paulo if (error == 0 && req->newptr != NULL) { 12300e1152fcSHans Petter Selasky unsigned int newspeed = v; 1231447666f0SRui Paulo asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed); 1232447666f0SRui Paulo } 1233447666f0SRui Paulo 123432a8088fSRui Paulo return (error); 123532a8088fSRui Paulo } 123632a8088fSRui Paulo 123732a8088fSRui Paulo static int 123832a8088fSRui Paulo asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 123932a8088fSRui Paulo { 124032a8088fSRui Paulo device_t dev = (device_t) arg1; 124132a8088fSRui Paulo int fan = arg2; 124232a8088fSRui Paulo int error; 124332a8088fSRui Paulo int32_t v; 124432a8088fSRui Paulo 124532a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 124632a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 124732a8088fSRui Paulo 1248447666f0SRui Paulo if (error == 0 && req->newptr != NULL) { 12490e1152fcSHans Petter Selasky unsigned int newspeed = v; 1250447666f0SRui Paulo asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed); 1251447666f0SRui Paulo } 1252447666f0SRui Paulo 125332a8088fSRui Paulo return (error); 125432a8088fSRui Paulo } 125532a8088fSRui Paulo 125632a8088fSRui Paulo /* 125732a8088fSRui Paulo * Temperature functions. 125832a8088fSRui Paulo */ 125932a8088fSRui Paulo static int 126032a8088fSRui Paulo asmc_temp_getvalue(device_t dev, const char *key) 126132a8088fSRui Paulo { 126232a8088fSRui Paulo uint8_t buf[2]; 126332a8088fSRui Paulo 126432a8088fSRui Paulo /* 126532a8088fSRui Paulo * Check for invalid temperatures. 126632a8088fSRui Paulo */ 12679c325393SMark Johnston if (asmc_key_read(dev, key, buf, sizeof buf) != 0) 126832a8088fSRui Paulo return (-1); 126932a8088fSRui Paulo 127032a8088fSRui Paulo return (buf[0]); 127132a8088fSRui Paulo } 127232a8088fSRui Paulo 127332a8088fSRui Paulo static int 127432a8088fSRui Paulo asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 127532a8088fSRui Paulo { 127632a8088fSRui Paulo device_t dev = (device_t) arg1; 127732a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 127832a8088fSRui Paulo int error, val; 127932a8088fSRui Paulo 128032a8088fSRui Paulo val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 128132a8088fSRui Paulo error = sysctl_handle_int(oidp, &val, 0, req); 128232a8088fSRui Paulo 128332a8088fSRui Paulo return (error); 128432a8088fSRui Paulo } 128532a8088fSRui Paulo 128632a8088fSRui Paulo /* 128732a8088fSRui Paulo * Sudden Motion Sensor functions. 128832a8088fSRui Paulo */ 128932a8088fSRui Paulo static int 129032a8088fSRui Paulo asmc_sms_read(device_t dev, const char *key, int16_t *val) 129132a8088fSRui Paulo { 129232a8088fSRui Paulo uint8_t buf[2]; 129332a8088fSRui Paulo int error; 129432a8088fSRui Paulo 129532a8088fSRui Paulo /* no need to do locking here as asmc_key_read() already does it */ 129632a8088fSRui Paulo switch (key[3]) { 129732a8088fSRui Paulo case 'X': 129832a8088fSRui Paulo case 'Y': 129932a8088fSRui Paulo case 'Z': 1300447666f0SRui Paulo error = asmc_key_read(dev, key, buf, sizeof buf); 130132a8088fSRui Paulo break; 130232a8088fSRui Paulo default: 130332a8088fSRui Paulo device_printf(dev, "%s called with invalid argument %s\n", 130432a8088fSRui Paulo __func__, key); 130532a8088fSRui Paulo error = 1; 130632a8088fSRui Paulo goto out; 130732a8088fSRui Paulo } 130832a8088fSRui Paulo *val = ((int16_t)buf[0] << 8) | buf[1]; 130932a8088fSRui Paulo out: 131032a8088fSRui Paulo return (error); 131132a8088fSRui Paulo } 131232a8088fSRui Paulo 131332a8088fSRui Paulo static void 131432a8088fSRui Paulo asmc_sms_calibrate(device_t dev) 131532a8088fSRui Paulo { 131632a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 131732a8088fSRui Paulo 131832a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 131932a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 132032a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 132132a8088fSRui Paulo } 132232a8088fSRui Paulo 132332a8088fSRui Paulo static int 132432a8088fSRui Paulo asmc_sms_intrfast(void *arg) 132532a8088fSRui Paulo { 132632a8088fSRui Paulo uint8_t type; 132732a8088fSRui Paulo device_t dev = (device_t) arg; 132832a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 13291269f4d4SRui Paulo if (!sc->sc_sms_intr_works) 13301269f4d4SRui Paulo return (FILTER_HANDLED); 133132a8088fSRui Paulo 133232a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 13334470f0f3SRui Paulo type = ASMC_INTPORT_READ(sc); 133432a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 133532a8088fSRui Paulo 133632a8088fSRui Paulo sc->sc_sms_intrtype = type; 133732a8088fSRui Paulo asmc_sms_printintr(dev, type); 133832a8088fSRui Paulo 133932a8088fSRui Paulo taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 134032a8088fSRui Paulo return (FILTER_HANDLED); 134132a8088fSRui Paulo } 134232a8088fSRui Paulo 134332a8088fSRui Paulo static void 134432a8088fSRui Paulo asmc_sms_printintr(device_t dev, uint8_t type) 134532a8088fSRui Paulo { 134632a8088fSRui Paulo 134732a8088fSRui Paulo switch (type) { 134832a8088fSRui Paulo case ASMC_SMS_INTFF: 134932a8088fSRui Paulo device_printf(dev, "WARNING: possible free fall!\n"); 135032a8088fSRui Paulo break; 135132a8088fSRui Paulo case ASMC_SMS_INTHA: 135232a8088fSRui Paulo device_printf(dev, "WARNING: high acceleration detected!\n"); 135332a8088fSRui Paulo break; 135432a8088fSRui Paulo case ASMC_SMS_INTSH: 135532a8088fSRui Paulo device_printf(dev, "WARNING: possible shock!\n"); 135632a8088fSRui Paulo break; 135732a8088fSRui Paulo default: 135832a8088fSRui Paulo device_printf(dev, "%s unknown interrupt\n", __func__); 135932a8088fSRui Paulo } 136032a8088fSRui Paulo } 136132a8088fSRui Paulo 136232a8088fSRui Paulo static void 136332a8088fSRui Paulo asmc_sms_task(void *arg, int pending) 136432a8088fSRui Paulo { 136532a8088fSRui Paulo struct asmc_softc *sc = (struct asmc_softc *)arg; 136632a8088fSRui Paulo char notify[16]; 136732a8088fSRui Paulo int type; 136832a8088fSRui Paulo 136932a8088fSRui Paulo switch (sc->sc_sms_intrtype) { 137032a8088fSRui Paulo case ASMC_SMS_INTFF: 137132a8088fSRui Paulo type = 2; 137232a8088fSRui Paulo break; 137332a8088fSRui Paulo case ASMC_SMS_INTHA: 137432a8088fSRui Paulo type = 1; 137532a8088fSRui Paulo break; 137632a8088fSRui Paulo case ASMC_SMS_INTSH: 137732a8088fSRui Paulo type = 0; 137832a8088fSRui Paulo break; 137932a8088fSRui Paulo default: 138032a8088fSRui Paulo type = 255; 138132a8088fSRui Paulo } 138232a8088fSRui Paulo 138332a8088fSRui Paulo snprintf(notify, sizeof(notify), " notify=0x%x", type); 13844470f0f3SRui Paulo devctl_notify("ACPI", "asmc", "SMS", notify); 138532a8088fSRui Paulo } 138632a8088fSRui Paulo 138732a8088fSRui Paulo static int 138832a8088fSRui Paulo asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 138932a8088fSRui Paulo { 139032a8088fSRui Paulo device_t dev = (device_t) arg1; 139132a8088fSRui Paulo int error; 139232a8088fSRui Paulo int16_t val; 139332a8088fSRui Paulo int32_t v; 139432a8088fSRui Paulo 139532a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 139632a8088fSRui Paulo v = (int32_t) val; 139732a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 139832a8088fSRui Paulo 139932a8088fSRui Paulo return (error); 140032a8088fSRui Paulo } 140132a8088fSRui Paulo 140232a8088fSRui Paulo static int 140332a8088fSRui Paulo asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 140432a8088fSRui Paulo { 140532a8088fSRui Paulo device_t dev = (device_t) arg1; 140632a8088fSRui Paulo int error; 140732a8088fSRui Paulo int16_t val; 140832a8088fSRui Paulo int32_t v; 140932a8088fSRui Paulo 141032a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 141132a8088fSRui Paulo v = (int32_t) val; 141232a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 141332a8088fSRui Paulo 141432a8088fSRui Paulo return (error); 141532a8088fSRui Paulo } 141632a8088fSRui Paulo 141732a8088fSRui Paulo static int 141832a8088fSRui Paulo asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 141932a8088fSRui Paulo { 142032a8088fSRui Paulo device_t dev = (device_t) arg1; 142132a8088fSRui Paulo int error; 142232a8088fSRui Paulo int16_t val; 142332a8088fSRui Paulo int32_t v; 142432a8088fSRui Paulo 142532a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 142632a8088fSRui Paulo v = (int32_t) val; 14270e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 142832a8088fSRui Paulo 142932a8088fSRui Paulo return (error); 143032a8088fSRui Paulo } 143132a8088fSRui Paulo 143232a8088fSRui Paulo static int 143332a8088fSRui Paulo asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 143432a8088fSRui Paulo { 143532a8088fSRui Paulo device_t dev = (device_t) arg1; 143632a8088fSRui Paulo uint8_t buf[6]; 143732a8088fSRui Paulo int error; 143832a8088fSRui Paulo int32_t v; 143932a8088fSRui Paulo 1440447666f0SRui Paulo asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); 144132a8088fSRui Paulo v = buf[2]; 14420e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 144332a8088fSRui Paulo 144432a8088fSRui Paulo return (error); 144532a8088fSRui Paulo } 144632a8088fSRui Paulo 144732a8088fSRui Paulo static int 144832a8088fSRui Paulo asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 144932a8088fSRui Paulo { 145032a8088fSRui Paulo device_t dev = (device_t) arg1; 145132a8088fSRui Paulo uint8_t buf[6]; 145232a8088fSRui Paulo int error; 145332a8088fSRui Paulo int32_t v; 145432a8088fSRui Paulo 1455447666f0SRui Paulo asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf); 145632a8088fSRui Paulo v = buf[2]; 14570e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 1458be80e49aSRui Paulo 1459be80e49aSRui Paulo return (error); 1460be80e49aSRui Paulo } 1461be80e49aSRui Paulo 1462be80e49aSRui Paulo static int 1463be80e49aSRui Paulo asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 1464be80e49aSRui Paulo { 1465be80e49aSRui Paulo device_t dev = (device_t) arg1; 1466be80e49aSRui Paulo uint8_t buf[2]; 1467be80e49aSRui Paulo int error; 14680e1152fcSHans Petter Selasky int v; 1469be80e49aSRui Paulo 1470108e3076SAdrian Chadd v = light_control; 14710e1152fcSHans Petter Selasky error = sysctl_handle_int(oidp, &v, 0, req); 14720e1152fcSHans Petter Selasky 14730e1152fcSHans Petter Selasky if (error == 0 && req->newptr != NULL) { 14740e1152fcSHans Petter Selasky if (v < 0 || v > 255) 14750e1152fcSHans Petter Selasky return (EINVAL); 1476108e3076SAdrian Chadd light_control = v; 1477108e3076SAdrian Chadd buf[0] = light_control; 147832a8088fSRui Paulo buf[1] = 0x00; 1479447666f0SRui Paulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); 148032a8088fSRui Paulo } 148132a8088fSRui Paulo return (error); 148232a8088fSRui Paulo } 1483