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