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