diff options
author | 2015-09-30 12:15:12 +0000 | |
---|---|---|
committer | 2015-09-30 12:15:12 +0000 | |
commit | 25d83aa9c941dd99ad2c4777c24afd2c82901b82 (patch) | |
tree | 849b679cd16393faf8c49792d29fb295214bbc2a | |
parent | sync (diff) | |
download | wireguard-openbsd-25d83aa9c941dd99ad2c4777c24afd2c82901b82.tar.xz wireguard-openbsd-25d83aa9c941dd99ad2c4777c24afd2c82901b82.zip |
add a (disabled) driver for the Apple System Management Controller (SMC) as
found in Apple Intel based devices
"go at it" deraadt@
-rw-r--r-- | share/man/man4/asmc.4 | 62 | ||||
-rw-r--r-- | share/man/man4/isa.4 | 6 | ||||
-rw-r--r-- | sys/arch/amd64/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/dev/isa/asmc.c | 651 | ||||
-rw-r--r-- | sys/dev/isa/files.isa | 7 |
6 files changed, 727 insertions, 5 deletions
diff --git a/share/man/man4/asmc.4 b/share/man/man4/asmc.4 new file mode 100644 index 00000000000..154abaceda6 --- /dev/null +++ b/share/man/man4/asmc.4 @@ -0,0 +1,62 @@ +.\" $OpenBSD: asmc.4,v 1.1 2015/09/30 12:15:12 jung Exp $ +.\" +.\" Copyright (c) 2015 Joerg Jung <jung@openbsd.org> +.\" +.\" 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 30 2015 $ +.Dt ASMC 4 +.Os +.Sh NAME +.Nm asmc +.Nd Apple System Management Controller (SMC) +.Sh SYNOPSIS +.Cd "asmc0 at isa? port 0x300" +.Sh DESCRIPTION +The +.Nm +driver provides support for the Apple System Management Controller (SMC), as +found in Intel based Apple devices. +.Pp +The driver possesses a collection of temperature, fan, light, and acceleration +sensor values which are made available through the +.Xr sysctl 8 +interface. +.Pp +If available, the keyboard backlight is enabled by the driver. +.Sh SEE ALSO +.Xr intro 4 , +.Xr isa 4 , +.Xr sensorsd 8 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Ox 5.9 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Joerg Jung Aq Mt jung@openbsd.org . +.Sh CAVEATS +Light sensor values may not be available on older products. +.Pp +Acceleration sensors are not available and the associated interrupt handling is +not implemented. +.Pp +Changing the keyboard backlight value is not implemented. +.Pp +Besides the sensors, the huge amount of other functions and information +available from the SMC is not supported. diff --git a/share/man/man4/isa.4 b/share/man/man4/isa.4 index 1658a68a10d..f261022746a 100644 --- a/share/man/man4/isa.4 +++ b/share/man/man4/isa.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: isa.4,v 1.73 2014/12/10 05:42:25 jsg Exp $ +.\" $OpenBSD: isa.4,v 1.74 2015/09/30 12:15:12 jung Exp $ .\" $NetBSD: isa.4,v 1.19 2000/03/18 16:54:37 augustss Exp $ .\" .\" Copyright (c) 2000 Theo de Raadt. All rights reserved. @@ -31,7 +31,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: December 10 2014 $ +.Dd $Mdocdate: September 30 2015 $ .Dt ISA 4 .Os .Sh NAME @@ -185,6 +185,8 @@ SoundForte RadioLink SF16-FMR2 FM radio device .Bl -tag -width 12n -offset ind -compact .It Xr aps 4 ThinkPad Active Protection System accelerometer +.It Xr asmc 4 +Apple System Management Controller (SMC) .It Xr fins 4 Fintek F71805F LPC Super I/O .It Xr it 4 diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index ea31984b4e0..e05d37a9fad 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.396 2015/09/10 16:30:23 krw Exp $ +# $OpenBSD: GENERIC,v 1.397 2015/09/30 12:15:12 jung Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -105,6 +105,7 @@ lm* at wbsio? uguru0 at isa? disable port 0xe0 # ABIT uGuru aps0 at isa? port 0x1600 # ThinkPad Active Protection System +#asmc0 at isa? port 0x300 # Apple SMC piixpm* at pci? # Intel PIIX PM iic* at piixpm? diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index eeb90afa13a..1f94e7538c7 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.805 2015/09/10 16:30:23 krw Exp $ +# $OpenBSD: GENERIC,v 1.806 2015/09/30 12:15:12 jung Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -154,6 +154,7 @@ uguru0 at isa? disable port 0xe0 # ABIT uGuru fins0 at isa? port 0x4e # Fintek F71805 Super I/O aps0 at isa? port 0x1600 # ThinkPad Active Protection System +#asmc0 at isa? port 0x300 # Apple SMC itherm* at pci? # Intel 3400 Thermal Sensor adc* at iic? # Analog Devices AD7416/AD7417/7418 diff --git a/sys/dev/isa/asmc.c b/sys/dev/isa/asmc.c new file mode 100644 index 00000000000..a5d81798efc --- /dev/null +++ b/sys/dev/isa/asmc.c @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2015 Joerg Jung <jung@openbsd.org> + * + * 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 Apple's System Management Controller (SMC) + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/sensors.h> + +#include <machine/bus.h> + +#include <dev/isa/isavar.h> + +#define ASMC_BASE 0x300 /* SMC base address */ +#define ASMC_IOSIZE 32 /* I/O region size 0x300-0x31f */ + +#define ASMC_DATA 0x00 /* SMC data port offset */ +#define ASMC_COMMAND 0x04 /* SMC command port offset */ +#define ASMC_STATUS 0x1e /* SMC status port offset */ +#define ASMC_INTERRUPT 0x1f /* SMC interrupt port offset */ + +#define ASMC_READ 0x10 /* SMC read command */ +#define ASMC_WRITE 0x11 /* SMC write command */ +#define ASMC_INFO 0x13 /* SMC info/type command */ + +#define ASMC_RETRY 10 +#define ASMC_MAXLEN 32 /* SMC maximum data size len */ +#define ASMC_NOTFOUND 0x84 /* SMC status key not found */ + +#define ASMC_MAXTEMP 101 /* known asmc_prods temperature sensor keys */ +#define ASMC_MAXFAN 10 /* fan keys with digits 0-9 */ +#define ASMC_MAXLIGHT 2 /* left and right light sensor */ +#define ASMC_MAXMOTION 3 /* x y z axis motion sensors */ + +struct asmc_prod { + const char *pr_name; + const char *pr_temp[ASMC_MAXTEMP]; +}; + +struct asmc_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + struct asmc_prod *sc_prod; + uint8_t sc_lightlen; /* light data len */ + + struct ksensor sc_sensor_temp[ASMC_MAXTEMP]; + struct ksensor sc_sensor_fan[ASMC_MAXFAN]; + struct ksensor sc_sensor_light[ASMC_MAXLIGHT]; + struct ksensor sc_sensor_motion[ASMC_MAXMOTION]; + struct ksensordev sc_sensor_dev; + struct sensor_task *sc_sensor_task; +}; + +int asmc_init(struct asmc_softc *); +void asmc_update(void *); + +int asmc_match(struct device *, void *, void *); +void asmc_attach(struct device *, struct device *, void *); +int asmc_detach(struct device *, int); + +struct cfattach asmc_ca = { + sizeof(struct asmc_softc), asmc_match, asmc_attach +}; + +struct cfdriver asmc_cd = { + NULL, "asmc", DV_DULL +}; + +static struct asmc_prod asmc_prods[] = { + { "MacBookAir", { + "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0C", "TC0D", "TC0E", + "TC0F", "TC0P", "TC1C", "TC1E", "TC2C", "TCFP", "TCGC", "TCSA", + "TCZ3", "TCZ4", "TCZ5", "TG0E", "TG1E", "TG2E", "TGZ3", "TGZ4", + "TGZ5", "THSP", "TM0P", "TN0D", "TPCD", "TTF0", "TV0P", "TVFP", + "TW0P", "Ta0P", "Th0H", "Th0P", "Th1H", "Tm0P", "Tm1P", "Tp0P", + "Tp1P", "TpFP", "Ts0P", "Ts0S", NULL } + }, + { "MacBookPro", { + "TA0P", "TALP", "TB0T", "TB1T", "TB2T", "TB3T", "TBXT", "TC0C", + "TC0D", "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", "TC4C", + "TCFC", "TCGC", "TCSA", "TCTD", "TCXC", "TG0D", "TG0F", "TG0H", + "TG0P", "TG0T", "TG1D", "TG1F", "TG1H", "TG1d", "TH0A", "TH0B", + "TH0F", "TH0R", "TH0V", "TH0a", "TH0b", "TH0c", "THSP", "TM0P", + "TM0S", "TMBS", "TMCD", "TN0D", "TN0P", "TN0S", "TN1D", "TN1F", + "TN1G", "TN1S", "TP0P", "TPCD", "TTF0", "TW0P", "Ta0P", "TaSP", + "Th0H", "Th1H", "Th2H", "Tm0P", "Ts0P", "Ts0S", "Ts1P", "Ts1S", + NULL } + }, + { "MacBook", { + "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TM0P", "TN0D", + "TN0P", "TN1P", "TTF0", "TW0P", "Th0H", "Th0S", "Th1H", "ThFH", + "Ts0P", "Ts0S", NULL } + }, + { "MacPro", { + "TA0P", "TC0C", "TC0D", "TC0P", "TC1C", "TC1D", "TC2C", "TC2D", + "TC3C", "TC3D", "TCAC", "TCAD", "TCAG", "TCAH", "TCAS", "TCBC", + "TCBD", "TCBG", "TCBH", "TCBS", "TH0P", "TH1F", "TH1P", "TH1V", + "TH2F", "TH2P", "TH2V", "TH3F", "TH3P", "TH3V", "TH4F", "TH4P", + "TH4V", "THPS", "THTG", "TM0P", "TM0S", "TM1P", "TM1S", "TM2P", + "TM2S", "TM2V", "TM3P", "TM3S", "TM3V", "TM4P", "TM5P", "TM6P", + "TM6V", "TM7P", "TM7V", "TM8P", "TM8S", "TM8V", "TM9P", "TM9S", + "TM9V", "TMA1", "TMA2", "TMA3", "TMA4", "TMAP", "TMAS", "TMB1", + "TMB2", "TMB3", "TMB4", "TMBS", "TMHS", "TMLS", "TMPS", "TMPV", + "TMTG", "TN0C", "TN0D", "TN0H", "TNTG", "TS0C", "Te1F", "Te1P", + "Te1S", "Te2F", "Te2S", "Te3F", "Te3S", "Te4F", "Te4S", "Te5F", + "Te5S", "TeGG", "TeGP", "TeRG", "TeRP", "TeRV", "Tp0C", "Tp1C", + "TpPS", "TpTG", "Tv0S", "Tv1S", NULL } + }, + { "MacMini", { + "TC0D", "TC0H", "TC0P", "TH0P", "TN0D", "TN0P", "TN0P", "TN1P", + "TW0P", NULL } + }, + { "iMac", { + "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P", + "TL0P", "TN0D", "TN0H", "TN0P", "TO0P", "TW0P", "Tm0P", "Tp0C", + "Tp0P", NULL } + }, + { NULL, { NULL } } +}; + +static const char *asmc_temp_desc[][2] = { + { "TA0P", "Ambient" }, { "TA0P", "HDD Bay 1" }, + { "TA0S", "PCI Slot 1 Pos 1" }, { "TA1P", "Ambient 2" }, + { "TA1S", "PCI Slot 1 Pos 2" }, { "TA2S", "PCI Slot 2 Pos 1" }, + { "TA3S", "PCI Slot 2 Pos 2" }, + { "TB0T", "Enclosure Bottom" }, { "TB1T", "Enclosure Bottom 2" }, + { "TB2T", "Enclosure Bottom 3" }, { "TB3T", "Enclosure Bottom 4" }, + { "TC0D", "CPU0 Die Core" }, { "TC0H", "CPU0 Heatsink" }, + { "TC0P", "CPU0 Proximity" }, + { "TC1D", "CPU1" }, { "TC2D", "CPU2" }, { "TC3D", "CPU3" }, + { "TCAH", "CPU0" }, { "TCBH", "CPU1" }, { "TCCH", "CPU2" }, + { "TCDH", "CPU3" }, + { "TG0D", "GPU0 Diode" }, { "TG0H", "GPU0 Heatsink" }, + { "TG0P", "GPU0 Proximity" }, + { "TG1H", "GPU Heatsink 2" }, + { "TH0P", "HDD Bay 1" }, { "TH1P", "HDD Bay 2" }, + { "TH2P", "HDD Bay 3" }, { "TH3P", "HDD Bay 4" }, + { "TL0P", "LCD Proximity"}, + { "TM0P", "Mem Bank A1" }, { "TM0S", "Mem module A1" }, + { "TM1P", "Mem Bank A2" }, { "TM1S", "Mem module A2" }, + { "TM2P", "Mem Bank A3" }, { "TM2S", "Mem module A3" }, + { "TM3P", "Mem Bank A4" }, { "TM3S", "Mem module A4" }, + { "TM4P", "Mem Bank A5" }, { "TM4S", "Mem module A5" }, + { "TM5P", "Mem Bank A6" }, { "TM5S", "Mem module A6" }, + { "TM6P", "Mem Bank A7" }, { "TM6S", "Mem module A7" }, + { "TM7P", "Mem Bank A8" }, { "TM7S", "Mem module A8" }, + { "TM8P", "Mem Bank B1" }, { "TM8S", "Mem module B1" }, + { "TM9P", "Mem Bank B2" }, { "TM9S", "Mem module B2" }, + { "TMA1", "RAM A1" }, { "TMA2", "RAM A2" }, + { "TMA3", "RAM A3" }, { "TMA4", "RAM A4" }, + { "TMB1", "RAM B1" }, { "TMB2", "RAM B2" }, + { "TMB3", "RAM B3" }, { "TMB4", "RAM B4" }, + { "TMAP", "Mem Bank B3" }, { "TMAS", "Mem module B3" }, + { "TMBP", "Mem Bank B4" }, { "TMBS", "Mem module B4" }, + { "TMCP", "Mem Bank B5" }, { "TMCS", "Mem module B5" }, + { "TMDP", "Mem Bank B6" }, { "TMDS", "Mem module B6" }, + { "TMEP", "Mem Bank B7" }, { "TMES", "Mem module B7" }, + { "TMFP", "Mem Bank B8" }, { "TMFS", "Mem module B8" }, + { "TN0D", "Northbridge Die Core" }, { "TN0H", "Northbridge" }, + { "TN0P", "Northbridge Proximity" }, { "TN1P", "Northbridge 2" }, + { "TO0P", "Optical Drive" }, { "TS0C", "Expansion Slots" }, + { "TW0P", "Wireless Airport Card" }, + { "Th0H", "Main Heatsink A" }, { "Th1H", "Main Heatsink B" }, + { "Th2H", "Main Heatsink C" }, + { "Tm0P", "Memory Controller" }, + { "Tp0C", "Power supply 1" }, { "Tp0P", "Power supply 1" }, + { "Tp1C", "Power supply 2" }, { "Tp1P", "Power supply 2" }, + { "Tp2P", "Power supply 3" }, { "Tp3P", "Power supply 4" }, + { "Tp4P", "Power supply 5" }, { "Tp5P", "Power supply 6" }, + { NULL, NULL } +}; + +static const char *asmc_light_desc[ASMC_MAXLIGHT] = { + "left", "right" +}; + +extern char *hw_vendor, *hw_prod; + +int +asmc_match(struct device *parent, void *match, void *aux) +{ + struct asmc_softc *sc = match; + struct isa_attach_args *ia = aux; + bus_space_handle_t ioh; + int i; + + if (!hw_vendor || !hw_prod || strcmp(hw_vendor, "Apple Inc.")) + return 0; + + for (i = 0; asmc_prods[i].pr_name && !sc->sc_prod; i++) + if (!strncasecmp(asmc_prods[i].pr_name, hw_prod, + strlen(asmc_prods[i].pr_name))) + sc->sc_prod = &asmc_prods[i]; + if (!sc->sc_prod) + return 0; + + if (ia->ia_iobase != ASMC_BASE || + bus_space_map(ia->ia_iot, ia->ia_iobase, ASMC_IOSIZE, 0, &ioh)) + return 0; + + bus_space_unmap(ia->ia_iot, ioh, ASMC_IOSIZE); + ia->ia_iosize = ASMC_IOSIZE; + ia->ipa_nio = 1; + ia->ipa_nmem = 0; + ia->ipa_nirq = 0; + ia->ipa_ndrq = 0; + + return 1; +} + +void +asmc_attach(struct device *parent, struct device *self, void *aux) +{ + struct asmc_softc *sc = (struct asmc_softc *)self; + struct isa_attach_args *ia = aux; + + if (bus_space_map(ia->ia_iot, ia->ia_iobase, ia->ia_iosize, 0, + &sc->sc_ioh)) { + printf(": can't map i/o space\n"); + return; + } + sc->sc_iot = ia->ia_iot; + + printf("\n"); + + strlcpy(sc->sc_sensor_dev.xname, sc->sc_dev.dv_xname, + sizeof(sc->sc_sensor_dev.xname)); + + if (asmc_init(sc)) { + printf("%s: unable to initialize\n", sc->sc_dev.dv_xname); + bus_space_unmap(ia->ia_iot, ia->ia_iobase, ASMC_IOSIZE); + return; + } + + if (!(sc->sc_sensor_task = sensor_task_register(sc, asmc_update, 8))) { + printf("%s: unable to register task\n", sc->sc_dev.dv_xname); + bus_space_unmap(ia->ia_iot, ia->ia_iobase, ASMC_IOSIZE); + return; + } + sensordev_install(&sc->sc_sensor_dev); +} + +int +asmc_detach(struct device *self, int flags) +{ + struct asmc_softc *sc = (struct asmc_softc *)self; + int i; + + wakeup(&sc->sc_sensor_task); + sensordev_deinstall(&sc->sc_sensor_dev); + if (sc->sc_sensor_task) + sensor_task_unregister(sc->sc_sensor_task); + + for (i = 0; i < ASMC_MAXMOTION; i++) + sensor_detach(&sc->sc_sensor_dev, &sc->sc_sensor_motion[i]); + + for (i = 0; i < ASMC_MAXLIGHT; i++) + sensor_detach(&sc->sc_sensor_dev, &sc->sc_sensor_light[i]); + + for (i = 0; i < ASMC_MAXFAN; i++) + sensor_detach(&sc->sc_sensor_dev, &sc->sc_sensor_fan[i]); + + for (i = 0; i < ASMC_MAXTEMP; i++) + sensor_detach(&sc->sc_sensor_dev, &sc->sc_sensor_temp[i]); + + return 0; +} + +static uint8_t +asmc_status(struct asmc_softc *sc) +{ + return bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASMC_STATUS); +} + +static int +asmc_wait(struct asmc_softc *sc, uint8_t m) +{ + int us; + + for (us = (2 << 4); us < (2 << 16); us *= 2) { /* wait up to 128 ms */ + (!sc->sc_sensor_task) ? delay(us) : + tsleep(&sc->sc_sensor_task, 0, "asmc", + (us * hz + 999999) / 1000000 + 1); + if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASMC_COMMAND) & m) + return 1; + } + return 0; +} + +static int +asmc_write(struct asmc_softc *sc, uint8_t off, uint8_t val) +{ + int i; + + for (i = 0; i < ASMC_RETRY; i++) { + bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, val); + if (asmc_wait(sc, 0x04)) /* write accepted? */ + return 0; + } + return 1; +} + +static int +asmc_read(struct asmc_softc *sc, uint8_t off, uint8_t *buf) +{ + if (asmc_wait(sc, 0x01)) { /* ready for read? */ + *buf = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off); + return 0; + } + return 1; +} + +static int +asmc_command(struct asmc_softc *sc, int cmd, const char *key, uint8_t *buf, + uint8_t len) +{ + uint8_t n; + int i; + + if (len > ASMC_MAXLEN) + return 1; + if (asmc_write(sc, ASMC_COMMAND, cmd)) + return 1; + for (i = 0; i < 4; i++) + if (asmc_write(sc, ASMC_DATA, key[i])) + return 1; + if (asmc_write(sc, ASMC_DATA, len)) + return 1; + if (cmd == ASMC_READ || cmd == ASMC_INFO) { + for (i = 0; i < len; i++) + if (asmc_read(sc, ASMC_DATA, &buf[i])) + return 1; + for (i = 0; i < ASMC_MAXLEN; i++) /* sanity flush */ + if (asmc_read(sc, ASMC_DATA, &n)) + break; + } else if (cmd == ASMC_WRITE) { + for (i = 0; i < len; i++) + if (asmc_write(sc, ASMC_DATA, buf[i])) + return 1; + } else + return 1; + return 0; +} + +static int +asmc_try(struct asmc_softc *sc, int cmd, const char *key, uint8_t *buf, + uint8_t len) +{ + int i; + + for (i = 0; i < ASMC_RETRY; i++) + if (!asmc_command(sc, cmd, key, buf, len)) + return 0; + return 1; +} + +static int +asmc_temps(struct asmc_softc *sc, uint8_t *n) +{ + uint8_t buf[2], s; + int i, j; + + for (i = 0, *n = 0; i < ASMC_MAXTEMP; i++) { + sc->sc_sensor_temp[i].type = SENSOR_TEMP; + sc->sc_sensor_temp[i].flags |= SENSOR_FINVALID; + if (!sc->sc_prod->pr_temp[i]) + continue; + + s = 0; + if (asmc_try(sc, ASMC_READ, sc->sc_prod->pr_temp[i], buf, 2) && + (s = asmc_status(sc)) != ASMC_NOTFOUND) { + printf(", read %s failed (0x%x)", + sc->sc_prod->pr_temp[i], s); + continue; /*return 1;*/ + } + if (s == ASMC_NOTFOUND) + continue; + + (*n)++; + strlcpy(sc->sc_sensor_temp[i].desc, sc->sc_prod->pr_temp[i], + sizeof(sc->sc_sensor_temp[i].desc)); + for (j = 0; asmc_temp_desc[j][0]; j++) + if (!strcmp(asmc_temp_desc[j][0], + sc->sc_prod->pr_temp[i])) + break; + if (asmc_temp_desc[j][0]) { + strlcat(sc->sc_sensor_temp[i].desc, " ", + sizeof(sc->sc_sensor_temp[i].desc)); + strlcat(sc->sc_sensor_temp[i].desc, + asmc_temp_desc[j][1], + sizeof(sc->sc_sensor_temp[i].desc)); + } + sc->sc_sensor_temp[i].flags &= ~SENSOR_FINVALID; + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_temp[i]); + } + return 0; +} + +static int +asmc_fans(struct asmc_softc *sc, uint8_t *n) +{ + char key[5]; + uint8_t buf[16], *end; + int i; + + *n = 0; + if (asmc_try(sc, ASMC_READ, "FNum", buf, 1)) { + printf(", read FNum failed (0x%x)", asmc_status(sc)); + return 1; + } + *n = buf[0]; + + for (i = 0; i < ASMC_MAXFAN; i++) { + sc->sc_sensor_fan[i].type = SENSOR_FANRPM; + sc->sc_sensor_fan[i].flags |= SENSOR_FINVALID; + if (i >= *n) + continue; + + snprintf(key, sizeof(key), "F%dID", i); + if (asmc_try(sc, ASMC_READ, key, buf, 16)) { + printf(", read %s failed (0x%x)", key, + asmc_status(sc)); + return 1; + } + end = buf + 4 + strlen((char *)buf + 4) - 1; + while (buf + 4 < end && *end == ' ') /* trim trailing spaces */ + *end-- = '\0'; + strlcpy(sc->sc_sensor_fan[i].desc, buf + 4, + sizeof(sc->sc_sensor_fan[i].desc)); + sc->sc_sensor_fan[i].flags &= ~SENSOR_FINVALID; + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_fan[i]); + } + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_fan[3]); + return 0; +} + +static int +asmc_lights(struct asmc_softc *sc, uint8_t *n) +{ + char key[5]; + uint8_t buf[6], s; + int i; + + for (i = 0, *n = 0; i < ASMC_MAXLIGHT; i++) { + sc->sc_sensor_light[i].type = SENSOR_LUX; + sc->sc_sensor_light[i].flags |= SENSOR_FINVALID; + s = 0; + snprintf(key, sizeof(key), "ALV%d", i); + if (asmc_try(sc, ASMC_READ, key, buf, 6) && + (s = asmc_status(sc) != ASMC_NOTFOUND)) { + printf(", read %s failed (0x%x)", key, s); + return 1; + } + if (s == ASMC_NOTFOUND) + continue; + + (*n)++; + if (!sc->sc_lightlen) { + if (asmc_try(sc, ASMC_INFO, key, buf, 6)) { + printf(", info %s failed (0x%x)", key, + asmc_status(sc)); + return 1; + } + sc->sc_lightlen = buf[0]; + } + strlcpy(sc->sc_sensor_light[i].desc, asmc_light_desc[i], + sizeof(sc->sc_sensor_light[i].desc)); + sc->sc_sensor_light[i].flags &= ~SENSOR_FINVALID; + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_light[i]); + } + return 0; +} + +static int +asmc_motions(struct asmc_softc *sc, uint8_t *n) +{ + uint8_t buf[2], s; + int i; + + *n = 0; + if (asmc_try(sc, ASMC_READ, "MOCN", buf, 2) && + (s = asmc_status(sc)) != ASMC_NOTFOUND) { + printf(", read MOCN failed (0x%x)", s); + return 1; + } + if (s == ASMC_NOTFOUND); + return 0; + + *n = 1; +#if 0 /* todo: initialize sudden motion sensors and setup interrupt handling */ + buf[0] = 0xe0, buf[1] = 0xf8; + if (asmc_try(sc, ASMC_WRITE, "MOCN", buf, 2)) { + printf(", write MOCN failed (0x%x)", asmc_status(sc)); + return 0; + } +#endif + for (i = 0; i < ASMC_MAXMOTION; i++) { + sc->sc_sensor_motion[i].type = SENSOR_ACCEL; + sc->sc_sensor_motion[i].flags |= SENSOR_FINVALID; + +#if 0 /* todo: setup and attach sensors and description */ + strlcpy(sc->sc_sensor_motion[i].desc, 120 + i, /* x, y, z */ + sizeof(sc->sc_sensor_motion[i].desc)); + strlcat(sc->sc_sensor_motion[i].desc, "-axis", + sizeof(sc->sc_sensor_motion[i].desc)); + sc->sc_sensor_motion[i].flags &= ~SENSOR_FINVALID; + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_motion[i]); +#endif + } + return 0; +} + +int +asmc_init(struct asmc_softc *sc) +{ + uint8_t buf[6], n, s; + + printf("%s:", sc->sc_dev.dv_xname); + + if (asmc_try(sc, ASMC_READ, "REV ", buf, 6)) { + printf(" revision failed (0x%x)\n", asmc_status(sc)); + return 1; + } + printf(" rev %x.%x%x%x", buf[0], buf[1], buf[2], + ntohs(*(uint16_t *)buf + 4)); + + if (asmc_try(sc, ASMC_READ, "#KEY", buf, 4)) { + printf(", no of keys failed (0x%x)\n", asmc_status(sc)); + return 1; + } + printf(", %u key%s", ntohl(*(uint32_t *)buf), + (ntohl(*(uint32_t *)buf) == 1) ? "" : "s"); + + if (asmc_temps(sc, &n)) { /* temperature sensors depend on product */ + printf(", temperature sensors failed\n"); + return 1; + } + printf(", %u temperature%s", n, (n == 1) ? "" : "s"); + + if (asmc_fans(sc, &n)) { /* fan sensors depend on product */ + printf(", fan sensors failed\n"); + return 1; + } + printf(", %u fan%s", n, (n == 1) ? "" : "s"); + + if (asmc_lights(sc, &n)) { /* l/r light sensors are optional */ + printf(", light sensors failed\n"); + return 1; + } + printf(", %u light%s", n, (n == 1) ? "" : "s"); + + if (asmc_motions(sc, &n)) { /* motion sensors are optional */ + printf(", sudden motion sensors failed\n"); + return 1; + } + printf("%s", n ? ", motions" : ""); + + buf[0] = 127, buf[1] = 0; /* keyboard backlight led is optional */ + if (asmc_try(sc, ASMC_WRITE, "LKSB", buf, 2) && + (s = asmc_status(sc)) != ASMC_NOTFOUND) { + printf(", keyboard backlight failed (0x%x)\n", s); + return 1; + } + printf("%s\n", (s == ASMC_NOTFOUND) ? "" : ", kbdled"); + + return 0; +} + +void +asmc_update(void *arg) +{ + struct asmc_softc *sc = arg; + char key[5]; + uint8_t buf[10]; + int i; + + /* spe78: floating point, signed, 7 bits exponent, 8 bits fraction */ + for (i = 0; i < ASMC_MAXTEMP; i++) { + if (!(sc->sc_sensor_temp[i].flags & SENSOR_FINVALID) && + !asmc_try(sc, ASMC_READ, sc->sc_prod->pr_temp[i], buf, 2)) + sc->sc_sensor_temp[i].value = + (((int16_t)ntohs(*(uint16_t *)buf)) >> 8) * + 1000000 + 273150000; + } + + /* fpe2: floating point, unsigned, 14 bits exponent, 2 bits fraction */ + for (i = 0; i < ASMC_MAXFAN; i++) { + snprintf(key, sizeof(key), "F%dAc", i); + if (!(sc->sc_sensor_fan[i].flags & SENSOR_FINVALID) && + !asmc_try(sc, ASMC_READ, key, buf, 2)) + sc->sc_sensor_fan[i].value = + ntohs(*(uint16_t *)buf) >> 2; + } + + for (i = 0; i < ASMC_MAXLIGHT; i++) { + snprintf(key, sizeof(key), "ALV%d", i); + if (!(sc->sc_sensor_light[i].flags & SENSOR_FINVALID) && + !asmc_try(sc, ASMC_READ, key, buf, sc->sc_lightlen)) { + if (!buf[0]) { /* check if found data is valid */ + sc->sc_sensor_light[i].flags |= + SENSOR_FINVALID; + continue; + } + /* newer macbooks report an 10 bit big endian value */ + sc->sc_sensor_light[i].value = + (sc->sc_lightlen == 10) ? + /* + * fp18.14: floating point, + * 18 bits exponent, 14 bits fraction + */ + (ntohl(*(uint32_t *)(buf + 6)) >> 14) * 1000000 : + /* + * todo: calculate lux from ADC raw data: + * buf[1] true/false for high/low gain chan reads + * chan 0: ntohs(*(uint16_t *)(buf + 2)); + * chan 1: ntohs(*(uint16_t *)(buf + 4)); + */ + ((sc->sc_sensor_light[i].flags |= + SENSOR_FUNKNOWN), 0); + } + } + +#if 0 /* todo: implement motion sensors update */ + for (i = 0; i < ASMC_MAXMOTION; i++) { + snprintf(key, sizeof(key), "MO_%c", 88 + i); /* X, Y, Z */ + if (!(sc->sc_sensor_motion[i].flags & SENSOR_FINVALID) && + !asmc_try(sc, ASMC_READ, key, buf, 2)) + sc->sc_sensor_motion[i].value = 0; + } +#endif +} diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 565e2bfb1be..863d11c2afd 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $OpenBSD: files.isa,v 1.118 2015/05/11 06:46:21 ratchov Exp $ +# $OpenBSD: files.isa,v 1.119 2015/09/30 12:15:12 jung Exp $ # $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $ # # Config file and device description for machine-independent ISA code. @@ -360,6 +360,11 @@ device aps attach aps at isa file dev/isa/aps.c aps +# Apple System Management Controller (SMC) +device asmc +attach asmc at isa +file dev/isa/asmc.c asmc + # ISA I/O mapped as GPIO device isagpio: gpiobus attach isagpio at isa |