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 *
asmc_match(device_t dev)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
asmc_probe(device_t dev)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
asmc_attach(device_t dev)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
asmc_detach(device_t dev)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
asmc_resume(device_t dev)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
asmc_dumpall(device_t dev)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
asmc_init(device_t dev)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
asmc_wait_ack(device_t dev,uint8_t val,int amount)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
asmc_wait(device_t dev,uint8_t val)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
asmc_command(device_t dev,uint8_t command)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
asmc_key_read(device_t dev,const char * key,uint8_t * buf,uint8_t len)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
asmc_key_dump(device_t dev,int number)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
asmc_key_write(device_t dev,const char * key,uint8_t * buf,uint8_t len)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
asmc_fan_count(device_t dev)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
asmc_fan_getvalue(device_t dev,const char * key,int fan)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*
asmc_fan_getstring(device_t dev,const char * key,int fan,uint8_t * buf,uint8_t buflen)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
asmc_fan_setvalue(device_t dev,const char * key,int fan,int speed)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
asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)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
asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)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
asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)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
asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)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
asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)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
asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)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
asmc_temp_getvalue(device_t dev,const char * key)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
asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)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
asmc_sms_read(device_t dev,const char * key,int16_t * val)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
asmc_sms_calibrate(device_t dev)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
asmc_sms_intrfast(void * arg)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
asmc_sms_printintr(device_t dev,uint8_t type)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
asmc_sms_task(void * arg,int pending)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
asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)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
asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)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
asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)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
asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)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
asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)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
asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)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
asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)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