xref: /openbsd/sys/dev/usb/upd.c (revision d89ec533)
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