1/* $FreeBSD: releng/11.0/sys/dev/usb/usb_hid.c 298932 2016-05-02 17:44:03Z pfg $ */
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
76struct hid_pos_data {
77	int32_t rid;
78	uint32_t pos;
79};
80
81struct hid_data {
82	const uint8_t *start;
83	const uint8_t *end;
84	const uint8_t *p;
85	struct hid_item cur[MAXPUSH];
86	struct hid_pos_data last_pos[MAXID];
87	int32_t	usages_min[MAXUSAGE];
88	int32_t	usages_max[MAXUSAGE];
89	int32_t usage_last;	/* last seen usage */
90	uint32_t loc_size;	/* last seen size */
91	uint32_t loc_count;	/* last seen count */
92	uint8_t	kindset;	/* we have 5 kinds so 8 bits are enough */
93	uint8_t	pushlevel;	/* current pushlevel */
94	uint8_t	ncount;		/* end usage item count */
95	uint8_t icount;		/* current usage item count */
96	uint8_t	nusage;		/* end "usages_min/max" index */
97	uint8_t	iusage;		/* current "usages_min/max" index */
98	uint8_t ousage;		/* current "usages_min/max" offset */
99	uint8_t	susage;		/* usage set flags */
100};
101
102/*------------------------------------------------------------------------*
103 *	hid_clear_local
104 *------------------------------------------------------------------------*/
105static void
106hid_clear_local(struct hid_item *c)
107{
108
109	c->loc.count = 0;
110	c->loc.size = 0;
111	c->usage = 0;
112	c->usage_minimum = 0;
113	c->usage_maximum = 0;
114	c->designator_index = 0;
115	c->designator_minimum = 0;
116	c->designator_maximum = 0;
117	c->string_index = 0;
118	c->string_minimum = 0;
119	c->string_maximum = 0;
120	c->set_delimiter = 0;
121}
122
123static void
124hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
125{
126	uint8_t i;
127
128	/* check for same report ID - optimise */
129
130	if (c->report_ID == next_rID)
131		return;
132
133	/* save current position for current rID */
134
135	if (c->report_ID == 0) {
136		i = 0;
137	} else {
138		for (i = 1; i != MAXID; i++) {
139			if (s->last_pos[i].rid == c->report_ID)
140				break;
141			if (s->last_pos[i].rid == 0)
142				break;
143		}
144	}
145	if (i != MAXID) {
146		s->last_pos[i].rid = c->report_ID;
147		s->last_pos[i].pos = c->loc.pos;
148	}
149
150	/* store next report ID */
151
152	c->report_ID = next_rID;
153
154	/* lookup last position for next rID */
155
156	if (next_rID == 0) {
157		i = 0;
158	} else {
159		for (i = 1; i != MAXID; i++) {
160			if (s->last_pos[i].rid == next_rID)
161				break;
162			if (s->last_pos[i].rid == 0)
163				break;
164		}
165	}
166	if (i != MAXID) {
167		s->last_pos[i].rid = next_rID;
168		c->loc.pos = s->last_pos[i].pos;
169	} else {
170		DPRINTF("Out of RID entries, position is set to zero!\n");
171		c->loc.pos = 0;
172	}
173}
174
175/*------------------------------------------------------------------------*
176 *	hid_start_parse
177 *------------------------------------------------------------------------*/
178struct hid_data *
179hid_start_parse(const void *d, usb_size_t len, int kindset)
180{
181	struct hid_data *s;
182
183	if ((kindset-1) & kindset) {
184		DPRINTFN(0, "Only one bit can be "
185		    "set in the kindset\n");
186		return (NULL);
187	}
188
189	s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
190	s->start = s->p = d;
191	s->end = ((const uint8_t *)d) + len;
192	s->kindset = kindset;
193	return (s);
194}
195
196/*------------------------------------------------------------------------*
197 *	hid_end_parse
198 *------------------------------------------------------------------------*/
199void
200hid_end_parse(struct hid_data *s)
201{
202	if (s == NULL)
203		return;
204
205	free(s, M_TEMP);
206}
207
208/*------------------------------------------------------------------------*
209 *	get byte from HID descriptor
210 *------------------------------------------------------------------------*/
211static uint8_t
212hid_get_byte(struct hid_data *s, const uint16_t wSize)
213{
214	const uint8_t *ptr;
215	uint8_t retval;
216
217	ptr = s->p;
218
219	/* check if end is reached */
220	if (ptr == s->end)
221		return (0);
222
223	/* read out a byte */
224	retval = *ptr;
225
226	/* check if data pointer can be advanced by "wSize" bytes */
227	if ((s->end - ptr) < wSize)
228		ptr = s->end;
229	else
230		ptr += wSize;
231
232	/* update pointer */
233	s->p = ptr;
234
235	return (retval);
236}
237
238/*------------------------------------------------------------------------*
239 *	hid_get_item
240 *------------------------------------------------------------------------*/
241int
242hid_get_item(struct hid_data *s, struct hid_item *h)
243{
244	struct hid_item *c;
245	unsigned int bTag, bType, bSize;
246	uint32_t oldpos;
247	int32_t mask;
248	int32_t dval;
249
250	if (s == NULL)
251		return (0);
252
253	c = &s->cur[s->pushlevel];
254
255 top:
256	/* check if there is an array of items */
257	if (s->icount < s->ncount) {
258		/* get current usage */
259		if (s->iusage < s->nusage) {
260			dval = s->usages_min[s->iusage] + s->ousage;
261			c->usage = dval;
262			s->usage_last = dval;
263			if (dval == s->usages_max[s->iusage]) {
264				s->iusage ++;
265				s->ousage = 0;
266			} else {
267				s->ousage ++;
268			}
269		} else {
270			DPRINTFN(1, "Using last usage\n");
271			dval = s->usage_last;
272		}
273		s->icount ++;
274		/*
275		 * Only copy HID item, increment position and return
276		 * if correct kindset!
277		 */
278		if (s->kindset & (1 << c->kind)) {
279			*h = *c;
280			DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
281			    h->loc.size, h->loc.count);
282			c->loc.pos += c->loc.size * c->loc.count;
283			return (1);
284		}
285	}
286
287	/* reset state variables */
288	s->icount = 0;
289	s->ncount = 0;
290	s->iusage = 0;
291	s->nusage = 0;
292	s->susage = 0;
293	s->ousage = 0;
294	hid_clear_local(c);
295
296	/* get next item */
297	while (s->p != s->end) {
298
299		bSize = hid_get_byte(s, 1);
300		if (bSize == 0xfe) {
301			/* long item */
302			bSize = hid_get_byte(s, 1);
303			bSize |= hid_get_byte(s, 1) << 8;
304			bTag = hid_get_byte(s, 1);
305			bType = 0xff;	/* XXX what should it be */
306		} else {
307			/* short item */
308			bTag = bSize >> 4;
309			bType = (bSize >> 2) & 3;
310			bSize &= 3;
311			if (bSize == 3)
312				bSize = 4;
313		}
314		switch (bSize) {
315		case 0:
316			dval = 0;
317			mask = 0;
318			break;
319		case 1:
320			dval = (int8_t)hid_get_byte(s, 1);
321			mask = 0xFF;
322			break;
323		case 2:
324			dval = hid_get_byte(s, 1);
325			dval |= hid_get_byte(s, 1) << 8;
326			dval = (int16_t)dval;
327			mask = 0xFFFF;
328			break;
329		case 4:
330			dval = hid_get_byte(s, 1);
331			dval |= hid_get_byte(s, 1) << 8;
332			dval |= hid_get_byte(s, 1) << 16;
333			dval |= hid_get_byte(s, 1) << 24;
334			mask = 0xFFFFFFFF;
335			break;
336		default:
337			dval = hid_get_byte(s, bSize);
338			DPRINTFN(0, "bad length %u (data=0x%02x)\n",
339			    bSize, dval);
340			continue;
341		}
342
343		switch (bType) {
344		case 0:		/* Main */
345			switch (bTag) {
346			case 8:	/* Input */
347				c->kind = hid_input;
348				c->flags = dval;
349		ret:
350				c->loc.count = s->loc_count;
351				c->loc.size = s->loc_size;
352
353				if (c->flags & HIO_VARIABLE) {
354					/* range check usage count */
355					if (c->loc.count > 255) {
356						DPRINTFN(0, "Number of "
357						    "items(%u) truncated to 255\n",
358						    (unsigned)(c->loc.count));
359						s->ncount = 255;
360					} else
361						s->ncount = c->loc.count;
362
363					/*
364					 * The "top" loop will return
365					 * one and one item:
366					 */
367					c->loc.count = 1;
368				} else {
369					s->ncount = 1;
370				}
371				goto top;
372
373			case 9:	/* Output */
374				c->kind = hid_output;
375				c->flags = dval;
376				goto ret;
377			case 10:	/* Collection */
378				c->kind = hid_collection;
379				c->collection = dval;
380				c->collevel++;
381				c->usage = s->usage_last;
382				*h = *c;
383				return (1);
384			case 11:	/* Feature */
385				c->kind = hid_feature;
386				c->flags = dval;
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				s->pushlevel ++;
438				if (s->pushlevel < MAXPUSH) {
439					s->cur[s->pushlevel] = *c;
440					/* store size and count */
441					c->loc.size = s->loc_size;
442					c->loc.count = s->loc_count;
443					/* update current item pointer */
444					c = &s->cur[s->pushlevel];
445				} else {
446					DPRINTFN(0, "Cannot push "
447					    "item @ %d\n", s->pushlevel);
448				}
449				break;
450			case 11:	/* Pop */
451				s->pushlevel --;
452				if (s->pushlevel < MAXPUSH) {
453					/* preserve position */
454					oldpos = c->loc.pos;
455					c = &s->cur[s->pushlevel];
456					/* restore size and count */
457					s->loc_size = c->loc.size;
458					s->loc_count = c->loc.count;
459					/* set default item location */
460					c->loc.pos = oldpos;
461					c->loc.size = 0;
462					c->loc.count = 0;
463				} else {
464					DPRINTFN(0, "Cannot pop "
465					    "item @ %d\n", s->pushlevel);
466				}
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 *	hid_is_mouse
853 *
854 * This function will decide if a USB descriptor belongs to a USB mouse.
855 *
856 * Return values:
857 * Zero: Not a USB mouse.
858 * Else: Is a USB mouse.
859 *------------------------------------------------------------------------*/
860int
861hid_is_mouse(const void *d_ptr, uint16_t d_len)
862{
863	struct hid_data *hd;
864	struct hid_item hi;
865	int mdepth;
866	int found;
867
868	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
869	if (hd == NULL)
870		return (0);
871
872	mdepth = 0;
873	found = 0;
874
875	while (hid_get_item(hd, &hi)) {
876		switch (hi.kind) {
877		case hid_collection:
878			if (mdepth != 0)
879				mdepth++;
880			else if (hi.collection == 1 &&
881			     hi.usage ==
882			      HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
883				mdepth++;
884			break;
885		case hid_endcollection:
886			if (mdepth != 0)
887				mdepth--;
888			break;
889		case hid_input:
890			if (mdepth == 0)
891				break;
892			if (hi.usage ==
893			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
894			    (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
895				found++;
896			if (hi.usage ==
897			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
898			    (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
899				found++;
900			break;
901		default:
902			break;
903		}
904	}
905	hid_end_parse(hd);
906	return (found);
907}
908
909/*------------------------------------------------------------------------*
910 *	hid_is_keyboard
911 *
912 * This function will decide if a USB descriptor belongs to a USB keyboard.
913 *
914 * Return values:
915 * Zero: Not a USB keyboard.
916 * Else: Is a USB keyboard.
917 *------------------------------------------------------------------------*/
918int
919hid_is_keyboard(const void *d_ptr, uint16_t d_len)
920{
921	if (hid_is_collection(d_ptr, d_len,
922	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
923		return (1);
924	return (0);
925}
926