xref: /openbsd-src/sys/dev/usb/uhidpp.c (revision a119297bd5e44b38d77070a02315a6e337fde1cb)
1 /*	$OpenBSD: uhidpp.c,v 1.7 2021/02/11 11:03:57 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_LINK_STATUS(x)	((x) & (1 << 7))
57 
58 #define HIDPP_REPORT_ID_SHORT			0x10
59 #define HIDPP_REPORT_ID_LONG			0x11
60 
61 /*
62  * Length of reports. Note that the effective length is always +1 as
63  * uhidev_set_report() prepends the report ID.
64  */
65 #define HIDPP_REPORT_SHORT_LENGTH		(7 - 1)
66 #define HIDPP_REPORT_LONG_LENGTH		(20 - 1)
67 
68 /*
69  * Maximum number of allowed parameters for reports. Note, the parameters always
70  * starts at offset 3 for both RAP and FAP reports.
71  */
72 #define HIDPP_REPORT_SHORT_PARAMS_MAX		(HIDPP_REPORT_SHORT_LENGTH - 3)
73 #define HIDPP_REPORT_LONG_PARAMS_MAX		(HIDPP_REPORT_LONG_LENGTH - 3)
74 
75 #define HIDPP_DEVICE_ID_RECEIVER		0xff
76 
77 #define HIDPP_FEAT_ROOT_IDX			0x00
78 #define HIDPP_FEAT_ROOT_PING_FUNC		0x01
79 #define HIDPP_FEAT_ROOT_PING_DATA		0x5a
80 
81 #define HIDPP_SET_REGISTER			0x80
82 #define HIDPP_GET_REGISTER			0x81
83 #define HIDPP_SET_LONG_REGISTER			0x82
84 #define HIDPP_GET_LONG_REGISTER			0x83
85 
86 #define HIDPP_REG_ENABLE_REPORTS		0x00
87 #define HIDPP_REG_PAIRING_INFORMATION		0xb5
88 
89 #define HIDPP_NOTIF_DEVICE_BATTERY_STATUS	(1 << 4)
90 #define HIDPP_NOTIF_RECEIVER_WIRELESS		(1 << 0)
91 #define HIDPP_NOTIF_RECEIVER_SOFTWARE_PRESENT	(1 << 3)
92 
93 /* HID++ 1.0 error codes. */
94 #define HIDPP_ERROR				0x8f
95 #define HIDPP_ERROR_SUCCESS			0x00
96 #define HIDPP_ERROR_INVALID_SUBID		0x01
97 #define HIDPP_ERROR_INVALID_ADRESS		0x02
98 #define HIDPP_ERROR_INVALID_VALUE		0x03
99 #define HIDPP_ERROR_CONNECT_FAIL		0x04
100 #define HIDPP_ERROR_TOO_MANY_DEVICES		0x05
101 #define HIDPP_ERROR_ALREADY_EXISTS		0x06
102 #define HIDPP_ERROR_BUSY			0x07
103 #define HIDPP_ERROR_UNKNOWN_DEVICE		0x08
104 #define HIDPP_ERROR_RESOURCE_ERROR		0x09
105 #define HIDPP_ERROR_REQUEST_UNAVAILABLE		0x0a
106 #define HIDPP_ERROR_INVALID_PARAM_VALUE		0x0b
107 #define HIDPP_ERROR_WRONG_PIN_CODE		0x0c
108 
109 /*
110  * The software ID is added to feature access reports (FAP) and used to
111  * distinguish responses from notifications. Note, the software ID must be
112  * greater than zero which is reserved for notifications.
113  */
114 #define HIDPP_SOFTWARE_ID			0x01
115 #define HIDPP_SOFTWARE_ID_LEN			4
116 
117 #define HIDPP20_FEAT_ROOT_IDX			0x00
118 #define HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC	0x00
119 
120 #define HIDPP20_FEAT_BATTERY_IDX		0x1000
121 #define HIDPP20_FEAT_BATTERY_LEVEL_FUNC		0x0000
122 #define HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC	0x0001
123 
124 /* HID++ 2.0 error codes. */
125 #define HIDPP20_ERROR				0xff
126 #define HIDPP20_ERROR_NO_ERROR			0x00
127 #define HIDPP20_ERROR_UNKNOWN			0x01
128 #define HIDPP20_ERROR_INVALID_ARGUMENT		0x02
129 #define HIDPP20_ERROR_OUT_OF_RANGE		0x03
130 #define HIDPP20_ERROR_HARDWARE_ERROR		0x04
131 #define HIDPP20_ERROR_LOGITECH_INTERNAL		0x05
132 #define HIDPP20_ERROR_INVALID_FEATURE_INDEX	0x06
133 #define HIDPP20_ERROR_INVALID_FUNCTION_ID	0x07
134 #define HIDPP20_ERROR_BUSY			0x08
135 #define HIDPP20_ERROR_UNSUPPORTED		0x09
136 
137 /*
138  * Sentinels used for interrupt response synchronization. The values must be
139  * disjoint from existing report IDs.
140  */
141 #define UHIDPP_RESP_NONE			0
142 #define UHIDPP_RESP_WAIT			1
143 #define UHIDPP_RESP_ERROR			2
144 
145 /* Maximum number of devices associated with a single receiver. */
146 #define UHIDPP_NDEVICES				6
147 
148 /* Maximum number of pending notifications. */
149 #define UHIDPP_NNOTIFICATIONS			4
150 
151 /* Number of sensors per paired device. */
152 #define UHIDPP_NSENSORS				2
153 
154 /* Feature access report used by the HID++ 2.0 (and greater) protocol. */
155 struct fap {
156 	uint8_t feature_idx;
157 	uint8_t funcidx_swid;
158 	uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX];
159 };
160 
161 /*
162  * Register access report used by the HID++ 1.0 protocol. Receivers always uses
163  * this type of report.
164  */
165 struct rap {
166 	uint8_t sub_id;
167 	uint8_t reg_address;
168 	uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX];
169 };
170 
171 struct uhidpp_report {
172 	uint8_t device_id;
173 	union {
174 		struct fap fap;
175 		struct rap rap;
176 	};
177 } __packed;
178 
179 struct uhidpp_notification {
180 	struct uhidpp_report n_rep;
181 	unsigned int n_id;
182 };
183 
184 struct uhidpp_device {
185 	uint8_t d_id;
186 	uint8_t d_connected;
187 	uint8_t d_major;
188 	uint8_t d_minor;
189 	struct {
190 		struct ksensor b_sens[UHIDPP_NSENSORS];
191 		uint8_t b_feature_idx;
192 		uint8_t b_level;
193 		uint8_t b_next_level;
194 		uint8_t b_status;
195 		uint8_t b_nlevels;
196 	} d_battery;
197 };
198 
199 /*
200  * Locking:
201  *	[m]	sc_mtx
202  */
203 struct uhidpp_softc {
204 	struct uhidev sc_hdev;
205 	struct usbd_device *sc_udev;
206 
207 	struct mutex sc_mtx;
208 
209 	struct uhidpp_device sc_devices[UHIDPP_NDEVICES];
210 					/* [m] connected devices */
211 
212 	struct uhidpp_notification sc_notifications[UHIDPP_NNOTIFICATIONS];
213 					/* [m] pending notifications */
214 
215 	struct usb_task sc_task;	/* [m] notification task */
216 
217 	struct ksensordev sc_sensdev;	/* [m] */
218 	struct sensor_task *sc_senstsk;	/* [m] */
219 
220 	struct uhidpp_report *sc_req;	/* [m] synchronous request buffer */
221 	struct uhidpp_report *sc_resp;	/* [m] synchronous response buffer */
222 	u_int sc_resp_state;		/* [m] synchronous response state */
223 
224 };
225 
226 int uhidpp_match(struct device *, void *, void *);
227 void uhidpp_attach(struct device *, struct device *, void *);
228 int uhidpp_detach(struct device *, int flags);
229 void uhidpp_intr(struct uhidev *addr, void *ibuf, u_int len);
230 void uhidpp_refresh(void *);
231 void uhidpp_task(void *);
232 int uhidpp_sleep(struct uhidpp_softc *, uint64_t);
233 
234 void uhidpp_device_connect(struct uhidpp_softc *, struct uhidpp_device *);
235 void uhidpp_device_refresh(struct uhidpp_softc *, struct uhidpp_device *);
236 
237 struct uhidpp_notification *uhidpp_claim_notification(struct uhidpp_softc *);
238 int uhidpp_consume_notification(struct uhidpp_softc *, struct uhidpp_report *);
239 int uhidpp_is_notification(struct uhidpp_softc *, struct uhidpp_report *);
240 
241 int hidpp_get_protocol_version(struct uhidpp_softc  *, uint8_t, uint8_t *,
242     uint8_t *);
243 
244 int hidpp10_get_name(struct uhidpp_softc *, uint8_t, char *, size_t);
245 int hidpp10_get_serial(struct uhidpp_softc *, uint8_t, uint8_t *, size_t);
246 int hidpp10_get_type(struct uhidpp_softc *, uint8_t, const char **);
247 int hidpp10_enable_notifications(struct uhidpp_softc *, uint8_t);
248 
249 int hidpp20_root_get_feature(struct uhidpp_softc *, uint8_t, uint16_t,
250     uint8_t *, uint8_t *);
251 int hidpp20_battery_get_level_status(struct uhidpp_softc *, uint8_t, uint8_t,
252     uint8_t *, uint8_t *, uint8_t *);
253 int hidpp20_battery_get_capability(struct uhidpp_softc *, uint8_t, uint8_t,
254     uint8_t *);
255 
256 int hidpp_send_validate(uint8_t, int);
257 int hidpp_send_rap_report(struct uhidpp_softc *, uint8_t, uint8_t,
258     uint8_t, uint8_t, uint8_t *, int, struct uhidpp_report *);
259 int hidpp_send_fap_report(struct uhidpp_softc *, uint8_t, uint8_t, uint8_t,
260     uint8_t, uint8_t *, int, struct uhidpp_report *);
261 int hidpp_send_report(struct uhidpp_softc *, uint8_t, struct uhidpp_report *,
262     struct uhidpp_report *);
263 
264 struct cfdriver uhidpp_cd = {
265 	NULL, "uhidpp", DV_DULL
266 };
267 
268 const struct cfattach uhidpp_ca = {
269 	sizeof(struct uhidpp_softc),
270 	uhidpp_match,
271 	uhidpp_attach,
272 	uhidpp_detach,
273 };
274 
275 static const struct usb_devno uhidpp_devs[] = {
276 	{ USB_VENDOR_LOGITECH,	USB_PRODUCT_ANY },
277 };
278 
279 int
280 uhidpp_match(struct device *parent, void *match, void *aux)
281 {
282 	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
283 	void *desc;
284 	int descsiz, siz;
285 
286 	if (uha->reportid != HIDPP_REPORT_ID_SHORT &&
287 	    uha->reportid != HIDPP_REPORT_ID_LONG)
288 		return UMATCH_NONE;
289 
290 	if (usb_lookup(uhidpp_devs,
291 		    uha->uaa->vendor, uha->uaa->product) == NULL)
292 		return UMATCH_NONE;
293 
294 	uhidev_get_report_desc(uha->parent, &desc, &descsiz);
295 	siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_SHORT);
296 	if (siz != HIDPP_REPORT_SHORT_LENGTH)
297 		return UMATCH_NONE;
298 	siz = hid_report_size(desc, descsiz, hid_output, HIDPP_REPORT_ID_LONG);
299 	if (siz != HIDPP_REPORT_LONG_LENGTH)
300 		return UMATCH_NONE;
301 
302 	return UMATCH_VENDOR_PRODUCT;
303 }
304 
305 void
306 uhidpp_attach(struct device *parent, struct device *self, void *aux)
307 {
308 	struct uhidpp_softc *sc = (struct uhidpp_softc *)self;
309 	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
310 	struct usb_attach_arg *uaa = uha->uaa;
311 	int error, i;
312 	int npaired = 0;
313 
314 	sc->sc_hdev.sc_intr = uhidpp_intr;
315 	sc->sc_hdev.sc_udev = uaa->device;
316 	sc->sc_hdev.sc_parent = uha->parent;
317 	sc->sc_hdev.sc_report_id = uha->reportid;
318 	/* The largest supported report dictates the sizes. */
319 	sc->sc_hdev.sc_isize = HIDPP_REPORT_LONG_LENGTH;
320 	sc->sc_hdev.sc_osize = HIDPP_REPORT_LONG_LENGTH;
321 
322 	sc->sc_udev = uaa->device;
323 
324 	mtx_init(&sc->sc_mtx, IPL_USB);
325 
326 	sc->sc_resp = NULL;
327 	sc->sc_resp_state = UHIDPP_RESP_NONE;
328 
329 	error = uhidev_open(&sc->sc_hdev);
330 	if (error) {
331 		printf(" open error %d\n", error);
332 		return;
333 	}
334 
335 	usb_init_task(&sc->sc_task, uhidpp_task, sc, USB_TASK_TYPE_GENERIC);
336 
337 	mtx_enter(&sc->sc_mtx);
338 
339 	/*
340 	 * Wire up report device handlers before issuing commands to the device
341 	 * in order to receive responses. Necessary as uhidev by default
342 	 * performs the wiring after the attach routine has returned.
343 	 */
344 	error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev,
345 	    HIDPP_REPORT_ID_SHORT);
346 	if (error) {
347 		printf(" short report error %d\n", error);
348 		return;
349 	}
350 	error = uhidev_set_report_dev(sc->sc_hdev.sc_parent, &sc->sc_hdev,
351 	    HIDPP_REPORT_ID_LONG);
352 	if (error) {
353 		printf(" long report error %d\n", error);
354 		return;
355 	}
356 
357 	/* Probe paired devices. */
358 	for (i = 0; i < UHIDPP_NDEVICES; i++) {
359 		char name[16];
360 		uint8_t serial[4];
361 		struct uhidpp_device *dev = &sc->sc_devices[i];
362 		const char *type;
363 		uint8_t device_id = i + 1;
364 
365 		dev->d_id = device_id;
366 
367 		if (hidpp10_get_serial(sc, device_id, serial, sizeof(serial)) ||
368 		    hidpp10_get_type(sc, device_id, &type) ||
369 		    hidpp10_get_name(sc, device_id, name, sizeof(name)))
370 			continue;
371 
372 		if (npaired > 0)
373 			printf(",");
374 		printf(" device %d", device_id);
375 		printf(" %s", type);
376 		printf(" \"%s\"", name);
377 		printf(" serial %02x-%02x-%02x-%02x",
378 		    serial[0], serial[1], serial[2], serial[3]);
379 		npaired++;
380 	}
381 
382 	/* Enable notifications for the receiver. */
383 	error = hidpp10_enable_notifications(sc, HIDPP_DEVICE_ID_RECEIVER);
384 	if (error)
385 		printf(" error %d", error);
386 
387 	printf("\n");
388 
389 	strlcpy(sc->sc_sensdev.xname, sc->sc_hdev.sc_dev.dv_xname,
390 	    sizeof(sc->sc_sensdev.xname));
391 	sensordev_install(&sc->sc_sensdev);
392 	sc->sc_senstsk = sensor_task_register(sc, uhidpp_refresh, 6);
393 
394 	mtx_leave(&sc->sc_mtx);
395 }
396 
397 int
398 uhidpp_detach(struct device *self, int flags)
399 {
400 	struct uhidpp_softc *sc = (struct uhidpp_softc *)self;
401 	int i, j;
402 
403 	usb_rem_wait_task(sc->sc_udev, &sc->sc_task);
404 
405 	if (sc->sc_senstsk != NULL)
406 		sensor_task_unregister(sc->sc_senstsk);
407 
408 	KASSERT(sc->sc_resp_state == UHIDPP_RESP_NONE);
409 
410 	sensordev_deinstall(&sc->sc_sensdev);
411 
412 	for (i = 0; i < UHIDPP_NDEVICES; i++) {
413 		struct uhidpp_device *dev = &sc->sc_devices[i];
414 
415 		if (!dev->d_connected)
416 			continue;
417 
418 		for (j = 0; j < UHIDPP_NSENSORS; j++)
419 			sensor_detach(&sc->sc_sensdev, &dev->d_battery.b_sens[j]);
420 	}
421 
422 	/*
423 	 * Since this driver has multiple device handlers attached, remove all
424 	 * of them preventing the uhidev parent from calling this detach routine
425 	 * more than once.
426 	 */
427 	uhidev_unset_report_dev(sc->sc_hdev.sc_parent, HIDPP_REPORT_ID_SHORT);
428 	uhidev_unset_report_dev(sc->sc_hdev.sc_parent, HIDPP_REPORT_ID_LONG);
429 
430 	uhidev_close(&sc->sc_hdev);
431 
432 	return 0;
433 }
434 
435 void
436 uhidpp_intr(struct uhidev *addr, void *buf, u_int len)
437 {
438 	struct uhidpp_softc *sc = (struct uhidpp_softc *)addr;
439 	struct uhidpp_report *rep = buf;
440 	int dowake = 0;
441 	uint8_t repid;
442 
443 	/*
444 	 * Ugliness ahead as the report ID is stripped of by uhidev_intr() but
445 	 * needed to determine if an error occurred.
446 	 * Note that an error response is always a short report even if the
447 	 * command that caused the error is a long report.
448 	 */
449 	repid = ((uint8_t *)buf)[-1];
450 
451 	DREPORT(__func__, repid, buf, len);
452 
453 	mtx_enter(&sc->sc_mtx);
454 	if (uhidpp_is_notification(sc, rep)) {
455 		struct uhidpp_notification *ntf;
456 
457 		ntf = uhidpp_claim_notification(sc);
458 		if (ntf != NULL) {
459 			memcpy(&ntf->n_rep, buf, len);
460 			usb_add_task(sc->sc_udev, &sc->sc_task);
461 		} else {
462 			DPRINTF("%s: too many notifications", __func__);
463 		}
464 	} else {
465 		KASSERT(sc->sc_resp_state == UHIDPP_RESP_WAIT);
466 		dowake = 1;
467 		sc->sc_resp_state = repid;
468 		memcpy(sc->sc_resp, buf, len);
469 	}
470 	mtx_leave(&sc->sc_mtx);
471 	if (dowake)
472 		wakeup(sc);
473 }
474 
475 void
476 uhidpp_refresh(void *arg)
477 {
478 	struct uhidpp_softc *sc = arg;
479 	int i;
480 
481 	mtx_enter(&sc->sc_mtx);
482 	for (i = 0; i < UHIDPP_NDEVICES; i++) {
483 		struct uhidpp_device *dev = &sc->sc_devices[i];
484 
485 		if (dev->d_connected)
486 			uhidpp_device_refresh(sc, dev);
487 	}
488 	mtx_leave(&sc->sc_mtx);
489 }
490 
491 void
492 uhidpp_task(void *arg)
493 {
494 	struct uhidpp_softc *sc = arg;
495 
496 	mtx_enter(&sc->sc_mtx);
497 	for (;;) {
498 		struct uhidpp_report rep;
499 		struct uhidpp_device *dev;
500 
501 		if (uhidpp_consume_notification(sc, &rep))
502 			break;
503 
504 		DPRINTF("%s: device_id=%d, sub_id=%02x\n",
505 		    __func__, rep.device_id, rep.rap.sub_id);
506 
507 		if (rep.device_id == 0 || rep.device_id > UHIDPP_NDEVICES) {
508 			DPRINTF("%s: invalid device\n", __func__);
509 			continue;
510 		}
511 		dev = &sc->sc_devices[rep.device_id - 1];
512 
513 		switch (rep.rap.sub_id) {
514 		case 0x0e:	/* leds */
515 		case 0x40:	/* disconnect */
516 		case 0x4b:	/* pairing accepted */
517 			break;
518 		case 0x41:	/* connect */
519 			/*
520 			 * Do nothing if the link is reported to be out of
521 			 * range. This happens when a device has been idle for a
522 			 * while.
523 			 */
524 			if (HIDPP_LINK_STATUS(rep.rap.params[0]))
525 				uhidpp_device_connect(sc, dev);
526 			break;
527 		}
528 	}
529 	mtx_leave(&sc->sc_mtx);
530 }
531 
532 int
533 uhidpp_sleep(struct uhidpp_softc *sc, uint64_t nsecs)
534 {
535 	return msleep_nsec(sc, &sc->sc_mtx, PZERO, "uhidpp", nsecs);
536 }
537 
538 void
539 uhidpp_device_connect(struct uhidpp_softc *sc, struct uhidpp_device *dev)
540 {
541 	struct ksensor *sens;
542 	int error;
543 	uint8_t feature_type;
544 
545 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
546 
547 	/* A connected device will continously send connect events. */
548 	if (dev->d_connected)
549 		return;
550 
551 	error = hidpp_get_protocol_version(sc, dev->d_id,
552 	    &dev->d_major, &dev->d_minor);
553 	if (error) {
554 		DPRINTF("%s: protocol version failure: device_id=%d, "
555 		    "error=%d\n",
556 		    __func__, dev->d_id, error);
557 		return;
558 	}
559 
560 	DPRINTF("%s: device_id=%d, version=%d.%d\n",
561 	    __func__, dev->d_id, dev->d_major, dev->d_minor);
562 
563 	if (dev->d_major >= 2) {
564 		error = hidpp20_root_get_feature(sc, dev->d_id,
565 		    HIDPP20_FEAT_BATTERY_IDX,
566 		    &dev->d_battery.b_feature_idx, &feature_type);
567 		if (error) {
568 			DPRINTF("%s: battery feature index failure: "
569 			    "device_id=%d, error=%d\n",
570 			    __func__, dev->d_id, error);
571 			return;
572 		}
573 
574 		error = hidpp20_battery_get_capability(sc, dev->d_id,
575 		    dev->d_battery.b_feature_idx, &dev->d_battery.b_nlevels);
576 		if (error) {
577 			DPRINTF("%s: battery capability failure: device_id=%d, "
578 			    "error=%d\n", __func__, dev->d_id, error);
579 			return;
580 		}
581 
582 	} else {
583 		return;
584 	}
585 
586 	sens = &dev->d_battery.b_sens[0];
587 	strlcpy(sens->desc, "battery level", sizeof(sens->desc));
588 	sens->type = SENSOR_PERCENT;
589 	sens->flags = SENSOR_FUNKNOWN;
590 	sensor_attach(&sc->sc_sensdev, sens);
591 
592 	sens = &dev->d_battery.b_sens[1];
593 	strlcpy(sens->desc, "battery levels", sizeof(sens->desc));
594 	sens->type = SENSOR_INTEGER;
595 	sens->value = dev->d_battery.b_nlevels;
596 	sensor_attach(&sc->sc_sensdev, sens);
597 
598 	dev->d_connected = 1;
599 	uhidpp_device_refresh(sc, dev);
600 }
601 
602 void
603 uhidpp_device_refresh(struct uhidpp_softc *sc, struct uhidpp_device *dev)
604 {
605 	int error;
606 
607 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
608 
609 	if (dev->d_major >= 2) {
610 		error = hidpp20_battery_get_level_status(sc, dev->d_id,
611 		    dev->d_battery.b_feature_idx,
612 		    &dev->d_battery.b_level, &dev->d_battery.b_next_level,
613 		    &dev->d_battery.b_status);
614 		if (error) {
615 			DPRINTF("%s: battery status failure: device_id=%d, "
616 			    "error=%d\n",
617 			    __func__, dev->d_id, error);
618 			return;
619 		}
620 
621 		dev->d_battery.b_sens[0].value = dev->d_battery.b_level * 1000;
622 		dev->d_battery.b_sens[0].flags &= ~SENSOR_FUNKNOWN;
623 		if (dev->d_battery.b_nlevels < 10) {
624 			/*
625 			 * According to the HID++ 2.0 specification, less than
626 			 * 10 levels should be mapped to the following 4 levels:
627 			 *
628 			 * [0, 10]   critical
629 			 * [11, 30]  low
630 			 * [31, 80]  good
631 			 * [81, 100] full
632 			 *
633 			 * Since sensors are limited to 3 valid statuses, clamp
634 			 * it even further.
635 			 */
636 			if (dev->d_battery.b_level <= 10)
637 				dev->d_battery.b_sens[0].status = SENSOR_S_CRIT;
638 			else if (dev->d_battery.b_level <= 30)
639 				dev->d_battery.b_sens[0].status = SENSOR_S_WARN;
640 			else
641 				dev->d_battery.b_sens[0].status = SENSOR_S_OK;
642 		} else {
643 			/*
644 			 * XXX the device supports battery mileage. The current
645 			 * level must be checked against resp.fap.params[3]
646 			 * given by hidpp20_battery_get_capability().
647 			 */
648 			dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN;
649 		}
650 	}
651 }
652 
653 /*
654  * Returns the next available notification slot, if available.
655  */
656 struct uhidpp_notification *
657 uhidpp_claim_notification(struct uhidpp_softc *sc)
658 {
659 	struct uhidpp_notification *ntf = NULL;
660 	int nclaimed = 0;
661 	int i;
662 
663 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
664 
665 	for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) {
666 		struct uhidpp_notification *tmp = &sc->sc_notifications[i];
667 
668 		if (tmp->n_id > 0)
669 			nclaimed++;
670 		else if (ntf == NULL)
671 			ntf = tmp;
672 	}
673 
674 	if (ntf == NULL)
675 		return NULL;
676 	ntf->n_id = nclaimed + 1;
677 	return ntf;
678 }
679 
680 /*
681  * Consume the first unhandled notification, if present.
682  */
683 int
684 uhidpp_consume_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep)
685 {
686 	struct uhidpp_notification *ntf = NULL;
687 	int i;
688 
689 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
690 
691 	for (i = 0; i < UHIDPP_NNOTIFICATIONS; i++) {
692 		struct uhidpp_notification *tmp = &sc->sc_notifications[i];
693 
694 		if (tmp->n_id > 0 && (ntf == NULL || tmp->n_id < ntf->n_id))
695 			ntf = tmp;
696 	}
697 	if (ntf == NULL)
698 		return 1;
699 
700 	memcpy(rep, &ntf->n_rep, sizeof(*rep));
701 	ntf->n_id = 0;
702 	return 0;
703 }
704 
705 
706 /*
707  * Returns non-zero if the given report is a notification. Otherwise, it must be
708  * a response.
709  */
710 int
711 uhidpp_is_notification(struct uhidpp_softc *sc, struct uhidpp_report *rep)
712 {
713 	/* Not waiting for a response. */
714 	if (sc->sc_req == NULL)
715 		return 1;
716 
717 	/* Everything except the parameters must be repeated in a response. */
718 	if (sc->sc_req->device_id == rep->device_id &&
719 	    sc->sc_req->rap.sub_id == rep->rap.sub_id &&
720 	    sc->sc_req->rap.reg_address == rep->rap.reg_address)
721 		return 0;
722 
723 	/* An error must always be a response. */
724 	if ((rep->rap.sub_id == HIDPP_ERROR ||
725 		    rep->fap.feature_idx == HIDPP20_ERROR) &&
726 	    rep->fap.funcidx_swid == sc->sc_req->fap.feature_idx &&
727 	    rep->fap.params[0] == sc->sc_req->fap.funcidx_swid)
728 		return 0;
729 
730 	return 1;
731 }
732 
733 int
734 hidpp_get_protocol_version(struct uhidpp_softc  *sc, uint8_t device_id,
735     uint8_t *major, uint8_t *minor)
736 {
737 	struct uhidpp_report resp;
738 	uint8_t params[3] = { 0, 0, HIDPP_FEAT_ROOT_PING_DATA };
739 	int error;
740 
741 	error = hidpp_send_fap_report(sc,
742 	    HIDPP_REPORT_ID_SHORT,
743 	    device_id,
744 	    HIDPP_FEAT_ROOT_IDX,
745 	    HIDPP_FEAT_ROOT_PING_FUNC,
746 	    params, sizeof(params), &resp);
747 	if (error == HIDPP_ERROR_INVALID_SUBID) {
748 		*major = 1;
749 		*minor = 0;
750 		return 0;
751 	}
752 	if (error)
753 		return error;
754 	if (resp.rap.params[2] != HIDPP_FEAT_ROOT_PING_DATA)
755 		return -EPROTO;
756 
757 	*major = resp.fap.params[0];
758 	*minor = resp.fap.params[1];
759 	return 0;
760 }
761 
762 int
763 hidpp10_get_name(struct uhidpp_softc *sc, uint8_t device_id,
764     char *buf, size_t bufsiz)
765 {
766 	struct uhidpp_report resp;
767 	int error;
768 	uint8_t params[1] = { 0x40 + (device_id - 1) };
769 	uint8_t len;
770 
771 	error = hidpp_send_rap_report(sc,
772 	    HIDPP_REPORT_ID_SHORT,
773 	    HIDPP_DEVICE_ID_RECEIVER,
774 	    HIDPP_GET_LONG_REGISTER,
775 	    HIDPP_REG_PAIRING_INFORMATION,
776 	    params, sizeof(params), &resp);
777 	if (error)
778 		return error;
779 
780 	len = resp.rap.params[1];
781 	if (len + 2 > sizeof(resp.rap.params))
782 		return -ENAMETOOLONG;
783 	if (len > bufsiz - 1)
784 		len = bufsiz - 1;
785 	memcpy(buf, &resp.rap.params[2], len);
786 	buf[len] = '\0';
787 	return 0;
788 }
789 
790 int
791 hidpp10_get_serial(struct uhidpp_softc *sc, uint8_t device_id,
792     uint8_t *buf, size_t bufsiz)
793 {
794 	struct uhidpp_report resp;
795 	int error;
796 	uint8_t params[1] = { 0x30 + (device_id - 1) };
797 	uint8_t len;
798 
799 	error = hidpp_send_rap_report(sc,
800 	    HIDPP_REPORT_ID_SHORT,
801 	    HIDPP_DEVICE_ID_RECEIVER,
802 	    HIDPP_GET_LONG_REGISTER,
803 	    HIDPP_REG_PAIRING_INFORMATION,
804 	    params, sizeof(params), &resp);
805 	if (error)
806 		return error;
807 
808 	len = 4;
809 	if (bufsiz < len)
810 		len = bufsiz;
811 	memcpy(buf, &resp.rap.params[1], len);
812 	return 0;
813 }
814 
815 int
816 hidpp10_get_type(struct uhidpp_softc *sc, uint8_t device_id, const char **type)
817 {
818 	struct uhidpp_report resp;
819 	int error;
820 	uint8_t params[1] = { 0x20 + (device_id - 1) };
821 
822 	error = hidpp_send_rap_report(sc,
823 	    HIDPP_REPORT_ID_SHORT,
824 	    HIDPP_DEVICE_ID_RECEIVER,
825 	    HIDPP_GET_LONG_REGISTER,
826 	    HIDPP_REG_PAIRING_INFORMATION,
827 	    params, sizeof(params), &resp);
828 	if (error)
829 		return error;
830 
831 	switch (resp.rap.params[7]) {
832 	case 0x00:
833 		*type = "unknown";
834 		return 0;
835 	case 0x01:
836 		*type = "keyboard";
837 		return 0;
838 	case 0x02:
839 		*type = "mouse";
840 		return 0;
841 	case 0x03:
842 		*type = "numpad";
843 		return 0;
844 	case 0x04:
845 		*type = "presenter";
846 		return 0;
847 	case 0x08:
848 		*type = "trackball";
849 		return 0;
850 	case 0x09:
851 		*type = "touchpad";
852 		return 0;
853 	}
854 	return -ENOENT;
855 }
856 
857 int
858 hidpp10_enable_notifications(struct uhidpp_softc *sc, uint8_t device_id)
859 {
860 	struct uhidpp_report resp;
861 	uint8_t params[3];
862 
863 	/* Device reporting flags. */
864 	params[0] = HIDPP_NOTIF_DEVICE_BATTERY_STATUS;
865 	/* Receiver reporting flags. */
866 	params[1] = HIDPP_NOTIF_RECEIVER_WIRELESS |
867 	    HIDPP_NOTIF_RECEIVER_SOFTWARE_PRESENT;
868 	/* Device reporting flags (continued). */
869 	params[2] = 0;
870 
871 	return hidpp_send_rap_report(sc,
872 	    HIDPP_REPORT_ID_SHORT,
873 	    device_id,
874 	    HIDPP_SET_REGISTER,
875 	    HIDPP_REG_ENABLE_REPORTS,
876 	    params, sizeof(params), &resp);
877 }
878 
879 int
880 hidpp20_root_get_feature(struct uhidpp_softc *sc, uint8_t device_id,
881     uint16_t feature, uint8_t *feature_idx, uint8_t *feature_type)
882 {
883 	struct uhidpp_report resp;
884 	uint8_t params[2] = { feature >> 8, feature & 0xff };
885 	int error;
886 
887 	error = hidpp_send_fap_report(sc,
888 	    HIDPP_REPORT_ID_LONG,
889 	    device_id,
890 	    HIDPP20_FEAT_ROOT_IDX,
891 	    HIDPP20_FEAT_ROOT_GET_FEATURE_FUNC,
892 	    params, sizeof(params), &resp);
893 	if (error)
894 		return error;
895 
896 	if (resp.fap.params[0] == 0)
897 		return -ENOENT;
898 
899 	*feature_idx = resp.fap.params[0];
900 	*feature_type = resp.fap.params[1];
901 	return 0;
902 }
903 
904 int
905 hidpp20_battery_get_level_status(struct uhidpp_softc *sc, uint8_t device_id,
906     uint8_t feature_idx, uint8_t *level, uint8_t *next_level, uint8_t *status)
907 {
908 	struct uhidpp_report resp;
909 	int error;
910 
911 	error = hidpp_send_fap_report(sc,
912 	    HIDPP_REPORT_ID_LONG,
913 	    device_id,
914 	    feature_idx,
915 	    HIDPP20_FEAT_BATTERY_LEVEL_FUNC,
916 	    NULL, 0, &resp);
917 	if (error)
918 		return error;
919 
920 	*level = resp.fap.params[0];
921 	*next_level = resp.fap.params[1];
922 	*status = resp.fap.params[2];
923 	return 0;
924 }
925 
926 int
927 hidpp20_battery_get_capability(struct uhidpp_softc *sc, uint8_t device_id,
928     uint8_t feature_idx, uint8_t *nlevels)
929 {
930 	struct uhidpp_report resp;
931 	int error;
932 
933 	error = hidpp_send_fap_report(sc,
934 	    HIDPP_REPORT_ID_LONG,
935 	    device_id,
936 	    feature_idx,
937 	    HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC,
938 	    NULL, 0, &resp);
939 	if (error)
940 		return error;
941 	*nlevels = resp.fap.params[0];
942 	return 0;
943 }
944 
945 int
946 hidpp_send_validate(uint8_t report_id, int nparams)
947 {
948 	if (report_id == HIDPP_REPORT_ID_SHORT) {
949 		if (nparams > HIDPP_REPORT_SHORT_PARAMS_MAX)
950 			return -EMSGSIZE;
951 	} else if (report_id == HIDPP_REPORT_ID_LONG) {
952 		if (nparams > HIDPP_REPORT_LONG_PARAMS_MAX)
953 			return -EMSGSIZE;
954 	} else {
955 		return -EINVAL;
956 	}
957 	return 0;
958 }
959 
960 int
961 hidpp_send_fap_report(struct uhidpp_softc *sc, uint8_t report_id,
962     uint8_t device_id, uint8_t feature_idx, uint8_t funcidx_swid,
963     uint8_t *params, int nparams, struct uhidpp_report *resp)
964 {
965 	struct uhidpp_report req;
966 	int error;
967 
968 	error = hidpp_send_validate(report_id, nparams);
969 	if (error)
970 		return error;
971 
972 	memset(&req, 0, sizeof(req));
973 	req.device_id = device_id;
974 	req.fap.feature_idx = feature_idx;
975 	req.fap.funcidx_swid =
976 	    (funcidx_swid << HIDPP_SOFTWARE_ID_LEN) | HIDPP_SOFTWARE_ID;
977 	memcpy(req.fap.params, params, nparams);
978 	return hidpp_send_report(sc, report_id, &req, resp);
979 }
980 
981 int
982 hidpp_send_rap_report(struct uhidpp_softc *sc, uint8_t report_id,
983     uint8_t device_id, uint8_t sub_id, uint8_t reg_address,
984     uint8_t *params, int nparams, struct uhidpp_report *resp)
985 {
986 	struct uhidpp_report req;
987 	int error;
988 
989 	error = hidpp_send_validate(report_id, nparams);
990 	if (error)
991 		return error;
992 
993 	memset(&req, 0, sizeof(req));
994 	req.device_id = device_id;
995 	req.rap.sub_id = sub_id;
996 	req.rap.reg_address = reg_address;
997 	memcpy(req.rap.params, params, nparams);
998 	return hidpp_send_report(sc, report_id, &req, resp);
999 }
1000 
1001 int
1002 hidpp_send_report(struct uhidpp_softc *sc, uint8_t report_id,
1003     struct uhidpp_report *req, struct uhidpp_report *resp)
1004 {
1005 	int error, len, n;
1006 
1007 	MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
1008 
1009 	if (report_id == HIDPP_REPORT_ID_SHORT)
1010 		len = HIDPP_REPORT_SHORT_LENGTH;
1011 	else if (report_id == HIDPP_REPORT_ID_LONG)
1012 		len = HIDPP_REPORT_LONG_LENGTH;
1013 	else
1014 		return -EINVAL;
1015 
1016 	DREPORT(__func__, report_id, (const unsigned char *)req, len);
1017 
1018 	/* Wait until any ongoing command has completed. */
1019 	while (sc->sc_resp_state != UHIDPP_RESP_NONE)
1020 		uhidpp_sleep(sc, INFSLP);
1021 	sc->sc_req = req;
1022 	sc->sc_resp = resp;
1023 	sc->sc_resp_state = UHIDPP_RESP_WAIT;
1024 	/*
1025 	 * The mutex must be temporarily released while calling
1026 	 * uhidev_set_report() as it might end up sleeping.
1027 	 */
1028 	mtx_leave(&sc->sc_mtx);
1029 
1030 	n = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
1031 	    report_id, req, len);
1032 
1033 	mtx_enter(&sc->sc_mtx);
1034 	if (len != n) {
1035 		error = -EBUSY;
1036 		goto out;
1037 	}
1038 	/*
1039 	 * The interrupt could already have been received while the mutex was
1040 	 * released. Otherwise, wait for it.
1041 	 */
1042 	if (sc->sc_resp_state == UHIDPP_RESP_WAIT) {
1043 		/* Timeout taken from the hid-logitech-hidpp Linux driver. */
1044 		error = uhidpp_sleep(sc, SEC_TO_NSEC(5));
1045 		if (error) {
1046 			error = -error;
1047 			goto out;
1048 		}
1049 	}
1050 
1051 	if (sc->sc_resp_state == UHIDPP_RESP_ERROR)
1052 		error = -EIO;
1053 	else if (sc->sc_resp_state == HIDPP_REPORT_ID_SHORT &&
1054 	    resp->rap.sub_id == HIDPP_ERROR)
1055 		error = resp->rap.params[1];
1056 	else if (sc->sc_resp_state == HIDPP_REPORT_ID_LONG &&
1057 	    resp->fap.feature_idx == HIDPP20_ERROR)
1058 		error = resp->fap.params[1];
1059 
1060 out:
1061 	sc->sc_req = NULL;
1062 	sc->sc_resp = NULL;
1063 	sc->sc_resp_state = UHIDPP_RESP_NONE;
1064 	wakeup(sc);
1065 	return error;
1066 }
1067 
1068 #ifdef UHIDPP_DEBUG
1069 
1070 void
1071 uhidd_dump_report(const char *prefix, uint8_t repid, const unsigned char *buf,
1072     u_int buflen)
1073 {
1074 	u_int i;
1075 
1076 	printf("%s: %02x ", prefix, repid);
1077 	for (i = 0; i < buflen; i++) {
1078 		printf("%02x%s", buf[i],
1079 		    i == 2 ? " [" : (i + 1 < buflen ? " " : ""));
1080 	}
1081 	printf("]\n");
1082 }
1083 
1084 #endif
1085