> On Apr 30, 2015, at 7:09 AM, Martin Pieuchot <m...@openbsd.org> wrote: > > On 24/04/15(Fri) 20:48, David Higgs wrote: >> This is the final patch in the series. >> >> Utilize the pending flags and report callback for their intended purpose - >> to process async behavior. >> >> Apply splusb() to ensure report callbacks can't fire before their data >> structures have been properly updated. This only needs to happen in >> upd_refresh(); all other calls to upd_request_children() are from a report >> callback. > > This is some good work. I don't think your patch #6 makes sense without > #7, so I merged them. > > I don't think you need a "pending" flags for the sensors, since what you > are querying are the reports. You basically do not want to send to > requests for the same report at once. >
I still disagree. However, the fix for this isn’t difficult and can be handled in a future diff. > I'd also take the simpler approach of not deactivating all sensors if > you fail to *submit* a transfer. When such thing happens it's either > because the device/bus is going away or because we cannot allocate > memory. > Even in these situations, invalidating all affected sensors seems an easy and consistent thing to do. > I tweaked your diff below, included some comments and your copyright. > This is untested but I hope you'll correct/improve it. > Your tweaks were good, so I tweaked it further: - When submit fails, invalidate affected sensors as described above. - When invalidating sensors, do it recursively. - When battery is not present, invalidate children but not BatteryPresent. Let me know what you think. --david --- a/upd.c +++ b/upd.c @@ -1,6 +1,7 @@ /* $OpenBSD: upd.c,v 1.19 2015/04/30 10:09:31 mpi Exp $ */ /* + * Copyright (c) 2015 David Higgs <hig...@gmail.com> * Copyright (c) 2014 Andre de Oliveira <an...@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -78,25 +79,28 @@ static struct upd_usage_entry upd_usage_ }; #define UPD_MAX_SENSORS (nitems(upd_usage_batdep) + nitems(upd_usage_roots)) +SLIST_HEAD(upd_sensor_head, upd_sensor); + struct upd_report { - size_t size; - SLIST_HEAD(, upd_sensor) sensors; + size_t size; /* Size of the report */ + struct upd_sensor_head sensors; /* List in dependency order */ + int pending; /* Waiting for an answer */ }; -SLIST_HEAD(upd_sensor_head, upd_sensor); struct upd_sensor { - struct ksensor ksensor; - struct hid_item hitem; - int attached; - struct upd_sensor_head children; - SLIST_ENTRY(upd_sensor) dep_next; - SLIST_ENTRY(upd_sensor) rep_next; + struct ksensor ksensor; + struct hid_item hitem; + int attached; /* Is there a matching report */ + struct upd_sensor_head children; /* list of children sensors */ + SLIST_ENTRY(upd_sensor) dep_next; /* next in the child list */ + SLIST_ENTRY(upd_sensor) rep_next; /* next in the report list */ }; struct upd_softc { struct uhidev sc_hdev; int sc_num_sensors; u_int sc_max_repid; + char sc_buf[256]; /* sensor framework */ struct ksensordev sc_sensordev; @@ -112,11 +116,13 @@ void upd_attach_sensor_tree(struct upd_s struct upd_usage_entry *, struct upd_sensor_head *); int upd_detach(struct device *, int); -void upd_refresh(void *); -void upd_update_sensors(struct upd_softc *, uint8_t *, unsigned int, int); -void upd_update_sensor_value(struct upd_softc *, struct upd_sensor *, - uint8_t *, int); void upd_intr(struct uhidev *, void *, uint); +void upd_refresh(void *); +void upd_request_children(struct upd_softc *, struct upd_sensor_head *); +void upd_update_report_cb(void *, int, void *, int); + +void upd_sensor_invalidate(struct upd_softc *, struct upd_sensor *); +void upd_sensor_update(struct upd_softc *, struct upd_sensor *, uint8_t *, int); int upd_lookup_usage_entry(void *, int, struct upd_usage_entry *, struct hid_item *); struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int); @@ -126,10 +132,7 @@ struct cfdriver upd_cd = { }; const struct cfattach upd_ca = { - sizeof(struct upd_softc), - upd_match, - upd_attach, - upd_detach + sizeof(struct upd_softc), upd_match, upd_attach, upd_detach }; int @@ -273,42 +276,50 @@ upd_detach(struct device *self, int flag sensor = &sc->sc_sensors[i]; if (sensor->attached) sensor_detach(&sc->sc_sensordev, &sensor->ksensor); - DPRINTF(("upd_detach: %s\n", sensor->ksensor.desc)); } free(sc->sc_reports, M_USBDEV, 0); free(sc->sc_sensors, M_USBDEV, 0); - DPRINTF(("upd_detach: complete\n")); return (0); } void upd_refresh(void *arg) { - struct upd_softc *sc = (struct upd_softc *)arg; + struct upd_softc *sc = arg; + int s; + + /* request root sensors, do not let async handlers fire yet */ + s = splusb(); + upd_request_children(sc, &sc->sc_root_sensors); + splx(s); +} + +void +upd_request_children(struct upd_softc *sc, struct upd_sensor_head *queue) +{ + struct upd_sensor *sensor; struct upd_report *report; - uint8_t buf[256]; - int repid, actlen; + int len, repid; - for (repid = 0; repid < sc->sc_max_repid; repid++) { + SLIST_FOREACH(sensor, queue, dep_next) { + repid = sensor->hitem.report_ID; report = &sc->sc_reports[repid]; - if (SLIST_EMPTY(&report->sensors)) - continue; - 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)); + /* already requested */ + if (report->pending) continue; - } + report->pending = 1; - /* Deal with buggy firmwares. */ - if (actlen < report->size) - report->size = actlen; - - upd_update_sensors(sc, buf, report->size, repid); + len = uhidev_get_report_async(sc->sc_hdev.sc_parent, + UHID_FEATURE_REPORT, repid, sc->sc_buf, report->size, sc, + upd_update_report_cb); + + /* request failed, force-invalidate all sensors in report */ + if (len < 0) { + upd_update_report_cb(sc, repid, NULL, -1); + report->pending = 0; + } } } @@ -349,42 +360,44 @@ 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 = &sc->sc_reports[repid]; 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 */ + if (len > 0 && report->size != len) + report->size = len; + + if (data == NULL || len <= 0) { + SLIST_FOREACH(sensor, &report->sensors, rep_next) + upd_sensor_invalidate(sc, sensor); + } else { + SLIST_FOREACH(sensor, &report->sensors, rep_next) + upd_sensor_update(sc, sensor, data, len); + } + report->pending = 0; +} - for (i = 0; i < sc->sc_num_sensors; i++) { - sensor = &sc->sc_sensors[i]; - if (!(sensor->hitem.report_ID == repid && sensor->attached)) - continue; +void +upd_sensor_invalidate(struct upd_softc *sc, struct upd_sensor *sensor) +{ + struct upd_sensor *child; - /* 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; - } - } + sensor->ksensor.status = SENSOR_S_UNKNOWN; + sensor->ksensor.flags |= SENSOR_FINVALID; - upd_update_sensor_value(sc, sensor, buf, len); - } + SLIST_FOREACH(child, &sensor->children, dep_next) + upd_sensor_invalidate(sc, child); } void -upd_update_sensor_value(struct upd_softc *sc, struct upd_sensor *sensor, +upd_sensor_update(struct upd_softc *sc, struct upd_sensor *sensor, uint8_t *buf, int len) { - int64_t hdata, adjust; + struct upd_sensor *child; + int64_t hdata, adjust; switch (HID_GET_USAGE(sensor->hitem.usage)) { case HUB_REL_STATEOF_CHARGE: @@ -402,8 +415,17 @@ upd_update_sensor_value(struct upd_softc sensor->ksensor.value = hdata * adjust; sensor->ksensor.status = SENSOR_S_OK; sensor->ksensor.flags &= ~SENSOR_FINVALID; - DPRINTF(("%s: %s hidget data: %lld\n", DEVNAME(sc), - sensor->ksensor.desc, hdata)); + + /* 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) { + SLIST_FOREACH(child, &sensor->children, dep_next) + upd_sensor_invalidate(sc, child); + return; + } + + upd_request_children(sc, &sensor->children); } void