1*8e650cf5Slandry /* $OpenBSD: upd.c,v 1.33 2024/12/01 09:05:05 landry Exp $ */ 259b9e08dSandre 359b9e08dSandre /* 4a2254ca0Smpi * Copyright (c) 2015 David Higgs <higgsd@gmail.com> 559b9e08dSandre * Copyright (c) 2014 Andre de Oliveira <andre@openbsd.org> 659b9e08dSandre * 759b9e08dSandre * Permission to use, copy, modify, and distribute this software for any 859b9e08dSandre * purpose with or without fee is hereby granted, provided that the above 959b9e08dSandre * copyright notice and this permission notice appear in all copies. 1059b9e08dSandre * 1159b9e08dSandre * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES 1259b9e08dSandre * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1359b9e08dSandre * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1459b9e08dSandre * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1559b9e08dSandre * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1659b9e08dSandre * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1759b9e08dSandre * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1859b9e08dSandre */ 1959b9e08dSandre 20a007768dSsthen /* 21a007768dSsthen * Driver for USB Power Devices sensors 22a007768dSsthen * https://usb.org/sites/default/files/pdcv10.pdf 23a007768dSsthen */ 2459b9e08dSandre 2559b9e08dSandre #include <sys/param.h> 2659b9e08dSandre #include <sys/systm.h> 2759b9e08dSandre #include <sys/malloc.h> 2859b9e08dSandre #include <sys/device.h> 293d645ebbSmpi #include <sys/queue.h> 3059b9e08dSandre #include <sys/sensors.h> 3159b9e08dSandre 3259b9e08dSandre #include <dev/usb/usb.h> 3359b9e08dSandre #include <dev/usb/usbdi.h> 3459b9e08dSandre #include <dev/usb/usbhid.h> 3559b9e08dSandre #include <dev/usb/uhidev.h> 3659b9e08dSandre 3759b9e08dSandre #ifdef UPD_DEBUG 3859b9e08dSandre #define DPRINTF(x) do { printf x; } while (0) 3959b9e08dSandre #else 4059b9e08dSandre #define DPRINTF(x) 4159b9e08dSandre #endif 4259b9e08dSandre 436acf6676Smpi #define DEVNAME(sc) ((sc)->sc_hdev.sc_dev.dv_xname) 446acf6676Smpi 4559b9e08dSandre struct upd_usage_entry { 4659b9e08dSandre uint8_t usage_pg; 4759b9e08dSandre uint8_t usage_id; 4859b9e08dSandre enum sensor_type senstype; 4959b9e08dSandre char *usage_name; /* sensor string */ 503d645ebbSmpi int nchildren; 513d645ebbSmpi struct upd_usage_entry *children; 5259b9e08dSandre }; 5359b9e08dSandre 543d645ebbSmpi static struct upd_usage_entry upd_usage_batdep[] = { 550415792bSandre { HUP_BATTERY, HUB_REL_STATEOF_CHARGE, 5659b9e08dSandre SENSOR_PERCENT, "RelativeStateOfCharge" }, 570415792bSandre { HUP_BATTERY, HUB_ABS_STATEOF_CHARGE, 5859b9e08dSandre SENSOR_PERCENT, "AbsoluteStateOfCharge" }, 590415792bSandre { HUP_BATTERY, HUB_REM_CAPACITY, 6059b9e08dSandre SENSOR_PERCENT, "RemainingCapacity" }, 610415792bSandre { HUP_BATTERY, HUB_FULLCHARGE_CAPACITY, 6259b9e08dSandre SENSOR_PERCENT, "FullChargeCapacity" }, 63*8e650cf5Slandry { HUP_POWER, HUP_PERCENT_LOAD, 64*8e650cf5Slandry SENSOR_PERCENT, "PercentLoad" }, 650415792bSandre { HUP_BATTERY, HUB_CHARGING, 6659b9e08dSandre SENSOR_INDICATOR, "Charging" }, 670415792bSandre { HUP_BATTERY, HUB_DISCHARGING, 6859b9e08dSandre SENSOR_INDICATOR, "Discharging" }, 690415792bSandre { HUP_BATTERY, HUB_ATRATE_TIMETOFULL, 70d55e24b2Smpi SENSOR_TIMEDELTA, "AtRateTimeToFull" }, 71d55e24b2Smpi { HUP_BATTERY, HUB_ATRATE_TIMETOEMPTY, 72d55e24b2Smpi SENSOR_TIMEDELTA, "AtRateTimeToEmpty" }, 73d55e24b2Smpi { HUP_BATTERY, HUB_RUNTIMETO_EMPTY, 74d55e24b2Smpi SENSOR_TIMEDELTA, "RunTimeToEmpty" }, 75d55e24b2Smpi { HUP_BATTERY, HUB_NEED_REPLACEMENT, 76d55e24b2Smpi SENSOR_INDICATOR, "NeedReplacement" }, 7759b9e08dSandre }; 783d645ebbSmpi static struct upd_usage_entry upd_usage_roots[] = { 793d645ebbSmpi { HUP_BATTERY, HUB_BATTERY_PRESENT, 803d645ebbSmpi SENSOR_INDICATOR, "BatteryPresent", 813d645ebbSmpi nitems(upd_usage_batdep), upd_usage_batdep }, 823d645ebbSmpi { HUP_POWER, HUP_SHUTDOWN_IMMINENT, 833d645ebbSmpi SENSOR_INDICATOR, "ShutdownImminent" }, 843d645ebbSmpi { HUP_BATTERY, HUB_AC_PRESENT, 85d55e24b2Smpi SENSOR_INDICATOR, "ACPresent" }, 86d55e24b2Smpi { HUP_POWER, HUP_OVERLOAD, 87d55e24b2Smpi SENSOR_INDICATOR, "Overload" }, 883d645ebbSmpi }; 893d645ebbSmpi #define UPD_MAX_SENSORS (nitems(upd_usage_batdep) + nitems(upd_usage_roots)) 9059b9e08dSandre 91a2254ca0Smpi SLIST_HEAD(upd_sensor_head, upd_sensor); 92a2254ca0Smpi 930415792bSandre struct upd_report { 94a2254ca0Smpi size_t size; /* Size of the report */ 95a2254ca0Smpi struct upd_sensor_head sensors; /* List in dependency order */ 96a2254ca0Smpi int pending; /* Waiting for an answer */ 970415792bSandre }; 980415792bSandre 9959b9e08dSandre struct upd_sensor { 1000415792bSandre struct ksensor ksensor; 1010415792bSandre struct hid_item hitem; 102a2254ca0Smpi int attached; /* Is there a matching report */ 103a2254ca0Smpi struct upd_sensor_head children; /* list of children sensors */ 104a2254ca0Smpi SLIST_ENTRY(upd_sensor) dep_next; /* next in the child list */ 105a2254ca0Smpi SLIST_ENTRY(upd_sensor) rep_next; /* next in the report list */ 10659b9e08dSandre }; 10759b9e08dSandre 10859b9e08dSandre struct upd_softc { 10959b9e08dSandre struct uhidev sc_hdev; 11059b9e08dSandre int sc_num_sensors; 1110415792bSandre u_int sc_max_repid; 112a2254ca0Smpi char sc_buf[256]; 11359b9e08dSandre 11459b9e08dSandre /* sensor framework */ 11559b9e08dSandre struct ksensordev sc_sensordev; 11659b9e08dSandre struct sensor_task *sc_sensortask; 1170415792bSandre struct upd_report *sc_reports; 1180415792bSandre struct upd_sensor *sc_sensors; 1193d645ebbSmpi struct upd_sensor_head sc_root_sensors; 12059b9e08dSandre }; 12159b9e08dSandre 12259b9e08dSandre int upd_match(struct device *, void *, void *); 12359b9e08dSandre void upd_attach(struct device *, struct device *, void *); 1243d645ebbSmpi void upd_attach_sensor_tree(struct upd_softc *, void *, int, int, 1253d645ebbSmpi struct upd_usage_entry *, struct upd_sensor_head *); 12659b9e08dSandre int upd_detach(struct device *, int); 12759b9e08dSandre 12859b9e08dSandre void upd_intr(struct uhidev *, void *, uint); 129a2254ca0Smpi void upd_refresh(void *); 130a2254ca0Smpi void upd_request_children(struct upd_softc *, struct upd_sensor_head *); 131a2254ca0Smpi void upd_update_report_cb(void *, int, void *, int); 132a2254ca0Smpi 133a2254ca0Smpi void upd_sensor_invalidate(struct upd_softc *, struct upd_sensor *); 134a2254ca0Smpi void upd_sensor_update(struct upd_softc *, struct upd_sensor *, uint8_t *, int); 135dd459b5aSmpi int upd_lookup_usage_entry(void *, int, struct upd_usage_entry *, 136dd459b5aSmpi struct hid_item *); 1370415792bSandre struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int); 13859b9e08dSandre 13959b9e08dSandre struct cfdriver upd_cd = { 14059b9e08dSandre NULL, "upd", DV_DULL 14159b9e08dSandre }; 14259b9e08dSandre 14359b9e08dSandre const struct cfattach upd_ca = { 144a2254ca0Smpi sizeof(struct upd_softc), upd_match, upd_attach, upd_detach 14559b9e08dSandre }; 14659b9e08dSandre 14759b9e08dSandre int 14859b9e08dSandre upd_match(struct device *parent, void *match, void *aux) 14959b9e08dSandre { 15059b9e08dSandre struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 1510415792bSandre int size; 1520415792bSandre void *desc; 1530415792bSandre struct hid_item item; 1540415792bSandre int ret = UMATCH_NONE; 155dd459b5aSmpi int i; 15659b9e08dSandre 157faac88c0Santon if (!UHIDEV_CLAIM_MULTIPLE_REPORTID(uha)) 1580415792bSandre return (ret); 15959b9e08dSandre 1600415792bSandre DPRINTF(("upd: vendor=0x%04x, product=0x%04x\n", uha->uaa->vendor, 16159b9e08dSandre uha->uaa->product)); 16259b9e08dSandre 1633d645ebbSmpi /* need at least one sensor from root of tree */ 1640415792bSandre uhidev_get_report_desc(uha->parent, &desc, &size); 1653d645ebbSmpi for (i = 0; i < nitems(upd_usage_roots); i++) 166dd459b5aSmpi if (upd_lookup_usage_entry(desc, size, 1673d645ebbSmpi upd_usage_roots + i, &item)) { 1680415792bSandre ret = UMATCH_VENDOR_PRODUCT; 169fac838e3Sabieber uha->claimed[item.report_ID] = 1; 1700415792bSandre } 1710415792bSandre 1720415792bSandre return (ret); 17359b9e08dSandre } 17459b9e08dSandre 17559b9e08dSandre void 17659b9e08dSandre upd_attach(struct device *parent, struct device *self, void *aux) 17759b9e08dSandre { 17859b9e08dSandre struct upd_softc *sc = (struct upd_softc *)self; 17959b9e08dSandre struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 18059b9e08dSandre int size; 181dd459b5aSmpi int i; 18259b9e08dSandre void *desc; 18359b9e08dSandre 18459b9e08dSandre sc->sc_hdev.sc_intr = upd_intr; 18559b9e08dSandre sc->sc_hdev.sc_parent = uha->parent; 1863d645ebbSmpi SLIST_INIT(&sc->sc_root_sensors); 18759b9e08dSandre 1886acf6676Smpi strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), 18959b9e08dSandre sizeof(sc->sc_sensordev.xname)); 19059b9e08dSandre 1910415792bSandre sc->sc_max_repid = uha->parent->sc_nrepid; 1920415792bSandre DPRINTF(("\nupd: devname=%s sc_max_repid=%d\n", 1936acf6676Smpi DEVNAME(sc), sc->sc_max_repid)); 19459b9e08dSandre 195b7958b67Sderaadt sc->sc_reports = mallocarray(sc->sc_max_repid, 196b7958b67Sderaadt sizeof(struct upd_report), M_USBDEV, M_WAITOK | M_ZERO); 197c7bdea97Smpi for (i = 0; i < sc->sc_max_repid; i++) 198c7bdea97Smpi SLIST_INIT(&sc->sc_reports[i].sensors); 1993d645ebbSmpi sc->sc_sensors = mallocarray(UPD_MAX_SENSORS, 200b7958b67Sderaadt sizeof(struct upd_sensor), M_USBDEV, M_WAITOK | M_ZERO); 2013d645ebbSmpi for (i = 0; i < UPD_MAX_SENSORS; i++) 2023d645ebbSmpi SLIST_INIT(&sc->sc_sensors[i].children); 203dd459b5aSmpi 2043d645ebbSmpi sc->sc_num_sensors = 0; 20559b9e08dSandre uhidev_get_report_desc(uha->parent, &desc, &size); 2063d645ebbSmpi upd_attach_sensor_tree(sc, desc, size, nitems(upd_usage_roots), 2073d645ebbSmpi upd_usage_roots, &sc->sc_root_sensors); 2083d645ebbSmpi DPRINTF(("upd: sc_num_sensors=%d\n", sc->sc_num_sensors)); 2093d645ebbSmpi 2103d645ebbSmpi sc->sc_sensortask = sensor_task_register(sc, upd_refresh, 6); 2113d645ebbSmpi if (sc->sc_sensortask == NULL) { 2123d645ebbSmpi printf(", unable to register update task\n"); 2133d645ebbSmpi return; 2143d645ebbSmpi } 2153d645ebbSmpi sensordev_install(&sc->sc_sensordev); 2163d645ebbSmpi 2173d645ebbSmpi printf("\n"); 2183d645ebbSmpi 2193d645ebbSmpi DPRINTF(("upd_attach: complete\n")); 2203d645ebbSmpi } 2213d645ebbSmpi 2223d645ebbSmpi void 2233d645ebbSmpi upd_attach_sensor_tree(struct upd_softc *sc, void *desc, int size, 2243d645ebbSmpi int nentries, struct upd_usage_entry *entries, 2253d645ebbSmpi struct upd_sensor_head *queue) 2263d645ebbSmpi { 2273d645ebbSmpi struct hid_item item; 2283d645ebbSmpi struct upd_usage_entry *entry; 2293d645ebbSmpi struct upd_sensor *sensor; 230c7bdea97Smpi struct upd_report *report; 2313d645ebbSmpi int i; 2323d645ebbSmpi 2333d645ebbSmpi for (i = 0; i < nentries; i++) { 2343d645ebbSmpi entry = entries + i; 235d1175cffSmpi if (!upd_lookup_usage_entry(desc, size, entry, &item)) { 236d1175cffSmpi /* dependency missing, add children to parent */ 237d1175cffSmpi upd_attach_sensor_tree(sc, desc, size, 238d1175cffSmpi entry->nchildren, entry->children, queue); 239dd459b5aSmpi continue; 240d1175cffSmpi } 241dd459b5aSmpi 242dd459b5aSmpi DPRINTF(("%s: found %s on repid=%d\n", DEVNAME(sc), 243dd459b5aSmpi entry->usage_name, item.report_ID)); 244dd459b5aSmpi if (item.report_ID < 0 || 2455526e273Smpi item.report_ID >= sc->sc_max_repid) 2460415792bSandre continue; 24759b9e08dSandre 2480415792bSandre sensor = &sc->sc_sensors[sc->sc_num_sensors]; 2490415792bSandre memcpy(&sensor->hitem, &item, sizeof(struct hid_item)); 2500415792bSandre strlcpy(sensor->ksensor.desc, entry->usage_name, 2510415792bSandre sizeof(sensor->ksensor.desc)); 2520415792bSandre sensor->ksensor.type = entry->senstype; 2530415792bSandre sensor->ksensor.flags |= SENSOR_FINVALID; 2540415792bSandre sensor->ksensor.status = SENSOR_S_UNKNOWN; 2550415792bSandre sensor->ksensor.value = 0; 2560415792bSandre sensor_attach(&sc->sc_sensordev, &sensor->ksensor); 2570415792bSandre sensor->attached = 1; 2583d645ebbSmpi SLIST_INSERT_HEAD(queue, sensor, dep_next); 2590415792bSandre sc->sc_num_sensors++; 2600415792bSandre 2613d645ebbSmpi upd_attach_sensor_tree(sc, desc, size, entry->nchildren, 2623d645ebbSmpi entry->children, &sensor->children); 2633d645ebbSmpi 264c7bdea97Smpi report = &sc->sc_reports[item.report_ID]; 265c7bdea97Smpi if (SLIST_EMPTY(&report->sensors)) 266c7bdea97Smpi report->size = hid_report_size(desc, 2670415792bSandre size, item.kind, item.report_ID); 268c7bdea97Smpi SLIST_INSERT_HEAD(&report->sensors, sensor, rep_next); 2690415792bSandre } 27059b9e08dSandre } 27159b9e08dSandre 27259b9e08dSandre int 27359b9e08dSandre upd_detach(struct device *self, int flags) 27459b9e08dSandre { 27559b9e08dSandre struct upd_softc *sc = (struct upd_softc *)self; 27659b9e08dSandre struct upd_sensor *sensor; 27759b9e08dSandre int i; 27859b9e08dSandre 279f0f44f97Smpi if (sc->sc_sensortask != NULL) 28059b9e08dSandre sensor_task_unregister(sc->sc_sensortask); 28159b9e08dSandre 28259b9e08dSandre sensordev_deinstall(&sc->sc_sensordev); 28359b9e08dSandre 2840415792bSandre for (i = 0; i < sc->sc_num_sensors; i++) { 28559b9e08dSandre sensor = &sc->sc_sensors[i]; 2860415792bSandre if (sensor->attached) 2870415792bSandre sensor_detach(&sc->sc_sensordev, &sensor->ksensor); 28859b9e08dSandre } 28959b9e08dSandre 290234dfda1Sderaadt free(sc->sc_reports, M_USBDEV, sc->sc_max_repid * sizeof(struct upd_report)); 291234dfda1Sderaadt free(sc->sc_sensors, M_USBDEV, UPD_MAX_SENSORS * sizeof(struct upd_sensor)); 29259b9e08dSandre return (0); 29359b9e08dSandre } 29459b9e08dSandre 29559b9e08dSandre void 29659b9e08dSandre upd_refresh(void *arg) 29759b9e08dSandre { 298a2254ca0Smpi struct upd_softc *sc = arg; 299a2254ca0Smpi int s; 30059b9e08dSandre 301a2254ca0Smpi /* request root sensors, do not let async handlers fire yet */ 302a2254ca0Smpi s = splusb(); 303a2254ca0Smpi upd_request_children(sc, &sc->sc_root_sensors); 304a2254ca0Smpi splx(s); 3056ffdf332Sandre } 3066ffdf332Sandre 307a2254ca0Smpi void 308a2254ca0Smpi upd_request_children(struct upd_softc *sc, struct upd_sensor_head *queue) 309a2254ca0Smpi { 310a2254ca0Smpi struct upd_sensor *sensor; 311a2254ca0Smpi struct upd_report *report; 312a2254ca0Smpi int len, repid; 3132b2858ecSmpi 314a2254ca0Smpi SLIST_FOREACH(sensor, queue, dep_next) { 315a2254ca0Smpi repid = sensor->hitem.report_ID; 316a2254ca0Smpi report = &sc->sc_reports[repid]; 317a2254ca0Smpi 318a2254ca0Smpi /* already requested */ 319a2254ca0Smpi if (report->pending) 320a2254ca0Smpi continue; 321a2254ca0Smpi report->pending = 1; 322a2254ca0Smpi 323a2254ca0Smpi len = uhidev_get_report_async(sc->sc_hdev.sc_parent, 324a2254ca0Smpi UHID_FEATURE_REPORT, repid, sc->sc_buf, report->size, sc, 325a2254ca0Smpi upd_update_report_cb); 326a2254ca0Smpi 327a2254ca0Smpi /* request failed, force-invalidate all sensors in report */ 328a2254ca0Smpi if (len < 0) { 329a2254ca0Smpi upd_update_report_cb(sc, repid, NULL, -1); 330a2254ca0Smpi report->pending = 0; 331a2254ca0Smpi } 33259b9e08dSandre } 33359b9e08dSandre } 33459b9e08dSandre 335dd459b5aSmpi int 336dd459b5aSmpi upd_lookup_usage_entry(void *desc, int size, struct upd_usage_entry *entry, 337dd459b5aSmpi struct hid_item *item) 33859b9e08dSandre { 339dd459b5aSmpi struct hid_data *hdata; 340dd459b5aSmpi int ret = 0; 3410415792bSandre 342dd459b5aSmpi for (hdata = hid_start_parse(desc, size, hid_feature); 343dd459b5aSmpi hid_get_item(hdata, item); ) { 344dd459b5aSmpi if (item->kind == hid_feature && 345dd459b5aSmpi entry->usage_pg == HID_GET_USAGE_PAGE(item->usage) && 346dd459b5aSmpi entry->usage_id == HID_GET_USAGE(item->usage)) { 347dd459b5aSmpi ret = 1; 348dd459b5aSmpi break; 3490415792bSandre } 350dd459b5aSmpi } 351dd459b5aSmpi hid_end_parse(hdata); 352dd459b5aSmpi 353dd459b5aSmpi return (ret); 3540415792bSandre } 3550415792bSandre 3560415792bSandre struct upd_sensor * 3570415792bSandre upd_lookup_sensor(struct upd_softc *sc, int page, int usage) 3580415792bSandre { 35959b9e08dSandre struct upd_sensor *sensor = NULL; 36059b9e08dSandre int i; 36159b9e08dSandre 3620415792bSandre for (i = 0; i < sc->sc_num_sensors; i++) { 36359b9e08dSandre sensor = &sc->sc_sensors[i]; 3640415792bSandre if (page == HID_GET_USAGE_PAGE(sensor->hitem.usage) && 3650415792bSandre usage == HID_GET_USAGE(sensor->hitem.usage)) 3660415792bSandre return (sensor); 3670415792bSandre } 3680415792bSandre return (NULL); 3690415792bSandre } 3700415792bSandre 3710415792bSandre void 372a2254ca0Smpi upd_update_report_cb(void *priv, int repid, void *data, int len) 3730415792bSandre { 374a2254ca0Smpi struct upd_softc *sc = priv; 375a2254ca0Smpi struct upd_report *report = &sc->sc_reports[repid]; 3760415792bSandre struct upd_sensor *sensor; 3770415792bSandre 378a2254ca0Smpi /* handle buggy firmware */ 379a2254ca0Smpi if (len > 0 && report->size != len) 380a2254ca0Smpi report->size = len; 3810415792bSandre 382a2254ca0Smpi if (data == NULL || len <= 0) { 383a2254ca0Smpi SLIST_FOREACH(sensor, &report->sensors, rep_next) 384a2254ca0Smpi upd_sensor_invalidate(sc, sensor); 385a2254ca0Smpi } else { 386a2254ca0Smpi SLIST_FOREACH(sensor, &report->sensors, rep_next) 387a2254ca0Smpi upd_sensor_update(sc, sensor, data, len); 38859b9e08dSandre } 389a2254ca0Smpi report->pending = 0; 390136270beSmpi } 391136270beSmpi 392136270beSmpi void 393a2254ca0Smpi upd_sensor_invalidate(struct upd_softc *sc, struct upd_sensor *sensor) 394a2254ca0Smpi { 395a2254ca0Smpi struct upd_sensor *child; 396a2254ca0Smpi 397a2254ca0Smpi sensor->ksensor.status = SENSOR_S_UNKNOWN; 398a2254ca0Smpi sensor->ksensor.flags |= SENSOR_FINVALID; 399a2254ca0Smpi 400a2254ca0Smpi SLIST_FOREACH(child, &sensor->children, dep_next) 401a2254ca0Smpi upd_sensor_invalidate(sc, child); 402a2254ca0Smpi } 403a2254ca0Smpi 404a2254ca0Smpi void 405a2254ca0Smpi upd_sensor_update(struct upd_softc *sc, struct upd_sensor *sensor, 406136270beSmpi uint8_t *buf, int len) 407136270beSmpi { 408a2254ca0Smpi struct upd_sensor *child; 409136270beSmpi int64_t hdata, adjust; 410136270beSmpi 4110415792bSandre switch (HID_GET_USAGE(sensor->hitem.usage)) { 4120415792bSandre case HUB_REL_STATEOF_CHARGE: 4130415792bSandre case HUB_ABS_STATEOF_CHARGE: 4140415792bSandre case HUB_REM_CAPACITY: 4150415792bSandre case HUB_FULLCHARGE_CAPACITY: 416*8e650cf5Slandry case HUP_PERCENT_LOAD: 4170415792bSandre adjust = 1000; /* scale adjust */ 4180415792bSandre break; 419d55e24b2Smpi case HUB_ATRATE_TIMETOFULL: 420d55e24b2Smpi case HUB_ATRATE_TIMETOEMPTY: 421d55e24b2Smpi case HUB_RUNTIMETO_EMPTY: 422d55e24b2Smpi /* spec says minutes, not seconds */ 423d55e24b2Smpi adjust = 1000000000LL; 424d55e24b2Smpi break; 4250415792bSandre default: 4260415792bSandre adjust = 1; /* no scale adjust */ 4270415792bSandre break; 4280415792bSandre } 4290415792bSandre 430e6a02383Smpi hdata = hid_get_data(buf, len, &sensor->hitem.loc); 431b0a4640cSmpi if (sensor->ksensor.type == SENSOR_INDICATOR) 432b0a4640cSmpi sensor->ksensor.value = hdata ? 1 : 0; 433b0a4640cSmpi else 4340415792bSandre sensor->ksensor.value = hdata * adjust; 4350415792bSandre sensor->ksensor.status = SENSOR_S_OK; 4360415792bSandre sensor->ksensor.flags &= ~SENSOR_FINVALID; 437a2254ca0Smpi 438a2254ca0Smpi /* if battery not present, invalidate children */ 439a2254ca0Smpi if (HID_GET_USAGE_PAGE(sensor->hitem.usage) == HUP_BATTERY && 440a2254ca0Smpi HID_GET_USAGE(sensor->hitem.usage) == HUB_BATTERY_PRESENT && 441a2254ca0Smpi sensor->ksensor.value == 0) { 442a2254ca0Smpi SLIST_FOREACH(child, &sensor->children, dep_next) 443a2254ca0Smpi upd_sensor_invalidate(sc, child); 444a2254ca0Smpi return; 445a2254ca0Smpi } 446a2254ca0Smpi 447a2254ca0Smpi upd_request_children(sc, &sensor->children); 4480415792bSandre } 4490415792bSandre 45059b9e08dSandre void 45159b9e08dSandre upd_intr(struct uhidev *uh, void *p, uint len) 45259b9e08dSandre { 45359b9e08dSandre /* noop */ 45459b9e08dSandre } 455