Module Name: src
Committed By: riastradh
Date: Tue Apr 1 17:47:36 UTC 2014
Modified Files:
src/sys/conf: files
src/sys/dev/acpi: files.acpi
Added Files:
src/sys/dev/acpi: apple_smc_acpi.c
src/sys/dev/ic: apple_smc.c apple_smc.h apple_smc_fan.c
apple_smc_temp.c apple_smcreg.h apple_smcvar.h
src/sys/modules/apple_smc: Makefile apple_smc.ioconf
Log Message:
First draft of drivers for the Apple System Management Controller.
Device interface derived by reading the Linux driver source code and
<http:///www.parhelia.ch/blog/statics/k3_keys.html> as of 2012-12-05.
Includes support for attaching fan and temperature sensors to sysmon.
No accelerometer yet.
Compile-tested only, based on some run-testing of experiments from
userland. Module attachment is not quite finished, so it won't work
yet.
To generate a diff of this commit:
cvs rdiff -u -r1.1087 -r1.1088 src/sys/conf/files
cvs rdiff -u -r0 -r1.1 src/sys/dev/acpi/apple_smc_acpi.c
cvs rdiff -u -r1.93 -r1.94 src/sys/dev/acpi/files.acpi
cvs rdiff -u -r0 -r1.1 src/sys/dev/ic/apple_smc.c src/sys/dev/ic/apple_smc.h \
src/sys/dev/ic/apple_smc_fan.c src/sys/dev/ic/apple_smc_temp.c \
src/sys/dev/ic/apple_smcreg.h src/sys/dev/ic/apple_smcvar.h
cvs rdiff -u -r0 -r1.1 src/sys/modules/apple_smc/Makefile \
src/sys/modules/apple_smc/apple_smc.ioconf
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1087 src/sys/conf/files:1.1088
--- src/sys/conf/files:1.1087 Wed Mar 19 15:26:42 2014
+++ src/sys/conf/files Tue Apr 1 17:47:36 2014
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1087 2014/03/19 15:26:42 nonaka Exp $
+# $NetBSD: files,v 1.1088 2014/04/01 17:47:36 riastradh Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20100430
@@ -1095,6 +1095,26 @@ file dev/ic/hpet.c hpet needs-flag
device smsh: arp, ether, ifnet, mii
file dev/ic/lan9118.c smsh
+# Apple System Management Controller
+#
+device applesmc {}
+file dev/ic/apple_smc.c applesmc
+
+# Apple SMC fan sensors and control
+device applesmcfan: applesmc, sysmon_envsys
+attach applesmcfan at applesmc with apple_smc_fan
+file dev/ic/apple_smc_fan.c applesmcfan
+
+# Apple SMC temperature sensors
+device applesmctemp: applesmc, sysmon_envsys
+attach applesmctemp at applesmc with apple_smc_temp
+file dev/ic/apple_smc_temp.c applesmctemp
+
+# Apple SMC accelerometer
+#device applesmcaccel: applesmc, sysmon_envsys
+#attach applesmcaccel at applesmc with apple_smc_accel
+#file dev/ic/apple_smc_accel.c applesmcaccel
+
# DRM - Direct Rendering Infrastructure: dev/drm
define drm {}
include "external/bsd/drm/conf/files.drm"
Index: src/sys/dev/acpi/files.acpi
diff -u src/sys/dev/acpi/files.acpi:1.93 src/sys/dev/acpi/files.acpi:1.94
--- src/sys/dev/acpi/files.acpi:1.93 Sun Jan 22 06:44:28 2012
+++ src/sys/dev/acpi/files.acpi Tue Apr 1 17:47:36 2014
@@ -1,4 +1,4 @@
-# $NetBSD: files.acpi,v 1.93 2012/01/22 06:44:28 christos Exp $
+# $NetBSD: files.acpi,v 1.94 2014/04/01 17:47:36 riastradh Exp $
include "dev/acpi/acpica/files.acpica"
@@ -206,4 +206,8 @@ device fujhk: sysmon_power
attach fujhk at acpinodebus
file dev/acpi/fujhk_acpi.c fujhk
+# Apple SMC
+attach applesmc at acpinodebus with apple_smc_acpi
+file dev/acpi/apple_smc_acpi.c apple_smc_acpi
+
include "dev/acpi/wmi/files.wmi"
Added files:
Index: src/sys/dev/acpi/apple_smc_acpi.c
diff -u /dev/null src/sys/dev/acpi/apple_smc_acpi.c:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/dev/acpi/apple_smc_acpi.c Tue Apr 1 17:47:36 2014
@@ -0,0 +1,145 @@
+/* $NetBSD: apple_smc_acpi.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $ */
+
+/*
+ * Apple System Management Controller: ACPI Attachment
+ */
+
+/*-
+ * Copyright (c) 2013 Taylor R. Campbell
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: apple_smc_acpi.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+
+#include <dev/ic/apple_smcreg.h>
+#include <dev/ic/apple_smcvar.h>
+
+#define _COMPONENT ACPI_RESOURCE_COMPONENT
+ACPI_MODULE_NAME ("apple_smc_acpi")
+
+struct apple_smc_acpi_softc {
+ struct apple_smc_tag sc_smc;
+};
+
+static int apple_smc_acpi_match(device_t, cfdata_t, void *);
+static void apple_smc_acpi_attach(device_t, device_t, void *);
+static int apple_smc_acpi_detach(device_t, int);
+
+CFATTACH_DECL_NEW(apple_smc_acpi, sizeof(struct apple_smc_acpi_softc),
+ apple_smc_acpi_match, apple_smc_acpi_attach, apple_smc_acpi_detach, NULL);
+
+static const char *const apple_smc_ids[] = {
+ "APP0001",
+ NULL
+};
+
+static int
+apple_smc_acpi_match(device_t parent, cfdata_t match, void *aux)
+{
+ struct acpi_attach_args *aa = aux;
+
+ if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
+ return 0;
+
+ if (!acpi_match_hid(aa->aa_node->ad_devinfo, apple_smc_ids))
+ return 0;
+
+ return 1;
+}
+
+static void
+apple_smc_acpi_attach(device_t parent, device_t self, void *aux)
+{
+ struct apple_smc_acpi_softc *sc = device_private(self);
+ struct apple_smc_tag *smc = &sc->sc_smc;
+ struct acpi_attach_args *aa = aux;
+ struct acpi_resources res;
+ struct acpi_io *io;
+ int rv;
+
+ smc->smc_dev = self;
+
+ aprint_normal("\n");
+ aprint_naive("\n");
+
+ rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS",
+ &res, &acpi_resource_parse_ops_default);
+ if (ACPI_FAILURE(rv)) {
+ aprint_error_dev(self, "couldn't parse SMC resources: %s\n",
+ AcpiFormatException(rv));
+ goto out0;
+ }
+
+ io = acpi_res_io(&res, 0);
+ if (io == NULL) {
+ aprint_error_dev(self, "no I/O resource\n");
+ goto out1;
+ }
+
+ if (io->ar_length < APPLE_SMC_REGSIZE) {
+ aprint_error_dev(self, "I/O resources too small: %"PRId32"\n",
+ io->ar_length);
+ goto out1;
+ }
+
+ if (bus_space_map(aa->aa_iot, io->ar_base, io->ar_length, 0,
+ &smc->smc_bsh) != 0) {
+ aprint_error_dev(self, "unable to map I/O registers\n");
+ goto out1;
+ }
+
+ smc->smc_bst = aa->aa_iot;
+ smc->smc_size = io->ar_length;
+
+ apple_smc_attach(smc);
+
+out1: acpi_resource_cleanup(&res);
+out0: return;
+}
+
+static int
+apple_smc_acpi_detach(device_t self, int flags)
+{
+ struct apple_smc_acpi_softc *sc = device_private(self);
+ struct apple_smc_tag *smc = &sc->sc_smc;
+ int error;
+
+ if (smc->smc_size != 0) {
+ error = apple_smc_detach(smc, flags);
+ if (error)
+ return error;
+
+ bus_space_unmap(smc->smc_bst, smc->smc_bsh, smc->smc_size);
+ smc->smc_size = 0;
+ }
+
+ return 0;
+}
Index: src/sys/dev/ic/apple_smc.c
diff -u /dev/null src/sys/dev/ic/apple_smc.c:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/dev/ic/apple_smc.c Tue Apr 1 17:47:36 2014
@@ -0,0 +1,524 @@
+/* $NetBSD: apple_smc.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $ */
+
+/*
+ * Apple System Management Controller
+ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: apple_smc.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
+#if 0 /* XXX sysctl */
+#include <sys/sysctl.h>
+#endif
+#include <sys/systm.h>
+
+#include <dev/ic/apple_smc.h>
+#include <dev/ic/apple_smcreg.h>
+#include <dev/ic/apple_smcvar.h>
+
+static void apple_smc_rescan1(struct apple_smc_tag *,
+ struct apple_smc_attach_args *,
+ const char *, const char *, device_t *);
+static uint8_t apple_smc_bus_read_1(struct apple_smc_tag *, bus_size_t);
+static void apple_smc_bus_write_1(struct apple_smc_tag *, bus_size_t,
+ uint8_t);
+static int apple_smc_read_data(struct apple_smc_tag *, uint8_t *);
+static int apple_smc_write(struct apple_smc_tag *, bus_size_t, uint8_t);
+static int apple_smc_write_cmd(struct apple_smc_tag *, uint8_t);
+static int apple_smc_write_data(struct apple_smc_tag *, uint8_t);
+static int apple_smc_begin(struct apple_smc_tag *, uint8_t,
+ const char *, uint8_t);
+static int apple_smc_input(struct apple_smc_tag *, uint8_t,
+ const char *, void *, uint8_t);
+static int apple_smc_output(struct apple_smc_tag *, uint8_t,
+ const char *, const void *, uint8_t);
+
+void
+apple_smc_attach(struct apple_smc_tag *smc)
+{
+
+ mutex_init(&smc->smc_lock, MUTEX_DEFAULT, IPL_NONE);
+
+#if 0 /* XXX sysctl */
+ apple_smc_sysctl_setup(smc);
+#endif
+
+ (void)apple_smc_rescan(smc, NULL, NULL);
+}
+
+int
+apple_smc_rescan(struct apple_smc_tag *smc, const char *ifattr,
+ const int *locators)
+{
+ struct apple_smc_attach_args asa;
+
+ (void)locators; /* ignore */
+
+ (void)memset(&asa, 0, sizeof asa);
+ asa.asa_smc = smc;
+#if 0 /* XXX sysctl */
+ asa.asa_sysctlnode = smc->smc_sysctlnode;
+#endif
+
+ apple_smc_rescan1(smc, &asa, ifattr, "applesmcfan", &smc->smc_fan);
+ apple_smc_rescan1(smc, &asa, ifattr, "applesmctemp", &smc->smc_temp);
+#if 0 /* XXX accelerometer */
+ apple_smc_rescan1(smc, &asa, ifattr, "applesmcaccel",
+ &smc->smc_accelfan);
+#endif
+
+ return 0;
+}
+
+static void
+apple_smc_rescan1(struct apple_smc_tag *smc, struct apple_smc_attach_args *asa,
+ const char *ifattr, const char *ifa_conf, device_t *devp)
+{
+
+ if (ifattr_match(ifattr, ifa_conf) && *devp == NULL)
+ *devp = config_found_ia(smc->smc_dev, ifa_conf, asa, NULL);
+}
+
+int
+apple_smc_detach(struct apple_smc_tag *smc, int flags)
+{
+ int error;
+
+ error = config_detach_children(smc->smc_dev, flags);
+ if (error)
+ return error;
+
+#if 0 /* XXX sysctl */
+ sysctl_teardown(&smc->smc_log);
+#endif
+
+ return 0;
+}
+
+static uint8_t
+apple_smc_bus_read_1(struct apple_smc_tag *smc, bus_size_t reg)
+{
+
+ return bus_space_read_1(smc->smc_bst, smc->smc_bsh, reg);
+}
+
+static void
+apple_smc_bus_write_1(struct apple_smc_tag *smc, bus_size_t reg, uint8_t v)
+{
+
+ bus_space_write_1(smc->smc_bst, smc->smc_bsh, reg, v);
+}
+
+/*
+ * XXX These delays are pretty randomly chosen. Wait in 100 us
+ * increments, up to a total of 1 ms.
+ */
+
+static int
+apple_smc_read_data(struct apple_smc_tag *smc, uint8_t *byte)
+{
+ uint8_t status;
+ unsigned int i;
+
+ KASSERT(mutex_owned(&smc->smc_lock));
+
+ for (i = 0; i < 100; i++) {
+ status = apple_smc_bus_read_1(smc, APPLE_SMC_CSR);
+ if (status & APPLE_SMC_STATUS_READ_READY) {
+ *byte = apple_smc_bus_read_1(smc, APPLE_SMC_DATA);
+ return 0;
+ }
+ DELAY(100);
+ }
+
+ return ETIMEDOUT;
+}
+
+static int
+apple_smc_write(struct apple_smc_tag *smc, bus_size_t reg, uint8_t byte)
+{
+ uint8_t status;
+ unsigned int i;
+
+ KASSERT(mutex_owned(&smc->smc_lock));
+
+ apple_smc_bus_write_1(smc, reg, byte);
+ for (i = 0; i < 100; i++) {
+ status = apple_smc_bus_read_1(smc, APPLE_SMC_CSR);
+ if (status & APPLE_SMC_STATUS_WRITE_ACCEPTED)
+ return 0;
+ DELAY(100);
+ if (!(status & APPLE_SMC_STATUS_WRITE_PENDING))
+ apple_smc_bus_write_1(smc, reg, byte);
+ }
+
+ return ETIMEDOUT;
+}
+
+static int
+apple_smc_write_cmd(struct apple_smc_tag *smc, uint8_t cmd)
+{
+
+ return apple_smc_write(smc, APPLE_SMC_CSR, cmd);
+}
+
+static int
+apple_smc_write_data(struct apple_smc_tag *smc, uint8_t data)
+{
+
+ return apple_smc_write(smc, APPLE_SMC_DATA, data);
+}
+
+struct apple_smc_key {
+ char ask_name[4 + 1];
+ struct apple_smc_desc ask_desc;
+#ifdef DIAGNOSTIC
+ struct apple_smc_tag *ask_smc;
+#endif
+};
+
+static int
+apple_smc_begin(struct apple_smc_tag *smc, uint8_t cmd, const char *key,
+ uint8_t size)
+{
+ unsigned int i;
+ int error;
+
+ KASSERT(mutex_owned(&smc->smc_lock));
+
+ error = apple_smc_write_cmd(smc, cmd);
+ if (error)
+ return error;
+
+ for (i = 0; i < 4; i++) {
+ error = apple_smc_write_data(smc, key[i]);
+ if (error)
+ return error;
+ }
+
+ error = apple_smc_write_data(smc, size);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int
+apple_smc_input(struct apple_smc_tag *smc, uint8_t cmd, const char *key,
+ void *buffer, uint8_t size)
+{
+ uint8_t *bytes = buffer;
+ uint8_t i;
+ int error;
+
+ mutex_enter(&smc->smc_lock);
+ error = apple_smc_begin(smc, cmd, key, size);
+ if (error)
+ goto out;
+
+ for (i = 0; i < size; i++) {
+ error = apple_smc_read_data(smc, &bytes[i]);
+ if (error)
+ goto out;
+ }
+
+ /* Success! */
+ error = 0;
+
+out:
+ mutex_exit(&smc->smc_lock);
+ return error;
+}
+
+static int
+apple_smc_output(struct apple_smc_tag *smc, uint8_t cmd, const char *key,
+ const void *buffer, uint8_t size)
+{
+ const uint8_t *bytes = buffer;
+ uint8_t i;
+ int error;
+
+ mutex_enter(&smc->smc_lock);
+ error = apple_smc_begin(smc, cmd, key, size);
+ if (error)
+ goto out;
+
+ for (i = 0; i < size; i++) {
+ error = apple_smc_write_data(smc, bytes[i]);
+ if (error)
+ goto out;
+ }
+
+out:
+ mutex_exit(&smc->smc_lock);
+ return error;
+}
+
+const char *
+apple_smc_key_name(const struct apple_smc_key *key)
+{
+
+ return key->ask_name;
+}
+
+const struct apple_smc_desc *
+apple_smc_key_desc(const struct apple_smc_key *key)
+{
+
+ return &key->ask_desc;
+}
+
+uint32_t
+apple_smc_nkeys(struct apple_smc_tag *smc)
+{
+
+ return smc->smc_nkeys;
+}
+
+int
+apple_smc_nth_key(struct apple_smc_tag *smc, uint32_t index,
+ const char type[4 + 1], struct apple_smc_key **keyp)
+{
+ union { uint32_t u32; char name[4]; } index_be;
+ struct apple_smc_key *key;
+ int error;
+
+ if ((type != NULL) && (strlen(type) != 4))
+ return EINVAL;
+
+ key = kmem_alloc(sizeof(*key), KM_SLEEP);
+#ifdef DIAGNOSTIC
+ key->ask_smc = smc;
+#endif
+
+ index_be.u32 = htobe32(index);
+ error = apple_smc_input(smc, APPLE_SMC_CMD_NTH_KEY, index_be.name,
+ key->ask_name, 4);
+ if (error)
+ goto fail;
+ key->ask_name[4] = '\0';
+
+ CTASSERT(sizeof(key->ask_desc) == 6);
+ error = apple_smc_input(smc, APPLE_SMC_CMD_KEY_DESC, key->ask_name,
+ &key->ask_desc, 6);
+ if (error)
+ goto fail;
+
+ if ((type != NULL) && (0 != memcmp(key->ask_desc.asd_type, type, 4))) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ /* Success! */
+ *keyp = key;
+ return 0;
+
+fail:
+ kmem_free(key, sizeof(*key));
+ return error;
+}
+
+int
+apple_smc_named_key(struct apple_smc_tag *smc, const char name[4 + 1],
+ const char type[4 + 1], struct apple_smc_key **keyp)
+{
+ struct apple_smc_key *key;
+ int error;
+
+ KASSERT(name != NULL);
+ if (strlen(name) != 4)
+ return EINVAL;
+
+ if ((type != NULL) && (strlen(type) != 4))
+ return EINVAL;
+
+ key = kmem_alloc(sizeof(*key), KM_SLEEP);
+#ifdef DIAGNOSTIC
+ key->ask_smc = smc;
+#endif
+ (void)memcpy(key->ask_name, name, 4);
+ key->ask_name[4] = '\0';
+
+ CTASSERT(sizeof(key->ask_desc) == 6);
+ error = apple_smc_input(smc, APPLE_SMC_CMD_KEY_DESC, key->ask_name,
+ &key->ask_desc, 6);
+ if (error)
+ goto fail;
+
+ if ((type != NULL) && (0 != memcmp(key->ask_desc.asd_type, type, 4))) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ *keyp = key;
+ return 0;
+
+fail:
+ kmem_free(key, sizeof(*key));
+ return error;
+}
+
+void
+apple_smc_release_key(struct apple_smc_tag *smc, struct apple_smc_key *key)
+{
+
+#ifdef DIAGNOSTIC
+ if (key->ask_smc != smc)
+ aprint_error_dev(smc->smc_dev,
+ "releasing key with wrong tag: %p != %p",
+ smc, key->ask_smc);
+#endif
+ kmem_free(key, sizeof(*key));
+}
+
+int
+apple_smc_key_search(struct apple_smc_tag *smc, const char *name,
+ uint32_t *result)
+{
+ struct apple_smc_key *key;
+ uint32_t start = 0, end = apple_smc_nkeys(smc), median;
+ int error;
+
+ while (start < end) {
+ median = (start + ((end - start) / 2));
+ error = apple_smc_nth_key(smc, median, NULL, &key);
+ if (error)
+ return error;
+
+ if (memcmp(name, apple_smc_key_name(key), 4) < 0)
+ end = median;
+ else
+ start = (median + 1);
+ apple_smc_release_key(smc, key);
+ }
+
+ *result = start;
+ return 0;
+}
+
+int
+apple_smc_read_key(struct apple_smc_tag *smc, const struct apple_smc_key *key,
+ void *buffer, uint8_t size)
+{
+
+ if (key->ask_desc.asd_size != size)
+ return EINVAL;
+ if (!(key->ask_desc.asd_flags & APPLE_SMC_FLAG_READ))
+ return EACCES;
+
+ return apple_smc_input(smc, APPLE_SMC_CMD_READ_KEY, key->ask_name,
+ buffer, size);
+}
+
+int
+apple_smc_read_key_1(struct apple_smc_tag *smc,
+ const struct apple_smc_key *key, uint8_t *p)
+{
+
+ return apple_smc_read_key(smc, key, p, 1);
+}
+
+int
+apple_smc_read_key_2(struct apple_smc_tag *smc,
+ const struct apple_smc_key *key, uint16_t *p)
+{
+ uint16_t be;
+ int error;
+
+ error = apple_smc_read_key(smc, key, &be, 2);
+ if (error)
+ return error;
+
+ *p = be16toh(be);
+ return 0;
+}
+
+int
+apple_smc_read_key_4(struct apple_smc_tag *smc,
+ const struct apple_smc_key *key, uint32_t *p)
+{
+ uint32_t be;
+ int error;
+
+ error = apple_smc_read_key(smc, key, &be, 4);
+ if (error)
+ return error;
+
+ *p = be32toh(be);
+ return 0;
+}
+
+int
+apple_smc_write_key(struct apple_smc_tag *smc, const struct apple_smc_key *key,
+ const void *buffer, uint8_t size)
+{
+
+ if (key->ask_desc.asd_size != size)
+ return EINVAL;
+ if (!(key->ask_desc.asd_flags & APPLE_SMC_FLAG_WRITE))
+ return EACCES;
+
+ return apple_smc_output(smc, APPLE_SMC_CMD_WRITE_KEY, key->ask_name,
+ buffer, size);
+}
+
+int
+apple_smc_write_key_1(struct apple_smc_tag *smc,
+ const struct apple_smc_key *key, uint8_t v)
+{
+
+ return apple_smc_write_key(smc, key, &v, 1);
+}
+
+int
+apple_smc_write_key_2(struct apple_smc_tag *smc,
+ const struct apple_smc_key *key, uint16_t v)
+{
+ const uint16_t v_be = htobe16(v);
+
+ return apple_smc_write_key(smc, key, &v_be, 2);
+}
+
+int
+apple_smc_write_key_4(struct apple_smc_tag *smc,
+ const struct apple_smc_key *key, uint32_t v)
+{
+ const uint16_t v_be = htobe32(v);
+
+ return apple_smc_write_key(smc, key, &v_be, 4);
+}
Index: src/sys/dev/ic/apple_smc.h
diff -u /dev/null src/sys/dev/ic/apple_smc.h:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/dev/ic/apple_smc.h Tue Apr 1 17:47:36 2014
@@ -0,0 +1,109 @@
+/* $NetBSD: apple_smc.h,v 1.1 2014/04/01 17:47:36 riastradh Exp $ */
+
+/*
+ * Apple System Management Controller Interface
+ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _DEV_IC_APPLE_SMC_H_
+#define _DEV_IC_APPLE_SMC_H_
+
+#include <sys/types.h>
+
+struct apple_smc_tag;
+
+struct apple_smc_attach_args {
+ struct apple_smc_tag *asa_smc;
+};
+
+struct apple_smc_key;
+
+struct apple_smc_desc {
+ uint8_t asd_size;
+
+ char asd_type[4];
+#define APPLE_SMC_TYPE_UINT8 "ui8 "
+#define APPLE_SMC_TYPE_UINT16 "ui16"
+#define APPLE_SMC_TYPE_UINT32 "ui32"
+#define APPLE_SMC_TYPE_SINT8 "si8 "
+#define APPLE_SMC_TYPE_SINT16 "si16"
+#define APPLE_SMC_TYPE_SINT32 "si32"
+#define APPLE_SMC_TYPE_STRING "ch8*"
+#define APPLE_SMC_TYPE_FANDESC "{fds" /* fan description */
+#define APPLE_SMC_TYPE_FPE2 "fpe2" /* fan RPM */
+#define APPLE_SMC_TYPE_SP78 "sp78" /* temperature in a weird scale */
+
+ uint8_t asd_flags;
+#define APPLE_SMC_FLAG_UNKNOWN0 0x01
+#define APPLE_SMC_FLAG_UNKNOWN1 0x02
+#define APPLE_SMC_FLAG_UNKNOWN2 0x04
+#define APPLE_SMC_FLAG_UNKNOWN3 0x08
+#define APPLE_SMC_FLAG_UNKNOWN4 0x10
+#define APPLE_SMC_FLAG_UNKNOWN5 0x20
+#define APPLE_SMC_FLAG_WRITE 0x40
+#define APPLE_SMC_FLAG_READ 0x80
+} __packed;
+
+uint32_t apple_smc_nkeys(struct apple_smc_tag *);
+int apple_smc_nth_key(struct apple_smc_tag *,
+ uint32_t, const char[4 + 1],
+ struct apple_smc_key **);
+int apple_smc_named_key(struct apple_smc_tag *,
+ const char[4 + 1], const char[4 + 1],
+ struct apple_smc_key **);
+void apple_smc_release_key(struct apple_smc_tag *,
+ struct apple_smc_key *);
+int apple_smc_key_search(struct apple_smc_tag *, const char[4 + 1],
+ uint32_t *);
+const char * apple_smc_key_name(const struct apple_smc_key *);
+uint32_t apple_smc_key_index(const struct apple_smc_key *);
+const struct apple_smc_desc *
+ apple_smc_key_desc(const struct apple_smc_key *);
+
+int apple_smc_read_key(struct apple_smc_tag *,
+ const struct apple_smc_key *, void *, uint8_t);
+int apple_smc_read_key_1(struct apple_smc_tag *,
+ const struct apple_smc_key *, uint8_t *);
+int apple_smc_read_key_2(struct apple_smc_tag *,
+ const struct apple_smc_key *, uint16_t *);
+int apple_smc_read_key_4(struct apple_smc_tag *,
+ const struct apple_smc_key *, uint32_t *);
+
+int apple_smc_write_key(struct apple_smc_tag *,
+ const struct apple_smc_key *, const void *, uint8_t);
+int apple_smc_write_key_1(struct apple_smc_tag *,
+ const struct apple_smc_key *, uint8_t);
+int apple_smc_write_key_2(struct apple_smc_tag *,
+ const struct apple_smc_key *, uint16_t);
+int apple_smc_write_key_4(struct apple_smc_tag *,
+ const struct apple_smc_key *, uint32_t);
+
+#endif /* _DEV_IC_APPLE_SMC_H_ */
Index: src/sys/dev/ic/apple_smc_fan.c
diff -u /dev/null src/sys/dev/ic/apple_smc_fan.c:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/dev/ic/apple_smc_fan.c Tue Apr 1 17:47:36 2014
@@ -0,0 +1,406 @@
+/* $NetBSD: apple_smc_fan.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $ */
+
+/*
+ * Apple System Management Controller: Fans
+ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: apple_smc_fan.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#if 0 /* XXX sysctl */
+#include <sys/sysctl.h>
+#endif
+#include <sys/systm.h>
+
+#include <dev/ic/apple_smc.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#define APPLE_SMC_NFANS_KEY "FNum"
+
+static const struct fan_sensor {
+ const char *fs_name;
+ const char *fs_key_suffix;
+} fan_sensors[] = {
+ { "actual", "Ac" },
+ { "minimum", "Mn" },
+ { "maximum", "Mx" },
+ { "safe", "Sf" },
+ { "target", "Tg" },
+};
+
+struct apple_smc_fan_softc {
+ device_t sc_dev;
+ struct apple_smc_tag *sc_smc;
+ struct sysmon_envsys *sc_sme;
+ uint8_t sc_nfans;
+ struct {
+ struct {
+ struct apple_smc_key *sensor_key;
+ struct envsys_data sensor_data;
+ } sensors[__arraycount(fan_sensors)];
+ } *sc_fans;
+
+#if 0 /* XXX sysctl */
+ struct sysctllog *sc_sysctl_log;
+ const struct sysctlnode *sc_sysctl_node;
+#endif
+};
+
+struct fan_desc {
+ uint8_t fd_type;
+ uint8_t fd_zone;
+ uint8_t fd_location;
+ uint8_t fd_reserved0;
+ char fd_name[12];
+} __packed;
+
+static int apple_smc_fan_match(device_t, cfdata_t, void *);
+static void apple_smc_fan_attach(device_t, device_t, void *);
+static int apple_smc_fan_detach(device_t, int);
+static int apple_smc_fan_attach_sensors(struct apple_smc_fan_softc *);
+static void apple_smc_fan_attach_sensor(struct apple_smc_fan_softc *,
+ uint8_t, const char *, uint8_t);
+static void apple_smc_fan_refresh(struct sysmon_envsys *,
+ struct envsys_data *);
+static void apple_smc_fan_release_keys(struct apple_smc_fan_softc *);
+#if 0 /* XXX sysctl */
+static int apple_smc_fan_sysctl_setup(struct apple_smc_fan_softc *);
+static void apple_smc_fan_sysctl_setup_1(struct apple_smc_tag *,
+ uint8_t);
+#endif
+
+CFATTACH_DECL_NEW(apple_smc_fan, sizeof(struct apple_smc_fan_softc),
+ apple_smc_fan_match, apple_smc_fan_attach, apple_smc_fan_detach, NULL);
+
+static int
+apple_smc_fan_match(device_t parent, cfdata_t match, void *aux)
+{
+ const struct apple_smc_attach_args *asa = aux;
+ struct apple_smc_key *nfans_key;
+ uint8_t nfans;
+ int rv = 0;
+ int error;
+
+ error = apple_smc_named_key(asa->asa_smc, APPLE_SMC_NFANS_KEY,
+ APPLE_SMC_TYPE_UINT8, &nfans_key);
+ if (error)
+ goto out0;
+
+ error = apple_smc_read_key_1(asa->asa_smc, nfans_key, &nfans);
+ if (error)
+ goto out1;
+
+ if (nfans > 0)
+ rv = 1;
+
+out1: apple_smc_release_key(asa->asa_smc, nfans_key);
+out0: return rv;
+}
+
+static void
+apple_smc_fan_attach(device_t parent, device_t self, void *aux)
+{
+ struct apple_smc_fan_softc *sc = device_private(self);
+ const struct apple_smc_attach_args *asa = aux;
+ struct apple_smc_key *nfans_key;
+ int error;
+
+ aprint_normal(": Apple SMC fan sensors\n");
+
+ sc->sc_dev = self;
+ sc->sc_smc = asa->asa_smc;
+
+ error = apple_smc_named_key(sc->sc_smc, APPLE_SMC_NFANS_KEY,
+ APPLE_SMC_TYPE_UINT8, &nfans_key);
+ if (error)
+ goto out0;
+
+ error = apple_smc_read_key_1(sc->sc_smc, nfans_key, &sc->sc_nfans);
+ if (error)
+ goto out1;
+
+ if (sc->sc_nfans == 0) { /* XXX */
+ aprint_error_dev(self, "no fans\n");
+ goto out1;
+ }
+
+ /* Must fit in a single decimal digit. */
+ if (sc->sc_nfans >= 10) {
+ aprint_error_dev(self, "too many fans: %"PRIu8"\n",
+ sc->sc_nfans);
+ sc->sc_nfans = 9;
+ }
+
+#if 0 /* XXX sysctl */
+ error = apple_smc_fan_sysctl_setup(sc);
+ if (error)
+ goto fail0;
+#endif
+
+ error = apple_smc_fan_attach_sensors(sc);
+ if (error)
+ goto fail1;
+
+ goto out1;
+
+#if 0
+fail2:
+ apple_smc_fan_detach_sensors(sc);
+#endif
+
+fail1:
+#if 0 /* XXX sysctl */
+ sysctl_teardown(&sc->sc_sysctl_log);
+fail0:
+#endif
+
+out1: apple_smc_release_key(sc->sc_smc, nfans_key);
+out0: return;
+}
+
+static int
+apple_smc_fan_detach(device_t self, int flags)
+{
+ struct apple_smc_fan_softc *sc = device_private(self);
+
+ if (sc->sc_sme != NULL) {
+ sysmon_envsys_unregister(sc->sc_sme);
+ sc->sc_sme = NULL;
+
+ KASSERT(sc->sc_fans != NULL);
+ KASSERT(sc->sc_nfans > 0);
+ KASSERT(sc->sc_nfans < 10);
+
+ apple_smc_fan_release_keys(sc);
+ kmem_free(sc->sc_fans,
+ (sizeof(sc->sc_fans[0]) * sc->sc_nfans));
+ sc->sc_fans = NULL;
+ sc->sc_nfans = 0;
+ }
+
+#if 0 /* XXX sysctl */
+ sysctl_teardown(&sc->sc_sysctl_log);
+#endif
+
+ return 0;
+}
+
+static int
+apple_smc_fan_attach_sensors(struct apple_smc_fan_softc *sc)
+{
+ uint8_t fan, sensor;
+ char fan_desc_key_name[4 + 1];
+ struct apple_smc_key *fan_desc_key;
+ struct fan_desc fan_desc;
+ char name[sizeof(fan_desc.fd_name) + 1];
+ int error;
+
+ sc->sc_sme = sysmon_envsys_create();
+ sc->sc_sme->sme_name = device_xname(sc->sc_dev);
+ sc->sc_sme->sme_cookie = sc;
+ sc->sc_sme->sme_refresh = apple_smc_fan_refresh;
+
+ CTASSERT(10 <= (SIZE_MAX / sizeof(sc->sc_fans[0])));
+ sc->sc_fans = kmem_zalloc((sizeof(sc->sc_fans[0]) * sc->sc_nfans),
+ KM_SLEEP);
+
+ for (fan = 0; fan < sc->sc_nfans; fan++) {
+ (void)snprintf(fan_desc_key_name, sizeof fan_desc_key_name,
+ "F%"PRIu8"ID", fan);
+ KASSERT(4 == strlen(fan_desc_key_name));
+
+ error = apple_smc_named_key(sc->sc_smc, fan_desc_key_name,
+ APPLE_SMC_TYPE_FANDESC, &fan_desc_key);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "error identifying fan %"PRIu8": %d\n",
+ fan, error);
+ continue;
+ }
+
+ error = apple_smc_read_key(sc->sc_smc, fan_desc_key, &fan_desc,
+ sizeof fan_desc);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "error identifying fan %"PRIu8": %d\n",
+ fan, error);
+ continue;
+ }
+
+ /*
+ * XXX Do more with the fan description...
+ */
+
+ (void)memcpy(name, fan_desc.fd_name, sizeof(fan_desc.fd_name));
+ name[sizeof(fan_desc.fd_name)] = 0;
+
+ for (sensor = 0; sensor < __arraycount(fan_sensors); sensor++)
+ apple_smc_fan_attach_sensor(sc, fan, name, sensor);
+
+#if 0 /* XXX sysctl */
+ apple_smc_fan_sysctl_setup_1(sc, fan);
+#endif
+ }
+
+ error = sysmon_envsys_register(sc->sc_sme);
+ if (error)
+ goto fail;
+
+ error = 0;
+ goto out;
+
+fail: sysmon_envsys_destroy(sc->sc_sme);
+ sc->sc_sme = NULL;
+out: return error;
+}
+
+static void
+apple_smc_fan_attach_sensor(struct apple_smc_fan_softc *sc, uint8_t fan,
+ const char *name, uint8_t sensor)
+{
+ char key_name[4 + 1];
+ struct apple_smc_key **keyp;
+ struct envsys_data *edata;
+ int error;
+
+ KASSERT(fan < sc->sc_nfans);
+ KASSERT(sensor < __arraycount(fan_sensors));
+
+ keyp = &sc->sc_fans[fan].sensors[sensor].sensor_key;
+ (void)snprintf(key_name, sizeof key_name, "F%d%s",
+ (int)sensor, fan_sensors[sensor].fs_key_suffix);
+ KASSERT(strlen(key_name) == 4);
+ error = apple_smc_named_key(sc->sc_smc, key_name, APPLE_SMC_TYPE_FPE2,
+ keyp);
+ if (error)
+ goto fail0;
+
+ edata = &sc->sc_fans[fan].sensors[sensor].sensor_data;
+ edata->units = ENVSYS_SFANRPM;
+ edata->state = ENVSYS_SINVALID;
+ edata->flags = ENVSYS_FHAS_ENTROPY;
+ (void)snprintf(edata->desc, sizeof(edata->desc), "fan %s %s speed",
+ name, fan_sensors[sensor].fs_name);
+
+ error = sysmon_envsys_sensor_attach(sc->sc_sme, edata);
+ if (error)
+ goto fail1;
+
+ return;
+
+fail1: apple_smc_release_key(sc->sc_smc, *keyp);
+fail0: *keyp = NULL;
+ aprint_error_dev(sc->sc_dev,
+ "failed to attach fan %s %s speed sensor: %d\n",
+ name, fan_sensors[sensor].fs_name, error);
+}
+
+static void
+apple_smc_fan_refresh(struct sysmon_envsys *sme, struct envsys_data *edata)
+{
+ struct apple_smc_fan_softc *sc = sme->sme_cookie;
+ uint8_t fan, sensor;
+ struct apple_smc_key *key;
+ uint16_t rpm;
+ int error;
+
+ CTASSERT(10 <= (SIZE_MAX / __arraycount(fan_sensors)));
+ KASSERT(sc->sc_nfans < 10);
+ if (edata->sensor >= (sc->sc_nfans * __arraycount(fan_sensors))) {
+ aprint_error_dev(sc->sc_dev, "unknown sensor %"PRIu32"\n",
+ edata->sensor);
+ return;
+ }
+
+ fan = (edata->sensor / __arraycount(fan_sensors));
+ sensor = (edata->sensor % __arraycount(fan_sensors));
+
+ KASSERT(fan < sc->sc_nfans);
+ KASSERT(sensor < __arraycount(fan_sensors));
+ KASSERT(edata == &sc->sc_fans[fan].sensors[sensor].sensor_data);
+
+ /*
+ * If we're refreshing, this sensor got attached, so we ought
+ * to have a sensor key.
+ */
+ key = sc->sc_fans[fan].sensors[sensor].sensor_key;
+ KASSERT(key != NULL);
+
+ error = apple_smc_read_key_2(sc->sc_smc, key, &rpm);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "failed to read fan %d %s speed: %d\n",
+ fan, fan_sensors[sensor].fs_name, error);
+ edata->state = ENVSYS_SINVALID;
+ return;
+ }
+
+ edata->value_cur = rpm;
+ edata->state = ENVSYS_SVALID;
+}
+
+static void
+apple_smc_fan_release_keys(struct apple_smc_fan_softc *sc)
+{
+ uint8_t fan, sensor;
+
+ for (fan = 0; fan < sc->sc_nfans; fan++) {
+ for (sensor = 0;
+ sensor < __arraycount(fan_sensors);
+ sensor++) {
+ struct apple_smc_key **const keyp =
+ &sc->sc_fans[fan].sensors[sensor].sensor_key;
+ if (*keyp != NULL) {
+ apple_smc_release_key(sc->sc_smc, *keyp);
+ *keyp = NULL;
+ }
+ }
+ }
+}
+
+#if 0 /* XXX sysctl */
+static int
+apple_smc_fan_sysctl_setup(struct apple_smc_fan_softc *sc)
+{
+ ...
+}
+
+static void
+apple_smc_fan_sysctl_setup_1(struct apple_smc_fan_softc *sc, uint8_t fan)
+{
+}
+#endif
Index: src/sys/dev/ic/apple_smc_temp.c
diff -u /dev/null src/sys/dev/ic/apple_smc_temp.c:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/dev/ic/apple_smc_temp.c Tue Apr 1 17:47:36 2014
@@ -0,0 +1,361 @@
+/* $NetBSD: apple_smc_temp.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $ */
+
+/*
+ * Apple System Management Controller: Temperature Sensors
+ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: apple_smc_temp.c,v 1.1 2014/04/01 17:47:36 riastradh Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+
+#include <dev/ic/apple_smc.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+struct apple_smc_temp_softc {
+ device_t sc_dev;
+ struct apple_smc_tag *sc_smc;
+ struct sysmon_envsys *sc_sme;
+ struct {
+ struct apple_smc_key *sensor_key;
+ struct envsys_data sensor_data;
+ } *sc_sensors;
+ size_t sc_nsensors;
+};
+
+static int apple_smc_temp_match(device_t, cfdata_t, void *);
+static void apple_smc_temp_attach(device_t, device_t, void *);
+static int apple_smc_temp_detach(device_t, int);
+static void apple_smc_temp_refresh(struct sysmon_envsys *,
+ struct envsys_data *);
+static int apple_smc_temp_count_sensors(struct apple_smc_tag *,
+ uint32_t *);
+static void apple_smc_temp_count_sensors_scanner(struct apple_smc_tag *,
+ void *, struct apple_smc_key *);
+static int apple_smc_temp_find_sensors(struct apple_smc_temp_softc *);
+static int apple_smc_temp_find_sensors_init(struct apple_smc_tag *,
+ void *, uint32_t);
+static void apple_smc_temp_find_sensors_scanner(struct apple_smc_tag *,
+ void *, struct apple_smc_key *);
+static void apple_smc_temp_release_keys(struct apple_smc_temp_softc *);
+static int apple_smc_scan_temp_sensors(struct apple_smc_tag *, void *,
+ int (*)(struct apple_smc_tag *, void *, uint32_t),
+ void (*)(struct apple_smc_tag *, void *,
+ struct apple_smc_key *));
+static int apple_smc_bound_temp_sensors(struct apple_smc_tag *,
+ uint32_t *, uint32_t *);
+static bool apple_smc_temp_sensor_p(const struct apple_smc_key *);
+
+CFATTACH_DECL_NEW(apple_smc_temp, sizeof(struct apple_smc_temp_softc),
+ apple_smc_temp_match, apple_smc_temp_attach, apple_smc_temp_detach, NULL);
+
+static int
+apple_smc_temp_match(device_t parent, cfdata_t match, void *aux)
+{
+ const struct apple_smc_attach_args *asa = aux;
+ uint32_t nsensors;
+ int error;
+
+ error = apple_smc_temp_count_sensors(asa->asa_smc, &nsensors);
+ if (error)
+ return 0;
+
+ if (nsensors == 0)
+ return 0;
+
+ return 1;
+}
+
+static void
+apple_smc_temp_attach(device_t parent, device_t self, void *aux)
+{
+ struct apple_smc_temp_softc *sc = device_private(self);
+ const struct apple_smc_attach_args *asa = aux;
+
+ sc->sc_dev = self;
+ sc->sc_smc = asa->asa_smc;
+ sc->sc_sme = sysmon_envsys_create();
+ sc->sc_sme->sme_name = device_xname(self);
+ sc->sc_sme->sme_cookie = sc;
+ sc->sc_sme->sme_refresh = apple_smc_temp_refresh;
+
+ (void)apple_smc_temp_find_sensors(sc);
+}
+
+static int
+apple_smc_temp_detach(device_t self, int flags)
+{
+ struct apple_smc_temp_softc *sc = device_private(self);
+
+ KASSERT(sc->sc_sme != NULL);
+ sysmon_envsys_unregister(sc->sc_sme);
+ sc->sc_sme = NULL;
+
+ if (sc->sc_sensors != NULL) {
+ KASSERT(sc->sc_nsensors > 0);
+ apple_smc_temp_release_keys(sc);
+ kmem_free(sc->sc_sensors,
+ (sizeof(sc->sc_sensors[0]) * sc->sc_nsensors));
+ sc->sc_sensors = NULL;
+ sc->sc_nsensors = 0;
+ }
+
+ return 0;
+}
+
+static void
+apple_smc_temp_refresh(struct sysmon_envsys *sme, struct envsys_data *edata)
+{
+ struct apple_smc_temp_softc *sc = sme->sme_cookie;
+ const struct apple_smc_key *key;
+ uint16_t utemp16;
+ int32_t temp;
+ int error;
+
+ if (edata->sensor >= sc->sc_nsensors) {
+ aprint_error_dev(sc->sc_dev, "unknown sensor %"PRIu32"\n",
+ edata->sensor);
+ return;
+ }
+
+ key = sc->sc_sensors[edata->sensor].sensor_key;
+ error = apple_smc_read_key_2(sc->sc_smc, key, &utemp16);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "failed to read temperature sensor %"PRIu32" (%s): %d\n",
+ edata->sensor, apple_smc_key_name(key), error);
+ edata->state = ENVSYS_SINVALID;
+ return;
+ }
+
+ /* Sign-extend, in case we ever get below freezing... */
+ temp = (int16_t)utemp16;
+
+ /* Convert to `millicentigrade'. */
+ temp *= 250;
+ temp >>= 6;
+
+ /* Convert to millikelvins. */
+ temp += 273150;
+
+ /* Finally, convert to microkelvins as sysmon_envsys wants. */
+ temp *= 1000;
+
+ edata->value_cur = temp;
+ edata->state = ENVSYS_SVALID;
+}
+
+static int
+apple_smc_temp_count_sensors(struct apple_smc_tag *smc, uint32_t *nsensors)
+{
+
+ *nsensors = 0;
+
+ return apple_smc_scan_temp_sensors(smc, nsensors,
+ NULL,
+ &apple_smc_temp_count_sensors_scanner);
+}
+
+static void
+apple_smc_temp_count_sensors_scanner(struct apple_smc_tag *smc, void *arg,
+ struct apple_smc_key *key)
+{
+ uint32_t *nsensors = arg;
+
+ (*nsensors)++;
+ apple_smc_release_key(smc, key);
+}
+
+struct fss { /* Find Sensors State */
+ struct apple_smc_temp_softc *fss_sc;
+ size_t fss_sensor;
+};
+
+static int
+apple_smc_temp_find_sensors(struct apple_smc_temp_softc *sc)
+{
+ struct fss fss;
+ int error;
+
+ fss.fss_sc = sc;
+ fss.fss_sensor = 0;
+
+ error = apple_smc_scan_temp_sensors(sc->sc_smc, &fss,
+ &apple_smc_temp_find_sensors_init,
+ &apple_smc_temp_find_sensors_scanner);
+ if (error)
+ return error;
+
+ /* Shrink the array if we overshot. */
+ if (fss.fss_sensor < sc->sc_nsensors) {
+ void *sensors = kmem_alloc((fss.fss_sensor *
+ sizeof(sc->sc_sensors[0])), KM_SLEEP);
+ (void)memcpy(sensors, sc->sc_sensors,
+ (fss.fss_sensor * sizeof(sc->sc_sensors[0])));
+ kmem_free(sc->sc_sensors, sc->sc_nsensors);
+ sc->sc_nsensors = fss.fss_sensor;
+ sc->sc_sensors = sensors;
+ }
+
+ return 0;
+}
+
+static int
+apple_smc_temp_find_sensors_init(struct apple_smc_tag *smc, void *arg,
+ uint32_t nsensors)
+{
+ struct fss *fss = arg;
+
+ fss->fss_sc->sc_nsensors = nsensors;
+ if (nsensors == 0)
+ fss->fss_sc->sc_sensors = NULL;
+ else
+ fss->fss_sc->sc_sensors = kmem_alloc((nsensors *
+ sizeof(fss->fss_sc->sc_sensors[0])), KM_SLEEP);
+
+ return 0;
+}
+
+static void
+apple_smc_temp_find_sensors_scanner(struct apple_smc_tag *smc, void *arg,
+ struct apple_smc_key *key)
+{
+ struct fss *fss = arg;
+ const uint32_t sensor = fss->fss_sensor;
+ struct envsys_data *edata =
+ &fss->fss_sc->sc_sensors[sensor].sensor_data;
+ int error;
+
+ edata->units = ENVSYS_STEMP;
+ edata->state = ENVSYS_SINVALID;
+ edata->flags = ENVSYS_FHAS_ENTROPY;
+
+ /*
+ * XXX Use a more meaningful name based on a table of known
+ * temperature sensors.
+ */
+ CTASSERT(sizeof(edata->desc) >= 4);
+ (void)strlcpy(edata->desc, apple_smc_key_name(key), 4);
+
+ error = sysmon_envsys_sensor_attach(fss->fss_sc->sc_sme, edata);
+ if (error) {
+ aprint_error_dev(fss->fss_sc->sc_dev,
+ "failed to attach temperature sensor %s: %d\n",
+ apple_smc_key_name(key), error);
+ return;
+ }
+
+ fss->fss_sc->sc_sensors[sensor].sensor_key = key;
+
+ fss->fss_sensor++;
+}
+
+static void
+apple_smc_temp_release_keys(struct apple_smc_temp_softc *sc)
+{
+ uint32_t sensor;
+
+ for (sensor = 0; sensor < sc->sc_nsensors; sensor++) {
+ KASSERT(sc->sc_sensors[sensor].sensor_key != NULL);
+ apple_smc_release_key(sc->sc_smc,
+ sc->sc_sensors[sensor].sensor_key);
+ }
+}
+
+static int
+apple_smc_scan_temp_sensors(struct apple_smc_tag *smc, void *arg,
+ int (*init)(struct apple_smc_tag *, void *, uint32_t),
+ void (*scanner)(struct apple_smc_tag *, void *, struct apple_smc_key *))
+{
+ uint32_t tstart, ustart, i;
+ struct apple_smc_key *key;
+ int error;
+
+ error = apple_smc_bound_temp_sensors(smc, &tstart, &ustart);
+ if (error)
+ return error;
+ KASSERT(tstart <= ustart);
+
+ if (init != NULL) {
+ error = (*init)(smc, arg, (ustart - tstart));
+ if (error)
+ return error;
+ }
+
+ for (i = tstart; i < ustart; i++) {
+ error = apple_smc_nth_key(smc, i, NULL, &key);
+ if (error)
+ continue;
+
+ if (!apple_smc_temp_sensor_p(key)) {
+ apple_smc_release_key(smc, key);
+ continue;
+ }
+
+ (*scanner)(smc, arg, key);
+ }
+
+ return 0;
+}
+
+static bool
+apple_smc_temp_sensor_p(const struct apple_smc_key *key)
+{
+
+ return (0 == memcmp(apple_smc_key_desc(key)->asd_type,
+ APPLE_SMC_TYPE_SP78, 4));
+}
+
+static int
+apple_smc_bound_temp_sensors(struct apple_smc_tag *smc, uint32_t *tstart,
+ uint32_t *ustart)
+{
+ int error;
+
+ error = apple_smc_key_search(smc, "T", tstart);
+ if (error)
+ return error;
+
+ error = apple_smc_key_search(smc, "U", ustart);
+ if (error)
+ return error;
+
+ if (!(*tstart <= *ustart))
+ return EIO;
+
+ return 0;
+}
Index: src/sys/dev/ic/apple_smcreg.h
diff -u /dev/null src/sys/dev/ic/apple_smcreg.h:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/dev/ic/apple_smcreg.h Tue Apr 1 17:47:36 2014
@@ -0,0 +1,54 @@
+/* $NetBSD: apple_smcreg.h,v 1.1 2014/04/01 17:47:36 riastradh Exp $ */
+
+/*
+ * Apple System Management Controller Registers
+ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _DEV_IC_APPLE_SMCREG_H_
+#define _DEV_IC_APPLE_SMCREG_H_
+
+#define APPLE_SMC_DATA 0x00
+#define APPLE_SMC_CSR 0x04
+#define APPLE_SMC_REGSIZE 0x08
+
+#define APPLE_SMC_STATUS_READ_READY 0x01 /* Ready for read. */
+#define APPLE_SMC_STATUS_WRITE_PENDING 0x02 /* Write not yet accepted. */
+#define APPLE_SMC_STATUS_WRITE_ACCEPTED 0x04 /* Write accepted. */
+
+#define APPLE_SMC_CMD_READ_KEY 0x10
+#define APPLE_SMC_CMD_WRITE_KEY 0x11
+#define APPLE_SMC_CMD_NTH_KEY 0x12
+#define APPLE_SMC_CMD_KEY_DESC 0x13
+
+#define APPLE_SMC_NKEYS_KEY "#KEY"
+
+#endif /* _DEV_IC_APPLE_SMCREG_H_ */
Index: src/sys/dev/ic/apple_smcvar.h
diff -u /dev/null src/sys/dev/ic/apple_smcvar.h:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/dev/ic/apple_smcvar.h Tue Apr 1 17:47:36 2014
@@ -0,0 +1,70 @@
+/* $NetBSD: apple_smcvar.h,v 1.1 2014/04/01 17:47:36 riastradh Exp $ */
+
+/*
+ * Apple System Management Controller State
+ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef _DEV_IC_APPLE_SMCVAR_H_
+#define _DEV_IC_APPLE_SMCVAR_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+
+struct apple_smc_tag {
+ device_t smc_dev;
+ bus_space_tag_t smc_bst;
+ bus_space_handle_t smc_bsh;
+ bus_size_t smc_size;
+ uint32_t smc_nkeys;
+ kmutex_t smc_lock;
+
+#if 0 /* XXX sysctl */
+ struct sysctllog *smc_sysctllog;
+ const struct sysctlnode *smc_sysctlnode;
+#endif
+
+ device_t smc_fan;
+ device_t smc_temp;
+#if 0 /* XXX accelerometer */
+ device_t smc_accel;
+#endif
+};
+
+void apple_smc_attach(struct apple_smc_tag *);
+int apple_smc_rescan(struct apple_smc_tag *, const char *,
+ const int *);
+int apple_smc_detach(struct apple_smc_tag *, int);
+
+#endif /* _DEV_IC_APPLE_SMCVAR_H_ */
Index: src/sys/modules/apple_smc/Makefile
diff -u /dev/null src/sys/modules/apple_smc/Makefile:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/modules/apple_smc/Makefile Tue Apr 1 17:47:36 2014
@@ -0,0 +1,17 @@
+# $NetBSD: Makefile,v 1.1 2014/04/01 17:47:36 riastradh Exp $
+
+.include "../Makefile.inc"
+
+.PATH: ${S}/dev/ic
+.PATH: ${S}/dev/acpi
+
+KMOD= apple_smc
+IOCONF= apple_smc.ioconf
+SRCS= apple_smc.c apple_smc_acpi.c apple_smc_fan.c apple_smc_temp.c
+
+WARNS= 4
+
+# XXX What's the right thing here?
+CPPFLAGS+= -DDIAGNOSTIC
+
+.include <bsd.kmodule.mk>
Index: src/sys/modules/apple_smc/apple_smc.ioconf
diff -u /dev/null src/sys/modules/apple_smc/apple_smc.ioconf:1.1
--- /dev/null Tue Apr 1 17:47:36 2014
+++ src/sys/modules/apple_smc/apple_smc.ioconf Tue Apr 1 17:47:36 2014
@@ -0,0 +1,13 @@
+# $NetBSD: apple_smc.ioconf,v 1.1 2014/04/01 17:47:36 riastradh Exp $
+
+ioconf apple_smc
+
+include "conf/files"
+include "dev/acpi/files.acpi"
+
+pseudo-root acpi*
+
+applesmc* at acpi?
+applesmcfan* at applesmc?
+applesmctemp* at applesmc?
+#applesmcaccel* at applesmc?