> 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
> 
> 

Reply via email to