parse.c revision 224511
167217Sn_hibma/* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */ 261560Sn_hibma 361560Sn_hibma/* 4113273Smdodd * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org> 561560Sn_hibma * All rights reserved. 661560Sn_hibma * 761560Sn_hibma * Redistribution and use in source and binary forms, with or without 861560Sn_hibma * modification, are permitted provided that the following conditions 961560Sn_hibma * are met: 1061560Sn_hibma * 1. Redistributions of source code must retain the above copyright 1161560Sn_hibma * notice, this list of conditions and the following disclaimer. 1261560Sn_hibma * 2. Redistributions in binary form must reproduce the above copyright 1361560Sn_hibma * notice, this list of conditions and the following disclaimer in the 1461560Sn_hibma * documentation and/or other materials provided with the distribution. 1561560Sn_hibma * 1661560Sn_hibma * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1761560Sn_hibma * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1861560Sn_hibma * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1961560Sn_hibma * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2061560Sn_hibma * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2161560Sn_hibma * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2261560Sn_hibma * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2361560Sn_hibma * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2461560Sn_hibma * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2561560Sn_hibma * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2661560Sn_hibma * SUCH DAMAGE. 2761560Sn_hibma */ 2861560Sn_hibma 2984224Sdillon#include <sys/cdefs.h> 3084224Sdillon__FBSDID("$FreeBSD: head/lib/libusbhid/parse.c 224511 2011-07-30 13:22:44Z mav $"); 3184224Sdillon 3261560Sn_hibma#include <assert.h> 3361560Sn_hibma#include <stdlib.h> 3461560Sn_hibma#include <string.h> 3561560Sn_hibma#include <sys/time.h> 3661560Sn_hibma 3761560Sn_hibma#include <dev/usb/usb.h> 3861560Sn_hibma#include <dev/usb/usbhid.h> 3961560Sn_hibma 40113273Smdodd#include "usbhid.h" 4161560Sn_hibma#include "usbvar.h" 4261560Sn_hibma 43205728Skaiw#define MAXUSAGE 100 44205728Skaiw#define MAXPUSH 4 45205728Skaiw#define MAXID 64 4667217Sn_hibma 47205728Skaiwstruct hid_pos_data { 48205728Skaiw int32_t rid; 49205728Skaiw uint32_t pos; 5061560Sn_hibma}; 5161560Sn_hibma 52205728Skaiwstruct hid_data { 53205728Skaiw const uint8_t *start; 54205728Skaiw const uint8_t *end; 55205728Skaiw const uint8_t *p; 56205728Skaiw struct hid_item cur[MAXPUSH]; 57205728Skaiw struct hid_pos_data last_pos[MAXID]; 58205728Skaiw int32_t usages_min[MAXUSAGE]; 59205728Skaiw int32_t usages_max[MAXUSAGE]; 60205728Skaiw int32_t usage_last; /* last seen usage */ 61205728Skaiw uint32_t loc_size; /* last seen size */ 62205728Skaiw uint32_t loc_count; /* last seen count */ 63205728Skaiw uint8_t kindset; /* we have 5 kinds so 8 bits are enough */ 64205728Skaiw uint8_t pushlevel; /* current pushlevel */ 65205728Skaiw uint8_t ncount; /* end usage item count */ 66205728Skaiw uint8_t icount; /* current usage item count */ 67205728Skaiw uint8_t nusage; /* end "usages_min/max" index */ 68205728Skaiw uint8_t iusage; /* current "usages_min/max" index */ 69205728Skaiw uint8_t ousage; /* current "usages_min/max" offset */ 70205728Skaiw uint8_t susage; /* usage set flags */ 71205728Skaiw}; 7261560Sn_hibma 73205728Skaiw/*------------------------------------------------------------------------* 74205728Skaiw * hid_clear_local 75205728Skaiw *------------------------------------------------------------------------*/ 7661560Sn_hibmastatic void 7761560Sn_hibmahid_clear_local(hid_item_t *c) 7861560Sn_hibma{ 79205728Skaiw 8061560Sn_hibma c->usage = 0; 8161560Sn_hibma c->usage_minimum = 0; 8261560Sn_hibma c->usage_maximum = 0; 8361560Sn_hibma c->designator_index = 0; 8461560Sn_hibma c->designator_minimum = 0; 8561560Sn_hibma c->designator_maximum = 0; 8661560Sn_hibma c->string_index = 0; 8761560Sn_hibma c->string_minimum = 0; 8861560Sn_hibma c->string_maximum = 0; 8961560Sn_hibma c->set_delimiter = 0; 9061560Sn_hibma} 9161560Sn_hibma 92205728Skaiwstatic void 93205728Skaiwhid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID) 94205728Skaiw{ 95205728Skaiw uint8_t i; 96205728Skaiw 97205728Skaiw /* check for same report ID - optimise */ 98205728Skaiw 99205728Skaiw if (c->report_ID == next_rID) 100205728Skaiw return; 101205728Skaiw 102205728Skaiw /* save current position for current rID */ 103205728Skaiw 104205728Skaiw if (c->report_ID == 0) { 105205728Skaiw i = 0; 106205728Skaiw } else { 107205728Skaiw for (i = 1; i != MAXID; i++) { 108205728Skaiw if (s->last_pos[i].rid == c->report_ID) 109205728Skaiw break; 110205728Skaiw if (s->last_pos[i].rid == 0) 111205728Skaiw break; 112205728Skaiw } 113205728Skaiw } 114205728Skaiw if (i != MAXID) { 115205728Skaiw s->last_pos[i].rid = c->report_ID; 116205728Skaiw s->last_pos[i].pos = c->pos; 117205728Skaiw } 118205728Skaiw 119205728Skaiw /* store next report ID */ 120205728Skaiw 121205728Skaiw c->report_ID = next_rID; 122205728Skaiw 123205728Skaiw /* lookup last position for next rID */ 124205728Skaiw 125205728Skaiw if (next_rID == 0) { 126205728Skaiw i = 0; 127205728Skaiw } else { 128205728Skaiw for (i = 1; i != MAXID; i++) { 129205728Skaiw if (s->last_pos[i].rid == next_rID) 130205728Skaiw break; 131205728Skaiw if (s->last_pos[i].rid == 0) 132205728Skaiw break; 133205728Skaiw } 134205728Skaiw } 135205728Skaiw if (i != MAXID) { 136205728Skaiw s->last_pos[i].rid = next_rID; 137205728Skaiw c->pos = s->last_pos[i].pos; 138205728Skaiw } else 139205728Skaiw c->pos = 0; /* Out of RID entries. */ 140205728Skaiw} 141205728Skaiw 142205728Skaiw/*------------------------------------------------------------------------* 143205728Skaiw * hid_start_parse 144205728Skaiw *------------------------------------------------------------------------*/ 14561560Sn_hibmahid_data_t 146205728Skaiwhid_start_parse(report_desc_t d, int kindset, int id __unused) 14761560Sn_hibma{ 14861560Sn_hibma struct hid_data *s; 14961560Sn_hibma 15061560Sn_hibma s = malloc(sizeof *s); 15161560Sn_hibma memset(s, 0, sizeof *s); 15261560Sn_hibma s->start = s->p = d->data; 15361560Sn_hibma s->end = d->data + d->size; 15461560Sn_hibma s->kindset = kindset; 15561560Sn_hibma return (s); 15661560Sn_hibma} 15761560Sn_hibma 158205728Skaiw/*------------------------------------------------------------------------* 159205728Skaiw * hid_end_parse 160205728Skaiw *------------------------------------------------------------------------*/ 16161560Sn_hibmavoid 16261560Sn_hibmahid_end_parse(hid_data_t s) 16361560Sn_hibma{ 164205728Skaiw 165205728Skaiw if (s == NULL) 166205728Skaiw return; 167205728Skaiw 16861560Sn_hibma free(s); 16961560Sn_hibma} 17061560Sn_hibma 171205728Skaiw/*------------------------------------------------------------------------* 172205728Skaiw * get byte from HID descriptor 173205728Skaiw *------------------------------------------------------------------------*/ 174205728Skaiwstatic uint8_t 175205728Skaiwhid_get_byte(struct hid_data *s, const uint16_t wSize) 17661560Sn_hibma{ 177205728Skaiw const uint8_t *ptr; 178205728Skaiw uint8_t retval; 179113273Smdodd 180205728Skaiw ptr = s->p; 181205728Skaiw 182205728Skaiw /* check if end is reached */ 183205728Skaiw if (ptr == s->end) 184205728Skaiw return (0); 185205728Skaiw 186205728Skaiw /* read out a byte */ 187205728Skaiw retval = *ptr; 188205728Skaiw 189205728Skaiw /* check if data pointer can be advanced by "wSize" bytes */ 190205728Skaiw if ((s->end - ptr) < wSize) 191205728Skaiw ptr = s->end; 192205728Skaiw else 193205728Skaiw ptr += wSize; 194205728Skaiw 195205728Skaiw /* update pointer */ 196205728Skaiw s->p = ptr; 197205728Skaiw 198205728Skaiw return (retval); 199113273Smdodd} 200113273Smdodd 201205728Skaiw/*------------------------------------------------------------------------* 202205728Skaiw * hid_get_item 203205728Skaiw *------------------------------------------------------------------------*/ 204205728Skaiwint 205205728Skaiwhid_get_item(hid_data_t s, hid_item_t *h) 206113273Smdodd{ 20761560Sn_hibma hid_item_t *c; 208205728Skaiw unsigned int bTag, bType, bSize; 209205728Skaiw uint32_t oldpos; 210205728Skaiw int32_t mask; 211205728Skaiw int32_t dval; 21261560Sn_hibma 213205728Skaiw if (s == NULL) 214205728Skaiw return (0); 21561560Sn_hibma 216205728Skaiw c = &s->cur[s->pushlevel]; 217205728Skaiw 21861560Sn_hibma top: 219205728Skaiw /* check if there is an array of items */ 220205728Skaiw if (s->icount < s->ncount) { 221205728Skaiw /* get current usage */ 222205728Skaiw if (s->iusage < s->nusage) { 223205728Skaiw dval = s->usages_min[s->iusage] + s->ousage; 224205728Skaiw c->usage = dval; 225205728Skaiw s->usage_last = dval; 226205728Skaiw if (dval == s->usages_max[s->iusage]) { 227205728Skaiw s->iusage ++; 228205728Skaiw s->ousage = 0; 229205728Skaiw } else { 230205728Skaiw s->ousage ++; 231205728Skaiw } 232205728Skaiw } else { 233205728Skaiw /* Using last usage */ 234205728Skaiw dval = s->usage_last; 235113273Smdodd } 236205728Skaiw s->icount ++; 237205728Skaiw /* 238205728Skaiw * Only copy HID item, increment position and return 239205728Skaiw * if correct kindset! 240205728Skaiw */ 241205728Skaiw if (s->kindset & (1 << c->kind)) { 24261560Sn_hibma *h = *c; 243205728Skaiw c->pos += c->report_size * c->report_count; 24461560Sn_hibma return (1); 24561560Sn_hibma } 24661560Sn_hibma } 24761560Sn_hibma 248205728Skaiw /* reset state variables */ 249205728Skaiw s->icount = 0; 250205728Skaiw s->ncount = 0; 251205728Skaiw s->iusage = 0; 252205728Skaiw s->nusage = 0; 253205728Skaiw s->susage = 0; 254205728Skaiw s->ousage = 0; 255205728Skaiw hid_clear_local(c); 256205728Skaiw 257205728Skaiw /* get next item */ 258205728Skaiw while (s->p != s->end) { 259205728Skaiw 260205728Skaiw bSize = hid_get_byte(s, 1); 26161560Sn_hibma if (bSize == 0xfe) { 26261560Sn_hibma /* long item */ 263205728Skaiw bSize = hid_get_byte(s, 1); 264205728Skaiw bSize |= hid_get_byte(s, 1) << 8; 265205728Skaiw bTag = hid_get_byte(s, 1); 266205728Skaiw bType = 0xff; /* XXX what should it be */ 26761560Sn_hibma } else { 26861560Sn_hibma /* short item */ 26961560Sn_hibma bTag = bSize >> 4; 27061560Sn_hibma bType = (bSize >> 2) & 3; 27161560Sn_hibma bSize &= 3; 272205728Skaiw if (bSize == 3) 273205728Skaiw bSize = 4; 27461560Sn_hibma } 275205728Skaiw 27661560Sn_hibma switch(bSize) { 27761560Sn_hibma case 0: 27861560Sn_hibma dval = 0; 279205728Skaiw mask = 0; 28061560Sn_hibma break; 28161560Sn_hibma case 1: 282205728Skaiw dval = (int8_t)hid_get_byte(s, 1); 283205728Skaiw mask = 0xFF; 28461560Sn_hibma break; 28561560Sn_hibma case 2: 286205728Skaiw dval = hid_get_byte(s, 1); 287205728Skaiw dval |= hid_get_byte(s, 1) << 8; 288205728Skaiw dval = (int16_t)dval; 289205728Skaiw mask = 0xFFFF; 29061560Sn_hibma break; 29161560Sn_hibma case 4: 292205728Skaiw dval = hid_get_byte(s, 1); 293205728Skaiw dval |= hid_get_byte(s, 1) << 8; 294205728Skaiw dval |= hid_get_byte(s, 1) << 16; 295205728Skaiw dval |= hid_get_byte(s, 1) << 24; 296205728Skaiw mask = 0xFFFFFFFF; 29761560Sn_hibma break; 29861560Sn_hibma default: 299205728Skaiw dval = hid_get_byte(s, bSize); 300205728Skaiw continue; 30161560Sn_hibma } 30261560Sn_hibma 30361560Sn_hibma switch (bType) { 304205728Skaiw case 0: /* Main */ 30561560Sn_hibma switch (bTag) { 306205728Skaiw case 8: /* Input */ 307205728Skaiw c->kind = hid_input; 30861560Sn_hibma c->flags = dval; 309205728Skaiw ret: 310205728Skaiw c->report_count = s->loc_count; 311205728Skaiw c->report_size = s->loc_size; 312205728Skaiw 31361560Sn_hibma if (c->flags & HIO_VARIABLE) { 314205728Skaiw /* range check usage count */ 315205728Skaiw if (c->report_count > 255) { 316205728Skaiw s->ncount = 255; 317205728Skaiw } else 318205728Skaiw s->ncount = c->report_count; 319205728Skaiw 320205728Skaiw /* 321205728Skaiw * The "top" loop will return 322205728Skaiw * one and one item: 323205728Skaiw */ 32461560Sn_hibma c->report_count = 1; 325224511Smav c->usage_minimum = 0; 326224511Smav c->usage_maximum = 0; 32761560Sn_hibma } else { 328205728Skaiw s->ncount = 1; 32961560Sn_hibma } 330205728Skaiw goto top; 331205728Skaiw 332205728Skaiw case 9: /* Output */ 333205728Skaiw c->kind = hid_output; 334205728Skaiw c->flags = dval; 33561560Sn_hibma goto ret; 33661560Sn_hibma case 10: /* Collection */ 33761560Sn_hibma c->kind = hid_collection; 33861560Sn_hibma c->collection = dval; 33961560Sn_hibma c->collevel++; 340205728Skaiw c->usage = s->usage_last; 341205728Skaiw *h = *c; 342205728Skaiw return (1); 34361560Sn_hibma case 11: /* Feature */ 344205728Skaiw c->kind = hid_feature; 345205728Skaiw c->flags = dval; 34661560Sn_hibma goto ret; 34761560Sn_hibma case 12: /* End collection */ 34861560Sn_hibma c->kind = hid_endcollection; 349205728Skaiw if (c->collevel == 0) { 350205728Skaiw /* Invalid end collection. */ 351205728Skaiw return (0); 352205728Skaiw } 35361560Sn_hibma c->collevel--; 35461560Sn_hibma *h = *c; 35561560Sn_hibma return (1); 35661560Sn_hibma default: 357205728Skaiw break; 35861560Sn_hibma } 359113273Smdodd break; 36061560Sn_hibma 36161560Sn_hibma case 1: /* Global */ 36261560Sn_hibma switch (bTag) { 36361560Sn_hibma case 0: 36461560Sn_hibma c->_usage_page = dval << 16; 36561560Sn_hibma break; 36661560Sn_hibma case 1: 36761560Sn_hibma c->logical_minimum = dval; 36861560Sn_hibma break; 36961560Sn_hibma case 2: 37061560Sn_hibma c->logical_maximum = dval; 37161560Sn_hibma break; 37261560Sn_hibma case 3: 373205728Skaiw c->physical_minimum = dval; 37461560Sn_hibma break; 37561560Sn_hibma case 4: 37661560Sn_hibma c->physical_maximum = dval; 37761560Sn_hibma break; 37861560Sn_hibma case 5: 37961560Sn_hibma c->unit_exponent = dval; 38061560Sn_hibma break; 38161560Sn_hibma case 6: 38261560Sn_hibma c->unit = dval; 38361560Sn_hibma break; 38461560Sn_hibma case 7: 385205728Skaiw /* mask because value is unsigned */ 386205728Skaiw s->loc_size = dval & mask; 38761560Sn_hibma break; 38861560Sn_hibma case 8: 389205728Skaiw hid_switch_rid(s, c, dval); 39061560Sn_hibma break; 39161560Sn_hibma case 9: 392205728Skaiw /* mask because value is unsigned */ 393205728Skaiw s->loc_count = dval & mask; 39461560Sn_hibma break; 395205728Skaiw case 10: /* Push */ 396205728Skaiw s->pushlevel ++; 397205728Skaiw if (s->pushlevel < MAXPUSH) { 398205728Skaiw s->cur[s->pushlevel] = *c; 399205728Skaiw /* store size and count */ 400205728Skaiw c->report_size = s->loc_size; 401205728Skaiw c->report_count = s->loc_count; 402205728Skaiw /* update current item pointer */ 403205728Skaiw c = &s->cur[s->pushlevel]; 404205728Skaiw } 40561560Sn_hibma break; 406205728Skaiw case 11: /* Pop */ 407205728Skaiw s->pushlevel --; 408205728Skaiw if (s->pushlevel < MAXPUSH) { 409205728Skaiw /* preserve position */ 410205728Skaiw oldpos = c->pos; 411205728Skaiw c = &s->cur[s->pushlevel]; 412205728Skaiw /* restore size and count */ 413205728Skaiw s->loc_size = c->report_size; 414205728Skaiw s->loc_count = c->report_count; 415205728Skaiw /* set default item location */ 416205728Skaiw c->pos = oldpos; 417205728Skaiw c->report_size = 0; 418205728Skaiw c->report_count = 0; 419205728Skaiw } 42061560Sn_hibma break; 42161560Sn_hibma default: 422205728Skaiw break; 42361560Sn_hibma } 42461560Sn_hibma break; 42561560Sn_hibma case 2: /* Local */ 42661560Sn_hibma switch (bTag) { 42761560Sn_hibma case 0: 428205728Skaiw if (bSize != 4) 429205728Skaiw dval = (dval & mask) | c->_usage_page; 430205728Skaiw 431205728Skaiw /* set last usage, in case of a collection */ 432205728Skaiw s->usage_last = dval; 433205728Skaiw 434205728Skaiw if (s->nusage < MAXUSAGE) { 435205728Skaiw s->usages_min[s->nusage] = dval; 436205728Skaiw s->usages_max[s->nusage] = dval; 437205728Skaiw s->nusage ++; 438205728Skaiw } 43961560Sn_hibma /* else XXX */ 440205728Skaiw 441205728Skaiw /* clear any pending usage sets */ 442205728Skaiw s->susage = 0; 44361560Sn_hibma break; 44461560Sn_hibma case 1: 445205728Skaiw s->susage |= 1; 446205728Skaiw 447205728Skaiw if (bSize != 4) 448205728Skaiw dval = (dval & mask) | c->_usage_page; 449205728Skaiw c->usage_minimum = dval; 450205728Skaiw 451205728Skaiw goto check_set; 45261560Sn_hibma case 2: 453205728Skaiw s->susage |= 2; 454205728Skaiw 455205728Skaiw if (bSize != 4) 456205728Skaiw dval = (dval & mask) | c->_usage_page; 457205728Skaiw c->usage_maximum = dval; 458205728Skaiw 459205728Skaiw check_set: 460205728Skaiw if (s->susage != 3) 461205728Skaiw break; 462205728Skaiw 463205728Skaiw /* sanity check */ 464205728Skaiw if ((s->nusage < MAXUSAGE) && 465205728Skaiw (c->usage_minimum <= c->usage_maximum)) { 466205728Skaiw /* add usage range */ 467205728Skaiw s->usages_min[s->nusage] = 468205728Skaiw c->usage_minimum; 469205728Skaiw s->usages_max[s->nusage] = 470205728Skaiw c->usage_maximum; 471205728Skaiw s->nusage ++; 472205728Skaiw } 473205728Skaiw /* else XXX */ 474205728Skaiw 475205728Skaiw s->susage = 0; 47661560Sn_hibma break; 47761560Sn_hibma case 3: 47861560Sn_hibma c->designator_index = dval; 47961560Sn_hibma break; 48061560Sn_hibma case 4: 48161560Sn_hibma c->designator_minimum = dval; 48261560Sn_hibma break; 48361560Sn_hibma case 5: 48461560Sn_hibma c->designator_maximum = dval; 48561560Sn_hibma break; 48661560Sn_hibma case 7: 48761560Sn_hibma c->string_index = dval; 48861560Sn_hibma break; 48961560Sn_hibma case 8: 49061560Sn_hibma c->string_minimum = dval; 49161560Sn_hibma break; 49261560Sn_hibma case 9: 49361560Sn_hibma c->string_maximum = dval; 49461560Sn_hibma break; 49561560Sn_hibma case 10: 49661560Sn_hibma c->set_delimiter = dval; 49761560Sn_hibma break; 49861560Sn_hibma default: 499205728Skaiw break; 50061560Sn_hibma } 50161560Sn_hibma break; 50261560Sn_hibma default: 503205728Skaiw break; 50461560Sn_hibma } 50561560Sn_hibma } 506205728Skaiw return (0); 50761560Sn_hibma} 50861560Sn_hibma 50961560Sn_hibmaint 510113273Smdoddhid_report_size(report_desc_t r, enum hid_kind k, int id) 51161560Sn_hibma{ 51261560Sn_hibma struct hid_data *d; 513205728Skaiw struct hid_item h; 514205728Skaiw uint32_t temp; 515205728Skaiw uint32_t hpos; 516205728Skaiw uint32_t lpos; 517224511Smav int report_id = 0; 51861560Sn_hibma 519205728Skaiw hpos = 0; 520205728Skaiw lpos = 0xFFFFFFFF; 521205728Skaiw 52261560Sn_hibma memset(&h, 0, sizeof h); 523205728Skaiw for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) { 524224511Smav if ((h.report_ID == id || id < 0) && h.kind == k) { 525205728Skaiw /* compute minimum */ 526205728Skaiw if (lpos > h.pos) 527205728Skaiw lpos = h.pos; 528205728Skaiw /* compute end position */ 529205728Skaiw temp = h.pos + (h.report_size * h.report_count); 530205728Skaiw /* compute maximum */ 531205728Skaiw if (hpos < temp) 532205728Skaiw hpos = temp; 533224511Smav if (h.report_ID != 0) 534224511Smav report_id = 1; 53561560Sn_hibma } 53661560Sn_hibma } 53761560Sn_hibma hid_end_parse(d); 538205728Skaiw 539205728Skaiw /* safety check - can happen in case of currupt descriptors */ 540205728Skaiw if (lpos > hpos) 541205728Skaiw temp = 0; 542205728Skaiw else 543205728Skaiw temp = hpos - lpos; 544205728Skaiw 545205728Skaiw /* return length in bytes rounded up */ 546224511Smav return ((temp + 7) / 8 + report_id); 54761560Sn_hibma} 54861560Sn_hibma 54961560Sn_hibmaint 550113273Smdoddhid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 551113273Smdodd hid_item_t *h, int id) 55261560Sn_hibma{ 553205728Skaiw struct hid_data *d; 55461560Sn_hibma 555205728Skaiw for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) { 55661560Sn_hibma if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 55761560Sn_hibma hid_end_parse(d); 55861560Sn_hibma return (1); 55961560Sn_hibma } 56061560Sn_hibma } 56161560Sn_hibma hid_end_parse(d); 56261560Sn_hibma h->report_size = 0; 56361560Sn_hibma return (0); 56461560Sn_hibma} 565