Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/macppc/dev make this work properly:



details:   https://anonhg.NetBSD.org/src/rev/d5caba198f01
branches:  trunk
changeset: 1009449:d5caba198f01
user:      macallan <macallan%NetBSD.org@localhost>
date:      Thu Apr 23 12:56:40 2020 +0000

description:
make this work properly:
- get rid of cargo-culted register assignments, I found the right ones by
  experiment, now both light sensors report sane values
- keyboard brightness seems to max out at 16, act like it
- do what MacOS does and fade keyboard brightness instead of just switching
- add sysctls to configure keyboard brightness and environmental light
  thresholds
- don't poll the chip more often than once a second

diffstat:

 sys/arch/macppc/dev/lmu.c |  156 ++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 137 insertions(+), 19 deletions(-)

diffs (263 lines):

diff -r 3dc30a726d6b -r d5caba198f01 sys/arch/macppc/dev/lmu.c
--- a/sys/arch/macppc/dev/lmu.c Thu Apr 23 11:41:28 2020 +0000
+++ b/sys/arch/macppc/dev/lmu.c Thu Apr 23 12:56:40 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: lmu.c,v 1.3 2020/04/23 09:47:31 macallan Exp $ */
+/* $NetBSD: lmu.c,v 1.4 2020/04/23 12:56:40 macallan Exp $ */
 
 /*-
  * Copyright (c) 2020 Michael Lorenz
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lmu.c,v 1.3 2020/04/23 09:47:31 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lmu.c,v 1.4 2020/04/23 12:56:40 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -40,11 +40,18 @@
 #include <sys/bus.h>
 #include <sys/time.h>
 #include <sys/callout.h>
+#include <sys/sysctl.h>
 
 #include <dev/i2c/i2cvar.h>
 
 #include <dev/sysmon/sysmonvar.h>
 
+#ifdef LMU_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF if (0) printf
+#endif
+
 struct lmu_softc {
        device_t        sc_dev;
        i2c_tag_t       sc_i2c;
@@ -54,7 +61,9 @@
        struct sysmon_envsys *sc_sme;
        envsys_data_t   sc_sensors[2];
        callout_t       sc_adjust;
-       int             sc_thresh, sc_hyst, sc_level;
+       int             sc_thresh, sc_hyst, sc_level, sc_target, sc_current;
+       int             sc_lux[2];
+       time_t          sc_last;
        int             sc_lid_state, sc_video_state;
 };
 
@@ -65,6 +74,8 @@
 static void    lmu_set_brightness(struct lmu_softc *, int);
 static int     lmu_get_brightness(struct lmu_softc *, int);
 static void    lmu_adjust(void *);
+static int     lmu_sysctl(SYSCTLFN_ARGS);
+static int     lmu_sysctl_thresh(SYSCTLFN_ARGS);
 
 CFATTACH_DECL_NEW(lmu, sizeof(struct lmu_softc),
     lmu_match, lmu_attach, NULL, NULL);
@@ -75,6 +86,11 @@
        { NULL,                 0 }
 };
 
+/* time between polling the light sensors */
+#define LMU_POLL       (hz * 2)
+/* time between updates to keyboard brightness */
+#define LMU_FADE       (hz / 16)
+
 static void
 lmu_lid_open(device_t dev)
 {
@@ -125,11 +141,13 @@
        struct lmu_softc *sc = device_private(self);
        struct i2c_attach_args *ia = aux;
        envsys_data_t *s;
+       const struct sysctlnode *me;
 
        sc->sc_dev = self;
        sc->sc_i2c = ia->ia_tag;
        sc->sc_addr = ia->ia_addr;
        sc->sc_node = ia->ia_cookie;
+       sc->sc_last = 0;
 
        aprint_naive("\n");
        aprint_normal(": ambient light sensor\n");
@@ -161,7 +179,7 @@
        s->state = ENVSYS_SINVALID;
        s->units = ENVSYS_LUX;
        strcpy(s->desc, "left");
-       s->private = 2;
+       s->private = 1;
        sysmon_envsys_sensor_attach(sc->sc_sme, s);
 
        sysmon_envsys_register(sc->sc_sme);
@@ -169,7 +187,30 @@
        /* TODO: make this adjustable via sysctl */
        sc->sc_thresh = 300;
        sc->sc_hyst = 30;
-       sc->sc_level = 100;
+       sc->sc_level = 16;
+       sc->sc_target = 0;
+       sc->sc_current = 0;
+
+       sysctl_createv(NULL, 0, NULL, &me,
+               CTLFLAG_READWRITE,
+               CTLTYPE_NODE, "lmu",
+               SYSCTL_DESCR("LMU driver"),
+               NULL, 0, NULL, 0,
+               CTL_HW, CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(NULL, 0, NULL, NULL,
+               CTLFLAG_READWRITE,
+               CTLTYPE_INT, "level",
+               SYSCTL_DESCR("keyboard brightness"),
+               lmu_sysctl, 0, (void *)sc, 0,
+               CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(NULL, 0, NULL, NULL,
+               CTLFLAG_READWRITE,
+               CTLTYPE_INT, "threshold",
+               SYSCTL_DESCR("environmental light threshold"),
+               lmu_sysctl_thresh, 1, (void *)sc, 0,
+               CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
 
        callout_init(&sc->sc_adjust, 0);
        callout_setfunc(&sc->sc_adjust, lmu_adjust, sc);
@@ -193,28 +234,38 @@
 static int
 lmu_get_brightness(struct lmu_softc *sc, int reg)
 {
-       int error;
-       uint16_t buf;
-       uint8_t cmd = reg;
+       int error, i;
+       uint16_t buf[2];
+       uint8_t cmd = 0;
+
+       if (reg > 1) return -1;
+       if (time_second == sc->sc_last)
+               return sc->sc_lux[reg];
 
        iic_acquire_bus(sc->sc_i2c, 0);
        error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
-               sc->sc_addr, &cmd, 1, &buf, 2, 0);
+               sc->sc_addr, &cmd, 1, buf, 4, 0);
        iic_release_bus(sc->sc_i2c, 0);
        if (error) return -1;
-       return be16toh(buf);
+       sc->sc_last = time_second;
+
+       for (i = 0; i < 2; i++)
+               sc->sc_lux[i] = be16toh(buf[i]);
+
+       DPRINTF("<%d %04x %04x>", reg, buf[0], buf[1]);
+       
+       return (sc->sc_lux[reg]);
 }
 
 static void
 lmu_set_brightness(struct lmu_softc *sc, int b)
 {
-       int bb;
        uint8_t cmd[3];
 
        cmd[0] = 1;
-       bb = b * 255;
-       cmd[1] = (bb & 0xff00) >> 8;
-       cmd[2] =  bb & 0xff;
+
+       cmd[1] = (b & 0xff);
+       cmd[2] = (b & 0xff) >> 8;
 
        iic_acquire_bus(sc->sc_i2c, 0);
        iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
@@ -226,18 +277,85 @@
 lmu_adjust(void *cookie)
 {
        struct lmu_softc *sc = cookie;
-       int left, right, b;
+       int left, right, b, offset;
 
-       left = lmu_get_brightness(sc, 2);
+       left = lmu_get_brightness(sc, 1);
        right = lmu_get_brightness(sc, 0);
        b = left > right ? left : right;
 
        if ((b > (sc->sc_thresh + sc->sc_hyst)) ||
           !(sc->sc_lid_state && sc->sc_video_state)) {
-               lmu_set_brightness(sc, 0);
+               sc->sc_target = 0;
        } else if (b < sc->sc_thresh) {
-               lmu_set_brightness(sc, sc->sc_level);
+               sc->sc_target = sc->sc_level;
        }
 
-       callout_schedule(&sc->sc_adjust, hz * 2);       
+       if (sc->sc_target == sc->sc_current) {
+               /* no update needed, check again later */
+               callout_schedule(&sc->sc_adjust, LMU_POLL);
+               return;
+       }       
+
+
+       offset = ((sc->sc_target - sc->sc_current) > 0) ? 2 : -2;
+       sc->sc_current += offset;
+       if (sc->sc_current > sc->sc_level) sc->sc_current = sc->sc_level;
+       if (sc->sc_current < 0) sc->sc_current = 0;
+
+       DPRINTF("[%d]", sc->sc_current);
+
+       lmu_set_brightness(sc, sc->sc_current);
+
+       if (sc->sc_target == sc->sc_current) {
+               /* no update needed, check again later */
+               callout_schedule(&sc->sc_adjust, LMU_POLL);
+               return;
+       }       
+
+       /* more updates upcoming */
+       callout_schedule(&sc->sc_adjust, LMU_FADE);
 }
+
+static int
+lmu_sysctl(SYSCTLFN_ARGS)
+{
+       struct sysctlnode node = *rnode;
+       struct lmu_softc *sc = node.sysctl_data;
+       int target;
+
+       target = sc->sc_level;
+       node.sysctl_data = &target;
+       if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
+               int new_reg;
+
+               new_reg = *(int *)node.sysctl_data;
+               if (new_reg != sc->sc_target) {
+                       sc->sc_level = target;
+                       sc->sc_target = target;
+                       
+               }
+               return 0;
+       }
+       return EINVAL;
+}
+
+static int
+lmu_sysctl_thresh(SYSCTLFN_ARGS)
+{
+       struct sysctlnode node = *rnode;
+       struct lmu_softc *sc = node.sysctl_data;
+       int thresh;
+
+       thresh = sc->sc_thresh;
+       node.sysctl_data = &thresh;
+       if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
+               int new_reg;
+
+               new_reg = *(int *)node.sysctl_data;
+               if (new_reg != sc->sc_thresh && new_reg > 0) {
+                       sc->sc_thresh = new_reg;
+               }
+               return 0;
+       }
+       return EINVAL;
+}



Home | Main Index | Thread Index | Old Index