xref: /netbsd/lib/libusbhid/parse.c (revision 632f8fbb)
1*632f8fbbSfox /*	$NetBSD: parse.c,v 1.11 2020/04/04 21:26:16 fox Exp $	*/
28ac1932eSaugustss 
38ac1932eSaugustss /*
499410184Ssalo  * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@NetBSD.org>
58ac1932eSaugustss  * All rights reserved.
68ac1932eSaugustss  *
78ac1932eSaugustss  * Redistribution and use in source and binary forms, with or without
88ac1932eSaugustss  * modification, are permitted provided that the following conditions
98ac1932eSaugustss  * are met:
108ac1932eSaugustss  * 1. Redistributions of source code must retain the above copyright
118ac1932eSaugustss  *    notice, this list of conditions and the following disclaimer.
128ac1932eSaugustss  * 2. Redistributions in binary form must reproduce the above copyright
138ac1932eSaugustss  *    notice, this list of conditions and the following disclaimer in the
148ac1932eSaugustss  *    documentation and/or other materials provided with the distribution.
158ac1932eSaugustss  *
168ac1932eSaugustss  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
178ac1932eSaugustss  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188ac1932eSaugustss  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198ac1932eSaugustss  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
208ac1932eSaugustss  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218ac1932eSaugustss  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228ac1932eSaugustss  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238ac1932eSaugustss  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248ac1932eSaugustss  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258ac1932eSaugustss  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268ac1932eSaugustss  * SUCH DAMAGE.
278ac1932eSaugustss  */
288ac1932eSaugustss 
29e2d78706Slukem #include <sys/cdefs.h>
30*632f8fbbSfox __RCSID("$NetBSD: parse.c,v 1.11 2020/04/04 21:26:16 fox Exp $");
31e2d78706Slukem 
328ac1932eSaugustss #include <assert.h>
338ac1932eSaugustss #include <stdlib.h>
348ac1932eSaugustss #include <string.h>
358ac1932eSaugustss #include <sys/time.h>
368ac1932eSaugustss 
378ac1932eSaugustss #include <dev/usb/usb.h>
38f5493ae1Sbouyer #include <dev/hid/hid.h>
398ac1932eSaugustss 
408ac1932eSaugustss #include "usbhid.h"
418ac1932eSaugustss #include "usbvar.h"
428ac1932eSaugustss 
438ac1932eSaugustss #define MAXUSAGE 100
448ac1932eSaugustss struct hid_data {
458ac1932eSaugustss 	u_char *start;
468ac1932eSaugustss 	u_char *end;
478ac1932eSaugustss 	u_char *p;
488ac1932eSaugustss 	hid_item_t cur;
498ac1932eSaugustss 	unsigned int usages[MAXUSAGE];
508ac1932eSaugustss 	int nusage;
518ac1932eSaugustss 	int minset;
528ac1932eSaugustss 	int logminsize;
53e4328754Sjakllsch 	int phyminsize;
548ac1932eSaugustss 	int multi;
558ac1932eSaugustss 	int multimax;
568ac1932eSaugustss 	int kindset;
578ac1932eSaugustss 	int reportid;
588ac1932eSaugustss 
598ac1932eSaugustss 	/*
608ac1932eSaugustss 	 * The start of collection item has no report ID set, so save
618ac1932eSaugustss 	 * it until we know the ID.
628ac1932eSaugustss 	 */
638ac1932eSaugustss 	hid_item_t savedcoll;
648ac1932eSaugustss 	u_char hassavedcoll;
658ac1932eSaugustss 	/*
668ac1932eSaugustss 	 * Absolute data position (bits) for input/output/feature.
678ac1932eSaugustss 	 *  Assumes that hid_input, hid_output and hid_feature have
688ac1932eSaugustss 	 *  values 0, 1 and 2.
698ac1932eSaugustss 	 */
708ac1932eSaugustss 	unsigned int kindpos[3];
718ac1932eSaugustss };
728ac1932eSaugustss 
min(int x,int y)738ac1932eSaugustss static int min(int x, int y) { return x < y ? x : y; }
748ac1932eSaugustss 
758ac1932eSaugustss static int hid_get_item_raw(hid_data_t s, hid_item_t *h);
768ac1932eSaugustss 
778ac1932eSaugustss static void
hid_clear_local(hid_item_t * c)788ac1932eSaugustss hid_clear_local(hid_item_t *c)
798ac1932eSaugustss {
808ac1932eSaugustss 
818ac1932eSaugustss 	_DIAGASSERT(c != NULL);
828ac1932eSaugustss 
838ac1932eSaugustss 	c->usage = 0;
848ac1932eSaugustss 	c->usage_minimum = 0;
858ac1932eSaugustss 	c->usage_maximum = 0;
868ac1932eSaugustss 	c->designator_index = 0;
878ac1932eSaugustss 	c->designator_minimum = 0;
888ac1932eSaugustss 	c->designator_maximum = 0;
898ac1932eSaugustss 	c->string_index = 0;
908ac1932eSaugustss 	c->string_minimum = 0;
918ac1932eSaugustss 	c->string_maximum = 0;
928ac1932eSaugustss 	c->set_delimiter = 0;
938ac1932eSaugustss }
948ac1932eSaugustss 
958ac1932eSaugustss hid_data_t
hid_start_parse(report_desc_t d,int kindset,int id)968ac1932eSaugustss hid_start_parse(report_desc_t d, int kindset, int id)
978ac1932eSaugustss {
988ac1932eSaugustss 	struct hid_data *s;
998ac1932eSaugustss 
1008ac1932eSaugustss 	_DIAGASSERT(d != NULL);
1018ac1932eSaugustss 
1028ac1932eSaugustss 	s = malloc(sizeof *s);
1038ac1932eSaugustss 	memset(s, 0, sizeof *s);
1048ac1932eSaugustss 	s->start = s->p = d->data;
1058ac1932eSaugustss 	s->end = d->data + d->size;
1068ac1932eSaugustss 	s->kindset = kindset;
1078ac1932eSaugustss 	s->reportid = id;
1088ac1932eSaugustss 	s->hassavedcoll = 0;
1098ac1932eSaugustss 	return (s);
1108ac1932eSaugustss }
1118ac1932eSaugustss 
1128ac1932eSaugustss void
hid_end_parse(hid_data_t s)1138ac1932eSaugustss hid_end_parse(hid_data_t s)
1148ac1932eSaugustss {
1158ac1932eSaugustss 
1168ac1932eSaugustss 	_DIAGASSERT(s != NULL);
1178ac1932eSaugustss 
1188ac1932eSaugustss 	while (s->cur.next) {
1198ac1932eSaugustss 		hid_item_t *hi = s->cur.next->next;
1208ac1932eSaugustss 		free(s->cur.next);
1218ac1932eSaugustss 		s->cur.next = hi;
1228ac1932eSaugustss 	}
1238ac1932eSaugustss 	free(s);
1248ac1932eSaugustss }
1258ac1932eSaugustss 
1268ac1932eSaugustss int
hid_get_item(hid_data_t s,hid_item_t * h)1278ac1932eSaugustss hid_get_item(hid_data_t s, hid_item_t *h)
1288ac1932eSaugustss {
1298ac1932eSaugustss 	int r;
1308ac1932eSaugustss 
1318ac1932eSaugustss 	for (;;) {
1328ac1932eSaugustss 		r = hid_get_item_raw(s, h);
1338ac1932eSaugustss 		if (r <= 0)
1348ac1932eSaugustss 			break;
135dbe9bd1eSaugustss 		if (h->report_ID == s->reportid || s->reportid == -1)
1368ac1932eSaugustss 			break;
1378ac1932eSaugustss 	}
1388ac1932eSaugustss 	return (r);
1398ac1932eSaugustss }
1408ac1932eSaugustss 
1418ac1932eSaugustss #define REPORT_SAVED_COLL \
1428ac1932eSaugustss 	do { \
1438ac1932eSaugustss 		if (s->hassavedcoll) { \
1448ac1932eSaugustss 			*h = s->savedcoll; \
1458ac1932eSaugustss 			h->report_ID = c->report_ID; \
1468ac1932eSaugustss 			s->hassavedcoll = 0; \
1478ac1932eSaugustss 			return (1); \
1488ac1932eSaugustss 		} \
1498ac1932eSaugustss 	} while(/*LINTED*/ 0)
1508ac1932eSaugustss 
1518ac1932eSaugustss static int
hid_get_item_raw(hid_data_t s,hid_item_t * h)1528ac1932eSaugustss hid_get_item_raw(hid_data_t s, hid_item_t *h)
1538ac1932eSaugustss {
1548ac1932eSaugustss 	hid_item_t *c;
1558ac1932eSaugustss 	unsigned int bTag = 0, bType = 0, bSize;
1568ac1932eSaugustss 	unsigned char *data;
1578ac1932eSaugustss 	int dval;
1588ac1932eSaugustss 	unsigned char *p;
1598ac1932eSaugustss 	hid_item_t *hi;
1608ac1932eSaugustss 	hid_item_t nc;
1618ac1932eSaugustss 	int i;
1628ac1932eSaugustss 	hid_kind_t retkind;
1638ac1932eSaugustss 
1648ac1932eSaugustss 	_DIAGASSERT(s != NULL);
1658ac1932eSaugustss 	_DIAGASSERT(h != NULL);
1668ac1932eSaugustss 
1678ac1932eSaugustss 	c = &s->cur;
1688ac1932eSaugustss 
1698ac1932eSaugustss  top:
1708ac1932eSaugustss 	if (s->multimax) {
1718ac1932eSaugustss 		REPORT_SAVED_COLL;
1728ac1932eSaugustss 		if (c->logical_minimum >= c->logical_maximum) {
1738ac1932eSaugustss 			if (s->logminsize == 1)
1748ac1932eSaugustss 				c->logical_minimum =(int8_t)c->logical_minimum;
1758ac1932eSaugustss 			else if (s->logminsize == 2)
1768ac1932eSaugustss 				c->logical_minimum =(int16_t)c->logical_minimum;
1778ac1932eSaugustss 		}
178e4328754Sjakllsch 		if (c->physical_minimum >= c->physical_maximum) {
179e4328754Sjakllsch 			if (s->phyminsize == 1)
180e4328754Sjakllsch 				c->physical_minimum =
181e4328754Sjakllsch 					(int8_t)c->physical_minimum;
182e4328754Sjakllsch 			else if (s->phyminsize == 2)
183e4328754Sjakllsch 				c->physical_minimum =
184e4328754Sjakllsch 					(int16_t)c->physical_minimum;
185e4328754Sjakllsch 		}
1868ac1932eSaugustss 		if (s->multi < s->multimax) {
1878ac1932eSaugustss 			c->usage = s->usages[min(s->multi, s->nusage-1)];
1888ac1932eSaugustss 			s->multi++;
1898ac1932eSaugustss 			*h = *c;
1908ac1932eSaugustss 			/*
1918ac1932eSaugustss 			 * 'multimax' is only non-zero if the current
1928ac1932eSaugustss                          *  item kind is input/output/feature
1938ac1932eSaugustss 			 */
1948ac1932eSaugustss 			h->pos = s->kindpos[c->kind];
1958ac1932eSaugustss 			s->kindpos[c->kind] += c->report_size;
1968ac1932eSaugustss 			h->next = 0;
1978ac1932eSaugustss 			return (1);
1988ac1932eSaugustss 		} else {
1998ac1932eSaugustss 			c->report_count = s->multimax;
2008ac1932eSaugustss 			s->multimax = 0;
2018ac1932eSaugustss 			s->nusage = 0;
2028ac1932eSaugustss 			hid_clear_local(c);
2038ac1932eSaugustss 		}
2048ac1932eSaugustss 	}
2058ac1932eSaugustss 	for (;;) {
2068ac1932eSaugustss 		p = s->p;
2078ac1932eSaugustss 		if (p >= s->end)
2088ac1932eSaugustss 			return (0);
2098ac1932eSaugustss 
2108ac1932eSaugustss 		bSize = *p++;
2118ac1932eSaugustss 		if (bSize == 0xfe) {
2128ac1932eSaugustss 			/* long item */
2138ac1932eSaugustss 			bSize = *p++;
2148ac1932eSaugustss 			bSize |= *p++ << 8;
2158ac1932eSaugustss 			bTag = *p++;
2168ac1932eSaugustss 			data = p;
2178ac1932eSaugustss 			p += bSize;
2188ac1932eSaugustss 		} else {
2198ac1932eSaugustss 			/* short item */
2208ac1932eSaugustss 			bTag = bSize >> 4;
2218ac1932eSaugustss 			bType = (bSize >> 2) & 3;
2228ac1932eSaugustss 			bSize &= 3;
2238ac1932eSaugustss 			if (bSize == 3) bSize = 4;
2248ac1932eSaugustss 			data = p;
2258ac1932eSaugustss 			p += bSize;
2268ac1932eSaugustss 		}
2278ac1932eSaugustss 		s->p = p;
2288ac1932eSaugustss 		/*
2298ac1932eSaugustss 		 * The spec is unclear if the data is signed or unsigned.
2308ac1932eSaugustss 		 */
2318ac1932eSaugustss 		switch(bSize) {
2328ac1932eSaugustss 		case 0:
2338ac1932eSaugustss 			dval = 0;
2348ac1932eSaugustss 			break;
2358ac1932eSaugustss 		case 1:
2368ac1932eSaugustss 			dval = /*(int8_t)*/*data++;
2378ac1932eSaugustss 			break;
2388ac1932eSaugustss 		case 2:
2398ac1932eSaugustss 			dval = *data++;
2408ac1932eSaugustss 			dval |= *data++ << 8;
2418ac1932eSaugustss 			break;
2428ac1932eSaugustss 		case 4:
2438ac1932eSaugustss 			dval = *data++;
2448ac1932eSaugustss 			dval |= *data++ << 8;
2458ac1932eSaugustss 			dval |= *data++ << 16;
246*632f8fbbSfox 			dval |= ((uint32_t)*data++) << 24;
2478ac1932eSaugustss 			break;
2488ac1932eSaugustss 		default:
2498ac1932eSaugustss 			return (-1);
2508ac1932eSaugustss 		}
2518ac1932eSaugustss 
2528ac1932eSaugustss 		switch (bType) {
2538ac1932eSaugustss 		case 0:			/* Main */
2548ac1932eSaugustss 			switch (bTag) {
2558ac1932eSaugustss 			case 8:		/* Input */
2568ac1932eSaugustss 				retkind = hid_input;
2578ac1932eSaugustss 			ret:
2588ac1932eSaugustss 				if (!(s->kindset & (1 << retkind))) {
2598ac1932eSaugustss 					/* Drop the items of this kind */
2608ac1932eSaugustss 					s->nusage = 0;
2618ac1932eSaugustss 					continue;
2628ac1932eSaugustss 				}
2638ac1932eSaugustss 				c->kind = retkind;
2648ac1932eSaugustss 				c->flags = dval;
2658ac1932eSaugustss 				if (c->flags & HIO_VARIABLE) {
2668ac1932eSaugustss 					s->multimax = c->report_count;
2678ac1932eSaugustss 					s->multi = 0;
2688ac1932eSaugustss 					c->report_count = 1;
2698ac1932eSaugustss 					if (s->minset) {
2708ac1932eSaugustss 						for (i = c->usage_minimum;
2718ac1932eSaugustss 						     i <= c->usage_maximum;
2728ac1932eSaugustss 						     i++) {
2738ac1932eSaugustss 							s->usages[s->nusage] = i;
2748ac1932eSaugustss 							if (s->nusage < MAXUSAGE-1)
2758ac1932eSaugustss 								s->nusage++;
2768ac1932eSaugustss 						}
2778ac1932eSaugustss 						c->usage_minimum = 0;
2788ac1932eSaugustss 						c->usage_maximum = 0;
2798ac1932eSaugustss 						s->minset = 0;
2808ac1932eSaugustss 					}
2818ac1932eSaugustss 					goto top;
2828ac1932eSaugustss 				} else {
2838ac1932eSaugustss 					if (s->minset)
2848ac1932eSaugustss 						c->usage = c->usage_minimum;
2858ac1932eSaugustss 					*h = *c;
2868ac1932eSaugustss 					h->next = 0;
2878ac1932eSaugustss 					h->pos = s->kindpos[c->kind];
2888ac1932eSaugustss 					s->kindpos[c->kind] +=
2898ac1932eSaugustss 					    c->report_size * c->report_count;
2908ac1932eSaugustss 					hid_clear_local(c);
2918ac1932eSaugustss 					s->minset = 0;
2928ac1932eSaugustss 					return (1);
2938ac1932eSaugustss 				}
2948ac1932eSaugustss 			case 9:		/* Output */
2958ac1932eSaugustss 				retkind = hid_output;
2968ac1932eSaugustss 				goto ret;
2978ac1932eSaugustss 			case 10:	/* Collection */
2988ac1932eSaugustss 				c->kind = hid_collection;
2998ac1932eSaugustss 				c->collection = dval;
3008ac1932eSaugustss 				c->collevel++;
3018ac1932eSaugustss 				nc = *c;
3028ac1932eSaugustss 				hid_clear_local(c);
3038ac1932eSaugustss 				/*c->report_ID = NO_REPORT_ID;*/
3048ac1932eSaugustss 				s->nusage = 0;
3058ac1932eSaugustss 				if (s->hassavedcoll) {
3068ac1932eSaugustss 					*h = s->savedcoll;
3078ac1932eSaugustss 					h->report_ID = nc.report_ID;
3088ac1932eSaugustss 					s->savedcoll = nc;
3098ac1932eSaugustss 					return (1);
3108ac1932eSaugustss 				} else {
3118ac1932eSaugustss 					s->hassavedcoll = 1;
3128ac1932eSaugustss 					s->savedcoll = nc;
3138ac1932eSaugustss 				}
3148ac1932eSaugustss 				break;
3158ac1932eSaugustss 			case 11:	/* Feature */
3168ac1932eSaugustss 				retkind = hid_feature;
3178ac1932eSaugustss 				goto ret;
3188ac1932eSaugustss 			case 12:	/* End collection */
3198ac1932eSaugustss 				REPORT_SAVED_COLL;
3208ac1932eSaugustss 				c->kind = hid_endcollection;
3218ac1932eSaugustss 				c->collevel--;
3228ac1932eSaugustss 				*h = *c;
3238ac1932eSaugustss 				/*hid_clear_local(c);*/
3248ac1932eSaugustss 				s->nusage = 0;
3258ac1932eSaugustss 				return (1);
3268ac1932eSaugustss 			default:
3278ac1932eSaugustss 				return (-2);
3288ac1932eSaugustss 			}
3298ac1932eSaugustss 			break;
3308ac1932eSaugustss 
3318ac1932eSaugustss 		case 1:		/* Global */
3328ac1932eSaugustss 			switch (bTag) {
3338ac1932eSaugustss 			case 0:
3348ac1932eSaugustss 				c->_usage_page = dval << 16;
3358ac1932eSaugustss 				break;
3368ac1932eSaugustss 			case 1:
3378ac1932eSaugustss 				c->logical_minimum = dval;
3388ac1932eSaugustss 				s->logminsize = bSize;
3398ac1932eSaugustss 				break;
3408ac1932eSaugustss 			case 2:
3418ac1932eSaugustss 				c->logical_maximum = dval;
3428ac1932eSaugustss 				break;
3438ac1932eSaugustss 			case 3:
344ec1d44baSjakllsch 				c->physical_minimum = dval;
345e4328754Sjakllsch 				s->phyminsize = bSize;
3468ac1932eSaugustss 				break;
3478ac1932eSaugustss 			case 4:
3488ac1932eSaugustss 				c->physical_maximum = dval;
3498ac1932eSaugustss 				break;
3508ac1932eSaugustss 			case 5:
351e4328754Sjakllsch 				if ( dval > 7 && dval < 0x10)
352e4328754Sjakllsch 					c->unit_exponent = -16 + dval;
353e4328754Sjakllsch 				else
3548ac1932eSaugustss 					c->unit_exponent = dval;
3558ac1932eSaugustss 				break;
3568ac1932eSaugustss 			case 6:
3578ac1932eSaugustss 				c->unit = dval;
3588ac1932eSaugustss 				break;
3598ac1932eSaugustss 			case 7:
3608ac1932eSaugustss 				c->report_size = dval;
3618ac1932eSaugustss 				break;
3628ac1932eSaugustss 			case 8:
3638ac1932eSaugustss 				c->report_ID = dval;
364dbe9bd1eSaugustss 				s->kindpos[hid_input] =
365dbe9bd1eSaugustss 				    s->kindpos[hid_output] =
366dbe9bd1eSaugustss 				    s->kindpos[hid_feature] = 0;
3678ac1932eSaugustss 				break;
3688ac1932eSaugustss 			case 9:
3698ac1932eSaugustss 				c->report_count = dval;
3708ac1932eSaugustss 				break;
3718ac1932eSaugustss 			case 10: /* Push */
3728ac1932eSaugustss 				hi = malloc(sizeof *hi);
3738ac1932eSaugustss 				*hi = s->cur;
3748ac1932eSaugustss 				c->next = hi;
3758ac1932eSaugustss 				break;
3768ac1932eSaugustss 			case 11: /* Pop */
3778ac1932eSaugustss 				hi = c->next;
3781fd2ced0Sjakllsch 				if (hi == NULL)
3791fd2ced0Sjakllsch 					break;
3808ac1932eSaugustss 				s->cur = *hi;
3818ac1932eSaugustss 				free(hi);
3828ac1932eSaugustss 				break;
3838ac1932eSaugustss 			default:
3848ac1932eSaugustss 				return (-3);
3858ac1932eSaugustss 			}
3868ac1932eSaugustss 			break;
3878ac1932eSaugustss 		case 2:		/* Local */
3888ac1932eSaugustss 			switch (bTag) {
3898ac1932eSaugustss 			case 0:
3908ac1932eSaugustss 				c->usage = c->_usage_page | dval;
3918ac1932eSaugustss 				if (s->nusage < MAXUSAGE)
3928ac1932eSaugustss 					s->usages[s->nusage++] = c->usage;
3938ac1932eSaugustss 				/* else XXX */
3948ac1932eSaugustss 				break;
3958ac1932eSaugustss 			case 1:
3968ac1932eSaugustss 				s->minset = 1;
3978ac1932eSaugustss 				c->usage_minimum = c->_usage_page | dval;
3988ac1932eSaugustss 				break;
3998ac1932eSaugustss 			case 2:
4008ac1932eSaugustss 				c->usage_maximum = c->_usage_page | dval;
4018ac1932eSaugustss 				break;
4028ac1932eSaugustss 			case 3:
4038ac1932eSaugustss 				c->designator_index = dval;
4048ac1932eSaugustss 				break;
4058ac1932eSaugustss 			case 4:
4068ac1932eSaugustss 				c->designator_minimum = dval;
4078ac1932eSaugustss 				break;
4088ac1932eSaugustss 			case 5:
4098ac1932eSaugustss 				c->designator_maximum = dval;
4108ac1932eSaugustss 				break;
4118ac1932eSaugustss 			case 7:
4128ac1932eSaugustss 				c->string_index = dval;
4138ac1932eSaugustss 				break;
4148ac1932eSaugustss 			case 8:
4158ac1932eSaugustss 				c->string_minimum = dval;
4168ac1932eSaugustss 				break;
4178ac1932eSaugustss 			case 9:
4188ac1932eSaugustss 				c->string_maximum = dval;
4198ac1932eSaugustss 				break;
4208ac1932eSaugustss 			case 10:
4218ac1932eSaugustss 				c->set_delimiter = dval;
4228ac1932eSaugustss 				break;
4238ac1932eSaugustss 			default:
4248ac1932eSaugustss 				return (-4);
4258ac1932eSaugustss 			}
4268ac1932eSaugustss 			break;
4278ac1932eSaugustss 		default:
4288ac1932eSaugustss 			return (-5);
4298ac1932eSaugustss 		}
4308ac1932eSaugustss 	}
4318ac1932eSaugustss }
4328ac1932eSaugustss 
4338ac1932eSaugustss int
hid_report_size(report_desc_t r,enum hid_kind k,int id)4348ac1932eSaugustss hid_report_size(report_desc_t r, enum hid_kind k, int id)
4358ac1932eSaugustss {
4368ac1932eSaugustss 	struct hid_data *d;
4378ac1932eSaugustss 	hid_item_t h;
4388ac1932eSaugustss 	int size;
4398ac1932eSaugustss 
4408ac1932eSaugustss 	_DIAGASSERT(r != NULL);
4418ac1932eSaugustss 
4428ac1932eSaugustss 	memset(&h, 0, sizeof h);
4438ac1932eSaugustss 	size = 0;
4448ac1932eSaugustss 	for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) {
4458ac1932eSaugustss 		if (h.report_ID == id && h.kind == k) {
4468ac1932eSaugustss 			size = d->kindpos[k];
4478ac1932eSaugustss 		}
4488ac1932eSaugustss 	}
4498ac1932eSaugustss 	hid_end_parse(d);
4508ac1932eSaugustss 	return ((size + 7) / 8);
4518ac1932eSaugustss }
4528ac1932eSaugustss 
4538ac1932eSaugustss int
hid_locate(report_desc_t desc,unsigned int u,enum hid_kind k,hid_item_t * h,int id)4548ac1932eSaugustss hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k,
4558ac1932eSaugustss 	   hid_item_t *h, int id)
4568ac1932eSaugustss {
4578ac1932eSaugustss 	hid_data_t d;
4588ac1932eSaugustss 
4598ac1932eSaugustss 	_DIAGASSERT(desc != NULL);
4608ac1932eSaugustss 	_DIAGASSERT(h != NULL);
4618ac1932eSaugustss 
4628ac1932eSaugustss 	for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) {
4638ac1932eSaugustss 		if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) {
4648ac1932eSaugustss 			hid_end_parse(d);
4658ac1932eSaugustss 			return (1);
4668ac1932eSaugustss 		}
4678ac1932eSaugustss 	}
4688ac1932eSaugustss 	hid_end_parse(d);
4698ac1932eSaugustss 	h->report_size = 0;
4708ac1932eSaugustss 	return (0);
4718ac1932eSaugustss }
472