Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177354205
D61300.1794180781.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
67 KB
Referenced Files
None
Subscribers
None
D61300.1794180781.diff
View Options
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -120,6 +120,7 @@
dev/asmc/asmcdebug.c optional asmc isa asmc_debug
dev/asmc/asmcmmio.c optional asmc isa
dev/asmc/asmcpio.c optional asmc isa
+dev/asmc/asmcsysctl.c optional asmc isa
dev/axgbe/if_axgbe_pci.c optional axp
dev/axgbe/xgbe-desc.c optional axp
dev/axgbe/xgbe-dev.c optional axp
diff --git a/sys/dev/asmc/asmc.c b/sys/dev/asmc/asmc.c
--- a/sys/dev/asmc/asmc.c
+++ b/sys/dev/asmc/asmc.c
@@ -61,6 +61,7 @@
#include <dev/asmc/asmcvar.h>
#include <dev/asmc/asmcmmio.h>
#include <dev/asmc/asmcpio.h>
+#include <dev/asmc/asmcsysctl.h>
#include <dev/asmc/asmcdebug.h>
#include <dev/backlight/backlight.h>
@@ -89,10 +90,6 @@
*/
static int asmc_init(device_t dev);
static int asmc_fan_count(device_t dev);
-static int asmc_fan_getvalue(device_t dev, const char *key, int fan);
-static int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed);
-static int asmc_temp_getvalue(device_t dev, const char *key);
-static int asmc_sms_read(device_t, const char *key, int16_t *val);
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);
@@ -100,246 +97,11 @@
static void asmc_sms_init(device_t dev);
static void asmc_detect_capabilities(device_t dev);
-/*
- * Sysctl handlers.
- */
-static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
-static int asmc_mb_sysctl_fanspeed(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(SYSCTL_HANDLER_ARGS);
-static int asmc_mbp_sysctl_light(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);
-static int asmc_sil_sysctl(SYSCTL_HANDLER_ARGS);
-
-/* 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);
/* 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_search(device_t, const char *, unsigned int *);
-static const char *asmc_temp_desc(const char *key);
-
-/*
- * 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" },
-};
-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.
@@ -428,121 +190,7 @@
return (ENOMEM);
}
-/*
- * The per-fan speed keys, selected by the high byte of a fan sysctl's arg2.
- * Writable keys accept a new speed; the rest are reported only.
- */
-#define ASMC_FAN_ARG2(which, fan) (((which) << 8) | (fan))
-#define ASMC_FAN_ARG2_WHICH(arg2) (((arg2) >> 8) & 0xff)
-#define ASMC_FAN_ARG2_FAN(arg2) ((arg2) & 0xff)
-
-#define ASMC_FANSPEED_CUR 0
-#define ASMC_FANSPEED_SAFE 1
-#define ASMC_FANSPEED_MIN 2
-#define ASMC_FANSPEED_MAX 3
-#define ASMC_FANSPEED_TARGET 4
-
-static const struct {
- const char *key;
- bool writable;
-} asmc_fan_speed_keys[] = {
- [ASMC_FANSPEED_CUR] = { ASMC_KEY_FANSPEED, false },
- [ASMC_FANSPEED_SAFE] = { ASMC_KEY_FANSAFESPEED, false },
- [ASMC_FANSPEED_MIN] = { ASMC_KEY_FANMINSPEED, true },
- [ASMC_FANSPEED_MAX] = { ASMC_KEY_FANMAXSPEED, true },
- [ASMC_FANSPEED_TARGET] = { ASMC_KEY_FANTARGETSPEED, true },
-};
-
-/* The dev.asmc.n.fan.m leaves, in registration order. */
-static const struct {
- const char *name;
- const char *desc;
- int ctlflags;
- int (*handler)(SYSCTL_HANDLER_ARGS);
- int which;
- bool needs_safespeed;
-} asmc_fan_sysctls[] = {
- { "id", "Fan ID", CTLTYPE_STRING | CTLFLAG_RD,
- asmc_mb_sysctl_fanid, 0, false },
- { "speed", "Fan speed in RPM", CTLTYPE_INT | CTLFLAG_RD,
- asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_CUR, false },
- { "safespeed", "Fan safe speed in RPM", CTLTYPE_INT | CTLFLAG_RD,
- asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_SAFE, true },
- { "minspeed", "Fan minimum speed in RPM", CTLTYPE_INT | CTLFLAG_RW,
- asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_MIN, false },
- { "maxspeed", "Fan maximum speed in RPM", CTLTYPE_INT | CTLFLAG_RW,
- asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_MAX, false },
- { "targetspeed", "Fan target speed in RPM", CTLTYPE_INT | CTLFLAG_RW,
- asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_TARGET, false },
- { "manual", "Fan manual mode (0=auto, 1=manual)",
- CTLTYPE_INT | CTLFLAG_RW, asmc_mb_sysctl_fanmanual, 0, false },
-};
-
-static void
-asmc_sysctl_add_fan(device_t dev, struct sysctl_ctx_list *ctx)
-{
- struct asmc_softc *sc = device_get_softc(dev);
- char name[2];
-
- sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(ctx,
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fan",
- CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree");
-
- for (int i = 1; i <= sc->sc_nfan; i++) {
- int j = i - 1;
-
- name[0] = '0' + j;
- name[1] = 0;
- sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(ctx,
- SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name,
- CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree");
-
- for (unsigned int k = 0; k < nitems(asmc_fan_sysctls); k++) {
- if (asmc_fan_sysctls[k].needs_safespeed &&
- !sc->sc_has_safespeed)
- continue;
-
- /* SYSCTL_ADD_PROC() asserts flags at compile time. */
- sysctl_add_oid(ctx,
- SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
- OID_AUTO, asmc_fan_sysctls[k].name,
- asmc_fan_sysctls[k].ctlflags | CTLFLAG_MPSAFE,
- dev, ASMC_FAN_ARG2(asmc_fan_sysctls[k].which, j),
- asmc_fan_sysctls[k].handler, "I",
- asmc_fan_sysctls[k].desc, NULL);
- }
- }
-}
-
-/* The dev.asmc.n.sms axes, selected by arg2. */
-static const struct {
- const char *name;
- const char *key;
- const char *desc;
-} asmc_sms_sysctls[] = {
- { "x", ASMC_KEY_SMS_X, "Sudden Motion Sensor X value" },
- { "y", ASMC_KEY_SMS_Y, "Sudden Motion Sensor Y value" },
- { "z", ASMC_KEY_SMS_Z, "Sudden Motion Sensor Z value" },
-};
-static void
-asmc_sysctl_add_sms(device_t dev, struct sysctl_ctx_list *ctx)
-{
- struct asmc_softc *sc = device_get_softc(dev);
-
- sc->sc_sms_tree = SYSCTL_ADD_NODE(ctx,
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sms",
- CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor");
-
- for (unsigned int k = 0; k < nitems(asmc_sms_sysctls); k++) {
- SYSCTL_ADD_PROC(ctx,
- SYSCTL_CHILDREN(sc->sc_sms_tree),
- OID_AUTO, asmc_sms_sysctls[k].name,
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
- dev, k, asmc_mb_sysctl_sms, "I",
- asmc_sms_sysctls[k].desc);
- }
-}
/* Every key asmc_sms_init() touches; all must be present for SMS. */
static const char * const asmc_sms_required_keys[] = {
@@ -558,116 +206,8 @@
ASMC_KEY_INTOK,
};
-/* The ambient light sensors, selected by arg2. */
-#define ASMC_LIGHT_LEFT 0
-#define ASMC_LIGHT_RIGHT 1
-
-static const char * const asmc_light_keys[] = {
- [ASMC_LIGHT_LEFT] = ASMC_KEY_LIGHTLEFT,
- [ASMC_LIGHT_RIGHT] = ASMC_KEY_LIGHTRIGHT,
-};
-
-/* The dev.asmc.n.system leaves, in registration order; len_min 0 = any. */
-static const struct {
- const char *key;
- const char *name;
- const char *desc;
- const char *fmt;
- int ctlflags;
- int arg2;
- int (*handler)(SYSCTL_HANDLER_ARGS);
- uint8_t len_min;
- uint8_t len_max;
-} asmc_system_sysctls[] = {
- { ASMC_KEY_MSSD, "shutdown_cause", "Last shutdown cause (MSSD)",
- "A", CTLTYPE_STRING | CTLFLAG_RD, 0, asmc_cause_sysctl, 0, 0 },
- { ASMC_KEY_MSSP, "sleep_cause", "Last sleep cause (MSSP)",
- "A", CTLTYPE_STRING | CTLFLAG_RD, 1, asmc_cause_sysctl, 0, 0 },
- { ASMC_KEY_MSAL, "thermal_status",
- "Thermal subsystem status flags (MSAL)",
- "A", CTLTYPE_STRING | CTLFLAG_RD, 0, asmc_msal_sysctl, 0, 0 },
- { ASMC_KEY_CLKT, "time_of_day",
- "Seconds since midnight per SMC clock (CLKT)",
- "IU", CTLTYPE_UINT | CTLFLAG_RD, 0, asmc_clkt_sysctl, 0, 0 },
- { ASMC_KEY_MSPS, "power_state", "SMC power state index (MSPS)",
- "IU", CTLTYPE_UINT | CTLFLAG_RD, 0, asmc_msps_sysctl, 1, 2 },
- { ASMC_KEY_RPLT, "board_id", "Apple internal board codename (RPlt)",
- "A", CTLTYPE_STRING | CTLFLAG_RD, 0, asmc_rplt_sysctl, 0, 0 },
- { ASMC_KEY_RGEN, "chip_gen",
- "Apple security chip generation (RGEN; 3=T2)",
- "IU", CTLTYPE_UINT | CTLFLAG_RD, 0, asmc_rgen_sysctl, 0, 0 },
-};
-
-static int
-asmc_sysctl_add_system(device_t dev, struct sysctl_ctx_list *ctx)
-{
- struct sysctl_oid *sys_tree;
-
- sys_tree = SYSCTL_ADD_NODE(ctx,
- 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");
- return (ENXIO);
- }
-
- for (unsigned int k = 0; k < nitems(asmc_system_sysctls); k++) {
- uint8_t len = 0;
-
- if (asmc_key_getinfo(dev, asmc_system_sysctls[k].key,
- &len, NULL) != 0)
- continue;
- if (asmc_system_sysctls[k].len_min != 0 &&
- (len < asmc_system_sysctls[k].len_min ||
- len > asmc_system_sysctls[k].len_max))
- continue;
-
- /* SYSCTL_ADD_PROC() asserts flags at compile time. */
- sysctl_add_oid(ctx, SYSCTL_CHILDREN(sys_tree),
- OID_AUTO, asmc_system_sysctls[k].name,
- asmc_system_sysctls[k].ctlflags | CTLFLAG_MPSAFE,
- dev, asmc_system_sysctls[k].arg2,
- asmc_system_sysctls[k].handler,
- asmc_system_sysctls[k].fmt,
- asmc_system_sysctls[k].desc, NULL);
- }
-
- return (0);
-}
-
-/* Platform toggles under dev.asmc.n, each present only if its key reads. */
-static const struct {
- const char *key;
- const char *name;
- const char *desc;
- int (*handler)(SYSCTL_HANDLER_ARGS);
-} asmc_platform_sysctls[] = {
- { ASMC_KEY_AUPO, "auto_poweron",
- "Auto power-on after AC power loss (0=off, 1=on)",
- asmc_aupo_sysctl },
- { ASMC_KEY_MSLD, "sil", "Sleep indicator LED (0=off, 1=on)",
- asmc_sil_sysctl },
-};
-
-static void
-asmc_sysctl_add_platform(device_t dev, struct sysctl_ctx_list *ctx)
-{
- uint8_t buf[1];
- for (unsigned int k = 0; k < nitems(asmc_platform_sysctls); k++) {
- if (asmc_key_read(dev, asmc_platform_sysctls[k].key,
- buf, 1) != 0)
- continue;
- SYSCTL_ADD_PROC(ctx,
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, asmc_platform_sysctls[k].name,
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
- dev, 0, asmc_platform_sysctls[k].handler, "I",
- asmc_platform_sysctls[k].desc);
- }
-}
static int
asmc_attach(device_t dev)
@@ -702,60 +242,10 @@
asmc_detect_sensors(dev);
asmc_sysctl_add_fan(dev, sysctlctx);
+ asmc_sysctl_add_temp(dev, sysctlctx);
- /*
- * dev.asmc.n.temp tree.
- */
- sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
- SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
- CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors");
-
- for (int i = 0; i < sc->sc_temp_count; i++) {
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sc->sc_temp_tree),
- 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 (sc->sc_has_light) {
- sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
- SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
- CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
- "Keyboard backlight sensors");
-
- SYSCTL_ADD_PROC(sysctlctx,
- SYSCTL_CHILDREN(sc->sc_light_tree),
- OID_AUTO, "left",
- CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
- dev, ASMC_LIGHT_LEFT,
- sc->sc_light_len == ASMC_LIGHT_LONGLEN ?
- asmc_mbp_sysctl_light_left_10byte :
- asmc_mbp_sysctl_light,
- "I", "Keyboard backlight left 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, ASMC_LIGHT_RIGHT,
- asmc_mbp_sysctl_light, "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_MPSAFE,
- dev, 0, asmc_mbp_sysctl_light_control, "I",
- "Keyboard backlight brightness control");
+ asmc_sysctl_add_light(dev, sysctlctx);
sc->sc_kbd_bkl = backlight_register("asmc", dev);
if (sc->sc_kbd_bkl == NULL) {
@@ -1180,7 +670,7 @@
* Generic sensor value reader with automatic type conversion.
* Reads an SMC key, detects its type, and converts to millivalue.
*/
-static int
+int
asmc_sensor_read(device_t dev, const char *key, int *millivalue)
{
uint8_t buf[2];
@@ -1215,52 +705,6 @@
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));
-}
static bool
asmc_match_sp78(const char *key __unused, const char *type)
@@ -1517,232 +961,12 @@
return (buf[0]);
}
-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[4];
- char fankey[5];
- char type[ASMC_TYPELEN + 1];
- snprintf(fankey, sizeof(fankey), key, fan);
-
- /*
- * 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)
-{
- char fankey[5];
- char *desc;
-
- snprintf(fankey, sizeof(fankey), key, fan);
- if (asmc_key_read(dev, fankey, buf, buflen) != 0)
- return (NULL);
- desc = buf + 4;
-
- return (desc);
-}
-
-static int
-asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
-{
- struct asmc_softc *sc = device_get_softc(dev);
- uint8_t buf[4];
- char fankey[5];
- char type[ASMC_TYPELEN + 1];
-
- snprintf(fankey, sizeof(fankey), key, fan);
-
- 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);
-}
-
-static int
-asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
-{
- device_t dev = (device_t)arg1;
- int which = ASMC_FAN_ARG2_WHICH(arg2);
- int fan = ASMC_FAN_ARG2_FAN(arg2);
- int error;
- int32_t v;
-
- v = asmc_fan_getvalue(dev, asmc_fan_speed_keys[which].key, fan);
- error = sysctl_handle_int(oidp, &v, 0, req);
-
- if (error == 0 && req->newptr != NULL &&
- asmc_fan_speed_keys[which].writable) {
- unsigned int newspeed = v;
- asmc_fan_setvalue(dev, asmc_fan_speed_keys[which].key, fan,
- newspeed);
- }
-
- return (error);
-}
-
-static int
-asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
-{
- uint8_t buf[16];
- device_t dev = (device_t)arg1;
- int fan = ASMC_FAN_ARG2_FAN(arg2);
- int error = true;
- char *desc;
-
- desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
-
- if (desc != NULL)
- error = sysctl_handle_string(oidp, desc, 0, req);
-
- 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 = ASMC_FAN_ARG2_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.
- */
-static int
-asmc_temp_getvalue(device_t dev, const char *key)
-{
- uint8_t buf[2];
-
- /*
- * Check for invalid temperatures.
- */
- if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0)
- return (-1);
-
- return (buf[0]);
-}
-
-static int
-asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
-{
- device_t dev = (device_t)arg1;
- struct asmc_softc *sc = device_get_softc(dev);
- int error, val;
-
- 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);
-}
/*
* Sudden Motion Sensor functions.
*/
-static int
+int
asmc_sms_read(device_t dev, const char *key, int16_t *val)
{
uint8_t buf[2];
@@ -1853,150 +1077,7 @@
devctl_notify("ACPI", "asmc", "SMS", notify);
}
-static int
-asmc_mb_sysctl_sms(SYSCTL_HANDLER_ARGS)
-{
- device_t dev = (device_t)arg1;
- int error;
- int16_t val;
- int32_t v;
-
- asmc_sms_read(dev, asmc_sms_sysctls[arg2].key, &val);
- v = (int32_t)val;
- error = sysctl_handle_int(oidp, &v, 0, req);
-
- return (error);
-}
-
-static int
-asmc_mbp_sysctl_light(SYSCTL_HANDLER_ARGS)
-{
- device_t dev = (device_t)arg1;
- uint8_t buf[6];
- int error;
- int32_t v;
-
- asmc_key_read(dev, asmc_light_keys[arg2], buf, sizeof(buf));
- v = buf[2];
- error = sysctl_handle_int(oidp, &v, 0, req);
-
- return (error);
-}
-
-static int
-asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
-{
- device_t dev = (device_t)arg1;
- struct asmc_softc *sc = device_get_softc(dev);
- uint8_t buf[2];
- int error;
- int v;
-
- v = sc->sc_light_control;
- error = sysctl_handle_int(oidp, &v, 0, req);
-
- if (error == 0 && req->newptr != NULL) {
- if (v < 0 || v > 255)
- return (EINVAL);
- sc->sc_light_control = v;
- sc->sc_kbd_bkl_level = v * 100 / 255;
- buf[0] = sc->sc_light_control;
- buf[1] = 0x00;
- asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
- }
- return (error);
-}
-
-static int
-asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
-{
- 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));
-
- /*
- * This seems to be a 32 bit big endian value from buf[6] -> buf[9].
- *
- * Extract it out manually here, then shift/clamp it.
- */
- v = be32dec(&buf[6]);
-
- /*
- * Shift out, clamp at 255; that way it looks like the
- * earlier SMC firmware version responses.
- */
- v = v >> 8;
- if (v > 255)
- v = 255;
-
- error = sysctl_handle_int(oidp, &v, 0, req);
-
- 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);
-}
-
-/* Sleep Indicator LED (SIL) control; see ASMC_KEY_MSLD/MSLS in asmcvar.h. */
-static int
-asmc_sil_sysctl(SYSCTL_HANDLER_ARGS)
-{
- device_t dev = (device_t)arg1;
- uint8_t msld;
- int val, error;
- if (asmc_key_read(dev, ASMC_KEY_MSLD, &msld, 1) != 0)
- return (EIO);
-
- /* MSLD 0xff means off, anything else means on */
- val = (msld != 0xff) ? 1 : 0;
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error != 0 || req->newptr == NULL)
- return (error);
-
- if (val != 0) {
- /* Turn on: unlatch MSLS first, then set MSLD duty */
- uint8_t msls = 0x01;
- if (asmc_key_write(dev, ASMC_KEY_MSLS, &msls, 1) != 0)
- return (EIO);
- msld = 0x01;
- } else {
- /* Turn off: just set MSLD to 0xff */
- msld = 0xff;
- }
-
- if (asmc_key_write(dev, ASMC_KEY_MSLD, &msld, 1) != 0)
- return (EIO);
-
- return (0);
-}
static int
asmc_backlight_update_status(device_t dev, struct backlight_props *props)
@@ -2033,129 +1114,3 @@
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/asmcsysctl.h b/sys/dev/asmc/asmcsysctl.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/asmc/asmcsysctl.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <seuros@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _DEV_ASMC_ASMCSYSCTL_H_
+#define _DEV_ASMC_ASMCSYSCTL_H_
+
+/*
+ * Sysctl subtree builders, one per dev.asmc.N node. asmc_attach() calls these
+ * in registration order; only add_system can fail, and only because the key
+ * count it reads is what tells the rest of the driver the SMC is there.
+ */
+void asmc_sysctl_add_fan(device_t dev, struct sysctl_ctx_list *ctx);
+void asmc_sysctl_add_temp(device_t dev, struct sysctl_ctx_list *ctx);
+void asmc_sysctl_add_light(device_t dev, struct sysctl_ctx_list *ctx);
+void asmc_sysctl_add_sms(device_t dev, struct sysctl_ctx_list *ctx);
+int asmc_sysctl_add_system(device_t dev, struct sysctl_ctx_list *ctx);
+void asmc_sysctl_add_platform(device_t dev, struct sysctl_ctx_list *ctx);
+
+/* Registered by the core's sensor range scan, one OID per detected key. */
+int asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS);
+
+#endif /* _DEV_ASMC_ASMCSYSCTL_H_ */
diff --git a/sys/dev/asmc/asmcsysctl.c b/sys/dev/asmc/asmcsysctl.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/asmc/asmcsysctl.c
@@ -0,0 +1,1147 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <seuros@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Sysctl layer for Apple SMC.
+ *
+ * The dev.asmc.N tree: the leaf tables, the registration helpers asmc_attach()
+ * calls to build each subtree, and the handlers behind them. Everything here
+ * reaches the hardware through the key transport in asmc.c.
+ */
+
+#include "opt_asmc.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.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 <dev/asmc/asmcvar.h>
+#include <dev/asmc/asmcmmio.h>
+#include <dev/asmc/asmcsysctl.h>
+
+/*
+ * 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_CAUSE_BUFLEN 48 /* "-128 (temperature-overlimit-timeout)\0" */
+
+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 },
+};
+
+/*
+ * Sysctl handlers.
+ */
+static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
+static int asmc_mb_sysctl_fanspeed(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(SYSCTL_HANDLER_ARGS);
+static int asmc_mbp_sysctl_light(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);
+static int asmc_sil_sysctl(SYSCTL_HANDLER_ARGS);
+
+/* 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);
+
+static const char *asmc_temp_desc(const char *key);
+
+/*
+ * 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" },
+};
+
+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");
+}
+
+void
+asmc_sysctl_add_temp(device_t dev, struct sysctl_ctx_list *ctx)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+
+ sc->sc_temp_tree = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "temp",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors");
+
+ for (int i = 0; i < sc->sc_temp_count; i++) {
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(sc->sc_temp_tree),
+ 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]));
+ }
+}
+
+/*
+ * The per-fan speed keys, selected by the high byte of a fan sysctl's arg2.
+ * Writable keys accept a new speed; the rest are reported only.
+ */
+#define ASMC_FAN_ARG2(which, fan) (((which) << 8) | (fan))
+#define ASMC_FAN_ARG2_WHICH(arg2) (((arg2) >> 8) & 0xff)
+#define ASMC_FAN_ARG2_FAN(arg2) ((arg2) & 0xff)
+
+#define ASMC_FANSPEED_CUR 0
+#define ASMC_FANSPEED_SAFE 1
+#define ASMC_FANSPEED_MIN 2
+#define ASMC_FANSPEED_MAX 3
+#define ASMC_FANSPEED_TARGET 4
+
+static const struct {
+ const char *key;
+ bool writable;
+} asmc_fan_speed_keys[] = {
+ [ASMC_FANSPEED_CUR] = { ASMC_KEY_FANSPEED, false },
+ [ASMC_FANSPEED_SAFE] = { ASMC_KEY_FANSAFESPEED, false },
+ [ASMC_FANSPEED_MIN] = { ASMC_KEY_FANMINSPEED, true },
+ [ASMC_FANSPEED_MAX] = { ASMC_KEY_FANMAXSPEED, true },
+ [ASMC_FANSPEED_TARGET] = { ASMC_KEY_FANTARGETSPEED, true },
+};
+
+/* The dev.asmc.n.fan.m leaves, in registration order. */
+static const struct {
+ const char *name;
+ const char *desc;
+ int ctlflags;
+ int (*handler)(SYSCTL_HANDLER_ARGS);
+ int which;
+ bool needs_safespeed;
+} asmc_fan_sysctls[] = {
+ { "id", "Fan ID", CTLTYPE_STRING | CTLFLAG_RD,
+ asmc_mb_sysctl_fanid, 0, false },
+ { "speed", "Fan speed in RPM", CTLTYPE_INT | CTLFLAG_RD,
+ asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_CUR, false },
+ { "safespeed", "Fan safe speed in RPM", CTLTYPE_INT | CTLFLAG_RD,
+ asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_SAFE, true },
+ { "minspeed", "Fan minimum speed in RPM", CTLTYPE_INT | CTLFLAG_RW,
+ asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_MIN, false },
+ { "maxspeed", "Fan maximum speed in RPM", CTLTYPE_INT | CTLFLAG_RW,
+ asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_MAX, false },
+ { "targetspeed", "Fan target speed in RPM", CTLTYPE_INT | CTLFLAG_RW,
+ asmc_mb_sysctl_fanspeed, ASMC_FANSPEED_TARGET, false },
+ { "manual", "Fan manual mode (0=auto, 1=manual)",
+ CTLTYPE_INT | CTLFLAG_RW, asmc_mb_sysctl_fanmanual, 0, false },
+};
+
+void
+asmc_sysctl_add_fan(device_t dev, struct sysctl_ctx_list *ctx)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ char name[2];
+
+ sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fan",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree");
+
+ for (int i = 1; i <= sc->sc_nfan; i++) {
+ int j = i - 1;
+
+ name[0] = '0' + j;
+ name[1] = 0;
+ sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name,
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree");
+
+ for (unsigned int k = 0; k < nitems(asmc_fan_sysctls); k++) {
+ if (asmc_fan_sysctls[k].needs_safespeed &&
+ !sc->sc_has_safespeed)
+ continue;
+
+ /* SYSCTL_ADD_PROC() asserts flags at compile time. */
+ sysctl_add_oid(ctx,
+ SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
+ OID_AUTO, asmc_fan_sysctls[k].name,
+ asmc_fan_sysctls[k].ctlflags | CTLFLAG_MPSAFE,
+ dev, ASMC_FAN_ARG2(asmc_fan_sysctls[k].which, j),
+ asmc_fan_sysctls[k].handler, "I",
+ asmc_fan_sysctls[k].desc, NULL);
+ }
+ }
+}
+
+/* The dev.asmc.n.sms axes, selected by arg2. */
+static const struct {
+ const char *name;
+ const char *key;
+ const char *desc;
+} asmc_sms_sysctls[] = {
+ { "x", ASMC_KEY_SMS_X, "Sudden Motion Sensor X value" },
+ { "y", ASMC_KEY_SMS_Y, "Sudden Motion Sensor Y value" },
+ { "z", ASMC_KEY_SMS_Z, "Sudden Motion Sensor Z value" },
+};
+
+void
+asmc_sysctl_add_sms(device_t dev, struct sysctl_ctx_list *ctx)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+
+ sc->sc_sms_tree = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sms",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor");
+
+ for (unsigned int k = 0; k < nitems(asmc_sms_sysctls); k++) {
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(sc->sc_sms_tree),
+ OID_AUTO, asmc_sms_sysctls[k].name,
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, k, asmc_mb_sysctl_sms, "I",
+ asmc_sms_sysctls[k].desc);
+ }
+}
+
+/* The ambient light sensors, selected by arg2. */
+#define ASMC_LIGHT_LEFT 0
+#define ASMC_LIGHT_RIGHT 1
+
+static const char * const asmc_light_keys[] = {
+ [ASMC_LIGHT_LEFT] = ASMC_KEY_LIGHTLEFT,
+ [ASMC_LIGHT_RIGHT] = ASMC_KEY_LIGHTRIGHT,
+};
+
+void
+asmc_sysctl_add_light(device_t dev, struct sysctl_ctx_list *ctx)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+
+ sc->sc_light_tree = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "light",
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "Keyboard backlight sensors");
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(sc->sc_light_tree),
+ OID_AUTO, "left",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, ASMC_LIGHT_LEFT,
+ sc->sc_light_len == ASMC_LIGHT_LONGLEN ?
+ asmc_mbp_sysctl_light_left_10byte :
+ asmc_mbp_sysctl_light,
+ "I", "Keyboard backlight left sensor");
+
+ if (sc->sc_light_len != ASMC_LIGHT_LONGLEN &&
+ asmc_key_getinfo(dev, ASMC_KEY_LIGHTRIGHT,
+ NULL, NULL) == 0) {
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(sc->sc_light_tree),
+ OID_AUTO, "right",
+ CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ dev, ASMC_LIGHT_RIGHT,
+ asmc_mbp_sysctl_light, "I",
+ "Keyboard backlight right sensor");
+ }
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(sc->sc_light_tree),
+ OID_AUTO, "control",
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
+ dev, 0, asmc_mbp_sysctl_light_control, "I",
+ "Keyboard backlight brightness control");
+}
+
+/* The dev.asmc.n.system leaves, in registration order; len_min 0 = any. */
+static const struct {
+ const char *key;
+ const char *name;
+ const char *desc;
+ const char *fmt;
+ int ctlflags;
+ int arg2;
+ int (*handler)(SYSCTL_HANDLER_ARGS);
+ uint8_t len_min;
+ uint8_t len_max;
+} asmc_system_sysctls[] = {
+ { ASMC_KEY_MSSD, "shutdown_cause", "Last shutdown cause (MSSD)",
+ "A", CTLTYPE_STRING | CTLFLAG_RD, 0, asmc_cause_sysctl, 0, 0 },
+ { ASMC_KEY_MSSP, "sleep_cause", "Last sleep cause (MSSP)",
+ "A", CTLTYPE_STRING | CTLFLAG_RD, 1, asmc_cause_sysctl, 0, 0 },
+ { ASMC_KEY_MSAL, "thermal_status",
+ "Thermal subsystem status flags (MSAL)",
+ "A", CTLTYPE_STRING | CTLFLAG_RD, 0, asmc_msal_sysctl, 0, 0 },
+ { ASMC_KEY_CLKT, "time_of_day",
+ "Seconds since midnight per SMC clock (CLKT)",
+ "IU", CTLTYPE_UINT | CTLFLAG_RD, 0, asmc_clkt_sysctl, 0, 0 },
+ { ASMC_KEY_MSPS, "power_state", "SMC power state index (MSPS)",
+ "IU", CTLTYPE_UINT | CTLFLAG_RD, 0, asmc_msps_sysctl, 1, 2 },
+ { ASMC_KEY_RPLT, "board_id", "Apple internal board codename (RPlt)",
+ "A", CTLTYPE_STRING | CTLFLAG_RD, 0, asmc_rplt_sysctl, 0, 0 },
+ { ASMC_KEY_RGEN, "chip_gen",
+ "Apple security chip generation (RGEN; 3=T2)",
+ "IU", CTLTYPE_UINT | CTLFLAG_RD, 0, asmc_rgen_sysctl, 0, 0 },
+};
+
+int
+asmc_sysctl_add_system(device_t dev, struct sysctl_ctx_list *ctx)
+{
+ struct sysctl_oid *sys_tree;
+
+ sys_tree = SYSCTL_ADD_NODE(ctx,
+ 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");
+ return (ENXIO);
+ }
+
+ for (unsigned int k = 0; k < nitems(asmc_system_sysctls); k++) {
+ uint8_t len = 0;
+
+ if (asmc_key_getinfo(dev, asmc_system_sysctls[k].key,
+ &len, NULL) != 0)
+ continue;
+ if (asmc_system_sysctls[k].len_min != 0 &&
+ (len < asmc_system_sysctls[k].len_min ||
+ len > asmc_system_sysctls[k].len_max))
+ continue;
+
+ /* SYSCTL_ADD_PROC() asserts flags at compile time. */
+ sysctl_add_oid(ctx, SYSCTL_CHILDREN(sys_tree),
+ OID_AUTO, asmc_system_sysctls[k].name,
+ asmc_system_sysctls[k].ctlflags | CTLFLAG_MPSAFE,
+ dev, asmc_system_sysctls[k].arg2,
+ asmc_system_sysctls[k].handler,
+ asmc_system_sysctls[k].fmt,
+ asmc_system_sysctls[k].desc, NULL);
+ }
+
+ return (0);
+}
+
+/* Platform toggles under dev.asmc.n, each present only if its key reads. */
+static const struct {
+ const char *key;
+ const char *name;
+ const char *desc;
+ int (*handler)(SYSCTL_HANDLER_ARGS);
+} asmc_platform_sysctls[] = {
+ { ASMC_KEY_AUPO, "auto_poweron",
+ "Auto power-on after AC power loss (0=off, 1=on)",
+ asmc_aupo_sysctl },
+ { ASMC_KEY_MSLD, "sil", "Sleep indicator LED (0=off, 1=on)",
+ asmc_sil_sysctl },
+};
+
+void
+asmc_sysctl_add_platform(device_t dev, struct sysctl_ctx_list *ctx)
+{
+ uint8_t buf[1];
+
+ for (unsigned int k = 0; k < nitems(asmc_platform_sysctls); k++) {
+ if (asmc_key_read(dev, asmc_platform_sysctls[k].key,
+ buf, 1) != 0)
+ continue;
+
+ SYSCTL_ADD_PROC(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, asmc_platform_sysctls[k].name,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ dev, 0, asmc_platform_sysctls[k].handler, "I",
+ asmc_platform_sysctls[k].desc);
+ }
+}
+
+/*
+ * 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
+ */
+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));
+}
+
+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[4];
+ char fankey[5];
+ char type[ASMC_TYPELEN + 1];
+
+ snprintf(fankey, sizeof(fankey), key, fan);
+
+ /*
+ * 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)
+{
+ char fankey[5];
+ char *desc;
+
+ snprintf(fankey, sizeof(fankey), key, fan);
+ if (asmc_key_read(dev, fankey, buf, buflen) != 0)
+ return (NULL);
+ desc = buf + 4;
+
+ return (desc);
+}
+
+static int
+asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
+{
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t buf[4];
+ char fankey[5];
+ char type[ASMC_TYPELEN + 1];
+
+ snprintf(fankey, sizeof(fankey), key, fan);
+
+ 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);
+}
+
+static int
+asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ int which = ASMC_FAN_ARG2_WHICH(arg2);
+ int fan = ASMC_FAN_ARG2_FAN(arg2);
+ int error;
+ int32_t v;
+
+ v = asmc_fan_getvalue(dev, asmc_fan_speed_keys[which].key, fan);
+ error = sysctl_handle_int(oidp, &v, 0, req);
+
+ if (error == 0 && req->newptr != NULL &&
+ asmc_fan_speed_keys[which].writable) {
+ unsigned int newspeed = v;
+ asmc_fan_setvalue(dev, asmc_fan_speed_keys[which].key, fan,
+ newspeed);
+ }
+
+ return (error);
+}
+
+static int
+asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
+{
+ uint8_t buf[16];
+ device_t dev = (device_t)arg1;
+ int fan = ASMC_FAN_ARG2_FAN(arg2);
+ int error = true;
+ char *desc;
+
+ desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
+
+ if (desc != NULL)
+ error = sysctl_handle_string(oidp, desc, 0, req);
+
+ 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 = ASMC_FAN_ARG2_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.
+ */
+static int
+asmc_temp_getvalue(device_t dev, const char *key)
+{
+ uint8_t buf[2];
+
+ /*
+ * Check for invalid temperatures.
+ */
+ if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0)
+ return (-1);
+
+ return (buf[0]);
+}
+
+static int
+asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+ int error, val;
+
+ 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);
+}
+
+static int
+asmc_mb_sysctl_sms(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ int error;
+ int16_t val;
+ int32_t v;
+
+ asmc_sms_read(dev, asmc_sms_sysctls[arg2].key, &val);
+ v = (int32_t)val;
+ error = sysctl_handle_int(oidp, &v, 0, req);
+
+ return (error);
+}
+
+static int
+asmc_mbp_sysctl_light(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t buf[6];
+ int error;
+ int32_t v;
+
+ asmc_key_read(dev, asmc_light_keys[arg2], buf, sizeof(buf));
+ v = buf[2];
+ error = sysctl_handle_int(oidp, &v, 0, req);
+
+ return (error);
+}
+
+static int
+asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ struct asmc_softc *sc = device_get_softc(dev);
+ uint8_t buf[2];
+ int error;
+ int v;
+
+ v = sc->sc_light_control;
+ error = sysctl_handle_int(oidp, &v, 0, req);
+
+ if (error == 0 && req->newptr != NULL) {
+ if (v < 0 || v > 255)
+ return (EINVAL);
+ sc->sc_light_control = v;
+ sc->sc_kbd_bkl_level = v * 100 / 255;
+ buf[0] = sc->sc_light_control;
+ buf[1] = 0x00;
+ asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
+ }
+ return (error);
+}
+
+static int
+asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
+{
+ 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));
+
+ /*
+ * This seems to be a 32 bit big endian value from buf[6] -> buf[9].
+ *
+ * Extract it out manually here, then shift/clamp it.
+ */
+ v = be32dec(&buf[6]);
+
+ /*
+ * Shift out, clamp at 255; that way it looks like the
+ * earlier SMC firmware version responses.
+ */
+ v = v >> 8;
+ if (v > 255)
+ v = 255;
+
+ error = sysctl_handle_int(oidp, &v, 0, req);
+
+ 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);
+}
+
+/* Sleep Indicator LED (SIL) control; see ASMC_KEY_MSLD/MSLS in asmcvar.h. */
+static int
+asmc_sil_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t)arg1;
+ uint8_t msld;
+ int val, error;
+
+ if (asmc_key_read(dev, ASMC_KEY_MSLD, &msld, 1) != 0)
+ return (EIO);
+
+ /* MSLD 0xff means off, anything else means on */
+ val = (msld != 0xff) ? 1 : 0;
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ if (val != 0) {
+ /* Turn on: unlatch MSLS first, then set MSLD duty */
+ uint8_t msls = 0x01;
+ if (asmc_key_write(dev, ASMC_KEY_MSLS, &msls, 1) != 0)
+ return (EIO);
+ msld = 0x01;
+ } else {
+ /* Turn off: just set MSLD to 0xff */
+ msld = 0xff;
+ }
+
+ if (asmc_key_write(dev, ASMC_KEY_MSLD, &msld, 1) != 0)
+ return (EIO);
+
+ 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/asmcvar.h b/sys/dev/asmc/asmcvar.h
--- a/sys/dev/asmc/asmcvar.h
+++ b/sys/dev/asmc/asmcvar.h
@@ -248,59 +248,6 @@
#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_CAUSE_BUFLEN 48 /* "-128 (temperature-overlimit-timeout)\0" */
-
-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 },
-};
-
/*
* SMC key transport, implemented in asmc.c on top of the PIO and MMIO
* backends.
@@ -312,3 +259,7 @@
char *type);
int asmc_key_dump_by_index(device_t dev, int index, char *key, char *type,
uint8_t *len);
+
+/* Key readers shared with the sysctl layer. */
+int asmc_sms_read(device_t dev, const char *key, int16_t *val);
+int asmc_sensor_read(device_t dev, const char *key, int *millivalue);
diff --git a/sys/modules/asmc/Makefile b/sys/modules/asmc/Makefile
--- a/sys/modules/asmc/Makefile
+++ b/sys/modules/asmc/Makefile
@@ -1,7 +1,7 @@
.PATH: ${SRCTOP}/sys/dev/asmc
KMOD= asmc
-SRCS= asmc.c asmcmmio.c asmcpio.c opt_acpi.h opt_asmc.h
+SRCS= asmc.c asmcmmio.c asmcpio.c asmcsysctl.c opt_acpi.h opt_asmc.h
SRCS+= acpi_if.h backlight_if.h bus_if.h device_if.h
.if defined(ASMC_DEBUG)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 8, 11:33 PM (4 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41595933
Default Alt Text
D61300.1794180781.diff (67 KB)
Attached To
Mode
D61300: asmc: split the sysctl layer into asmcsysctl.c
Attached
Detach File
Event Timeline