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