aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/asmc
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/asmc')
-rw-r--r--sys/dev/asmc/asmc.c2364
-rw-r--r--sys/dev/asmc/asmcmmio.c402
-rw-r--r--sys/dev/asmc/asmcmmio.h56
-rw-r--r--sys/dev/asmc/asmcvar.h919
4 files changed, 2326 insertions, 1415 deletions
diff --git a/sys/dev/asmc/asmc.c b/sys/dev/asmc/asmc.c
index d99c1d56e67c..d55c585419fb 100644
--- a/sys/dev/asmc/asmc.c
+++ b/sys/dev/asmc/asmc.c
@@ -34,6 +34,8 @@
* Inspired by the Linux applesmc driver.
*/
+#include "opt_asmc.h"
+
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/conf.h>
@@ -43,17 +45,23 @@
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
+#include <sys/sbuf.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <sys/rman.h>
#include <machine/resource.h>
+#include <netinet/in.h>
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/acpica/acpivar.h>
#include <dev/asmc/asmcvar.h>
+#include <dev/asmc/asmcmmio.h>
+
+#include <dev/backlight/backlight.h>
+#include "backlight_if.h"
/*
* Device interface.
@@ -64,6 +72,15 @@ static int asmc_detach(device_t dev);
static int asmc_resume(device_t dev);
/*
+ * Backlight interface.
+ */
+static int asmc_backlight_update_status(device_t dev,
+ struct backlight_props *props);
+static int asmc_backlight_get_status(device_t dev,
+ struct backlight_props *props);
+static int asmc_backlight_get_info(device_t dev, struct backlight_info *info);
+
+/*
* SMC functions.
*/
static int asmc_init(device_t dev);
@@ -83,13 +100,15 @@ static void asmc_sms_calibrate(device_t dev);
static int asmc_sms_intrfast(void *arg);
static void asmc_sms_printintr(device_t dev, uint8_t);
static void asmc_sms_task(void *arg, int pending);
-#ifdef DEBUG
+static void asmc_sms_init(device_t dev);
+static void asmc_detect_capabilities(device_t dev);
+#ifdef ASMC_DEBUG
void asmc_dumpall(device_t);
static int asmc_key_dump(device_t, int);
#endif
/*
- * Model functions.
+ * Sysctl handlers.
*/
static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
@@ -97,6 +116,7 @@ static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
+static int asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS);
static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
@@ -105,392 +125,245 @@ static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS);
+static int asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS);
-struct asmc_model {
- const char *smc_model; /* smbios.system.product env var. */
- const char *smc_desc; /* driver description */
-
- /* Helper functions */
- int (*smc_sms_x)(SYSCTL_HANDLER_ARGS);
- int (*smc_sms_y)(SYSCTL_HANDLER_ARGS);
- int (*smc_sms_z)(SYSCTL_HANDLER_ARGS);
- int (*smc_fan_id)(SYSCTL_HANDLER_ARGS);
- int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS);
- int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS);
- int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS);
- int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS);
- int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
- int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
- int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
- int (*smc_light_control)(SYSCTL_HANDLER_ARGS);
-
- const char *smc_temps[ASMC_TEMP_MAX];
- const char *smc_tempnames[ASMC_TEMP_MAX];
- const char *smc_tempdescs[ASMC_TEMP_MAX];
-};
-
-static const struct asmc_model *asmc_match(device_t dev);
-
-#define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \
- asmc_mb_sysctl_sms_z
-
-#define ASMC_SMS_FUNCS_DISABLED NULL,NULL,NULL
-
-#define ASMC_FAN_FUNCS asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \
- asmc_mb_sysctl_fanminspeed, \
- asmc_mb_sysctl_fanmaxspeed, \
- asmc_mb_sysctl_fantargetspeed
-
-#define ASMC_FAN_FUNCS2 asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \
- asmc_mb_sysctl_fanminspeed, \
- asmc_mb_sysctl_fanmaxspeed, \
- asmc_mb_sysctl_fantargetspeed
-
-#define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \
- asmc_mbp_sysctl_light_right, \
- asmc_mbp_sysctl_light_control
-
-#define ASMC_LIGHT_FUNCS_10BYTE \
- asmc_mbp_sysctl_light_left_10byte, \
- NULL, \
- asmc_mbp_sysctl_light_control
-
-#define ASMC_LIGHT_FUNCS_DISABLED NULL, NULL, NULL
-
-static const struct asmc_model asmc_models[] = {
- {
- "MacBook1,1", "Apple SMC MacBook Core Duo",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
- ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
- },
-
- {
- "MacBook2,1", "Apple SMC MacBook Core 2 Duo",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
- ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
- },
-
- {
- "MacBook3,1", "Apple SMC MacBook Core 2 Duo",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
- ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS
- },
-
- {
- "MacBook7,1", "Apple SMC MacBook Core 2 Duo (mid 2010)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED,
- ASMC_MB71_TEMPS, ASMC_MB71_TEMPNAMES, ASMC_MB71_TEMPDESCS
- },
-
- {
- "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
- },
-
- {
- "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
- },
-
- {
- "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
- },
-
- {
- "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
- },
-
- {
- "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
- },
-
- {
- "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
- },
-
- {
- "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS
- },
-
- {
- "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP51_TEMPS, ASMC_MBP51_TEMPNAMES, ASMC_MBP51_TEMPDESCS
- },
-
- {
- "MacBookPro5,5", "Apple SMC MacBook Pro Core 2 Duo (Mid 2009)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
- ASMC_MBP55_TEMPS, ASMC_MBP55_TEMPNAMES, ASMC_MBP55_TEMPDESCS
- },
-
- {
- "MacBookPro6,2", "Apple SMC MacBook Pro (Mid 2010, 15-inch)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP62_TEMPS, ASMC_MBP62_TEMPNAMES, ASMC_MBP62_TEMPDESCS
- },
+static int asmc_key_getinfo(device_t, const char *, uint8_t *, char *);
- {
- "MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)",
- ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
- ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS
- },
-
- {
- "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS
- },
+/* System state / board identity sysctls */
+static int asmc_cause_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_msal_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_clkt_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_msps_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_rplt_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_rgen_sysctl(SYSCTL_HANDLER_ARGS);
- {
- "MacBookPro9,1", "Apple SMC MacBook Pro (mid 2012, 15-inch)",
- ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP91_TEMPS, ASMC_MBP91_TEMPNAMES, ASMC_MBP91_TEMPDESCS
- },
-
- {
- "MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012, 13-inch)",
- ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP92_TEMPS, ASMC_MBP92_TEMPNAMES, ASMC_MBP92_TEMPDESCS
- },
-
- {
- "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
- ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
- ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS
- },
-
- {
- "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS
- },
-
- {
- "MacBookPro11,4", "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch)",
- ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
- ASMC_MBP114_TEMPS, ASMC_MBP114_TEMPNAMES, ASMC_MBP114_TEMPDESCS
- },
-
- /* The Mac Mini has no SMS */
- {
- "Macmini1,1", "Apple SMC Mac Mini",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS,
- NULL, NULL, NULL,
- ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
- },
-
- /* The Mac Mini 2,1 has no SMS */
- {
- "Macmini2,1", "Apple SMC Mac Mini 2,1",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS,
- ASMC_LIGHT_FUNCS_DISABLED,
- ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS
- },
-
- /* The Mac Mini 3,1 has no SMS */
- {
- "Macmini3,1", "Apple SMC Mac Mini 3,1",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS,
- NULL, NULL, NULL,
- ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS
- },
-
- /* The Mac Mini 4,1 (Mid-2010) has no SMS */
- {
- "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS,
- ASMC_LIGHT_FUNCS_DISABLED,
- ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS
- },
-
- /* The Mac Mini 5,1 has no SMS */
- /* - same sensors as Mac Mini 5,2 */
- {
- "Macmini5,1", "Apple SMC Mac Mini 5,1",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS2,
- NULL, NULL, NULL,
- ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
- },
-
- /* The Mac Mini 5,2 has no SMS */
- {
- "Macmini5,2", "Apple SMC Mac Mini 5,2",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS2,
- NULL, NULL, NULL,
- ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
- },
-
- /* The Mac Mini 5,3 has no SMS */
- /* - same sensors as Mac Mini 5,2 */
- {
- "Macmini5,3", "Apple SMC Mac Mini 5,3",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS2,
- NULL, NULL, NULL,
- ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
- },
-
- /* The Mac Mini 6,1 has no SMS */
- {
- "Macmini6,1", "Apple SMC Mac Mini 6,1",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS2,
- NULL, NULL, NULL,
- ASMC_MM61_TEMPS, ASMC_MM61_TEMPNAMES, ASMC_MM61_TEMPDESCS
- },
-
- /* The Mac Mini 6,2 has no SMS */
- {
- "Macmini6,2", "Apple SMC Mac Mini 6,2",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS2,
- NULL, NULL, NULL,
- ASMC_MM62_TEMPS, ASMC_MM62_TEMPNAMES, ASMC_MM62_TEMPDESCS
- },
-
- /* The Mac Mini 7,1 has no SMS */
- {
- "Macmini7,1", "Apple SMC Mac Mini 7,1",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS2,
- NULL, NULL, NULL,
- ASMC_MM71_TEMPS, ASMC_MM71_TEMPNAMES, ASMC_MM71_TEMPDESCS
- },
-
- /* Idem for the Mac Pro "Quad Core" (original) */
- {
- "MacPro1,1", "Apple SMC Mac Pro (Quad Core)",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS,
- NULL, NULL, NULL,
- ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS
- },
-
- /* Idem for the Mac Pro (8-core) */
- {
- "MacPro2", "Apple SMC Mac Pro (8-core)",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS,
- NULL, NULL, NULL,
- ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS
- },
-
- /* Idem for the MacPro 2010*/
- {
- "MacPro5,1", "Apple SMC MacPro (2010)",
- NULL, NULL, NULL,
- ASMC_FAN_FUNCS,
- NULL, NULL, NULL,
- ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS
- },
-
- /* Idem for the Mac Pro 2013 (cylinder) */
- {
- "MacPro6,1", "Apple SMC Mac Pro (2013)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS_DISABLED,
- ASMC_MP6_TEMPS, ASMC_MP6_TEMPNAMES, ASMC_MP6_TEMPDESCS
- },
-
- {
- "MacBookAir1,1", "Apple SMC MacBook Air",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
- ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
- },
-
- {
- "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)",
- ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
- ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS
- },
+#ifdef ASMC_DEBUG
+/* Raw key access */
+static int asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS);
+#endif
- {
- "MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS,
- ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
- },
+/* Voltage/Current/Power/Light sensor support */
+static int asmc_sensor_read(device_t, const char *, int *);
+static int asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS);
+static int asmc_detect_sensors(device_t);
+static int asmc_key_dump_by_index(device_t, int, char *, char *, uint8_t *);
+static int asmc_key_search(device_t, const char *, unsigned int *);
+static const char *asmc_temp_desc(const char *key);
- {
- "MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS,
- ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
- },
-
- {
- "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS,
- ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
- },
-
- {
- "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS,
- ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
- },
- {
- "MacBookAir6,1", "Apple SMC MacBook Air 11-inch (Early 2013)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS_10BYTE,
- ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
- },
- {
- "MacBookAir6,2", "Apple SMC MacBook Air 13-inch (Early 2013)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS_10BYTE,
- ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
- },
- {
- "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS,
- ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
- },
- {
- "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)",
- ASMC_SMS_FUNCS_DISABLED,
- ASMC_FAN_FUNCS2,
- ASMC_LIGHT_FUNCS,
- ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
- },
- { NULL, NULL }
+/*
+ * SMC temperature key descriptions.
+ * These are universal across all Intel Apple hardware.
+ */
+static const struct {
+ const char *key;
+ const char *desc;
+} asmc_temp_descs[] = {
+ /* Ambient / airflow */
+ { "TA0P", "Ambient" },
+ { "TA0S", "PCIe Slot 1 Ambient" },
+ { "TA0p", "Ambient Air" },
+ { "TA1P", "Ambient 2" },
+ { "TA1S", "PCIe Slot 1 PCB" },
+ { "TA1p", "Ambient Air 2" },
+ { "TA2P", "Ambient 3" },
+ { "TA2S", "PCIe Slot 2 Ambient" },
+ { "TA3S", "PCIe Slot 2 PCB" },
+ { "TA0V", "Ambient" },
+ { "TALP", "Ambient Light Proximity" },
+ { "TaLC", "Airflow Left" },
+ { "TaRC", "Airflow Right" },
+ { "Ta0P", "Airflow Proximity" },
+ /* Battery / enclosure */
+ { "TB0T", "Enclosure Bottom" },
+ { "TB1T", "Battery 1" },
+ { "TB2T", "Battery 2" },
+ { "TB3T", "Battery 3" },
+ { "TBXT", "Battery" },
+ { "Tb0P", "BLC Proximity" },
+ /* CPU */
+ { "TC0C", "CPU Core 1" },
+ { "TC0D", "CPU Die" },
+ { "TC0E", "CPU 1" },
+ { "TC0F", "CPU 2" },
+ { "TC0G", "CPU Package GPU" },
+ { "TC0H", "CPU Heatsink" },
+ { "TC0h", "CPU Heatsink" },
+ { "TC0J", "CPU" },
+ { "TC0P", "CPU Proximity" },
+ { "TC0c", "CPU Core 1 PECI" },
+ { "TC0d", "CPU Die PECI" },
+ { "TC0p", "CPU Proximity" },
+ { "TC1C", "CPU Core 2" },
+ { "TC1c", "CPU Core 2 PECI" },
+ { "TC1P", "CPU Proximity 2" },
+ { "TC2C", "CPU Core 3" },
+ { "TC2P", "CPU Proximity 3" },
+ { "TC2c", "CPU Core 3 PECI" },
+ { "TC3C", "CPU Core 4" },
+ { "TC3P", "CPU Proximity 4" },
+ { "TC3c", "CPU Core 4 PECI" },
+ { "TC4C", "CPU Core 5" },
+ { "TC5C", "CPU Core 6" },
+ { "TC6C", "CPU Core 7" },
+ { "TC7C", "CPU Core 8" },
+ { "TC8C", "CPU Core 9" },
+ { "TCGC", "PECI GPU" },
+ { "TCGc", "PECI GPU" },
+ { "TCHP", "Charger Proximity" },
+ { "TCSA", "PECI SA" },
+ { "TCSC", "PECI SA" },
+ { "TCSc", "PECI SA" },
+ { "TCTD", "CPU DTS" },
+ { "TCXC", "PECI CPU" },
+ { "TCXc", "PECI CPU" },
+ { "TCPG", "CPU Package GPU" },
+ { "TCXR", "CPU PECI DTS" },
+ /* CPU dual-socket (Mac Pro) */
+ { "TCAG", "CPU A Package" },
+ { "TCAH", "CPU A Heatsink" },
+ { "TCBG", "CPU B Package" },
+ { "TCBH", "CPU B Heatsink" },
+ /* GPU */
+ { "TG0C", "GPU Core" },
+ { "TG0D", "GPU Diode" },
+ { "TG0H", "GPU Heatsink" },
+ { "TG0M", "GPU Memory" },
+ { "TG0P", "GPU Proximity" },
+ { "TG0T", "GPU Diode" },
+ { "TG0V", "GPU" },
+ { "TG0d", "GPU Die" },
+ { "TG0h", "GPU Heatsink" },
+ { "TG0p", "GPU Proximity" },
+ { "TGTV", "GPU" },
+ { "TG1D", "GPU 2 Diode" },
+ { "TG1H", "GPU 2 Heatsink" },
+ { "TG1P", "GPU 2 Proximity" },
+ { "TG1d", "GPU 2 Die" },
+ { "TGVP", "GPU Memory Proximity" },
+ /* Storage */
+ { "TH0A", "SSD A" },
+ { "TH0B", "SSD B" },
+ { "TH0C", "SSD C" },
+ { "TH0F", "SSD" },
+ { "TH0O", "HDD" },
+ { "TH0P", "HDD Proximity" },
+ { "TH0R", "SSD" },
+ { "TH0V", "SSD" },
+ { "TH0a", "SSD A" },
+ { "TH0b", "SSD B" },
+ { "TH0c", "SSD C" },
+ { "TH1O", "HDD 2" },
+ { "TH1P", "HDD Bay 2" },
+ { "TH2P", "HDD Bay 3" },
+ { "TH3P", "HDD Bay 4" },
+ { "Th0H", "Heatpipe 1" },
+ { "Th0N", "SSD" },
+ { "Th1H", "Heatpipe 2" },
+ { "Th2H", "Heatpipe 3" },
+ /* Thunderbolt */
+ { "THSP", "Thunderbolt Proximity" },
+ { "TI0P", "Thunderbolt 1" },
+ { "TI0p", "Thunderbolt 1" },
+ { "TI1P", "Thunderbolt 2" },
+ { "TI1p", "Thunderbolt 2" },
+ { "TTLD", "Thunderbolt Left" },
+ { "TTRD", "Thunderbolt Right" },
+ { "Te0T", "Thunderbolt Diode" },
+ { "Te0t", "Thunderbolt Diode" },
+ /* LCD */
+ { "TL0P", "LCD Proximity" },
+ { "TL0V", "LCD" },
+ { "TL0p", "LCD Proximity" },
+ { "TL1P", "LCD Panel 1" },
+ { "TL1V", "LCD 1" },
+ { "TL1p", "LCD Panel 1" },
+ { "TL1v", "LCD 1" },
+ { "TL2V", "LCD 2" },
+ { "TLAV", "LCD" },
+ { "TLBV", "LCD" },
+ { "TLCV", "LCD" },
+ /* Memory */
+ { "TM0P", "Memory Proximity" },
+ { "TM0S", "Memory Slot 1" },
+ { "TM0p", "Memory Proximity" },
+ { "TM1P", "Memory Riser A 2" },
+ { "TM1S", "Memory Slot 2" },
+ { "Tm0P", "Memory Proximity" },
+ { "Tm0p", "Memory Proximity" },
+ { "Tm1P", "Memory Proximity 2" },
+ { "TMBS", "Memory Bank" },
+ { "TMCD", "Memory DIMM" },
+ /* Northbridge / MCH */
+ { "TN0C", "Northbridge Core" },
+ { "TN0D", "Northbridge Diode" },
+ { "TN0H", "MCH Heatsink" },
+ { "TN0P", "Northbridge Proximity" },
+ { "TN1D", "MCH Die 2" },
+ { "TN1P", "Northbridge Proximity 2" },
+ /* PCH */
+ { "TP0P", "PCH Proximity" },
+ { "TP0p", "PCH Proximity" },
+ { "TPCD", "PCH Die" },
+ { "TPCd", "PCH Die" },
+ /* Optical drive */
+ { "TO0P", "Optical Drive" },
+ { "TO0p", "Optical Drive" },
+ /* Power supply */
+ { "Tp0C", "Power Supply" },
+ { "Tp0P", "Power Supply Proximity" },
+ { "Tp1C", "Power Supply 2" },
+ { "Tp1P", "Power Supply Component" },
+ { "Tp1p", "Power Supply Component" },
+ { "Tp2P", "Power Supply 2" },
+ { "Tp2h", "Power Supply 2" },
+ { "Tp2H", "Power Supply 2" },
+ { "Tp3P", "Power Supply 3 Inlet" },
+ { "Tp3h", "Power Supply 3" },
+ { "Tp3H", "Power Supply 3" },
+ { "Tp4P", "Power Supply 4" },
+ { "Tp5P", "Power Supply 5" },
+ /* Palm rest / trackpad */
+ { "Ts0P", "Palm Rest" },
+ { "Ts0S", "Memory Proximity" },
+ { "Ts1P", "Palm Rest 2" },
+ { "Ts1S", "Palm Rest 2" },
+ /* Wireless */
+ { "TW0P", "Wireless Proximity" },
+ { "TW0p", "Wireless Proximity" },
+ { "TBLR", "Bluetooth" },
+ /* Camera */
+ { "TS2P", "Camera Proximity" },
+ { "TS2V", "Camera" },
+ { "TS2p", "Camera Proximity" },
+ /* Expansion */
+ { "TS0C", "Expansion Slots" },
+ { "TS0P", "Expansion Proximity" },
+ { "TS0V", "Expansion" },
+ { "TS0p", "Expansion Proximity" },
+ /* Air vent */
+ { "TV0P", "Air Vent" },
+ /* VRM */
+ { "Tv0S", "VRM 1" },
+ { "Tv1S", "VRM 2" },
+ /* Misc */
+ { "TTF0", "Fan" },
+ { "TMLB", "Logic Board" },
};
-#undef ASMC_SMS_FUNCS
-#undef ASMC_SMS_FUNCS_DISABLED
-#undef ASMC_FAN_FUNCS
-#undef ASMC_FAN_FUNCS2
-#undef ASMC_LIGHT_FUNCS
+static const char *
+asmc_temp_desc(const char *key)
+{
+ unsigned int i;
+
+ for (i = 0; i < nitems(asmc_temp_descs); i++) {
+ if (strcmp(asmc_temp_descs[i].key, key) == 0)
+ return (asmc_temp_descs[i].desc);
+ }
+ return ("Temperature");
+}
/*
* Driver methods.
@@ -500,7 +373,13 @@ static device_method_t asmc_methods[] = {
DEVMETHOD(device_attach, asmc_attach),
DEVMETHOD(device_detach, asmc_detach),
DEVMETHOD(device_resume, asmc_resume),
- { 0, 0 }
+
+ /* Backlight interface */
+ DEVMETHOD(backlight_update_status, asmc_backlight_update_status),
+ DEVMETHOD(backlight_get_status, asmc_backlight_get_status),
+ DEVMETHOD(backlight_get_info, asmc_backlight_get_info),
+
+ DEVMETHOD_END
};
static driver_t asmc_driver = {
@@ -514,10 +393,10 @@ static driver_t asmc_driver = {
*/
#define _COMPONENT ACPI_OEM
ACPI_MODULE_NAME("ASMC")
-#ifdef DEBUG
-#define ASMC_DPRINTF(str) device_printf(dev, str)
+#ifdef ASMC_DEBUG
+#define ASMC_DPRINTF(str, ...) device_printf(dev, str, ##__VA_ARGS__)
#else
-#define ASMC_DPRINTF(str)
+#define ASMC_DPRINTF(str, ...)
#endif
/* NB: can't be const */
@@ -525,34 +404,15 @@ static char *asmc_ids[] = { "APP0001", NULL };
static unsigned int light_control = 0;
+ACPI_PNP_INFO(asmc_ids);
DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL);
MODULE_DEPEND(asmc, acpi, 1, 1, 1);
-
-static const struct asmc_model *
-asmc_match(device_t dev)
-{
- int i;
- char *model;
-
- model = kern_getenv("smbios.system.product");
- if (model == NULL)
- return (NULL);
-
- for (i = 0; asmc_models[i].smc_model; i++) {
- if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) {
- freeenv(model);
- return (&asmc_models[i]);
- }
- }
- freeenv(model);
-
- return (NULL);
-}
+MODULE_DEPEND(asmc, backlight, 1, 1, 1);
static int
asmc_probe(device_t dev)
{
- const struct asmc_model *model;
+ char *product;
int rv;
if (resource_disabled("asmc", 0))
@@ -560,15 +420,41 @@ asmc_probe(device_t dev)
rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL);
if (rv > 0)
return (rv);
+ product = kern_getenv("smbios.system.product");
+ device_set_descf(dev, "Apple %s", product ? product : "SMC");
+ freeenv(product);
+ return (rv);
+}
- model = asmc_match(dev);
- if (!model) {
- device_printf(dev, "model not recognized\n");
- return (ENXIO);
+/*
+ * Try PIO first; fall back to MMIO for T2 Macs.
+ */
+static int
+asmc_try_probe(device_t dev)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+
+ sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
+ &sc->sc_rid_port, RF_ACTIVE);
+ if (sc->sc_ioport != NULL)
+ return (0);
+
+ sc->sc_rid_mem = 0;
+ sc->sc_iomem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->sc_rid_mem, RF_ACTIVE);
+ if (sc->sc_iomem != NULL) {
+ if (asmc_mmio_probe(dev) == 0) {
+ sc->sc_is_mmio = true;
+ device_printf(dev, "using MMIO backend (T2)\n");
+ return (0);
+ }
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->sc_rid_mem, sc->sc_iomem);
+ sc->sc_iomem = NULL;
}
- device_set_desc(dev, model->smc_desc);
- return (rv);
+ device_printf(dev, "unable to allocate IO port\n");
+ return (ENOMEM);
}
static int
@@ -580,24 +466,30 @@ asmc_attach(device_t dev)
struct asmc_softc *sc = device_get_softc(dev);
struct sysctl_ctx_list *sysctlctx;
struct sysctl_oid *sysctlnode;
- const struct asmc_model *model;
- sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
- &sc->sc_rid_port, RF_ACTIVE);
- if (sc->sc_ioport == NULL) {
- device_printf(dev, "unable to allocate IO port\n");
- return (ENOMEM);
- }
+ ret = asmc_try_probe(dev);
+ if (ret != 0)
+ goto err;
- sysctlctx = device_get_sysctl_ctx(dev);
+ sysctlctx = device_get_sysctl_ctx(dev);
sysctlnode = device_get_sysctl_tree(dev);
- model = asmc_match(dev);
+ /* Mutex may already be initialized by asmc_mmio_probe() */
+ if (!mtx_initialized(&sc->sc_mtx))
+ mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
+
+ /* Read SMC revision, key count, fan count */
+ ret = asmc_init(dev);
+ if (ret != 0) {
+ device_printf(dev, "SMC not responding\n");
+ goto err;
+ }
- mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
+ /* Probe SMC keys to detect capabilities */
+ asmc_detect_capabilities(dev);
- sc->sc_model = model;
- asmc_init(dev);
+ /* Auto-detect and register voltage/current/power/ambient/temp sensors */
+ asmc_detect_sensors(dev);
/*
* dev.asmc.n.fan.* tree.
@@ -611,51 +503,57 @@ asmc_attach(device_t dev)
name[0] = '0' + j;
name[1] = 0;
sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
- SYSCTL_CHILDREN(sc->sc_fan_tree[0]),
- OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
- "Fan Subtree");
+ SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name,
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree");
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
OID_AUTO, "id",
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, j, model->smc_fan_id, "I",
- "Fan ID");
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
+ asmc_mb_sysctl_fanid, "I", "Fan ID");
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
OID_AUTO, "speed",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, j, model->smc_fan_speed, "I",
- "Fan speed in RPM");
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
+ asmc_mb_sysctl_fanspeed, "I", "Fan speed in RPM");
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
- OID_AUTO, "safespeed",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, j, model->smc_fan_safespeed, "I",
- "Fan safe speed in RPM");
+ if (sc->sc_has_safespeed) {
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
+ OID_AUTO, "safespeed",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
+ asmc_mb_sysctl_fansafespeed, "I",
+ "Fan safe speed in RPM");
+ }
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
OID_AUTO, "minspeed",
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
- dev, j, model->smc_fan_minspeed, "I",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
+ asmc_mb_sysctl_fanminspeed, "I",
"Fan minimum speed in RPM");
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
OID_AUTO, "maxspeed",
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
- dev, j, model->smc_fan_maxspeed, "I",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
+ asmc_mb_sysctl_fanmaxspeed, "I",
"Fan maximum speed in RPM");
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
OID_AUTO, "targetspeed",
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
- dev, j, model->smc_fan_targetspeed, "I",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
+ asmc_mb_sysctl_fantargetspeed, "I",
"Fan target speed in RPM");
+
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
+ OID_AUTO, "manual",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
+ asmc_mb_sysctl_fanmanual, "I",
+ "Fan manual mode (0=auto, 1=manual)");
}
/*
@@ -665,19 +563,19 @@ asmc_attach(device_t dev)
SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors");
- for (i = 0; model->smc_temps[i]; i++) {
+ for (i = 0; i < sc->sc_temp_count; i++) {
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_temp_tree),
- OID_AUTO, model->smc_tempnames[i],
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, i, asmc_temp_sysctl, "I",
- model->smc_tempdescs[i]);
+ OID_AUTO, sc->sc_temp_sensors[i],
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, i,
+ asmc_temp_sysctl, "I",
+ asmc_temp_desc(sc->sc_temp_sensors[i]));
}
/*
* dev.asmc.n.light
*/
- if (model->smc_light_left) {
+ if (sc->sc_has_light) {
sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
@@ -686,30 +584,164 @@ asmc_attach(device_t dev)
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_light_tree),
OID_AUTO, "left",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, 0, model->smc_light_left, "I",
- "Keyboard backlight left sensor");
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0,
+ sc->sc_light_len == ASMC_LIGHT_LONGLEN ?
+ asmc_mbp_sysctl_light_left_10byte :
+ asmc_mbp_sysctl_light_left,
+ "I", "Keyboard backlight left sensor");
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sc->sc_light_tree),
- OID_AUTO, "right",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, 0, model->smc_light_right, "I",
- "Keyboard backlight right sensor");
+ if (sc->sc_light_len != ASMC_LIGHT_LONGLEN &&
+ asmc_key_getinfo(dev, ASMC_KEY_LIGHTRIGHT,
+ NULL, NULL) == 0) {
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sc->sc_light_tree),
+ OID_AUTO, "right",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0,
+ asmc_mbp_sysctl_light_right, "I",
+ "Keyboard backlight right sensor");
+ }
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_light_tree),
OID_AUTO, "control",
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY |
- CTLFLAG_NEEDGIANT, dev, 0,
- model->smc_light_control, "I",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
+ dev, 0, asmc_mbp_sysctl_light_control, "I",
"Keyboard backlight brightness control");
+
+ sc->sc_kbd_bkl = backlight_register("asmc", dev);
+ if (sc->sc_kbd_bkl == NULL) {
+ device_printf(dev, "Can not register backlight\n");
+ ret = ENXIO;
+ goto err;
+ }
+ }
+
+#ifdef ASMC_DEBUG
+ /*
+ * Raw SMC key access for debugging.
+ */
+ sc->sc_raw_tree = SYSCTL_ADD_NODE(sysctlctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "raw", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Raw SMC key access");
+
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sc->sc_raw_tree),
+ OID_AUTO, "key",
+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ dev, 0, asmc_raw_key_sysctl, "A",
+ "SMC key name (4 chars)");
+
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sc->sc_raw_tree),
+ OID_AUTO, "value",
+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ dev, 0, asmc_raw_value_sysctl, "A",
+ "SMC key value (hex string)");
+
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sc->sc_raw_tree),
+ OID_AUTO, "len",
+ CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_raw_len_sysctl, "CU",
+ "SMC key value length");
+
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sc->sc_raw_tree),
+ OID_AUTO, "type",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_raw_type_sysctl, "A",
+ "SMC key type (4 chars)");
+#endif
+
+ /*
+ * Battery charge limit (T2 Macs).
+ */
+ if (sc->sc_is_t2 &&
+ asmc_key_getinfo(dev, ASMC_KEY_BCLM, NULL, NULL) == 0) {
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "battery_charge_limit",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ dev, 0, asmc_bclm_sysctl, "I",
+ "Battery charge limit (0-100)");
}
- if (model->smc_sms_x == NULL)
+ /* System state / board identity subtree. */
+ {
+ struct sysctl_oid *sys_tree;
+ uint8_t msps_len;
+
+ sys_tree = SYSCTL_ADD_NODE(sysctlctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "system", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "System state and board identity");
+ if (sys_tree == NULL) {
+ device_printf(dev,
+ "failed to create system sysctl node\n");
+ goto nosms;
+ }
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_MSSD, NULL, NULL) == 0)
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sys_tree), OID_AUTO, "shutdown_cause",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_cause_sysctl, "A",
+ "Last shutdown cause (MSSD)");
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_MSSP, NULL, NULL) == 0)
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sys_tree), OID_AUTO, "sleep_cause",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 1, asmc_cause_sysctl, "A",
+ "Last sleep cause (MSSP)");
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_MSAL, NULL, NULL) == 0)
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sys_tree), OID_AUTO, "thermal_status",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_msal_sysctl, "A",
+ "Thermal subsystem status flags (MSAL)");
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_CLKT, NULL, NULL) == 0)
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sys_tree), OID_AUTO, "time_of_day",
+ CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_clkt_sysctl, "IU",
+ "Seconds since midnight per SMC clock (CLKT)");
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_MSPS, &msps_len, NULL) == 0 &&
+ (msps_len == 1 || msps_len == 2))
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sys_tree), OID_AUTO, "power_state",
+ CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_msps_sysctl, "IU",
+ "SMC power state index (MSPS)");
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_RPLT, NULL, NULL) == 0)
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sys_tree), OID_AUTO, "board_id",
+ CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_rplt_sysctl, "A",
+ "Apple internal board codename (RPlt)");
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_RGEN, NULL, NULL) == 0)
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(sys_tree), OID_AUTO, "chip_gen",
+ CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_rgen_sysctl, "IU",
+ "Apple security chip generation (RGEN; 3=T2)");
+ }
+
+ if (!sc->sc_has_sms)
goto nosms;
/*
+ * Initialize SMS hardware.
+ */
+ asmc_sms_init(dev);
+
+ /*
* dev.asmc.n.sms tree.
*/
sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
@@ -719,22 +751,22 @@ asmc_attach(device_t dev)
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_sms_tree),
OID_AUTO, "x",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, 0, model->smc_sms_x, "I",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_mb_sysctl_sms_x, "I",
"Sudden Motion Sensor X value");
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_sms_tree),
OID_AUTO, "y",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, 0, model->smc_sms_y, "I",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_mb_sysctl_sms_y, "I",
"Sudden Motion Sensor Y value");
SYSCTL_ADD_PROC(sysctlctx,
SYSCTL_CHILDREN(sc->sc_sms_tree),
OID_AUTO, "z",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
- dev, 0, model->smc_sms_z, "I",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, 0, asmc_mb_sysctl_sms_z, "I",
"Sudden Motion Sensor Z value");
/*
@@ -757,33 +789,26 @@ asmc_attach(device_t dev)
* Allocate an IRQ for the SMS.
*/
sc->sc_rid_irq = 0;
- sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
- &sc->sc_rid_irq, RF_ACTIVE);
+ sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq,
+ RF_ACTIVE);
if (sc->sc_irq == NULL) {
device_printf(dev, "unable to allocate IRQ resource\n");
ret = ENXIO;
- goto err2;
+ goto err;
}
- ret = bus_setup_intr(dev, sc->sc_irq,
- INTR_TYPE_MISC | INTR_MPSAFE,
- asmc_sms_intrfast, NULL,
- dev, &sc->sc_cookie);
-
+ ret = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE,
+ asmc_sms_intrfast, NULL, dev, &sc->sc_cookie);
if (ret) {
device_printf(dev, "unable to setup SMS IRQ\n");
- goto err1;
+ goto err;
}
+
nosms:
return (0);
-err1:
- bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq);
-err2:
- bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
- sc->sc_ioport);
- mtx_destroy(&sc->sc_mtx);
- if (sc->sc_sms_tq)
- taskqueue_free(sc->sc_sms_tq);
+
+err:
+ asmc_detach(dev);
return (ret);
}
@@ -793,19 +818,46 @@ asmc_detach(device_t dev)
{
struct asmc_softc *sc = device_get_softc(dev);
+ if (sc->sc_kbd_bkl != NULL)
+ backlight_destroy(sc->sc_kbd_bkl);
+
+ /* Free temperature sensor key arrays */
+ for (int i = 0; i < sc->sc_temp_count; i++)
+ free(sc->sc_temp_sensors[i], M_DEVBUF);
+
+ /* Free sensor key arrays */
+ for (int i = 0; i < sc->sc_voltage_count; i++)
+ free(sc->sc_voltage_sensors[i], M_DEVBUF);
+ for (int i = 0; i < sc->sc_current_count; i++)
+ free(sc->sc_current_sensors[i], M_DEVBUF);
+ for (int i = 0; i < sc->sc_power_count; i++)
+ free(sc->sc_power_sensors[i], M_DEVBUF);
+ for (int i = 0; i < sc->sc_light_count; i++)
+ free(sc->sc_light_sensors[i], M_DEVBUF);
+
if (sc->sc_sms_tq) {
taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
taskqueue_free(sc->sc_sms_tq);
+ sc->sc_sms_tq = NULL;
}
- if (sc->sc_cookie)
+ if (sc->sc_cookie) {
bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
- if (sc->sc_irq)
+ sc->sc_cookie = NULL;
+ }
+ if (sc->sc_irq) {
bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
sc->sc_irq);
- if (sc->sc_ioport)
+ sc->sc_irq = NULL;
+ }
+ if (sc->sc_ioport) {
bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
sc->sc_ioport);
- mtx_destroy(&sc->sc_mtx);
+ sc->sc_ioport = NULL;
+ }
+ asmc_mmio_detach(dev, sc);
+ if (mtx_initialized(&sc->sc_mtx)) {
+ mtx_destroy(&sc->sc_mtx);
+ }
return (0);
}
@@ -813,33 +865,115 @@ asmc_detach(device_t dev)
static int
asmc_resume(device_t dev)
{
- uint8_t buf[2];
- buf[0] = light_control;
- buf[1] = 0x00;
- asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
- return (0);
+ uint8_t buf[2];
+
+ buf[0] = light_control;
+ buf[1] = 0x00;
+ asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
+
+ return (0);
}
-#ifdef DEBUG
-void asmc_dumpall(device_t dev)
+#ifdef ASMC_DEBUG
+void
+asmc_dumpall(device_t dev)
{
+ struct asmc_softc *sc = device_get_softc(dev);
int i;
- /* XXX magic number */
- for (i=0; i < 0x100; i++)
+ if (sc->sc_nkeys == 0) {
+ device_printf(dev, "asmc_dumpall: key count not available\n");
+ return;
+ }
+
+ device_printf(dev, "asmc_dumpall: dumping %d keys\n", sc->sc_nkeys);
+ for (i = 0; i < sc->sc_nkeys; i++)
asmc_key_dump(dev, i);
}
#endif
+/*
+ * Initialize SMC: read revision, key count, fan count.
+ * SMS initialization is handled separately in asmc_sms_init().
+ */
static int
asmc_init(device_t dev)
{
struct asmc_softc *sc = device_get_softc(dev);
- int i, error = 1;
- uint8_t buf[4];
+ struct sysctl_ctx_list *sysctlctx;
+ uint8_t buf[6];
+ int error;
- if (sc->sc_model->smc_sms_x == NULL)
- goto nosms;
+ sysctlctx = device_get_sysctl_ctx(dev);
+
+ error = asmc_key_read(dev, ASMC_KEY_REV, buf, 6);
+ if (error != 0) {
+ /*
+ * Could not read REV key; T2 Macs may not have it.
+ * Use #KEY as a liveness check instead.
+ */
+ if (sc->sc_is_t2) {
+ error = asmc_key_read(dev, ASMC_NKEYS, buf, 4);
+ if (error != 0)
+ goto out;
+ device_printf(dev, "T2 SMC: %d keys\n",
+ be32dec(buf));
+ } else {
+ goto out;
+ }
+ } else {
+ device_printf(dev, "SMC revision: %x.%x%x%x\n",
+ buf[0], buf[1], buf[2],
+ ntohs(*(uint16_t *)buf + 4));
+ }
+
+ /* Auto power-on after AC power loss (AUPO). */
+ if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) {
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "auto_poweron",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ dev, 0, asmc_aupo_sysctl, "I",
+ "Auto power-on after AC power loss (0=off, 1=on)");
+ }
+
+ sc->sc_nfan = asmc_fan_count(dev);
+ if (sc->sc_nfan > ASMC_MAXFANS) {
+ device_printf(dev,
+ "more than %d fans were detected. Please report this.\n",
+ ASMC_MAXFANS);
+ sc->sc_nfan = ASMC_MAXFANS;
+ }
+
+ /*
+ * Read and cache the number of SMC keys (32 bit buffer)
+ */
+ if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) {
+ sc->sc_nkeys = be32dec(buf);
+ if (bootverbose)
+ device_printf(dev, "number of keys: %d\n",
+ sc->sc_nkeys);
+ } else {
+ sc->sc_nkeys = 0;
+ }
+
+out:
+#ifdef ASMC_DEBUG
+ asmc_dumpall(dev);
+#endif
+ return (error);
+}
+
+/*
+ * Initialize the Sudden Motion Sensor hardware.
+ * Called from asmc_attach() after capabilities are detected.
+ */
+static void
+asmc_sms_init(device_t dev)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t buf[2];
+ int i;
/*
* We are ready to receive interrupts from the SMS.
@@ -892,9 +1026,8 @@ asmc_init(device_t dev)
for (i = 0; i < 1000; i++) {
if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
(buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) {
- error = 0;
sc->sc_sms_intr_works = 1;
- goto out;
+ goto done;
}
buf[0] = ASMC_SMS_INIT1;
buf[1] = ASMC_SMS_INIT2;
@@ -904,29 +1037,71 @@ asmc_init(device_t dev)
}
device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
-out:
+done:
asmc_sms_calibrate(dev);
-nosms:
- sc->sc_nfan = asmc_fan_count(dev);
- if (sc->sc_nfan > ASMC_MAXFANS) {
- device_printf(dev, "more than %d fans were detected. Please "
- "report this.\n", ASMC_MAXFANS);
- sc->sc_nfan = ASMC_MAXFANS;
- }
+}
- if (bootverbose) {
- /*
- * The number of keys is a 32 bit buffer
- */
- asmc_key_read(dev, ASMC_NKEYS, buf, 4);
- device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf));
+/*
+ * Probe SMC keys to detect hardware capabilities.
+ */
+static void
+asmc_detect_capabilities(device_t dev)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t len;
+ char type[ASMC_TYPELEN + 1];
+
+ /* SMS: require all keys used by asmc_sms_init() */
+ sc->sc_has_sms =
+ (asmc_key_getinfo(dev, ASMC_KEY_SMS,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_X,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_Y,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_Z,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW_INT,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH_INT,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_SMS_FLAG,
+ &len, type) == 0 &&
+ asmc_key_getinfo(dev, ASMC_KEY_INTOK,
+ &len, type) == 0);
+
+ /* Light sensor: require ALV0 (len 6 or 10) and LKSB */
+ if (asmc_key_getinfo(dev, ASMC_KEY_LIGHTLEFT,
+ &len, type) == 0 &&
+ (len == ASMC_LIGHT_SHORTLEN || len == ASMC_LIGHT_LONGLEN) &&
+ asmc_key_getinfo(dev, ASMC_KEY_LIGHTVALUE,
+ NULL, NULL) == 0) {
+ sc->sc_has_light = 1;
+ sc->sc_light_len = len;
+ } else {
+ sc->sc_has_light = 0;
+ sc->sc_light_len = 0;
}
-#ifdef DEBUG
- asmc_dumpall(dev);
-#endif
+ /* Fan safe speed */
+ sc->sc_has_safespeed =
+ (asmc_key_getinfo(dev, ASMC_KEY_FANSAFESPEED0,
+ &len, type) == 0);
- return (error);
+ /* Ambient light interrupt source */
+ sc->sc_has_alsl =
+ (asmc_key_getinfo(dev, ASMC_KEY_LIGHTSRC,
+ &len, type) == 0);
+
+ if (bootverbose)
+ device_printf(dev,
+ "capabilities: sms=%d light=%d (len=%d) safespeed=%d alsl=%d\n",
+ sc->sc_has_sms, sc->sc_has_light, sc->sc_light_len,
+ sc->sc_has_safespeed, sc->sc_has_alsl);
}
/*
@@ -957,21 +1132,18 @@ asmc_wait_ack(device_t dev, uint8_t val, int amount)
static int
asmc_wait(device_t dev, uint8_t val)
{
-#ifdef DEBUG
+#ifdef ASMC_DEBUG
struct asmc_softc *sc;
#endif
if (asmc_wait_ack(dev, val, 1000) == 0)
return (0);
-#ifdef DEBUG
+#ifdef ASMC_DEBUG
sc = device_get_softc(dev);
-#endif
- val = val & ASMC_STATUS_MASK;
-#ifdef DEBUG
- device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val,
- ASMC_CMDPORT_READ(sc));
+ device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__,
+ val & ASMC_STATUS_MASK, ASMC_CMDPORT_READ(sc));
#endif
return (1);
}
@@ -981,18 +1153,19 @@ asmc_wait(device_t dev, uint8_t val)
* the acknowledgement fails.
*/
static int
-asmc_command(device_t dev, uint8_t command) {
+asmc_command(device_t dev, uint8_t command)
+{
int i;
struct asmc_softc *sc = device_get_softc(dev);
- for (i=0; i < 10; i++) {
+ for (i = 0; i < 10; i++) {
ASMC_CMDPORT_WRITE(sc, command);
if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
return (0);
}
}
-#ifdef DEBUG
+#ifdef ASMC_DEBUG
device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
ASMC_CMDPORT_READ(sc));
#endif
@@ -1002,8 +1175,11 @@ asmc_command(device_t dev, uint8_t command) {
static int
asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
{
- int i, error = 1, try = 0;
struct asmc_softc *sc = device_get_softc(dev);
+ int i, error = 1, try = 0;
+
+ if (sc->sc_is_mmio)
+ return (asmc_mmio_key_read(dev, key, buf, len));
mtx_lock_spin(&sc->sc_mtx);
@@ -1028,9 +1204,10 @@ begin:
error = 0;
out:
if (error) {
- if (++try < 10) goto begin;
- device_printf(dev,"%s for key %s failed %d times, giving up\n",
- __func__, key, try);
+ if (++try < 10)
+ goto begin;
+ device_printf(dev, "%s for key %s failed %d times, giving up\n",
+ __func__, key, try);
}
mtx_unlock_spin(&sc->sc_mtx);
@@ -1038,57 +1215,78 @@ out:
return (error);
}
-#ifdef DEBUG
+#ifdef ASMC_DEBUG
static int
asmc_key_dump(device_t dev, int number)
{
struct asmc_softc *sc = device_get_softc(dev);
- char key[5] = { 0 };
- char type[7] = { 0 };
+ char key[ASMC_KEYLEN + 1] = { 0 };
+ char type[ASMC_KEYINFO_RESPLEN + 1] = { 0 };
uint8_t index[4];
- uint8_t v[32];
+ uint8_t v[ASMC_MAXVAL];
uint8_t maxlen;
int i, error = 1, try = 0;
+ if (sc->sc_is_mmio) {
+ uint8_t len = 0;
+ char mmio_type[ASMC_TYPELEN + 1] = { 0 };
+ if (asmc_key_dump_by_index(dev, number, key, mmio_type, &len))
+ return (1);
+ memset(v, 0, sizeof(v));
+ len = MIN(len, sizeof(v));
+ asmc_key_read(dev, key, v, len);
+ struct sbuf sb;
+ char buf[128];
+ sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
+ sbuf_printf(&sb, "key %d: %s, type %s (len %d), data",
+ number, key, mmio_type, len);
+ for (i = 0; i < len; i++)
+ sbuf_printf(&sb, " %02x", v[i]);
+ sbuf_finish(&sb);
+ device_printf(dev, "%s\n", sbuf_data(&sb));
+ sbuf_delete(&sb);
+ return (0);
+ }
+
mtx_lock_spin(&sc->sc_mtx);
index[0] = (number >> 24) & 0xff;
index[1] = (number >> 16) & 0xff;
index[2] = (number >> 8) & 0xff;
- index[3] = (number) & 0xff;
+ index[3] = number & 0xff;
begin:
- if (asmc_command(dev, 0x12))
+ if (asmc_command(dev, ASMC_CMDGETBYINDEX))
goto out;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ASMC_KEYLEN; i++) {
ASMC_DATAPORT_WRITE(sc, index[i]);
- if (asmc_wait(dev, 0x04))
+ if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
goto out;
}
- ASMC_DATAPORT_WRITE(sc, 4);
+ ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN);
- for (i = 0; i < 4; i++) {
- if (asmc_wait(dev, 0x05))
+ for (i = 0; i < ASMC_KEYLEN; i++) {
+ if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
goto out;
key[i] = ASMC_DATAPORT_READ(sc);
}
- /* get type */
- if (asmc_command(dev, 0x13))
+ /* Get key info (length + type). */
+ if (asmc_command(dev, ASMC_CMDGETINFO))
goto out;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ASMC_KEYLEN; i++) {
ASMC_DATAPORT_WRITE(sc, key[i]);
- if (asmc_wait(dev, 0x04))
+ if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
goto out;
}
- ASMC_DATAPORT_WRITE(sc, 6);
+ ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
- for (i = 0; i < 6; i++) {
- if (asmc_wait(dev, 0x05))
+ for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
+ if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
goto out;
type[i] = ASMC_DATAPORT_READ(sc);
}
@@ -1096,47 +1294,641 @@ begin:
error = 0;
out:
if (error) {
- if (++try < 10) goto begin;
- device_printf(dev,"%s for key %s failed %d times, giving up\n",
- __func__, key, try);
- mtx_unlock_spin(&sc->sc_mtx);
+ if (++try < ASMC_MAXRETRIES)
+ goto begin;
+ device_printf(dev,
+ "%s for key %d failed %d times, giving up\n",
+ __func__, number, try);
}
- else {
- char buf[1024];
- char buf2[8];
- mtx_unlock_spin(&sc->sc_mtx);
- maxlen = type[0];
- type[0] = ' ';
- type[5] = 0;
- if (maxlen > sizeof(v)) {
+ mtx_unlock_spin(&sc->sc_mtx);
+
+ if (error)
+ return (error);
+
+ maxlen = type[0];
+ type[0] = ' ';
+ type[5] = '\0';
+ maxlen = MIN(maxlen, sizeof(v));
+
+ memset(v, 0, sizeof(v));
+ error = asmc_key_read(dev, key, v, maxlen);
+ if (error)
+ return (error);
+
+ struct sbuf sb;
+ char buf[128];
+ sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
+ sbuf_printf(&sb, "key %d: %s, type%s (len %d), data",
+ number, key, type, maxlen);
+ for (i = 0; i < maxlen; i++)
+ sbuf_printf(&sb, " %02x", v[i]);
+ sbuf_finish(&sb);
+ device_printf(dev, "%s\n", sbuf_data(&sb));
+ sbuf_delete(&sb);
+
+ return (0);
+}
+#endif /* ASMC_DEBUG */
+
+/*
+ * Get key info (length and type) from SMC using command 0x13.
+ * If len is non-NULL, stores the key's value length.
+ * If type is non-NULL, stores the 4-char type string (must be at least 5 bytes).
+ */
+static int
+asmc_key_getinfo(device_t dev, const char *key, uint8_t *len, char *type)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t info[ASMC_KEYINFO_RESPLEN];
+ int i, error = -1, try = 0;
+
+ if (sc->sc_is_mmio)
+ return (asmc_mmio_key_getinfo(dev, key, len, type));
+
+ mtx_lock_spin(&sc->sc_mtx);
+
+begin:
+ if (asmc_command(dev, ASMC_CMDGETINFO))
+ goto out;
+
+ for (i = 0; i < ASMC_KEYLEN; i++) {
+ ASMC_DATAPORT_WRITE(sc, key[i]);
+ if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
+ goto out;
+ }
+
+ ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
+
+ for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
+ if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
+ goto out;
+ info[i] = ASMC_DATAPORT_READ(sc);
+ }
+
+ error = 0;
+out:
+ if (error && ++try < ASMC_MAXRETRIES)
+ goto begin;
+ mtx_unlock_spin(&sc->sc_mtx);
+
+ if (error == 0) {
+ if (len != NULL)
+ *len = info[0];
+ if (type != NULL) {
+ for (i = 0; i < ASMC_TYPELEN; i++)
+ type[i] = info[i + 1];
+ type[ASMC_TYPELEN] = '\0';
+ }
+ }
+ return (error);
+}
+
+#ifdef ASMC_DEBUG
+/*
+ * Raw SMC key access sysctls - enables reading/writing any SMC key by name
+ * Usage:
+ * sysctl dev.asmc.0.raw.key=TC0P # Set key, auto-detects length
+ * sysctl dev.asmc.0.raw.value # Read current value (hex bytes)
+ * sysctl dev.asmc.0.raw.value=01 # Write new value
+ */
+static int
+asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t) arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+ char newkey[ASMC_KEYLEN + 1];
+ uint8_t keylen;
+ int error;
+
+ strlcpy(newkey, sc->sc_rawkey, sizeof(newkey));
+ error = sysctl_handle_string(oidp, newkey, sizeof(newkey), req);
+ if (error || req->newptr == NULL)
+ return (error);
+
+ if (strlen(newkey) != ASMC_KEYLEN)
+ return (EINVAL);
+
+ /* Get key info to auto-detect length and type */
+ if (asmc_key_getinfo(dev, newkey, &keylen, sc->sc_rawtype) != 0)
+ return (ENOENT);
+
+ if (keylen > ASMC_MAXVAL)
+ keylen = ASMC_MAXVAL;
+
+ strlcpy(sc->sc_rawkey, newkey, sizeof(sc->sc_rawkey));
+ sc->sc_rawlen = keylen;
+ memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval));
+
+ /* Read the key value */
+ asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen);
+
+ return (0);
+}
+
+static int
+asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t) arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+ char hexbuf[ASMC_MAXVAL * 2 + 1];
+ int error, i;
+
+ /* Refresh from SMC if a key has been selected. */
+ if (sc->sc_rawkey[0] != '\0') {
+ asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval,
+ sc->sc_rawlen > 0 ? sc->sc_rawlen : ASMC_MAXVAL);
+ }
+
+ /* Format as hex string */
+ for (i = 0; i < sc->sc_rawlen && i < ASMC_MAXVAL; i++)
+ snprintf(hexbuf + i * 2, 3, "%02x", sc->sc_rawval[i]);
+ hexbuf[i * 2] = '\0';
+
+ error = sysctl_handle_string(oidp, hexbuf, sizeof(hexbuf), req);
+ if (error || req->newptr == NULL)
+ return (error);
+
+ /* Reject writes until a key is selected via raw.key. */
+ if (sc->sc_rawkey[0] == '\0')
+ return (EINVAL);
+
+ memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval));
+ for (i = 0; i < sc->sc_rawlen && hexbuf[i*2] && hexbuf[i*2+1]; i++) {
+ unsigned int val;
+ char tmp[3] = { hexbuf[i*2], hexbuf[i*2+1], 0 };
+ if (sscanf(tmp, "%02x", &val) == 1)
+ sc->sc_rawval[i] = (uint8_t)val;
+ }
+
+ if (asmc_key_write(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen) != 0)
+ return (EIO);
+
+ return (0);
+}
+
+static int
+asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t) arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+
+ return (sysctl_handle_8(oidp, &sc->sc_rawlen, 0, req));
+}
+
+static int
+asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t) arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+
+ return (sysctl_handle_string(oidp, sc->sc_rawtype,
+ sizeof(sc->sc_rawtype), req));
+}
+#endif
+
+/* SMC sensor type table: type string to fixed-point divisor. */
+static const struct {
+ const char type[5];
+ int divisor;
+} asmc_sensor_types[] = {
+ { "sp78", 256 },
+ { "sp87", 128 },
+ { "sp4b", 2048 },
+ { "sp5a", 1024 },
+ { "sp69", 512 },
+ { "sp96", 64 },
+ { "sp2d", 8192 },
+ { "ui16", 1 },
+ { "", 0 },
+};
+
+/* Convert a 2-byte SMC value to milli-units. */
+static bool
+asmc_sensor_convert(const char *type, const uint8_t *buf, int *millivalue)
+{
+ int i;
+
+ for (i = 0; asmc_sensor_types[i].divisor != 0; i++) {
+ if (strncmp(type, asmc_sensor_types[i].type, 4) != 0)
+ continue;
+ if (asmc_sensor_types[i].divisor == 1)
+ *millivalue = be16dec(buf);
+ else
+ *millivalue = ((int)(int16_t)be16dec(buf) * 1000) /
+ asmc_sensor_types[i].divisor;
+ return (true);
+ }
+ return (false);
+}
+
+static bool
+asmc_sensor_type_supported(const char *type)
+{
+ int i;
+
+ for (i = 0; asmc_sensor_types[i].divisor != 0; i++)
+ if (strncmp(type, asmc_sensor_types[i].type, 4) == 0)
+ return (true);
+ return (false);
+}
+
+/*
+ * Generic sensor value reader with automatic type conversion.
+ * Reads an SMC key, detects its type, and converts to millivalue.
+ */
+static int
+asmc_sensor_read(device_t dev, const char *key, int *millivalue)
+{
+ uint8_t buf[2];
+ char type[ASMC_TYPELEN + 1];
+ uint8_t len;
+ int error;
+
+ error = asmc_key_getinfo(dev, key, &len, type);
+ if (error != 0)
+ return (error);
+
+ if (len != 2) {
+ if (bootverbose)
device_printf(dev,
- "WARNING: cropping maxlen from %d to %zu\n",
- maxlen, sizeof(v));
- maxlen = sizeof(v);
+ "%s: key %s unexpected length %d\n",
+ __func__, key, len);
+ return (ENXIO);
+ }
+
+ error = asmc_key_read(dev, key, buf, sizeof(buf));
+ if (error != 0)
+ return (error);
+
+ if (!asmc_sensor_convert(type, buf, millivalue)) {
+ if (bootverbose)
+ device_printf(dev,
+ "%s: unknown type '%s' for key %s\n",
+ __func__, type, key);
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+/*
+ * Generic sensor sysctl handler for voltage/current/power/light sensors.
+ * arg2 encodes: sensor_type (high byte) | sensor_index (low byte)
+ * Sensor types: 'V'=voltage, 'I'=current, 'P'=power, 'L'=light
+ */
+static int
+asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t) arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+ int error, val;
+ int sensor_type = (arg2 >> 8) & 0xFF;
+ int sensor_idx = arg2 & 0xFF;
+ const char *key = NULL;
+
+ /* Select sensor based on type and index */
+ switch (sensor_type) {
+ case 'V': /* Voltage */
+ if (sensor_idx < sc->sc_voltage_count)
+ key = sc->sc_voltage_sensors[sensor_idx];
+ break;
+ case 'I': /* Current */
+ if (sensor_idx < sc->sc_current_count)
+ key = sc->sc_current_sensors[sensor_idx];
+ break;
+ case 'P': /* Power */
+ if (sensor_idx < sc->sc_power_count)
+ key = sc->sc_power_sensors[sensor_idx];
+ break;
+ case 'L': /* Light */
+ if (sensor_idx < sc->sc_light_count)
+ key = sc->sc_light_sensors[sensor_idx];
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (key == NULL)
+ return (ENOENT);
+
+ error = asmc_sensor_read(dev, key, &val);
+ if (error != 0)
+ return (error);
+
+ return (sysctl_handle_int(oidp, &val, 0, req));
+}
+
+/*
+ * Scan a range of SMC key indices, adding matching sensors.
+ * Only considers 2-byte keys with a supported type.
+ */
+static void
+asmc_scan_sensor_range(device_t dev, unsigned int start,
+ unsigned int end, char prefix, int *countp, char **sensors,
+ int maxcount)
+{
+ char key[ASMC_KEYLEN + 1];
+ char type[ASMC_TYPELEN + 1];
+ uint8_t len;
+ unsigned int i;
+ char *sensor_key;
+
+ for (i = start; i < end; i++) {
+ if (asmc_key_dump_by_index(dev, i, key, type, &len))
+ continue;
+ if (key[0] != prefix || len != 2)
+ continue;
+ if (!asmc_sensor_type_supported(type))
+ continue;
+ if (*countp >= maxcount)
+ break;
+ sensor_key = malloc(ASMC_KEYLEN + 1,
+ M_DEVBUF, M_WAITOK);
+ memcpy(sensor_key, key, ASMC_KEYLEN + 1);
+ sensors[(*countp)++] = sensor_key;
+ }
+}
+
+static int
+asmc_detect_sensors(device_t dev)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ struct sysctl_ctx_list *sysctlctx;
+ struct sysctl_oid *tree_node;
+ char key[ASMC_KEYLEN + 1];
+ char type[ASMC_TYPELEN + 1];
+ uint8_t len;
+ unsigned int start, end, i;
+ int error;
+ char *sensor_key;
+
+ sc->sc_voltage_count = 0;
+ sc->sc_current_count = 0;
+ sc->sc_power_count = 0;
+ sc->sc_light_count = 0;
+ sc->sc_temp_count = 0;
+
+ if (sc->sc_nkeys == 0)
+ return (0);
+
+ /*
+ * Temperature sensors: binary search for T..U range,
+ * then filter by type sp78.
+ */
+ error = asmc_key_search(dev, "T\0\0\0", &start);
+ if (error == 0)
+ error = asmc_key_search(dev, "U\0\0\0", &end);
+ if (error == 0) {
+ for (i = start; i < end; i++) {
+ if (asmc_key_dump_by_index(dev, i,
+ key, type, &len))
+ continue;
+ if (len != 2 ||
+ strncmp(type, "sp78", 4) != 0)
+ continue;
+ if (sc->sc_temp_count >= ASMC_TEMP_MAX)
+ break;
+ sensor_key = malloc(ASMC_KEYLEN + 1,
+ M_DEVBUF, M_WAITOK);
+ memcpy(sensor_key, key, ASMC_KEYLEN + 1);
+ sc->sc_temp_sensors[sc->sc_temp_count++] =
+ sensor_key;
}
- for (i = 0; i < sizeof(v); i++) {
- v[i] = 0;
+ }
+
+ /* Voltage/Current/Power sensors */
+ static const struct {
+ const char *range_start;
+ const char *range_end;
+ char prefix;
+ } sensor_ranges[] = {
+ { "V\0\0\0", "W\0\0\0", 'V' }, /* Voltage */
+ { "I\0\0\0", "J\0\0\0", 'I' }, /* Current */
+ { "P\0\0\0", "Q\0\0\0", 'P' }, /* Power */
+ };
+ static const size_t nsensor_ranges = nitems(sensor_ranges);
+
+ int *sensor_counts[] = {
+ &sc->sc_voltage_count, &sc->sc_current_count,
+ &sc->sc_power_count };
+ char **sensor_arrays[] = {
+ sc->sc_voltage_sensors, sc->sc_current_sensors,
+ sc->sc_power_sensors };
+
+ for (unsigned int r = 0; r < nsensor_ranges; r++) {
+ error = asmc_key_search(dev, sensor_ranges[r].range_start,
+ &start);
+ if (error == 0)
+ error = asmc_key_search(dev,
+ sensor_ranges[r].range_end, &end);
+ if (error == 0)
+ asmc_scan_sensor_range(dev, start, end,
+ sensor_ranges[r].prefix, sensor_counts[r],
+ sensor_arrays[r], ASMC_MAX_SENSORS);
+ }
+
+ /* Ambient light sensors: AL* in A..B range */
+ error = asmc_key_search(dev, "A\0\0\0", &start);
+ if (error == 0)
+ error = asmc_key_search(dev, "B\0\0\0", &end);
+ if (error == 0) {
+ for (i = start; i < end; i++) {
+ if (asmc_key_dump_by_index(dev, i,
+ key, type, &len))
+ continue;
+ if (key[0] != 'A' || key[1] != 'L' ||
+ (key[2] != 'V' && key[2] != 'S') ||
+ len != 2)
+ continue;
+ if (!asmc_sensor_type_supported(type))
+ continue;
+ if (sc->sc_light_count >= ASMC_MAX_SENSORS)
+ break;
+ sensor_key = malloc(ASMC_KEYLEN + 1,
+ M_DEVBUF, M_WAITOK);
+ memcpy(sensor_key, key, ASMC_KEYLEN + 1);
+ sc->sc_light_sensors[sc->sc_light_count++] =
+ sensor_key;
}
- asmc_key_read(dev, key, v, maxlen);
- snprintf(buf, sizeof(buf), "key %d is: %s, type %s "
- "(len %d), data", number, key, type, maxlen);
- for (i = 0; i < maxlen; i++) {
- snprintf(buf2, sizeof(buf2), " %02x", v[i]);
- strlcat(buf, buf2, sizeof(buf));
+ }
+
+ if (bootverbose)
+ device_printf(dev,
+ "detected %d temp, %d voltage, %d current, "
+ "%d power, %d light sensors\n",
+ sc->sc_temp_count, sc->sc_voltage_count,
+ sc->sc_current_count,
+ sc->sc_power_count, sc->sc_light_count);
+
+ /* Register sysctls for detected sensors */
+ sysctlctx = device_get_sysctl_ctx(dev);
+
+ static const struct {
+ const char *node_name;
+ const char *node_desc;
+ char tag;
+ const char *leaf_desc;
+ } sensor_sysctl[] = {
+ { "voltage", "Voltage sensors (millivolts)", 'V',
+ "Voltage sensor (millivolts)" },
+ { "current", "Current sensors (milliamps)", 'I',
+ "Current sensor (milliamps)" },
+ { "power", "Power sensors (milliwatts)", 'P',
+ "Power sensor (milliwatts)" },
+ { "ambient", "Ambient light sensors", 'L',
+ "Light sensor value" },
+ };
+
+ int *sysctl_counts[] = {
+ &sc->sc_voltage_count, &sc->sc_current_count,
+ &sc->sc_power_count, &sc->sc_light_count };
+ char **sysctl_arrays[] = {
+ sc->sc_voltage_sensors, sc->sc_current_sensors,
+ sc->sc_power_sensors, sc->sc_light_sensors };
+
+ for (unsigned int s = 0; s < nitems(sensor_sysctl); s++) {
+ int count = *sysctl_counts[s];
+ if (count <= 0)
+ continue;
+ tree_node = SYSCTL_ADD_NODE(sysctlctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ sensor_sysctl[s].node_name,
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ sensor_sysctl[s].node_desc);
+ for (i = 0; i < count; i++) {
+ SYSCTL_ADD_PROC(sysctlctx,
+ SYSCTL_CHILDREN(tree_node),
+ OID_AUTO, sysctl_arrays[s][i],
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, (sensor_sysctl[s].tag << 8) | i,
+ asmc_sensor_sysctl, "I",
+ sensor_sysctl[s].leaf_desc);
}
- strlcat(buf, " \n", sizeof(buf));
- device_printf(dev, "%s", buf);
}
+ return (0);
+}
+
+/*
+ * Helper function to get key info by index (for sensor detection).
+ */
+static int
+asmc_key_dump_by_index(device_t dev, int index, char *key_out,
+ char *type_out, uint8_t *len_out)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t index_buf[ASMC_KEYLEN];
+ uint8_t key_buf[ASMC_KEYLEN];
+ uint8_t info_buf[ASMC_KEYINFO_RESPLEN];
+ int error = ENXIO, try = 0;
+ int i;
+
+ if (sc->sc_is_mmio) {
+ error = asmc_mmio_key_getbyindex(dev, index, key_out);
+ if (error != 0)
+ return (error);
+ return (asmc_mmio_key_getinfo(dev, key_out, len_out,
+ type_out));
+ }
+
+ mtx_lock_spin(&sc->sc_mtx);
+
+ index_buf[0] = (index >> 24) & 0xff;
+ index_buf[1] = (index >> 16) & 0xff;
+ index_buf[2] = (index >> 8) & 0xff;
+ index_buf[3] = index & 0xff;
+
+begin:
+ if (asmc_command(dev, ASMC_CMDGETBYINDEX))
+ goto out;
+
+ for (i = 0; i < ASMC_KEYLEN; i++) {
+ ASMC_DATAPORT_WRITE(sc, index_buf[i]);
+ if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
+ goto out;
+ }
+
+ ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN);
+
+ for (i = 0; i < ASMC_KEYLEN; i++) {
+ if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
+ goto out;
+ key_buf[i] = ASMC_DATAPORT_READ(sc);
+ }
+
+ if (asmc_command(dev, ASMC_CMDGETINFO))
+ goto out;
+
+ for (i = 0; i < ASMC_KEYLEN; i++) {
+ ASMC_DATAPORT_WRITE(sc, key_buf[i]);
+ if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
+ goto out;
+ }
+
+ ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
+
+ for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
+ if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
+ goto out;
+ info_buf[i] = ASMC_DATAPORT_READ(sc);
+ }
+
+ memcpy(key_out, key_buf, ASMC_KEYLEN);
+ key_out[ASMC_KEYLEN] = '\0';
+ *len_out = info_buf[0];
+ memcpy(type_out, &info_buf[1], ASMC_TYPELEN);
+ type_out[ASMC_TYPELEN] = '\0';
+ error = 0;
+
+out:
+ if (error) {
+ if (++try < ASMC_MAXRETRIES)
+ goto begin;
+ }
+
+ mtx_unlock_spin(&sc->sc_mtx);
return (error);
}
-#endif
+
+/*
+ * Binary search for the first key index >= prefix.
+ * SMC keys are sorted, so this finds the lower bound efficiently.
+ */
+static int
+asmc_key_search(device_t dev, const char *prefix, unsigned int *idx)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ unsigned int lo, hi, mid;
+ char key[ASMC_KEYLEN + 1];
+ char type[ASMC_TYPELEN + 1];
+ uint8_t len;
+ int error;
+
+ lo = 0;
+ hi = sc->sc_nkeys;
+ while (lo < hi) {
+ mid = lo + (hi - lo) / 2;
+ error = asmc_key_dump_by_index(dev, mid,
+ key, type, &len);
+ if (error != 0)
+ return (error);
+ if (strncmp(key, prefix, ASMC_KEYLEN) < 0)
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
+ *idx = lo;
+ return (0);
+}
static int
asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
{
- int i, error = -1, try = 0;
struct asmc_softc *sc = device_get_softc(dev);
+ int i, error = -1, try = 0;
+
+ if (sc->sc_is_mmio)
+ return (asmc_mmio_key_write(dev, key, buf, len));
mtx_lock_spin(&sc->sc_mtx);
@@ -1164,15 +1956,15 @@ begin:
error = 0;
out:
if (error) {
- if (++try < 10) goto begin;
- device_printf(dev,"%s for key %s failed %d times, giving up\n",
- __func__, key, try);
+ if (++try < 10)
+ goto begin;
+ device_printf(dev, "%s for key %s failed %d times, giving up\n",
+ __func__, key, try);
}
mtx_unlock_spin(&sc->sc_mtx);
return (error);
-
}
/*
@@ -1183,7 +1975,7 @@ asmc_fan_count(device_t dev)
{
uint8_t buf[1];
- if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) != 0)
+ if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof(buf)) != 0)
return (-1);
return (buf[0]);
@@ -1192,28 +1984,45 @@ asmc_fan_count(device_t dev)
static int
asmc_fan_getvalue(device_t dev, const char *key, int fan)
{
+ struct asmc_softc *sc = device_get_softc(dev);
int speed;
- uint8_t buf[2];
+ uint8_t buf[4];
char fankey[5];
+ char type[ASMC_TYPELEN + 1];
snprintf(fankey, sizeof(fankey), key, fan);
- if (asmc_key_read(dev, fankey, buf, sizeof buf) != 0)
- return (-1);
- speed = (buf[0] << 6) | (buf[1] >> 2);
+
+ /*
+ * T2 Macs use IEEE 754 float ("flt ") for fan speeds,
+ * stored little-endian in the MMIO data register.
+ * Standard Macs use s14.2 fixed-point ("fpe2", 2 bytes).
+ */
+ if (sc->sc_is_t2 &&
+ asmc_key_getinfo(dev, fankey, NULL, type) == 0 &&
+ strncmp(type, "flt ", 4) == 0) {
+ if (asmc_key_read(dev, fankey, buf, 4) != 0)
+ return (-1);
+ speed = (int)asmc_float_to_u32(le32dec(buf));
+ } else {
+ if (asmc_key_read(dev, fankey, buf, 2) != 0)
+ return (-1);
+ speed = (buf[0] << 6) | (buf[1] >> 2);
+ }
return (speed);
}
-static char*
-asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen)
+static char *
+asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf,
+ uint8_t buflen)
{
char fankey[5];
- char* desc;
+ char *desc;
snprintf(fankey, sizeof(fankey), key, fan);
if (asmc_key_read(dev, fankey, buf, buflen) != 0)
return (NULL);
- desc = buf+4;
+ desc = buf + 4;
return (desc);
}
@@ -1221,17 +2030,30 @@ asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t
static int
asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
{
- uint8_t buf[2];
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t buf[4];
char fankey[5];
-
- speed *= 4;
-
- buf[0] = speed>>8;
- buf[1] = speed;
+ char type[ASMC_TYPELEN + 1];
snprintf(fankey, sizeof(fankey), key, fan);
- if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0)
- return (-1);
+
+ if (sc->sc_is_t2 &&
+ asmc_key_getinfo(dev, fankey, NULL, type) == 0 &&
+ strncmp(type, "flt ", 4) == 0) {
+ uint32_t fval;
+ speed = MAX(speed, 0);
+ speed = MIN(speed, 65535);
+ fval = asmc_u32_to_float((uint32_t)speed);
+ le32enc(buf, fval);
+ if (asmc_key_write(dev, fankey, buf, 4) != 0)
+ return (-1);
+ } else {
+ speed *= 4;
+ buf[0] = speed >> 8;
+ buf[1] = speed;
+ if (asmc_key_write(dev, fankey, buf, 2) != 0)
+ return (-1);
+ }
return (0);
}
@@ -1239,7 +2061,7 @@ asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
static int
asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int fan = arg2;
int error;
int32_t v;
@@ -1254,10 +2076,10 @@ static int
asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
{
uint8_t buf[16];
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int fan = arg2;
int error = true;
- char* desc;
+ char *desc;
desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
@@ -1270,7 +2092,7 @@ asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
static int
asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int fan = arg2;
int error;
int32_t v;
@@ -1284,7 +2106,7 @@ asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
static int
asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int fan = arg2;
int error;
int32_t v;
@@ -1303,7 +2125,7 @@ asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
static int
asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int fan = arg2;
int error;
int32_t v;
@@ -1322,7 +2144,7 @@ asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
static int
asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int fan = arg2;
int error;
int32_t v;
@@ -1338,6 +2160,79 @@ asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
return (error);
}
+static int
+asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+ int fan = arg2;
+ int error;
+ int32_t v;
+ uint8_t buf[2];
+ uint16_t val;
+ char fmkey[5];
+
+ /*
+ * T2 Macs use per-fan F%dMd keys (1 byte each).
+ * Standard Macs use FS! bitmask (2 bytes).
+ */
+ snprintf(fmkey, sizeof(fmkey), ASMC_KEY_FANMANUAL_T2, fan);
+ if (sc->sc_is_t2 &&
+ asmc_key_getinfo(dev, fmkey, NULL, NULL) == 0) {
+ error = asmc_key_read(dev, fmkey, buf, 1);
+ if (error != 0)
+ return (error);
+ v = buf[0] ? 1 : 0;
+
+ error = sysctl_handle_int(oidp, &v, 0, req);
+ if (error == 0 && req->newptr != NULL) {
+ if (v != 0 && v != 1)
+ return (EINVAL);
+ buf[0] = (uint8_t)v;
+ error = asmc_key_write(dev, fmkey, buf, 1);
+ }
+ return (error);
+ }
+
+ /* Read current FS! bitmask (asmc_key_read locks internally) */
+ error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf));
+ if (error != 0)
+ return (error);
+
+ /* Extract manual bit for this fan (big-endian) */
+ val = (buf[0] << 8) | buf[1];
+ v = (val >> fan) & 0x01;
+
+ /* Let sysctl handle the value */
+ error = sysctl_handle_int(oidp, &v, 0, req);
+
+ if (error == 0 && req->newptr != NULL) {
+ /* Validate input (0 = auto, 1 = manual) */
+ if (v != 0 && v != 1)
+ return (EINVAL);
+ /* Read-modify-write of FS! bitmask */
+ error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf,
+ sizeof(buf));
+ if (error == 0) {
+ val = (buf[0] << 8) | buf[1];
+
+ /* Modify single bit */
+ if (v)
+ val |= (1 << fan); /* Set to manual */
+ else
+ val &= ~(1 << fan); /* Set to auto */
+
+ /* Write back */
+ buf[0] = val >> 8;
+ buf[1] = val & 0xff;
+ error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf,
+ sizeof(buf));
+ }
+ }
+
+ return (error);
+}
+
/*
* Temperature functions.
*/
@@ -1349,7 +2244,7 @@ asmc_temp_getvalue(device_t dev, const char *key)
/*
* Check for invalid temperatures.
*/
- if (asmc_key_read(dev, key, buf, sizeof buf) != 0)
+ if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0)
return (-1);
return (buf[0]);
@@ -1358,11 +2253,14 @@ asmc_temp_getvalue(device_t dev, const char *key)
static int
asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
struct asmc_softc *sc = device_get_softc(dev);
int error, val;
- val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]);
+ if (arg2 < 0 || arg2 >= sc->sc_temp_count)
+ return (EINVAL);
+
+ val = asmc_temp_getvalue(dev, sc->sc_temp_sensors[arg2]);
error = sysctl_handle_int(oidp, &val, 0, req);
return (error);
@@ -1382,12 +2280,12 @@ asmc_sms_read(device_t dev, const char *key, int16_t *val)
case 'X':
case 'Y':
case 'Z':
- error = asmc_key_read(dev, key, buf, sizeof buf);
+ error = asmc_key_read(dev, key, buf, sizeof(buf));
break;
default:
device_printf(dev, "%s called with invalid argument %s\n",
- __func__, key);
- error = 1;
+ __func__, key);
+ error = EINVAL;
goto out;
}
*val = ((int16_t)buf[0] << 8) | buf[1];
@@ -1409,7 +2307,7 @@ static int
asmc_sms_intrfast(void *arg)
{
uint8_t type;
- device_t dev = (device_t) arg;
+ device_t dev = (device_t)arg;
struct asmc_softc *sc = device_get_softc(dev);
if (!sc->sc_sms_intr_works)
return (FILTER_HANDLED);
@@ -1421,6 +2319,10 @@ asmc_sms_intrfast(void *arg)
sc->sc_sms_intrtype = type;
asmc_sms_printintr(dev, type);
+ /* Don't queue SMS task for ambient light interrupts */
+ if (type == ASMC_ALSL_INT2A && sc->sc_has_alsl)
+ return (FILTER_HANDLED);
+
taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
return (FILTER_HANDLED);
}
@@ -1443,10 +2345,9 @@ asmc_sms_printintr(device_t dev, uint8_t type)
case ASMC_ALSL_INT2A:
/*
* This suppresses console and log messages for the ambient
- * light sensor for models known to generate this interrupt.
+ * light sensor interrupt on models that have ALSL.
*/
- if (strcmp(sc->sc_model->smc_model, "MacBookPro5,5") == 0 ||
- strcmp(sc->sc_model->smc_model, "MacBookPro6,2") == 0)
+ if (sc->sc_has_alsl)
break;
/* FALLTHROUGH */
default:
@@ -1482,13 +2383,13 @@ asmc_sms_task(void *arg, int pending)
static int
asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int error;
int16_t val;
int32_t v;
asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
- v = (int32_t) val;
+ v = (int32_t)val;
error = sysctl_handle_int(oidp, &v, 0, req);
return (error);
@@ -1497,13 +2398,13 @@ asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
static int
asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int error;
int16_t val;
int32_t v;
asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
- v = (int32_t) val;
+ v = (int32_t)val;
error = sysctl_handle_int(oidp, &v, 0, req);
return (error);
@@ -1512,13 +2413,13 @@ asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
static int
asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
int error;
int16_t val;
int32_t v;
asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
- v = (int32_t) val;
+ v = (int32_t)val;
error = sysctl_handle_int(oidp, &v, 0, req);
return (error);
@@ -1527,12 +2428,12 @@ asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
static int
asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
uint8_t buf[6];
int error;
int32_t v;
- asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf);
+ asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
v = buf[2];
error = sysctl_handle_int(oidp, &v, 0, req);
@@ -1542,12 +2443,12 @@ asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
static int
asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
uint8_t buf[6];
int error;
int32_t v;
- asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf);
+ asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof(buf));
v = buf[2];
error = sysctl_handle_int(oidp, &v, 0, req);
@@ -1557,7 +2458,8 @@ asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
static int
asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
uint8_t buf[2];
int error;
int v;
@@ -1569,9 +2471,10 @@ asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
if (v < 0 || v > 255)
return (EINVAL);
light_control = v;
+ sc->sc_kbd_bkl_level = v * 100 / 255;
buf[0] = light_control;
buf[1] = 0x00;
- asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
+ asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
}
return (error);
}
@@ -1579,12 +2482,12 @@ asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
static int
asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
{
- device_t dev = (device_t) arg1;
+ device_t dev = (device_t)arg1;
uint8_t buf[10];
int error;
uint32_t v;
- asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf);
+ asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
/*
* This seems to be a 32 bit big endian value from buf[6] -> buf[9].
@@ -1605,3 +2508,192 @@ asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
return (error);
}
+
+/*
+ * Auto power-on after AC power loss (AUPO key).
+ * When non-zero the machine boots automatically when AC is restored
+ * after an unclean power loss. Useful for always-on servers / home labs.
+ */
+static int
+asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t aupo;
+ int val, error;
+
+ if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
+ return (EIO);
+
+ val = (aupo != 0) ? 1 : 0;
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ aupo = (val != 0) ? 1 : 0;
+ if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
+ return (EIO);
+
+ return (0);
+}
+
+static int
+asmc_backlight_update_status(device_t dev, struct backlight_props *props)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t buf[2];
+
+ sc->sc_kbd_bkl_level = props->brightness;
+ light_control = props->brightness * 255 / 100;
+ buf[0] = light_control;
+ buf[1] = 0x00;
+ asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
+
+ return (0);
+}
+
+static int
+asmc_backlight_get_status(device_t dev, struct backlight_props *props)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+
+ props->brightness = sc->sc_kbd_bkl_level;
+ props->nlevels = 0;
+
+ return (0);
+}
+
+static int
+asmc_backlight_get_info(device_t dev, struct backlight_info *info)
+{
+ info->type = BACKLIGHT_TYPE_KEYBOARD;
+ strlcpy(info->name, "Apple MacBook Keyboard", BACKLIGHTMAXNAMELENGTH);
+
+ return (0);
+}
+
+static const char *
+asmc_cause_str(int8_t cause, bool is_sleep)
+{
+ size_t i;
+
+ for (i = 0; i < nitems(asmc_cause_table); i++) {
+ if (asmc_cause_table[i].code != cause)
+ continue;
+ if (is_sleep && asmc_cause_table[i].sleep_desc != NULL)
+ return (asmc_cause_table[i].sleep_desc);
+ return (asmc_cause_table[i].desc);
+ }
+ return (NULL);
+}
+
+/* MSSD/MSSP: last shutdown/sleep cause. arg2: 0=shutdown, 1=sleep. */
+static int
+asmc_cause_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ bool is_sleep = (arg2 != 0);
+ const char *key = is_sleep ? ASMC_KEY_MSSP : ASMC_KEY_MSSD;
+ int8_t cause;
+ const char *desc;
+ char buf[ASMC_CAUSE_BUFLEN];
+
+ /* EIO: SMC I/O bus did not respond to key read. */
+ if (asmc_key_read(dev, key, (uint8_t *)&cause, 1) != 0)
+ return (EIO);
+
+ desc = asmc_cause_str(cause, is_sleep);
+ if (desc != NULL)
+ snprintf(buf, sizeof(buf), "%d (%s)", (int)cause, desc);
+ else
+ snprintf(buf, sizeof(buf), "%d", (int)cause);
+
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
+static int
+asmc_msal_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t msal;
+ char buf[80];
+
+ /* EIO: SMC I/O bus did not respond to key read. */
+ if (asmc_key_read(dev, ASMC_KEY_MSAL, &msal, 1) != 0)
+ return (EIO);
+
+ snprintf(buf, sizeof(buf),
+ "0x%02x (tss=%d therm_valid=%d calib_valid=%d prochot=%d plimits=%d)",
+ msal,
+ (msal & ASMC_MSAL_TSS) != 0,
+ (msal & ASMC_MSAL_THERM_VALID) != 0,
+ (msal & ASMC_MSAL_CALIB_VALID) != 0,
+ (msal & ASMC_MSAL_PROCHOT) != 0,
+ (msal & ASMC_MSAL_PLIMITS) != 0);
+
+ return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
+}
+
+static int
+asmc_clkt_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t buf[4];
+ uint32_t secs;
+
+ if (asmc_key_read(dev, ASMC_KEY_CLKT, buf, 4) != 0)
+ return (EIO);
+
+ secs = be32dec(buf);
+ return (sysctl_handle_32(oidp, &secs, 0, req));
+}
+
+static int
+asmc_msps_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t buf[2], len;
+ uint32_t state;
+
+ if (asmc_key_getinfo(dev, ASMC_KEY_MSPS, &len, NULL) != 0)
+ return (EIO);
+ if (len != 1 && len != 2)
+ return (EIO);
+
+ memset(buf, 0, sizeof(buf));
+ if (asmc_key_read(dev, ASMC_KEY_MSPS, buf, len) != 0)
+ return (EIO);
+
+ state = (len == 1) ? buf[0] : be16dec(buf);
+ return (sysctl_handle_32(oidp, &state, 0, req));
+}
+
+static int
+asmc_rplt_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t buf[ASMC_RPLT_MAXLEN + 1];
+ char name[ASMC_RPLT_MAXLEN + 1];
+
+ memset(buf, 0, sizeof(buf));
+ if (asmc_key_read(dev, ASMC_KEY_RPLT, buf, ASMC_RPLT_MAXLEN) != 0)
+ return (EIO);
+
+ memcpy(name, buf, ASMC_RPLT_MAXLEN);
+ name[ASMC_RPLT_MAXLEN] = '\0';
+
+ return (sysctl_handle_string(oidp, name, sizeof(name), req));
+}
+
+static int
+asmc_rgen_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t gen;
+ uint32_t val;
+
+ if (asmc_key_read(dev, ASMC_KEY_RGEN, &gen, 1) != 0)
+ return (EIO);
+
+ val = gen;
+ return (sysctl_handle_32(oidp, &val, 0, req));
+}
diff --git a/sys/dev/asmc/asmcmmio.c b/sys/dev/asmc/asmcmmio.c
new file mode 100644
index 000000000000..237e8ec4ed52
--- /dev/null
+++ b/sys/dev/asmc/asmcmmio.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * MMIO backend for Apple SMC (T2 and later Macs).
+ *
+ * T2 Macs expose the SMC via memory-mapped registers instead of I/O ports.
+ * Protocol: clear status, write key/cmd, poll for ready, read result.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+
+#include <dev/asmc/asmcvar.h>
+#include <dev/asmc/asmcmmio.h>
+
+/*
+ * Wait for MMIO status register bit 5 (ready) with exponential backoff.
+ * Caller must hold sc_mtx.
+ */
+static int
+asmc_mmio_wait(device_t dev)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ int i;
+ uint8_t status;
+ int delay_us = 10;
+
+ for (i = 0; i < ASMC_MMIO_MAX_WAIT; i++) {
+ status = bus_read_1(sc->sc_iomem, ASMC_MMIO_STATUS);
+ if (status & ASMC_MMIO_STATUS_READY)
+ return (0);
+ DELAY(delay_us);
+ if (delay_us < 3200)
+ delay_us *= 2;
+ }
+
+ return (ETIMEDOUT);
+}
+
+int
+asmc_mmio_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint32_t key_int;
+ int error, i;
+ uint8_t cmd_result, rlen;
+
+ if (len > ASMC_MAXVAL)
+ return (EINVAL);
+
+ mtx_lock_spin(&sc->sc_mtx);
+
+ /* Clear status if non-zero */
+ if (bus_read_1(sc->sc_iomem, ASMC_MMIO_STATUS))
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
+
+ /* Write key name as raw 4 bytes */
+ memcpy(&key_int, key, 4);
+ bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, key_int);
+
+ /* Write SMC ID (always 0) and command */
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDREAD);
+
+ /* Wait for ready */
+ error = asmc_mmio_wait(dev);
+ if (error != 0) {
+ uint8_t st = bus_read_1(sc->sc_iomem, ASMC_MMIO_STATUS);
+ uint8_t cm = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
+ mtx_unlock_spin(&sc->sc_mtx);
+ device_printf(dev,
+ "%s: timeout key %.4s status=0x%02x cmd=0x%02x\n",
+ __func__, key, st, cm);
+ return (error);
+ }
+
+ /* Check command result (0 = success, 0x84 = key not found) */
+ cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
+ if (cmd_result != 0) {
+ mtx_unlock_spin(&sc->sc_mtx);
+ device_printf(dev,
+ "%s: key %.4s cmd error 0x%02x\n",
+ __func__, key, cmd_result);
+ return (EIO);
+ }
+
+ /* Read data length and data bytes; zero-fill remainder */
+ rlen = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA_LEN);
+ rlen = MIN(rlen, len);
+ for (i = rlen; i < len; i++)
+ buf[i] = 0;
+ for (i = 0; i < rlen; i++)
+ buf[i] = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA + i);
+
+ mtx_unlock_spin(&sc->sc_mtx);
+ return (0);
+}
+
+int
+asmc_mmio_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint32_t key_int;
+ int error, i;
+ uint8_t cmd_result;
+
+ if (len > ASMC_MAXVAL)
+ return (EINVAL);
+
+ mtx_lock_spin(&sc->sc_mtx);
+
+ /* Clear status */
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
+
+ /* Write data bytes first */
+ for (i = 0; i < len; i++)
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_DATA + i, buf[i]);
+
+ /* Write key name as raw 4 bytes */
+ memcpy(&key_int, key, 4);
+ bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, key_int);
+
+ /* Write length, SMC ID, command */
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_DATA_LEN, len);
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDWRITE);
+
+ /* Wait for ready */
+ error = asmc_mmio_wait(dev);
+ if (error != 0) {
+ mtx_unlock_spin(&sc->sc_mtx);
+ device_printf(dev, "%s: timeout writing key %.4s\n",
+ __func__, key);
+ return (error);
+ }
+
+ cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
+ mtx_unlock_spin(&sc->sc_mtx);
+
+ return (cmd_result == 0 ? 0 : EIO);
+}
+
+int
+asmc_mmio_key_getinfo(device_t dev, const char *key, uint8_t *len, char *type)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint32_t key_int;
+ int error, i;
+ uint8_t cmd_result;
+
+ mtx_lock_spin(&sc->sc_mtx);
+
+ /* Clear status */
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
+
+ /* Write key name as raw 4 bytes */
+ memcpy(&key_int, key, 4);
+ bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, key_int);
+
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDGETINFO);
+
+ error = asmc_mmio_wait(dev);
+ if (error != 0) {
+ mtx_unlock_spin(&sc->sc_mtx);
+ return (error);
+ }
+
+ cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
+ if (cmd_result != 0) {
+ mtx_unlock_spin(&sc->sc_mtx);
+ return (EIO);
+ }
+
+ /*
+ * GETINFO response layout (MMIO):
+ * data[0..3] = type code (4 chars)
+ * data[4] = reserved
+ * data[5] = data length
+ * data[6] = flags/attributes
+ */
+ if (type != NULL) {
+ for (i = 0; i < ASMC_TYPELEN; i++)
+ type[i] = bus_read_1(sc->sc_iomem,
+ ASMC_MMIO_DATA + i);
+ type[ASMC_TYPELEN] = '\0';
+ }
+ if (len != NULL)
+ *len = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA + 5);
+
+ mtx_unlock_spin(&sc->sc_mtx);
+ return (0);
+}
+
+int
+asmc_mmio_key_getbyindex(device_t dev, int index, char *key)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint32_t idx_val;
+ int error, i;
+ uint8_t cmd_result;
+
+ mtx_lock_spin(&sc->sc_mtx);
+
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
+
+ /* Write index as big-endian 4 bytes to key name register */
+ idx_val = htobe32(index);
+ bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, idx_val);
+
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
+ bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDGETBYINDEX);
+
+ error = asmc_mmio_wait(dev);
+ if (error != 0) {
+ mtx_unlock_spin(&sc->sc_mtx);
+ return (error);
+ }
+
+ cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
+ if (cmd_result != 0) {
+ mtx_unlock_spin(&sc->sc_mtx);
+ return (EIO);
+ }
+
+ /* Result: 4-byte key name in DATA */
+ for (i = 0; i < ASMC_KEYLEN; i++)
+ key[i] = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA + i);
+ key[ASMC_KEYLEN] = '\0';
+
+ mtx_unlock_spin(&sc->sc_mtx);
+ return (0);
+}
+
+/*
+ * Validate MMIO and detect T2.
+ * Check that status register is accessible and LDKN firmware version >= 2.
+ */
+int
+asmc_mmio_probe(device_t dev)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ rman_res_t size;
+ uint8_t status, ldkn;
+ int error;
+
+ size = rman_get_size(sc->sc_iomem);
+ if (size < ASMC_MMIO_MIN_SIZE) {
+ device_printf(dev, "MMIO region too small (%jd < %d)\n",
+ (intmax_t)size, ASMC_MMIO_MIN_SIZE);
+ return (ENXIO);
+ }
+
+ /* Check status register isn't stuck at 0xFF */
+ status = bus_read_1(sc->sc_iomem, ASMC_MMIO_STATUS);
+ if (status == 0xFF) {
+ device_printf(dev, "MMIO status register reads 0xFF\n");
+ return (ENXIO);
+ }
+
+ /*
+ * We need the mutex initialized before calling mmio_key_read,
+ * but attach hasn't done it yet. Initialize early.
+ */
+ if (!mtx_initialized(&sc->sc_mtx))
+ mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
+
+ /* Read LDKN (firmware version) -- must be >= 2 for MMIO */
+ error = asmc_mmio_key_read(dev, ASMC_KEY_LDKN, &ldkn, 1);
+ if (error != 0) {
+ device_printf(dev, "MMIO: failed to read LDKN key\n");
+ return (ENXIO);
+ }
+
+ if (ldkn < 2) {
+ device_printf(dev, "MMIO: LDKN=%d (need >= 2)\n", ldkn);
+ return (ENXIO);
+ }
+
+ device_printf(dev, "MMIO: LDKN=%d, T2 SMC detected\n", ldkn);
+ sc->sc_is_t2 = 1;
+
+ return (0);
+}
+
+void
+asmc_mmio_detach(device_t dev, struct asmc_softc *sc)
+{
+
+ if (sc->sc_iomem != NULL) {
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid_mem,
+ sc->sc_iomem);
+ sc->sc_iomem = NULL;
+ }
+ sc->sc_is_mmio = false;
+ sc->sc_is_t2 = 0;
+}
+
+/*
+ * Convert IEEE 754 float (as u32) to unsigned integer.
+ * Kernel soft-float: extract integer part only.
+ * Used for T2 fan RPM values (always positive, reasonable range).
+ */
+uint32_t
+asmc_float_to_u32(uint32_t d)
+{
+ int32_t exp;
+ uint32_t fr;
+
+ /* Negative or zero */
+ if (d == 0 || (d >> 31) != 0)
+ return (0);
+
+ exp = (int32_t)((d >> 23) & 0xff) - 0x7f;
+ fr = d & 0x7fffff; /* 23-bit mantissa */
+
+ if (exp < 0)
+ return (0);
+ if (exp > 23) {
+ if (exp > 30)
+ return (0xffffffffu);
+ return ((1u << exp) | (fr << (exp - 23)));
+ }
+ /* Normal case: 0 <= exp <= 23 */
+ return ((1u << exp) + (fr >> (23 - exp)));
+}
+
+/*
+ * Convert unsigned integer to IEEE 754 float (as u32).
+ * Only handles values in fan RPM range (0-65535).
+ */
+uint32_t
+asmc_u32_to_float(uint32_t d)
+{
+ uint32_t dc, bc, exp;
+
+ if (d == 0)
+ return (0);
+
+ /* Find highest set bit position */
+ dc = d;
+ bc = 0;
+ while (dc >>= 1)
+ ++bc;
+
+ bc = MIN(bc, 30);
+
+ exp = 0x7f + bc;
+
+ /*
+ * Mantissa: strip the implicit leading 1-bit and place
+ * remaining bits into the 23-bit mantissa field.
+ */
+ if (bc >= 23)
+ return ((exp << 23) | ((d >> (bc - 23)) & 0x7fffff));
+ else
+ return ((exp << 23) | ((d << (23 - bc)) & 0x7fffff));
+}
+
+/*
+ * Battery charge limit sysctl (T2 Macs).
+ * BCLM key: 1 byte, 0-100 (percentage).
+ */
+int
+asmc_bclm_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t bclm;
+ int val, error;
+
+ error = asmc_mmio_key_read(dev, ASMC_KEY_BCLM, &bclm, 1);
+ if (error != 0)
+ return (EIO);
+
+ val = (int)bclm;
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ if (val < 0 || val > 100)
+ return (EINVAL);
+
+ bclm = (uint8_t)val;
+ error = asmc_mmio_key_write(dev, ASMC_KEY_BCLM, &bclm, 1);
+
+ return (error != 0 ? EIO : 0);
+}
diff --git a/sys/dev/asmc/asmcmmio.h b/sys/dev/asmc/asmcmmio.h
new file mode 100644
index 000000000000..51e81707ece1
--- /dev/null
+++ b/sys/dev/asmc/asmcmmio.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _DEV_ASMC_ASMCMMIO_H_
+#define _DEV_ASMC_ASMCMMIO_H_
+
+struct asmc_softc;
+
+/*
+ * MMIO register offsets.
+ */
+#define ASMC_MMIO_DATA 0x0000
+#define ASMC_MMIO_KEY_NAME 0x0078
+#define ASMC_MMIO_DATA_LEN 0x007D
+#define ASMC_MMIO_SMC_ID 0x007E
+#define ASMC_MMIO_CMD 0x007F
+#define ASMC_MMIO_STATUS 0x4005
+#define ASMC_MMIO_MIN_SIZE 0x4006
+#define ASMC_MMIO_STATUS_READY 0x20 /* Bit 5 */
+#define ASMC_MMIO_MAX_WAIT 24
+
+/*
+ * T2-specific keys.
+ */
+#define ASMC_KEY_LDKN "LDKN" /* RO; 1 byte, firmware version */
+#define ASMC_KEY_BCLM "BCLM" /* RW; 1 byte, battery charge limit 0-100 */
+#define ASMC_KEY_FANMANUAL_T2 "F%dMd" /* RW; 1 byte per fan (T2) */
+
+/*
+ * MMIO backend functions.
+ */
+int asmc_mmio_probe(device_t dev);
+void asmc_mmio_detach(device_t dev, struct asmc_softc *sc);
+int asmc_mmio_key_read(device_t dev, const char *key,
+ uint8_t *buf, uint8_t len);
+int asmc_mmio_key_write(device_t dev, const char *key,
+ uint8_t *buf, uint8_t len);
+int asmc_mmio_key_getinfo(device_t dev, const char *key,
+ uint8_t *len, char *type);
+int asmc_mmio_key_getbyindex(device_t dev, int index, char *key);
+
+/*
+ * IEEE 754 float <-> uint32 conversion for T2 fan RPM values.
+ */
+uint32_t asmc_float_to_u32(uint32_t d);
+uint32_t asmc_u32_to_float(uint32_t d);
+
+/*
+ * T2-specific sysctls.
+ */
+int asmc_bclm_sysctl(SYSCTL_HANDLER_ARGS);
+
+#endif /* _DEV_ASMC_ASMCMMIO_H_ */
diff --git a/sys/dev/asmc/asmcvar.h b/sys/dev/asmc/asmcvar.h
index d40dc1e7c8ff..940119e59774 100644
--- a/sys/dev/asmc/asmcvar.h
+++ b/sys/dev/asmc/asmcvar.h
@@ -28,11 +28,19 @@
*/
#define ASMC_MAXFANS 6
+#define ASMC_MAXVAL 32 /* Maximum SMC value size */
+#define ASMC_KEYLEN 4 /* SMC key name length */
+#define ASMC_TYPELEN 4 /* SMC type string length */
+#define ASMC_MAX_SENSORS 64 /* Max sensors per type */
+
+/* Maximum number of auto-detected temperature sensors */
+#define ASMC_TEMP_MAX 80
struct asmc_softc {
device_t sc_dev;
struct mtx sc_mtx;
int sc_nfan;
+ int sc_nkeys;
int16_t sms_rest_x;
int16_t sms_rest_y;
int16_t sms_rest_z;
@@ -40,16 +48,48 @@ struct asmc_softc {
struct sysctl_oid *sc_temp_tree;
struct sysctl_oid *sc_sms_tree;
struct sysctl_oid *sc_light_tree;
- const struct asmc_model *sc_model;
int sc_rid_port;
int sc_rid_irq;
struct resource *sc_ioport;
struct resource *sc_irq;
void *sc_cookie;
+ /* MMIO backend (T2 Macs) */
+ int sc_rid_mem;
+ struct resource *sc_iomem;
+ bool sc_is_mmio;
+ int sc_is_t2; /* T2 fan float + per-fan manual */
int sc_sms_intrtype;
struct taskqueue *sc_sms_tq;
struct task sc_sms_task;
uint8_t sc_sms_intr_works;
+ struct cdev *sc_kbd_bkl;
+ uint32_t sc_kbd_bkl_level;
+#ifdef ASMC_DEBUG
+ /* Raw key access */
+ struct sysctl_oid *sc_raw_tree;
+ char sc_rawkey[ASMC_KEYLEN + 1];
+ uint8_t sc_rawval[ASMC_MAXVAL];
+ uint8_t sc_rawlen;
+ char sc_rawtype[ASMC_TYPELEN + 1];
+#endif
+ /* Voltage/Current/Power/Light sensors */
+ char *sc_voltage_sensors[ASMC_MAX_SENSORS];
+ int sc_voltage_count;
+ char *sc_current_sensors[ASMC_MAX_SENSORS];
+ int sc_current_count;
+ char *sc_power_sensors[ASMC_MAX_SENSORS];
+ int sc_power_count;
+ char *sc_light_sensors[ASMC_MAX_SENSORS];
+ int sc_light_count;
+ /* Auto-detected temperature sensors */
+ char *sc_temp_sensors[ASMC_TEMP_MAX];
+ int sc_temp_count;
+ /* Auto-detected capabilities */
+ int sc_has_sms;
+ int sc_has_light;
+ int sc_light_len; /* ASMC_LIGHT_{SHORT,LONG}LEN */
+ int sc_has_safespeed;
+ int sc_has_alsl; /* ALSL interrupt source */
};
/*
@@ -68,6 +108,14 @@ struct asmc_softc {
bus_write_1(sc->sc_ioport, 0x04, val)
#define ASMC_CMDREAD 0x10
#define ASMC_CMDWRITE 0x11
+#define ASMC_CMDGETBYINDEX 0x12
+#define ASMC_CMDGETINFO 0x13
+
+#define ASMC_STATUS_AWAIT_DATA 0x04
+#define ASMC_STATUS_DATA_READY 0x05
+
+#define ASMC_KEYINFO_RESPLEN 6 /* getinfo: 1 len + 4 type + 1 attr */
+#define ASMC_MAXRETRIES 10
/*
* Interrupt port.
@@ -77,6 +125,9 @@ struct asmc_softc {
/* Number of keys */
#define ASMC_NKEYS "#KEY" /* RO; 4 bytes */
+/* Query the ASMC revision */
+#define ASMC_KEY_REV "REV " /* RO: 6 bytes */
+
/*
* Fan control via SMC.
*/
@@ -84,7 +135,7 @@ struct asmc_softc {
#define ASMC_KEY_FANMANUAL "FS! " /* RW; 2 bytes */
#define ASMC_KEY_FANID "F%dID" /* RO; 16 bytes */
#define ASMC_KEY_FANSPEED "F%dAc" /* RO; 2 bytes */
-#define ASMC_KEY_FANMINSPEED "F%dMn" /* RO; 2 bytes */
+#define ASMC_KEY_FANMINSPEED "F%dMn" /* RW; 2 bytes */
#define ASMC_KEY_FANMAXSPEED "F%dMx" /* RO; 2 bytes */
#define ASMC_KEY_FANSAFESPEED "F%dSf" /* RO; 2 bytes */
#define ASMC_KEY_FANTARGETSPEED "F%dTg" /* RW; 2 bytes */
@@ -115,9 +166,13 @@ struct asmc_softc {
/*
* Keyboard backlight.
*/
-#define ASMC_KEY_LIGHTLEFT "ALV0" /* RO; 6 bytes */
+#define ASMC_LIGHT_SHORTLEN 6 /* ALV0 short format */
+#define ASMC_LIGHT_LONGLEN 10 /* ALV0 long format (10-byte) */
+#define ASMC_KEY_LIGHTLEFT "ALV0" /* RO; 6 or 10 bytes */
#define ASMC_KEY_LIGHTRIGHT "ALV1" /* RO; 6 bytes */
#define ASMC_KEY_LIGHTVALUE "LKSB" /* WO; 2 bytes */
+#define ASMC_KEY_LIGHTSRC "ALSL" /* RO; ambient light source */
+#define ASMC_KEY_FANSAFESPEED0 "F0Sf" /* RO; 2 bytes */
/*
* Clamshell.
@@ -125,793 +180,99 @@ struct asmc_softc {
#define ASMC_KEY_CLAMSHELL "MSLD" /* RO; 1 byte */
/*
+ * Auto power-on after AC power loss (AUPO).
+ * When set, the machine boots automatically when AC power is restored
+ * after an unclean power loss. This is NOT Wake-on-LAN.
+ */
+#define ASMC_KEY_AUPO "AUPO" /* RW; 1 byte */
+
+/*
* Interrupt keys.
*/
#define ASMC_KEY_INTOK "NTOK" /* WO; 1 byte */
/*
- * Temperatures.
- *
- * First for MacBook, second for MacBook Pro, third for Intel Mac Mini,
- * fourth the Mac Pro 8-core and finally the MacBook Air.
+ * System State Machine / diagnostics keys.
*
+ * MSSD - Mac System Shutdown cause (last shutdown reason code)
+ * MSSP - Mac System SleeP cause (last sleep reason code)
+ * MSAL - Mac System ALarm (thermal subsystem status bitmap)
+ * MSPS - Mac System Power State (current power state index)
+ * CLKT - CLocK Time (seconds since midnight, SMC RTC)
+ * MSTS - Mac System sTate/Status (SSM state; 0 = S0 awake)
*/
-/* maximum array size for temperatures including the last NULL */
-#define ASMC_TEMP_MAX 80
-#define ASMC_MB_TEMPS { "TB0T", "TN0P", "TN1P", "Th0H", "Th1H", \
- "TM0P", NULL }
-#define ASMC_MB_TEMPNAMES { "enclosure", "northbridge1", \
- "northbridge2", "heatsink1", \
- "heatsink2", "memory", }
-#define ASMC_MB_TEMPDESCS { "Enclosure Bottomside", \
- "Northbridge Point 1", \
- "Northbridge Point 2", "Heatsink 1", \
- "Heatsink 2", "Memory Bank A", }
-
-#define ASMC_MB31_TEMPS { "TB0T", "TN0P", "Th0H", "Th1H", \
- "TM0P", NULL }
-
-#define ASMC_MB31_TEMPNAMES { "enclosure", "northbridge1", \
- "heatsink1", "heatsink2", \
- "memory", }
-
-#define ASMC_MB31_TEMPDESCS { "Enclosure Bottomside", \
- "Northbridge Point 1", \
- "Heatsink 1","Heatsink 2" \
- "Memory Bank A", }
-
-#define ASMC_MB71_TEMPS { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", \
- "TH0P", "TN0D", "TN0P", "TN0S", "TN1D", \
- "TN1E", "TN1F", "TN1G", "TN1S", "Th1H", \
- "Ts0P", "Ts0S", NULL }
-
-#define ASMC_MB71_TEMPNAMES { "enclosure_bottom0", "battery_1", "battery_2", "cpu_package", "cpu_proximity", \
- "hdd_bay", "northbridge0_diode", "northbridge0_proximity", "TN0S", "mpc_die2", \
- "TN1E", "TN1F", "TN1G", "TN1S", "heatsink1", \
- "palm_rest", "memory_proximity", }
-
-#define ASMC_MB71_TEMPDESCS { "Enclosure Bottom 0", "Battery 1", "Battery 2", "CPU Package", "CPU Proximity", \
- "HDD Bay", "Northbridge Diode", "Northbridge Proximity", "TN0S", "MPC Die 2", \
- "TN1E", "TN1F", "TN1G", "TN1S", "Heatsink 1", \
- "Palm Rest", "Memory Proximity", }
-
-#define ASMC_MBP_TEMPS { "TB0T", "Th0H", "Th1H", "Tm0P", \
- "TG0H", "TG0P", "TG0T", NULL }
-
-#define ASMC_MBP_TEMPNAMES { "enclosure", "heatsink1", \
- "heatsink2", "memory", "graphics", \
- "graphicssink", "unknown", }
-
-#define ASMC_MBP_TEMPDESCS { "Enclosure Bottomside", \
- "Heatsink 1", "Heatsink 2", \
- "Memory Controller", \
- "Graphics Chip", "Graphics Heatsink", \
- "Unknown", }
-
-#define ASMC_MBP4_TEMPS { "TB0T", "Th0H", "Th1H", "Th2H", "Tm0P", \
- "TG0H", "TG0D", "TC0D", "TC0P", "Ts0P", \
- "TTF0", "TW0P", NULL }
-
-#define ASMC_MBP4_TEMPNAMES { "enclosure", "heatsink1", "heatsink2", \
- "heatsink3", "memory", "graphicssink", \
- "graphics", "cpu", "cpu2", "unknown1", \
- "unknown2", "wireless", }
-
-#define ASMC_MBP4_TEMPDESCS { "Enclosure Bottomside", \
- "Main Heatsink 1", "Main Heatsink 2", \
- "Main Heatsink 3", \
- "Memory Controller", \
- "Graphics Chip Heatsink", \
- "Graphics Chip Diode", \
- "CPU Temperature Diode", "CPU Point 2", \
- "Unknown", "Unknown", \
- "Wireless Module", }
-
-#define ASMC_MBP51_TEMPS { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", \
- "TC0F", "TC0P", "TG0D", "TG0F", "TG0H", \
- "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", \
- "TTF0", "Th2H", "Tm0P", "Ts0P", "Ts0S", \
- NULL }
-
-#define ASMC_MBP51_TEMPNAMES { "enclosure_bottom_0", "enclosure_bottom_1", \
- "enclosure_bottom_2", "enclosure_bottom_3", \
- "cpu_diode", "cpu", \
- "cpu_pin", "gpu_diode", \
- "gpu", "gpu_heatsink", \
- "gpu_pin", "gpu_transistor", \
- "gpu_2_heatsink", "northbridge_diode", \
- "northbridge_pin", "unknown", \
- "heatsink_2", "memory_controller", \
- "pci_express_slot_pin", "pci_express_slot_unk" }
-
-#define ASMC_MBP51_TEMPDESCS { "Enclosure Bottom 0", "Enclosure Bottom 1", \
- "Enclosure Bottom 2", "Enclosure Bottom 3", \
- "CPU Diode", "CPU ???", \
- "CPU Pin", "GPU Diode", \
- "GPU ???", "GPU Heatsink", \
- "GPU Pin", "GPU Transistor", \
- "GPU 2 Heatsink", "Northbridge Diode", \
- "Northbridge Pin", "Unknown", \
- "Heatsink 2", "Memory Controller", \
- "PCI Express Slot Pin", "PCI Express Slot (unk)" }
-
-#define ASMC_MBP62_TEMPS { "TB0T", "TB1T", "TB2T", \
- "TC0C", "TC0D", "TC0P", \
- "TC1C", "TG0D", "TG0P", \
- "TG0T", "TMCD", "TP0P", \
- "TPCD", "Th1H", "Th2H", \
- "Tm0P", "Ts0P", "Ts0S" }
-
-#define ASMC_MBP62_TEMPNAMES { "enclosure_bottom_0", "enclosure_bottom_1", \
- "enclosure_bottom_2", "cpu0", \
- "cpu_diode", "cpu_proximity", \
- "cpu1", "gpu_diode", \
- "gpu_pin", "gpu_transistor", \
- "TMCD", "pch_controller_proximity", \
- "pch_die", "heatsink1", \
- "heatsink2", "memory-controller", \
- "palmrest", "memoryproximity" }
-
-#define ASMC_MBP62_TEMPDESCS { "Enclosure Bottom 0", "Enclosure Bottom 1", \
- "Enclosure Bottom 2", "CPU 0", \
- "CPU Diode", "CPU Proximity", \
- "CPU 1", "GPU Diode", \
- "GPU Pin", "GPU Transistor", \
- "TMCD", "PCH Controller Proximity", \
- "PCH Die", "Heat Sink 1", \
- "Heat Sink 2", "Memory Controller", \
- "Palm Rest", "Memory Proximity" }
-
-#define ASMC_MBP55_TEMPS { "TB0T", "TB1T", \
- "TB2T", "TB3T", \
- "TC0D", "TC0P", \
- "TN0D", "TN0P", \
- "TTF0", \
- "Th0H", "Th1H", "ThFH", \
- "Ts0P", "Ts0S", \
- NULL }
-
-#define ASMC_MBP55_TEMPNAMES { "enclosure_bottom_0", "enclosure_bottom_1", \
- "enclosure_bottom_2", "enclosure_bottom_3", \
- "cpu_diode", "cpu_pin", \
- "northbridge_diode", "northbridge_pin", \
- "unknown", \
- "heatsink_0", "heatsink_1", "heatsink_2", \
- "pci_express_slot_pin", "pci_express_slot_unk" }
-
-#define ASMC_MBP55_TEMPDESCS { "Enclosure Bottom 0", "Enclosure Bottom 1", \
- "Enclosure Bottom 2", "Enclosure Bottom 3", \
- "CPU Diode", "CPU Pin", \
- "Northbridge Diode", "Northbridge Pin", \
- "Unknown", \
- "Heatsink 0", "Heatsink 1", "Heatsink 2", \
- "PCI Express Slot Pin", "PCI Express Slot (unk)" }
-
-#define ASMC_MBP81_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", \
- "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \
- "TCFC", "TCGC", "TCSA", "TM0S", "TMBS", \
- "TP0P", "TPCD", "TW0P", "Th1H", "Ts0P", \
- "Ts0S", NULL }
-
-#define ASMC_MBP81_TEMPNAMES { "enclosure", "TB1T", "TB2T", "TC0C", "TC0D", \
- "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \
- "TCFC", "TCGC", "TCSA", "TM0S", "TMBS", \
- "TP0P", "TPCD", "wireless", "Th1H", "Ts0P", \
- "Ts0S" }
-
-#define ASMC_MBP81_TEMPDESCS { "Enclosure Bottomside", "TB1T", "TB2T", "TC0C", "TC0D", \
- "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \
- "TCFC", "TCGC", "TCSA", "TM0S", "TMBS", \
- "TP0P", "TPCD", "TW0P", "Th1H", "Ts0P", \
- "Ts0S" }
-
-#define ASMC_MBP82_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", \
- "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \
- "TC3C", "TC4C", "TCFC", "TCGC", "TCSA", \
- "TCTD", "TG0D", "TG0P", "THSP", "TM0S", \
- "TMBS", "TP0P", "TPCD", "TW0P", "Th1H", \
- "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL }
-
-#define ASMC_MBP82_TEMPNAMES { "enclosure", "TB1T", "TB2T", "TC0C", "TC0D", \
- "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \
- "TC3C", "TC4C", "TCFC", "TCGC", "TCSA", \
- "TCTD", "graphics", "TG0P", "THSP", "TM0S", \
- "TMBS", "TP0P", "TPCD", "wireless", "Th1H", \
- "Th2H", "memory", "Ts0P", "Ts0S" }
-
-#define ASMC_MBP82_TEMPDESCS { "Enclosure Bottomside", "TB1T", "TB2T", "TC0C", "TC0D", \
- "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \
- "TC3C", "TC4C", "TCFC", "TCGC", "TCSA", \
- "TCTD", "TG0D", "TG0P", "THSP", "TM0S", \
- "TMBS", "TP0P", "TPCD", "TW0P", "Th1H", \
- "Th2H", "Tm0P", "Ts0P", "Ts0S" }
-
-#define ASMC_MBP91_TEMPS { "TA0P", "TB0T", "TB1T", "TB2T", "TC0E", \
- "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \
- "TC4C", "TCGC", "TCSA", "TCXC", "TG0D", \
- "TG0P", "TG1D", "TG1F", "TG1d", "TGTC", \
- "TGTD", "TM0P", "TM0S", "TP0P", "TPCD", \
- "Th1H", "Th2H", "Ts0P", "Ts0S", "Tsqf", NULL }
-
-#define ASMC_MBP91_TEMPNAMES { "ambient", "enclosure_bottom_1", "enclosure_bottom_2", \
- "enclosure_bottom_3", "cpu_die_peci_0", "cpu_die_peci_1", \
- "cpu_proximity", "cpu_core_1", "cpu_core_2", "cpu_core_3", \
- "cpu_core_4", "intel_gpu", "cpu_sys_agent", \
- "cpu_core_peci", "gpu_analog", \
- "gpu_proximity", "geforce_gpu_digital", "tg1f", \
- "gpu_2_die", "tgtc", "tgtd", "memory_proximity", \
- "mem_bank_a1", "platform_ctrl_hub", "pch_digital", \
- "main_heatsink_r", "main_heatsink_l", "palm_rest", \
- "bottom_skin", "tsqf" }
-
-#define ASMC_MBP91_TEMPDESCS { "Ambient", "Enclosure Bottom 1", "Enclosure Bottom 2", \
- "Enclosure Bottom 3", "CPU Die PECI 0", "CPU Die PECI 1", \
- "CPU Proximity", "CPU Core 1", "CPU Core 2", \
- "CPU Core 3", "CPU Core 4", "Intel GPU", \
- "CPU System Agent Core", "CPU Core - PECI", \
- "GPU Die - Analog", "GPU Proximity", \
- "GeForce GPU Die - Digital", "TG1F", "GPU 2 Die" \
- "TGTC", "TGTD", "Memory Proximity", \
- "Memory Bank A1", "Platform Controller Hub", "PCH Die - Digital", \
- "Main Heatsink Right", "Main Heatsink Left", "Palm Rest", \
- "Bottom Skin", "Tsqf" }
-
-#define ASMC_MBP92_TEMPS { "Ts0P", "Ts0S", "TA0P", "TB1T", "TB2T", \
- "TB0T", "TC1C", "TC2C", "TC0E", "TC0F", \
- "TC0J", "TC0P", "TCFC", "TCGC", "TCSA", \
- "TCTD", "TCXC", "TG1D", "TM0P", "TM0S", \
- "TPCD", NULL }
-
-#define ASMC_MBP92_TEMPNAMES { "Ts0P", "Ts0S", "TA0P", "TB1T", "TB2T", \
- "TB0T", "TC1C", "TC2C", "TC0E", "TC0F", \
- "TC0J", "TC0P", "TCFC", "TCGC", "TCSA", \
- "TCTD", "TCXC", "TG1D", "TM0P", "TM0S", \
- "TPCD" }
-
-#define ASMC_MBP92_TEMPDESCS { "Palm Rest", "Memory Proximity", "Airflow 1", \
- "Battery 1", "Battery 2", "Battery TS_MAX", \
- "CPU Core 1", "CPU Core 2", "CPU1", "CPU1", \
- "TC0J", "CPU 1 Proximity", "TCFC", \
- "PECI GPU", "PECI SA", "TCTD", "PECI CPU", \
- "GPU Die", "Memory Bank A1", "Memory Module A1", \
- "PCH Die" }
-
-#define ASMC_MBP112_TEMPS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \
- "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \
- "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \
- "TCXC", "TH0A", "TH0B", "TH0F", "TH0R", \
- "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \
- "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \
- "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \
- "Ts1S", NULL }
-
-#define ASMC_MBP112_TEMPNAMES { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \
- "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \
- "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \
- "TCXC", "TH0A", "TH0B", "TH0F", "TH0R", \
- "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \
- "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \
- "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \
- "Ts1S" }
-
-#define ASMC_MBP112_TEMPDESCS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \
- "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \
- "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \
- "TCXC", "TH0A", "TH0B", "TH0F", "TH0R", \
- "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \
- "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \
- "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \
- "Ts1S" }
-
-#define ASMC_MBP113_TEMPS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \
- "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \
- "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \
- "TCXC", "TG0D", "TG0P", "TG1D", "TG1F", \
- "TG1d", "TH0A", "TH0B", "TH0F", "TH0R", \
- "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \
- "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \
- "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \
- "Ts1S", NULL }
-
-#define ASMC_MBP113_TEMPNAMES { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \
- "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \
- "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \
- "TCXC", "TG0D", "TG0P", "TG1D", "TG1F", \
- "TG1d", "TH0A", "TH0B", "TH0F", "TH0R", \
- "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \
- "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \
- "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \
- "Ts1S" }
-
-#define ASMC_MBP113_TEMPDESCS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \
- "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \
- "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \
- "TCXC", "TG0D", "TG0P", "TG1D", "TG1F", \
- "TG1d", "TH0A", "TH0B", "TH0F", "TH0R", \
- "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \
- "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \
- "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \
- "Ts1S" }
-
-#define ASMC_MBP114_TEMPS { "IC0C", "ID0R", "IHDC", "IPBR", "IC0R", \
- "IO3R", "IO5R", "IM0C", "IC1C", "IC2C", \
- "IC3C", "ILDC", "IBLC", "IAPC", "IHSC", \
- "ICMC", "TC0P", "TP0P", "TM0P", \
- "Ta0P", "Th2H", "Th1H", "TW0P", "Ts0P", \
- "Ts1P", "TB0T", "TB1T", "TB2T", "TH0A", "TH0B", \
- "TC1C", "TC2C", "TC3C", "TC4C", "TCXC", \
- "TCGC", "TPCD", "TCSA", "VC0C", "VD0R", \
- "VP0R", "ALSL", "F0Ac", "F1Ac", "PCPC", \
- "PCPG", "PCPT", "PSTR", "PDTR", NULL }
-
-#define ASMC_MBP114_TEMPNAMES { "IC0C", "ID0R", "IHDC", "IPBR", "IC0R", \
- "IO3R", "IO5R", "IM0C", "IC1C", "IC2C", \
- "IC3C", "ILDC", "IBLC", "IAPC", "IHSC", \
- "ICMC", "TC0P", "TP0P", "TM0P", \
- "Ta0P", "Th2H", "Th1H", "TW0P", "Ts0P", \
- "Ts1P", "TB0T", "TB1T", "TB2T", "TH0A", "TH0B", \
- "TC1C", "TC2C", "TC3C", "TC4C", "TCXC", \
- "TCGC", "TPCD", "TCSA", "VC0C", "VD0R", \
- "VP0R", "ALSL", "F0Ac", "F1Ac", "PCPC", \
- "PCPG", "PCPT", "PSTR", "PDTR" }
-
-#define ASMC_MBP114_TEMPDESCS { "CPU High (CPU, I/O)", "DC In", "SSD", "Charger (BMON)", "CPU", \
- "Other 3.3V", "Other 5V", "Memory", "Platform Controller Hub Core", "CPU Load Current Monitor", \
- "CPU DDR", "LCD Panel", "LCD Backlight", "Airport", "Thunderbolt", \
- "S2", "CPU Proximity", "Platform Controller Hub", "Memory Proximity", "Air Flow Proximity", \
- "Left Fin Stack", "Right Fin Stack", "Airport Proximity", "Palm Rest", "Palm Rest Actuator", \
- "Battery Max", "Battery Sensor 1", "Battery Sensor 2", "SSD A", "SSD B", \
- "CPU Core 1", "CPU Core 2", "CPU Core 3", "CPU Core 4", "CPU PECI Die", \
- "Intel GPU", "Platform Controller Hub PECI", "CPU System Agent Core", "CPU VCore", "DC In", \
- "Pbus", "Ambient Light", "Leftside", "Rightside", "CPU Package Core", \
- "CPU Package GPU", "CPU Package Total", "System Total", "DC In" }
+#define ASMC_KEY_CLKT "CLKT" /* RO; 4 bytes ui32 BE */
+#define ASMC_KEY_MSSD "MSSD" /* RO; 1 byte si8 */
+#define ASMC_KEY_MSSP "MSSP" /* RO; 1 byte si8 */
+#define ASMC_KEY_MSAL "MSAL" /* RO; 1 byte hex_ */
+#define ASMC_KEY_MSPS "MSPS" /* RO; 1 or 2 bytes hex_ */
+#define ASMC_KEY_MSTS "MSTS" /* RO; 1 byte ui8 */
-#define ASMC_MM_TEMPS { "TN0P", "TN1P", NULL }
-#define ASMC_MM_TEMPNAMES { "northbridge1", "northbridge2" }
-#define ASMC_MM_TEMPDESCS { "Northbridge Point 1", \
- "Northbridge Point 2" }
-
-#define ASMC_MM21_TEMPS { "TA0P", "TC0D", \
- "TC0H", "TC0P", \
- "TC1P", "TN0P", \
- "TN1P", NULL }
-
-#define ASMC_MM21_TEMPNAMES { "ambient_air", "cpu_die", \
- "cpu_heatsink", "cpu_proximity1", \
- "cpu_proximity2", "northbridge_proximity1", \
- "northbridge_proximity2", }
-
-#define ASMC_MM21_TEMPDESCS { "Ambient Air Temperature" \
- "CPU Die Core Temperature", \
- "CPU Heatsink Temperature", \
- "CPU Proximity 1 Temperature", \
- "CPU Proximity 2 Temperature", \
- "Northbridge Proximity 1 Temperature", \
- "Northbridge Proximity 2 Temperature", }
-
-#define ASMC_MM31_TEMPS { "TC0D", "TC0H", \
- "TC0P", "TH0P", \
- "TN0D", "TN0P", \
- "TW0P", NULL }
-
-#define ASMC_MM31_TEMPNAMES { "cpu0_die", "cpu0_heatsink", \
- "cpu0_proximity", "hdd_bay", \
- "northbridge_die", \
- "northbridge_proximity", \
- "wireless_proximity", }
-
-#define ASMC_MM31_TEMPDESCS { "CPU0 Die Core Temperature", \
- "CPU0 Heatsink Temperature", \
- "CPU0 Proximity Temperature", \
- "HDD Bay Temperature", \
- "Northbridge Die Core Temperature", \
- "Northbridge Proximity Temperature", \
- "Wireless Module Proximity Temperature", }
-
-#define ASMC_MM41_TEMPS { "TA0P", "TC0D", "TC0G", "TC0H", "TC0P", \
- "TC0p", "TCPG", "TH0G", "TH0P", "TH0p", \
- "TM0G", "TM0P", "TM0p", "TN0D", "TN0G", \
- "TN0P", "TN0p", "TN1D", "TN1E", "TN1F", \
- "TN1G", "TN1S", "TNPG", "TO0P", "TO0p", \
- "TW0P", "Tm0P", "Tp0C", NULL }
-
-#define ASMC_MM41_TEMPNAMES { "TA0P", "TC0D", "TC0G", "TC0H", "TC0P", \
- "TC0p", "TCPG", "TH0G", "TH0P", "TH0p", \
- "TM0G", "TM0P", "TM0p", "TN0D", "TN0G", \
- "TN0P", "TN0p", "TN1D", "TN1E", "TN1F", \
- "TN1G", "TN1S", "TNPG", "TO0P", "TO0p", \
- "TW0P", "Tm0P", "Tp0C", NULL }
-
-#define ASMC_MM41_TEMPDESCS { "TA0P", "TC0D", "TC0G", "TC0H", "TC0P", \
- "TC0p", "TCPG", "TH0G", "TH0P", "TH0p", \
- "TM0G", "TM0P", "TM0p", "TN0D", "TN0G", \
- "TN0P", "TN0p", "TN1D", "TN1E", "TN1F", \
- "TN1G", "TN1S", "TNPG", "TO0P", "TO0p", \
- "TW0P", "Tm0P", "Tp0C", NULL }
-
-#define ASMC_MM52_TEMPS { "TA0P", "TA1P", \
- "TC0D", "TC0P", \
- "TG0D", "TG1D", \
- "TG0P", "TG0M", \
- "TI0P", \
- "TM0S", "TMBS", \
- "TM0P", "TP0P", \
- "TPCD", "Tp0C", \
- "TW0P", NULL }
-
-#define ASMC_MM52_TEMPNAMES { "ambient_air_proximity", "ambient_cpu_pch_wireless_dimm", \
- "cpu_die", "cpu_proximity", \
- "gpu_diode1", "gpu_diode2", \
- "gpu_proximity", "gpu_integrated_switcher", \
- "thunderbolt_proximity", \
- "memory_slot1", "memory_slot2", \
- "memory_proximity", "pch_controller_proximity", \
- "pch_controller_die", "pwr_supply", \
- "wireless_proximity", }
-
-#define ASMC_MM52_TEMPDESCS { "Ambient Air Proximity Temperature", \
- "Combo Ambient CPU PCH Wireless DIMM Temperature", \
- "CPU Die Temperature", "CPU Proximity Temperature", \
- "GPU Diode 1 Temperature" , "GPU Diode 2 Temperature", \
- "GPU Proximity Temperature", \
- "Integrated Graphics/GPU Switcher Temperature", \
- "Thunderbolt Proximity Temperature", \
- "Memory Slot 1 Temperature", \
- "Memory Slot 2 Temperature", \
- "Memory Slots Proximity Temperature", \
- "Platform Controller Hub Proximity Temperature", \
- "Platform Controller Hub Die Temperature", \
- "Power Supply Temperature", \
- "Wireless Module Proximity Temperature", }
-
-#define ASMC_MM61_TEMPS { "TA0P", "TA1P", \
- "TC0D", "TC0G", "TC0P", "TCPG", \
- "TI0P", \
- "TM0S", "TMBS", "TM0P", \
- "TP0P", "TPCD", \
- "Tp0C", \
- "TW0P", NULL }
-
-#define ASMC_MM61_TEMPNAMES { "ambient_air_proximity", "ambient_cpu_pch_wireless_dimm", \
- "cpu_die", "TC0G", "cpu_proximity", "TCPG", \
- "thunderbolt_proximity", \
- "memory_slot1", "memory_slot2", "memory_proximity", \
- "pch_controller_proximity", "pch_controller_die", \
- "pwr_supply", \
- "wireless_proximity", NULL }
-
-#define ASMC_MM61_TEMPDESCS { "Ambient Air Proximity Temperature", \
- "Combo Ambient CPU PCH Wireless DIMM Temperature", \
- "CPU Die Temperature", \
- NULL, \
- "CPU Proximity Temperature", \
- NULL, \
- "Thunderbolt Proximity Temperature", \
- "Memory Slot 1 Temperature", \
- "Memory Slot 2 Temperature", \
- "Memory Slots Proximity Temperature", \
- "Platform Controller Hub Proximity Temperature", \
- "Platform Controller Hub Die Temperature", \
- "Power Supply Temperature", \
- "Wireless Module Proximity Temperature", NULL }
-
-#define ASMC_MM62_TEMPS { "TA0P", "TA1P", \
- "TC0D", "TC0G", "TC0P", "TCPG", \
- "TI0P", \
- "TM0S", "TMBS", "TM0P", \
- "TP0P", "TPCD", \
- "Tp0C", \
- "TW0P", NULL }
-
-#define ASMC_MM62_TEMPNAMES { "ambient_air_proximity", "ambient_cpu_pch_wireless_dimm", \
- "cpu_die", "TC0G", "cpu_proximity", "TCPG", \
- "thunderbolt_proximity", \
- "memory_slot1", "memory_slot2", "memory_proximity", \
- "pch_controller_proximity", "pch_controller_die", \
- "pwr_supply", \
- "wireless_proximity", NULL }
-
-#define ASMC_MM62_TEMPDESCS { "Ambient Air Proximity Temperature", \
- "Combo Ambient CPU PCH Wireless DIMM Temperature", \
- "CPU Die Temperature", \
- NULL, \
- "CPU Proximity Temperature", \
- NULL, \
- "Thunderbolt Proximity Temperature", \
- "Memory Slot 1 Temperature", \
- "Memory Slot 2 Temperature", \
- "Memory Slots Proximity Temperature", \
- "Platform Controller Hub Proximity Temperature", \
- "Platform Controller Hub Die Temperature", \
- "Power Supply Temperature", \
- "Wireless Module Proximity Temperature", NULL }
-
-#define ASMC_MM71_TEMPS { "TA0p", "TA1p", \
- "TA2p", "TC0c", \
- "TC0p", "TC1c", \
- "TCGc", "TCSc", \
- "TCXC", "TCXR", \
- "TM0p", "TPCd", \
- "TW0p", "Te0T", \
- "Tm0P", NULL }
-
-#define ASMC_MM71_TEMPNAMES { "ambient_air1", "ambient_air2", \
- "ambient_air3", "cpu_core1_peci", \
- "cpu_proximity", "cpu_core2_peci", \
- "intel_gpu", "cpu_sa_core_peci", \
- "cpu_core", "cpu_peci_dts", \
- "memory_proximity", "pch_controller_die", \
- "wireless_proximity", "thunderbolt_diode", \
- "logic_board", }
-
-#define ASMC_MM71_TEMPDESCS { "Ambient Air Temperature 1", \
- "Ambient Air Temperature 2", \
- "Ambient Air Temperature 3", \
- "CPU Core 1 PECI Temperature", "CPU Proximity Temperature", \
- "CPU Core 2 PECI Temperature", "Intel GPU Temperature", \
- "CPU System Agent Core PECI Temperature", \
- "CPU Core Temperature", "CPU PECI DTS Temperature", \
- "Memory Proximity Temperature", \
- "Platform Controller Hub Die Temperature", \
- "Wireless Module Proximity Temperature", \
- "Thunderbolt Diode Temperature", \
- "Logic Board temperature", }
-
-#define ASMC_MP1_TEMPS { "TA0P", \
- "TCAH", "TCBH", \
- "TC0P", "TC0C", "TC1C", \
- "TC2C", "TC3C", "THTG", \
- "TH0P", "TH1P", \
- "TH2P", "TH3P", \
- "TM0P", "TM1P", "TM2P", \
- "TM8P", "TM9P", "TMAP", \
- "TM0S", "TM1S", "TM2P", "TM3S", \
- "TM8S", "TM9S", "TMAS", "TMBS", \
- "TN0H", "TS0C", \
- "Tp0C", "Tp1C", "Tv0S", "Tv1S", NULL }
-
-#define ASMC_MP1_TEMPNAMES { "ambient", \
- "cpu_a_heatsink", "cpu_b_heatsink", \
- "cpu_a_proximity", "cpu_core0", "cpu_core1", \
- "cpu_core2", "cpu_core3", "THTG", \
- "hdd_bay0", "hdd_bay1", \
- "hdd_bay2", "hdd_bay3", \
- "memory_card_a_proximity0", \
- "memory_card_a_proximity1", \
- "memory_card_a_proximity2", \
- "memory_card_b_proximity0", \
- "memory_card_b_proximity1", \
- "memory_card_b_proximity2", \
- "memory_card_a_slot0", \
- "memory_card_a_slot1", \
- "memory_card_a_slot2", \
- "memory_card_a_slot3", \
- "memory_card_b_slot0", \
- "memory_card_b_slot1", \
- "memory_card_b_slot2", \
- "memory_card_b_slot3", \
- "mch_heatsink", "expansion_slots", \
- "power_supply_loc0", "power_supply_loc1", \
- "Tv0S", "Tv1S", }
-
-#define ASMC_MP1_TEMPDESCS { "Ambient Air", \
- "CPU A Heatsink", "CPU B Heatsink", \
- "CPU A Proximity", \
- "CPU Core 1", "CPU Core 2", \
- "CPU Core 3", "CPU Core 4", "THTG", \
- "Hard Drive Bay 1", "Hard Drive Bay 2", \
- "Hard Drive Bay 3", "Hard Drive Bay 4", \
- "Memory Riser A, Proximity 1", \
- "Memory Riser A, Proximity 2", \
- "Memory Riser A, Proximity 3", \
- "Memory Riser B, Proximity 1", \
- "Memory Riser B, Proximity 2", \
- "Memory Riser B, Proximity 3", \
- "Memory Riser A, Slot 1", \
- "Memory Riser A, Slot 2", \
- "Memory Riser A, Slot 3", \
- "Memory Riser A, Slot 4", \
- "Memory Riser B, Slot 1", \
- "Memory Riser B, Slot 2", \
- "Memory Riser B, Slot 3", \
- "Memory Riser B, Slot 4", \
- "MCH Heatsink", "Expansion Slots", \
- "Power Supply, Location 1", \
- "Power Supply, Location 2", \
- "Tv0S", "Tv1S", }
-
-#define ASMC_MP2_TEMPS { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", \
- "TC0C", "TC0D", "TC0P", "TC1C", "TC1D", \
- "TC2C", "TC2D", "TC3C", "TC3D", "THTG", \
- "TH0P", "TH1P", "TH2P", "TH3P", "TMAP", \
- "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", \
- "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", \
- "TM8S", "TM9P", "TM9S", "TN0H", "TS0C", \
- NULL }
-
-#define ASMC_MP2_TEMPNAMES { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", \
- "TC0C", "TC0D", "TC0P", "TC1C", "TC1D", \
- "TC2C", "TC2D", "TC3C", "TC3D", "THTG", \
- "TH0P", "TH1P", "TH2P", "TH3P", "TMAP", \
- "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", \
- "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", \
- "TM8S", "TM9P", "TM9S", "TN0H", "TS0C", }
-
-#define ASMC_MP2_TEMPDESCS { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", \
- "TC0C", "TC0D", "TC0P", "TC1C", "TC1D", \
- "TC2C", "TC2D", "TC3C", "TC3D", "THTG", \
- "TH0P", "TH1P", "TH2P", "TH3P", "TMAP", \
- "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", \
- "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", \
- "TM8S", "TM9P", "TM9S", "TN0H", "TS0C", }
-
-#define ASMC_MP5_TEMPS { "TA0P", "TCAC", "TCAD", "TCAG", "TCAH", \
- "TCAS", "TCBC", "TCBD", "TCBG", "TCBH", \
- "TCBS", "TH1F", "TH1P", "TH1V", "TH2F", \
- "TH2P", "TH2V", "TH3F", "TH3P", "TH3V", \
- "TH4F", "TH4P", "TH4V", "THPS", "THTG", \
- "TM1P", "TM2P", "TM2V", "TM3P", "TM3V", \
- "TM4P", "TM5P", "TM6P", "TM6V", "TM7P", \
- "TM7V", "TM8P", "TM8V", "TM9V", "TMA1", \
- "TMA2", "TMA3", "TMA4", "TMB1", "TMB2", \
- "TMB3", "TMB4", "TMHS", "TMLS", "TMPS", \
- "TMPV", "TMTG", "TN0D", "TN0H", "TNTG", \
- "Te1F", "Te1P", "Te1S", "Te2F", "Te2S", \
- "Te3F", "Te3S", "Te4F", "Te4S", "Te5F", \
- "Te5S", "TeGG", "TeGP", "TeRG", "TeRP", \
- "TeRV", "Tp0C", "Tp1C", "TpPS", "TpTG", \
- NULL }
-
-#define ASMC_MP5_TEMPNAMES { "ambient", "TCAC", "TCAD", "TCAG", "TCAH", \
- "TCAS", "TCBC", "TCBD", "TCBG", "TCBH", \
- "TCBS", "TH1F", "TH1P", "TH1V", "TH2F", \
- "TH2P", "TH2V", "TH3F", "TH3P", "TH3V", \
- "TH4F", "TH4P", "TH4V", "THPS", "THTG", \
- "TM1P", "TM2P", "TM2V", "TM3P", "TM3V", \
- "TM4P", "TM5P", "TM6P", "TM6V", "TM7P", \
- "TM7V", "TM8P", "TM8V", "TM9V", "ram_a1", \
- "ram_a2", "ram_a3", "ram_a4", "ram_b1", "ram_b2", \
- "ram_b3", "ram_b4", "TMHS", "TMLS", "TMPS", \
- "TMPV", "TMTG", "TN0D", "TN0H", "TNTG", \
- "Te1F", "Te1P", "Te1S", "Te2F", "Te2S", \
- "Te3F", "Te3S", "Te4F", "Te4S", "Te5F", \
- "Te5S", "TeGG", "TeGP", "TeRG", "TeRP", \
- "TeRV", "Tp0C", "Tp1C", "TpPS", "TpTG", }
-
-#define ASMC_MP5_TEMPDESCS { "TA0P", "TCAC", "TCAD", "TCAG", "TCAH", \
- "TCAS", "TCBC", "TCBD", "TCBG", "TCBH", \
- "TCBS", "TH1F", "TH1P", "TH1V", "TH2F", \
- "TH2P", "TH2V", "TH3F", "TH3P", "TH3V", \
- "TH4F", "TH4P", "TH4V", "THPS", "THTG", \
- "TM1P", "TM2P", "TM2V", "TM3P", "TM3V", \
- "TM4P", "TM5P", "TM6P", "TM6V", "TM7P", \
- "TM7V", "TM8P", "TM8V", "TM9V", "TMA1", \
- "TMA2", "TMA3", "TMA4", "TMB1", "TMB2", \
- "TMB3", "TMB4", "TMHS", "TMLS", "TMPS", \
- "TMPV", "TMTG", "TN0D", "TN0H", "TNTG", \
- "Te1F", "Te1P", "Te1S", "Te2F", "Te2S", \
- "Te3F", "Te3S", "Te4F", "Te4S", "Te5F", \
- "Te5S", "TeGG", "TeGP", "TeRG", "TeRP", \
- "TeRV", "Tp0C", "Tp1C", "TpPS", "TpTG", }
-
-#define ASMC_MP6_TEMPS { "TA0P", "TA1P", "TC0P", "TG0D", "TG0P", \
- "TG1D", "TG1P", "TM0P", "TM1P", NULL }
-
-#define ASMC_MP6_TEMPNAMES { "ambient_air_1", "ambient_air_2", \
- "cpu_proximity", "gpu_diode_1", \
- "gpu_proximity_1", "gpu_diode_2", \
- "gpu_proximity_2", "mem_proximity_1", \
- "mem_proximity_2" }
-
-#define ASMC_MP6_TEMPDESCS { "Ambient Air 1", "Ambient Air 2", \
- "CPU Proximity", "GPU Diode 1", \
- "GPU Proximity 1", "GPU Diode 2", \
- "GPU Proximity 2", "Memory Bank A", \
- "Memory Bank B" }
-
-#define ASMC_MBA_TEMPS { "TB0T", NULL }
-#define ASMC_MBA_TEMPNAMES { "enclosure" }
-#define ASMC_MBA_TEMPDESCS { "Enclosure Bottom" }
-
-#define ASMC_MBA3_TEMPS { "TB0T", "TB1T", "TB2T", \
- "TC0D", "TC0E", "TC0P", NULL }
-
-#define ASMC_MBA3_TEMPNAMES { "enclosure", "TB1T", "TB2T", \
- "TC0D", "TC0E", "TC0P" }
-
-#define ASMC_MBA3_TEMPDESCS { "Enclosure Bottom", "TB1T", "TB2T", \
- "TC0D", "TC0E", "TC0P" }
-
-#define ASMC_MBA4_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", \
- "TC0D", "TC0E", "TC0F", "TC0P", \
- "TC1C", "TC2C", "TCGC", "TCSA", \
- "TH0F", "TH0J", "TH0O", "TH0o", \
- "TM0P", "TPCD", "Ta0P", "Th1H", \
- "Tm0P", "Tm1P", "Ts0P", "Ts0S", \
- NULL }
-
-#define ASMC_MBA4_TEMPNAMES { "TB0T", "TB1T", "TB2T", "TC0C", \
- "TC0D", "TC0E", "TC0F", "TC0P", \
- "TC1C", "TC2C", "TCGC", "TCSA", \
- "TH0F", "TH0J", "TH0O", "TH0o", \
- "TM0P", "TPCD", "Ta0P", "Th1H", \
- "Tm0P", "Tm1P", "Ts0P", "Ts0S", \
- NULL }
-
-#define ASMC_MBA4_TEMPDESCS { "TB0T", "TB1T", "TB2T", "TC0C", \
- "TC0D", "TC0E", "TC0F", "TC0P", \
- "TC1C", "TC2C", "TCGC", "TCSA", \
- "TH0F", "TH0J", "TH0O", "TH0o", \
- "TM0P", "TPCD", "Ta0P", "Th1H", \
- "Tm0P", "Tm1P", "Ts0P", "Ts0S", \
- NULL }
-
-#define ASMC_MBA5_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", \
- "TC0D", "TC0E", "TC0F", "TC0P", \
- "TC1C", "TC2C", "TCGC", "TCSA", \
- "TCXC", "THSP", "TM0P", "TPCD", \
- "Ta0P", "Th1H", "Tm0P", "Tm1P", \
- "Ts0P", "Ts0S", NULL }
-
-#define ASMC_MBA5_TEMPNAMES { "enclosure1", "enclosure2", "enclosure3", "TC0C", \
- "cpudiode", "cputemp1", "cputemp2", "cpuproximity", \
- "cpucore1", "cpucore2", "cpupeci", "pecisa", \
- "TCXC", "THSP", "memorybank", "pchdie", \
- "Ta0P", "heatpipe", "mainboardproximity1", "mainboardproximity2", \
- "palmrest", "memoryproximity" }
-
-#define ASMC_MBA5_TEMPDESCS { "Enclosure Bottom 1", "Enclosure Bottom 2", "Enclosure Bottom 3", "TC0C",\
- "CPU Diode", "CPU Temp 1", "CPU Temp 2", "CPU Proximity", \
- "CPU Core 1", "CPU Core 2", "CPU Peci Core", "PECI SA", \
- "TCXC", "THSP", "Memory Bank A", "PCH Die", \
- "Ta0P", "Heatpipe", "Mainboard Proximity 1", "Mainboard Proximity 2", \
- "Palm Rest", "Memory Proximity" }
+#define ASMC_MSAL_TSS 0x01 /* TSS running */
+#define ASMC_MSAL_THERM_VALID 0x02 /* thermal calibration valid */
+#define ASMC_MSAL_CALIB_VALID 0x08 /* I/P calibration valid */
+#define ASMC_MSAL_PROCHOT 0x40 /* Prochot enabled */
+#define ASMC_MSAL_PLIMITS 0x80 /* plimits enabled */
/*
- * TODO: validate the temp zones for MBA 6.x !
+ * Board identity keys.
+ *
+ * RPlt - board platform identifier (e.g. "Mac-XXXX")
+ * RGEN - security chip generation (3 = T2)
*/
-#define ASMC_MBA6_TEMPS { "TB0T", "TB1T", "TB2T", \
- "TC0E", "TC0F", "TC0P", \
- "TC1C", "TC2C", "TCGC", "TCSA", \
- "TCXC", "THSP", "TM0P", "TPCD", \
- "Ta0P", "Th1H", "Tm0P", \
- "Ts0P", "Ts0S", NULL }
-
-#define ASMC_MBA6_TEMPNAMES { "enclosure1", "enclosure2", "enclosure3", \
- "cputemp1", "cputemp2", "cpuproximity", \
- "cpucore1", "cpucore2", "cpupeci", "pecisa", \
- "TCXC", "THSP", "memorybank", "pchdie", \
- "Ta0P", "heatpipe", "mainboardproximity1", \
- "palmrest", "memoryproximity" }
-
-#define ASMC_MBA6_TEMPDESCS { "Enclosure Bottom 1", "Enclosure Bottom 2", "Enclosure Bottom 3", \
- "CPU Temp 1", "CPU Temp 2", "CPU Proximity", \
- "CPU Core 1", "CPU Core 2", "CPU Peci Core", "PECI SA", \
- "TCXC", "THSP", "Memory Bank A", "PCH Die", \
- "Ta0P", "Heatpipe", "Mainboard Proximity 1", \
- "Palm Rest", "Memory Proximity" }
+#define ASMC_KEY_RPLT "RPlt" /* RO; 8 bytes ch8* */
+#define ASMC_KEY_RGEN "RGEN" /* RO; 1 byte ui8 */
+#define ASMC_RPLT_MAXLEN 8 /* RPlt key data length */
+/*
+ * Shutdown/sleep cause codes (MSSD/MSSP values).
+ *
+ * Positive values indicate normal operation; negative values indicate
+ * fault conditions.
+ * Sources: Apple SMC firmware, VirtualSMC docs, macOS
+ * pmset/powermetrics output.
+ */
+struct asmc_cause {
+ int8_t code;
+ const char *desc; /* shutdown description */
+ const char *sleep_desc; /* sleep description, or NULL if same */
+};
-#define ASMC_MBA7_TEMPS { "TB0T", "TB1T", "TB2T", \
- "TC0E", "TC0F", "TC0P", \
- "TC1C", "TC2C", \
- "TCGC", "TCSA", "TCXC", \
- "THSP", "TM0P", "TPCD", \
- "TW0P" "Ta0P", "Th1H", \
- "Tm0P", "Ts0P", "Ts0S", NULL }
-
-#define ASMC_MBA7_TEMPNAMES { "enclosure1", "enclosure2", "enclosure3", \
- "cputemp1", "cputemp2", "cpuproximity", \
- "cpucore1", "cpucore2", \
- "pecigpu", "pecisa", "pecicpu", \
- "thunderboltproximity", "memorybank", "pchdie", \
- "wirelessproximity", "airflowproximity", "heatpipe", \
- "mainboardproximity", "palmrest", "memoryproximity" }
+#define ASMC_CAUSE_BUFLEN 48 /* "-128 (temperature-overlimit-timeout)\0" */
-#define ASMC_MBA7_TEMPDESCS { "Enclosure Bottom 1", "Enclosure Bottom 2", "Enclosure Bottom 3", \
- "CPU Temp 1", "CPU Temp 2", "CPU Proximity", \
- "CPU Core 1", "CPU Core 2", \
- "PECI GPU", "PECI SA", "PECI CPU", \
- "Thunderbolt Proximity", "Memory Bank A", "PCH Die", \
- "Wireless Proximity", "Airflow Proxmity", "Heatpipe", \
- "Mainboard Proximity", "Palm Rest", "Memory Proximity" }
+static const struct asmc_cause asmc_cause_table[] = {
+ { 5, "good-shutdown", "good-sleep" },
+ { 3, "power-button", NULL },
+ { 2, "low-battery-sleep", NULL },
+ { 1, "overtemp-sleep", NULL },
+ { 0, "initial", NULL },
+ { -1, "health-check", NULL },
+ { -2, "power-supply", NULL },
+ { -3, "temperature-multisleep", NULL },
+ { -4, "sensor-fan", NULL },
+ { -30, "temperature-overlimit-timeout",NULL },
+ { -40, "pswr-smrst", NULL }, /* power supply watchdog reset */
+ { -50, "unmapped", NULL },
+ { -60, "low-battery", NULL },
+ { -61, "ninja-shutdown", NULL }, /* sudden unexpected power loss */
+ { -62, "ninja-restart", NULL },
+ { -70, "palm-rest-temperature", NULL },
+ { -71, "sodimm-temperature", NULL },
+ { -72, "heatpipe-temperature", NULL },
+ { -74, "battery-temperature", NULL },
+ { -75, "adapter-timeout", NULL },
+ { -77, "manual-temperature", NULL },
+ { -78, "adapter-current", NULL },
+ { -79, "battery-current", NULL },
+ { -82, "skin-temperature", NULL },
+ { -83, "skin-temperature-sensors", NULL },
+ { -84, "backup-temperature", NULL },
+ { -86, "cpu-proximity-temperature", NULL },
+ { -95, "cpu-temperature", NULL },
+ { -100, "power-supply-temperature", NULL },
+ { -101, "lcd-temperature", NULL },
+ { -102, "rsm-power-fail", NULL },
+ { -103, "battery-cuv", NULL }, /* cell under-voltage */
+ { -127, "pmu-forced-shutdown", NULL },
+ { -128, "unknown", NULL },
+};