Hi,

here comes another diff of the series for the keyboard backlight
support.

Please find below a diff which enables keyboard backlight control on
Intel Apple Laptops via asmc(4).

This diff uses introduced wskbd(4) hooks from previously sent diffs and
also introduces locking and minor refactoring around asmc_try().

Comments, tests, OKs?

Thanks,
Regards,
Joerg


Index: asmc.c
===================================================================
RCS file: /cvs/src/sys/dev/isa/asmc.c,v
retrieving revision 1.13
diff -u -p -r1.13 asmc.c
--- asmc.c      29 Oct 2015 13:29:04 -0000      1.13
+++ asmc.c      7 Dec 2015 22:50:02 -0000
@@ -23,12 +23,14 @@
 #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/isa/isavar.h>
+#include <dev/wscons/wsconsio.h>
 
 #define ASMC_BASE      0x300   /* SMC base address */
 #define ASMC_IOSIZE    32      /* I/O region size 0x300-0x31f */
@@ -66,10 +68,13 @@ struct asmc_softc {
        uint8_t                  sc_init;       /* initialization done? */
        uint8_t                  sc_nfans;      /* number of fans */
        uint8_t                  sc_lightlen;   /* light data len */
+       uint8_t                  sc_kbdled;     /* backlight led value */
 
+       struct rwlock            sc_lock;
        struct taskq            *sc_taskq;
        struct task              sc_task_init;
        struct task              sc_task_refresh;
+       struct task              sc_task_backlight;
 
        struct ksensor           sc_sensor_temp[ASMC_MAXTEMP];
        struct ksensor           sc_sensor_fan[ASMC_MAXFAN];
@@ -81,7 +86,6 @@ struct asmc_softc {
 
 uint8_t        asmc_status(struct asmc_softc *);
 int    asmc_try(struct asmc_softc *, int, const char *, uint8_t *, uint8_t);
-void   asmc_kbdled(struct asmc_softc *, uint8_t);
 
 void   asmc_init(void *);
 void   asmc_refresh(void *);
@@ -91,6 +95,13 @@ int  asmc_match(struct device *, void *, 
 void   asmc_attach(struct device *, struct device *, void *);
 int    asmc_detach(struct device *, int);
 
+/* wskbd hook functions */
+void   asmc_kbdled(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
 };
@@ -256,7 +267,7 @@ asmc_attach(struct device *parent, struc
        struct asmc_softc *sc = (struct asmc_softc *)self;
        struct isa_attach_args *ia = aux;
        uint8_t buf[6];
-       int i;
+       int i, r;
 
        if (bus_space_map(ia->ia_iot, ia->ia_iobase, ia->ia_iosize, 0,
            &sc->sc_ioh)) {
@@ -265,23 +276,34 @@ asmc_attach(struct device *parent, struc
        }
        sc->sc_iot = ia->ia_iot;
 
-       if (asmc_try(sc, ASMC_READ, "REV ", buf, 6)) {
-               printf(": revision failed (0x%x)\n", asmc_status(sc));
+       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(ia->ia_iot, ia->ia_iobase, ASMC_IOSIZE);
                return;
        }
        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));
+       if ((r = asmc_try(sc, ASMC_READ, "#KEY", buf, 4))) {
+               printf(", no of keys failed (0x%x)\n", r);
                bus_space_unmap(ia->ia_iot, ia->ia_iobase, ASMC_IOSIZE);
                return;
        }
        printf(", %u key%s\n", ntohl(*(uint32_t *)buf),
            (ntohl(*(uint32_t *)buf) == 1) ? "" : "s");
 
-       asmc_kbdled(sc, 127);
+       /* keyboard backlight led is optional */
+       sc->sc_kbdled = 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;
+       }
 
        if (!(sc->sc_taskq = taskq_create("asmc", 1, IPL_NONE, 0))) {
                printf("%s: can't create task queue\n", sc->sc_dev.dv_xname);
@@ -290,6 +312,7 @@ asmc_attach(struct device *parent, struc
        }
        task_set(&sc->sc_task_init, asmc_init, sc);
        task_set(&sc->sc_task_refresh, asmc_refresh, sc);
+       task_set(&sc->sc_task_backlight, asmc_kbdled, sc);
 
        strlcpy(sc->sc_sensor_dev.xname, sc->sc_dev.dv_xname,
            sizeof(sc->sc_sensor_dev.xname));
@@ -327,6 +350,7 @@ int
 asmc_detach(struct device *self, int flags)
 {
        struct asmc_softc *sc = (struct asmc_softc *)self;
+       uint8_t buf[2] = { (sc->sc_kbdled = 0), 0 };
        int i;
 
        if (sc->sc_sensor_task) {
@@ -343,14 +367,66 @@ asmc_detach(struct device *self, int fla
        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);
        if (sc->sc_taskq) {
                task_del(sc->sc_taskq, &sc->sc_task_refresh);
                task_del(sc->sc_taskq, &sc->sc_task_init);
                taskq_destroy(sc->sc_taskq);
        }
 
-       asmc_kbdled(sc, 0);
+       asmc_try(sc, ASMC_WRITE, "LKSB", buf, 2);
+       return 0;
+}
+
+void
+asmc_kbdled(void *arg)
+{
+       struct asmc_softc *sc = arg;
+       uint8_t buf[2] = { sc->sc_kbdled, 0 };
+       int r;
 
+       if ((r = asmc_try(sc, ASMC_WRITE, "LKSB", buf, 2)))
+#if 0 /* todo: write error, as no 0x04 wait status, but led is changed */
+               printf("%s: keyboard backlight failed (0x%x)\n",
+                   sc->sc_dev.dv_xname, r);
+#endif
+               ;
+}
+
+int
+asmc_get_backlight(struct wskbd_backlight *kbl)
+{
+       struct asmc_softc *sc = NULL;
+       int i;
+
+       for (i = 0; i < asmc_cd.cd_ndevs && !sc; i++)
+               if (asmc_cd.cd_devs[i])
+                       sc = (struct asmc_softc *)asmc_cd.cd_devs[i];
+       if (!sc)
+               return -1;
+
+       kbl->min = 0;
+       kbl->max = 0xff;
+       kbl->curval = sc->sc_kbdled;
+       return 0;
+}
+
+int
+asmc_set_backlight(struct wskbd_backlight *kbl)
+{
+       struct asmc_softc *sc = NULL;
+       int i;
+
+       for (i = 0; i < asmc_cd.cd_ndevs && !sc; i++)
+               if (asmc_cd.cd_devs[i])
+                       sc = (struct asmc_softc *)asmc_cd.cd_devs[i];
+       if (!sc)
+               return -1;
+
+       if (kbl->curval > 0xff)
+               return EINVAL;
+       sc->sc_kbdled = kbl->curval;
+       task_add(systq, &sc->sc_task_backlight);
        return 0;
 }
 
@@ -430,12 +506,20 @@ int
 asmc_try(struct asmc_softc *sc, int cmd, const char *key, uint8_t *buf,
     uint8_t len)
 {
-       int i;
+       uint8_t s;
+       int i, r;
 
+       rw_enter_write(&sc->sc_lock);
        for (i = 0; i < ASMC_RETRY; i++)
-               if (!asmc_command(sc, cmd, key, buf, len))
-                       return 0;
-       return 1;
+               if (!(r = asmc_command(sc, cmd, key, buf, len)))
+                       break;
+       if (r && (s = asmc_status(sc)))
+               r = s;
+       rw_exit_write(&sc->sc_lock);
+       if (sc->sc_sensor_task) /* give kbdled a chance to grab the lock */
+               tsleep(&sc->sc_taskq, 0, "asmc",
+                   (1 * hz + 999999) / 1000000 + 1);
+       return r;
 }
 
 static uint32_t
@@ -472,10 +556,10 @@ static int
 asmc_temp(struct asmc_softc *sc, uint8_t idx)
 {
        uint8_t buf[2];
-       int i;
+       int i, r;
 
-       if (asmc_try(sc, ASMC_READ, sc->sc_prod->pr_temp[idx], buf, 2))
-               return 1;
+       if ((r = asmc_try(sc, ASMC_READ, sc->sc_prod->pr_temp[idx], buf, 2)))
+               return r;
        sc->sc_sensor_temp[idx].value = asmc_uk(buf);
        sc->sc_sensor_temp[idx].flags &= ~SENSOR_FUNKNOWN;
 
@@ -503,10 +587,11 @@ asmc_fan(struct asmc_softc *sc, uint8_t 
 {
        char key[5];
        uint8_t buf[16], *end;
+       int r;
 
        snprintf(key, sizeof(key), "F%dAc", idx);
-       if (asmc_try(sc, ASMC_READ, key, buf, 2))
-               return 1;
+       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;
 
@@ -514,8 +599,8 @@ asmc_fan(struct asmc_softc *sc, uint8_t 
                return 0;
 
        snprintf(key, sizeof(key), "F%dID", idx);
-       if (asmc_try(sc, ASMC_READ, key, buf, 16))
-               return 1;
+       if ((r = asmc_try(sc, ASMC_READ, key, buf, 16)))
+               return r;
        end = buf + 4 + strlen((char *)buf + 4) - 1;
        while (buf + 4 < end && *end == ' ') /* trim trailing spaces */
                *end-- = '\0';
@@ -537,15 +622,16 @@ asmc_light(struct asmc_softc *sc, uint8_
 {
        char key[5];
        uint8_t buf[10];
+       int r;
 
        snprintf(key, sizeof(key), "ALV%d", idx);
        if (!sc->sc_lightlen) {
-               if (asmc_try(sc, ASMC_INFO, key, buf, 6))
-                       return 1;
+               if ((r = asmc_try(sc, ASMC_INFO, key, buf, 6)))
+                       return r;
                if ((sc->sc_lightlen = buf[0]) > 10)
                        return 1;
        }
-       if (asmc_try(sc, ASMC_READ, key, buf, sc->sc_lightlen))
+       if ((r = asmc_try(sc, ASMC_READ, key, buf, sc->sc_lightlen)))
                return 1;
        if (!buf[0]) /* valid data? */
                return 0;
@@ -568,10 +654,11 @@ asmc_motion(struct asmc_softc *sc, uint8
 {
        char key[5];
        uint8_t buf[2];
+       int r;
 
        snprintf(key, sizeof(key), "MO_%c", 88 + idx); /* X, Y, Z */
-       if (asmc_try(sc, ASMC_READ, key, buf, 2))
-               return 1;
+       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;
 
@@ -590,61 +677,46 @@ asmc_motion(struct asmc_softc *sc, uint8
 #endif
 
 void
-asmc_kbdled(struct asmc_softc *sc, uint8_t b)
-{
-       uint8_t buf[2] = { b, 0 }, s;
-
-       /* keyboard backlight led is optional */
-       if (asmc_try(sc, ASMC_WRITE, "LKSB", buf, 2)) {
-               if ((s = asmc_status(sc)) != ASMC_NOTFOUND)
-                       printf("%s: keyboard backlight failed (0x%x)\n",
-                           sc->sc_dev.dv_xname, s);
-       }
-}
-
-void
 asmc_init(void *arg)
 {
        struct asmc_softc *sc = arg;
-       uint8_t buf[2], s;
-       int i;
+       uint8_t buf[2];
+       int i, r;
 
        /* number of temperature sensors depends on product */
        for (i = 0; sc->sc_prod->pr_temp[i] && i < ASMC_MAXTEMP; i++)
-               if (asmc_temp(sc, i) && (s = asmc_status(sc)) != ASMC_NOTFOUND)
+               if ((r = asmc_temp(sc, i)) && r != ASMC_NOTFOUND)
                        printf("%s: read temp %d failed (0x%x)\n",
-                           sc->sc_dev.dv_xname, i, s);
+                           sc->sc_dev.dv_xname, i, r);
        /* number of fan sensors depends on product */
-       if (asmc_try(sc, ASMC_READ, "FNum", buf, 1))
-               printf("%s: read FNum failed (0x%x)\n", sc->sc_dev.dv_xname,
-                   asmc_status(sc));
+       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 (asmc_fan(sc, i) && (s = asmc_status(sc)) != ASMC_NOTFOUND)
+               if ((r = asmc_fan(sc, i)) && r != ASMC_NOTFOUND)
                        printf("%s: read fan %d failed (0x%x)\n",
-                           sc->sc_dev.dv_xname, i, s);
+                           sc->sc_dev.dv_xname, i, r);
        /* left and right light sensors are optional */
        for (i = 0; i < ASMC_MAXLIGHT; i++)
-               if (asmc_light(sc, i) &&
-                   (s = asmc_status(sc)) != ASMC_NOTFOUND)
+               if ((r = asmc_light(sc, i)) && r != ASMC_NOTFOUND)
                        printf("%s: read light %d failed (0x%x)\n",
-                           sc->sc_dev.dv_xname, i, s);
+                           sc->sc_dev.dv_xname, i, r);
        /* motion sensors are optional */
-       if (asmc_try(sc, ASMC_READ, "MOCN", buf, 2) &&
-           (s = asmc_status(sc)) != ASMC_NOTFOUND)
+       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, s);
+                   sc->sc_dev.dv_xname, r);
 #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("%s write MOCN failed (0x%x)\n", sc->sc_dev.dv_xname,
-                   asmc_status(sc));
+       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 (asmc_motion(sc, i) &&
-                   (s = asmc_status(sc)) != ASMC_NOTFOUND)
+               if ((r = asmc_motion(sc, i)) && r != ASMC_NOTFOUND)
                        printf("%s: read motion %d failed (0x%x)\n",
-                           sc->sc_dev.dv_xname, i, s);
+                           sc->sc_dev.dv_xname, i, r);
 #endif
        sc->sc_init = 1;
 }

Reply via email to