This is the big change that puts all the previous work together.

When a sensor update is needed, mark its report as pending; do this in 
dependency order.  When a report fails to query/reply, mark it and its children 
as invalid.  When the BatteryPresent says there is no battery, mark its 
children as invalid too.

If BatteryPresent is on a repid that comes numerically after a child, the 
do/while loop will try again until there are no more pending reports.

If BatteryPresent is on the same repid as a child, the report->sensors list 
will have already put it in the correct order so the parent will update before 
the child.

If BatteryPresent=false invalidates children that belong to an already-pending 
report, they will not be updated, because sensor->pending will no longer be set.

--david

--- a/upd.c
+++ b/upd.c
@@ -81,6 +81,7 @@ static struct upd_usage_entry upd_usage_
 struct upd_report {
        size_t                          size;
        SLIST_HEAD(, upd_sensor)        sensors;
+       int                             pending;
 };
 
 SLIST_HEAD(upd_sensor_head, upd_sensor);
@@ -91,6 +92,7 @@ struct upd_sensor {
        struct upd_sensor_head          children;
        SLIST_ENTRY(upd_sensor)         dep_next;
        SLIST_ENTRY(upd_sensor)         rep_next;
+       int                             pending;
 };
 
 struct upd_softc {
@@ -113,7 +115,9 @@ void upd_attach_sensor_tree(struct upd_s
 int  upd_detach(struct device *, int);
 
 void upd_refresh(void *);
-void upd_update_sensors(struct upd_softc *, uint8_t *, unsigned int, int);
+void upd_request_children(struct upd_softc *, struct upd_sensor_head *, int);
+void upd_update_report_cb(void *, int, void *, int);
+void upd_update_sensor(struct upd_softc *, struct upd_sensor *, uint8_t *, 
int);
 void upd_update_sensor_value(struct upd_softc *, struct upd_sensor *,
     uint8_t *, int);
 void upd_intr(struct uhidev *, void *, uint);
@@ -285,30 +289,59 @@ upd_detach(struct device *self, int flag
 void
 upd_refresh(void *arg)
 {
-       struct upd_softc        *sc = (struct upd_softc *)arg;
+       struct upd_softc        *sc = arg;
        struct upd_report       *report;
        uint8_t                 buf[256];
-       int                     repid, actlen;
+       int                     repid, actlen, done;
 
-       for (repid = 0; repid < sc->sc_max_repid; repid++) {
-               report = &sc->sc_reports[repid];
-               if (SLIST_EMPTY(&report->sensors))
-                       continue;
+       /* request root sensors */
+       upd_request_children(sc, &sc->sc_root_sensors, 1);
 
-               memset(buf, 0x0, sizeof(buf));
-               actlen = uhidev_get_report(sc->sc_hdev.sc_parent,
-                   UHID_FEATURE_REPORT, repid, buf, report->size);
-
-               if (actlen == -1) {
-                       DPRINTF(("upd: failed to get report id=%02x\n", repid));
-                       continue;
+       /* repeat until all reports queried */
+       do {
+               done = 1;
+               for (repid = 0; repid < sc->sc_max_repid; repid++) {
+                       report = &sc->sc_reports[repid];
+                       if (!report->pending)
+                               continue;
+                       memset(buf, 0x0, sizeof(buf));
+                       actlen = uhidev_get_report(sc->sc_hdev.sc_parent,
+                           UHID_FEATURE_REPORT, repid, buf, report->size);
+                       upd_update_report_cb(sc, repid, buf, actlen);
+                       done = 0;
                }
+       } while (!done);
+}
+
+void
+upd_request_children(struct upd_softc *sc, struct upd_sensor_head *queue,
+    int valid)
+{
+       struct upd_sensor       *sensor;
+       struct upd_report       *report;
+       int                      repid;
 
-               /* Deal with buggy firmwares. */
-               if (actlen < report->size)
-                       report->size = actlen;
+       SLIST_FOREACH(sensor, queue, dep_next) {
+               repid = sensor->hitem.report_ID;
+               report = &sc->sc_reports[repid];
 
-               upd_update_sensors(sc, buf, report->size, repid);
+               if (sensor->pending)
+                       DPRINTF(("%s: %s still pending (repid=%d)\n",
+                           DEVNAME(sc), sensor->ksensor.desc, repid));
+               else if (!valid) {
+                       DPRINTF(("%s: marking %s invalid\n",
+                           DEVNAME(sc), sensor->ksensor.desc));
+                       sensor->pending = 1;
+                       upd_update_sensor(sc, sensor, NULL, -1);
+               } else if (report->pending)
+                       /* already requested */
+                       sensor->pending = 1;
+               else {
+                       DPRINTF(("%s: %s requests repid %d\n",
+                           DEVNAME(sc), sensor->ksensor.desc, repid));
+                       sensor->pending = 1;
+                       report->pending = 1;
+               }
        }
 }
 
@@ -349,34 +382,52 @@ upd_lookup_sensor(struct upd_softc *sc,
 }
 
 void
-upd_update_sensors(struct upd_softc *sc, uint8_t *buf, unsigned int len,
-    int repid)
+upd_update_report_cb(void *priv, int repid, void *data, int len)
 {
+       struct upd_softc        *sc = priv;
+       struct upd_report       *report;
        struct upd_sensor       *sensor;
-       ulong                   batpres;
-       int                     i;
 
-       sensor = upd_lookup_sensor(sc, HUP_BATTERY, HUB_BATTERY_PRESENT);
-       batpres = sensor ? sensor->ksensor.value : -1;
+       /* handle buggy firmware */
+       report = &sc->sc_reports[repid];
+       if (len > 0 && report->size != len) {
+               DPRINTF(("%s: adjusting repid %d size (%zd -> %d)\n",
+                   DEVNAME(sc), repid, report->size, len));
+               report->size = len;
+       }
 
-       for (i = 0; i < sc->sc_num_sensors; i++) {
-               sensor = &sc->sc_sensors[i];
-               if (!(sensor->hitem.report_ID == repid && sensor->attached))
-                       continue;
+       /* update all sensors in this report */
+       SLIST_FOREACH(sensor, &report->sensors, rep_next)
+               upd_update_sensor(sc, sensor, data, len);
+       report->pending = 0;
+}
 
-               /* invalidate battery dependent sensors */
-               if (HID_GET_USAGE_PAGE(sensor->hitem.usage) == HUP_BATTERY &&
-                   batpres <= 0) {
-                       /* exception to the battery sensor itself */
-                       if (HID_GET_USAGE(sensor->hitem.usage) !=
-                           HUB_BATTERY_PRESENT) {
-                               sensor->ksensor.status = SENSOR_S_UNKNOWN;
-                               sensor->ksensor.flags |= SENSOR_FINVALID;
-                               continue;
-                       }
+void
+upd_update_sensor(struct upd_softc *sc, struct upd_sensor *sensor,
+    uint8_t *buf, int len)
+{
+       int     valid;
+
+       if (sensor->pending) {
+               valid = (buf != NULL && len > 0);
+               if (valid) {
+                       upd_update_sensor_value(sc, sensor, buf, len);
+
+                       /* if battery not present, invalidate children */
+                       if (HID_GET_USAGE_PAGE(sensor->hitem.usage) ==
+                           HUP_BATTERY &&
+                           HID_GET_USAGE(sensor->hitem.usage) ==
+                           HUB_BATTERY_PRESENT &&
+                           sensor->ksensor.value == 0)
+                               valid = 0;
+               } else {
+                       sensor->ksensor.status = SENSOR_S_UNKNOWN;
+                       sensor->ksensor.flags |= SENSOR_FINVALID;
                }
 
-               upd_update_sensor_value(sc, sensor, buf, len);
+               /* refresh children */
+               upd_request_children(sc, &sensor->children, valid);
+               sensor->pending = 0;
        }
 }
 


Reply via email to