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