Line data Source code
1 : /* $OpenBSD: upd.c,v 1.26 2017/04/08 02:57:25 deraadt 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 0 : upd_match(struct device *parent, void *match, void *aux)
147 : {
148 0 : struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
149 0 : int size;
150 0 : void *desc;
151 0 : struct hid_item item;
152 : int ret = UMATCH_NONE;
153 : int i;
154 :
155 0 : if (uha->reportid != UHIDEV_CLAIM_ALLREPORTID)
156 0 : 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 0 : uhidev_get_report_desc(uha->parent, &desc, &size);
163 0 : for (i = 0; i < nitems(upd_usage_roots); i++)
164 0 : if (upd_lookup_usage_entry(desc, size,
165 0 : upd_usage_roots + i, &item)) {
166 : ret = UMATCH_VENDOR_PRODUCT;
167 0 : break;
168 : }
169 :
170 0 : return (ret);
171 0 : }
172 :
173 : void
174 0 : upd_attach(struct device *parent, struct device *self, void *aux)
175 : {
176 0 : struct upd_softc *sc = (struct upd_softc *)self;
177 0 : struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
178 0 : int size;
179 : int i;
180 0 : void *desc;
181 :
182 0 : sc->sc_hdev.sc_intr = upd_intr;
183 0 : sc->sc_hdev.sc_parent = uha->parent;
184 0 : SLIST_INIT(&sc->sc_root_sensors);
185 :
186 0 : strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
187 : sizeof(sc->sc_sensordev.xname));
188 :
189 0 : 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 0 : sc->sc_reports = mallocarray(sc->sc_max_repid,
194 : sizeof(struct upd_report), M_USBDEV, M_WAITOK | M_ZERO);
195 0 : for (i = 0; i < sc->sc_max_repid; i++)
196 0 : SLIST_INIT(&sc->sc_reports[i].sensors);
197 0 : sc->sc_sensors = mallocarray(UPD_MAX_SENSORS,
198 : sizeof(struct upd_sensor), M_USBDEV, M_WAITOK | M_ZERO);
199 0 : for (i = 0; i < UPD_MAX_SENSORS; i++)
200 0 : SLIST_INIT(&sc->sc_sensors[i].children);
201 :
202 0 : sc->sc_num_sensors = 0;
203 0 : uhidev_get_report_desc(uha->parent, &desc, &size);
204 0 : 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 0 : sc->sc_sensortask = sensor_task_register(sc, upd_refresh, 6);
209 0 : if (sc->sc_sensortask == NULL) {
210 0 : printf(", unable to register update task\n");
211 0 : return;
212 : }
213 0 : sensordev_install(&sc->sc_sensordev);
214 :
215 0 : printf("\n");
216 :
217 : DPRINTF(("upd_attach: complete\n"));
218 0 : }
219 :
220 : void
221 0 : 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 0 : 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 0 : for (i = 0; i < nentries; i++) {
232 0 : entry = entries + i;
233 0 : if (!upd_lookup_usage_entry(desc, size, entry, &item)) {
234 : /* dependency missing, add children to parent */
235 0 : upd_attach_sensor_tree(sc, desc, size,
236 0 : entry->nchildren, entry->children, queue);
237 0 : continue;
238 : }
239 :
240 : DPRINTF(("%s: found %s on repid=%d\n", DEVNAME(sc),
241 : entry->usage_name, item.report_ID));
242 0 : if (item.report_ID < 0 ||
243 0 : item.report_ID >= sc->sc_max_repid)
244 : continue;
245 :
246 0 : sensor = &sc->sc_sensors[sc->sc_num_sensors];
247 0 : memcpy(&sensor->hitem, &item, sizeof(struct hid_item));
248 0 : strlcpy(sensor->ksensor.desc, entry->usage_name,
249 : sizeof(sensor->ksensor.desc));
250 0 : sensor->ksensor.type = entry->senstype;
251 0 : sensor->ksensor.flags |= SENSOR_FINVALID;
252 0 : sensor->ksensor.status = SENSOR_S_UNKNOWN;
253 0 : sensor->ksensor.value = 0;
254 0 : sensor_attach(&sc->sc_sensordev, &sensor->ksensor);
255 0 : sensor->attached = 1;
256 0 : SLIST_INSERT_HEAD(queue, sensor, dep_next);
257 0 : sc->sc_num_sensors++;
258 :
259 0 : upd_attach_sensor_tree(sc, desc, size, entry->nchildren,
260 0 : entry->children, &sensor->children);
261 :
262 0 : report = &sc->sc_reports[item.report_ID];
263 0 : if (SLIST_EMPTY(&report->sensors))
264 0 : report->size = hid_report_size(desc,
265 0 : size, item.kind, item.report_ID);
266 0 : SLIST_INSERT_HEAD(&report->sensors, sensor, rep_next);
267 0 : }
268 0 : }
269 :
270 : int
271 0 : upd_detach(struct device *self, int flags)
272 : {
273 0 : struct upd_softc *sc = (struct upd_softc *)self;
274 : struct upd_sensor *sensor;
275 : int i;
276 :
277 0 : if (sc->sc_sensortask != NULL)
278 0 : sensor_task_unregister(sc->sc_sensortask);
279 :
280 0 : sensordev_deinstall(&sc->sc_sensordev);
281 :
282 0 : for (i = 0; i < sc->sc_num_sensors; i++) {
283 0 : sensor = &sc->sc_sensors[i];
284 0 : if (sensor->attached)
285 0 : sensor_detach(&sc->sc_sensordev, &sensor->ksensor);
286 : }
287 :
288 0 : free(sc->sc_reports, M_USBDEV, sc->sc_max_repid * sizeof(struct upd_report));
289 0 : free(sc->sc_sensors, M_USBDEV, UPD_MAX_SENSORS * sizeof(struct upd_sensor));
290 0 : return (0);
291 : }
292 :
293 : void
294 0 : upd_refresh(void *arg)
295 : {
296 0 : struct upd_softc *sc = arg;
297 : int s;
298 :
299 : /* request root sensors, do not let async handlers fire yet */
300 0 : s = splusb();
301 0 : upd_request_children(sc, &sc->sc_root_sensors);
302 0 : splx(s);
303 0 : }
304 :
305 : void
306 0 : 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 0 : SLIST_FOREACH(sensor, queue, dep_next) {
313 0 : repid = sensor->hitem.report_ID;
314 0 : report = &sc->sc_reports[repid];
315 :
316 : /* already requested */
317 0 : if (report->pending)
318 : continue;
319 0 : report->pending = 1;
320 :
321 0 : len = uhidev_get_report_async(sc->sc_hdev.sc_parent,
322 0 : 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 0 : if (len < 0) {
327 0 : upd_update_report_cb(sc, repid, NULL, -1);
328 0 : report->pending = 0;
329 0 : }
330 : }
331 0 : }
332 :
333 : int
334 0 : 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 0 : for (hdata = hid_start_parse(desc, size, hid_feature);
341 0 : hid_get_item(hdata, item); ) {
342 0 : if (item->kind == hid_feature &&
343 0 : entry->usage_pg == HID_GET_USAGE_PAGE(item->usage) &&
344 0 : entry->usage_id == HID_GET_USAGE(item->usage)) {
345 : ret = 1;
346 0 : break;
347 : }
348 : }
349 0 : hid_end_parse(hdata);
350 :
351 0 : return (ret);
352 : }
353 :
354 : struct upd_sensor *
355 0 : upd_lookup_sensor(struct upd_softc *sc, int page, int usage)
356 : {
357 : struct upd_sensor *sensor = NULL;
358 : int i;
359 :
360 0 : for (i = 0; i < sc->sc_num_sensors; i++) {
361 0 : sensor = &sc->sc_sensors[i];
362 0 : if (page == HID_GET_USAGE_PAGE(sensor->hitem.usage) &&
363 0 : usage == HID_GET_USAGE(sensor->hitem.usage))
364 0 : return (sensor);
365 : }
366 0 : return (NULL);
367 0 : }
368 :
369 : void
370 0 : upd_update_report_cb(void *priv, int repid, void *data, int len)
371 : {
372 0 : struct upd_softc *sc = priv;
373 0 : struct upd_report *report = &sc->sc_reports[repid];
374 : struct upd_sensor *sensor;
375 :
376 : /* handle buggy firmware */
377 0 : if (len > 0 && report->size != len)
378 0 : report->size = len;
379 :
380 0 : if (data == NULL || len <= 0) {
381 0 : SLIST_FOREACH(sensor, &report->sensors, rep_next)
382 0 : upd_sensor_invalidate(sc, sensor);
383 : } else {
384 0 : SLIST_FOREACH(sensor, &report->sensors, rep_next)
385 0 : upd_sensor_update(sc, sensor, data, len);
386 : }
387 0 : report->pending = 0;
388 0 : }
389 :
390 : void
391 0 : upd_sensor_invalidate(struct upd_softc *sc, struct upd_sensor *sensor)
392 : {
393 : struct upd_sensor *child;
394 :
395 0 : sensor->ksensor.status = SENSOR_S_UNKNOWN;
396 0 : sensor->ksensor.flags |= SENSOR_FINVALID;
397 :
398 0 : SLIST_FOREACH(child, &sensor->children, dep_next)
399 0 : upd_sensor_invalidate(sc, child);
400 0 : }
401 :
402 : void
403 0 : 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 0 : 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 0 : 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 0 : break;
422 : default:
423 : adjust = 1; /* no scale adjust */
424 0 : break;
425 : }
426 :
427 0 : hdata = hid_get_data(buf, len, &sensor->hitem.loc);
428 0 : sensor->ksensor.value = hdata * adjust;
429 0 : sensor->ksensor.status = SENSOR_S_OK;
430 0 : sensor->ksensor.flags &= ~SENSOR_FINVALID;
431 :
432 : /* if battery not present, invalidate children */
433 0 : if (HID_GET_USAGE_PAGE(sensor->hitem.usage) == HUP_BATTERY &&
434 0 : HID_GET_USAGE(sensor->hitem.usage) == HUB_BATTERY_PRESENT &&
435 0 : sensor->ksensor.value == 0) {
436 0 : SLIST_FOREACH(child, &sensor->children, dep_next)
437 0 : upd_sensor_invalidate(sc, child);
438 0 : return;
439 : }
440 :
441 0 : upd_request_children(sc, &sensor->children);
442 0 : }
443 :
444 : void
445 0 : upd_intr(struct uhidev *uh, void *p, uint len)
446 : {
447 : /* noop */
448 0 : }
|