> Date: Sat, 12 Sep 2020 09:20:26 +0200 > From: Marcus Glocker <[email protected]> > > On Fri, 11 Sep 2020 23:18:56 +0200 (CEST) > Mark Kettenis <[email protected]> wrote: > > > > Date: Fri, 11 Sep 2020 17:42:23 +0200 > > > From: Marcus Glocker <[email protected]> > > > > > > On Thu, 10 Sep 2020 23:44:38 +0200 > > > Joerg Jung <[email protected]> wrote: > > > > > > > Don’t give up so quickly ;) > > > > let’s try to make the driver work on your iMac, send me dmesg and > > > > sysctl hw output please. > > > > > > > > Your idea of converting it to ACPI is the right thing to do > > > > anyways, would be nice to get this working. > > > > > > Here we go: > > > > > > $ dmesg | grep smc > > > asmc0 at acpi0: SMC_ (smc-piketon) addr 0x300/0x20: rev 1.64f564, > > > 276 keys > > > > > > $ sysctl -a | grep smc > > > hw.sensors.asmc0.temp0=27.00 degC (TA0P ambient) > > > hw.sensors.asmc0.temp1=42.00 degC (TC0H cpu0 heatsink) > > > hw.sensors.asmc0.temp2=55.00 degC (TG0D gpu0 diode) > > > hw.sensors.asmc0.temp3=53.00 degC (TG0H gpu0 heatsink) > > > hw.sensors.asmc0.temp4=38.00 degC (TL0P lcd proximity) > > > hw.sensors.asmc0.temp5=41.00 degC (TO0P optical drive) > > > hw.sensors.asmc0.temp6=50.00 degC (Tm0P memory controller) > > > hw.sensors.asmc0.fan0=998 RPM (ODD, right mid rear) > > > hw.sensors.asmc0.fan1=1158 RPM (HDD, center mid rear) > > > hw.sensors.asmc0.fan2=1200 RPM (CPU, left lower rear) > > > > > > Does that work for you guys? > > > > $ dmesg | grep smc > > asmc0 at acpi0: SMC_ (smc-napa) addr 0x300/0x20: rev 1.3f503, 137 keys > > > > $ sysctl -a | grep smc > > hw.sensors.asmc0.temp0=63.00 degC (TC0D cpu0 die core) > > hw.sensors.asmc0.temp1=55.00 degC (TC0H cpu0 heatsink) > > hw.sensors.asmc0.temp2=58.00 degC (TC0P cpu0 proximity) > > hw.sensors.asmc0.temp3=52.00 degC (TN0P northbridge proximity) > > hw.sensors.asmc0.temp4=52.00 degC (TN1P northbridge 2) > > hw.sensors.asmc0.fan0=2077 RPM (Master, left upper front) > > > > So yes, this works for me. > > Cool. > > > You'll need to make changes to the i386 GENERIC kernel as well. > > Yep, done. > > > And I'd like to ask you to make one small change... > > > > +const char *acpiapplesmc_hids[] = { > > > > ...can you rename this variable to asmc_hids[]? > > Of course, copy/pasto, thanks for spotting. > > Also Joerg did suggest to hard code smc0 in GENERIC like it was before, > since it won't be possible that there is more than 1 SMC available on a > machine.
Meh. We tend to only do that if there is a fundamental reason why there can only be one. But it doesn't hurt. ok kettenis@ > Index: sys/arch/amd64/conf/GENERIC > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v > retrieving revision 1.490 > diff -u -p -u -p -r1.490 GENERIC > --- sys/arch/amd64/conf/GENERIC 2 Jun 2020 16:24:24 -0000 1.490 > +++ sys/arch/amd64/conf/GENERIC 12 Sep 2020 07:17:29 -0000 > @@ -68,6 +68,7 @@ glkgpio* at acpi? > sdhc* at acpi? > acpicbkbd* at acpi? > acpials* at acpi? > +asmc0 at acpi? # Apple SMC > tpm* at acpi? > acpihve* at acpi? > acpisurface* at acpi? > @@ -132,7 +133,6 @@ 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? > Index: sys/arch/i386/conf/GENERIC > =================================================================== > RCS file: /cvs/src/sys/arch/i386/conf/GENERIC,v > retrieving revision 1.851 > diff -u -p -u -p -r1.851 GENERIC > --- sys/arch/i386/conf/GENERIC 22 Jun 2020 00:33:28 -0000 1.851 > +++ sys/arch/i386/conf/GENERIC 12 Sep 2020 07:17:30 -0000 > @@ -62,6 +62,7 @@ acpivideo* at acpi? > acpivout* at acpivideo? > acpipwrres* at acpi? > aibs* at acpi? > +asmc0 at acpi? # Apple SMC > > option PCIVERBOSE > option EISAVERBOSE > @@ -148,7 +149,6 @@ uguru0 at isa? disable port 0xe0 # ABIT > 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 > Index: sys/dev/acpi/asmc.c > =================================================================== > RCS file: sys/dev/acpi/asmc.c > diff -N sys/dev/acpi/asmc.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ sys/dev/acpi/asmc.c 12 Sep 2020 07:17:31 -0000 > @@ -0,0 +1,744 @@ > +/* $OpenBSD: asmc.c,v 1.33 2020/08/26 03:29:06 visa Exp $ */ > +/* > + * Copyright (c) 2015 Joerg Jung <[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 Apple's System Management Controller (SMC) an H8S/2117 chip > + */ > + > +#include <sys/param.h> > +#include <sys/systm.h> > +#include <sys/device.h> > +#include <sys/kernel.h> > +#include <sys/rwlock.h> > +#include <sys/task.h> > +#include <sys/sensors.h> > + > +#include <machine/bus.h> > + > +#include <dev/acpi/acpivar.h> > +#include <dev/acpi/acpidev.h> > +#include <dev/acpi/amltypes.h> > +#include <dev/acpi/dsdt.h> > + > +#include <dev/wscons/wsconsio.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_OBF 0x01 /* Output buffer full */ > +#define ASMC_IBF 0x02 /* Input buffer full */ > +#define ASMC_ACCEPT 0x04 > + > +#define ASMC_RETRY 3 > +#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; > + uint8_t pr_light; > + const char *pr_temp[ASMC_MAXTEMP]; > +}; > + > +struct asmc_softc { > + struct device sc_dev; > + > + struct acpi_softc *sc_acpi; > + struct aml_node *sc_devnode; > + > + bus_space_tag_t sc_iot; > + bus_space_handle_t sc_ioh; > + > + struct asmc_prod *sc_prod; > + uint8_t sc_nfans; /* number of fans */ > + uint8_t sc_lightlen; /* light data len */ > + uint8_t sc_backlight; /* keyboard backlight value */ > + > + struct rwlock sc_lock; > + struct task sc_task_backlight; > + > + 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_try(struct asmc_softc *, int, const char *, uint8_t *, uint8_t); > +void 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); > +int asmc_activate(struct device *, int); > + > +/* wskbd hook functions */ > +void asmc_backlight(void *); > +int asmc_get_backlight(struct wskbd_backlight *); > +int asmc_set_backlight(struct wskbd_backlight *); > +extern int (*wskbd_get_backlight)(struct wskbd_backlight *); > +extern int (*wskbd_set_backlight)(struct wskbd_backlight *); > + > +const struct cfattach asmc_ca = { > + sizeof(struct asmc_softc), asmc_match, asmc_attach, NULL, asmc_activate > +}; > + > +struct cfdriver asmc_cd = { > + NULL, "asmc", DV_DULL > +}; > + > +const char *asmc_hids[] = { > + "APP0001", NULL > +}; > + > +static struct asmc_prod asmc_prods[] = { > + { "MacBookAir", 1, { > + "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TBXT", "TC0C", "TC0D", > + "TC0E", "TC0F", "TC0P", "TC1C", "TC1E", "TC2C", "TCFP", "TCGC", > + "TCHP", "TCMX", "TCSA", "TCXC", "TCZ3", "TCZ4", "TCZ5", "TG0E", > + "TG1E", "TG2E", "TGZ3", "TGZ4", "TGZ5", "TH0A", "TH0B", "TH0V", > + "TH0a", "TH0b", "THSP", "TM0P", "TN0D", "TPCD", "TS2P", "TTF0", > + "TV0P", "TVFP", "TW0P", "Ta0P", "Th0H", "Th0P", "Th1H", "Tm0P", > + "Tm1P", "Tp0P", "Tp1P", "TpFP", "Ts0P", "Ts0S", NULL } > + }, > + { "MacBookPro", 1, { > + "TA0P", "TA1P", "TALP", "TB0T", "TB1T", "TB2T", "TB3T", "TBXT", > + "TC0C", "TC0D", "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", > + "TC4C", "TCGC", "TCSA", "TCXC", "TG0D", "TG0F", "TG0H", "TG0P", > + "TG0T", "TG1D", "TG1F", "TG1H", "TG1d", "TH0A", "TH0B", "TH0F", > + "TH0R", "TH0V", "TH0a", "TH0b", "TH0c", "TH0x", "THSP", "TM0P", > + "TM0S", "TMCD", "TN0D", "TN0P", "TN0S", "TN1D", "TN1F", "TN1G", > + "TN1S", "TP0P", "TPCD", "TTF0", "TW0P", "Ta0P", "TaSP", "Th0H", > + "Th1H", "Th2H", "Tm0P", "Ts0P", "Ts0S", "Ts1P", "Ts1S", NULL } > + }, > + { "MacBook", 0, { > + "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", "TC0P", "TM0P", "TN0D", > + "TN0P", "TN1P", "TTF0", "TW0P", "Th0H", "Th0S", "Th1H", "ThFH", > + "Ts0P", "Ts0S", NULL } > + }, > + { "MacPro", 0, { > + "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", 0, { > + "TC0D", "TC0H", "TC0P", "TH0P", "TN0D", "TN0P", "TN1P", "TW0P", > + NULL } > + }, > + { "iMac", 0, { > + "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P", > + "TL0P", "TN0D", "TN0H", "TN0P", "TO0P", "TW0P", "Tm0P", "Tp0C", > + "Tp0P", NULL } > + }, > + { NULL, 0, { 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_fan_loc[] = { > + "left lower front", "center lower front", "right lower front", > + "left mid front", "center mid front", "right mid front", > + "left upper front", "center upper front", "right upper front", > + "left lower rear", "center lower rear", "right lower rear", > + "left mid rear", "center mid rear", "right mid rear", > + "left upper rear", "center upper rear", "right upper rear" > +}; > + > +static const char *asmc_light_desc[ASMC_MAXLIGHT] = { > + "left", "right" > +}; > + > +int > +asmc_match(struct device *parent, void *match, void *aux) > +{ > + struct acpi_attach_args *aa = aux; > + struct cfdata *cf = match; > + > + return acpi_matchhids(aa, asmc_hids, cf->cf_driver->cd_name); > +} > + > +void > +asmc_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct asmc_softc *sc = (struct asmc_softc *)self; > + struct acpi_attach_args *aaa = aux; > + struct aml_value res; > + int64_t sta; > + uint8_t buf[6]; > + int i, r; > + > + if (!hw_vendor || !hw_prod || strncmp(hw_vendor, "Apple", 5)) > + return; > + > + 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; > + > + 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", aaa->aaa_addr[0], aaa->aaa_size[0]); > + > + sc->sc_iot = aaa->aaa_bst[0]; > + if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0], 0, > + &sc->sc_ioh)) { > + printf(": can't map registers\n"); > + return; > + } > + > + rw_init(&sc->sc_lock, sc->sc_dev.dv_xname); > + > + if ((r = asmc_try(sc, ASMC_READ, "REV ", buf, 6))) { > + printf(": revision failed (0x%x)\n", r); > + bus_space_unmap(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0]); > + return; > + } > + printf(": rev %x.%x%x%x", buf[0], buf[1], buf[2], > + ntohs(*(uint16_t *)buf + 4)); > + > + if ((r = asmc_try(sc, ASMC_READ, "#KEY", buf, 4))) { > + printf(", no of keys failed (0x%x)\n", r); > + bus_space_unmap(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0]); > + return; > + } > + printf(", %u key%s\n", ntohl(*(uint32_t *)buf), > + (ntohl(*(uint32_t *)buf) == 1) ? "" : "s"); > + > + /* keyboard backlight led is optional */ > + sc->sc_backlight = buf[0] = 127, buf[1] = 0; > + if ((r = asmc_try(sc, ASMC_WRITE, "LKSB", buf, 2))) { > + if (r != ASMC_NOTFOUND) > + printf("%s: keyboard backlight failed (0x%x)\n", > + sc->sc_dev.dv_xname, r); > + } else { > + wskbd_get_backlight = asmc_get_backlight; > + wskbd_set_backlight = asmc_set_backlight; > + } > + task_set(&sc->sc_task_backlight, asmc_backlight, sc); > + > + strlcpy(sc->sc_sensor_dev.xname, sc->sc_dev.dv_xname, > + sizeof(sc->sc_sensor_dev.xname)); > + for (i = 0; i < ASMC_MAXTEMP; i++) { > + sc->sc_sensor_temp[i].flags |= SENSOR_FINVALID; > + sc->sc_sensor_temp[i].flags |= SENSOR_FUNKNOWN; > + } > + for (i = 0; i < ASMC_MAXFAN; i++) { > + sc->sc_sensor_fan[i].flags |= SENSOR_FINVALID; > + sc->sc_sensor_fan[i].flags |= SENSOR_FUNKNOWN; > + } > + for (i = 0; i < ASMC_MAXLIGHT; i++) { > + sc->sc_sensor_light[i].flags |= SENSOR_FINVALID; > + sc->sc_sensor_light[i].flags |= SENSOR_FUNKNOWN; > + } > + for (i = 0; i < ASMC_MAXMOTION; i++) { > + sc->sc_sensor_motion[i].flags |= SENSOR_FINVALID; > + sc->sc_sensor_motion[i].flags |= SENSOR_FUNKNOWN; > + } > + asmc_init(sc); > + > + if (!(sc->sc_sensor_task = sensor_task_register(sc, asmc_update, 5))) { > + printf("%s: unable to register task\n", sc->sc_dev.dv_xname); > + bus_space_unmap(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0]); > + return; > + } > + sensordev_install(&sc->sc_sensor_dev); > +} > + > +int > +asmc_detach(struct device *self, int flags) > +{ > + struct asmc_softc *sc = (struct asmc_softc *)self; > + uint8_t buf[2] = { (sc->sc_backlight = 0), 0 }; > + int i; > + > + if (sc->sc_sensor_task) { > + sensor_task_unregister(sc->sc_sensor_task); > + sc->sc_sensor_task = NULL; > + } > + sensordev_deinstall(&sc->sc_sensor_dev); > + 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]); > + > + task_del(systq, &sc->sc_task_backlight); > + asmc_try(sc, ASMC_WRITE, "LKSB", buf, 2); > + return 0; > +} > + > +int > +asmc_activate(struct device *self, int act) > +{ > + struct asmc_softc *sc = (struct asmc_softc *)self; > + > + switch (act) { > + case DVACT_WAKEUP: > + asmc_backlight(sc); > + break; > + } > + > + return 0; > +} > + > +void > +asmc_backlight(void *arg) > +{ > + struct asmc_softc *sc = arg; > + uint8_t buf[2] = { sc->sc_backlight, 0 }; > + int r; > + > + if ((r = asmc_try(sc, ASMC_WRITE, "LKSB", buf, 2))) > + printf("%s: keyboard backlight failed (0x%x)\n", > + sc->sc_dev.dv_xname, r); > +} > + > +int > +asmc_get_backlight(struct wskbd_backlight *kbl) > +{ > + struct asmc_softc *sc = asmc_cd.cd_devs[0]; > + > + KASSERT(sc != NULL); > + kbl->min = 0; > + kbl->max = 0xff; > + kbl->curval = sc->sc_backlight; > + return 0; > +} > + > +int > +asmc_set_backlight(struct wskbd_backlight *kbl) > +{ > + struct asmc_softc *sc = asmc_cd.cd_devs[0]; > + > + KASSERT(sc != NULL); > + if (kbl->curval > 0xff) > + return EINVAL; > + sc->sc_backlight = kbl->curval; > + task_add(systq, &sc->sc_task_backlight); > + 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 mask, uint8_t val) > +{ > + int i; > + > + for (i = 0; i < 500; i++) { /* wait up to 5 ms */ > + if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASMC_COMMAND) & > + mask) == val) > + return 0; > + delay(10); > + } > + return ETIMEDOUT; > +} > + > +static int > +asmc_write(struct asmc_softc *sc, uint8_t off, uint8_t val) > +{ > + if (asmc_wait(sc, ASMC_IBF, 0)) > + return 1; > + bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, val); > + if (asmc_wait(sc, ASMC_ACCEPT, ASMC_ACCEPT)) > + return 1; > + return 0; > +} > + > +static int > +asmc_read(struct asmc_softc *sc, uint8_t off, uint8_t *buf) > +{ > + if (asmc_wait(sc, ASMC_OBF, ASMC_OBF)) > + return 1; > + *buf = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off); > + return 0; > +} > + > +static int > +asmc_command(struct asmc_softc *sc, int cmd, const char *key, uint8_t *buf, > + uint8_t len) > +{ > + 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; > + } 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; > +} > + > +int > +asmc_try(struct asmc_softc *sc, int cmd, const char *key, uint8_t *buf, > + uint8_t len) > +{ > + uint8_t s; > + int i, r; > + > + rw_enter_write(&sc->sc_lock); > + for (i = 0; i < ASMC_RETRY; i++) > + if (!(r = asmc_command(sc, cmd, key, buf, len))) > + break; > + if (r && (s = asmc_status(sc))) > + r = s; > + rw_exit_write(&sc->sc_lock); > + > + return r; > +} > + > +static uint32_t > +asmc_uk(uint8_t *buf) > +{ > + /* spe78: floating point, signed, 7 bits exponent, 8 bits fraction */ > + return (((int16_t)ntohs(*(uint16_t *)buf)) >> 8) * 1000000 + 273150000; > +} > + > +static uint16_t > +asmc_rpm(uint8_t *buf) > +{ > + /* fpe2: floating point, unsigned, 14 bits exponent, 2 bits fraction */ > + return ntohs(*(uint16_t *)buf) >> 2; > +} > + > +static uint32_t > +asmc_lux(uint8_t *buf, uint8_t lightlen) > +{ > + /* newer macbooks report a 10 bit big endian value */ > + return (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)); > + */ > + ntohs(*(uint16_t *)(buf + 2)) * 1000000; > +} > + > +static int > +asmc_temp(struct asmc_softc *sc, uint8_t idx, int init) > +{ > + uint8_t buf[2]; > + uint32_t uk; > + int i, r; > + > + if ((r = asmc_try(sc, ASMC_READ, sc->sc_prod->pr_temp[idx], buf, 2))) > + return r; > + if ((uk = asmc_uk(buf)) < 253150000) /* ignore unlikely values */ > + return 0; > + sc->sc_sensor_temp[idx].value = uk; > + sc->sc_sensor_temp[idx].flags &= ~SENSOR_FUNKNOWN; > + > + if (!init) > + return 0; > + > + strlcpy(sc->sc_sensor_temp[idx].desc, sc->sc_prod->pr_temp[idx], > + sizeof(sc->sc_sensor_temp[idx].desc)); > + for (i = 0; asmc_temp_desc[i][0]; i++) > + if (!strcmp(asmc_temp_desc[i][0], sc->sc_prod->pr_temp[idx])) > + break; > + if (asmc_temp_desc[i][0]) { > + strlcat(sc->sc_sensor_temp[idx].desc, " ", > + sizeof(sc->sc_sensor_temp[idx].desc)); > + strlcat(sc->sc_sensor_temp[idx].desc, asmc_temp_desc[i][1], > + sizeof(sc->sc_sensor_temp[idx].desc)); > + } > + sc->sc_sensor_temp[idx].type = SENSOR_TEMP; > + sc->sc_sensor_temp[idx].flags &= ~SENSOR_FINVALID; > + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_temp[idx]); > + return 0; > +} > + > +static int > +asmc_fan(struct asmc_softc *sc, uint8_t idx, int init) > +{ > + char key[5]; > + uint8_t buf[17], *end; > + int r; > + > + snprintf(key, sizeof(key), "F%dAc", idx); > + if ((r = asmc_try(sc, ASMC_READ, key, buf, 2))) > + return r; > + sc->sc_sensor_fan[idx].value = asmc_rpm(buf); > + sc->sc_sensor_fan[idx].flags &= ~SENSOR_FUNKNOWN; > + > + if (!init) > + return 0; > + > + snprintf(key, sizeof(key), "F%dID", idx); > + if ((r = asmc_try(sc, ASMC_READ, key, buf, 16))) > + return r; > + buf[16] = '\0'; > + end = buf + 4 + strlen((char *)buf + 4) - 1; > + while (buf + 4 < end && *end == ' ') /* trim trailing spaces */ > + *end-- = '\0'; > + strlcpy(sc->sc_sensor_fan[idx].desc, buf + 4, > + sizeof(sc->sc_sensor_fan[idx].desc)); > + if (buf[2] < nitems(asmc_fan_loc)) { > + strlcat(sc->sc_sensor_fan[idx].desc, ", ", > + sizeof(sc->sc_sensor_fan[idx].desc)); > + strlcat(sc->sc_sensor_fan[idx].desc, asmc_fan_loc[buf[2]], > + sizeof(sc->sc_sensor_fan[idx].desc)); > + } > + sc->sc_sensor_fan[idx].type = SENSOR_FANRPM; > + sc->sc_sensor_fan[idx].flags &= ~SENSOR_FINVALID; > + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_fan[idx]); > + return 0; > +} > + > +static int > +asmc_light(struct asmc_softc *sc, uint8_t idx, int init) > +{ > + char key[5]; > + uint8_t buf[10]; > + int r; > + > + snprintf(key, sizeof(key), "ALV%d", idx); > + if (!sc->sc_lightlen) { > + if ((r = asmc_try(sc, ASMC_INFO, key, buf, 6))) > + return r; > + if ((sc->sc_lightlen = buf[0]) > 10) > + return 1; > + } > + if ((r = asmc_try(sc, ASMC_READ, key, buf, sc->sc_lightlen))) > + return r; > + if (!buf[0]) /* valid data? */ > + return 0; > + sc->sc_sensor_light[idx].value = asmc_lux(buf, sc->sc_lightlen); > + sc->sc_sensor_light[idx].flags &= ~SENSOR_FUNKNOWN; > + > + if (!init) > + return 0; > + > + strlcpy(sc->sc_sensor_light[idx].desc, asmc_light_desc[idx], > + sizeof(sc->sc_sensor_light[idx].desc)); > + sc->sc_sensor_light[idx].type = SENSOR_LUX; > + sc->sc_sensor_light[idx].flags &= ~SENSOR_FINVALID; > + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_light[idx]); > + return 0; > +} > + > +#if 0 /* todo: implement motion sensors update and initialization */ > +static int > +asmc_motion(struct asmc_softc *sc, uint8_t idx, int init) > +{ > + char key[5]; > + uint8_t buf[2]; > + int r; > + > + snprintf(key, sizeof(key), "MO_%c", 88 + idx); /* X, Y, Z */ > + if ((r = asmc_try(sc, ASMC_READ, key, buf, 2))) > + return r; > + sc->sc_sensor_motion[idx].value = 0; > + sc->sc_sensor_motion[idx].flags &= ~SENSOR_FUNKNOWN; > + > + if (!init) > + return 0; > + > + /* todo: setup and attach sensors and description */ > + strlcpy(sc->sc_sensor_motion[idx].desc, 120 + idx, /* x, y, z */ > + sizeof(sc->sc_sensor_motion[idx].desc)); > + strlcat(sc->sc_sensor_motion[idx].desc, "-axis", > + sizeof(sc->sc_sensor_motion[idx].desc)); > + sc->sc_sensor_motion[idx].type = SENSOR_ACCEL; > + sc->sc_sensor_motion[idx].flags &= ~SENSOR_FINVALID; > + sensor_attach(&sc->sc_sensor_dev, &sc->sc_sensor_motion[idx]); > + return 0; > +} > +#endif > + > +void > +asmc_init(struct asmc_softc *sc) > +{ > + uint8_t buf[2]; > + int i, r; > + > + /* number of temperature sensors depends on product */ > + for (i = 0; i < ASMC_MAXTEMP && sc->sc_prod->pr_temp[i]; i++) > + if ((r = asmc_temp(sc, i, 1)) && r != ASMC_NOTFOUND) > + printf("%s: read temp %d failed (0x%x)\n", > + sc->sc_dev.dv_xname, i, r); > + /* number of fan sensors depends on product */ > + if ((r = asmc_try(sc, ASMC_READ, "FNum", buf, 1))) > + printf("%s: read FNum failed (0x%x)\n", > + sc->sc_dev.dv_xname, r); > + else > + sc->sc_nfans = buf[0]; > + for (i = 0; i < sc->sc_nfans && i < ASMC_MAXFAN; i++) > + if ((r = asmc_fan(sc, i, 1)) && r != ASMC_NOTFOUND) > + printf("%s: read fan %d failed (0x%x)\n", > + sc->sc_dev.dv_xname, i, r); > + /* left and right light sensors are optional */ > + for (i = 0; sc->sc_prod->pr_light && i < ASMC_MAXLIGHT; i++) > + if ((r = asmc_light(sc, i, 1)) && r != ASMC_NOTFOUND) > + printf("%s: read light %d failed (0x%x)\n", > + sc->sc_dev.dv_xname, i, r); > + /* motion sensors are optional */ > + if ((r = asmc_try(sc, ASMC_READ, "MOCN", buf, 2)) && > + r != ASMC_NOTFOUND) > + printf("%s: read MOCN failed (0x%x)\n", > + sc->sc_dev.dv_xname, r); > +#if 0 /* todo: initialize sudden motion sensors and setup interrupt handling > */ > + buf[0] = 0xe0, buf[1] = 0xf8; > + if ((r = asmc_try(sc, ASMC_WRITE, "MOCN", buf, 2))) > + printf("%s write MOCN failed (0x%x)\n", > + sc->sc_dev.dv_xname, r); > + for (i = 0; i < ASMC_MAXMOTION; i++) > + if ((r = asmc_motion(sc, i, 1)) && r != ASMC_NOTFOUND) > + printf("%s: read motion %d failed (0x%x)\n", > + sc->sc_dev.dv_xname, i, r); > +#endif > +} > + > +void > +asmc_update(void *arg) > +{ > + struct asmc_softc *sc = arg; > + int i; > + > + for (i = 0; i < ASMC_MAXTEMP && sc->sc_prod->pr_temp[i]; i++) > + if (!(sc->sc_sensor_temp[i].flags & SENSOR_FINVALID)) > + asmc_temp(sc, i, 0); > + for (i = 0; i < sc->sc_nfans && i < ASMC_MAXFAN; i++) > + if (!(sc->sc_sensor_fan[i].flags & SENSOR_FINVALID)) > + asmc_fan(sc, i, 0); > + for (i = 0; i < ASMC_MAXLIGHT; i++) > + if (!(sc->sc_sensor_light[i].flags & SENSOR_FINVALID)) > + asmc_light(sc, i, 0); > +#if 0 > + for (i = 0; i < ASMC_MAXMOTION; i++) > + if (!(sc->sc_sensor_motion[i].flags & SENSOR_FINVALID)) > + asmc_motion(sc, i, 0); > +#endif > +} > 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 12 Sep 2020 07:17:31 -0000 > @@ -75,6 +75,11 @@ device acpidock > attach acpidock at acpi > file dev/acpi/acpidock.c acpidock > > +# Apple System Management Controller (SMC) > +device asmc > +attach asmc at acpi > +file dev/acpi/asmc.c asmc > + > # ASUS ACPI Hotkeys > device acpiasus > attach acpiasus at acpi > Index: sys/dev/isa/files.isa > =================================================================== > RCS file: /cvs/src/sys/dev/isa/files.isa,v > retrieving revision 1.126 > diff -u -p -u -p -r1.126 files.isa > --- sys/dev/isa/files.isa 24 Jan 2020 05:14:51 -0000 1.126 > +++ sys/dev/isa/files.isa 12 Sep 2020 07:17:31 -0000 > @@ -293,11 +293,6 @@ 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 > >
