xref: /freebsd/lib/libusbhid/parse.c (revision cf0e07e504093d39ee5a0782b88ad372a9893643)
1b425e319SNick Hibma /*	$NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $	*/
29e2046dfSNick Hibma 
39e2046dfSNick Hibma /*
4cf0e07e5SMatthew N. Dodd  * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org>
59e2046dfSNick Hibma  * All rights reserved.
69e2046dfSNick Hibma  *
79e2046dfSNick Hibma  * Redistribution and use in source and binary forms, with or without
89e2046dfSNick Hibma  * modification, are permitted provided that the following conditions
99e2046dfSNick Hibma  * are met:
109e2046dfSNick Hibma  * 1. Redistributions of source code must retain the above copyright
119e2046dfSNick Hibma  *    notice, this list of conditions and the following disclaimer.
129e2046dfSNick Hibma  * 2. Redistributions in binary form must reproduce the above copyright
139e2046dfSNick Hibma  *    notice, this list of conditions and the following disclaimer in the
149e2046dfSNick Hibma  *    documentation and/or other materials provided with the distribution.
159e2046dfSNick Hibma  *
169e2046dfSNick Hibma  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
179e2046dfSNick Hibma  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
189e2046dfSNick Hibma  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199e2046dfSNick Hibma  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
209e2046dfSNick Hibma  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219e2046dfSNick Hibma  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
229e2046dfSNick Hibma  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
239e2046dfSNick Hibma  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249e2046dfSNick Hibma  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
259e2046dfSNick Hibma  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
269e2046dfSNick Hibma  * SUCH DAMAGE.
279e2046dfSNick Hibma  */
289e2046dfSNick Hibma 
29209040d8SMatthew Dillon #include <sys/cdefs.h>
30209040d8SMatthew Dillon __FBSDID("$FreeBSD$");
31209040d8SMatthew Dillon 
329e2046dfSNick Hibma #include <assert.h>
339e2046dfSNick Hibma #include <stdlib.h>
349e2046dfSNick Hibma #include <string.h>
359e2046dfSNick Hibma #include <sys/time.h>
369e2046dfSNick Hibma 
379e2046dfSNick Hibma #include <dev/usb/usb.h>
389e2046dfSNick Hibma #include <dev/usb/usbhid.h>
399e2046dfSNick Hibma 
40cf0e07e5SMatthew N. Dodd #include "usbhid.h"
419e2046dfSNick Hibma #include "usbvar.h"
429e2046dfSNick Hibma 
439e2046dfSNick Hibma #define MAXUSAGE 100
449e2046dfSNick Hibma struct hid_data {
459e2046dfSNick Hibma 	u_char *start;
469e2046dfSNick Hibma 	u_char *end;
479e2046dfSNick Hibma 	u_char *p;
489e2046dfSNick Hibma 	hid_item_t cur;
499e2046dfSNick Hibma 	unsigned int usages[MAXUSAGE];
509e2046dfSNick Hibma 	int nusage;
519e2046dfSNick Hibma 	int minset;
52cf0e07e5SMatthew N. Dodd 	int logminsize;
539e2046dfSNick Hibma 	int multi;
549e2046dfSNick Hibma 	int multimax;
559e2046dfSNick Hibma 	int kindset;
56cf0e07e5SMatthew N. Dodd 	int reportid;
57b425e319SNick Hibma 
58cf0e07e5SMatthew N. Dodd 	/*
59cf0e07e5SMatthew N. Dodd 	 * The start of collection item has no report ID set, so save
60cf0e07e5SMatthew N. Dodd 	 * it until we know the ID.
61cf0e07e5SMatthew N. Dodd 	 */
62cf0e07e5SMatthew N. Dodd 	hid_item_t savedcoll;
63cf0e07e5SMatthew N. Dodd 	u_char hassavedcoll;
64cf0e07e5SMatthew N. Dodd 	/*
65cf0e07e5SMatthew N. Dodd 	 * Absolute data position (bits) for input/output/feature.
66cf0e07e5SMatthew N. Dodd 	 *  Assumes that hid_input, hid_output and hid_feature have
67cf0e07e5SMatthew N. Dodd 	 *  values 0, 1 and 2.
68cf0e07e5SMatthew N. Dodd 	 */
69b425e319SNick Hibma 	unsigned int kindpos[3];
709e2046dfSNick Hibma };
719e2046dfSNick Hibma 
729e2046dfSNick Hibma static int min(int x, int y) { return x < y ? x : y; }
739e2046dfSNick Hibma 
74cf0e07e5SMatthew N. Dodd static int hid_get_item_raw(hid_data_t s, hid_item_t *h);
75cf0e07e5SMatthew N. Dodd 
769e2046dfSNick Hibma static void
779e2046dfSNick Hibma hid_clear_local(hid_item_t *c)
789e2046dfSNick Hibma {
799e2046dfSNick Hibma 	c->usage = 0;
809e2046dfSNick Hibma 	c->usage_minimum = 0;
819e2046dfSNick Hibma 	c->usage_maximum = 0;
829e2046dfSNick Hibma 	c->designator_index = 0;
839e2046dfSNick Hibma 	c->designator_minimum = 0;
849e2046dfSNick Hibma 	c->designator_maximum = 0;
859e2046dfSNick Hibma 	c->string_index = 0;
869e2046dfSNick Hibma 	c->string_minimum = 0;
879e2046dfSNick Hibma 	c->string_maximum = 0;
889e2046dfSNick Hibma 	c->set_delimiter = 0;
89234e6b87SMatthew N. Dodd 	c->report_size = 0;
909e2046dfSNick Hibma }
919e2046dfSNick Hibma 
929e2046dfSNick Hibma hid_data_t
93cf0e07e5SMatthew N. Dodd hid_start_parse(report_desc_t d, int kindset, int id)
949e2046dfSNick Hibma {
959e2046dfSNick Hibma 	struct hid_data *s;
969e2046dfSNick Hibma 
979e2046dfSNick Hibma 	s = malloc(sizeof *s);
989e2046dfSNick Hibma 	memset(s, 0, sizeof *s);
999e2046dfSNick Hibma 	s->start = s->p = d->data;
1009e2046dfSNick Hibma 	s->end = d->data + d->size;
1019e2046dfSNick Hibma 	s->kindset = kindset;
102cf0e07e5SMatthew N. Dodd 	s->reportid = id;
103cf0e07e5SMatthew N. Dodd 	s->hassavedcoll = 0;
1049e2046dfSNick Hibma 	return (s);
1059e2046dfSNick Hibma }
1069e2046dfSNick Hibma 
1079e2046dfSNick Hibma void
1089e2046dfSNick Hibma hid_end_parse(hid_data_t s)
1099e2046dfSNick Hibma {
1109e2046dfSNick Hibma 	while (s->cur.next) {
1119e2046dfSNick Hibma 		hid_item_t *hi = s->cur.next->next;
1129e2046dfSNick Hibma 		free(s->cur.next);
1139e2046dfSNick Hibma 		s->cur.next = hi;
1149e2046dfSNick Hibma 	}
1159e2046dfSNick Hibma 	free(s);
1169e2046dfSNick Hibma }
1179e2046dfSNick Hibma 
1189e2046dfSNick Hibma int
1199e2046dfSNick Hibma hid_get_item(hid_data_t s, hid_item_t *h)
1209e2046dfSNick Hibma {
121cf0e07e5SMatthew N. Dodd 	int r;
122cf0e07e5SMatthew N. Dodd 
123cf0e07e5SMatthew N. Dodd 	for (;;) {
124cf0e07e5SMatthew N. Dodd 		r = hid_get_item_raw(s, h);
125cf0e07e5SMatthew N. Dodd 		if (r <= 0)
126cf0e07e5SMatthew N. Dodd 			break;
127cf0e07e5SMatthew N. Dodd 		if (h->report_ID == s->reportid || s->reportid == -1)
128cf0e07e5SMatthew N. Dodd 			break;
129cf0e07e5SMatthew N. Dodd 	}
130cf0e07e5SMatthew N. Dodd 	return (r);
131cf0e07e5SMatthew N. Dodd }
132cf0e07e5SMatthew N. Dodd 
133cf0e07e5SMatthew N. Dodd #define REPORT_SAVED_COLL \
134cf0e07e5SMatthew N. Dodd 	do { \
135cf0e07e5SMatthew N. Dodd 		if (s->hassavedcoll) { \
136cf0e07e5SMatthew N. Dodd 			*h = s->savedcoll; \
137cf0e07e5SMatthew N. Dodd 			h->report_ID = c->report_ID; \
138cf0e07e5SMatthew N. Dodd 			s->hassavedcoll = 0; \
139cf0e07e5SMatthew N. Dodd 			return (1); \
140cf0e07e5SMatthew N. Dodd 		} \
141cf0e07e5SMatthew N. Dodd 	} while(/*LINTED*/ 0)
142cf0e07e5SMatthew N. Dodd 
143cf0e07e5SMatthew N. Dodd static int
144cf0e07e5SMatthew N. Dodd hid_get_item_raw(hid_data_t s, hid_item_t *h)
145cf0e07e5SMatthew N. Dodd {
1469e2046dfSNick Hibma 	hid_item_t *c;
147b425e319SNick Hibma 	unsigned int bTag = 0, bType = 0, bSize;
1489e2046dfSNick Hibma 	unsigned char *data;
1499e2046dfSNick Hibma 	int dval;
1509e2046dfSNick Hibma 	unsigned char *p;
1519e2046dfSNick Hibma 	hid_item_t *hi;
152cf0e07e5SMatthew N. Dodd 	hid_item_t nc;
1539e2046dfSNick Hibma 	int i;
154b425e319SNick Hibma 	hid_kind_t retkind;
1559e2046dfSNick Hibma 
1569e2046dfSNick Hibma 	c = &s->cur;
1579e2046dfSNick Hibma 
1589e2046dfSNick Hibma  top:
1599e2046dfSNick Hibma 	if (s->multimax) {
160cf0e07e5SMatthew N. Dodd 		REPORT_SAVED_COLL;
161cf0e07e5SMatthew N. Dodd 		if (c->logical_minimum >= c->logical_maximum) {
162cf0e07e5SMatthew N. Dodd 			if (s->logminsize == 1)
163cf0e07e5SMatthew N. Dodd 				c->logical_minimum =(int8_t)c->logical_minimum;
164cf0e07e5SMatthew N. Dodd 			else if (s->logminsize == 2)
165cf0e07e5SMatthew N. Dodd 				c->logical_minimum =(int16_t)c->logical_minimum;
166cf0e07e5SMatthew N. Dodd 		}
1679e2046dfSNick Hibma 		if (s->multi < s->multimax) {
1689e2046dfSNick Hibma 			c->usage = s->usages[min(s->multi, s->nusage-1)];
1699e2046dfSNick Hibma 			s->multi++;
1709e2046dfSNick Hibma 			*h = *c;
171cf0e07e5SMatthew N. Dodd 			/*
172cf0e07e5SMatthew N. Dodd 			 * 'multimax' is only non-zero if the current
173cf0e07e5SMatthew N. Dodd                          *  item kind is input/output/feature
174cf0e07e5SMatthew N. Dodd 			 */
175b425e319SNick Hibma 			h->pos = s->kindpos[c->kind];
176b425e319SNick Hibma 			s->kindpos[c->kind] += c->report_size;
1779e2046dfSNick Hibma 			h->next = 0;
1789e2046dfSNick Hibma 			return (1);
1799e2046dfSNick Hibma 		} else {
1809e2046dfSNick Hibma 			c->report_count = s->multimax;
1819e2046dfSNick Hibma 			s->multimax = 0;
1829e2046dfSNick Hibma 			s->nusage = 0;
1839e2046dfSNick Hibma 			hid_clear_local(c);
1849e2046dfSNick Hibma 		}
1859e2046dfSNick Hibma 	}
1869e2046dfSNick Hibma 	for (;;) {
1879e2046dfSNick Hibma 		p = s->p;
1889e2046dfSNick Hibma 		if (p >= s->end)
1899e2046dfSNick Hibma 			return (0);
1909e2046dfSNick Hibma 
1919e2046dfSNick Hibma 		bSize = *p++;
1929e2046dfSNick Hibma 		if (bSize == 0xfe) {
1939e2046dfSNick Hibma 			/* long item */
1949e2046dfSNick Hibma 			bSize = *p++;
1959e2046dfSNick Hibma 			bSize |= *p++ << 8;
1969e2046dfSNick Hibma 			bTag = *p++;
1979e2046dfSNick Hibma 			data = p;
1989e2046dfSNick Hibma 			p += bSize;
1999e2046dfSNick Hibma 		} else {
2009e2046dfSNick Hibma 			/* short item */
2019e2046dfSNick Hibma 			bTag = bSize >> 4;
2029e2046dfSNick Hibma 			bType = (bSize >> 2) & 3;
2039e2046dfSNick Hibma 			bSize &= 3;
2049e2046dfSNick Hibma 			if (bSize == 3) bSize = 4;
2059e2046dfSNick Hibma 			data = p;
2069e2046dfSNick Hibma 			p += bSize;
2079e2046dfSNick Hibma 		}
2089e2046dfSNick Hibma 		s->p = p;
2099e2046dfSNick Hibma 		/*
2109e2046dfSNick Hibma 		 * The spec is unclear if the data is signed or unsigned.
2119e2046dfSNick Hibma 		 */
2129e2046dfSNick Hibma 		switch(bSize) {
2139e2046dfSNick Hibma 		case 0:
2149e2046dfSNick Hibma 			dval = 0;
2159e2046dfSNick Hibma 			break;
2169e2046dfSNick Hibma 		case 1:
2179e2046dfSNick Hibma 			dval = (int8_t)*data++;
2189e2046dfSNick Hibma 			break;
2199e2046dfSNick Hibma 		case 2:
2209e2046dfSNick Hibma 			dval = *data++;
2219e2046dfSNick Hibma 			dval |= *data++ << 8;
2229e2046dfSNick Hibma 			dval = (int16_t)dval;
2239e2046dfSNick Hibma 			break;
2249e2046dfSNick Hibma 		case 4:
2259e2046dfSNick Hibma 			dval = *data++;
2269e2046dfSNick Hibma 			dval |= *data++ << 8;
2279e2046dfSNick Hibma 			dval |= *data++ << 16;
2289e2046dfSNick Hibma 			dval |= *data++ << 24;
2299e2046dfSNick Hibma 			break;
2309e2046dfSNick Hibma 		default:
2319e2046dfSNick Hibma 			return (-1);
2329e2046dfSNick Hibma 		}
2339e2046dfSNick Hibma 
2349e2046dfSNick Hibma 		switch (bType) {
2359e2046dfSNick Hibma 		case 0:			/* Main */
2369e2046dfSNick Hibma 			switch (bTag) {
2379e2046dfSNick Hibma 			case 8:		/* Input */
238b425e319SNick Hibma 				retkind = hid_input;
2399e2046dfSNick Hibma 			ret:
240b425e319SNick Hibma 				if (!(s->kindset & (1 << retkind))) {
241b425e319SNick Hibma 					/* Drop the items of this kind */
242b425e319SNick Hibma 					s->nusage = 0;
243b425e319SNick Hibma 					continue;
244b425e319SNick Hibma 				}
245b425e319SNick Hibma 				c->kind = retkind;
246b425e319SNick Hibma 				c->flags = dval;
2479e2046dfSNick Hibma 				if (c->flags & HIO_VARIABLE) {
2489e2046dfSNick Hibma 					s->multimax = c->report_count;
2499e2046dfSNick Hibma 					s->multi = 0;
2509e2046dfSNick Hibma 					c->report_count = 1;
2519e2046dfSNick Hibma 					if (s->minset) {
2529e2046dfSNick Hibma 						for (i = c->usage_minimum;
2539e2046dfSNick Hibma 						     i <= c->usage_maximum;
2549e2046dfSNick Hibma 						     i++) {
2559e2046dfSNick Hibma 							s->usages[s->nusage] = i;
2569e2046dfSNick Hibma 							if (s->nusage < MAXUSAGE-1)
2579e2046dfSNick Hibma 								s->nusage++;
2589e2046dfSNick Hibma 						}
259cf0e07e5SMatthew N. Dodd 						c->usage_minimum = 0;
260cf0e07e5SMatthew N. Dodd 						c->usage_maximum = 0;
2619e2046dfSNick Hibma 						s->minset = 0;
2629e2046dfSNick Hibma 					}
2639e2046dfSNick Hibma 					goto top;
2649e2046dfSNick Hibma 				} else {
2659e2046dfSNick Hibma 					if (s->minset)
2669e2046dfSNick Hibma 						c->usage = c->usage_minimum;
2679e2046dfSNick Hibma 					*h = *c;
2689e2046dfSNick Hibma 					h->next = 0;
269b425e319SNick Hibma 					h->pos = s->kindpos[c->kind];
270cf0e07e5SMatthew N. Dodd 					s->kindpos[c->kind] +=
271cf0e07e5SMatthew N. Dodd 					    c->report_size * c->report_count;
2729e2046dfSNick Hibma 					hid_clear_local(c);
2739e2046dfSNick Hibma 					s->minset = 0;
2749e2046dfSNick Hibma 					return (1);
2759e2046dfSNick Hibma 				}
2769e2046dfSNick Hibma 			case 9:		/* Output */
277b425e319SNick Hibma 				retkind = hid_output;
2789e2046dfSNick Hibma 				goto ret;
2799e2046dfSNick Hibma 			case 10:	/* Collection */
2809e2046dfSNick Hibma 				c->kind = hid_collection;
2819e2046dfSNick Hibma 				c->collection = dval;
2829e2046dfSNick Hibma 				c->collevel++;
283cf0e07e5SMatthew N. Dodd 				nc = *c;
2849e2046dfSNick Hibma 				hid_clear_local(c);
285cf0e07e5SMatthew N. Dodd 				/*c->report_ID = NO_REPORT_ID;*/
2869e2046dfSNick Hibma 				s->nusage = 0;
287cf0e07e5SMatthew N. Dodd 				if (s->hassavedcoll) {
288cf0e07e5SMatthew N. Dodd 					*h = s->savedcoll;
289cf0e07e5SMatthew N. Dodd 					h->report_ID = nc.report_ID;
290cf0e07e5SMatthew N. Dodd 					s->savedcoll = nc;
2919e2046dfSNick Hibma 					return (1);
292cf0e07e5SMatthew N. Dodd 				} else {
293cf0e07e5SMatthew N. Dodd 					s->hassavedcoll = 1;
294cf0e07e5SMatthew N. Dodd 					s->savedcoll = nc;
295cf0e07e5SMatthew N. Dodd 				}
296cf0e07e5SMatthew N. Dodd 				break;
2979e2046dfSNick Hibma 			case 11:	/* Feature */
298b425e319SNick Hibma 				retkind = hid_feature;
2999e2046dfSNick Hibma 				goto ret;
3009e2046dfSNick Hibma 			case 12:	/* End collection */
301cf0e07e5SMatthew N. Dodd 				REPORT_SAVED_COLL;
3029e2046dfSNick Hibma 				c->kind = hid_endcollection;
3039e2046dfSNick Hibma 				c->collevel--;
3049e2046dfSNick Hibma 				*h = *c;
3059e2046dfSNick Hibma 				/*hid_clear_local(c);*/
3069e2046dfSNick Hibma 				s->nusage = 0;
3079e2046dfSNick Hibma 				return (1);
3089e2046dfSNick Hibma 			default:
3099e2046dfSNick Hibma 				return (-2);
3109e2046dfSNick Hibma 			}
311cf0e07e5SMatthew N. Dodd 			break;
3129e2046dfSNick Hibma 
3139e2046dfSNick Hibma 		case 1:		/* Global */
3149e2046dfSNick Hibma 			switch (bTag) {
3159e2046dfSNick Hibma 			case 0:
3169e2046dfSNick Hibma 				c->_usage_page = dval << 16;
3179e2046dfSNick Hibma 				break;
3189e2046dfSNick Hibma 			case 1:
3199e2046dfSNick Hibma 				c->logical_minimum = dval;
320cf0e07e5SMatthew N. Dodd 				s->logminsize = bSize;
3219e2046dfSNick Hibma 				break;
3229e2046dfSNick Hibma 			case 2:
3239e2046dfSNick Hibma 				c->logical_maximum = dval;
3249e2046dfSNick Hibma 				break;
3259e2046dfSNick Hibma 			case 3:
3269e2046dfSNick Hibma 				c->physical_maximum = dval;
3279e2046dfSNick Hibma 				break;
3289e2046dfSNick Hibma 			case 4:
3299e2046dfSNick Hibma 				c->physical_maximum = dval;
3309e2046dfSNick Hibma 				break;
3319e2046dfSNick Hibma 			case 5:
3329e2046dfSNick Hibma 				c->unit_exponent = dval;
3339e2046dfSNick Hibma 				break;
3349e2046dfSNick Hibma 			case 6:
3359e2046dfSNick Hibma 				c->unit = dval;
3369e2046dfSNick Hibma 				break;
3379e2046dfSNick Hibma 			case 7:
3389e2046dfSNick Hibma 				c->report_size = dval;
3399e2046dfSNick Hibma 				break;
3409e2046dfSNick Hibma 			case 8:
3419e2046dfSNick Hibma 				c->report_ID = dval;
342cf0e07e5SMatthew N. Dodd 				s->kindpos[hid_input] =
343cf0e07e5SMatthew N. Dodd 				    s->kindpos[hid_output] =
344cf0e07e5SMatthew N. Dodd 				    s->kindpos[hid_feature] = 0;
3459e2046dfSNick Hibma 				break;
3469e2046dfSNick Hibma 			case 9:
3479e2046dfSNick Hibma 				c->report_count = dval;
3489e2046dfSNick Hibma 				break;
3499e2046dfSNick Hibma 			case 10: /* Push */
3509e2046dfSNick Hibma 				hi = malloc(sizeof *hi);
3519e2046dfSNick Hibma 				*hi = s->cur;
3529e2046dfSNick Hibma 				c->next = hi;
3539e2046dfSNick Hibma 				break;
3549e2046dfSNick Hibma 			case 11: /* Pop */
3559e2046dfSNick Hibma 				hi = c->next;
3569e2046dfSNick Hibma 				s->cur = *hi;
3579e2046dfSNick Hibma 				free(hi);
3589e2046dfSNick Hibma 				break;
3599e2046dfSNick Hibma 			default:
3609e2046dfSNick Hibma 				return (-3);
3619e2046dfSNick Hibma 			}
3629e2046dfSNick Hibma 			break;
3639e2046dfSNick Hibma 		case 2:		/* Local */
3649e2046dfSNick Hibma 			switch (bTag) {
3659e2046dfSNick Hibma 			case 0:
366cf0e07e5SMatthew N. Dodd 				c->usage = c->_usage_page | dval;
3679e2046dfSNick Hibma 				if (s->nusage < MAXUSAGE)
368cf0e07e5SMatthew N. Dodd 					s->usages[s->nusage++] = c->usage;
3699e2046dfSNick Hibma 				/* else XXX */
3709e2046dfSNick Hibma 				break;
3719e2046dfSNick Hibma 			case 1:
3729e2046dfSNick Hibma 				s->minset = 1;
373cf0e07e5SMatthew N. Dodd 				c->usage_minimum = c->_usage_page | dval;
3749e2046dfSNick Hibma 				break;
3759e2046dfSNick Hibma 			case 2:
376cf0e07e5SMatthew N. Dodd 				c->usage_maximum = c->_usage_page | dval;
3779e2046dfSNick Hibma 				break;
3789e2046dfSNick Hibma 			case 3:
3799e2046dfSNick Hibma 				c->designator_index = dval;
3809e2046dfSNick Hibma 				break;
3819e2046dfSNick Hibma 			case 4:
3829e2046dfSNick Hibma 				c->designator_minimum = dval;
3839e2046dfSNick Hibma 				break;
3849e2046dfSNick Hibma 			case 5:
3859e2046dfSNick Hibma 				c->designator_maximum = dval;
3869e2046dfSNick Hibma 				break;
3879e2046dfSNick Hibma 			case 7:
3889e2046dfSNick Hibma 				c->string_index = dval;
3899e2046dfSNick Hibma 				break;
3909e2046dfSNick Hibma 			case 8:
3919e2046dfSNick Hibma 				c->string_minimum = dval;
3929e2046dfSNick Hibma 				break;
3939e2046dfSNick Hibma 			case 9:
3949e2046dfSNick Hibma 				c->string_maximum = dval;
3959e2046dfSNick Hibma 				break;
3969e2046dfSNick Hibma 			case 10:
3979e2046dfSNick Hibma 				c->set_delimiter = dval;
3989e2046dfSNick Hibma 				break;
3999e2046dfSNick Hibma 			default:
4009e2046dfSNick Hibma 				return (-4);
4019e2046dfSNick Hibma 			}
4029e2046dfSNick Hibma 			break;
4039e2046dfSNick Hibma 		default:
4049e2046dfSNick Hibma 			return (-5);
4059e2046dfSNick Hibma 		}
4069e2046dfSNick Hibma 	}
4079e2046dfSNick Hibma }
4089e2046dfSNick Hibma 
4099e2046dfSNick Hibma int
410cf0e07e5SMatthew N. Dodd hid_report_size(report_desc_t r, enum hid_kind k, int id)
4119e2046dfSNick Hibma {
4129e2046dfSNick Hibma 	struct hid_data *d;
4139e2046dfSNick Hibma 	hid_item_t h;
414cf0e07e5SMatthew N. Dodd 	int size;
4159e2046dfSNick Hibma 
4169e2046dfSNick Hibma 	memset(&h, 0, sizeof h);
417cf0e07e5SMatthew N. Dodd 	size = 0;
418cf0e07e5SMatthew N. Dodd 	for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) {
419b425e319SNick Hibma 		if (h.report_ID == id && h.kind == k) {
420cf0e07e5SMatthew N. Dodd 			size = d->kindpos[k];
4219e2046dfSNick Hibma 		}
4229e2046dfSNick Hibma 	}
4239e2046dfSNick Hibma 	hid_end_parse(d);
424cf0e07e5SMatthew N. Dodd 	return ((size + 7) / 8);
4259e2046dfSNick Hibma }
4269e2046dfSNick Hibma 
4279e2046dfSNick Hibma int
428cf0e07e5SMatthew N. Dodd hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k,
429cf0e07e5SMatthew N. Dodd 	   hid_item_t *h, int id)
4309e2046dfSNick Hibma {
4319e2046dfSNick Hibma 	hid_data_t d;
4329e2046dfSNick Hibma 
433cf0e07e5SMatthew N. Dodd 	for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) {
4349e2046dfSNick Hibma 		if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) {
4359e2046dfSNick Hibma 			hid_end_parse(d);
4369e2046dfSNick Hibma 			return (1);
4379e2046dfSNick Hibma 		}
4389e2046dfSNick Hibma 	}
4399e2046dfSNick Hibma 	hid_end_parse(d);
4409e2046dfSNick Hibma 	h->report_size = 0;
4419e2046dfSNick Hibma 	return (0);
4429e2046dfSNick Hibma }
443