1*8a83145eSjcs /* $OpenBSD: hid.c,v 1.1 2016/01/08 15:54:13 jcs Exp $ */ 2*8a83145eSjcs /* $NetBSD: hid.c,v 1.23 2002/07/11 21:14:25 augustss Exp $ */ 3*8a83145eSjcs /* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */ 4*8a83145eSjcs 5*8a83145eSjcs /* 6*8a83145eSjcs * Copyright (c) 1998 The NetBSD Foundation, Inc. 7*8a83145eSjcs * All rights reserved. 8*8a83145eSjcs * 9*8a83145eSjcs * This code is derived from software contributed to The NetBSD Foundation 10*8a83145eSjcs * by Lennart Augustsson (lennart@augustsson.net) at 11*8a83145eSjcs * Carlstedt Research & Technology. 12*8a83145eSjcs * 13*8a83145eSjcs * Redistribution and use in source and binary forms, with or without 14*8a83145eSjcs * modification, are permitted provided that the following conditions 15*8a83145eSjcs * are met: 16*8a83145eSjcs * 1. Redistributions of source code must retain the above copyright 17*8a83145eSjcs * notice, this list of conditions and the following disclaimer. 18*8a83145eSjcs * 2. Redistributions in binary form must reproduce the above copyright 19*8a83145eSjcs * notice, this list of conditions and the following disclaimer in the 20*8a83145eSjcs * documentation and/or other materials provided with the distribution. 21*8a83145eSjcs * 22*8a83145eSjcs * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23*8a83145eSjcs * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24*8a83145eSjcs * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25*8a83145eSjcs * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26*8a83145eSjcs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27*8a83145eSjcs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28*8a83145eSjcs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29*8a83145eSjcs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30*8a83145eSjcs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31*8a83145eSjcs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32*8a83145eSjcs * POSSIBILITY OF SUCH DAMAGE. 33*8a83145eSjcs */ 34*8a83145eSjcs 35*8a83145eSjcs #include <sys/param.h> 36*8a83145eSjcs #include <sys/systm.h> 37*8a83145eSjcs #include <sys/malloc.h> 38*8a83145eSjcs 39*8a83145eSjcs #include <dev/hid/hid.h> 40*8a83145eSjcs 41*8a83145eSjcs #ifdef USBHID_DEBUG 42*8a83145eSjcs #define DPRINTF(x...) do { printf(x); } while (0) 43*8a83145eSjcs #else 44*8a83145eSjcs #define DPRINTF(x...) 45*8a83145eSjcs #endif 46*8a83145eSjcs 47*8a83145eSjcs #define MAXUSAGE 64 48*8a83145eSjcs #define MAXPUSH 4 49*8a83145eSjcs #define MAXID 16 50*8a83145eSjcs 51*8a83145eSjcs struct hid_pos_data { 52*8a83145eSjcs int32_t rid; 53*8a83145eSjcs uint32_t pos; 54*8a83145eSjcs }; 55*8a83145eSjcs 56*8a83145eSjcs struct hid_data { 57*8a83145eSjcs const uint8_t *start; 58*8a83145eSjcs const uint8_t *end; 59*8a83145eSjcs const uint8_t *p; 60*8a83145eSjcs struct hid_item cur[MAXPUSH]; 61*8a83145eSjcs struct hid_pos_data last_pos[MAXID]; 62*8a83145eSjcs int32_t usages_min[MAXUSAGE]; 63*8a83145eSjcs int32_t usages_max[MAXUSAGE]; 64*8a83145eSjcs int32_t usage_last; /* last seen usage */ 65*8a83145eSjcs uint32_t loc_size; /* last seen size */ 66*8a83145eSjcs uint32_t loc_count; /* last seen count */ 67*8a83145eSjcs enum hid_kind kind; 68*8a83145eSjcs uint8_t pushlevel; /* current pushlevel */ 69*8a83145eSjcs uint8_t ncount; /* end usage item count */ 70*8a83145eSjcs uint8_t icount; /* current usage item count */ 71*8a83145eSjcs uint8_t nusage; /* end "usages_min/max" index */ 72*8a83145eSjcs uint8_t iusage; /* current "usages_min/max" index */ 73*8a83145eSjcs uint8_t ousage; /* current "usages_min/max" offset */ 74*8a83145eSjcs uint8_t susage; /* usage set flags */ 75*8a83145eSjcs }; 76*8a83145eSjcs 77*8a83145eSjcs static void 78*8a83145eSjcs hid_clear_local(struct hid_item *c) 79*8a83145eSjcs { 80*8a83145eSjcs c->loc.count = 0; 81*8a83145eSjcs c->loc.size = 0; 82*8a83145eSjcs c->usage = 0; 83*8a83145eSjcs c->usage_minimum = 0; 84*8a83145eSjcs c->usage_maximum = 0; 85*8a83145eSjcs c->designator_index = 0; 86*8a83145eSjcs c->designator_minimum = 0; 87*8a83145eSjcs c->designator_maximum = 0; 88*8a83145eSjcs c->string_index = 0; 89*8a83145eSjcs c->string_minimum = 0; 90*8a83145eSjcs c->string_maximum = 0; 91*8a83145eSjcs c->set_delimiter = 0; 92*8a83145eSjcs } 93*8a83145eSjcs 94*8a83145eSjcs static void 95*8a83145eSjcs hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t nextid) 96*8a83145eSjcs { 97*8a83145eSjcs uint8_t i; 98*8a83145eSjcs 99*8a83145eSjcs if (c->report_ID == nextid) 100*8a83145eSjcs return; 101*8a83145eSjcs 102*8a83145eSjcs /* save current position for current rID */ 103*8a83145eSjcs if (c->report_ID == 0) { 104*8a83145eSjcs i = 0; 105*8a83145eSjcs } else { 106*8a83145eSjcs for (i = 1; i != MAXID; i++) { 107*8a83145eSjcs if (s->last_pos[i].rid == c->report_ID) 108*8a83145eSjcs break; 109*8a83145eSjcs if (s->last_pos[i].rid == 0) 110*8a83145eSjcs break; 111*8a83145eSjcs } 112*8a83145eSjcs } 113*8a83145eSjcs if (i != MAXID) { 114*8a83145eSjcs s->last_pos[i].rid = c->report_ID; 115*8a83145eSjcs s->last_pos[i].pos = c->loc.pos; 116*8a83145eSjcs } 117*8a83145eSjcs 118*8a83145eSjcs /* store next report ID */ 119*8a83145eSjcs c->report_ID = nextid; 120*8a83145eSjcs 121*8a83145eSjcs /* lookup last position for next rID */ 122*8a83145eSjcs if (nextid == 0) { 123*8a83145eSjcs i = 0; 124*8a83145eSjcs } else { 125*8a83145eSjcs for (i = 1; i != MAXID; i++) { 126*8a83145eSjcs if (s->last_pos[i].rid == nextid) 127*8a83145eSjcs break; 128*8a83145eSjcs if (s->last_pos[i].rid == 0) 129*8a83145eSjcs break; 130*8a83145eSjcs } 131*8a83145eSjcs } 132*8a83145eSjcs if (i != MAXID) { 133*8a83145eSjcs s->last_pos[i].rid = nextid; 134*8a83145eSjcs c->loc.pos = s->last_pos[i].pos; 135*8a83145eSjcs } else { 136*8a83145eSjcs DPRINTF("Out of RID entries, position is set to zero!\n"); 137*8a83145eSjcs c->loc.pos = 0; 138*8a83145eSjcs } 139*8a83145eSjcs } 140*8a83145eSjcs 141*8a83145eSjcs struct hid_data * 142*8a83145eSjcs hid_start_parse(const void *d, int len, enum hid_kind kind) 143*8a83145eSjcs { 144*8a83145eSjcs struct hid_data *s; 145*8a83145eSjcs 146*8a83145eSjcs s = malloc(sizeof(*s), M_TEMP, M_WAITOK | M_ZERO); 147*8a83145eSjcs 148*8a83145eSjcs s->start = s->p = d; 149*8a83145eSjcs s->end = ((const uint8_t *)d) + len; 150*8a83145eSjcs s->kind = kind; 151*8a83145eSjcs return (s); 152*8a83145eSjcs } 153*8a83145eSjcs 154*8a83145eSjcs void 155*8a83145eSjcs hid_end_parse(struct hid_data *s) 156*8a83145eSjcs { 157*8a83145eSjcs if (s == NULL) 158*8a83145eSjcs return; 159*8a83145eSjcs 160*8a83145eSjcs free(s, M_TEMP, 0); 161*8a83145eSjcs } 162*8a83145eSjcs 163*8a83145eSjcs static uint8_t 164*8a83145eSjcs hid_get_byte(struct hid_data *s, const uint16_t wSize) 165*8a83145eSjcs { 166*8a83145eSjcs const uint8_t *ptr; 167*8a83145eSjcs uint8_t retval; 168*8a83145eSjcs 169*8a83145eSjcs ptr = s->p; 170*8a83145eSjcs 171*8a83145eSjcs /* check if end is reached */ 172*8a83145eSjcs if (ptr == s->end) 173*8a83145eSjcs return (0); 174*8a83145eSjcs 175*8a83145eSjcs /* read out a byte */ 176*8a83145eSjcs retval = *ptr; 177*8a83145eSjcs 178*8a83145eSjcs /* check if data pointer can be advanced by "wSize" bytes */ 179*8a83145eSjcs if ((s->end - ptr) < wSize) 180*8a83145eSjcs ptr = s->end; 181*8a83145eSjcs else 182*8a83145eSjcs ptr += wSize; 183*8a83145eSjcs 184*8a83145eSjcs /* update pointer */ 185*8a83145eSjcs s->p = ptr; 186*8a83145eSjcs 187*8a83145eSjcs return (retval); 188*8a83145eSjcs } 189*8a83145eSjcs 190*8a83145eSjcs int 191*8a83145eSjcs hid_get_item(struct hid_data *s, struct hid_item *h) 192*8a83145eSjcs { 193*8a83145eSjcs struct hid_item *c; 194*8a83145eSjcs unsigned int bTag, bType, bSize; 195*8a83145eSjcs uint32_t oldpos; 196*8a83145eSjcs int32_t mask; 197*8a83145eSjcs int32_t dval; 198*8a83145eSjcs 199*8a83145eSjcs if (s == NULL) 200*8a83145eSjcs return (0); 201*8a83145eSjcs 202*8a83145eSjcs c = &s->cur[s->pushlevel]; 203*8a83145eSjcs 204*8a83145eSjcs top: 205*8a83145eSjcs /* check if there is an array of items */ 206*8a83145eSjcs DPRINTF("%s: icount=%d ncount=%d\n", __func__, 207*8a83145eSjcs s->icount, s->ncount); 208*8a83145eSjcs if (s->icount < s->ncount) { 209*8a83145eSjcs /* get current usage */ 210*8a83145eSjcs if (s->iusage < s->nusage) { 211*8a83145eSjcs dval = s->usages_min[s->iusage] + s->ousage; 212*8a83145eSjcs c->usage = dval; 213*8a83145eSjcs s->usage_last = dval; 214*8a83145eSjcs if (dval == s->usages_max[s->iusage]) { 215*8a83145eSjcs s->iusage ++; 216*8a83145eSjcs s->ousage = 0; 217*8a83145eSjcs } else { 218*8a83145eSjcs s->ousage ++; 219*8a83145eSjcs } 220*8a83145eSjcs } else { 221*8a83145eSjcs DPRINTF("Using last usage\n"); 222*8a83145eSjcs dval = s->usage_last; 223*8a83145eSjcs } 224*8a83145eSjcs s->icount ++; 225*8a83145eSjcs /* 226*8a83145eSjcs * Only copy HID item, increment position and return 227*8a83145eSjcs * if correct kind! 228*8a83145eSjcs */ 229*8a83145eSjcs if (s->kind == c->kind) { 230*8a83145eSjcs *h = *c; 231*8a83145eSjcs DPRINTF("%u,%u,%u\n", h->loc.pos, 232*8a83145eSjcs h->loc.size, h->loc.count); 233*8a83145eSjcs c->loc.pos += c->loc.size * c->loc.count; 234*8a83145eSjcs return (1); 235*8a83145eSjcs } 236*8a83145eSjcs } 237*8a83145eSjcs 238*8a83145eSjcs /* reset state variables */ 239*8a83145eSjcs s->icount = 0; 240*8a83145eSjcs s->ncount = 0; 241*8a83145eSjcs s->iusage = 0; 242*8a83145eSjcs s->nusage = 0; 243*8a83145eSjcs s->susage = 0; 244*8a83145eSjcs s->ousage = 0; 245*8a83145eSjcs hid_clear_local(c); 246*8a83145eSjcs 247*8a83145eSjcs /* get next item */ 248*8a83145eSjcs while (s->p != s->end) { 249*8a83145eSjcs 250*8a83145eSjcs bSize = hid_get_byte(s, 1); 251*8a83145eSjcs if (bSize == 0xfe) { 252*8a83145eSjcs /* long item */ 253*8a83145eSjcs bSize = hid_get_byte(s, 1); 254*8a83145eSjcs bSize |= hid_get_byte(s, 1) << 8; 255*8a83145eSjcs bTag = hid_get_byte(s, 1); 256*8a83145eSjcs bType = 0xff; /* XXX what should it be */ 257*8a83145eSjcs } else { 258*8a83145eSjcs /* short item */ 259*8a83145eSjcs bTag = bSize >> 4; 260*8a83145eSjcs bType = (bSize >> 2) & 3; 261*8a83145eSjcs bSize &= 3; 262*8a83145eSjcs if (bSize == 3) 263*8a83145eSjcs bSize = 4; 264*8a83145eSjcs } 265*8a83145eSjcs switch (bSize) { 266*8a83145eSjcs case 0: 267*8a83145eSjcs dval = 0; 268*8a83145eSjcs mask = 0; 269*8a83145eSjcs break; 270*8a83145eSjcs case 1: 271*8a83145eSjcs dval = hid_get_byte(s, 1); 272*8a83145eSjcs mask = 0xFF; 273*8a83145eSjcs break; 274*8a83145eSjcs case 2: 275*8a83145eSjcs dval = hid_get_byte(s, 1); 276*8a83145eSjcs dval |= hid_get_byte(s, 1) << 8; 277*8a83145eSjcs mask = 0xFFFF; 278*8a83145eSjcs break; 279*8a83145eSjcs case 4: 280*8a83145eSjcs dval = hid_get_byte(s, 1); 281*8a83145eSjcs dval |= hid_get_byte(s, 1) << 8; 282*8a83145eSjcs dval |= hid_get_byte(s, 1) << 16; 283*8a83145eSjcs dval |= hid_get_byte(s, 1) << 24; 284*8a83145eSjcs mask = 0xFFFFFFFF; 285*8a83145eSjcs break; 286*8a83145eSjcs default: 287*8a83145eSjcs dval = hid_get_byte(s, bSize); 288*8a83145eSjcs DPRINTF("bad length %u (data=0x%02x)\n", 289*8a83145eSjcs bSize, dval); 290*8a83145eSjcs continue; 291*8a83145eSjcs } 292*8a83145eSjcs 293*8a83145eSjcs DPRINTF("%s: bType=%d bTag=%d dval=%d\n", __func__, 294*8a83145eSjcs bType, bTag, dval); 295*8a83145eSjcs switch (bType) { 296*8a83145eSjcs case 0: /* Main */ 297*8a83145eSjcs switch (bTag) { 298*8a83145eSjcs case 8: /* Input */ 299*8a83145eSjcs c->kind = hid_input; 300*8a83145eSjcs c->flags = dval; 301*8a83145eSjcs ret: 302*8a83145eSjcs c->loc.count = s->loc_count; 303*8a83145eSjcs c->loc.size = s->loc_size; 304*8a83145eSjcs 305*8a83145eSjcs if (c->flags & HIO_VARIABLE) { 306*8a83145eSjcs /* range check usage count */ 307*8a83145eSjcs if (c->loc.count > 255) { 308*8a83145eSjcs DPRINTF("Number of " 309*8a83145eSjcs "items truncated to 255\n"); 310*8a83145eSjcs s->ncount = 255; 311*8a83145eSjcs } else 312*8a83145eSjcs s->ncount = c->loc.count; 313*8a83145eSjcs 314*8a83145eSjcs /* 315*8a83145eSjcs * The "top" loop will return 316*8a83145eSjcs * one and one item: 317*8a83145eSjcs */ 318*8a83145eSjcs c->loc.count = 1; 319*8a83145eSjcs } else { 320*8a83145eSjcs s->ncount = 1; 321*8a83145eSjcs } 322*8a83145eSjcs goto top; 323*8a83145eSjcs 324*8a83145eSjcs case 9: /* Output */ 325*8a83145eSjcs c->kind = hid_output; 326*8a83145eSjcs c->flags = dval; 327*8a83145eSjcs goto ret; 328*8a83145eSjcs case 10: /* Collection */ 329*8a83145eSjcs c->kind = hid_collection; 330*8a83145eSjcs c->collection = dval; 331*8a83145eSjcs c->collevel++; 332*8a83145eSjcs c->usage = s->usage_last; 333*8a83145eSjcs *h = *c; 334*8a83145eSjcs return (1); 335*8a83145eSjcs case 11: /* Feature */ 336*8a83145eSjcs c->kind = hid_feature; 337*8a83145eSjcs c->flags = dval; 338*8a83145eSjcs goto ret; 339*8a83145eSjcs case 12: /* End collection */ 340*8a83145eSjcs c->kind = hid_endcollection; 341*8a83145eSjcs if (c->collevel == 0) { 342*8a83145eSjcs DPRINTF("invalid end collection\n"); 343*8a83145eSjcs return (0); 344*8a83145eSjcs } 345*8a83145eSjcs c->collevel--; 346*8a83145eSjcs *h = *c; 347*8a83145eSjcs return (1); 348*8a83145eSjcs default: 349*8a83145eSjcs DPRINTF("Main bTag=%d\n", bTag); 350*8a83145eSjcs break; 351*8a83145eSjcs } 352*8a83145eSjcs break; 353*8a83145eSjcs case 1: /* Global */ 354*8a83145eSjcs switch (bTag) { 355*8a83145eSjcs case 0: 356*8a83145eSjcs c->_usage_page = dval << 16; 357*8a83145eSjcs break; 358*8a83145eSjcs case 1: 359*8a83145eSjcs c->logical_minimum = dval; 360*8a83145eSjcs break; 361*8a83145eSjcs case 2: 362*8a83145eSjcs c->logical_maximum = dval; 363*8a83145eSjcs break; 364*8a83145eSjcs case 3: 365*8a83145eSjcs c->physical_minimum = dval; 366*8a83145eSjcs break; 367*8a83145eSjcs case 4: 368*8a83145eSjcs c->physical_maximum = dval; 369*8a83145eSjcs break; 370*8a83145eSjcs case 5: 371*8a83145eSjcs c->unit_exponent = dval; 372*8a83145eSjcs break; 373*8a83145eSjcs case 6: 374*8a83145eSjcs c->unit = dval; 375*8a83145eSjcs break; 376*8a83145eSjcs case 7: 377*8a83145eSjcs /* mask because value is unsigned */ 378*8a83145eSjcs s->loc_size = dval & mask; 379*8a83145eSjcs break; 380*8a83145eSjcs case 8: 381*8a83145eSjcs hid_switch_rid(s, c, dval & mask); 382*8a83145eSjcs break; 383*8a83145eSjcs case 9: 384*8a83145eSjcs /* mask because value is unsigned */ 385*8a83145eSjcs s->loc_count = dval & mask; 386*8a83145eSjcs break; 387*8a83145eSjcs case 10: /* Push */ 388*8a83145eSjcs s->pushlevel ++; 389*8a83145eSjcs if (s->pushlevel < MAXPUSH) { 390*8a83145eSjcs s->cur[s->pushlevel] = *c; 391*8a83145eSjcs /* store size and count */ 392*8a83145eSjcs c->loc.size = s->loc_size; 393*8a83145eSjcs c->loc.count = s->loc_count; 394*8a83145eSjcs /* update current item pointer */ 395*8a83145eSjcs c = &s->cur[s->pushlevel]; 396*8a83145eSjcs } else { 397*8a83145eSjcs DPRINTF("Cannot push " 398*8a83145eSjcs "item @ %d\n", s->pushlevel); 399*8a83145eSjcs } 400*8a83145eSjcs break; 401*8a83145eSjcs case 11: /* Pop */ 402*8a83145eSjcs s->pushlevel --; 403*8a83145eSjcs if (s->pushlevel < MAXPUSH) { 404*8a83145eSjcs /* preserve position */ 405*8a83145eSjcs oldpos = c->loc.pos; 406*8a83145eSjcs c = &s->cur[s->pushlevel]; 407*8a83145eSjcs /* restore size and count */ 408*8a83145eSjcs s->loc_size = c->loc.size; 409*8a83145eSjcs s->loc_count = c->loc.count; 410*8a83145eSjcs /* set default item location */ 411*8a83145eSjcs c->loc.pos = oldpos; 412*8a83145eSjcs c->loc.size = 0; 413*8a83145eSjcs c->loc.count = 0; 414*8a83145eSjcs } else { 415*8a83145eSjcs DPRINTF("Cannot pop " 416*8a83145eSjcs "item @ %d\n", s->pushlevel); 417*8a83145eSjcs } 418*8a83145eSjcs break; 419*8a83145eSjcs default: 420*8a83145eSjcs DPRINTF("Global bTag=%d\n", bTag); 421*8a83145eSjcs break; 422*8a83145eSjcs } 423*8a83145eSjcs break; 424*8a83145eSjcs case 2: /* Local */ 425*8a83145eSjcs switch (bTag) { 426*8a83145eSjcs case 0: 427*8a83145eSjcs if (bSize != 4) 428*8a83145eSjcs dval = (dval & mask) | c->_usage_page; 429*8a83145eSjcs 430*8a83145eSjcs /* set last usage, in case of a collection */ 431*8a83145eSjcs s->usage_last = dval; 432*8a83145eSjcs 433*8a83145eSjcs if (s->nusage < MAXUSAGE) { 434*8a83145eSjcs s->usages_min[s->nusage] = dval; 435*8a83145eSjcs s->usages_max[s->nusage] = dval; 436*8a83145eSjcs s->nusage ++; 437*8a83145eSjcs } else { 438*8a83145eSjcs DPRINTF("max usage reached\n"); 439*8a83145eSjcs } 440*8a83145eSjcs 441*8a83145eSjcs /* clear any pending usage sets */ 442*8a83145eSjcs s->susage = 0; 443*8a83145eSjcs break; 444*8a83145eSjcs case 1: 445*8a83145eSjcs s->susage |= 1; 446*8a83145eSjcs 447*8a83145eSjcs if (bSize != 4) 448*8a83145eSjcs dval = (dval & mask) | c->_usage_page; 449*8a83145eSjcs c->usage_minimum = dval; 450*8a83145eSjcs 451*8a83145eSjcs goto check_set; 452*8a83145eSjcs case 2: 453*8a83145eSjcs s->susage |= 2; 454*8a83145eSjcs 455*8a83145eSjcs if (bSize != 4) 456*8a83145eSjcs dval = (dval & mask) | c->_usage_page; 457*8a83145eSjcs c->usage_maximum = dval; 458*8a83145eSjcs 459*8a83145eSjcs check_set: 460*8a83145eSjcs if (s->susage != 3) 461*8a83145eSjcs break; 462*8a83145eSjcs 463*8a83145eSjcs /* sanity check */ 464*8a83145eSjcs if ((s->nusage < MAXUSAGE) && 465*8a83145eSjcs (c->usage_minimum <= c->usage_maximum)) { 466*8a83145eSjcs /* add usage range */ 467*8a83145eSjcs s->usages_min[s->nusage] = 468*8a83145eSjcs c->usage_minimum; 469*8a83145eSjcs s->usages_max[s->nusage] = 470*8a83145eSjcs c->usage_maximum; 471*8a83145eSjcs s->nusage ++; 472*8a83145eSjcs } else { 473*8a83145eSjcs DPRINTF("Usage set dropped\n"); 474*8a83145eSjcs } 475*8a83145eSjcs s->susage = 0; 476*8a83145eSjcs break; 477*8a83145eSjcs case 3: 478*8a83145eSjcs c->designator_index = dval; 479*8a83145eSjcs break; 480*8a83145eSjcs case 4: 481*8a83145eSjcs c->designator_minimum = dval; 482*8a83145eSjcs break; 483*8a83145eSjcs case 5: 484*8a83145eSjcs c->designator_maximum = dval; 485*8a83145eSjcs break; 486*8a83145eSjcs case 7: 487*8a83145eSjcs c->string_index = dval; 488*8a83145eSjcs break; 489*8a83145eSjcs case 8: 490*8a83145eSjcs c->string_minimum = dval; 491*8a83145eSjcs break; 492*8a83145eSjcs case 9: 493*8a83145eSjcs c->string_maximum = dval; 494*8a83145eSjcs break; 495*8a83145eSjcs case 10: 496*8a83145eSjcs c->set_delimiter = dval; 497*8a83145eSjcs break; 498*8a83145eSjcs default: 499*8a83145eSjcs DPRINTF("Local bTag=%d\n", bTag); 500*8a83145eSjcs break; 501*8a83145eSjcs } 502*8a83145eSjcs break; 503*8a83145eSjcs default: 504*8a83145eSjcs DPRINTF("default bType=%d\n", bType); 505*8a83145eSjcs break; 506*8a83145eSjcs } 507*8a83145eSjcs } 508*8a83145eSjcs return (0); 509*8a83145eSjcs } 510*8a83145eSjcs 511*8a83145eSjcs int 512*8a83145eSjcs hid_report_size(const void *buf, int len, enum hid_kind k, u_int8_t id) 513*8a83145eSjcs { 514*8a83145eSjcs struct hid_data *d; 515*8a83145eSjcs struct hid_item h; 516*8a83145eSjcs int lo, hi; 517*8a83145eSjcs 518*8a83145eSjcs h.report_ID = 0; 519*8a83145eSjcs lo = hi = -1; 520*8a83145eSjcs DPRINTF("hid_report_size: kind=%d id=%d\n", k, id); 521*8a83145eSjcs for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) { 522*8a83145eSjcs DPRINTF("hid_report_size: item kind=%d id=%d pos=%d " 523*8a83145eSjcs "size=%d count=%d\n", 524*8a83145eSjcs h.kind, h.report_ID, h.loc.pos, h.loc.size, 525*8a83145eSjcs h.loc.count); 526*8a83145eSjcs if (h.report_ID == id && h.kind == k) { 527*8a83145eSjcs if (lo < 0) { 528*8a83145eSjcs lo = h.loc.pos; 529*8a83145eSjcs #ifdef DIAGNOSTIC 530*8a83145eSjcs if (lo != 0) { 531*8a83145eSjcs printf("hid_report_size: lo != 0\n"); 532*8a83145eSjcs } 533*8a83145eSjcs #endif 534*8a83145eSjcs } 535*8a83145eSjcs hi = h.loc.pos + h.loc.size * h.loc.count; 536*8a83145eSjcs DPRINTF("hid_report_size: lo=%d hi=%d\n", lo, hi); 537*8a83145eSjcs 538*8a83145eSjcs } 539*8a83145eSjcs } 540*8a83145eSjcs hid_end_parse(d); 541*8a83145eSjcs return ((hi - lo + 7) / 8); 542*8a83145eSjcs } 543*8a83145eSjcs 544*8a83145eSjcs int 545*8a83145eSjcs hid_locate(const void *desc, int size, int32_t u, uint8_t id, enum hid_kind k, 546*8a83145eSjcs struct hid_location *loc, uint32_t *flags) 547*8a83145eSjcs { 548*8a83145eSjcs struct hid_data *d; 549*8a83145eSjcs struct hid_item h; 550*8a83145eSjcs 551*8a83145eSjcs h.report_ID = 0; 552*8a83145eSjcs DPRINTF("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id); 553*8a83145eSjcs for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) { 554*8a83145eSjcs DPRINTF("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n", 555*8a83145eSjcs h.usage, h.kind, h.report_ID, h.flags); 556*8a83145eSjcs if (h.kind == k && !(h.flags & HIO_CONST) && 557*8a83145eSjcs h.usage == u && h.report_ID == id) { 558*8a83145eSjcs if (loc != NULL) 559*8a83145eSjcs *loc = h.loc; 560*8a83145eSjcs if (flags != NULL) 561*8a83145eSjcs *flags = h.flags; 562*8a83145eSjcs hid_end_parse(d); 563*8a83145eSjcs return (1); 564*8a83145eSjcs } 565*8a83145eSjcs } 566*8a83145eSjcs hid_end_parse(d); 567*8a83145eSjcs if (loc != NULL) 568*8a83145eSjcs loc->size = 0; 569*8a83145eSjcs if (flags != NULL) 570*8a83145eSjcs *flags = 0; 571*8a83145eSjcs return (0); 572*8a83145eSjcs } 573*8a83145eSjcs 574*8a83145eSjcs int32_t 575*8a83145eSjcs hid_get_data(const uint8_t *buf, int len, struct hid_location *loc) 576*8a83145eSjcs { 577*8a83145eSjcs uint32_t hpos = loc->pos; 578*8a83145eSjcs uint32_t hsize = loc->size; 579*8a83145eSjcs uint32_t data; 580*8a83145eSjcs uint32_t rpos; 581*8a83145eSjcs uint8_t n; 582*8a83145eSjcs 583*8a83145eSjcs DPRINTF("hid_get_data: loc %d/%d\n", hpos, hsize); 584*8a83145eSjcs 585*8a83145eSjcs /* Range check and limit */ 586*8a83145eSjcs if (hsize == 0) 587*8a83145eSjcs return (0); 588*8a83145eSjcs if (hsize > 32) 589*8a83145eSjcs hsize = 32; 590*8a83145eSjcs 591*8a83145eSjcs /* Get data in a safe way */ 592*8a83145eSjcs data = 0; 593*8a83145eSjcs rpos = (hpos / 8); 594*8a83145eSjcs n = (hsize + 7) / 8; 595*8a83145eSjcs rpos += n; 596*8a83145eSjcs while (n--) { 597*8a83145eSjcs rpos--; 598*8a83145eSjcs if (rpos < len) 599*8a83145eSjcs data |= buf[rpos] << (8 * n); 600*8a83145eSjcs } 601*8a83145eSjcs 602*8a83145eSjcs /* Correctly shift down data */ 603*8a83145eSjcs data = (data >> (hpos % 8)); 604*8a83145eSjcs n = 32 - hsize; 605*8a83145eSjcs 606*8a83145eSjcs data = (int32_t)((int32_t)data << n) >> n; 607*8a83145eSjcs 608*8a83145eSjcs DPRINTF("hid_get_data: loc %d/%d = %lu\n", 609*8a83145eSjcs loc->pos, loc->size, (long)data); 610*8a83145eSjcs return (data); 611*8a83145eSjcs } 612*8a83145eSjcs 613*8a83145eSjcs int 614*8a83145eSjcs hid_is_collection(const void *desc, int size, uint8_t id, int32_t usage) 615*8a83145eSjcs { 616*8a83145eSjcs struct hid_data *hd; 617*8a83145eSjcs struct hid_item hi; 618*8a83145eSjcs uint32_t coll_usage = ~0; 619*8a83145eSjcs 620*8a83145eSjcs hd = hid_start_parse(desc, size, hid_none); 621*8a83145eSjcs 622*8a83145eSjcs DPRINTF("%s: id=%d usage=0x%x\n", __func__, id, usage); 623*8a83145eSjcs while (hid_get_item(hd, &hi)) { 624*8a83145eSjcs DPRINTF("%s: kind=%d id=%d usage=0x%x(0x%x)\n", __func__, 625*8a83145eSjcs hi.kind, hi.report_ID, hi.usage, coll_usage); 626*8a83145eSjcs if (hi.kind == hid_collection && 627*8a83145eSjcs hi.collection == HCOLL_APPLICATION) 628*8a83145eSjcs coll_usage = hi.usage; 629*8a83145eSjcs if (hi.kind == hid_endcollection && 630*8a83145eSjcs coll_usage == usage && hi.report_ID == id) { 631*8a83145eSjcs DPRINTF("%s: found\n", __func__); 632*8a83145eSjcs hid_end_parse(hd); 633*8a83145eSjcs return (1); 634*8a83145eSjcs } 635*8a83145eSjcs } 636*8a83145eSjcs DPRINTF("%s: not found\n", __func__); 637*8a83145eSjcs hid_end_parse(hd); 638*8a83145eSjcs return (0); 639*8a83145eSjcs } 640