/*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2007, 2008 Rui Paulo * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #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; struct sysctl_oid *sc_fan_tree[ASMC_MAXFANS+1]; struct sysctl_oid *sc_temp_tree; struct sysctl_oid *sc_sms_tree; struct sysctl_oid *sc_light_tree; 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 */ }; /* * Data port. */ #define ASMC_DATAPORT_READ(sc) bus_read_1(sc->sc_ioport, 0x00) #define ASMC_DATAPORT_WRITE(sc, val) \ bus_write_1(sc->sc_ioport, 0x00, val) #define ASMC_STATUS_MASK 0x0f /* * Command port. */ #define ASMC_CMDPORT_READ(sc) bus_read_1(sc->sc_ioport, 0x04) #define ASMC_CMDPORT_WRITE(sc, val) \ 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. */ #define ASMC_INTPORT_READ(sc) bus_read_1(sc->sc_ioport, 0x1f) /* 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. */ #define ASMC_KEY_FANCOUNT "FNum" /* RO; 1 byte */ #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" /* 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 */ /* * Sudden Motion Sensor (SMS). */ #define ASMC_SMS_INIT1 0xe0 #define ASMC_SMS_INIT2 0xf8 #define ASMC_KEY_SMS "MOCN" /* RW; 2 bytes */ #define ASMC_KEY_SMS_X "MO_X" /* RO; 2 bytes */ #define ASMC_KEY_SMS_Y "MO_Y" /* RO; 2 bytes */ #define ASMC_KEY_SMS_Z "MO_Z" /* RO; 2 bytes */ #define ASMC_KEY_SMS_LOW "MOLT" /* RW; 2 bytes */ #define ASMC_KEY_SMS_HIGH "MOHT" /* RW; 2 bytes */ #define ASMC_KEY_SMS_LOW_INT "MOLD" /* RW; 1 byte */ #define ASMC_KEY_SMS_HIGH_INT "MOHD" /* RW; 1 byte */ #define ASMC_KEY_SMS_FLAG "MSDW" /* RW; 1 byte */ #define ASMC_SMS_INTFF 0x60 /* Free fall Interrupt */ #define ASMC_SMS_INTHA 0x6f /* High Acceleration Interrupt */ #define ASMC_SMS_INTSH 0x80 /* Shock Interrupt */ /* * Light Sensor. */ #define ASMC_ALSL_INT2A 0x2a /* Ambient Light related Interrupt */ /* * Keyboard backlight. */ #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 */ /* * Sleep Indicator LED (SIL). * * MSLD controls the duty cycle of the front-panel sleep indicator LED. * 0x00 = LED at idle brightness, 0xff = LED fully off. * MSLS is the SIL state latch — must be written to 0x01 before MSLD * can re-enable the LED after it has been turned off. * * Protocol: OFF = write MSLD 0xff * ON = write MSLS 0x01, then write MSLD 0x01 * * Present on all Intel Macs with a sleep indicator (laptops + Mac Mini). */ #define ASMC_KEY_MSLD "MSLD" /* RW; 1 byte, SIL duty */ #define ASMC_KEY_MSLS "MSLS" /* RW; 1 byte, SIL state latch */ /* * 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 */ /* * 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) */ #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_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 */ /* * Board identity keys. * * RPlt - board platform identifier (e.g. "Mac-XXXX") * RGEN - security chip generation (3 = T2) */ #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_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 }, };