1b425e319SNick Hibma /* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */ 29e2046dfSNick Hibma 3*5e53a4f9SPedro F. Giffuni /*- 4*5e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5*5e53a4f9SPedro F. Giffuni * 6cf0e07e5SMatthew N. Dodd * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org> 79e2046dfSNick Hibma * All rights reserved. 89e2046dfSNick Hibma * 99e2046dfSNick Hibma * Redistribution and use in source and binary forms, with or without 109e2046dfSNick Hibma * modification, are permitted provided that the following conditions 119e2046dfSNick Hibma * are met: 129e2046dfSNick Hibma * 1. Redistributions of source code must retain the above copyright 139e2046dfSNick Hibma * notice, this list of conditions and the following disclaimer. 149e2046dfSNick Hibma * 2. Redistributions in binary form must reproduce the above copyright 159e2046dfSNick Hibma * notice, this list of conditions and the following disclaimer in the 169e2046dfSNick Hibma * documentation and/or other materials provided with the distribution. 179e2046dfSNick Hibma * 189e2046dfSNick Hibma * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 199e2046dfSNick Hibma * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 209e2046dfSNick Hibma * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 219e2046dfSNick Hibma * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 229e2046dfSNick Hibma * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 239e2046dfSNick Hibma * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 249e2046dfSNick Hibma * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 259e2046dfSNick Hibma * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 269e2046dfSNick Hibma * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 279e2046dfSNick Hibma * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 289e2046dfSNick Hibma * SUCH DAMAGE. 299e2046dfSNick Hibma */ 309e2046dfSNick Hibma 31209040d8SMatthew Dillon #include <sys/cdefs.h> 32209040d8SMatthew Dillon __FBSDID("$FreeBSD$"); 33209040d8SMatthew Dillon 349e2046dfSNick Hibma #include <assert.h> 359e2046dfSNick Hibma #include <stdlib.h> 369e2046dfSNick Hibma #include <string.h> 379e2046dfSNick Hibma #include <sys/time.h> 389e2046dfSNick Hibma 399e2046dfSNick Hibma #include <dev/usb/usb.h> 409e2046dfSNick Hibma #include <dev/usb/usbhid.h> 419e2046dfSNick Hibma 42cf0e07e5SMatthew N. Dodd #include "usbhid.h" 439e2046dfSNick Hibma #include "usbvar.h" 449e2046dfSNick Hibma 459e2046dfSNick Hibma #define MAXUSAGE 100 46cde58781SKai Wang #define MAXPUSH 4 47cde58781SKai Wang #define MAXID 64 487778ab7eSAlexander Motin #define ITEMTYPES 3 49b425e319SNick Hibma 50cde58781SKai Wang struct hid_pos_data { 51cde58781SKai Wang int32_t rid; 527778ab7eSAlexander Motin uint32_t pos[ITEMTYPES]; 539e2046dfSNick Hibma }; 549e2046dfSNick Hibma 55cde58781SKai Wang struct hid_data { 56cde58781SKai Wang const uint8_t *start; 57cde58781SKai Wang const uint8_t *end; 58cde58781SKai Wang const uint8_t *p; 59cde58781SKai Wang struct hid_item cur[MAXPUSH]; 60cde58781SKai Wang struct hid_pos_data last_pos[MAXID]; 617778ab7eSAlexander Motin uint32_t pos[ITEMTYPES]; 62cde58781SKai Wang int32_t usages_min[MAXUSAGE]; 63cde58781SKai Wang int32_t usages_max[MAXUSAGE]; 64cde58781SKai Wang int32_t usage_last; /* last seen usage */ 65cde58781SKai Wang uint32_t loc_size; /* last seen size */ 66cde58781SKai Wang uint32_t loc_count; /* last seen count */ 67cde58781SKai Wang uint8_t kindset; /* we have 5 kinds so 8 bits are enough */ 68cde58781SKai Wang uint8_t pushlevel; /* current pushlevel */ 69cde58781SKai Wang uint8_t ncount; /* end usage item count */ 70cde58781SKai Wang uint8_t icount; /* current usage item count */ 71cde58781SKai Wang uint8_t nusage; /* end "usages_min/max" index */ 72cde58781SKai Wang uint8_t iusage; /* current "usages_min/max" index */ 73cde58781SKai Wang uint8_t ousage; /* current "usages_min/max" offset */ 74cde58781SKai Wang uint8_t susage; /* usage set flags */ 75ec9b9fbdSAlexander Motin int32_t reportid; /* requested report ID */ 76cde58781SKai Wang }; 779e2046dfSNick Hibma 78cde58781SKai Wang /*------------------------------------------------------------------------* 79cde58781SKai Wang * hid_clear_local 80cde58781SKai Wang *------------------------------------------------------------------------*/ 819e2046dfSNick Hibma static void 829e2046dfSNick Hibma hid_clear_local(hid_item_t *c) 839e2046dfSNick Hibma { 84cde58781SKai Wang 859e2046dfSNick Hibma c->usage = 0; 869e2046dfSNick Hibma c->usage_minimum = 0; 879e2046dfSNick Hibma c->usage_maximum = 0; 889e2046dfSNick Hibma c->designator_index = 0; 899e2046dfSNick Hibma c->designator_minimum = 0; 909e2046dfSNick Hibma c->designator_maximum = 0; 919e2046dfSNick Hibma c->string_index = 0; 929e2046dfSNick Hibma c->string_minimum = 0; 939e2046dfSNick Hibma c->string_maximum = 0; 949e2046dfSNick Hibma c->set_delimiter = 0; 959e2046dfSNick Hibma } 969e2046dfSNick Hibma 97cde58781SKai Wang static void 98cde58781SKai Wang hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID) 99cde58781SKai Wang { 1007778ab7eSAlexander Motin uint8_t i, j; 101cde58781SKai Wang 102cde58781SKai Wang /* check for same report ID - optimise */ 103cde58781SKai Wang 104cde58781SKai Wang if (c->report_ID == next_rID) 105cde58781SKai Wang return; 106cde58781SKai Wang 107cde58781SKai Wang /* save current position for current rID */ 108cde58781SKai Wang 109cde58781SKai Wang if (c->report_ID == 0) { 110cde58781SKai Wang i = 0; 111cde58781SKai Wang } else { 112cde58781SKai Wang for (i = 1; i != MAXID; i++) { 113cde58781SKai Wang if (s->last_pos[i].rid == c->report_ID) 114cde58781SKai Wang break; 115cde58781SKai Wang if (s->last_pos[i].rid == 0) 116cde58781SKai Wang break; 117cde58781SKai Wang } 118cde58781SKai Wang } 119cde58781SKai Wang if (i != MAXID) { 120cde58781SKai Wang s->last_pos[i].rid = c->report_ID; 1217778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1227778ab7eSAlexander Motin s->last_pos[i].pos[j] = s->pos[j]; 123cde58781SKai Wang } 124cde58781SKai Wang 125cde58781SKai Wang /* store next report ID */ 126cde58781SKai Wang 127cde58781SKai Wang c->report_ID = next_rID; 128cde58781SKai Wang 129cde58781SKai Wang /* lookup last position for next rID */ 130cde58781SKai Wang 131cde58781SKai Wang if (next_rID == 0) { 132cde58781SKai Wang i = 0; 133cde58781SKai Wang } else { 134cde58781SKai Wang for (i = 1; i != MAXID; i++) { 135cde58781SKai Wang if (s->last_pos[i].rid == next_rID) 136cde58781SKai Wang break; 137cde58781SKai Wang if (s->last_pos[i].rid == 0) 138cde58781SKai Wang break; 139cde58781SKai Wang } 140cde58781SKai Wang } 141cde58781SKai Wang if (i != MAXID) { 142cde58781SKai Wang s->last_pos[i].rid = next_rID; 1437778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1447778ab7eSAlexander Motin s->pos[j] = s->last_pos[i].pos[j]; 1457778ab7eSAlexander Motin } else { 1467778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1477778ab7eSAlexander Motin s->pos[j] = 0; /* Out of RID entries. */ 1487778ab7eSAlexander Motin } 149cde58781SKai Wang } 150cde58781SKai Wang 151cde58781SKai Wang /*------------------------------------------------------------------------* 152cde58781SKai Wang * hid_start_parse 153cde58781SKai Wang *------------------------------------------------------------------------*/ 1549e2046dfSNick Hibma hid_data_t 155ec9b9fbdSAlexander Motin hid_start_parse(report_desc_t d, int kindset, int id) 1569e2046dfSNick Hibma { 1579e2046dfSNick Hibma struct hid_data *s; 1589e2046dfSNick Hibma 1599e2046dfSNick Hibma s = malloc(sizeof *s); 1609e2046dfSNick Hibma memset(s, 0, sizeof *s); 1619e2046dfSNick Hibma s->start = s->p = d->data; 1629e2046dfSNick Hibma s->end = d->data + d->size; 1639e2046dfSNick Hibma s->kindset = kindset; 164ec9b9fbdSAlexander Motin s->reportid = id; 1659e2046dfSNick Hibma return (s); 1669e2046dfSNick Hibma } 1679e2046dfSNick Hibma 168cde58781SKai Wang /*------------------------------------------------------------------------* 169cde58781SKai Wang * hid_end_parse 170cde58781SKai Wang *------------------------------------------------------------------------*/ 1719e2046dfSNick Hibma void 1729e2046dfSNick Hibma hid_end_parse(hid_data_t s) 1739e2046dfSNick Hibma { 174cde58781SKai Wang 175cde58781SKai Wang if (s == NULL) 176cde58781SKai Wang return; 177cde58781SKai Wang 1789e2046dfSNick Hibma free(s); 1799e2046dfSNick Hibma } 1809e2046dfSNick Hibma 181cde58781SKai Wang /*------------------------------------------------------------------------* 182cde58781SKai Wang * get byte from HID descriptor 183cde58781SKai Wang *------------------------------------------------------------------------*/ 184cde58781SKai Wang static uint8_t 185cde58781SKai Wang hid_get_byte(struct hid_data *s, const uint16_t wSize) 186cde58781SKai Wang { 187cde58781SKai Wang const uint8_t *ptr; 188cde58781SKai Wang uint8_t retval; 189cde58781SKai Wang 190cde58781SKai Wang ptr = s->p; 191cde58781SKai Wang 192cde58781SKai Wang /* check if end is reached */ 193cde58781SKai Wang if (ptr == s->end) 194cde58781SKai Wang return (0); 195cde58781SKai Wang 196cde58781SKai Wang /* read out a byte */ 197cde58781SKai Wang retval = *ptr; 198cde58781SKai Wang 199cde58781SKai Wang /* check if data pointer can be advanced by "wSize" bytes */ 200cde58781SKai Wang if ((s->end - ptr) < wSize) 201cde58781SKai Wang ptr = s->end; 202cde58781SKai Wang else 203cde58781SKai Wang ptr += wSize; 204cde58781SKai Wang 205cde58781SKai Wang /* update pointer */ 206cde58781SKai Wang s->p = ptr; 207cde58781SKai Wang 208cde58781SKai Wang return (retval); 209cde58781SKai Wang } 210cde58781SKai Wang 211cde58781SKai Wang /*------------------------------------------------------------------------* 212cde58781SKai Wang * hid_get_item 213cde58781SKai Wang *------------------------------------------------------------------------*/ 214ec9b9fbdSAlexander Motin static int 215ec9b9fbdSAlexander Motin hid_get_item_raw(hid_data_t s, hid_item_t *h) 2169e2046dfSNick Hibma { 2179e2046dfSNick Hibma hid_item_t *c; 218cde58781SKai Wang unsigned int bTag, bType, bSize; 219cde58781SKai Wang int32_t mask; 220cde58781SKai Wang int32_t dval; 2219e2046dfSNick Hibma 222cde58781SKai Wang if (s == NULL) 2239e2046dfSNick Hibma return (0); 2249e2046dfSNick Hibma 225cde58781SKai Wang c = &s->cur[s->pushlevel]; 226cde58781SKai Wang 227cde58781SKai Wang top: 228cde58781SKai Wang /* check if there is an array of items */ 229cde58781SKai Wang if (s->icount < s->ncount) { 230cde58781SKai Wang /* get current usage */ 231cde58781SKai Wang if (s->iusage < s->nusage) { 232cde58781SKai Wang dval = s->usages_min[s->iusage] + s->ousage; 233cde58781SKai Wang c->usage = dval; 234cde58781SKai Wang s->usage_last = dval; 235cde58781SKai Wang if (dval == s->usages_max[s->iusage]) { 236cde58781SKai Wang s->iusage ++; 237cde58781SKai Wang s->ousage = 0; 238cde58781SKai Wang } else { 239cde58781SKai Wang s->ousage ++; 240cde58781SKai Wang } 241cde58781SKai Wang } else { 242cde58781SKai Wang /* Using last usage */ 243cde58781SKai Wang dval = s->usage_last; 244cde58781SKai Wang } 245cde58781SKai Wang s->icount ++; 246cde58781SKai Wang /* 247cde58781SKai Wang * Only copy HID item, increment position and return 248cde58781SKai Wang * if correct kindset! 249cde58781SKai Wang */ 250cde58781SKai Wang if (s->kindset & (1 << c->kind)) { 251cde58781SKai Wang *h = *c; 2527778ab7eSAlexander Motin h->pos = s->pos[c->kind]; 2537778ab7eSAlexander Motin s->pos[c->kind] += c->report_size * c->report_count; 254cde58781SKai Wang return (1); 255cde58781SKai Wang } 256cde58781SKai Wang } 257cde58781SKai Wang 258cde58781SKai Wang /* reset state variables */ 259cde58781SKai Wang s->icount = 0; 260cde58781SKai Wang s->ncount = 0; 261cde58781SKai Wang s->iusage = 0; 262cde58781SKai Wang s->nusage = 0; 263cde58781SKai Wang s->susage = 0; 264cde58781SKai Wang s->ousage = 0; 265cde58781SKai Wang hid_clear_local(c); 266cde58781SKai Wang 267cde58781SKai Wang /* get next item */ 268cde58781SKai Wang while (s->p != s->end) { 269cde58781SKai Wang 270cde58781SKai Wang bSize = hid_get_byte(s, 1); 2719e2046dfSNick Hibma if (bSize == 0xfe) { 2729e2046dfSNick Hibma /* long item */ 273cde58781SKai Wang bSize = hid_get_byte(s, 1); 274cde58781SKai Wang bSize |= hid_get_byte(s, 1) << 8; 275cde58781SKai Wang bTag = hid_get_byte(s, 1); 276cde58781SKai Wang bType = 0xff; /* XXX what should it be */ 2779e2046dfSNick Hibma } else { 2789e2046dfSNick Hibma /* short item */ 2799e2046dfSNick Hibma bTag = bSize >> 4; 2809e2046dfSNick Hibma bType = (bSize >> 2) & 3; 2819e2046dfSNick Hibma bSize &= 3; 282cde58781SKai Wang if (bSize == 3) 283cde58781SKai Wang bSize = 4; 2849e2046dfSNick Hibma } 285cde58781SKai Wang 2869e2046dfSNick Hibma switch(bSize) { 2879e2046dfSNick Hibma case 0: 2889e2046dfSNick Hibma dval = 0; 289cde58781SKai Wang mask = 0; 2909e2046dfSNick Hibma break; 2919e2046dfSNick Hibma case 1: 292cde58781SKai Wang dval = (int8_t)hid_get_byte(s, 1); 293cde58781SKai Wang mask = 0xFF; 2949e2046dfSNick Hibma break; 2959e2046dfSNick Hibma case 2: 296cde58781SKai Wang dval = hid_get_byte(s, 1); 297cde58781SKai Wang dval |= hid_get_byte(s, 1) << 8; 298cde58781SKai Wang dval = (int16_t)dval; 299cde58781SKai Wang mask = 0xFFFF; 3009e2046dfSNick Hibma break; 3019e2046dfSNick Hibma case 4: 302cde58781SKai Wang dval = hid_get_byte(s, 1); 303cde58781SKai Wang dval |= hid_get_byte(s, 1) << 8; 304cde58781SKai Wang dval |= hid_get_byte(s, 1) << 16; 305cde58781SKai Wang dval |= hid_get_byte(s, 1) << 24; 306cde58781SKai Wang mask = 0xFFFFFFFF; 3079e2046dfSNick Hibma break; 3089e2046dfSNick Hibma default: 309cde58781SKai Wang dval = hid_get_byte(s, bSize); 310cde58781SKai Wang continue; 3119e2046dfSNick Hibma } 3129e2046dfSNick Hibma 3139e2046dfSNick Hibma switch (bType) { 3149e2046dfSNick Hibma case 0: /* Main */ 3159e2046dfSNick Hibma switch (bTag) { 3169e2046dfSNick Hibma case 8: /* Input */ 317cde58781SKai Wang c->kind = hid_input; 318b425e319SNick Hibma c->flags = dval; 319cde58781SKai Wang ret: 320cde58781SKai Wang c->report_count = s->loc_count; 321cde58781SKai Wang c->report_size = s->loc_size; 322cde58781SKai Wang 3239e2046dfSNick Hibma if (c->flags & HIO_VARIABLE) { 324cde58781SKai Wang /* range check usage count */ 325cde58781SKai Wang if (c->report_count > 255) { 326cde58781SKai Wang s->ncount = 255; 327cde58781SKai Wang } else 328cde58781SKai Wang s->ncount = c->report_count; 329cde58781SKai Wang 330cde58781SKai Wang /* 331cde58781SKai Wang * The "top" loop will return 332cde58781SKai Wang * one and one item: 333cde58781SKai Wang */ 3349e2046dfSNick Hibma c->report_count = 1; 3351bee2ec7SAlexander Motin c->usage_minimum = 0; 3361bee2ec7SAlexander Motin c->usage_maximum = 0; 337cde58781SKai Wang } else { 338cde58781SKai Wang s->ncount = 1; 3399e2046dfSNick Hibma } 3409e2046dfSNick Hibma goto top; 341cde58781SKai Wang 3429e2046dfSNick Hibma case 9: /* Output */ 343cde58781SKai Wang c->kind = hid_output; 344cde58781SKai Wang c->flags = dval; 3459e2046dfSNick Hibma goto ret; 3469e2046dfSNick Hibma case 10: /* Collection */ 3479e2046dfSNick Hibma c->kind = hid_collection; 3489e2046dfSNick Hibma c->collection = dval; 3499e2046dfSNick Hibma c->collevel++; 350cde58781SKai Wang c->usage = s->usage_last; 351cde58781SKai Wang *h = *c; 3529e2046dfSNick Hibma return (1); 3539e2046dfSNick Hibma case 11: /* Feature */ 354cde58781SKai Wang c->kind = hid_feature; 355cde58781SKai Wang c->flags = dval; 3569e2046dfSNick Hibma goto ret; 3579e2046dfSNick Hibma case 12: /* End collection */ 3589e2046dfSNick Hibma c->kind = hid_endcollection; 359cde58781SKai Wang if (c->collevel == 0) { 360cde58781SKai Wang /* Invalid end collection. */ 361cde58781SKai Wang return (0); 362cde58781SKai Wang } 3639e2046dfSNick Hibma c->collevel--; 3649e2046dfSNick Hibma *h = *c; 3659e2046dfSNick Hibma return (1); 3669e2046dfSNick Hibma default: 367cde58781SKai Wang break; 3689e2046dfSNick Hibma } 369cf0e07e5SMatthew N. Dodd break; 3709e2046dfSNick Hibma 3719e2046dfSNick Hibma case 1: /* Global */ 3729e2046dfSNick Hibma switch (bTag) { 3739e2046dfSNick Hibma case 0: 3749e2046dfSNick Hibma c->_usage_page = dval << 16; 3759e2046dfSNick Hibma break; 3769e2046dfSNick Hibma case 1: 3779e2046dfSNick Hibma c->logical_minimum = dval; 3789e2046dfSNick Hibma break; 3799e2046dfSNick Hibma case 2: 3809e2046dfSNick Hibma c->logical_maximum = dval; 3819e2046dfSNick Hibma break; 3829e2046dfSNick Hibma case 3: 383cde58781SKai Wang c->physical_minimum = dval; 3849e2046dfSNick Hibma break; 3859e2046dfSNick Hibma case 4: 3869e2046dfSNick Hibma c->physical_maximum = dval; 3879e2046dfSNick Hibma break; 3889e2046dfSNick Hibma case 5: 3899e2046dfSNick Hibma c->unit_exponent = dval; 3909e2046dfSNick Hibma break; 3919e2046dfSNick Hibma case 6: 3929e2046dfSNick Hibma c->unit = dval; 3939e2046dfSNick Hibma break; 3949e2046dfSNick Hibma case 7: 395cde58781SKai Wang /* mask because value is unsigned */ 396cde58781SKai Wang s->loc_size = dval & mask; 3979e2046dfSNick Hibma break; 3989e2046dfSNick Hibma case 8: 399cff79d9eSAlexander Motin hid_switch_rid(s, c, dval & mask); 4009e2046dfSNick Hibma break; 4019e2046dfSNick Hibma case 9: 402cde58781SKai Wang /* mask because value is unsigned */ 403cde58781SKai Wang s->loc_count = dval & mask; 4049e2046dfSNick Hibma break; 4059e2046dfSNick Hibma case 10: /* Push */ 406cde58781SKai Wang s->pushlevel ++; 407cde58781SKai Wang if (s->pushlevel < MAXPUSH) { 408cde58781SKai Wang s->cur[s->pushlevel] = *c; 409cde58781SKai Wang /* store size and count */ 410cde58781SKai Wang c->report_size = s->loc_size; 411cde58781SKai Wang c->report_count = s->loc_count; 412cde58781SKai Wang /* update current item pointer */ 413cde58781SKai Wang c = &s->cur[s->pushlevel]; 414cde58781SKai Wang } 4159e2046dfSNick Hibma break; 4169e2046dfSNick Hibma case 11: /* Pop */ 417cde58781SKai Wang s->pushlevel --; 418cde58781SKai Wang if (s->pushlevel < MAXPUSH) { 419cde58781SKai Wang c = &s->cur[s->pushlevel]; 420cde58781SKai Wang /* restore size and count */ 421cde58781SKai Wang s->loc_size = c->report_size; 422cde58781SKai Wang s->loc_count = c->report_count; 423cde58781SKai Wang c->report_size = 0; 424cde58781SKai Wang c->report_count = 0; 425cde58781SKai Wang } 4269e2046dfSNick Hibma break; 4279e2046dfSNick Hibma default: 428cde58781SKai Wang break; 4299e2046dfSNick Hibma } 4309e2046dfSNick Hibma break; 4319e2046dfSNick Hibma case 2: /* Local */ 4329e2046dfSNick Hibma switch (bTag) { 4339e2046dfSNick Hibma case 0: 434cde58781SKai Wang if (bSize != 4) 435cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 436cde58781SKai Wang 437cde58781SKai Wang /* set last usage, in case of a collection */ 438cde58781SKai Wang s->usage_last = dval; 439cde58781SKai Wang 440cde58781SKai Wang if (s->nusage < MAXUSAGE) { 441cde58781SKai Wang s->usages_min[s->nusage] = dval; 442cde58781SKai Wang s->usages_max[s->nusage] = dval; 443cde58781SKai Wang s->nusage ++; 444cde58781SKai Wang } 4459e2046dfSNick Hibma /* else XXX */ 446cde58781SKai Wang 447cde58781SKai Wang /* clear any pending usage sets */ 448cde58781SKai Wang s->susage = 0; 4499e2046dfSNick Hibma break; 4509e2046dfSNick Hibma case 1: 451cde58781SKai Wang s->susage |= 1; 452cde58781SKai Wang 453cde58781SKai Wang if (bSize != 4) 454cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 455cde58781SKai Wang c->usage_minimum = dval; 456cde58781SKai Wang 457cde58781SKai Wang goto check_set; 4589e2046dfSNick Hibma case 2: 459cde58781SKai Wang s->susage |= 2; 460cde58781SKai Wang 461cde58781SKai Wang if (bSize != 4) 462cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 463cde58781SKai Wang c->usage_maximum = dval; 464cde58781SKai Wang 465cde58781SKai Wang check_set: 466cde58781SKai Wang if (s->susage != 3) 467cde58781SKai Wang break; 468cde58781SKai Wang 469cde58781SKai Wang /* sanity check */ 470cde58781SKai Wang if ((s->nusage < MAXUSAGE) && 471cde58781SKai Wang (c->usage_minimum <= c->usage_maximum)) { 472cde58781SKai Wang /* add usage range */ 473cde58781SKai Wang s->usages_min[s->nusage] = 474cde58781SKai Wang c->usage_minimum; 475cde58781SKai Wang s->usages_max[s->nusage] = 476cde58781SKai Wang c->usage_maximum; 477cde58781SKai Wang s->nusage ++; 478cde58781SKai Wang } 479cde58781SKai Wang /* else XXX */ 480cde58781SKai Wang 481cde58781SKai Wang s->susage = 0; 4829e2046dfSNick Hibma break; 4839e2046dfSNick Hibma case 3: 4849e2046dfSNick Hibma c->designator_index = dval; 4859e2046dfSNick Hibma break; 4869e2046dfSNick Hibma case 4: 4879e2046dfSNick Hibma c->designator_minimum = dval; 4889e2046dfSNick Hibma break; 4899e2046dfSNick Hibma case 5: 4909e2046dfSNick Hibma c->designator_maximum = dval; 4919e2046dfSNick Hibma break; 4929e2046dfSNick Hibma case 7: 4939e2046dfSNick Hibma c->string_index = dval; 4949e2046dfSNick Hibma break; 4959e2046dfSNick Hibma case 8: 4969e2046dfSNick Hibma c->string_minimum = dval; 4979e2046dfSNick Hibma break; 4989e2046dfSNick Hibma case 9: 4999e2046dfSNick Hibma c->string_maximum = dval; 5009e2046dfSNick Hibma break; 5019e2046dfSNick Hibma case 10: 5029e2046dfSNick Hibma c->set_delimiter = dval; 5039e2046dfSNick Hibma break; 5049e2046dfSNick Hibma default: 505cde58781SKai Wang break; 5069e2046dfSNick Hibma } 5079e2046dfSNick Hibma break; 5089e2046dfSNick Hibma default: 509cde58781SKai Wang break; 5109e2046dfSNick Hibma } 5119e2046dfSNick Hibma } 512cde58781SKai Wang return (0); 5139e2046dfSNick Hibma } 5149e2046dfSNick Hibma 5159e2046dfSNick Hibma int 516ec9b9fbdSAlexander Motin hid_get_item(hid_data_t s, hid_item_t *h) 517ec9b9fbdSAlexander Motin { 518ec9b9fbdSAlexander Motin int r; 519ec9b9fbdSAlexander Motin 520ec9b9fbdSAlexander Motin for (;;) { 521ec9b9fbdSAlexander Motin r = hid_get_item_raw(s, h); 522ec9b9fbdSAlexander Motin if (r <= 0 || s->reportid == -1 || h->report_ID == s->reportid) 523ec9b9fbdSAlexander Motin break; 524ec9b9fbdSAlexander Motin } 525ec9b9fbdSAlexander Motin return (r); 526ec9b9fbdSAlexander Motin } 527ec9b9fbdSAlexander Motin 528ec9b9fbdSAlexander Motin int 529cf0e07e5SMatthew N. Dodd hid_report_size(report_desc_t r, enum hid_kind k, int id) 5309e2046dfSNick Hibma { 5319e2046dfSNick Hibma struct hid_data *d; 532cde58781SKai Wang struct hid_item h; 533cde58781SKai Wang uint32_t temp; 534cde58781SKai Wang uint32_t hpos; 535cde58781SKai Wang uint32_t lpos; 5361bee2ec7SAlexander Motin int report_id = 0; 537cde58781SKai Wang 538cde58781SKai Wang hpos = 0; 539cde58781SKai Wang lpos = 0xFFFFFFFF; 5409e2046dfSNick Hibma 5419e2046dfSNick Hibma memset(&h, 0, sizeof h); 542cf0e07e5SMatthew N. Dodd for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) { 543ec9b9fbdSAlexander Motin if (h.kind == k) { 544cde58781SKai Wang /* compute minimum */ 545cde58781SKai Wang if (lpos > h.pos) 546cde58781SKai Wang lpos = h.pos; 547cde58781SKai Wang /* compute end position */ 548cde58781SKai Wang temp = h.pos + (h.report_size * h.report_count); 549cde58781SKai Wang /* compute maximum */ 550cde58781SKai Wang if (hpos < temp) 551cde58781SKai Wang hpos = temp; 5521bee2ec7SAlexander Motin if (h.report_ID != 0) 5531bee2ec7SAlexander Motin report_id = 1; 5549e2046dfSNick Hibma } 5559e2046dfSNick Hibma } 5569e2046dfSNick Hibma hid_end_parse(d); 557cde58781SKai Wang 558cde58781SKai Wang /* safety check - can happen in case of currupt descriptors */ 559cde58781SKai Wang if (lpos > hpos) 560cde58781SKai Wang temp = 0; 561cde58781SKai Wang else 562cde58781SKai Wang temp = hpos - lpos; 563cde58781SKai Wang 564cde58781SKai Wang /* return length in bytes rounded up */ 5651bee2ec7SAlexander Motin return ((temp + 7) / 8 + report_id); 5669e2046dfSNick Hibma } 5679e2046dfSNick Hibma 5689e2046dfSNick Hibma int 569cf0e07e5SMatthew N. Dodd hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 570cf0e07e5SMatthew N. Dodd hid_item_t *h, int id) 5719e2046dfSNick Hibma { 572cde58781SKai Wang struct hid_data *d; 5739e2046dfSNick Hibma 574cf0e07e5SMatthew N. Dodd for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) { 5759e2046dfSNick Hibma if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 5769e2046dfSNick Hibma hid_end_parse(d); 5779e2046dfSNick Hibma return (1); 5789e2046dfSNick Hibma } 5799e2046dfSNick Hibma } 5809e2046dfSNick Hibma hid_end_parse(d); 5819e2046dfSNick Hibma h->report_size = 0; 5829e2046dfSNick Hibma return (0); 5839e2046dfSNick Hibma } 584