1 /* $OpenBSD: upd.c,v 1.31 2021/11/15 15:36:24 anton Exp $ */ 2 3 /* 4 * Copyright (c) 2015 David Higgs <higgsd@gmail.com> 5 * Copyright (c) 2014 Andre de Oliveira <andre@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * Driver for USB Power Devices sensors 22 * https://usb.org/sites/default/files/pdcv10.pdf 23 */ 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/kernel.h> 28 #include <sys/malloc.h> 29 #include <sys/device.h> 30 #include <sys/queue.h> 31 #include <sys/sensors.h> 32 33 #include <dev/usb/usb.h> 34 #include <dev/usb/usbdi.h> 35 #include <dev/usb/usbdevs.h> 36 #include <dev/usb/usbhid.h> 37 #include <dev/usb/uhidev.h> 38 #include <dev/usb/usbdi_util.h> 39 40 #ifdef UPD_DEBUG 41 #define DPRINTF(x) do { printf x; } while (0) 42 #else 43 #define DPRINTF(x) 44 #endif 45 46 #define DEVNAME(sc) ((sc)->sc_hdev.sc_dev.dv_xname) 47 48 struct upd_usage_entry { 49 uint8_t usage_pg; 50 uint8_t usage_id; 51 enum sensor_type senstype; 52 char *usage_name; /* sensor string */ 53 int nchildren; 54 struct upd_usage_entry *children; 55 }; 56 57 static struct upd_usage_entry upd_usage_batdep[] = { 58 { HUP_BATTERY, HUB_REL_STATEOF_CHARGE, 59 SENSOR_PERCENT, "RelativeStateOfCharge" }, 60 { HUP_BATTERY, HUB_ABS_STATEOF_CHARGE, 61 SENSOR_PERCENT, "AbsoluteStateOfCharge" }, 62 { HUP_BATTERY, HUB_REM_CAPACITY, 63 SENSOR_PERCENT, "RemainingCapacity" }, 64 { HUP_BATTERY, HUB_FULLCHARGE_CAPACITY, 65 SENSOR_PERCENT, "FullChargeCapacity" }, 66 { HUP_BATTERY, HUB_CHARGING, 67 SENSOR_INDICATOR, "Charging" }, 68 { HUP_BATTERY, HUB_DISCHARGING, 69 SENSOR_INDICATOR, "Discharging" }, 70 { HUP_BATTERY, HUB_ATRATE_TIMETOFULL, 71 SENSOR_TIMEDELTA, "AtRateTimeToFull" }, 72 { HUP_BATTERY, HUB_ATRATE_TIMETOEMPTY, 73 SENSOR_TIMEDELTA, "AtRateTimeToEmpty" }, 74 { HUP_BATTERY, HUB_RUNTIMETO_EMPTY, 75 SENSOR_TIMEDELTA, "RunTimeToEmpty" }, 76 { HUP_BATTERY, HUB_NEED_REPLACEMENT, 77 SENSOR_INDICATOR, "NeedReplacement" }, 78 }; 79 static struct upd_usage_entry upd_usage_roots[] = { 80 { HUP_BATTERY, HUB_BATTERY_PRESENT, 81 SENSOR_INDICATOR, "BatteryPresent", 82 nitems(upd_usage_batdep), upd_usage_batdep }, 83 { HUP_POWER, HUP_SHUTDOWN_IMMINENT, 84 SENSOR_INDICATOR, "ShutdownImminent" }, 85 { HUP_BATTERY, HUB_AC_PRESENT, 86 SENSOR_INDICATOR, "ACPresent" }, 87 { HUP_POWER, HUP_OVERLOAD, 88 SENSOR_INDICATOR, "Overload" }, 89 }; 90 #define UPD_MAX_SENSORS (nitems(upd_usage_batdep) + nitems(upd_usage_roots)) 91 92 SLIST_HEAD(upd_sensor_head, upd_sensor); 93 94 struct upd_report { 95 size_t size; /* Size of the report */ 96 struct upd_sensor_head sensors; /* List in dependency order */ 97 int pending; /* Waiting for an answer */ 98 }; 99 100 struct upd_sensor { 101 struct ksensor ksensor; 102 struct hid_item hitem; 103 int attached; /* Is there a matching report */ 104 struct upd_sensor_head children; /* list of children sensors */ 105 SLIST_ENTRY(upd_sensor) dep_next; /* next in the child list */ 106 SLIST_ENTRY(upd_sensor) rep_next; /* next in the report list */ 107 }; 108 109 struct upd_softc { 110 struct uhidev sc_hdev; 111 int sc_num_sensors; 112 u_int sc_max_repid; 113 char sc_buf[256]; 114 115 /* sensor framework */ 116 struct ksensordev sc_sensordev; 117 struct sensor_task *sc_sensortask; 118 struct upd_report *sc_reports; 119 struct upd_sensor *sc_sensors; 120 struct upd_sensor_head sc_root_sensors; 121 }; 122 123 int upd_match(struct device *, void *, void *); 124 void upd_attach(struct device *, struct device *, void *); 125 void upd_attach_sensor_tree(struct upd_softc *, void *, int, int, 126 struct upd_usage_entry *, struct upd_sensor_head *); 127 int upd_detach(struct device *, int); 128 129 void upd_intr(struct uhidev *, void *, uint); 130 void upd_refresh(void *); 131 void upd_request_children(struct upd_softc *, struct upd_sensor_head *); 132 void upd_update_report_cb(void *, int, void *, int); 133 134 void upd_sensor_invalidate(struct upd_softc *, struct upd_sensor *); 135 void upd_sensor_update(struct upd_softc *, struct upd_sensor *, uint8_t *, int); 136 int upd_lookup_usage_entry(void *, int, struct upd_usage_entry *, 137 struct hid_item *); 138 struct upd_sensor *upd_lookup_sensor(struct upd_softc *, int, int); 139 140 struct cfdriver upd_cd = { 141 NULL, "upd", DV_DULL 142 }; 143 144 const struct cfattach upd_ca = { 145 sizeof(struct upd_softc), upd_match, upd_attach, upd_detach 146 }; 147 148 int 149 upd_match(struct device *parent, void *match, void *aux) 150 { 151 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 152 int size; 153 void *desc; 154 struct hid_item item; 155 int ret = UMATCH_NONE; 156 int i; 157 158 if (!UHIDEV_CLAIM_MULTIPLE_REPORTID(uha)) 159 return (ret); 160 161 DPRINTF(("upd: vendor=0x%04x, product=0x%04x\n", uha->uaa->vendor, 162 uha->uaa->product)); 163 164 /* need at least one sensor from root of tree */ 165 uhidev_get_report_desc(uha->parent, &desc, &size); 166 for (i = 0; i < nitems(upd_usage_roots); i++) 167 if (upd_lookup_usage_entry(desc, size, 168 upd_usage_roots + i, &item)) { 169 ret = UMATCH_VENDOR_PRODUCT; 170 uha->claimed[item.report_ID] = 1; 171 } 172 173 return (ret); 174 } 175 176 void 177 upd_attach(struct device *parent, struct device *self, void *aux) 178 { 179 struct upd_softc *sc = (struct upd_softc *)self; 180 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 181 int size; 182 int i; 183 void *desc; 184 185 sc->sc_hdev.sc_intr = upd_intr; 186 sc->sc_hdev.sc_parent = uha->parent; 187 SLIST_INIT(&sc->sc_root_sensors); 188 189 strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), 190 sizeof(sc->sc_sensordev.xname)); 191 192 sc->sc_max_repid = uha->parent->sc_nrepid; 193 DPRINTF(("\nupd: devname=%s sc_max_repid=%d\n", 194 DEVNAME(sc), sc->sc_max_repid)); 195 196 sc->sc_reports = mallocarray(sc->sc_max_repid, 197 sizeof(struct upd_report), M_USBDEV, M_WAITOK | M_ZERO); 198 for (i = 0; i < sc->sc_max_repid; i++) 199 SLIST_INIT(&sc->sc_reports[i].sensors); 200 sc->sc_sensors = mallocarray(UPD_MAX_SENSORS, 201 sizeof(struct upd_sensor), M_USBDEV, M_WAITOK | M_ZERO); 202 for (i = 0; i < UPD_MAX_SENSORS; i++) 203 SLIST_INIT(&sc->sc_sensors[i].children); 204 205 sc->sc_num_sensors = 0; 206 uhidev_get_report_desc(uha->parent, &desc, &size); 207 upd_attach_sensor_tree(sc, desc, size, nitems(upd_usage_roots), 208 upd_usage_roots, &sc->sc_root_sensors); 209 DPRINTF(("upd: sc_num_sensors=%d\n", sc->sc_num_sensors)); 210 211 sc->sc_sensortask = sensor_task_register(sc, upd_refresh, 6); 212 if (sc->sc_sensortask == NULL) { 213 printf(", unable to register update task\n"); 214 return; 215 } 216 sensordev_install(&sc->sc_sensordev); 217 218 printf("\n"); 219 220 DPRINTF(("upd_attach: complete\n")); 221 } 222 223 void 224 upd_attach_sensor_tree(struct upd_softc *sc, void *desc, int size, 225 int nentries, struct upd_usage_entry *entries, 226 struct upd_sensor_head *queue) 227 { 228 struct hid_item item; 229 struct upd_usage_entry *entry; 230 struct upd_sensor *sensor; 231 struct upd_report *report; 232 int i; 233 234 for (i = 0; i < nentries; i++) { 235 entry = entries + i; 236 if (!upd_lookup_usage_entry(desc, size, entry, &item)) { 237 /* dependency missing, add children to parent */ 238 upd_attach_sensor_tree(sc, desc, size, 239 entry->nchildren, entry->children, queue); 240 continue; 241 } 242 243 DPRINTF(("%s: found %s on repid=%d\n", DEVNAME(sc), 244 entry->usage_name, item.report_ID)); 245 if (item.report_ID < 0 || 246 item.report_ID >= sc->sc_max_repid) 247 continue; 248 249 sensor = &sc->sc_sensors[sc->sc_num_sensors]; 250 memcpy(&sensor->hitem, &item, sizeof(struct hid_item)); 251 strlcpy(sensor->ksensor.desc, entry->usage_name, 252 sizeof(sensor->ksensor.desc)); 253 sensor->ksensor.type = entry->senstype; 254 sensor->ksensor.flags |= SENSOR_FINVALID; 255 sensor->ksensor.status = SENSOR_S_UNKNOWN; 256 sensor->ksensor.value = 0; 257 sensor_attach(&sc->sc_sensordev, &sensor->ksensor); 258 sensor->attached = 1; 259 SLIST_INSERT_HEAD(queue, sensor, dep_next); 260 sc->sc_num_sensors++; 261 262 upd_attach_sensor_tree(sc, desc, size, entry->nchildren, 263 entry->children, &sensor->children); 264 265 report = &sc->sc_reports[item.report_ID]; 266 if (SLIST_EMPTY(&report->sensors)) 267 report->size = hid_report_size(desc, 268 size, item.kind, item.report_ID); 269 SLIST_INSERT_HEAD(&report->sensors, sensor, rep_next); 270 } 271 } 272 273 int 274 upd_detach(struct device *self, int flags) 275 { 276 struct upd_softc *sc = (struct upd_softc *)self; 277 struct upd_sensor *sensor; 278 int i; 279 280 if (sc->sc_sensortask != NULL) 281 sensor_task_unregister(sc->sc_sensortask); 282 283 sensordev_deinstall(&sc->sc_sensordev); 284 285 for (i = 0; i < sc->sc_num_sensors; i++) { 286 sensor = &sc->sc_sensors[i]; 287 if (sensor->attached) 288 sensor_detach(&sc->sc_sensordev, &sensor->ksensor); 289 } 290 291 free(sc->sc_reports, M_USBDEV, sc->sc_max_repid * sizeof(struct upd_report)); 292 free(sc->sc_sensors, M_USBDEV, UPD_MAX_SENSORS * sizeof(struct upd_sensor)); 293 return (0); 294 } 295 296 void 297 upd_refresh(void *arg) 298 { 299 struct upd_softc *sc = arg; 300 int s; 301 302 /* request root sensors, do not let async handlers fire yet */ 303 s = splusb(); 304 upd_request_children(sc, &sc->sc_root_sensors); 305 splx(s); 306 } 307 308 void 309 upd_request_children(struct upd_softc *sc, struct upd_sensor_head *queue) 310 { 311 struct upd_sensor *sensor; 312 struct upd_report *report; 313 int len, repid; 314 315 SLIST_FOREACH(sensor, queue, dep_next) { 316 repid = sensor->hitem.report_ID; 317 report = &sc->sc_reports[repid]; 318 319 /* already requested */ 320 if (report->pending) 321 continue; 322 report->pending = 1; 323 324 len = uhidev_get_report_async(sc->sc_hdev.sc_parent, 325 UHID_FEATURE_REPORT, repid, sc->sc_buf, report->size, sc, 326 upd_update_report_cb); 327 328 /* request failed, force-invalidate all sensors in report */ 329 if (len < 0) { 330 upd_update_report_cb(sc, repid, NULL, -1); 331 report->pending = 0; 332 } 333 } 334 } 335 336 int 337 upd_lookup_usage_entry(void *desc, int size, struct upd_usage_entry *entry, 338 struct hid_item *item) 339 { 340 struct hid_data *hdata; 341 int ret = 0; 342 343 for (hdata = hid_start_parse(desc, size, hid_feature); 344 hid_get_item(hdata, item); ) { 345 if (item->kind == hid_feature && 346 entry->usage_pg == HID_GET_USAGE_PAGE(item->usage) && 347 entry->usage_id == HID_GET_USAGE(item->usage)) { 348 ret = 1; 349 break; 350 } 351 } 352 hid_end_parse(hdata); 353 354 return (ret); 355 } 356 357 struct upd_sensor * 358 upd_lookup_sensor(struct upd_softc *sc, int page, int usage) 359 { 360 struct upd_sensor *sensor = NULL; 361 int i; 362 363 for (i = 0; i < sc->sc_num_sensors; i++) { 364 sensor = &sc->sc_sensors[i]; 365 if (page == HID_GET_USAGE_PAGE(sensor->hitem.usage) && 366 usage == HID_GET_USAGE(sensor->hitem.usage)) 367 return (sensor); 368 } 369 return (NULL); 370 } 371 372 void 373 upd_update_report_cb(void *priv, int repid, void *data, int len) 374 { 375 struct upd_softc *sc = priv; 376 struct upd_report *report = &sc->sc_reports[repid]; 377 struct upd_sensor *sensor; 378 379 /* handle buggy firmware */ 380 if (len > 0 && report->size != len) 381 report->size = len; 382 383 if (data == NULL || len <= 0) { 384 SLIST_FOREACH(sensor, &report->sensors, rep_next) 385 upd_sensor_invalidate(sc, sensor); 386 } else { 387 SLIST_FOREACH(sensor, &report->sensors, rep_next) 388 upd_sensor_update(sc, sensor, data, len); 389 } 390 report->pending = 0; 391 } 392 393 void 394 upd_sensor_invalidate(struct upd_softc *sc, struct upd_sensor *sensor) 395 { 396 struct upd_sensor *child; 397 398 sensor->ksensor.status = SENSOR_S_UNKNOWN; 399 sensor->ksensor.flags |= SENSOR_FINVALID; 400 401 SLIST_FOREACH(child, &sensor->children, dep_next) 402 upd_sensor_invalidate(sc, child); 403 } 404 405 void 406 upd_sensor_update(struct upd_softc *sc, struct upd_sensor *sensor, 407 uint8_t *buf, int len) 408 { 409 struct upd_sensor *child; 410 int64_t hdata, adjust; 411 412 switch (HID_GET_USAGE(sensor->hitem.usage)) { 413 case HUB_REL_STATEOF_CHARGE: 414 case HUB_ABS_STATEOF_CHARGE: 415 case HUB_REM_CAPACITY: 416 case HUB_FULLCHARGE_CAPACITY: 417 adjust = 1000; /* scale adjust */ 418 break; 419 case HUB_ATRATE_TIMETOFULL: 420 case HUB_ATRATE_TIMETOEMPTY: 421 case HUB_RUNTIMETO_EMPTY: 422 /* spec says minutes, not seconds */ 423 adjust = 1000000000LL; 424 break; 425 default: 426 adjust = 1; /* no scale adjust */ 427 break; 428 } 429 430 hdata = hid_get_data(buf, len, &sensor->hitem.loc); 431 if (sensor->ksensor.type == SENSOR_INDICATOR) 432 sensor->ksensor.value = hdata ? 1 : 0; 433 else 434 sensor->ksensor.value = hdata * adjust; 435 sensor->ksensor.status = SENSOR_S_OK; 436 sensor->ksensor.flags &= ~SENSOR_FINVALID; 437 438 /* if battery not present, invalidate children */ 439 if (HID_GET_USAGE_PAGE(sensor->hitem.usage) == HUP_BATTERY && 440 HID_GET_USAGE(sensor->hitem.usage) == HUB_BATTERY_PRESENT && 441 sensor->ksensor.value == 0) { 442 SLIST_FOREACH(child, &sensor->children, dep_next) 443 upd_sensor_invalidate(sc, child); 444 return; 445 } 446 447 upd_request_children(sc, &sensor->children); 448 } 449 450 void 451 upd_intr(struct uhidev *uh, void *p, uint len) 452 { 453 /* noop */ 454 } 455