xref: /openbsd/sys/dev/usb/uhidpp.c (revision 5dea098c)
1 /*	$OpenBSD: uhidpp.c,v 1.43 2023/01/08 06:54:51 anton Exp $	*/
2 
3 /*
4  * Copyright (c) 2021 Anton Lindqvist <anton@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/device.h>
23 #include <sys/mutex.h>
24 #include <sys/sensors.h>
25 
26 #include <dev/usb/usb.h>
27 #include <dev/usb/usbhid.h>
28 #include <dev/usb/usbdi.h>
29 #include <dev/usb/usbdevs.h>
30 #include <dev/usb/uhidev.h>
31 
32 /* #define UHIDPP_DEBUG */
33 #ifdef UHIDPP_DEBUG
34 
35 #define DPRINTF(x...) do {						\
36 	if (uhidpp_debug)						\
37 		printf(x);						\
38 } while (0)
39 
40 #define DREPORT(prefix, repid, buf, len) do {				\
41 	if (uhidpp_debug)						\
42 		uhidd_dump_report((prefix), (repid), (buf), (len));	\
43 } while (0)
44 
45 void uhidd_dump_report(const char *, uint8_t, const unsigned char *, u_int);
46 
47 int uhidpp_debug = 1;
48 
49 #else
50 
51 #define DPRINTF(x...)
52 #define DREPORT(prefix, repid, buf, len)
53 
54 #endif
55 
56 #define HIDPP_REPORT_ID_SHORT			0x10
57 #define HIDPP_REPORT_ID_LONG			0x11
58 
59 /*
60  * Length of reports. Note that the effective length is always +1 as
61  * uhidev_set_report() prepends the report ID.
62  */
63 #define HIDPP_REPORT_SHORT_LENGTH		(7 - 1)
64 #define HIDPP_REPORT_LONG_LENGTH		(20 - 1)
65 
66 /*
67  * Maximum number of allowed parameters for reports. Note, the parameters always
68  * starts at offset 3 for both RAP and FAP reports.
69  */
70 #define HIDPP_REPORT_SHORT_PARAMS_MAX		(HIDPP_REPORT_SHORT_LENGTH - 3)
71 #define HIDPP_REPORT_LONG_PARAMS_MAX		(HIDPP_REPORT_LONG_LENGTH - 3)
72 
73 #define HIDPP_DEVICE_ID_RECEIVER		0xff
74 
75 #define HIDPP_FEAT_ROOT_ID			0x00
76 #define HIDPP_FEAT_ROOT_PING_FUNC		0x01
77 #define  HIDPP_PING_DATA			0x5a
78 
79 #define HIDPP_SET_REGISTER			0x80
80 #define HIDPP_GET_REGISTER			0x81
81 #define HIDPP_SET_LONG_REGISTER			0x82
82 #define HIDPP_GET_LONG_REGISTER			0x83
83 
84 #define HIDPP_REG_ENABLE_REPORTS			0x00
85 #define  HIDPP_ENABLE_REPORTS_DEVICE_BATTERY_STATUS	0x10
86 #define  HIDPP_ENABLE_REPORTS_RECEIVER_WIRELESS		0x01
87 #define  HIDPP_ENABLE_REPORTS_RECEIVER_SOFTWARE_PRESENT	0x08
88 
89 #define HIDPP_REG_PAIRING_INFORMATION		0xb5
90 
91 /* HID++ 1.0 error codes. */
92 #define HIDPP_ERROR				0x8f
93 #define HIDPP_ERROR_SUCCESS			0x00
94 #define HIDPP_ERROR_INVALID_SUBID		0x01
95 #define HIDPP_ERROR_INVALID_ADRESS		0x02
96 #define HIDPP_ERROR_INVALID_VALUE		0x03
97 #define HIDPP_ERROR_CONNECT_FAIL		0x04
98 #define HIDPP_ERROR_TOO_MANY_DEVICES		0x05
99 #define HIDPP_ERROR_ALREADY_EXISTS		0x06
100 #define HIDPP_ERROR_BUSY			0x07
101 #define HIDPP_ERROR_UNKNOWN_DEVICE		0x08
102 #define HIDPP_ERROR_RESOURCE_ERROR		0x09
103 #define HIDPP_ERROR_REQUEST_UNAVAILABLE		0x0a
104 #define HIDPP_ERROR_INVALID_PARAM_VALUE		0x0b
105 #define HIDPP_ERROR_WRONG_PIN_CODE		0x0c
106 
107 /*
108  * The software ID is added to feature access reports (FAP) and used to
109  * distinguish responses from notifications. Note, the software ID must be
110  * greater than zero which is reserved for notifications.
111  * The effective software ID round robins within its allowed interval [1, 15]
112  * making it easier to correlate requests and responses.
113  */
114 #define HIDPP_SOFTWARE_ID_MIN			1
115 #define HIDPP_SOFTWARE_ID_MAX			15
116 #define HIDPP_SOFTWARE_ID_LEN			4
117 
118 #define HIDPP20_FEAT_ROOT_ID			0x0000
119 #define HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC	0x0000
120 
121 #define HIDPP20_FEAT_FEATURE_ID			0x0001
122 #define HIDPP20_FEAT_FEATURE_COUNT_FUNC		0x0000
123 #define HIDPP20_FEAT_FEATURE_ID_FUNC		0x0001
124 
125 #define HIDPP20_FEAT_BATTERY_ID			0x1000
126 #define HIDPP20_FEAT_BATTERY_LEVEL_STATUS_FUNC	0x0000
127 #define  HIDPP20_LEVEL_STATUS_CHARGING_DONE	0x0003
128 #define HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC	0x0001
129 #define  HIDPP20_CAPABILITY_RECHARGEABLE	0x0004
130 
131 #define HIDPP20_FEAT_UNIFIED_BATTERY_ID			0x1004
132 #define HIDPP20_FEAT_UNIFIED_BATTERY_CAPABILITIES_FUNC	0x0000
133 #define  HIDPP20_CAPABILITES_RECHARGEABLE		0x0002
134 #define HIDPP20_FEAT_UNIFIED_BATTERY_STATUS_FUNC	0x0001
135 #define  HIDPP20_BATTERY_STATUS_CRITICAL		0x0001
136 #define  HIDPP20_BATTERY_STATUS_LOW			0x0002
137 #define  HIDPP20_BATTERY_STATUS_GOOD			0x0004
138 #define  HIDPP20_BATTERY_STATUS_FULL			0x0008
139 
140 /* HID++ 2.0 error codes. */
141 #define HIDPP20_ERROR				0xff
142 #define HIDPP20_ERROR_NO_ERROR			0x00
143 #define HIDPP20_ERROR_UNKNOWN			0x01
144 #define HIDPP20_ERROR_INVALID_ARGUMENT		0x02
145 #define HIDPP20_ERROR_OUT_OF_RANGE		0x03
146 #define HIDPP20_ERROR_HARDWARE_ERROR		0x04
147 #define HIDPP20_ERROR_LOGITECH_INTERNAL		0x05
148 #define HIDPP20_ERROR_INVALID_FEATURE_INDEX	0x06
149 #define HIDPP20_ERROR_INVALID_FUNCTION_ID	0x07
150 #define HIDPP20_ERROR_BUSY			0x08
151 #define HIDPP20_ERROR_UNSUPPORTED		0x09
152 
153 /*
154  * Sentinels used for interrupt response synchronization. The values must be
155  * disjoint from existing report IDs.
156  */
157 #define UHIDPP_RESP_NONE			0
158 #define UHIDPP_RESP_WAIT			1
159 #define UHIDPP_RESP_ERROR			2
160 
161 /* Maximum number of devices associated with a single receiver. */
162 #define UHIDPP_NDEVICES				6
163 
164 /* Maximum number of pending notifications. */
165 #define UHIDPP_NNOTIFICATIONS			4
166 
167 /* Number of sensors per paired device. */
168 #define UHIDPP_NSENSORS				3
169 
170 /* Feature access report used by the HID++ 2.0 (and greater) protocol. */
171 struct fap {
172 	uint8_t feature_idx;
173 	uint8_t funcidx_swid;
174 	uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX];
175 };
176 
177 /*
178  * Register access report used by the HID++ 1.0 protocol. Receivers always uses
179  * this type of report.
180  */
181 struct rap {
182 	uint8_t sub_id;
183 	uint8_t reg_address;
184 	uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX];
185 };
186 
187 struct uhidpp_report {
188 	uint8_t device_id;
189 	union {
190 		struct fap fap;
191 		struct rap rap;
192 	};
193 } __packed;
194 
195 struct uhidpp_notification {
196 	struct uhidpp_report n_rep;
197 	unsigned int n_id;
198 };
199 
200 struct uhidpp_device {
201 	uint8_t d_id;
202 	uint8_t d_connected;
203 	uint8_t d_major;
204 	uint8_t d_minor;
205 	uint8_t d_features;
206 #define UHIDPP_DEVICE_FEATURE_ROOT		0x01
207 #define UHIDPP_DEVICE_FEATURE_BATTERY		0x02
208 #define UHIDPP_DEVICE_FEATURE_UNIFIED_BATTERY	0x04
209 
210 	struct {
211 		struct ksensor sens[UHIDPP_NSENSORS];
212 		uint8_t feature_idx;
213 		uint8_t nlevels;
214 		uint8_t unified_level_mask;
215 		uint8_t rechargeable;
216 	} d_battery;
217 };
218 
219 /*
220  * Locking:
221  *	[I]	immutable
222  *	[m]	sc_mtx
223  */
224 struct uhidpp_softc {
225 	struct uhidev sc_hdev;
226 	struct usbd_device *sc_udev;
227 
228 	struct mutex sc_mtx;
229 
230 	struct uhidpp_device sc_devices[UHIDPP_NDEVICES];
231 					/* [m] connected devices */
232 
233 	struct uhidpp_notification sc_notifications[UHIDPP_NNOTIFICATIONS];
234 					/* [m] pending notifications */
235 
236 	struct usb_task sc_task;	/* [m] notification task */
237 
238 	struct ksensordev sc_sensdev;	/* [m] */
239 	struct sensor_task *sc_senstsk;	/* [m] */
240 
241 	struct uhidpp_report *sc_req;	/* [m] synchronous request buffer */
242 	struct uhidpp_report *sc_resp;	/* [m] synchronous response buffer */
243 	u_int sc_resp_state;		/* [m] synchronous response state */
244 	u_int sc_swid;			/* [m] request software id */
245 
246 	enum {
247 		UHIDPP_RECEIVER_UNIFYING,
248 		UHIDPP_RECEIVER_BOLT,
249 	} sc_receiver;			/* [I] */
250 };
251 
252 int uhidpp_match(struct device *, void *, void *);
253 void uhidpp_attach(struct device *, struct device *, void *);
254 int uhidpp_detach(struct device *, int flags);
255 void uhidpp_intr(struct uhidev *addr, void *ibuf, u_int len);
256 void uhidpp_refresh(void *);
257 void uhidpp_task(void *);
258 int uhidpp_sleep(struct uhidpp_softc *, uint64_t);
259 
260 void uhidpp_device_connect(struct uhidpp_softc *, struct uhidpp_device *);
261 void uhidpp_device_refresh(struct uhidpp_softc *, struct uhidpp_device *);
262 int uhidpp_device_features(struct uhidpp_softc *, struct uhidpp_device *);
263 
264 struct uhidpp_notification *uhidpp_claim_notification(struct uhidpp_softc *);
265 int uhidpp_consume_notification(struct uhidpp_softc *, struct uhidpp_report *);
266 int uhidpp_is_notification(struct uhidpp_softc *, struct uhidpp_report *);
267 
268 static int uhidpp_has_sensors(struct uhidpp_softc *);
269 
270 int hidpp_get_protocol_version(struct uhidpp_softc *, uint8_t, uint8_t *,
271     uint8_t *);
272 
273 int hidpp10_get_name(struct uhidpp_softc *, uint8_t, char *, size_t);
274 int hidpp10_get_type(struct uhidpp_softc *, uint8_t, const char **);
275 int hidpp10_enable_notifications(struct uhidpp_softc *, uint8_t);
276 
277 int hidpp20_root_get_feature(struct uhidpp_softc *, uint8_t, uint16_t,
278     uint8_t *, uint8_t *);
279 int hidpp20_feature_get_count(struct uhidpp_softc *, uint8_t, uint8_t,
280     uint8_t *);
281 int hidpp20_feature_get_id(struct uhidpp_softc *, uint8_t, uint8_t, uint8_t,
282     uint16_t *, uint8_t *);
283 int hidpp20_battery_get_level_status(struct uhidpp_softc *,
284     struct uhidpp_device *);
285 int hidpp20_battery_get_capability(struct uhidpp_softc *,
286     struct uhidpp_device *);
287 int hidpp20_battery_status_is_charging(uint8_t);
288 int hidpp20_unified_battery_get_capabilities(struct uhidpp_softc *,
289     struct uhidpp_device *);
290 int hidpp20_unified_battery_get_status(struct uhidpp_softc *,
291     struct uhidpp_device *);
292 int hidpp20_unified_battery_status_is_charging(uint8_t);
293 
294 int hidpp_send_validate(uint8_t, int);
295 int hidpp_send_rap_report(struct uhidpp_softc *, uint8_t, uint8_t, uint8_t,
296     uint8_t, uint8_t *, int, struct uhidpp_report *);
297 int hidpp_send_fap_report(struct uhidpp_softc *, uint8_t, uint8_t, uint8_t,
298     uint8_t, uint8_t *, int, struct uhidpp_report *);
299 int hidpp_send_report(struct uhidpp_softc *, uint8_t, struct uhidpp_report *,
300     struct uhidpp_report *);
301 
302 static uint8_t
303 nlevels(uint8_t mask)
304 {
305 	uint8_t nbits = 0;
306 
307 	for (; mask > 0; mask >>= 1) {
308 		if (mask & 1)
309 			nbits++;
310 	}
311 	return nbits;
312 }
313 
314 struct cfdriver uhidpp_cd = {
315 	NULL, "uhidpp", DV_DULL
316 };
317 
318 const struct cfattach uhidpp_ca = {
319 	sizeof(struct uhidpp_softc),
320 	uhidpp_match,
321 	uhidpp_attach,
322 	uhidpp_detach,
323 };
324 
325 static const struct usb_devno uhidpp_devs[] = {
326 	{ USB_VENDOR_LOGITECH,	USB_PRODUCT_ANY },
327 };
328 
329 int
330 uhidpp_match(struct device *parent, void *match, void *aux)
331 {
332 	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
333 	void *desc;
334 	int descsiz, siz;
335 
336 	if (!UHIDEV_CLAIM_MULTIPLE_REPORTID(uha))
337 		return UMATCH_NONE;
338 
339 	if (usb_lookup(uhidpp_devs,
340 	    uha->uaa->vendor, uha->uaa->product) == NULL)
341 		return UMATCH_NONE;
342 
343 	uhidev_get_report_desc(uha->parent, &desc, &descsiz);
344 	siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_SHORT);
345 	if (siz != HIDPP_REPORT_SHORT_LENGTH)
346 		return UMATCH_NONE;
347 	siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_LONG);
348 	if (siz != HIDPP_REPORT_LONG_LENGTH)
349 		return UMATCH_NONE;
350 
351 	uha->claimed[HIDPP_REPORT_ID_SHORT] = 1;
352 	uha->claimed[HIDPP_REPORT_ID_LONG] = 1;
353 	return UMATCH_VENDOR_PRODUCT;
354 }
355 
356 void
357 uhidpp_attach(struct device *parent, struct device *self, void *aux)
358 {
359 	struct uhidpp_softc *sc = (struct uhidpp_softc *)self;
360 	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
361 	struct usb_attach_arg *uaa = uha->uaa;
362 	int npaired = 0;
363 	int error, i;
364 
365 	sc->sc_hdev.sc_intr = uhidpp_intr;
366 	sc->sc_hdev.sc_udev = uaa->device;
367 	sc->sc_hdev.sc_parent = uha->parent;
368 	sc->sc_hdev.sc_report_id = uha->reportid;
369 	/* The largest supported report dictates the sizes. */
370 	sc->sc_hdev.sc_isize = HIDPP_REPORT_LONG_LENGTH;
371 	sc->sc_hdev.sc_osize = HIDPP_REPORT_LONG_LENGTH;
372 
373 	sc->sc_udev = uaa->device;
374 
375 	mtx_init(&sc->sc_mtx, IPL_USB);
376 
377 	sc->sc_resp = NULL;
378 	sc->sc_resp_state = UHIDPP_RESP_NONE;
379 	sc->sc_swid = HIDPP_SOFTWARE_ID_MIN;
380 
381 	error = uhidev_open(&sc->sc_hdev);
382 	if (error) {
383 		printf(" open error %d\n", error);
384 		return;
385 	}
386 
387 	usb_init_task(&sc->sc_task, uhidpp_task, sc, USB_TASK_TYPE_GENERIC);
388 
389 	mtx_enter(&sc->sc_mtx);
390 
391 	/*
392 	 * Wire up report device handlers before issuing commands to the device
393 	 * in order to receive responses. Necessary as uhidev by default
394 	 * performs the wiring after the attach routine has returned.
395 	 */
396 	error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev,
397 	    HIDPP_REPORT_ID_SHORT);
398 	if (error) {
399 		mtx_leave(&sc->sc_mtx);
400 		printf(" short report error %d\n", error);
401 		return;
402 	}
403 	error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev,
404 	    HIDPP_REPORT_ID_LONG);
405 	if (error) {
406 		mtx_leave(&sc->sc_mtx);
407 		printf(" long report error %d\n", error);
408 		return;
409 	}
410 
411 	if (uaa->product == 0xc548)
412 		sc->sc_receiver = UHIDPP_RECEIVER_BOLT;
413 	else
414 		sc->sc_receiver = UHIDPP_RECEIVER_UNIFYING;
415 
416 	/* Probe paired devices. */
417 	for (i = 0; i < UHIDPP_NDEVICES; i++) {
418 		char name[16];
419 		struct uhidpp_device *dev = &sc->sc_devices[i];
420 		const char *type;
421 		uint8_t device_id = i + 1;
422 
423 		dev->d_id = device_id;
424 
425 		if (hidpp10_get_type(sc, device_id, &type) ||
426 		    hidpp10_get_name(sc, device_id, name, sizeof(name)))
427 			continue;
428 
429 		if (npaired > 0)
430 			printf(",");
431 		printf(" device %d", device_id);
432 		printf(" %s", type);
433 		printf(" \"%s\"", name);
434 		npaired++;
435 	}
436 	if (npaired == 0)
437 		goto out;
438 
439 	/* Enable notifications for the receiver. */
440 	error = hidpp10_enable_notifications(sc, HIDPP_DEVICE_ID_RECEIVER);
441 	if (error)
442 		printf(" error %d", error);
443 
444 out:
445 	mtx_leave(&sc->sc_mtx);
446 	printf("\n");
447 }
448 
449 int
450 uhidpp_detach(struct device *self, int flags)
451 {
452 	struct uhidpp_softc *sc = (struct uhidpp_softc *)self;
453 	int i;
454 
455 	usb_rem_wait_task(sc->sc_udev, &sc->sc_task);
456 
457 	if (uhidpp_has_sensors(sc))
458 		sensor_task_unregister(sc->sc_senstsk);
459 
460 	KASSERT(sc->sc_resp_state == UHIDPP_RESP_NONE);
461 
462 	if (uhidpp_has_sensors(sc))
463 		sensordev_deinstall(&sc->sc_sensdev);
464 
465 	for (i = 0; i < UHIDPP_NDEVICES; i++) {
466 		struct uhidpp_device *dev = &sc->sc_devices[i];
467 		struct ksensor *sens = dev->d_battery.sens;
468 
469 		if (!dev->d_connected)
470 			continue;
471 
472 		sensor_detach(&sc->sc_sensdev, &sens[0]);
473 		sensor_detach(&sc->sc_sensdev, &sens[1]);
474 		if (dev->d_battery.rechargeable)
475 			sensor_detach(&sc->sc_sensdev, &sens[2]);
476 	}
477 
478 	uhidev_close(&sc->sc_hdev);
479 
480 	return 0;
481 }
482 
483 void
484 uhidpp_intr(struct uhidev *addr, void *buf, u_int len)
485 {
486 	struct uhidpp_softc *sc = (struct uhidpp_softc *)addr;
487 	struct uhidpp_report *rep = buf;
488 	int dowake = 0;
489 	uint8_t repid;
490 
491 	/*
492 	 * Ugliness ahead as the report ID is stripped of by uhidev_intr() but
493 	 * needed to determine if an error occurred.
494 	 * Note that an error response is always a short report even if the
495 	 * command that caused the error is a long report.
496 	 */
497 	repid = ((uint8_t *)buf)[-1];
498 
499 	DREPORT(__func__, repid, buf, len);
500 
501 	mtx_enter(&sc->sc_mtx);
502 	if (uhidpp_is_notification(sc, rep)) {
503 		struct uhidpp_notification *ntf;
504 
505 		ntf = uhidpp_claim_notification(sc);
506 		if (ntf != NULL) {
507 			memcpy(&ntf->n_rep, buf, len);
508 			usb_add_task(sc->sc_udev, &sc->sc_task);
509 		} else {
510 			DPRINTF("%s: too many notifications", __func__);
511 		}
512 	} else {
513 		KASSERT(sc->sc_resp_state == UHIDPP_RESP_WAIT);
514 		dowake = 1;
515 		sc->sc_resp_state = repid;
516 		memcpy(sc->sc_resp, buf, len);
517 	}
518 	mtx_leave(&sc->sc_mtx);
519 	if (dowake)
520 		wakeup(sc);
521 }
522 
523 void
524 uhidpp_refresh(void *arg)
525 {
526 	struct uhidpp_softc *sc = arg;
527 	int i;
528 
529 	mtx_enter(&sc->sc_mtx);
530 	for (i = 0; i < UHIDPP_NDEVICES; i++) {
531 		struct uhidpp_device *dev = &sc->sc_devices[i];
532 
533 		if (dev->d_connected)
534 			uhidpp_device_refresh(sc, dev);
535 	}
536 	mtx_leave(&sc->sc_mtx);
537 }
538 
539 void
540 uhidpp_task(void *arg)
541 {
542 	struct uhidpp_softc *sc = arg;
543 
544 	mtx_enter(&sc->sc_mtx);
545 	for (;;) {
546 		struct uhidpp_report rep;
547 		struct uhidpp_device *dev;
548 
549 		if (uhidpp_consume_notification(sc, &rep))
550 			break;
551 
552 		DPRINTF("%s: device_id=%d, sub_id=%02x\n",
553 		    __func__, rep.device_id, rep.rap.sub_id);
554 
555 		if (rep.device_id == 0 || rep.device_id > UHIDPP_NDEVICES) {
556 			DPRINTF("%s: invalid device\n", __func__);
557 			continue;
558 		}
559 		dev = &sc->sc_devices[rep.device_id - 1];
560 
561 		switch (rep.rap.sub_id) {
562 		case 0x0e:	/* leds */
563 		case 0x40:	/* disconnect */
564 		case 0x4b:	/* pairing accepted */
565 			break;
566 		case 0x41:	/* connect */
567 			uhidpp_device_connect(sc, dev);
568 			break;
569 		}
570 	}
571 	mtx_leave(&sc->sc_mtx);
572 }
573 
574 int
575 uhidpp_sleep(struct uhidpp_softc *sc, uint64_t nsecs)
576 {
577 	return msleep_nsec(sc, &sc->sc_mtx, PZERO, "uhidpp", nsecs);
578 }
579 
580 void
581 uhidpp_device_connect(struct uhidpp_softc *sc, struct uhidpp_device *dev)
582 {
583 	struct ksensor *sens;
584 	int error;
585 
586 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
587 
588 	/* A connected device will continuously send connect events. */
589 	if (dev->d_connected)
590 		return;
591 
592 	/*
593 	 * If features are already present, it must be a device lacking battery
594 	 * support.
595 	 */
596 	if (dev->d_features)
597 		return;
598 
599 	error = hidpp_get_protocol_version(sc, dev->d_id,
600 	    &dev->d_major, &dev->d_minor);
601 	if (error) {
602 		DPRINTF("%s: protocol version failure: device_id=%d, "
603 		    "error=%d\n",
604 		    __func__, dev->d_id, error);
605 		return;
606 	}
607 	DPRINTF("%s: device_id=%d, version=%d.%d\n",
608 	    __func__, dev->d_id, dev->d_major, dev->d_minor);
609 	if (dev->d_major <= 1)
610 		return;
611 
612 	error = uhidpp_device_features(sc, dev);
613 	if (error) {
614 		DPRINTF("%s: features failure: device_id=%d, "
615 		    "error=%d\n",
616 		    __func__, dev->d_id, error);
617 		return;
618 	}
619 
620 	if (dev->d_features & UHIDPP_DEVICE_FEATURE_BATTERY)
621 		error = hidpp20_battery_get_capability(sc, dev);
622 	else if (dev->d_features & UHIDPP_DEVICE_FEATURE_UNIFIED_BATTERY)
623 		error = hidpp20_unified_battery_get_capabilities(sc, dev);
624 	if (error) {
625 		DPRINTF("%s: battery capability failure: device_id=%d, "
626 		    "error=%d\n", __func__, dev->d_id, error);
627 		return;
628 	}
629 
630 	dev->d_connected = 1;
631 
632 	sens = &dev->d_battery.sens[0];
633 	strlcpy(sens->desc, "battery level", sizeof(sens->desc));
634 	sens->type = SENSOR_PERCENT;
635 	sens->flags = SENSOR_FUNKNOWN;
636 	sensor_attach(&sc->sc_sensdev, sens);
637 
638 	sens = &dev->d_battery.sens[1];
639 	strlcpy(sens->desc, "number of battery levels", sizeof(sens->desc));
640 	sens->type = SENSOR_INTEGER;
641 	sens->value = dev->d_battery.nlevels;
642 	sensor_attach(&sc->sc_sensdev, sens);
643 
644 	if (dev->d_battery.rechargeable) {
645 		sens = &dev->d_battery.sens[2];
646 		strlcpy(sens->desc, "charger", sizeof(sens->desc));
647 		sens->type = SENSOR_INDICATOR;
648 		sens->value = 0;
649 		sensor_attach(&sc->sc_sensdev, sens);
650 	}
651 
652 	uhidpp_device_refresh(sc, dev);
653 
654 	/*
655 	 * There could be many devices connected to the same receiver, therefore
656 	 * only install the sensors once.
657 	 */
658 	if (uhidpp_has_sensors(sc))
659 		return;
660 
661 	strlcpy(sc->sc_sensdev.xname, sc->sc_hdev.sc_dev.dv_xname,
662 	    sizeof(sc->sc_sensdev.xname));
663 	sensordev_install(&sc->sc_sensdev);
664 
665 	/*
666 	 * The mutex must be temporarily released while calling
667 	 * sensor_task_register() as it might end up sleeping.
668 	 */
669 	KASSERT(sc->sc_senstsk == NULL);
670 	mtx_leave(&sc->sc_mtx);
671 	sc->sc_senstsk = sensor_task_register(sc, uhidpp_refresh, 60);
672 	mtx_enter(&sc->sc_mtx);
673 }
674 
675 void
676 uhidpp_device_refresh(struct uhidpp_softc *sc, struct uhidpp_device *dev)
677 {
678 	int error;
679 
680 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
681 
682 	if (dev->d_major <= 1)
683 		return;
684 
685 	if (dev->d_features & UHIDPP_DEVICE_FEATURE_BATTERY)
686 		error = hidpp20_battery_get_level_status(sc, dev);
687 	else if (dev->d_features & UHIDPP_DEVICE_FEATURE_UNIFIED_BATTERY)
688 		error = hidpp20_unified_battery_get_status(sc, dev);
689 	else
690 		error = -ENOTSUP;
691 	if (error) {
692 		DPRINTF("%s: battery status failure: device_id=%d, error=%d\n",
693 		    __func__, dev->d_id, error);
694 	}
695 }
696 
697 /*
698  * Enumerate all supported HID++ 2.0 features for the given device.
699  */
700 int
701 uhidpp_device_features(struct uhidpp_softc *sc, struct uhidpp_device *dev)
702 {
703 	int error;
704 	uint8_t count, feature_idx, feature_type, i;
705 
706 	/* All devices support the root feature. */
707 	dev->d_features |= UHIDPP_DEVICE_FEATURE_ROOT;
708 
709 	error = hidpp20_root_get_feature(sc, dev->d_id,
710 	    HIDPP20_FEAT_FEATURE_ID,
711 	    &feature_idx, &feature_type);
712 	if (error) {
713 		DPRINTF("%s: feature index failure: device_id=%d, error=%d\n",
714 		    __func__, dev->d_id, error);
715 		return error;
716 	}
717 
718 	error = hidpp20_feature_get_count(sc, dev->d_id, feature_idx, &count);
719 	if (error) {
720 		DPRINTF("%s: feature count failure: device_id=%d, error=%d\n",
721 		    __func__, dev->d_id, error);
722 		return error;
723 	}
724 
725 	for (i = 1; i <= count; i++) {
726 		uint16_t id;
727 		uint8_t type;
728 
729 		error = hidpp20_feature_get_id(sc, dev->d_id, feature_idx, i,
730 		    &id, &type);
731 		if (error)
732 			continue;
733 
734 		if (id == HIDPP20_FEAT_BATTERY_ID) {
735 			dev->d_features |= UHIDPP_DEVICE_FEATURE_BATTERY;
736 			dev->d_battery.feature_idx = i;
737 		} else if (id == HIDPP20_FEAT_UNIFIED_BATTERY_ID) {
738 			dev->d_features |= UHIDPP_DEVICE_FEATURE_UNIFIED_BATTERY;
739 			dev->d_battery.feature_idx = i;
740 		}
741 
742 		DPRINTF("%s: idx=%d, id=%x, type=%x device_id=%d\n",
743 		    __func__, i, id, type, dev->d_id);
744 	}
745 	DPRINTF("%s: device_id=%d, count=%d, features=%x\n",
746 	    __func__, dev->d_id, count, dev->d_features);
747 
748 	if ((dev->d_features & ~UHIDPP_DEVICE_FEATURE_ROOT) == 0)
749 		return -ENODEV;
750 	return 0;
751 }
752 
753 /*
754  * Returns the next available notification slot, if available.
755  */
756 struct uhidpp_notification *
757 uhidpp_claim_notification(struct uhidpp_softc *sc)
758 {
759 	struct uhidpp_notification *ntf = NULL;
760 	int nclaimed = 0;
761 	int i;
762 
763 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
764 
765 	for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) {
766 		struct uhidpp_notification *tmp = &sc->sc_notifications[i];
767 
768 		if (tmp->n_id > 0)
769 			nclaimed++;
770 		else if (ntf == NULL)
771 			ntf = tmp;
772 	}
773 
774 	if (ntf == NULL)
775 		return NULL;
776 	ntf->n_id = nclaimed + 1;
777 	return ntf;
778 }
779 
780 /*
781  * Consume the first unhandled notification, if present.
782  */
783 int
784 uhidpp_consume_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep)
785 {
786 	struct uhidpp_notification *ntf = NULL;
787 	int i;
788 
789 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
790 
791 	for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) {
792 		struct uhidpp_notification *tmp = &sc->sc_notifications[i];
793 
794 		if (tmp->n_id > 0 && (ntf == NULL || tmp->n_id < ntf->n_id))
795 			ntf = tmp;
796 	}
797 	if (ntf == NULL)
798 		return 1;
799 
800 	memcpy(rep, &ntf->n_rep, sizeof(*rep));
801 	ntf->n_id = 0;
802 	return 0;
803 }
804 
805 /*
806  * Returns non-zero if the given report is a notification. Otherwise, it must be
807  * a response.
808  */
809 int
810 uhidpp_is_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep)
811 {
812 	/* Not waiting for a response. */
813 	if (sc->sc_req == NULL)
814 		return 1;
815 
816 	/* Everything except the parameters must be repeated in a response. */
817 	if (sc->sc_req->device_id == rep->device_id &&
818 	    sc->sc_req->rap.sub_id == rep->rap.sub_id &&
819 	    sc->sc_req->rap.reg_address == rep->rap.reg_address)
820 		return 0;
821 
822 	/* An error must always be a response. */
823 	if ((rep->rap.sub_id == HIDPP_ERROR ||
824 	    rep->fap.feature_idx == HIDPP20_ERROR) &&
825 	    rep->fap.funcidx_swid == sc->sc_req->fap.feature_idx &&
826 	    rep->fap.params[0] == sc->sc_req->fap.funcidx_swid)
827 		return 0;
828 
829 	return 1;
830 }
831 
832 static int
833 uhidpp_has_sensors(struct uhidpp_softc *sc)
834 {
835 	return sc->sc_sensdev.xname[0] != '\0';
836 }
837 
838 int
839 hidpp_get_protocol_version(struct uhidpp_softc *sc, uint8_t device_id,
840     uint8_t *major, uint8_t *minor)
841 {
842 	struct uhidpp_report resp;
843 	uint8_t params[3] = { 0, 0, HIDPP_PING_DATA };
844 	int error;
845 
846 	error = hidpp_send_fap_report(sc,
847 	    HIDPP_REPORT_ID_SHORT,
848 	    device_id,
849 	    HIDPP_FEAT_ROOT_ID,
850 	    HIDPP_FEAT_ROOT_PING_FUNC,
851 	    params, sizeof(params), &resp);
852 	if (error == HIDPP_ERROR_INVALID_SUBID) {
853 		*major = 1;
854 		*minor = 0;
855 		return 0;
856 	}
857 	if (error)
858 		return error;
859 	if (resp.rap.params[2] != HIDPP_PING_DATA)
860 		return -EPROTO;
861 
862 	*major = resp.fap.params[0];
863 	*minor = resp.fap.params[1];
864 	return 0;
865 }
866 
867 int
868 hidpp10_get_name(struct uhidpp_softc *sc, uint8_t device_id,
869     char *buf, size_t bufsiz)
870 {
871 	struct uhidpp_report resp;
872 	int error;
873 	const uint8_t *name;
874 	uint8_t len;
875 
876 	if (sc->sc_receiver == UHIDPP_RECEIVER_BOLT) {
877 		uint8_t params[2] = { 0x60 + device_id, 0x01 };
878 
879 		error = hidpp_send_rap_report(sc,
880 		    HIDPP_REPORT_ID_SHORT,
881 		    HIDPP_DEVICE_ID_RECEIVER,
882 		    HIDPP_GET_LONG_REGISTER,
883 		    HIDPP_REG_PAIRING_INFORMATION,
884 		    params, sizeof(params), &resp);
885 		if (error)
886 			return error;
887 		len = resp.rap.params[2];
888 		name = &resp.rap.params[3];
889 	} else {
890 		uint8_t params[1] = { 0x40 + (device_id - 1) };
891 
892 		error = hidpp_send_rap_report(sc,
893 		    HIDPP_REPORT_ID_SHORT,
894 		    HIDPP_DEVICE_ID_RECEIVER,
895 		    HIDPP_GET_LONG_REGISTER,
896 		    HIDPP_REG_PAIRING_INFORMATION,
897 		    params, sizeof(params), &resp);
898 		if (error)
899 			return error;
900 		len = resp.rap.params[1];
901 		name = &resp.rap.params[2];
902 	}
903 
904 	if (len > bufsiz - 1)
905 		len = bufsiz - 1;
906 	memcpy(buf, name, len);
907 	buf[len] = '\0';
908 	return 0;
909 }
910 
911 int
912 hidpp10_get_type(struct uhidpp_softc *sc, uint8_t device_id, const char **buf)
913 {
914 	struct uhidpp_report resp;
915 	int error;
916 	uint8_t type;
917 
918 	if (sc->sc_receiver == UHIDPP_RECEIVER_BOLT) {
919 		uint8_t params[1] = { 0x50 + device_id };
920 
921 		error = hidpp_send_rap_report(sc,
922 		    HIDPP_REPORT_ID_SHORT,
923 		    HIDPP_DEVICE_ID_RECEIVER,
924 		    HIDPP_GET_LONG_REGISTER,
925 		    HIDPP_REG_PAIRING_INFORMATION,
926 		    params, sizeof(params), &resp);
927 		if (error)
928 			return error;
929 		type = resp.rap.params[1] & 0xf;
930 	} else {
931 		uint8_t params[1] = { 0x20 + (device_id - 1) };
932 
933 		error = hidpp_send_rap_report(sc,
934 		    HIDPP_REPORT_ID_SHORT,
935 		    HIDPP_DEVICE_ID_RECEIVER,
936 		    HIDPP_GET_LONG_REGISTER,
937 		    HIDPP_REG_PAIRING_INFORMATION,
938 		    params, sizeof(params), &resp);
939 		if (error)
940 			return error;
941 		type = resp.rap.params[7];
942 	}
943 
944 	switch (type) {
945 	case 0x00:
946 		*buf = "unknown";
947 		return 0;
948 	case 0x01:
949 		*buf = "keyboard";
950 		return 0;
951 	case 0x02:
952 		*buf = "mouse";
953 		return 0;
954 	case 0x03:
955 		*buf = "numpad";
956 		return 0;
957 	case 0x04:
958 		*buf = "presenter";
959 		return 0;
960 	case 0x08:
961 		*buf = "trackball";
962 		return 0;
963 	case 0x09:
964 		*buf = "touchpad";
965 		return 0;
966 	}
967 	return -ENOENT;
968 }
969 
970 int
971 hidpp10_enable_notifications(struct uhidpp_softc *sc, uint8_t device_id)
972 {
973 	struct uhidpp_report resp;
974 	uint8_t params[3];
975 
976 	/* Device reporting flags. */
977 	params[0] = HIDPP_ENABLE_REPORTS_DEVICE_BATTERY_STATUS;
978 	/* Receiver reporting flags. */
979 	params[1] = HIDPP_ENABLE_REPORTS_RECEIVER_WIRELESS |
980 	    HIDPP_ENABLE_REPORTS_RECEIVER_SOFTWARE_PRESENT;
981 	/* Device reporting flags (continued). */
982 	params[2] = 0;
983 
984 	return hidpp_send_rap_report(sc,
985 	    HIDPP_REPORT_ID_SHORT,
986 	    device_id,
987 	    HIDPP_SET_REGISTER,
988 	    HIDPP_REG_ENABLE_REPORTS,
989 	    params, sizeof(params), &resp);
990 }
991 
992 int
993 hidpp20_root_get_feature(struct uhidpp_softc *sc, uint8_t device_id,
994     uint16_t feature, uint8_t *feature_idx, uint8_t *feature_type)
995 {
996 	struct uhidpp_report resp;
997 	uint8_t params[2] = { feature >> 8, feature & 0xff };
998 	int error;
999 
1000 	error = hidpp_send_fap_report(sc,
1001 	    HIDPP_REPORT_ID_LONG,
1002 	    device_id,
1003 	    HIDPP20_FEAT_ROOT_ID,
1004 	    HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC,
1005 	    params, sizeof(params), &resp);
1006 	if (error)
1007 		return error;
1008 
1009 	if (resp.fap.params[0] == 0)
1010 		return -ENOENT;
1011 
1012 	*feature_idx = resp.fap.params[0];
1013 	*feature_type = resp.fap.params[1];
1014 	return 0;
1015 }
1016 
1017 int
1018 hidpp20_feature_get_count(struct uhidpp_softc *sc, uint8_t device_id,
1019     uint8_t feature_idx, uint8_t *count)
1020 {
1021 	struct uhidpp_report resp;
1022 	int error;
1023 
1024 	error = hidpp_send_fap_report(sc,
1025 	    HIDPP_REPORT_ID_LONG,
1026 	    device_id,
1027 	    feature_idx,
1028 	    HIDPP20_FEAT_FEATURE_COUNT_FUNC,
1029 	    NULL, 0, &resp);
1030 	if (error)
1031 		return error;
1032 
1033 	*count = resp.fap.params[0];
1034 	return 0;
1035 }
1036 
1037 int
1038 hidpp20_feature_get_id(struct uhidpp_softc *sc, uint8_t device_id,
1039     uint8_t feature_idx, uint8_t idx, uint16_t *id, uint8_t *type)
1040 {
1041 	struct uhidpp_report resp;
1042 	uint8_t params[1] = { idx };
1043 	int error;
1044 
1045 	error = hidpp_send_fap_report(sc,
1046 	    HIDPP_REPORT_ID_LONG,
1047 	    device_id,
1048 	    feature_idx,
1049 	    HIDPP20_FEAT_FEATURE_ID_FUNC,
1050 	    params, sizeof(params), &resp);
1051 	if (error)
1052 		return error;
1053 
1054 	*id = bemtoh16(resp.fap.params);
1055 	*type = resp.fap.params[2];
1056 	return 0;
1057 }
1058 
1059 int
1060 hidpp20_battery_get_level_status(struct uhidpp_softc *sc,
1061     struct uhidpp_device *dev)
1062 {
1063 	struct uhidpp_report resp;
1064 	int charging, error;
1065 	uint8_t level, status;
1066 
1067 	error = hidpp_send_fap_report(sc,
1068 	    HIDPP_REPORT_ID_LONG,
1069 	    dev->d_id,
1070 	    dev->d_battery.feature_idx,
1071 	    HIDPP20_FEAT_BATTERY_LEVEL_STATUS_FUNC,
1072 	    NULL, 0, &resp);
1073 	if (error)
1074 		return error;
1075 
1076 	level = resp.fap.params[0];
1077 	/* next_level = resp.fap.params[1]; */
1078 	status = resp.fap.params[2];
1079 	/*
1080 	 * While charging, the reported level cannot be trusted. However, fake
1081 	 * the battery state once the charging is done.
1082 	 */
1083 	if (status == HIDPP20_LEVEL_STATUS_CHARGING_DONE) {
1084 		level = 100;
1085 		status = 0;
1086 	}
1087 
1088 	charging = hidpp20_battery_status_is_charging(status);
1089 
1090 	dev->d_battery.sens[0].value = level * 1000;
1091 	dev->d_battery.sens[0].flags &= ~SENSOR_FUNKNOWN;
1092 	if (dev->d_battery.nlevels < 10) {
1093 		/*
1094 		 * According to the HID++ 2.0 specification, less than
1095 		 * 10 levels should be mapped to the following 4 levels:
1096 		 *
1097 		 * [0, 10]   critical
1098 		 * [11, 30]  low
1099 		 * [31, 80]  good
1100 		 * [81, 100] full
1101 		 *
1102 		 * Since sensors are limited to 3 valid statuses, clamp
1103 		 * it even further. Unless the battery is charging in
1104 		 * which the level cannot be trusted.
1105 		 */
1106 		if (charging)
1107 			dev->d_battery.sens[0].status = SENSOR_S_UNKNOWN;
1108 		else if (level <= 10)
1109 			dev->d_battery.sens[0].status = SENSOR_S_CRIT;
1110 		else if (level <= 30)
1111 			dev->d_battery.sens[0].status = SENSOR_S_WARN;
1112 		else
1113 			dev->d_battery.sens[0].status = SENSOR_S_OK;
1114 	} else {
1115 		/*
1116 		 * XXX the device supports battery mileage. The current
1117 		 * level must be checked against resp.fap.params[3]
1118 		 * given by hidpp20_battery_get_capability().
1119 		 */
1120 		dev->d_battery.sens[0].status = SENSOR_S_UNKNOWN;
1121 	}
1122 
1123 	if (dev->d_battery.rechargeable)
1124 		dev->d_battery.sens[2].value = charging;
1125 
1126 	return 0;
1127 }
1128 
1129 int
1130 hidpp20_battery_get_capability(struct uhidpp_softc *sc,
1131     struct uhidpp_device *dev)
1132 {
1133 	struct uhidpp_report resp;
1134 	int error;
1135 
1136 	error = hidpp_send_fap_report(sc,
1137 	    HIDPP_REPORT_ID_LONG,
1138 	    dev->d_id,
1139 	    dev->d_battery.feature_idx,
1140 	    HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC,
1141 	    NULL, 0, &resp);
1142 	if (error)
1143 		return error;
1144 	dev->d_battery.nlevels = resp.fap.params[0];
1145 	dev->d_battery.rechargeable = resp.fap.params[1] &
1146 	    HIDPP20_CAPABILITY_RECHARGEABLE;
1147 	return 0;
1148 }
1149 
1150 int
1151 hidpp20_unified_battery_get_capabilities(struct uhidpp_softc *sc,
1152     struct uhidpp_device *dev)
1153 {
1154 	struct uhidpp_report resp;
1155 	int error;
1156 
1157 	error = hidpp_send_fap_report(sc,
1158 	    HIDPP_REPORT_ID_LONG,
1159 	    dev->d_id,
1160 	    dev->d_battery.feature_idx,
1161 	    HIDPP20_FEAT_UNIFIED_BATTERY_CAPABILITIES_FUNC,
1162 	    NULL, 0, &resp);
1163 	if (error)
1164 		return error;
1165 	dev->d_battery.nlevels = nlevels(resp.fap.params[0]);
1166 	dev->d_battery.unified_level_mask = resp.fap.params[0];
1167 	dev->d_battery.rechargeable = resp.fap.params[1] &
1168 	    HIDPP20_CAPABILITES_RECHARGEABLE;
1169 	return 0;
1170 }
1171 
1172 int
1173 hidpp20_unified_battery_get_status(struct uhidpp_softc *sc,
1174     struct uhidpp_device *dev)
1175 {
1176 	struct uhidpp_report resp;
1177 	int charging, error;
1178 	uint8_t level, percentage, status;
1179 
1180 	error = hidpp_send_fap_report(sc,
1181 	    HIDPP_REPORT_ID_LONG,
1182 	    dev->d_id,
1183 	    dev->d_battery.feature_idx,
1184 	    HIDPP20_FEAT_UNIFIED_BATTERY_STATUS_FUNC,
1185 	    NULL, 0, &resp);
1186 	if (error)
1187 		return error;
1188 	percentage = resp.fap.params[0];
1189 	level = resp.fap.params[1] & dev->d_battery.unified_level_mask;
1190 	status = resp.fap.params[2];
1191 	/* external_power_status = resp.fap.params[3]; */
1192 
1193 	charging = hidpp20_unified_battery_status_is_charging(status);
1194 	dev->d_battery.sens[0].value = percentage * 1000;
1195 	dev->d_battery.sens[0].flags &= ~SENSOR_FUNKNOWN;
1196 	dev->d_battery.sens[0].status = SENSOR_S_UNKNOWN;
1197 	/* Do not trust the level while charging. */
1198 	if (!charging) {
1199 		if (level & HIDPP20_BATTERY_STATUS_CRITICAL)
1200 			dev->d_battery.sens[0].status = SENSOR_S_CRIT;
1201 		else if (level & HIDPP20_BATTERY_STATUS_LOW)
1202 			dev->d_battery.sens[0].status = SENSOR_S_WARN;
1203 		else if (level & HIDPP20_BATTERY_STATUS_GOOD)
1204 			dev->d_battery.sens[0].status = SENSOR_S_OK;
1205 		else if (level & HIDPP20_BATTERY_STATUS_FULL)
1206 			dev->d_battery.sens[0].status = SENSOR_S_OK;
1207 	}
1208 	if (dev->d_battery.rechargeable)
1209 		dev->d_battery.sens[2].value = charging;
1210 	return 0;
1211 }
1212 
1213 int
1214 hidpp20_unified_battery_status_is_charging(uint8_t status)
1215 {
1216 	switch (status) {
1217 	case 1: /* charging */
1218 	case 2: /* charging slow */
1219 		return 1;
1220 	default:
1221 		return 0;
1222 	}
1223 }
1224 
1225 int
1226 hidpp20_battery_status_is_charging(uint8_t status)
1227 {
1228 	switch (status) {
1229 	case 1:	/* recharging */
1230 	case 2:	/* charge in final stage */
1231 	case 4:	/* recharging below optimal speed */
1232 		return 1;
1233 
1234 	case 3:	/* charge complete */
1235 		return 1;
1236 
1237 	case 0:	/* discharging */
1238 	case 5:	/* invalid battery type */
1239 	case 6:	/* thermal error */
1240 	case 7:	/* other charging error */
1241 	default:
1242 		return 0;
1243 	}
1244 }
1245 
1246 int
1247 hidpp_send_validate(uint8_t report_id, int nparams)
1248 {
1249 	if (report_id == HIDPP_REPORT_ID_SHORT) {
1250 		if (nparams > HIDPP_REPORT_SHORT_PARAMS_MAX)
1251 			return -EMSGSIZE;
1252 	} else if (report_id == HIDPP_REPORT_ID_LONG) {
1253 		if (nparams > HIDPP_REPORT_LONG_PARAMS_MAX)
1254 			return -EMSGSIZE;
1255 	} else {
1256 		return -EINVAL;
1257 	}
1258 	return 0;
1259 }
1260 
1261 int
1262 hidpp_send_fap_report(struct uhidpp_softc *sc, uint8_t report_id,
1263     uint8_t device_id, uint8_t feature_idx, uint8_t func_idx,
1264     uint8_t *params, int nparams, struct uhidpp_report *resp)
1265 {
1266 	struct uhidpp_report req;
1267 	int error;
1268 
1269 	error = hidpp_send_validate(report_id, nparams);
1270 	if (error)
1271 		return error;
1272 
1273 	memset(&req, 0, sizeof(req));
1274 	req.device_id = device_id;
1275 	req.fap.feature_idx = feature_idx;
1276 	sc->sc_swid = sc->sc_swid == HIDPP_SOFTWARE_ID_MAX ?
1277 	    HIDPP_SOFTWARE_ID_MIN : sc->sc_swid + 1;
1278 	req.fap.funcidx_swid =
1279 	    (func_idx << HIDPP_SOFTWARE_ID_LEN) | sc->sc_swid;
1280 	memcpy(req.fap.params, params, nparams);
1281 	return hidpp_send_report(sc, report_id, &req, resp);
1282 }
1283 
1284 int
1285 hidpp_send_rap_report(struct uhidpp_softc *sc, uint8_t report_id,
1286     uint8_t device_id, uint8_t sub_id, uint8_t reg_address,
1287     uint8_t *params, int nparams, struct uhidpp_report *resp)
1288 {
1289 	struct uhidpp_report req;
1290 	int error;
1291 
1292 	error = hidpp_send_validate(report_id, nparams);
1293 	if (error)
1294 		return error;
1295 
1296 	memset(&req, 0, sizeof(req));
1297 	req.device_id = device_id;
1298 	req.rap.sub_id = sub_id;
1299 	req.rap.reg_address = reg_address;
1300 	memcpy(req.rap.params, params, nparams);
1301 	return hidpp_send_report(sc, report_id, &req, resp);
1302 }
1303 
1304 int
1305 hidpp_send_report(struct uhidpp_softc *sc, uint8_t report_id,
1306     struct uhidpp_report *req, struct uhidpp_report *resp)
1307 {
1308 	int error = 0;
1309 	int len, n;
1310 
1311 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
1312 
1313 	if (report_id == HIDPP_REPORT_ID_SHORT)
1314 		len = HIDPP_REPORT_SHORT_LENGTH;
1315 	else if (report_id == HIDPP_REPORT_ID_LONG)
1316 		len = HIDPP_REPORT_LONG_LENGTH;
1317 	else
1318 		return -EINVAL;
1319 
1320 	DREPORT(__func__, report_id, (const unsigned char *)req, len);
1321 
1322 	/* Wait until any ongoing command has completed. */
1323 	while (sc->sc_resp_state != UHIDPP_RESP_NONE)
1324 		uhidpp_sleep(sc, INFSLP);
1325 	sc->sc_req = req;
1326 	sc->sc_resp = resp;
1327 	sc->sc_resp_state = UHIDPP_RESP_WAIT;
1328 	/*
1329 	 * The mutex must be temporarily released while calling
1330 	 * uhidev_set_report() as it might end up sleeping.
1331 	 */
1332 	mtx_leave(&sc->sc_mtx);
1333 
1334 	n = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
1335 	    report_id, req, len);
1336 
1337 	mtx_enter(&sc->sc_mtx);
1338 	if (len != n) {
1339 		error = -EBUSY;
1340 		goto out;
1341 	}
1342 	/*
1343 	 * The interrupt could already have been received while the mutex was
1344 	 * released. Otherwise, wait for it.
1345 	 */
1346 	if (sc->sc_resp_state == UHIDPP_RESP_WAIT) {
1347 		/* Timeout taken from the hid-logitech-hidpp Linux driver. */
1348 		error = uhidpp_sleep(sc, SEC_TO_NSEC(5));
1349 		if (error) {
1350 			error = -error;
1351 			goto out;
1352 		}
1353 	}
1354 
1355 	if (sc->sc_resp_state == UHIDPP_RESP_ERROR)
1356 		error = -EIO;
1357 	else if (sc->sc_resp_state == HIDPP_REPORT_ID_SHORT &&
1358 	    resp->rap.sub_id == HIDPP_ERROR)
1359 		error = resp->rap.params[1];
1360 	else if (sc->sc_resp_state == HIDPP_REPORT_ID_LONG &&
1361 	    resp->fap.feature_idx == HIDPP20_ERROR)
1362 		error = resp->fap.params[1];
1363 
1364 out:
1365 	sc->sc_req = NULL;
1366 	sc->sc_resp = NULL;
1367 	sc->sc_resp_state = UHIDPP_RESP_NONE;
1368 	wakeup(sc);
1369 	return error;
1370 }
1371 
1372 #ifdef UHIDPP_DEBUG
1373 
1374 void
1375 uhidd_dump_report(const char *prefix, uint8_t repid, const unsigned char *buf,
1376     u_int buflen)
1377 {
1378 	u_int i;
1379 
1380 	printf("%s: %02x ", prefix, repid);
1381 	for (i = 0; i < buflen; i++) {
1382 		printf("%02x%s", buf[i],
1383 		    i == 2 ? " [" : (i + 1 < buflen ? " " : ""));
1384 	}
1385 	printf("]\n");
1386 }
1387 
1388 #endif
1389