This is an initial driver for the Apple System Management Controller
found in Intel based Apple computers.
The driver is currently missing support for the Sudden Motion Sensor
(SMS), light sensor, and keyboard backlight since I don't have that
hardware available to develop on.
On my iMac11,2 it can deliver fan and temperatures values:
hw.sensors.acpiapplesmc0.temp0=24.00 degC (Airflow 1)
hw.sensors.acpiapplesmc0.temp1=33.00 degC (CPU Core 0)
hw.sensors.acpiapplesmc0.temp2=36.00 degC (CPU Heatsink)
hw.sensors.acpiapplesmc0.temp3=40.00 degC (CPU Core 1)
hw.sensors.acpiapplesmc0.temp4=47.00 degC (GPU)
hw.sensors.acpiapplesmc0.temp5=45.00 degC (GPU Heatsink)
hw.sensors.acpiapplesmc0.temp6=59.00 degC (PCH)
hw.sensors.acpiapplesmc0.temp7=42.00 degC (Memory)
hw.sensors.acpiapplesmc0.temp8=45.00 degC (Mainboard Proximity)
hw.sensors.acpiapplesmc0.fan0=998 RPM
hw.sensors.acpiapplesmc0.fan1=1132 RPM
hw.sensors.acpiapplesmc0.fan2=1198 RPM
Feedback, testers, OKs?
Index: share/man/man4/Makefile
===================================================================
RCS file: /cvs/src/share/man/man4/Makefile,v
retrieving revision 1.782
diff -u -p -u -p -r1.782 Makefile
--- share/man/man4/Makefile 25 Jun 2020 12:26:31 -0000 1.782
+++ share/man/man4/Makefile 7 Sep 2020 04:54:57 -0000
@@ -1,7 +1,7 @@
# $OpenBSD: Makefile,v 1.782 2020/06/25 12:26:31 patrick Exp $
MAN= aac.4 abcrtc.4 ac97.4 acphy.4 acrtc.4 \
- acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \
+ acpi.4 acpiac.4 acpials.4 acpiapplesmc.4 acpiasus.4 acpibat.4 \
acpibtn.4 acpicbkbd.4 acpicpu.4 acpidock.4 acpihve.4 acpiec.4 \
acpihid.4 \
acpihpet.4 acpimadt.4 acpimcfg.4 acpipci.4 acpiprt.4 acpipwrres.4 \
Index: share/man/man4/acpiapplesmc.4
===================================================================
RCS file: share/man/man4/acpiapplesmc.4
diff -N share/man/man4/acpiapplesmc.4
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ share/man/man4/acpiapplesmc.4 7 Sep 2020 04:54:57 -0000
@@ -0,0 +1,63 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2020 Marcus Glocker <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: September 07 2020 $
+.Dt APPLESMC 4
+.Os
+.Sh NAME
+.Nm acpiapplesmc
+.Nd Apple System Management Controller
+.Sh SYNOPSIS
+.Cd "acpiapplesmc* at acpi?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the Apple System Management Controller chipsets
+found in Intel based Apple computers. The sensors are exposed through the
+.Xr sysctl 8
+interface.
+.Pp
+The currently supported sensors are:
+.Bl -column "CPU power cons." "Units" "Typical Use" -offset indent
+.It Sy "Sensor" Ta Sy "Units" Ta Sy "Typical Use"
+.It Li "F?Ac" Ta "RPM" Ta "Fan"
+.It Li "TA0P" Ta "degC" Ta "Airflow 1"
+.It Li "TC0C" Ta "degC" Ta "CPU Core 0"
+.It Li "TC0H" Ta "degC" Ta "CPU Heatsink"
+.It Li "TC1C" Ta "degC" Ta "CPU Core 1"
+.It Li "TG0D" Ta "degC" Ta "GPU"
+.It Li "TG0H" Ta "degC" Ta "GPU Heatsink"
+.It Li "TPCD" Ta "degC" Ta "PCH"
+.It Li "Tm0P" Ta "degC" Ta "Memory"
+.It Li "Tm1P" Ta "degC" Ta "Mainboard Proximity"
+.El
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr sensorsd 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 6.8 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Marcus Glocker Aq Mt [email protected] .
+.Sh CAVEATS
+The driver is currently missing support for the Sudden Motion Sensor (SMS),
+light sensor, and keyboard backlight.
Index: sys/dev/acpi/acpiapplesmc.c
===================================================================
RCS file: sys/dev/acpi/acpiapplesmc.c
diff -N sys/dev/acpi/acpiapplesmc.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/acpi/acpiapplesmc.c 7 Sep 2020 04:54:57 -0000
@@ -0,0 +1,661 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2020 Marcus Glocker <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Driver for the System Management Controller (SMC).
+ *
+ * The documentation to write this driver was found in the FreeBSD asmc and
+ * Linux applesmc driver.
+ *
+ * TODO:
+ * - Add support for Sudden Motion Sensor (SMS).
+ * - Add support for light sensor.
+ * - Add support for keyboard backlight.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#define ACPIAPPLESMC_DEBUG
+#ifdef ACPIAPPLESMC_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+#define APPLESMC_PORT_DATA 0x00
+#define APPLESMC_PORT_CMD 0x04
+
+#define APLLESMC_WAITACK_WRITE 0x04
+#define APLLESMC_WAITACK_READ 0x05
+#define APPLESMC_WAITACK_CMD 0x0C
+#define APPLESMC_WAITACK_RETRY 1600
+
+#define APPLESMC_CMD_KEY_READ 0x10
+#define APPLESMC_CMD_KEY_WRITE 0x11
+#define APPLESMC_CMD_KEY_GET_BY_INDEX 0x12
+#define APPLESMC_CMD_KEY_GET_TYPE 0x13
+#define APPLESMC_CMD_RETRY 10
+
+#define APPLESMC_KEY_LEN 4
+#define APPLESMC_KEY_TYPE_LEN 6
+#define APPLESMC_KEY_COUNT "#KEY"
+#define APPLESMC_KEY_FANCOUNT "FNum"
+#define APPLESMC_KEY_FANSPEED "F%dAc"
+
+#define APPLESMC_MAX_KEY 1024
+#define APPLESMC_MAX_FAN 8
+#define APPLESMC_MAX_TEMP 16
+
+/* List of known temperature sensors. */
+const struct {
+ char *key;
+ char *desc;
+} acpiapplesmc_temp_desc[] = {
+ { "TA0P", "Airflow 1" },
+ { "TC0C", "CPU Core 0" },
+ { "TC0H", "CPU Heatsink" },
+ { "TC1C", "CPU Core 1" },
+ { "TG0D", "GPU" },
+ { "TG0H", "GPU Heatsink" },
+ { "TPCD", "PCH" },
+ { "Tm0P", "Memory" },
+ { "Tm1P", "Mainboard Proximity" },
+ { NULL, NULL }
+};
+
+/* Key entry. */
+struct acpiapplesmc_key {
+ char key[5];
+ char type[5];
+ uint8_t len;
+ uint8_t flags;
+ uint8_t temp_use;
+};
+
+struct acpiapplesmc_softc {
+ struct device sc_dev;
+
+ struct acpi_softc *sc_acpi;
+ struct aml_node *sc_devnode;
+
+ bus_space_tag_t sc_bt;
+ bus_space_handle_t sc_bh;
+
+ struct ksensor sc_sens[APPLESMC_MAX_FAN + APPLESMC_MAX_TEMP];
+ struct ksensordev sc_sensdev;
+
+ uint32_t sc_key_count;
+ uint8_t sc_fan_count;
+ uint8_t sc_temp_count;
+ uint8_t sc_temp_count_total;
+ int sc_keys_init;
+ struct acpiapplesmc_key sc_keys[APPLESMC_MAX_KEY];
+};
+
+int acpiapplesmc_match(struct device *, void *, void *);
+void acpiapplesmc_attach(struct device *, struct device *, void *);
+int acpiapplesmc_notify(struct aml_node *, int, void *);
+int acpiapplesmc_activate(struct device *, int);
+
+int acpiapplesmc_waitack(struct acpiapplesmc_softc *,
+ const uint8_t);
+int acpiapplesmc_cmd(struct acpiapplesmc_softc *,
+ const uint8_t);
+int acpiapplesmc_key_read(struct acpiapplesmc_softc *,
+ const char *, char *, const uint8_t);
+int acpiapplesmc_key_write(struct acpiapplesmc_softc *,
+ const char *, const char *, const uint8_t);
+int acpiapplesmc_key_get_byindex(struct acpiapplesmc_softc *,
+ const uint32_t, char *);
+int acpiapplesmc_key_get_type(struct acpiapplesmc_softc *,
+ const char *, char *);
+int acpiapplesmc_key_count(struct acpiapplesmc_softc *,
+ uint32_t *);
+int acpiapplesmc_key_get_entry(struct acpiapplesmc_softc *,
+ const int, struct acpiapplesmc_key *);
+int acpiapplesmc_key_init(struct acpiapplesmc_softc *,
+ const int);
+int acpiapplesmc_fan_count(struct acpiapplesmc_softc *,
+ uint8_t *);
+int acpiapplesmc_fan_get_value(struct acpiapplesmc_softc *,
+ const char *, const uint8_t, uint16_t *);
+int acpiapplesmc_temp_count_total(struct acpiapplesmc_softc *,
+ uint8_t *);
+int acpiapplesmc_temp_init(struct acpiapplesmc_softc *,
+ uint8_t *);
+int acpiapplesmc_temp_get_value(struct acpiapplesmc_softc *,
+ const char *, uint8_t *);
+int acpiapplesmc_temp_get_desc(struct acpiapplesmc_softc *,
+ const char *, const int, char *);
+int acpiapplesmc_init(struct acpiapplesmc_softc *);
+
+struct cfattach acpiapplesmc_ca = {
+ sizeof(struct acpiapplesmc_softc), acpiapplesmc_match,
+ acpiapplesmc_attach, NULL, acpiapplesmc_activate
+};
+
+struct cfdriver acpiapplesmc_cd = {
+ NULL, "acpiapplesmc", DV_DULL
+};
+
+const char *acpiapplesmc_hids[] = {
+ "APP0001", NULL
+};
+
+int
+acpiapplesmc_match(struct device *parent, void *match, void *aux)
+{
+ struct acpi_attach_args *aa = aux;
+ struct cfdata *cf = match;
+
+ return acpi_matchhids(aa, acpiapplesmc_hids, cf->cf_driver->cd_name);
+}
+
+void
+acpiapplesmc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct acpiapplesmc_softc *sc = (struct acpiapplesmc_softc *)self;
+ struct acpi_attach_args *aaa = aux;
+ int64_t sta;
+ struct aml_value res;
+ int i, sens_index;
+
+ sc->sc_acpi = (struct acpi_softc *)parent;
+ sc->sc_devnode = aaa->aaa_node;
+
+ printf(": %s", sc->sc_devnode->name);
+
+ sta = acpi_getsta(sc->sc_acpi, sc->sc_devnode);
+ if ((sta & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
+ (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) {
+ printf(": not enabled\n");
+ return;
+ }
+
+ if (!(aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CID", 0, NULL, &res)))
+ printf(" (%s)", res.v_string);
+
+ if (aaa->aaa_naddr < 1) {
+ printf(": no registers\n");
+ return;
+ }
+
+ printf (" addr 0x%llx/0x%llx\n", aaa->aaa_addr[0], aaa->aaa_size[0]);
+
+ sc->sc_bt = aaa->aaa_bst[0];
+ if (bus_space_map(sc->sc_bt, aaa->aaa_addr[0], aaa->aaa_size[0], 0,
+ &sc->sc_bh)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ if (acpiapplesmc_init(sc) == -1) {
+ printf("%s: SMC init failed!\n", DEVNAME(sc));
+ return;
+ }
+
+ strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
+ sizeof(sc->sc_sensdev.xname));
+
+ /* Add fans to sensor framework. */
+ for (i = 0; i < sc->sc_fan_count; i++) {
+ sc->sc_sens[i].type = SENSOR_FANRPM;
+ sensor_attach(&sc->sc_sensdev, &sc->sc_sens[i]);
+ }
+ sens_index = i;
+
+ /* Add temperature sensors to sensor framework. */
+ for (i = 0; sc->sc_temp_count != 0 && i < sc->sc_key_count; i++) {
+ if (sc->sc_keys[i].temp_use == 0)
+ continue;
+ sc->sc_sens[sens_index].type = SENSOR_TEMP;
+ (void)acpiapplesmc_temp_get_desc(sc,
+ sc->sc_keys[i].key,
+ sizeof(sc->sc_sens[sens_index].desc),
+ sc->sc_sens[sens_index].desc);
+ sensor_attach(&sc->sc_sensdev, &sc->sc_sens[sens_index]);
+ sens_index++;
+ }
+
+ sensordev_install(&sc->sc_sensdev);
+
+ aml_register_notify(sc->sc_devnode, NULL, acpiapplesmc_notify, sc,
+ ACPIDEV_POLL);
+}
+
+int
+acpiapplesmc_notify(struct aml_node *node, int notify_type, void *arg)
+{
+ struct acpiapplesmc_softc *sc = arg;
+ uint8_t temp;
+ uint16_t rpm;
+ int i, sens_index;
+
+ /* Get current fan speed. */
+ for (i = 0; i < sc->sc_fan_count; i++) {
+ if (acpiapplesmc_fan_get_value(sc, APPLESMC_KEY_FANSPEED, i,
+ &rpm) == -1) {
+ printf("%s: can't get fan #%d speed!\n",
+ DEVNAME(sc), i);
+ } else
+ sc->sc_sens[i].value = rpm;
+ }
+ sens_index = i;
+
+ /* Get current sensor temperature. */
+ for (i = 0; sc->sc_temp_count != 0 && i < sc->sc_key_count; i++) {
+ if (sc->sc_keys[i].temp_use == 0)
+ continue;
+ if (acpiapplesmc_temp_get_value(sc, sc->sc_keys[i].key, &temp)
+ == -1) {
+ printf("%s: can't get sensor #%d temperature!\n",
+ DEVNAME(sc), i);
+ } else {
+ sc->sc_sens[sens_index].value =
+ (temp * 1000000) + 273150000;
+ sens_index++;
+ }
+ }
+
+ return 0;
+}
+
+int
+acpiapplesmc_activate(struct device *self, int act)
+{
+#if 0
+ struct acpiapplesmc_softc *sc = (struct acpiapplesmc_softc *)self;
+
+ DPRINTF(("%s: %s\n", DEVNAME(sc), __func__));
+#endif
+ return 0;
+}
+
+/* **************************************************************************
*/
+
+int
+acpiapplesmc_waitack(struct acpiapplesmc_softc *sc, const uint8_t status_wait)
+{
+ int i;
+ uint8_t status;
+
+ for (i = 0; i < APPLESMC_WAITACK_RETRY; i++) {
+ status = bus_space_read_1(sc->sc_bt, sc->sc_bh,
+ APPLESMC_PORT_CMD);
+ if ((status & 0xf) == (status_wait & 0xf))
+ return 0;
+ delay(1);
+ }
+
+ return -1;
+}
+
+int
+acpiapplesmc_cmd(struct acpiapplesmc_softc *sc, const uint8_t cmd)
+{
+ int i;
+
+ for (i = 0; i < APPLESMC_CMD_RETRY; i++) {
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_CMD, cmd);
+
+ if (acpiapplesmc_waitack(sc, APPLESMC_WAITACK_CMD) == 0)
+ return 0;
+ }
+
+ DPRINTF(("%s: %s: command did fail after %d retries!\n",
+ DEVNAME(sc), __func__, APPLESMC_CMD_RETRY));
+
+ return -1;
+}
+
+int
+acpiapplesmc_key_read(struct acpiapplesmc_softc *sc, const char *key,
+ char *value, const uint8_t len)
+{
+ int i;
+
+ if (acpiapplesmc_cmd(sc, APPLESMC_CMD_KEY_READ) == -1)
+ return -1;
+
+ for (i = 0; i < APPLESMC_KEY_LEN; i++) {
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA,
+ key[i]);
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_WRITE) == -1)
+ return -1;
+ }
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA, len);
+
+ for (i = 0; i < len; i++) {
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_READ) == -1)
+ return -1;
+ value[i] = bus_space_read_1(sc->sc_bt, sc->sc_bh,
+ APPLESMC_PORT_DATA);
+ }
+
+ return 0;
+}
+
+int
+acpiapplesmc_key_write(struct acpiapplesmc_softc *sc, const char *key,
+ const char *value, const uint8_t len)
+{
+ int i;
+
+ if (acpiapplesmc_cmd(sc, APPLESMC_CMD_KEY_WRITE) == -1)
+ return -1;
+
+ for (i = 0; i < APPLESMC_KEY_LEN; i++) {
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA,
+ key[i]);
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_WRITE) == -1)
+ return -1;
+ }
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA, len);
+
+ for (i = 0; i < len; i++) {
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_WRITE) == -1)
+ return -1;
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA,
+ value[i]);
+ }
+
+ return 0;
+}
+
+int
+acpiapplesmc_key_get_byindex(struct acpiapplesmc_softc *sc,
+ const uint32_t index, char *key)
+{
+ int i;
+ uint32_t indexbe;
+ char index_send[4];
+
+ indexbe = htobe32(index);
+ index_send[0] = indexbe & 0xff;
+ index_send[1] = (indexbe >> 8) & 0xff;
+ index_send[2] = (indexbe >> 16) & 0xff;
+ index_send[3] = (indexbe >> 24) & 0xff;
+
+ if (acpiapplesmc_cmd(sc, APPLESMC_CMD_KEY_GET_BY_INDEX) == -1)
+ return -1;
+
+ for (i = 0; i < APPLESMC_KEY_LEN; i++) {
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA,
+ index_send[i]);
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_WRITE) == -1)
+ return -1;
+ }
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA,
+ APPLESMC_KEY_LEN);
+
+ for (i = 0; i < APPLESMC_KEY_LEN; i++) {
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_READ) == -1)
+ return -1;
+ key[i] = bus_space_read_1(sc->sc_bt, sc->sc_bh,
+ APPLESMC_PORT_DATA);
+ }
+
+ return 0;
+}
+
+int
+acpiapplesmc_key_get_type(struct acpiapplesmc_softc *sc, const char *key,
+ char *key_type)
+{
+ int i;
+
+ if (acpiapplesmc_cmd(sc, APPLESMC_CMD_KEY_GET_TYPE) == -1)
+ return -1;
+
+ for (i = 0; i < APPLESMC_KEY_LEN; i++) {
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA,
+ key[i]);
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_WRITE) == -1)
+ return -1;
+ }
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, APPLESMC_PORT_DATA,
+ APPLESMC_KEY_LEN);
+
+ for (i = 0; i < APPLESMC_KEY_TYPE_LEN; i++) {
+ if (acpiapplesmc_waitack(sc, APLLESMC_WAITACK_READ) == -1)
+ return -1;
+ key_type[i] = bus_space_read_1(sc->sc_bt, sc->sc_bh,
+ APPLESMC_PORT_DATA);
+ }
+
+ return 0;
+}
+
+int
+acpiapplesmc_key_count(struct acpiapplesmc_softc *sc, uint32_t *key_count)
+{
+ uint32_t buf;
+
+ if (acpiapplesmc_key_read(sc, APPLESMC_KEY_COUNT, (uint8_t *)&buf,
+ sizeof(buf)) == -1)
+ return -1;
+
+ *key_count = be32toh(buf);
+
+ return 0;
+}
+
+int
+acpiapplesmc_key_get_entry(struct acpiapplesmc_softc *sc, const int index,
+ struct acpiapplesmc_key *k)
+{
+ char key[4];
+ char key_info[6];
+
+ if (acpiapplesmc_key_get_byindex(sc, index, key) == -1)
+ return -1;
+ if (acpiapplesmc_key_get_type(sc, key, key_info) == -1)
+ return -1;
+
+ memcpy(k->key, key, sizeof(key));
+ memcpy(k->type, (key_info + 1), 4);
+ k->len = key_info[0];
+ k->flags = key_info[5];
+
+ return 0;
+}
+
+int
+acpiapplesmc_key_init(struct acpiapplesmc_softc *sc, const int key_count)
+{
+ int i;
+
+ memset(sc->sc_keys, 0, sizeof(struct acpiapplesmc_key));
+
+ for (i = 0; i < sc->sc_key_count; i++) {
+ if (acpiapplesmc_key_get_entry(sc, i, &sc->sc_keys[i]) == -1)
+ return -1;
+ DPRINTF(("%d: key=%s, type_len=%d, type=%s, type_flags=0x%x\n",
+ i,
+ sc->sc_keys[i].key,
+ sc->sc_keys[i].len,
+ sc->sc_keys[i].type,
+ sc->sc_keys[i].flags));
+ }
+ sc->sc_keys_init = 1;
+
+ return 0;
+}
+
+int
+acpiapplesmc_fan_count(struct acpiapplesmc_softc *sc, uint8_t *fan_count)
+{
+ uint8_t buf[1];
+
+ if (acpiapplesmc_key_read(sc, APPLESMC_KEY_FANCOUNT, buf, sizeof(buf))
+ == -1)
+ return -1;
+
+ *fan_count = buf[0];
+
+ return 0;
+}
+
+int
+acpiapplesmc_fan_get_value(struct acpiapplesmc_softc *sc,
+ const char *key, const uint8_t fan, uint16_t *fan_speed)
+{
+ uint8_t buf[2];
+ char fankey[5];
+
+ snprintf(fankey, sizeof(fankey), key, fan);
+
+ if (acpiapplesmc_key_read(sc, fankey, buf, sizeof(buf)) == -1)
+ return -1;
+
+ *fan_speed = (buf[0] << 6) | (buf[1] >> 2);
+
+ return 0;
+}
+
+int
+acpiapplesmc_temp_count(struct acpiapplesmc_softc *sc, uint8_t *temp_count)
+{
+ int i;
+ uint8_t tc = 0;
+
+ if (sc->sc_keys_init != 1)
+ return -1;
+
+ for (i = 0; i < sc->sc_key_count; i++) {
+ if (sc->sc_keys[i].key[0] == 'T')
+ tc++;
+ }
+
+ *temp_count = tc;
+
+ return 0;
+}
+
+int
+acpiapplesmc_temp_init(struct acpiapplesmc_softc *sc, uint8_t *temp_count)
+{
+ int i;
+ uint8_t tc;
+
+ if (sc->sc_keys_init != 1)
+ return -1;
+
+ for (tc = 0, i = 0; i < sc->sc_key_count; i++) {
+ if (sc->sc_keys[i].key[0] == 'T' &&
+ acpiapplesmc_temp_get_desc(sc, sc->sc_keys[i].key, 0,
+ NULL)) {
+ sc->sc_keys[i].temp_use = 1;
+ tc++;
+ }
+ }
+
+ *temp_count = tc;
+
+ return 0;
+}
+
+int
+acpiapplesmc_temp_get_value(struct acpiapplesmc_softc *sc, const char *key,
+ uint8_t *temp)
+{
+ uint8_t buf[2];
+
+ if (acpiapplesmc_key_read(sc, key, buf, sizeof(buf)) == -1)
+ return -1;
+
+ *temp = buf[0];
+
+ return 0;
+}
+
+int
+acpiapplesmc_temp_get_desc(struct acpiapplesmc_softc *sc, const char *key,
+ const int len, char *desc)
+{
+ int i;
+
+ for (i = 0; acpiapplesmc_temp_desc[i].key != NULL; i++) {
+ if (strcmp(key, acpiapplesmc_temp_desc[i].key) == 0) {
+ if (len != 0 && key != NULL) {
+ strlcpy(desc, acpiapplesmc_temp_desc[i].desc,
+ len);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+acpiapplesmc_init(struct acpiapplesmc_softc *sc)
+{
+ /* Count all available keys. */
+ if (acpiapplesmc_key_count(sc, &sc->sc_key_count) == -1) {
+ printf("%s: acpiapplesmc_key_count failed!\n", DEVNAME(sc));
+ return -1;
+ }
+ if (sc->sc_key_count > APPLESMC_MAX_KEY) {
+ printf("%s: key count exceeded!\n", DEVNAME(sc));
+ return -1;
+ }
+ /* Store all available keys in to an internal array. */
+ if (acpiapplesmc_key_init(sc, sc->sc_key_count) == -1) {
+ printf("%s: acpiapplesmc_key_init failed!\n", DEVNAME(sc));
+ return -1;
+ }
+
+ /* Count all available fans. */
+ if (acpiapplesmc_fan_count(sc, &sc->sc_fan_count) == -1) {
+ printf("%s: acpiapplesmc_fan_count failed!\n", DEVNAME(sc));
+ return -1;
+ }
+ if (sc->sc_fan_count > APPLESMC_MAX_FAN) {
+ printf("%s: fan count exceeded!\n", DEVNAME(sc));
+ return -1;
+ }
+
+ /* Count all available temperature sensors. */
+ if (acpiapplesmc_temp_count(sc, &sc->sc_temp_count_total) == -1) {
+ printf("%s: acpiapplesmc_temp_count failed!\n", DEVNAME(sc));
+ return -1;
+ }
+
+ /* Select which temperature sensors to use. */
+ if (acpiapplesmc_temp_init(sc, &sc->sc_temp_count) == -1) {
+ printf("%s: acpiapplesmc_temp_init failed!\n", DEVNAME(sc));
+ return -1;
+ }
+ if (sc->sc_temp_count > APPLESMC_MAX_TEMP) {
+ printf("%s: temp count exceeded!\n", DEVNAME(sc));
+ return -1;
+ }
+
+ DPRINTF(("# keys = %d\n", sc->sc_key_count));
+ DPRINTF(("# fans = %d\n", sc->sc_fan_count));
+ DPRINTF(("# temp total = %d\n", sc->sc_temp_count_total));
+ DPRINTF(("# temp use = %d\n", sc->sc_temp_count));
+
+ return 0;
+}
Index: sys/dev/acpi/files.acpi
===================================================================
RCS file: /cvs/src/sys/dev/acpi/files.acpi,v
retrieving revision 1.55
diff -u -p -u -p -r1.55 files.acpi
--- sys/dev/acpi/files.acpi 2 Jun 2020 16:24:24 -0000 1.55
+++ sys/dev/acpi/files.acpi 7 Sep 2020 04:54:57 -0000
@@ -75,6 +75,11 @@ device acpidock
attach acpidock at acpi
file dev/acpi/acpidock.c acpidock
+# Apple SMC support
+device acpiapplesmc
+attach acpiapplesmc at acpi
+file dev/acpi/acpiapplesmc.c acpiapplesmc
+
# ASUS ACPI Hotkeys
device acpiasus
attach acpiasus at acpi