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 */ 73cde58781SKai Wang }; 749e2046dfSNick Hibma 75cde58781SKai Wang /*------------------------------------------------------------------------* 76cde58781SKai Wang * hid_clear_local 77cde58781SKai Wang *------------------------------------------------------------------------*/ 789e2046dfSNick Hibma static void 799e2046dfSNick Hibma hid_clear_local(hid_item_t *c) 809e2046dfSNick Hibma { 81cde58781SKai Wang 829e2046dfSNick Hibma c->usage = 0; 839e2046dfSNick Hibma c->usage_minimum = 0; 849e2046dfSNick Hibma c->usage_maximum = 0; 859e2046dfSNick Hibma c->designator_index = 0; 869e2046dfSNick Hibma c->designator_minimum = 0; 879e2046dfSNick Hibma c->designator_maximum = 0; 889e2046dfSNick Hibma c->string_index = 0; 899e2046dfSNick Hibma c->string_minimum = 0; 909e2046dfSNick Hibma c->string_maximum = 0; 919e2046dfSNick Hibma c->set_delimiter = 0; 929e2046dfSNick Hibma } 939e2046dfSNick Hibma 94cde58781SKai Wang static void 95cde58781SKai Wang hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID) 96cde58781SKai Wang { 977778ab7eSAlexander Motin uint8_t i, j; 98cde58781SKai Wang 99cde58781SKai Wang /* check for same report ID - optimise */ 100cde58781SKai Wang 101cde58781SKai Wang if (c->report_ID == next_rID) 102cde58781SKai Wang return; 103cde58781SKai Wang 104cde58781SKai Wang /* save current position for current rID */ 105cde58781SKai Wang 106cde58781SKai Wang if (c->report_ID == 0) { 107cde58781SKai Wang i = 0; 108cde58781SKai Wang } else { 109cde58781SKai Wang for (i = 1; i != MAXID; i++) { 110cde58781SKai Wang if (s->last_pos[i].rid == c->report_ID) 111cde58781SKai Wang break; 112cde58781SKai Wang if (s->last_pos[i].rid == 0) 113cde58781SKai Wang break; 114cde58781SKai Wang } 115cde58781SKai Wang } 116cde58781SKai Wang if (i != MAXID) { 117cde58781SKai Wang s->last_pos[i].rid = c->report_ID; 1187778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1197778ab7eSAlexander Motin s->last_pos[i].pos[j] = s->pos[j]; 120cde58781SKai Wang } 121cde58781SKai Wang 122cde58781SKai Wang /* store next report ID */ 123cde58781SKai Wang 124cde58781SKai Wang c->report_ID = next_rID; 125cde58781SKai Wang 126cde58781SKai Wang /* lookup last position for next rID */ 127cde58781SKai Wang 128cde58781SKai Wang if (next_rID == 0) { 129cde58781SKai Wang i = 0; 130cde58781SKai Wang } else { 131cde58781SKai Wang for (i = 1; i != MAXID; i++) { 132cde58781SKai Wang if (s->last_pos[i].rid == next_rID) 133cde58781SKai Wang break; 134cde58781SKai Wang if (s->last_pos[i].rid == 0) 135cde58781SKai Wang break; 136cde58781SKai Wang } 137cde58781SKai Wang } 138cde58781SKai Wang if (i != MAXID) { 139cde58781SKai Wang s->last_pos[i].rid = next_rID; 1407778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1417778ab7eSAlexander Motin s->pos[j] = s->last_pos[i].pos[j]; 1427778ab7eSAlexander Motin } else { 1437778ab7eSAlexander Motin for (j = 0; j < ITEMTYPES; j++) 1447778ab7eSAlexander Motin s->pos[j] = 0; /* Out of RID entries. */ 1457778ab7eSAlexander Motin } 146cde58781SKai Wang } 147cde58781SKai Wang 148cde58781SKai Wang /*------------------------------------------------------------------------* 149cde58781SKai Wang * hid_start_parse 150cde58781SKai Wang *------------------------------------------------------------------------*/ 1519e2046dfSNick Hibma hid_data_t 152cde58781SKai Wang hid_start_parse(report_desc_t d, int kindset, int id __unused) 1539e2046dfSNick Hibma { 1549e2046dfSNick Hibma struct hid_data *s; 1559e2046dfSNick Hibma 1569e2046dfSNick Hibma s = malloc(sizeof *s); 1579e2046dfSNick Hibma memset(s, 0, sizeof *s); 1589e2046dfSNick Hibma s->start = s->p = d->data; 1599e2046dfSNick Hibma s->end = d->data + d->size; 1609e2046dfSNick Hibma s->kindset = kindset; 1619e2046dfSNick Hibma return (s); 1629e2046dfSNick Hibma } 1639e2046dfSNick Hibma 164cde58781SKai Wang /*------------------------------------------------------------------------* 165cde58781SKai Wang * hid_end_parse 166cde58781SKai Wang *------------------------------------------------------------------------*/ 1679e2046dfSNick Hibma void 1689e2046dfSNick Hibma hid_end_parse(hid_data_t s) 1699e2046dfSNick Hibma { 170cde58781SKai Wang 171cde58781SKai Wang if (s == NULL) 172cde58781SKai Wang return; 173cde58781SKai Wang 1749e2046dfSNick Hibma free(s); 1759e2046dfSNick Hibma } 1769e2046dfSNick Hibma 177cde58781SKai Wang /*------------------------------------------------------------------------* 178cde58781SKai Wang * get byte from HID descriptor 179cde58781SKai Wang *------------------------------------------------------------------------*/ 180cde58781SKai Wang static uint8_t 181cde58781SKai Wang hid_get_byte(struct hid_data *s, const uint16_t wSize) 182cde58781SKai Wang { 183cde58781SKai Wang const uint8_t *ptr; 184cde58781SKai Wang uint8_t retval; 185cde58781SKai Wang 186cde58781SKai Wang ptr = s->p; 187cde58781SKai Wang 188cde58781SKai Wang /* check if end is reached */ 189cde58781SKai Wang if (ptr == s->end) 190cde58781SKai Wang return (0); 191cde58781SKai Wang 192cde58781SKai Wang /* read out a byte */ 193cde58781SKai Wang retval = *ptr; 194cde58781SKai Wang 195cde58781SKai Wang /* check if data pointer can be advanced by "wSize" bytes */ 196cde58781SKai Wang if ((s->end - ptr) < wSize) 197cde58781SKai Wang ptr = s->end; 198cde58781SKai Wang else 199cde58781SKai Wang ptr += wSize; 200cde58781SKai Wang 201cde58781SKai Wang /* update pointer */ 202cde58781SKai Wang s->p = ptr; 203cde58781SKai Wang 204cde58781SKai Wang return (retval); 205cde58781SKai Wang } 206cde58781SKai Wang 207cde58781SKai Wang /*------------------------------------------------------------------------* 208cde58781SKai Wang * hid_get_item 209cde58781SKai Wang *------------------------------------------------------------------------*/ 2109e2046dfSNick Hibma int 2119e2046dfSNick Hibma hid_get_item(hid_data_t s, hid_item_t *h) 2129e2046dfSNick Hibma { 2139e2046dfSNick Hibma hid_item_t *c; 214cde58781SKai Wang unsigned int bTag, bType, bSize; 215cde58781SKai Wang int32_t mask; 216cde58781SKai Wang int32_t dval; 2179e2046dfSNick Hibma 218cde58781SKai Wang if (s == NULL) 2199e2046dfSNick Hibma return (0); 2209e2046dfSNick Hibma 221cde58781SKai Wang c = &s->cur[s->pushlevel]; 222cde58781SKai Wang 223cde58781SKai Wang top: 224cde58781SKai Wang /* check if there is an array of items */ 225cde58781SKai Wang if (s->icount < s->ncount) { 226cde58781SKai Wang /* get current usage */ 227cde58781SKai Wang if (s->iusage < s->nusage) { 228cde58781SKai Wang dval = s->usages_min[s->iusage] + s->ousage; 229cde58781SKai Wang c->usage = dval; 230cde58781SKai Wang s->usage_last = dval; 231cde58781SKai Wang if (dval == s->usages_max[s->iusage]) { 232cde58781SKai Wang s->iusage ++; 233cde58781SKai Wang s->ousage = 0; 234cde58781SKai Wang } else { 235cde58781SKai Wang s->ousage ++; 236cde58781SKai Wang } 237cde58781SKai Wang } else { 238cde58781SKai Wang /* Using last usage */ 239cde58781SKai Wang dval = s->usage_last; 240cde58781SKai Wang } 241cde58781SKai Wang s->icount ++; 242cde58781SKai Wang /* 243cde58781SKai Wang * Only copy HID item, increment position and return 244cde58781SKai Wang * if correct kindset! 245cde58781SKai Wang */ 246cde58781SKai Wang if (s->kindset & (1 << c->kind)) { 247cde58781SKai Wang *h = *c; 2487778ab7eSAlexander Motin h->pos = s->pos[c->kind]; 2497778ab7eSAlexander Motin s->pos[c->kind] += c->report_size * c->report_count; 250cde58781SKai Wang return (1); 251cde58781SKai Wang } 252cde58781SKai Wang } 253cde58781SKai Wang 254cde58781SKai Wang /* reset state variables */ 255cde58781SKai Wang s->icount = 0; 256cde58781SKai Wang s->ncount = 0; 257cde58781SKai Wang s->iusage = 0; 258cde58781SKai Wang s->nusage = 0; 259cde58781SKai Wang s->susage = 0; 260cde58781SKai Wang s->ousage = 0; 261cde58781SKai Wang hid_clear_local(c); 262cde58781SKai Wang 263cde58781SKai Wang /* get next item */ 264cde58781SKai Wang while (s->p != s->end) { 265cde58781SKai Wang 266cde58781SKai Wang bSize = hid_get_byte(s, 1); 2679e2046dfSNick Hibma if (bSize == 0xfe) { 2689e2046dfSNick Hibma /* long item */ 269cde58781SKai Wang bSize = hid_get_byte(s, 1); 270cde58781SKai Wang bSize |= hid_get_byte(s, 1) << 8; 271cde58781SKai Wang bTag = hid_get_byte(s, 1); 272cde58781SKai Wang bType = 0xff; /* XXX what should it be */ 2739e2046dfSNick Hibma } else { 2749e2046dfSNick Hibma /* short item */ 2759e2046dfSNick Hibma bTag = bSize >> 4; 2769e2046dfSNick Hibma bType = (bSize >> 2) & 3; 2779e2046dfSNick Hibma bSize &= 3; 278cde58781SKai Wang if (bSize == 3) 279cde58781SKai Wang bSize = 4; 2809e2046dfSNick Hibma } 281cde58781SKai Wang 2829e2046dfSNick Hibma switch(bSize) { 2839e2046dfSNick Hibma case 0: 2849e2046dfSNick Hibma dval = 0; 285cde58781SKai Wang mask = 0; 2869e2046dfSNick Hibma break; 2879e2046dfSNick Hibma case 1: 288cde58781SKai Wang dval = (int8_t)hid_get_byte(s, 1); 289cde58781SKai Wang mask = 0xFF; 2909e2046dfSNick Hibma break; 2919e2046dfSNick Hibma case 2: 292cde58781SKai Wang dval = hid_get_byte(s, 1); 293cde58781SKai Wang dval |= hid_get_byte(s, 1) << 8; 294cde58781SKai Wang dval = (int16_t)dval; 295cde58781SKai Wang mask = 0xFFFF; 2969e2046dfSNick Hibma break; 2979e2046dfSNick Hibma case 4: 298cde58781SKai Wang dval = hid_get_byte(s, 1); 299cde58781SKai Wang dval |= hid_get_byte(s, 1) << 8; 300cde58781SKai Wang dval |= hid_get_byte(s, 1) << 16; 301cde58781SKai Wang dval |= hid_get_byte(s, 1) << 24; 302cde58781SKai Wang mask = 0xFFFFFFFF; 3039e2046dfSNick Hibma break; 3049e2046dfSNick Hibma default: 305cde58781SKai Wang dval = hid_get_byte(s, bSize); 306cde58781SKai Wang continue; 3079e2046dfSNick Hibma } 3089e2046dfSNick Hibma 3099e2046dfSNick Hibma switch (bType) { 3109e2046dfSNick Hibma case 0: /* Main */ 3119e2046dfSNick Hibma switch (bTag) { 3129e2046dfSNick Hibma case 8: /* Input */ 313cde58781SKai Wang c->kind = hid_input; 314b425e319SNick Hibma c->flags = dval; 315cde58781SKai Wang ret: 316cde58781SKai Wang c->report_count = s->loc_count; 317cde58781SKai Wang c->report_size = s->loc_size; 318cde58781SKai Wang 3199e2046dfSNick Hibma if (c->flags & HIO_VARIABLE) { 320cde58781SKai Wang /* range check usage count */ 321cde58781SKai Wang if (c->report_count > 255) { 322cde58781SKai Wang s->ncount = 255; 323cde58781SKai Wang } else 324cde58781SKai Wang s->ncount = c->report_count; 325cde58781SKai Wang 326cde58781SKai Wang /* 327cde58781SKai Wang * The "top" loop will return 328cde58781SKai Wang * one and one item: 329cde58781SKai Wang */ 3309e2046dfSNick Hibma c->report_count = 1; 3311bee2ec7SAlexander Motin c->usage_minimum = 0; 3321bee2ec7SAlexander Motin c->usage_maximum = 0; 333cde58781SKai Wang } else { 334cde58781SKai Wang s->ncount = 1; 3359e2046dfSNick Hibma } 3369e2046dfSNick Hibma goto top; 337cde58781SKai Wang 3389e2046dfSNick Hibma case 9: /* Output */ 339cde58781SKai Wang c->kind = hid_output; 340cde58781SKai Wang c->flags = dval; 3419e2046dfSNick Hibma goto ret; 3429e2046dfSNick Hibma case 10: /* Collection */ 3439e2046dfSNick Hibma c->kind = hid_collection; 3449e2046dfSNick Hibma c->collection = dval; 3459e2046dfSNick Hibma c->collevel++; 346cde58781SKai Wang c->usage = s->usage_last; 347cde58781SKai Wang *h = *c; 3489e2046dfSNick Hibma return (1); 3499e2046dfSNick Hibma case 11: /* Feature */ 350cde58781SKai Wang c->kind = hid_feature; 351cde58781SKai Wang c->flags = dval; 3529e2046dfSNick Hibma goto ret; 3539e2046dfSNick Hibma case 12: /* End collection */ 3549e2046dfSNick Hibma c->kind = hid_endcollection; 355cde58781SKai Wang if (c->collevel == 0) { 356cde58781SKai Wang /* Invalid end collection. */ 357cde58781SKai Wang return (0); 358cde58781SKai Wang } 3599e2046dfSNick Hibma c->collevel--; 3609e2046dfSNick Hibma *h = *c; 3619e2046dfSNick Hibma return (1); 3629e2046dfSNick Hibma default: 363cde58781SKai Wang break; 3649e2046dfSNick Hibma } 365cf0e07e5SMatthew N. Dodd break; 3669e2046dfSNick Hibma 3679e2046dfSNick Hibma case 1: /* Global */ 3689e2046dfSNick Hibma switch (bTag) { 3699e2046dfSNick Hibma case 0: 3709e2046dfSNick Hibma c->_usage_page = dval << 16; 3719e2046dfSNick Hibma break; 3729e2046dfSNick Hibma case 1: 3739e2046dfSNick Hibma c->logical_minimum = dval; 3749e2046dfSNick Hibma break; 3759e2046dfSNick Hibma case 2: 3769e2046dfSNick Hibma c->logical_maximum = dval; 3779e2046dfSNick Hibma break; 3789e2046dfSNick Hibma case 3: 379cde58781SKai Wang c->physical_minimum = dval; 3809e2046dfSNick Hibma break; 3819e2046dfSNick Hibma case 4: 3829e2046dfSNick Hibma c->physical_maximum = dval; 3839e2046dfSNick Hibma break; 3849e2046dfSNick Hibma case 5: 3859e2046dfSNick Hibma c->unit_exponent = dval; 3869e2046dfSNick Hibma break; 3879e2046dfSNick Hibma case 6: 3889e2046dfSNick Hibma c->unit = dval; 3899e2046dfSNick Hibma break; 3909e2046dfSNick Hibma case 7: 391cde58781SKai Wang /* mask because value is unsigned */ 392cde58781SKai Wang s->loc_size = dval & mask; 3939e2046dfSNick Hibma break; 3949e2046dfSNick Hibma case 8: 395*cff79d9eSAlexander Motin hid_switch_rid(s, c, dval & mask); 3969e2046dfSNick Hibma break; 3979e2046dfSNick Hibma case 9: 398cde58781SKai Wang /* mask because value is unsigned */ 399cde58781SKai Wang s->loc_count = dval & mask; 4009e2046dfSNick Hibma break; 4019e2046dfSNick Hibma case 10: /* Push */ 402cde58781SKai Wang s->pushlevel ++; 403cde58781SKai Wang if (s->pushlevel < MAXPUSH) { 404cde58781SKai Wang s->cur[s->pushlevel] = *c; 405cde58781SKai Wang /* store size and count */ 406cde58781SKai Wang c->report_size = s->loc_size; 407cde58781SKai Wang c->report_count = s->loc_count; 408cde58781SKai Wang /* update current item pointer */ 409cde58781SKai Wang c = &s->cur[s->pushlevel]; 410cde58781SKai Wang } 4119e2046dfSNick Hibma break; 4129e2046dfSNick Hibma case 11: /* Pop */ 413cde58781SKai Wang s->pushlevel --; 414cde58781SKai Wang if (s->pushlevel < MAXPUSH) { 415cde58781SKai Wang c = &s->cur[s->pushlevel]; 416cde58781SKai Wang /* restore size and count */ 417cde58781SKai Wang s->loc_size = c->report_size; 418cde58781SKai Wang s->loc_count = c->report_count; 419cde58781SKai Wang c->report_size = 0; 420cde58781SKai Wang c->report_count = 0; 421cde58781SKai Wang } 4229e2046dfSNick Hibma break; 4239e2046dfSNick Hibma default: 424cde58781SKai Wang break; 4259e2046dfSNick Hibma } 4269e2046dfSNick Hibma break; 4279e2046dfSNick Hibma case 2: /* Local */ 4289e2046dfSNick Hibma switch (bTag) { 4299e2046dfSNick Hibma case 0: 430cde58781SKai Wang if (bSize != 4) 431cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 432cde58781SKai Wang 433cde58781SKai Wang /* set last usage, in case of a collection */ 434cde58781SKai Wang s->usage_last = dval; 435cde58781SKai Wang 436cde58781SKai Wang if (s->nusage < MAXUSAGE) { 437cde58781SKai Wang s->usages_min[s->nusage] = dval; 438cde58781SKai Wang s->usages_max[s->nusage] = dval; 439cde58781SKai Wang s->nusage ++; 440cde58781SKai Wang } 4419e2046dfSNick Hibma /* else XXX */ 442cde58781SKai Wang 443cde58781SKai Wang /* clear any pending usage sets */ 444cde58781SKai Wang s->susage = 0; 4459e2046dfSNick Hibma break; 4469e2046dfSNick Hibma case 1: 447cde58781SKai Wang s->susage |= 1; 448cde58781SKai Wang 449cde58781SKai Wang if (bSize != 4) 450cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 451cde58781SKai Wang c->usage_minimum = dval; 452cde58781SKai Wang 453cde58781SKai Wang goto check_set; 4549e2046dfSNick Hibma case 2: 455cde58781SKai Wang s->susage |= 2; 456cde58781SKai Wang 457cde58781SKai Wang if (bSize != 4) 458cde58781SKai Wang dval = (dval & mask) | c->_usage_page; 459cde58781SKai Wang c->usage_maximum = dval; 460cde58781SKai Wang 461cde58781SKai Wang check_set: 462cde58781SKai Wang if (s->susage != 3) 463cde58781SKai Wang break; 464cde58781SKai Wang 465cde58781SKai Wang /* sanity check */ 466cde58781SKai Wang if ((s->nusage < MAXUSAGE) && 467cde58781SKai Wang (c->usage_minimum <= c->usage_maximum)) { 468cde58781SKai Wang /* add usage range */ 469cde58781SKai Wang s->usages_min[s->nusage] = 470cde58781SKai Wang c->usage_minimum; 471cde58781SKai Wang s->usages_max[s->nusage] = 472cde58781SKai Wang c->usage_maximum; 473cde58781SKai Wang s->nusage ++; 474cde58781SKai Wang } 475cde58781SKai Wang /* else XXX */ 476cde58781SKai Wang 477cde58781SKai Wang s->susage = 0; 4789e2046dfSNick Hibma break; 4799e2046dfSNick Hibma case 3: 4809e2046dfSNick Hibma c->designator_index = dval; 4819e2046dfSNick Hibma break; 4829e2046dfSNick Hibma case 4: 4839e2046dfSNick Hibma c->designator_minimum = dval; 4849e2046dfSNick Hibma break; 4859e2046dfSNick Hibma case 5: 4869e2046dfSNick Hibma c->designator_maximum = dval; 4879e2046dfSNick Hibma break; 4889e2046dfSNick Hibma case 7: 4899e2046dfSNick Hibma c->string_index = dval; 4909e2046dfSNick Hibma break; 4919e2046dfSNick Hibma case 8: 4929e2046dfSNick Hibma c->string_minimum = dval; 4939e2046dfSNick Hibma break; 4949e2046dfSNick Hibma case 9: 4959e2046dfSNick Hibma c->string_maximum = dval; 4969e2046dfSNick Hibma break; 4979e2046dfSNick Hibma case 10: 4989e2046dfSNick Hibma c->set_delimiter = dval; 4999e2046dfSNick Hibma break; 5009e2046dfSNick Hibma default: 501cde58781SKai Wang break; 5029e2046dfSNick Hibma } 5039e2046dfSNick Hibma break; 5049e2046dfSNick Hibma default: 505cde58781SKai Wang break; 5069e2046dfSNick Hibma } 5079e2046dfSNick Hibma } 508cde58781SKai Wang return (0); 5099e2046dfSNick Hibma } 5109e2046dfSNick Hibma 5119e2046dfSNick Hibma int 512cf0e07e5SMatthew N. Dodd hid_report_size(report_desc_t r, enum hid_kind k, int id) 5139e2046dfSNick Hibma { 5149e2046dfSNick Hibma struct hid_data *d; 515cde58781SKai Wang struct hid_item h; 516cde58781SKai Wang uint32_t temp; 517cde58781SKai Wang uint32_t hpos; 518cde58781SKai Wang uint32_t lpos; 5191bee2ec7SAlexander Motin int report_id = 0; 520cde58781SKai Wang 521cde58781SKai Wang hpos = 0; 522cde58781SKai Wang lpos = 0xFFFFFFFF; 5239e2046dfSNick Hibma 5249e2046dfSNick Hibma memset(&h, 0, sizeof h); 525cf0e07e5SMatthew N. Dodd for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) { 5261bee2ec7SAlexander Motin if ((h.report_ID == id || id < 0) && h.kind == k) { 527cde58781SKai Wang /* compute minimum */ 528cde58781SKai Wang if (lpos > h.pos) 529cde58781SKai Wang lpos = h.pos; 530cde58781SKai Wang /* compute end position */ 531cde58781SKai Wang temp = h.pos + (h.report_size * h.report_count); 532cde58781SKai Wang /* compute maximum */ 533cde58781SKai Wang if (hpos < temp) 534cde58781SKai Wang hpos = temp; 5351bee2ec7SAlexander Motin if (h.report_ID != 0) 5361bee2ec7SAlexander Motin report_id = 1; 5379e2046dfSNick Hibma } 5389e2046dfSNick Hibma } 5399e2046dfSNick Hibma hid_end_parse(d); 540cde58781SKai Wang 541cde58781SKai Wang /* safety check - can happen in case of currupt descriptors */ 542cde58781SKai Wang if (lpos > hpos) 543cde58781SKai Wang temp = 0; 544cde58781SKai Wang else 545cde58781SKai Wang temp = hpos - lpos; 546cde58781SKai Wang 547cde58781SKai Wang /* return length in bytes rounded up */ 5481bee2ec7SAlexander Motin return ((temp + 7) / 8 + report_id); 5499e2046dfSNick Hibma } 5509e2046dfSNick Hibma 5519e2046dfSNick Hibma int 552cf0e07e5SMatthew N. Dodd hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 553cf0e07e5SMatthew N. Dodd hid_item_t *h, int id) 5549e2046dfSNick Hibma { 555cde58781SKai Wang struct hid_data *d; 5569e2046dfSNick Hibma 557cf0e07e5SMatthew N. Dodd for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) { 5589e2046dfSNick Hibma if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 5599e2046dfSNick Hibma hid_end_parse(d); 5609e2046dfSNick Hibma return (1); 5619e2046dfSNick Hibma } 5629e2046dfSNick Hibma } 5639e2046dfSNick Hibma hid_end_parse(d); 5649e2046dfSNick Hibma h->report_size = 0; 5659e2046dfSNick Hibma return (0); 5669e2046dfSNick Hibma } 567