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