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