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 44cde58781SKai Wang #define MAXPUSH 4 45cde58781SKai Wang #define MAXID 64 467778ab7eSAlexander Motin #define ITEMTYPES 3 47b425e319SNick Hibma 48cde58781SKai Wang struct hid_pos_data { 49cde58781SKai Wang int32_t rid; 507778ab7eSAlexander Motin uint32_t pos[ITEMTYPES]; 519e2046dfSNick Hibma }; 529e2046dfSNick Hibma 53cde58781SKai Wang struct hid_data { 54cde58781SKai Wang const uint8_t *start; 55cde58781SKai Wang const uint8_t *end; 56cde58781SKai Wang const uint8_t *p; 57cde58781SKai Wang struct hid_item cur[MAXPUSH]; 58cde58781SKai Wang struct hid_pos_data last_pos[MAXID]; 597778ab7eSAlexander Motin uint32_t pos[ITEMTYPES]; 60cde58781SKai Wang int32_t usages_min[MAXUSAGE]; 61cde58781SKai Wang int32_t usages_max[MAXUSAGE]; 62cde58781SKai Wang int32_t usage_last; /* last seen usage */ 63cde58781SKai Wang uint32_t loc_size; /* last seen size */ 64cde58781SKai Wang uint32_t loc_count; /* last seen count */ 65cde58781SKai Wang uint8_t kindset; /* we have 5 kinds so 8 bits are enough */ 66cde58781SKai Wang uint8_t pushlevel; /* current pushlevel */ 67cde58781SKai Wang uint8_t ncount; /* end usage item count */ 68cde58781SKai Wang uint8_t icount; /* current usage item count */ 69cde58781SKai Wang uint8_t nusage; /* end "usages_min/max" index */ 70cde58781SKai Wang uint8_t iusage; /* current "usages_min/max" index */ 71cde58781SKai Wang uint8_t ousage; /* current "usages_min/max" offset */ 72cde58781SKai Wang uint8_t susage; /* usage set flags */ 73*ec9b9fbdSAlexander Motin int32_t reportid; /* requested report ID */ 74cde58781SKai Wang }; 759e2046dfSNick Hibma 76cde58781SKai Wang /*------------------------------------------------------------------------* 77cde58781SKai Wang * hid_clear_local 78cde58781SKai Wang *------------------------------------------------------------------------*/ 799e2046dfSNick Hibma static void 809e2046dfSNick Hibma hid_clear_local(hid_item_t *c) 819e2046dfSNick Hibma { 82cde58781SKai Wang 839e2046dfSNick Hibma c->usage = 0; 849e2046dfSNick Hibma c->usage_minimum = 0; 859e2046dfSNick Hibma c->usage_maximum = 0; 869e2046dfSNick Hibma c->designator_index = 0; 879e2046dfSNick Hibma c->designator_minimum = 0; 889e2046dfSNick Hibma c->designator_maximum = 0; 899e2046dfSNick Hibma c->string_index = 0; 909e2046dfSNick Hibma c->string_minimum = 0; 919e2046dfSNick Hibma c->string_maximum = 0; 929e2046dfSNick Hibma c->set_delimiter = 0; 939e2046dfSNick Hibma } 949e2046dfSNick Hibma 95cde58781SKai Wang static void 96cde58781SKai Wang hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID) 97cde58781SKai Wang { 987778ab7eSAlexander Motin uint8_t i, j; 99cde58781SKai Wang 100cde58781SKai Wang /* check for same report ID - optimise */ 101cde58781SKai Wang 102cde58781SKai Wang if (c->report_ID == next_rID) 103cde58781SKai Wang return; 104cde58781SKai Wang 105cde58781SKai Wang /* save current position for current rID */ 106cde58781SKai Wang 107cde58781SKai Wang if (c->report_ID == 0) { 108cde58781SKai Wang i = 0; 109cde58781SKai Wang } else { 110cde58781SKai Wang for (i = 1; i != MAXID; i++) { 111cde58781SKai Wang if (s->last_pos[i].rid == c->report_ID) 112cde58781SKai Wang break; 113cde58781SKai Wang if (s->last_pos[i].rid == 0) 114cde58781SKai Wang break; 115cde58781SKai Wang } 116cde58781SKai Wang } 117cde58781SKai Wang if (i != MAXID) { 118cde58781SKai Wang s->last_pos[i].rid = c->report_ID; 1197778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1207778ab7eSAlexander Motin s->last_pos[i].pos[j] = s->pos[j]; 121cde58781SKai Wang } 122cde58781SKai Wang 123cde58781SKai Wang /* store next report ID */ 124cde58781SKai Wang 125cde58781SKai Wang c->report_ID = next_rID; 126cde58781SKai Wang 127cde58781SKai Wang /* lookup last position for next rID */ 128cde58781SKai Wang 129cde58781SKai Wang if (next_rID == 0) { 130cde58781SKai Wang i = 0; 131cde58781SKai Wang } else { 132cde58781SKai Wang for (i = 1; i != MAXID; i++) { 133cde58781SKai Wang if (s->last_pos[i].rid == next_rID) 134cde58781SKai Wang break; 135cde58781SKai Wang if (s->last_pos[i].rid == 0) 136cde58781SKai Wang break; 137cde58781SKai Wang } 138cde58781SKai Wang } 139cde58781SKai Wang if (i != MAXID) { 140cde58781SKai Wang s->last_pos[i].rid = next_rID; 1417778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1427778ab7eSAlexander Motin s->pos[j] = s->last_pos[i].pos[j]; 1437778ab7eSAlexander Motin } else { 1447778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1457778ab7eSAlexander Motin s->pos[j] = 0; /* Out of RID entries. */ 1467778ab7eSAlexander Motin } 147cde58781SKai Wang } 148cde58781SKai Wang 149cde58781SKai Wang /*------------------------------------------------------------------------* 150cde58781SKai Wang * hid_start_parse 151cde58781SKai Wang *------------------------------------------------------------------------*/ 1529e2046dfSNick Hibma hid_data_t 153*ec9b9fbdSAlexander Motin hid_start_parse(report_desc_t d, int kindset, int id) 1549e2046dfSNick Hibma { 1559e2046dfSNick Hibma struct hid_data *s; 1569e2046dfSNick Hibma 1579e2046dfSNick Hibma s = malloc(sizeof *s); 1589e2046dfSNick Hibma memset(s, 0, sizeof *s); 1599e2046dfSNick Hibma s->start = s->p = d->data; 1609e2046dfSNick Hibma s->end = d->data + d->size; 1619e2046dfSNick Hibma s->kindset = kindset; 162*ec9b9fbdSAlexander Motin s->reportid = id; 1639e2046dfSNick Hibma return (s); 1649e2046dfSNick Hibma } 1659e2046dfSNick Hibma 166cde58781SKai Wang /*------------------------------------------------------------------------* 167cde58781SKai Wang * hid_end_parse 168cde58781SKai Wang *------------------------------------------------------------------------*/ 1699e2046dfSNick Hibma void 1709e2046dfSNick Hibma hid_end_parse(hid_data_t s) 1719e2046dfSNick Hibma { 172cde58781SKai Wang 173cde58781SKai Wang if (s == NULL) 174cde58781SKai Wang return; 175cde58781SKai Wang 1769e2046dfSNick Hibma free(s); 1779e2046dfSNick Hibma } 1789e2046dfSNick Hibma 179cde58781SKai Wang /*------------------------------------------------------------------------* 180cde58781SKai Wang * get byte from HID descriptor 181cde58781SKai Wang *------------------------------------------------------------------------*/ 182cde58781SKai Wang static uint8_t 183cde58781SKai Wang hid_get_byte(struct hid_data *s, const uint16_t wSize) 184cde58781SKai Wang { 185cde58781SKai Wang const uint8_t *ptr; 186cde58781SKai Wang uint8_t retval; 187cde58781SKai Wang 188cde58781SKai Wang ptr = s->p; 189cde58781SKai Wang 190cde58781SKai Wang /* check if end is reached */ 191cde58781SKai Wang if (ptr == s->end) 192cde58781SKai Wang return (0); 193cde58781SKai Wang 194cde58781SKai Wang /* read out a byte */ 195cde58781SKai Wang retval = *ptr; 196cde58781SKai Wang 197cde58781SKai Wang /* check if data pointer can be advanced by "wSize" bytes */ 198cde58781SKai Wang if ((s->end - ptr) < wSize) 199cde58781SKai Wang ptr = s->end; 200cde58781SKai Wang else 201cde58781SKai Wang ptr += wSize; 202cde58781SKai Wang 203cde58781SKai Wang /* update pointer */ 204cde58781SKai Wang s->p = ptr; 205cde58781SKai Wang 206cde58781SKai Wang return (retval); 207cde58781SKai Wang } 208cde58781SKai Wang 209cde58781SKai Wang /*------------------------------------------------------------------------* 210cde58781SKai Wang * hid_get_item 211cde58781SKai Wang *------------------------------------------------------------------------*/ 212*ec9b9fbdSAlexander Motin static int 213*ec9b9fbdSAlexander Motin hid_get_item_raw(hid_data_t s, hid_item_t *h) 2149e2046dfSNick Hibma { 2159e2046dfSNick Hibma hid_item_t *c; 216cde58781SKai Wang unsigned int bTag, bType, bSize; 217cde58781SKai Wang int32_t mask; 218cde58781SKai Wang int32_t dval; 2199e2046dfSNick Hibma 220cde58781SKai Wang if (s == NULL) 2219e2046dfSNick Hibma return (0); 2229e2046dfSNick Hibma 223cde58781SKai Wang c = &s->cur[s->pushlevel]; 224cde58781SKai Wang 225cde58781SKai Wang top: 226cde58781SKai Wang /* check if there is an array of items */ 227cde58781SKai Wang if (s->icount < s->ncount) { 228cde58781SKai Wang /* get current usage */ 229cde58781SKai Wang if (s->iusage < s->nusage) { 230cde58781SKai Wang dval = s->usages_min[s->iusage] + s->ousage; 231cde58781SKai Wang c->usage = dval; 232cde58781SKai Wang s->usage_last = dval; 233cde58781SKai Wang if (dval == s->usages_max[s->iusage]) { 234cde58781SKai Wang s->iusage ++; 235cde58781SKai Wang s->ousage = 0; 236cde58781SKai Wang } else { 237cde58781SKai Wang s->ousage ++; 238cde58781SKai Wang } 239cde58781SKai Wang } else { 240cde58781SKai Wang /* Using last usage */ 241cde58781SKai Wang dval = s->usage_last; 242cde58781SKai Wang } 243cde58781SKai Wang s->icount ++; 244cde58781SKai Wang /* 245cde58781SKai Wang * Only copy HID item, increment position and return 246cde58781SKai Wang * if correct kindset! 247cde58781SKai Wang */ 248cde58781SKai Wang if (s->kindset & (1 << c->kind)) { 249cde58781SKai Wang *h = *c; 2507778ab7eSAlexander Motin h->pos = s->pos[c->kind]; 2517778ab7eSAlexander Motin s->pos[c->kind] += c->report_size * c->report_count; 252cde58781SKai Wang return (1); 253cde58781SKai Wang } 254cde58781SKai Wang } 255cde58781SKai Wang 256cde58781SKai Wang /* reset state variables */ 257cde58781SKai Wang s->icount = 0; 258cde58781SKai Wang s->ncount = 0; 259cde58781SKai Wang s->iusage = 0; 260cde58781SKai Wang s->nusage = 0; 261cde58781SKai Wang s->susage = 0; 262cde58781SKai Wang s->ousage = 0; 263cde58781SKai Wang hid_clear_local(c); 264cde58781SKai Wang 265cde58781SKai Wang /* get next item */ 266cde58781SKai Wang while (s->p != s->end) { 267cde58781SKai Wang 268cde58781SKai Wang bSize = hid_get_byte(s, 1); 2699e2046dfSNick Hibma if (bSize == 0xfe) { 2709e2046dfSNick Hibma /* long item */ 271cde58781SKai Wang bSize = hid_get_byte(s, 1); 272cde58781SKai Wang bSize |= hid_get_byte(s, 1) << 8; 273cde58781SKai Wang bTag = hid_get_byte(s, 1); 274cde58781SKai Wang bType = 0xff; /* XXX what should it be */ 2759e2046dfSNick Hibma } else { 2769e2046dfSNick Hibma /* short item */ 2779e2046dfSNick Hibma bTag = bSize >> 4; 2789e2046dfSNick Hibma bType = (bSize >> 2) & 3; 2799e2046dfSNick Hibma bSize &= 3; 280cde58781SKai Wang if (bSize == 3) 281cde58781SKai Wang bSize = 4; 2829e2046dfSNick Hibma } 283cde58781SKai Wang 2849e2046dfSNick Hibma switch(bSize) { 2859e2046dfSNick Hibma case 0: 2869e2046dfSNick Hibma dval = 0; 287cde58781SKai Wang mask = 0; 2889e2046dfSNick Hibma break; 2899e2046dfSNick Hibma case 1: 290cde58781SKai Wang dval = (int8_t)hid_get_byte(s, 1); 291cde58781SKai Wang mask = 0xFF; 2929e2046dfSNick Hibma break; 2939e2046dfSNick Hibma case 2: 294cde58781SKai Wang dval = hid_get_byte(s, 1); 295cde58781SKai Wang dval |= hid_get_byte(s, 1) << 8; 296cde58781SKai Wang dval = (int16_t)dval; 297cde58781SKai Wang mask = 0xFFFF; 2989e2046dfSNick Hibma break; 2999e2046dfSNick Hibma case 4: 300cde58781SKai Wang dval = hid_get_byte(s, 1); 301cde58781SKai Wang dval |= hid_get_byte(s, 1) << 8; 302cde58781SKai Wang dval |= hid_get_byte(s, 1) << 16; 303cde58781SKai Wang dval |= hid_get_byte(s, 1) << 24; 304cde58781SKai Wang mask = 0xFFFFFFFF; 3059e2046dfSNick Hibma break; 3069e2046dfSNick Hibma default: 307cde58781SKai Wang dval = hid_get_byte(s, bSize); 308cde58781SKai Wang continue; 3099e2046dfSNick Hibma } 3109e2046dfSNick Hibma 3119e2046dfSNick Hibma switch (bType) { 3129e2046dfSNick Hibma case 0: /* Main */ 3139e2046dfSNick Hibma switch (bTag) { 3149e2046dfSNick Hibma case 8: /* Input */ 315cde58781SKai Wang c->kind = hid_input; 316b425e319SNick Hibma c->flags = dval; 317cde58781SKai Wang ret: 318cde58781SKai Wang c->report_count = s->loc_count; 319cde58781SKai Wang c->report_size = s->loc_size; 320cde58781SKai Wang 3219e2046dfSNick Hibma if (c->flags & HIO_VARIABLE) { 322cde58781SKai Wang /* range check usage count */ 323cde58781SKai Wang if (c->report_count > 255) { 324cde58781SKai Wang s->ncount = 255; 325cde58781SKai Wang } else 326cde58781SKai Wang s->ncount = c->report_count; 327cde58781SKai Wang 328cde58781SKai Wang /* 329cde58781SKai Wang * The "top" loop will return 330cde58781SKai Wang * one and one item: 331cde58781SKai Wang */ 3329e2046dfSNick Hibma c->report_count = 1; 3331bee2ec7SAlexander Motin c->usage_minimum = 0; 3341bee2ec7SAlexander Motin c->usage_maximum = 0; 335cde58781SKai Wang } else { 336cde58781SKai Wang s->ncount = 1; 3379e2046dfSNick Hibma } 3389e2046dfSNick Hibma goto top; 339cde58781SKai Wang 3409e2046dfSNick Hibma case 9: /* Output */ 341cde58781SKai Wang c->kind = hid_output; 342cde58781SKai Wang c->flags = dval; 3439e2046dfSNick Hibma goto ret; 3449e2046dfSNick Hibma case 10: /* Collection */ 3459e2046dfSNick Hibma c->kind = hid_collection; 3469e2046dfSNick Hibma c->collection = dval; 3479e2046dfSNick Hibma c->collevel++; 348cde58781SKai Wang c->usage = s->usage_last; 349cde58781SKai Wang *h = *c; 3509e2046dfSNick Hibma return (1); 3519e2046dfSNick Hibma case 11: /* Feature */ 352cde58781SKai Wang c->kind = hid_feature; 353cde58781SKai Wang c->flags = dval; 3549e2046dfSNick Hibma goto ret; 3559e2046dfSNick Hibma case 12: /* End collection */ 3569e2046dfSNick Hibma c->kind = hid_endcollection; 357cde58781SKai Wang if (c->collevel == 0) { 358cde58781SKai Wang /* Invalid end collection. */ 359cde58781SKai Wang return (0); 360cde58781SKai Wang } 3619e2046dfSNick Hibma c->collevel--; 3629e2046dfSNick Hibma *h = *c; 3639e2046dfSNick Hibma return (1); 3649e2046dfSNick Hibma default: 365cde58781SKai Wang break; 3669e2046dfSNick Hibma } 367cf0e07e5SMatthew N. Dodd break; 3689e2046dfSNick Hibma 3699e2046dfSNick Hibma case 1: /* Global */ 3709e2046dfSNick Hibma switch (bTag) { 3719e2046dfSNick Hibma case 0: 3729e2046dfSNick Hibma c->_usage_page = dval << 16; 3739e2046dfSNick Hibma break; 3749e2046dfSNick Hibma case 1: 3759e2046dfSNick Hibma c->logical_minimum = dval; 3769e2046dfSNick Hibma break; 3779e2046dfSNick Hibma case 2: 3789e2046dfSNick Hibma c->logical_maximum = dval; 3799e2046dfSNick Hibma break; 3809e2046dfSNick Hibma case 3: 381cde58781SKai Wang c->physical_minimum = dval; 3829e2046dfSNick Hibma break; 3839e2046dfSNick Hibma case 4: 3849e2046dfSNick Hibma c->physical_maximum = dval; 3859e2046dfSNick Hibma break; 3869e2046dfSNick Hibma case 5: 3879e2046dfSNick Hibma c->unit_exponent = dval; 3889e2046dfSNick Hibma break; 3899e2046dfSNick Hibma case 6: 3909e2046dfSNick Hibma c->unit = dval; 3919e2046dfSNick Hibma break; 3929e2046dfSNick Hibma case 7: 393cde58781SKai Wang /* mask because value is unsigned */ 394cde58781SKai Wang s->loc_size = dval & mask; 3959e2046dfSNick Hibma break; 3969e2046dfSNick Hibma case 8: 397cff79d9eSAlexander Motin hid_switch_rid(s, c, dval & mask); 3989e2046dfSNick Hibma break; 3999e2046dfSNick Hibma case 9: 400cde58781SKai Wang /* mask because value is unsigned */ 401cde58781SKai Wang s->loc_count = dval & mask; 4029e2046dfSNick Hibma break; 4039e2046dfSNick Hibma case 10: /* Push */ 404cde58781SKai Wang s->pushlevel ++; 405cde58781SKai Wang if (s->pushlevel < MAXPUSH) { 406cde58781SKai Wang s->cur[s->pushlevel] = *c; 407cde58781SKai Wang /* store size and count */ 408cde58781SKai Wang c->report_size = s->loc_size; 409cde58781SKai Wang c->report_count = s->loc_count; 410cde58781SKai Wang /* update current item pointer */ 411cde58781SKai Wang c = &s->cur[s->pushlevel]; 412cde58781SKai Wang } 4139e2046dfSNick Hibma break; 4149e2046dfSNick Hibma case 11: /* Pop */ 415cde58781SKai Wang s->pushlevel --; 416cde58781SKai Wang if (s->pushlevel < MAXPUSH) { 417cde58781SKai Wang c = &s->cur[s->pushlevel]; 418cde58781SKai Wang /* restore size and count */ 419cde58781SKai Wang s->loc_size = c->report_size; 420cde58781SKai Wang s->loc_count = c->report_count; 421cde58781SKai Wang c->report_size = 0; 422cde58781SKai Wang c->report_count = 0; 423cde58781SKai Wang } 4249e2046dfSNick Hibma break; 4259e2046dfSNick Hibma default: 426cde58781SKai Wang break; 4279e2046dfSNick Hibma } 4289e2046dfSNick Hibma break; 4299e2046dfSNick Hibma case 2: /* Local */ 4309e2046dfSNick Hibma switch (bTag) { 4319e2046dfSNick Hibma case 0: 432cde58781SKai Wang if (bSize != 4) 433cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 434cde58781SKai Wang 435cde58781SKai Wang /* set last usage, in case of a collection */ 436cde58781SKai Wang s->usage_last = dval; 437cde58781SKai Wang 438cde58781SKai Wang if (s->nusage < MAXUSAGE) { 439cde58781SKai Wang s->usages_min[s->nusage] = dval; 440cde58781SKai Wang s->usages_max[s->nusage] = dval; 441cde58781SKai Wang s->nusage ++; 442cde58781SKai Wang } 4439e2046dfSNick Hibma /* else XXX */ 444cde58781SKai Wang 445cde58781SKai Wang /* clear any pending usage sets */ 446cde58781SKai Wang s->susage = 0; 4479e2046dfSNick Hibma break; 4489e2046dfSNick Hibma case 1: 449cde58781SKai Wang s->susage |= 1; 450cde58781SKai Wang 451cde58781SKai Wang if (bSize != 4) 452cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 453cde58781SKai Wang c->usage_minimum = dval; 454cde58781SKai Wang 455cde58781SKai Wang goto check_set; 4569e2046dfSNick Hibma case 2: 457cde58781SKai Wang s->susage |= 2; 458cde58781SKai Wang 459cde58781SKai Wang if (bSize != 4) 460cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 461cde58781SKai Wang c->usage_maximum = dval; 462cde58781SKai Wang 463cde58781SKai Wang check_set: 464cde58781SKai Wang if (s->susage != 3) 465cde58781SKai Wang break; 466cde58781SKai Wang 467cde58781SKai Wang /* sanity check */ 468cde58781SKai Wang if ((s->nusage < MAXUSAGE) && 469cde58781SKai Wang (c->usage_minimum <= c->usage_maximum)) { 470cde58781SKai Wang /* add usage range */ 471cde58781SKai Wang s->usages_min[s->nusage] = 472cde58781SKai Wang c->usage_minimum; 473cde58781SKai Wang s->usages_max[s->nusage] = 474cde58781SKai Wang c->usage_maximum; 475cde58781SKai Wang s->nusage ++; 476cde58781SKai Wang } 477cde58781SKai Wang /* else XXX */ 478cde58781SKai Wang 479cde58781SKai Wang s->susage = 0; 4809e2046dfSNick Hibma break; 4819e2046dfSNick Hibma case 3: 4829e2046dfSNick Hibma c->designator_index = dval; 4839e2046dfSNick Hibma break; 4849e2046dfSNick Hibma case 4: 4859e2046dfSNick Hibma c->designator_minimum = dval; 4869e2046dfSNick Hibma break; 4879e2046dfSNick Hibma case 5: 4889e2046dfSNick Hibma c->designator_maximum = dval; 4899e2046dfSNick Hibma break; 4909e2046dfSNick Hibma case 7: 4919e2046dfSNick Hibma c->string_index = dval; 4929e2046dfSNick Hibma break; 4939e2046dfSNick Hibma case 8: 4949e2046dfSNick Hibma c->string_minimum = dval; 4959e2046dfSNick Hibma break; 4969e2046dfSNick Hibma case 9: 4979e2046dfSNick Hibma c->string_maximum = dval; 4989e2046dfSNick Hibma break; 4999e2046dfSNick Hibma case 10: 5009e2046dfSNick Hibma c->set_delimiter = dval; 5019e2046dfSNick Hibma break; 5029e2046dfSNick Hibma default: 503cde58781SKai Wang break; 5049e2046dfSNick Hibma } 5059e2046dfSNick Hibma break; 5069e2046dfSNick Hibma default: 507cde58781SKai Wang break; 5089e2046dfSNick Hibma } 5099e2046dfSNick Hibma } 510cde58781SKai Wang return (0); 5119e2046dfSNick Hibma } 5129e2046dfSNick Hibma 5139e2046dfSNick Hibma int 514*ec9b9fbdSAlexander Motin hid_get_item(hid_data_t s, hid_item_t *h) 515*ec9b9fbdSAlexander Motin { 516*ec9b9fbdSAlexander Motin int r; 517*ec9b9fbdSAlexander Motin 518*ec9b9fbdSAlexander Motin for (;;) { 519*ec9b9fbdSAlexander Motin r = hid_get_item_raw(s, h); 520*ec9b9fbdSAlexander Motin if (r <= 0 || s->reportid == -1 || h->report_ID == s->reportid) 521*ec9b9fbdSAlexander Motin break; 522*ec9b9fbdSAlexander Motin } 523*ec9b9fbdSAlexander Motin return (r); 524*ec9b9fbdSAlexander Motin } 525*ec9b9fbdSAlexander Motin 526*ec9b9fbdSAlexander Motin int 527cf0e07e5SMatthew N. Dodd hid_report_size(report_desc_t r, enum hid_kind k, int id) 5289e2046dfSNick Hibma { 5299e2046dfSNick Hibma struct hid_data *d; 530cde58781SKai Wang struct hid_item h; 531cde58781SKai Wang uint32_t temp; 532cde58781SKai Wang uint32_t hpos; 533cde58781SKai Wang uint32_t lpos; 5341bee2ec7SAlexander Motin int report_id = 0; 535cde58781SKai Wang 536cde58781SKai Wang hpos = 0; 537cde58781SKai Wang lpos = 0xFFFFFFFF; 5389e2046dfSNick Hibma 5399e2046dfSNick Hibma memset(&h, 0, sizeof h); 540cf0e07e5SMatthew N. Dodd for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) { 541*ec9b9fbdSAlexander Motin if (h.kind == k) { 542cde58781SKai Wang /* compute minimum */ 543cde58781SKai Wang if (lpos > h.pos) 544cde58781SKai Wang lpos = h.pos; 545cde58781SKai Wang /* compute end position */ 546cde58781SKai Wang temp = h.pos + (h.report_size * h.report_count); 547cde58781SKai Wang /* compute maximum */ 548cde58781SKai Wang if (hpos < temp) 549cde58781SKai Wang hpos = temp; 5501bee2ec7SAlexander Motin if (h.report_ID != 0) 5511bee2ec7SAlexander Motin report_id = 1; 5529e2046dfSNick Hibma } 5539e2046dfSNick Hibma } 5549e2046dfSNick Hibma hid_end_parse(d); 555cde58781SKai Wang 556cde58781SKai Wang /* safety check - can happen in case of currupt descriptors */ 557cde58781SKai Wang if (lpos > hpos) 558cde58781SKai Wang temp = 0; 559cde58781SKai Wang else 560cde58781SKai Wang temp = hpos - lpos; 561cde58781SKai Wang 562cde58781SKai Wang /* return length in bytes rounded up */ 5631bee2ec7SAlexander Motin return ((temp + 7) / 8 + report_id); 5649e2046dfSNick Hibma } 5659e2046dfSNick Hibma 5669e2046dfSNick Hibma int 567cf0e07e5SMatthew N. Dodd hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 568cf0e07e5SMatthew N. Dodd hid_item_t *h, int id) 5699e2046dfSNick Hibma { 570cde58781SKai Wang struct hid_data *d; 5719e2046dfSNick Hibma 572cf0e07e5SMatthew N. Dodd for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) { 5739e2046dfSNick Hibma if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 5749e2046dfSNick Hibma hid_end_parse(d); 5759e2046dfSNick Hibma return (1); 5769e2046dfSNick Hibma } 5779e2046dfSNick Hibma } 5789e2046dfSNick Hibma hid_end_parse(d); 5799e2046dfSNick Hibma h->report_size = 0; 5809e2046dfSNick Hibma return (0); 5819e2046dfSNick Hibma } 582