diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-05-11 08:51:32 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-05-11 08:51:32 +0000 |
commit | 1a2cb8e72fe851545fddb1c81bc7aacb7e82261a (patch) | |
tree | 346a4872327e9c69b2f73b428f29fd07019e8765 | |
parent | c8a3d9a2e391da1d5ab87227a95ed769279d9dfb (diff) |
Refresh sensor values asynchronously.
From David Higgs.
-rw-r--r-- | sys/dev/usb/upd.c | 150 |
1 files changed, 86 insertions, 64 deletions
diff --git a/sys/dev/usb/upd.c b/sys/dev/usb/upd.c index fc5e0b2cfcf..4150a4791b9 100644 --- a/sys/dev/usb/upd.c +++ b/sys/dev/usb/upd.c @@ -1,6 +1,7 @@ -/* $OpenBSD: upd.c,v 1.19 2015/04/30 10:09:31 mpi Exp $ */ +/* $OpenBSD: upd.c,v 1.20 2015/05/11 08:51:31 mpi Exp $ */ /* + * Copyright (c) 2015 David Higgs <higgsd@gmail.com> * Copyright (c) 2014 Andre de Oliveira <andre@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -78,25 +79,28 @@ static struct upd_usage_entry upd_usage_roots[] = { }; #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_softc *, void *, int, int, 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 flags) 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; + len = uhidev_get_report_async(sc->sc_hdev.sc_parent, + UHID_FEATURE_REPORT, repid, sc->sc_buf, report->size, sc, + upd_update_report_cb); - upd_update_sensors(sc, buf, report->size, repid); + /* 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, int page, int usage) } 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; - for (i = 0; i < sc->sc_num_sensors; i++) { - sensor = &sc->sc_sensors[i]; - if (!(sensor->hitem.report_ID == repid && sensor->attached)) - continue; + 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; +} - /* 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_sensor_invalidate(struct upd_softc *sc, struct upd_sensor *sensor) +{ + struct upd_sensor *child; - upd_update_sensor_value(sc, sensor, buf, len); - } + sensor->ksensor.status = SENSOR_S_UNKNOWN; + sensor->ksensor.flags |= SENSOR_FINVALID; + + 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 *sc, struct upd_sensor *sensor, 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 |