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