xref: /freebsd/sys/dev/hid/hid.c (revision 67de2db2623a10dc4edec1642b2f8685d5587d7f)
1 /* $FreeBSD$ */
2 /*	$NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $	*/
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
5  *
6  * Copyright (c) 1998 The NetBSD Foundation, Inc.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to The NetBSD Foundation
10  * by Lennart Augustsson (lennart@augustsson.net) at
11  * Carlstedt Research & Technology.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #ifdef USB_GLOBAL_INCLUDE_FILE
36 #include USB_GLOBAL_INCLUDE_FILE
37 #else
38 #include <sys/stdint.h>
39 #include <sys/stddef.h>
40 #include <sys/param.h>
41 #include <sys/queue.h>
42 #include <sys/types.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/bus.h>
46 #include <sys/module.h>
47 #include <sys/lock.h>
48 #include <sys/mutex.h>
49 #include <sys/condvar.h>
50 #include <sys/sysctl.h>
51 #include <sys/sx.h>
52 #include <sys/unistd.h>
53 #include <sys/callout.h>
54 #include <sys/malloc.h>
55 #include <sys/priv.h>
56 
57 #include <dev/usb/usb.h>
58 #include <dev/usb/usbdi.h>
59 #include <dev/usb/usbdi_util.h>
60 #include <dev/usb/usbhid.h>
61 
62 #define	USB_DEBUG_VAR usb_debug
63 
64 #include <dev/usb/usb_core.h>
65 #include <dev/usb/usb_debug.h>
66 #include <dev/usb/usb_process.h>
67 #include <dev/usb/usb_device.h>
68 #include <dev/usb/usb_request.h>
69 #endif			/* USB_GLOBAL_INCLUDE_FILE */
70 
71 static void hid_clear_local(struct hid_item *);
72 static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize);
73 
74 #define	MAXUSAGE 64
75 #define	MAXPUSH 4
76 #define	MAXID 16
77 #define	MAXLOCCNT 2048
78 
79 struct hid_pos_data {
80 	int32_t rid;
81 	uint32_t pos;
82 };
83 
84 struct hid_data {
85 	const uint8_t *start;
86 	const uint8_t *end;
87 	const uint8_t *p;
88 	struct hid_item cur[MAXPUSH];
89 	struct hid_pos_data last_pos[MAXID];
90 	int32_t	usages_min[MAXUSAGE];
91 	int32_t	usages_max[MAXUSAGE];
92 	int32_t usage_last;	/* last seen usage */
93 	uint32_t loc_size;	/* last seen size */
94 	uint32_t loc_count;	/* last seen count */
95 	uint32_t ncount;	/* end usage item count */
96 	uint32_t icount;	/* current usage item count */
97 	uint8_t	kindset;	/* we have 5 kinds so 8 bits are enough */
98 	uint8_t	pushlevel;	/* current pushlevel */
99 	uint8_t	nusage;		/* end "usages_min/max" index */
100 	uint8_t	iusage;		/* current "usages_min/max" index */
101 	uint8_t ousage;		/* current "usages_min/max" offset */
102 	uint8_t	susage;		/* usage set flags */
103 };
104 
105 /*------------------------------------------------------------------------*
106  *	hid_clear_local
107  *------------------------------------------------------------------------*/
108 static void
109 hid_clear_local(struct hid_item *c)
110 {
111 
112 	c->loc.count = 0;
113 	c->loc.size = 0;
114 	c->nusages = 0;
115 	memset(c->usages, 0, sizeof(c->usages));
116 	c->usage_minimum = 0;
117 	c->usage_maximum = 0;
118 	c->designator_index = 0;
119 	c->designator_minimum = 0;
120 	c->designator_maximum = 0;
121 	c->string_index = 0;
122 	c->string_minimum = 0;
123 	c->string_maximum = 0;
124 	c->set_delimiter = 0;
125 }
126 
127 static void
128 hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
129 {
130 	uint8_t i;
131 
132 	/* check for same report ID - optimise */
133 
134 	if (c->report_ID == next_rID)
135 		return;
136 
137 	/* save current position for current rID */
138 
139 	if (c->report_ID == 0) {
140 		i = 0;
141 	} else {
142 		for (i = 1; i != MAXID; i++) {
143 			if (s->last_pos[i].rid == c->report_ID)
144 				break;
145 			if (s->last_pos[i].rid == 0)
146 				break;
147 		}
148 	}
149 	if (i != MAXID) {
150 		s->last_pos[i].rid = c->report_ID;
151 		s->last_pos[i].pos = c->loc.pos;
152 	}
153 
154 	/* store next report ID */
155 
156 	c->report_ID = next_rID;
157 
158 	/* lookup last position for next rID */
159 
160 	if (next_rID == 0) {
161 		i = 0;
162 	} else {
163 		for (i = 1; i != MAXID; i++) {
164 			if (s->last_pos[i].rid == next_rID)
165 				break;
166 			if (s->last_pos[i].rid == 0)
167 				break;
168 		}
169 	}
170 	if (i != MAXID) {
171 		s->last_pos[i].rid = next_rID;
172 		c->loc.pos = s->last_pos[i].pos;
173 	} else {
174 		DPRINTF("Out of RID entries, position is set to zero!\n");
175 		c->loc.pos = 0;
176 	}
177 }
178 
179 /*------------------------------------------------------------------------*
180  *	hid_start_parse
181  *------------------------------------------------------------------------*/
182 struct hid_data *
183 hid_start_parse(const void *d, usb_size_t len, int kindset)
184 {
185 	struct hid_data *s;
186 
187 	if ((kindset-1) & kindset) {
188 		DPRINTFN(0, "Only one bit can be "
189 		    "set in the kindset\n");
190 		return (NULL);
191 	}
192 
193 	s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
194 	s->start = s->p = d;
195 	s->end = ((const uint8_t *)d) + len;
196 	s->kindset = kindset;
197 	return (s);
198 }
199 
200 /*------------------------------------------------------------------------*
201  *	hid_end_parse
202  *------------------------------------------------------------------------*/
203 void
204 hid_end_parse(struct hid_data *s)
205 {
206 	if (s == NULL)
207 		return;
208 
209 	free(s, M_TEMP);
210 }
211 
212 /*------------------------------------------------------------------------*
213  *	get byte from HID descriptor
214  *------------------------------------------------------------------------*/
215 static uint8_t
216 hid_get_byte(struct hid_data *s, const uint16_t wSize)
217 {
218 	const uint8_t *ptr;
219 	uint8_t retval;
220 
221 	ptr = s->p;
222 
223 	/* check if end is reached */
224 	if (ptr == s->end)
225 		return (0);
226 
227 	/* read out a byte */
228 	retval = *ptr;
229 
230 	/* check if data pointer can be advanced by "wSize" bytes */
231 	if ((s->end - ptr) < wSize)
232 		ptr = s->end;
233 	else
234 		ptr += wSize;
235 
236 	/* update pointer */
237 	s->p = ptr;
238 
239 	return (retval);
240 }
241 
242 /*------------------------------------------------------------------------*
243  *	hid_get_item
244  *------------------------------------------------------------------------*/
245 int
246 hid_get_item(struct hid_data *s, struct hid_item *h)
247 {
248 	struct hid_item *c;
249 	unsigned int bTag, bType, bSize;
250 	uint32_t oldpos;
251 	int32_t mask;
252 	int32_t dval;
253 
254 	if (s == NULL)
255 		return (0);
256 
257 	c = &s->cur[s->pushlevel];
258 
259  top:
260 	/* check if there is an array of items */
261 	if (s->icount < s->ncount) {
262 		/* get current usage */
263 		if (s->iusage < s->nusage) {
264 			dval = s->usages_min[s->iusage] + s->ousage;
265 			c->usage = dval;
266 			s->usage_last = dval;
267 			if (dval == s->usages_max[s->iusage]) {
268 				s->iusage ++;
269 				s->ousage = 0;
270 			} else {
271 				s->ousage ++;
272 			}
273 		} else {
274 			DPRINTFN(1, "Using last usage\n");
275 			dval = s->usage_last;
276 		}
277 		c->nusages = 1;
278 		/* array type HID item may have multiple usages */
279 		while ((c->flags & HIO_VARIABLE) == 0 && s->ousage == 0 &&
280 		    s->iusage < s->nusage && c->nusages < HID_ITEM_MAXUSAGE)
281 			c->usages[c->nusages++] = s->usages_min[s->iusage++];
282 		if ((c->flags & HIO_VARIABLE) == 0 && s->ousage == 0 &&
283 		    s->iusage < s->nusage)
284 			DPRINTFN(0, "HID_ITEM_MAXUSAGE should be increased "
285 			    "up to %hhu to parse the HID report descriptor\n",
286 			    s->nusage);
287 		s->icount ++;
288 		/*
289 		 * Only copy HID item, increment position and return
290 		 * if correct kindset!
291 		 */
292 		if (s->kindset & (1 << c->kind)) {
293 			*h = *c;
294 			DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
295 			    h->loc.size, h->loc.count);
296 			c->loc.pos += c->loc.size * c->loc.count;
297 			return (1);
298 		}
299 	}
300 
301 	/* reset state variables */
302 	s->icount = 0;
303 	s->ncount = 0;
304 	s->iusage = 0;
305 	s->nusage = 0;
306 	s->susage = 0;
307 	s->ousage = 0;
308 	hid_clear_local(c);
309 
310 	/* get next item */
311 	while (s->p != s->end) {
312 		bSize = hid_get_byte(s, 1);
313 		if (bSize == 0xfe) {
314 			/* long item */
315 			bSize = hid_get_byte(s, 1);
316 			bSize |= hid_get_byte(s, 1) << 8;
317 			bTag = hid_get_byte(s, 1);
318 			bType = 0xff;	/* XXX what should it be */
319 		} else {
320 			/* short item */
321 			bTag = bSize >> 4;
322 			bType = (bSize >> 2) & 3;
323 			bSize &= 3;
324 			if (bSize == 3)
325 				bSize = 4;
326 		}
327 		switch (bSize) {
328 		case 0:
329 			dval = 0;
330 			mask = 0;
331 			break;
332 		case 1:
333 			dval = (int8_t)hid_get_byte(s, 1);
334 			mask = 0xFF;
335 			break;
336 		case 2:
337 			dval = hid_get_byte(s, 1);
338 			dval |= hid_get_byte(s, 1) << 8;
339 			dval = (int16_t)dval;
340 			mask = 0xFFFF;
341 			break;
342 		case 4:
343 			dval = hid_get_byte(s, 1);
344 			dval |= hid_get_byte(s, 1) << 8;
345 			dval |= hid_get_byte(s, 1) << 16;
346 			dval |= hid_get_byte(s, 1) << 24;
347 			mask = 0xFFFFFFFF;
348 			break;
349 		default:
350 			dval = hid_get_byte(s, bSize);
351 			DPRINTFN(0, "bad length %u (data=0x%02x)\n",
352 			    bSize, dval);
353 			continue;
354 		}
355 
356 		switch (bType) {
357 		case 0:		/* Main */
358 			switch (bTag) {
359 			case 8:	/* Input */
360 				c->kind = hid_input;
361 		ret:
362 				c->flags = dval;
363 				c->loc.count = s->loc_count;
364 				c->loc.size = s->loc_size;
365 
366 				if (c->flags & HIO_VARIABLE) {
367 					/* range check usage count */
368 					if (c->loc.count > MAXLOCCNT) {
369 						DPRINTFN(0, "Number of "
370 						    "items(%u) truncated to %u\n",
371 						    (unsigned)(c->loc.count),
372 						    MAXLOCCNT);
373 						s->ncount = MAXLOCCNT;
374 					} else
375 						s->ncount = c->loc.count;
376 
377 					/*
378 					 * The "top" loop will return
379 					 * one and one item:
380 					 */
381 					c->loc.count = 1;
382 				} else {
383 					s->ncount = 1;
384 				}
385 				goto top;
386 
387 			case 9:	/* Output */
388 				c->kind = hid_output;
389 				goto ret;
390 			case 10:	/* Collection */
391 				c->kind = hid_collection;
392 				c->collection = dval;
393 				c->collevel++;
394 				c->usage = s->usage_last;
395 				c->nusages = 1;
396 				*h = *c;
397 				return (1);
398 			case 11:	/* Feature */
399 				c->kind = hid_feature;
400 				goto ret;
401 			case 12:	/* End collection */
402 				c->kind = hid_endcollection;
403 				if (c->collevel == 0) {
404 					DPRINTFN(0, "invalid end collection\n");
405 					return (0);
406 				}
407 				c->collevel--;
408 				*h = *c;
409 				return (1);
410 			default:
411 				DPRINTFN(0, "Main bTag=%d\n", bTag);
412 				break;
413 			}
414 			break;
415 		case 1:		/* Global */
416 			switch (bTag) {
417 			case 0:
418 				c->_usage_page = dval << 16;
419 				break;
420 			case 1:
421 				c->logical_minimum = dval;
422 				break;
423 			case 2:
424 				c->logical_maximum = dval;
425 				break;
426 			case 3:
427 				c->physical_minimum = dval;
428 				break;
429 			case 4:
430 				c->physical_maximum = dval;
431 				break;
432 			case 5:
433 				c->unit_exponent = dval;
434 				break;
435 			case 6:
436 				c->unit = dval;
437 				break;
438 			case 7:
439 				/* mask because value is unsigned */
440 				s->loc_size = dval & mask;
441 				break;
442 			case 8:
443 				hid_switch_rid(s, c, dval & mask);
444 				break;
445 			case 9:
446 				/* mask because value is unsigned */
447 				s->loc_count = dval & mask;
448 				break;
449 			case 10:	/* Push */
450 				/* stop parsing, if invalid push level */
451 				if ((s->pushlevel + 1) >= MAXPUSH) {
452 					DPRINTFN(0, "Cannot push item @ %d\n", s->pushlevel);
453 					return (0);
454 				}
455 				s->pushlevel ++;
456 				s->cur[s->pushlevel] = *c;
457 				/* store size and count */
458 				c->loc.size = s->loc_size;
459 				c->loc.count = s->loc_count;
460 				/* update current item pointer */
461 				c = &s->cur[s->pushlevel];
462 				break;
463 			case 11:	/* Pop */
464 				/* stop parsing, if invalid push level */
465 				if (s->pushlevel == 0) {
466 					DPRINTFN(0, "Cannot pop item @ 0\n");
467 					return (0);
468 				}
469 				s->pushlevel --;
470 				/* preserve position */
471 				oldpos = c->loc.pos;
472 				c = &s->cur[s->pushlevel];
473 				/* restore size and count */
474 				s->loc_size = c->loc.size;
475 				s->loc_count = c->loc.count;
476 				/* set default item location */
477 				c->loc.pos = oldpos;
478 				c->loc.size = 0;
479 				c->loc.count = 0;
480 				break;
481 			default:
482 				DPRINTFN(0, "Global bTag=%d\n", bTag);
483 				break;
484 			}
485 			break;
486 		case 2:		/* Local */
487 			switch (bTag) {
488 			case 0:
489 				if (bSize != 4)
490 					dval = (dval & mask) | c->_usage_page;
491 
492 				/* set last usage, in case of a collection */
493 				s->usage_last = dval;
494 
495 				if (s->nusage < MAXUSAGE) {
496 					s->usages_min[s->nusage] = dval;
497 					s->usages_max[s->nusage] = dval;
498 					s->nusage ++;
499 				} else {
500 					DPRINTFN(0, "max usage reached\n");
501 				}
502 
503 				/* clear any pending usage sets */
504 				s->susage = 0;
505 				break;
506 			case 1:
507 				s->susage |= 1;
508 
509 				if (bSize != 4)
510 					dval = (dval & mask) | c->_usage_page;
511 				c->usage_minimum = dval;
512 
513 				goto check_set;
514 			case 2:
515 				s->susage |= 2;
516 
517 				if (bSize != 4)
518 					dval = (dval & mask) | c->_usage_page;
519 				c->usage_maximum = dval;
520 
521 			check_set:
522 				if (s->susage != 3)
523 					break;
524 
525 				/* sanity check */
526 				if ((s->nusage < MAXUSAGE) &&
527 				    (c->usage_minimum <= c->usage_maximum)) {
528 					/* add usage range */
529 					s->usages_min[s->nusage] =
530 					    c->usage_minimum;
531 					s->usages_max[s->nusage] =
532 					    c->usage_maximum;
533 					s->nusage ++;
534 				} else {
535 					DPRINTFN(0, "Usage set dropped\n");
536 				}
537 				s->susage = 0;
538 				break;
539 			case 3:
540 				c->designator_index = dval;
541 				break;
542 			case 4:
543 				c->designator_minimum = dval;
544 				break;
545 			case 5:
546 				c->designator_maximum = dval;
547 				break;
548 			case 7:
549 				c->string_index = dval;
550 				break;
551 			case 8:
552 				c->string_minimum = dval;
553 				break;
554 			case 9:
555 				c->string_maximum = dval;
556 				break;
557 			case 10:
558 				c->set_delimiter = dval;
559 				break;
560 			default:
561 				DPRINTFN(0, "Local bTag=%d\n", bTag);
562 				break;
563 			}
564 			break;
565 		default:
566 			DPRINTFN(0, "default bType=%d\n", bType);
567 			break;
568 		}
569 	}
570 	return (0);
571 }
572 
573 /*------------------------------------------------------------------------*
574  *	hid_report_size
575  *------------------------------------------------------------------------*/
576 int
577 hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, uint8_t *id)
578 {
579 	struct hid_data *d;
580 	struct hid_item h;
581 	uint32_t temp;
582 	uint32_t hpos;
583 	uint32_t lpos;
584 	uint8_t any_id;
585 
586 	any_id = 0;
587 	hpos = 0;
588 	lpos = 0xFFFFFFFF;
589 
590 	for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
591 		if (h.kind == k) {
592 			/* check for ID-byte presence */
593 			if ((h.report_ID != 0) && !any_id) {
594 				if (id != NULL)
595 					*id = h.report_ID;
596 				any_id = 1;
597 			}
598 			/* compute minimum */
599 			if (lpos > h.loc.pos)
600 				lpos = h.loc.pos;
601 			/* compute end position */
602 			temp = h.loc.pos + (h.loc.size * h.loc.count);
603 			/* compute maximum */
604 			if (hpos < temp)
605 				hpos = temp;
606 		}
607 	}
608 	hid_end_parse(d);
609 
610 	/* safety check - can happen in case of currupt descriptors */
611 	if (lpos > hpos)
612 		temp = 0;
613 	else
614 		temp = hpos - lpos;
615 
616 	/* check for ID byte */
617 	if (any_id)
618 		temp += 8;
619 	else if (id != NULL)
620 		*id = 0;
621 
622 	/* return length in bytes rounded up */
623 	return ((temp + 7) / 8);
624 }
625 
626 /*------------------------------------------------------------------------*
627  *	hid_locate
628  *------------------------------------------------------------------------*/
629 int
630 hid_locate(const void *desc, usb_size_t size, int32_t u, enum hid_kind k,
631     uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id)
632 {
633 	struct hid_data *d;
634 	struct hid_item h;
635 	int i;
636 
637 	for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
638 		for (i = 0; i < h.nusages; i++) {
639 			if (h.kind == k && h.usages[i] == u) {
640 				if (index--)
641 					break;
642 				if (loc != NULL)
643 					*loc = h.loc;
644 				if (flags != NULL)
645 					*flags = h.flags;
646 				if (id != NULL)
647 					*id = h.report_ID;
648 				hid_end_parse(d);
649 				return (1);
650 			}
651 		}
652 	}
653 	if (loc != NULL)
654 		loc->size = 0;
655 	if (flags != NULL)
656 		*flags = 0;
657 	if (id != NULL)
658 		*id = 0;
659 	hid_end_parse(d);
660 	return (0);
661 }
662 
663 /*------------------------------------------------------------------------*
664  *	hid_get_data
665  *------------------------------------------------------------------------*/
666 static uint32_t
667 hid_get_data_sub(const uint8_t *buf, usb_size_t len, struct hid_location *loc,
668     int is_signed)
669 {
670 	uint32_t hpos = loc->pos;
671 	uint32_t hsize = loc->size;
672 	uint32_t data;
673 	uint32_t rpos;
674 	uint8_t n;
675 
676 	DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
677 
678 	/* Range check and limit */
679 	if (hsize == 0)
680 		return (0);
681 	if (hsize > 32)
682 		hsize = 32;
683 
684 	/* Get data in a safe way */
685 	data = 0;
686 	rpos = (hpos / 8);
687 	n = (hsize + 7) / 8;
688 	rpos += n;
689 	while (n--) {
690 		rpos--;
691 		if (rpos < len)
692 			data |= buf[rpos] << (8 * n);
693 	}
694 
695 	/* Correctly shift down data */
696 	data = (data >> (hpos % 8));
697 	n = 32 - hsize;
698 
699 	/* Mask and sign extend in one */
700 	if (is_signed != 0)
701 		data = (int32_t)((int32_t)data << n) >> n;
702 	else
703 		data = (uint32_t)((uint32_t)data << n) >> n;
704 
705 	DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
706 	    loc->pos, loc->size, (long)data);
707 	return (data);
708 }
709 
710 int32_t
711 hid_get_data(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
712 {
713 	return (hid_get_data_sub(buf, len, loc, 1));
714 }
715 
716 uint32_t
717 hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
718 {
719         return (hid_get_data_sub(buf, len, loc, 0));
720 }
721 
722 /*------------------------------------------------------------------------*
723  *	hid_put_data
724  *------------------------------------------------------------------------*/
725 void
726 hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
727     struct hid_location *loc, unsigned int value)
728 {
729 	uint32_t hpos = loc->pos;
730 	uint32_t hsize = loc->size;
731 	uint64_t data;
732 	uint64_t mask;
733 	uint32_t rpos;
734 	uint8_t n;
735 
736 	DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
737 
738 	/* Range check and limit */
739 	if (hsize == 0)
740 		return;
741 	if (hsize > 32)
742 		hsize = 32;
743 
744 	/* Put data in a safe way */
745 	rpos = (hpos / 8);
746 	n = (hsize + 7) / 8;
747 	data = ((uint64_t)value) << (hpos % 8);
748 	mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
749 	rpos += n;
750 	while (n--) {
751 		rpos--;
752 		if (rpos < len) {
753 			buf[rpos] &= ~(mask >> (8 * n));
754 			buf[rpos] |= (data >> (8 * n));
755 		}
756 	}
757 }
758 
759 /*------------------------------------------------------------------------*
760  *	hid_is_collection
761  *------------------------------------------------------------------------*/
762 int
763 hid_is_collection(const void *desc, usb_size_t size, int32_t usage)
764 {
765 	struct hid_data *hd;
766 	struct hid_item hi;
767 	int err;
768 
769 	hd = hid_start_parse(desc, size, hid_input);
770 	if (hd == NULL)
771 		return (0);
772 
773 	while ((err = hid_get_item(hd, &hi))) {
774 		 if (hi.kind == hid_collection &&
775 		     hi.usage == usage)
776 			break;
777 	}
778 	hid_end_parse(hd);
779 	return (err);
780 }
781 
782 /*------------------------------------------------------------------------*
783  * calculate HID item resolution. unit/mm for distances, unit/rad for angles
784  *------------------------------------------------------------------------*/
785 int32_t
786 hid_item_resolution(struct hid_item *hi)
787 {
788 	/*
789 	 * hid unit scaling table according to HID Usage Table Review
790 	 * Request 39 Tbl 17 http://www.usb.org/developers/hidpage/HUTRR39b.pdf
791 	 */
792 	static const int64_t scale[0x10][2] = {
793 	    [0x00] = { 1, 1 },
794 	    [0x01] = { 1, 10 },
795 	    [0x02] = { 1, 100 },
796 	    [0x03] = { 1, 1000 },
797 	    [0x04] = { 1, 10000 },
798 	    [0x05] = { 1, 100000 },
799 	    [0x06] = { 1, 1000000 },
800 	    [0x07] = { 1, 10000000 },
801 	    [0x08] = { 100000000, 1 },
802 	    [0x09] = { 10000000, 1 },
803 	    [0x0A] = { 1000000, 1 },
804 	    [0x0B] = { 100000, 1 },
805 	    [0x0C] = { 10000, 1 },
806 	    [0x0D] = { 1000, 1 },
807 	    [0x0E] = { 100, 1 },
808 	    [0x0F] = { 10, 1 },
809 	};
810 	int64_t logical_size;
811 	int64_t physical_size;
812 	int64_t multiplier;
813 	int64_t divisor;
814 	int64_t resolution;
815 
816 	switch (hi->unit) {
817 	case HUM_CENTIMETER:
818 		multiplier = 1;
819 		divisor = 10;
820 		break;
821 	case HUM_INCH:
822 		multiplier = 10;
823 		divisor = 254;
824 		break;
825 	case HUM_RADIAN:
826 		multiplier = 1;
827 		divisor = 1;
828 		break;
829 	case HUM_DEGREE:
830 		multiplier = 573;
831 		divisor = 10;
832 		break;
833 	default:
834 		return (0);
835 	}
836 
837 	if ((hi->logical_maximum <= hi->logical_minimum) ||
838 	    (hi->physical_maximum <= hi->physical_minimum) ||
839 	    (hi->unit_exponent < 0) || (hi->unit_exponent >= nitems(scale)))
840 		return (0);
841 
842 	logical_size = (int64_t)hi->logical_maximum -
843 	    (int64_t)hi->logical_minimum;
844 	physical_size = (int64_t)hi->physical_maximum -
845 	    (int64_t)hi->physical_minimum;
846 	/* Round to ceiling */
847 	resolution = logical_size * multiplier * scale[hi->unit_exponent][0] /
848 	    (physical_size * divisor * scale[hi->unit_exponent][1]);
849 
850 	if (resolution > INT32_MAX)
851 		return (0);
852 
853 	return (resolution);
854 }
855 
856 /*------------------------------------------------------------------------*
857  *	hid_is_mouse
858  *
859  * This function will decide if a USB descriptor belongs to a USB mouse.
860  *
861  * Return values:
862  * Zero: Not a USB mouse.
863  * Else: Is a USB mouse.
864  *------------------------------------------------------------------------*/
865 int
866 hid_is_mouse(const void *d_ptr, uint16_t d_len)
867 {
868 	struct hid_data *hd;
869 	struct hid_item hi;
870 	int mdepth;
871 	int found;
872 
873 	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
874 	if (hd == NULL)
875 		return (0);
876 
877 	mdepth = 0;
878 	found = 0;
879 
880 	while (hid_get_item(hd, &hi)) {
881 		switch (hi.kind) {
882 		case hid_collection:
883 			if (mdepth != 0)
884 				mdepth++;
885 			else if (hi.collection == 1 &&
886 			     hi.usage ==
887 			      HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
888 				mdepth++;
889 			break;
890 		case hid_endcollection:
891 			if (mdepth != 0)
892 				mdepth--;
893 			break;
894 		case hid_input:
895 			if (mdepth == 0)
896 				break;
897 			if (hi.usage ==
898 			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
899 			    (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
900 				found++;
901 			if (hi.usage ==
902 			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
903 			    (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
904 				found++;
905 			break;
906 		default:
907 			break;
908 		}
909 	}
910 	hid_end_parse(hd);
911 	return (found);
912 }
913 
914 /*------------------------------------------------------------------------*
915  *	hid_is_keyboard
916  *
917  * This function will decide if a USB descriptor belongs to a USB keyboard.
918  *
919  * Return values:
920  * Zero: Not a USB keyboard.
921  * Else: Is a USB keyboard.
922  *------------------------------------------------------------------------*/
923 int
924 hid_is_keyboard(const void *d_ptr, uint16_t d_len)
925 {
926 	if (hid_is_collection(d_ptr, d_len,
927 	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
928 		return (1);
929 	return (0);
930 }
931 
932 MODULE_VERSION(hid, 1);
933