1 /* $OpenBSD: parse.c,v 1.7 2012/07/16 19:57:17 jasper 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 #include <sys/time.h> 33 34 #include <dev/usb/usb.h> 35 #include <dev/usb/usbhid.h> 36 37 #include "usbhid.h" 38 #include "usbvar.h" 39 40 #define MAXUSAGE 100 41 struct hid_data { 42 u_char *start; 43 u_char *end; 44 u_char *p; 45 hid_item_t cur; 46 unsigned int usages[MAXUSAGE]; 47 int nusage; 48 int minset; 49 int logminsize; 50 int multi; 51 int multimax; 52 int kindset; 53 int reportid; 54 55 /* 56 * The start of collection item has no report ID set, so save 57 * it until we know the ID. 58 */ 59 hid_item_t savedcoll; 60 u_char hassavedcoll; 61 /* 62 * Absolute data position (bits) for input/output/feature. 63 * Assumes that hid_input, hid_output and hid_feature have 64 * values 0, 1 and 2. 65 */ 66 unsigned int kindpos[3]; 67 }; 68 69 static int min(int x, int y) { return x < y ? x : y; } 70 71 static int hid_get_item_raw(hid_data_t s, hid_item_t *h); 72 73 static void 74 hid_clear_local(hid_item_t *c) 75 { 76 77 c->usage = 0; 78 c->usage_minimum = 0; 79 c->usage_maximum = 0; 80 c->designator_index = 0; 81 c->designator_minimum = 0; 82 c->designator_maximum = 0; 83 c->string_index = 0; 84 c->string_minimum = 0; 85 c->string_maximum = 0; 86 c->set_delimiter = 0; 87 } 88 89 hid_data_t 90 hid_start_parse(report_desc_t d, int kindset, int id) 91 { 92 struct hid_data *s; 93 94 s = malloc(sizeof *s); 95 if (s == NULL) 96 return (NULL); 97 memset(s, 0, sizeof *s); 98 s->start = s->p = d->data; 99 s->end = d->data + d->size; 100 s->kindset = kindset; 101 s->reportid = id; 102 s->hassavedcoll = 0; 103 return (s); 104 } 105 106 void 107 hid_end_parse(hid_data_t s) 108 { 109 110 while (s->cur.next) { 111 hid_item_t *hi = s->cur.next->next; 112 free(s->cur.next); 113 s->cur.next = hi; 114 } 115 free(s); 116 } 117 118 int 119 hid_get_item(hid_data_t s, hid_item_t *h) 120 { 121 int r; 122 123 for (;;) { 124 r = hid_get_item_raw(s, h); 125 if (r <= 0) 126 break; 127 if (h->report_ID == s->reportid || s->reportid == -1) 128 break; 129 } 130 return (r); 131 } 132 133 #define REPORT_SAVED_COLL \ 134 do { \ 135 if (s->hassavedcoll) { \ 136 *h = s->savedcoll; \ 137 h->report_ID = c->report_ID; \ 138 s->hassavedcoll = 0; \ 139 return (1); \ 140 } \ 141 } while(/*LINTED*/ 0) 142 143 static int 144 hid_get_item_raw(hid_data_t s, hid_item_t *h) 145 { 146 hid_item_t *c = &s->cur, *hi, nc; 147 unsigned int bTag = 0, bType = 0, bSize; 148 unsigned char *data; 149 hid_kind_t retkind; 150 unsigned char *p; 151 int dval, i; 152 153 top: 154 if (s->multimax) { 155 REPORT_SAVED_COLL; 156 if (c->logical_minimum >= c->logical_maximum) { 157 if (s->logminsize == 1) 158 c->logical_minimum =(int8_t)c->logical_minimum; 159 else if (s->logminsize == 2) 160 c->logical_minimum =(int16_t)c->logical_minimum; 161 } 162 if (s->multi < s->multimax) { 163 c->usage = s->usages[min(s->multi, s->nusage-1)]; 164 s->multi++; 165 *h = *c; 166 /* 167 * 'multimax' is only non-zero if the current 168 * item kind is input/output/feature 169 */ 170 h->pos = s->kindpos[c->kind]; 171 s->kindpos[c->kind] += c->report_size; 172 h->next = 0; 173 return (1); 174 } else { 175 c->report_count = s->multimax; 176 s->multimax = 0; 177 s->nusage = 0; 178 hid_clear_local(c); 179 } 180 } 181 for (;;) { 182 p = s->p; 183 if (p >= s->end) 184 return (0); 185 186 bSize = *p++; 187 if (bSize == 0xfe) { 188 /* long item */ 189 bSize = *p++; 190 bSize |= *p++ << 8; 191 bTag = *p++; 192 data = p; 193 p += bSize; 194 } else { 195 /* short item */ 196 bTag = bSize >> 4; 197 bType = (bSize >> 2) & 3; 198 bSize &= 3; 199 if (bSize == 3) bSize = 4; 200 data = p; 201 p += bSize; 202 } 203 s->p = p; 204 /* 205 * The spec is unclear if the data is signed or unsigned. 206 */ 207 switch(bSize) { 208 case 0: 209 dval = 0; 210 break; 211 case 1: 212 dval = /*(int8_t)*/*data++; 213 break; 214 case 2: 215 dval = *data++; 216 dval |= *data++ << 8; 217 dval = /*(int16_t)*/dval; 218 break; 219 case 4: 220 dval = *data++; 221 dval |= *data++ << 8; 222 dval |= *data++ << 16; 223 dval |= *data++ << 24; 224 break; 225 default: 226 return (-1); 227 } 228 229 switch (bType) { 230 case 0: /* Main */ 231 switch (bTag) { 232 case 8: /* Input */ 233 retkind = hid_input; 234 ret: 235 if (!(s->kindset & (1 << retkind))) { 236 /* Drop the items of this kind */ 237 s->nusage = 0; 238 continue; 239 } 240 c->kind = retkind; 241 c->flags = dval; 242 if (c->flags & HIO_VARIABLE) { 243 s->multimax = c->report_count; 244 s->multi = 0; 245 c->report_count = 1; 246 if (s->minset) { 247 for (i = c->usage_minimum; 248 i <= c->usage_maximum; i++) { 249 s->usages[s->nusage] = i; 250 if (s->nusage < MAXUSAGE-1) 251 s->nusage++; 252 } 253 c->usage_minimum = 0; 254 c->usage_maximum = 0; 255 s->minset = 0; 256 } 257 goto top; 258 } else { 259 if (s->minset) 260 c->usage = c->usage_minimum; 261 *h = *c; 262 h->next = 0; 263 h->pos = s->kindpos[c->kind]; 264 s->kindpos[c->kind] += 265 c->report_size * c->report_count; 266 hid_clear_local(c); 267 s->minset = 0; 268 return (1); 269 } 270 case 9: /* Output */ 271 retkind = hid_output; 272 goto ret; 273 case 10: /* Collection */ 274 c->kind = hid_collection; 275 c->collection = dval; 276 c->collevel++; 277 nc = *c; 278 hid_clear_local(c); 279 /*c->report_ID = NO_REPORT_ID;*/ 280 s->nusage = 0; 281 if (s->hassavedcoll) { 282 *h = s->savedcoll; 283 h->report_ID = nc.report_ID; 284 s->savedcoll = nc; 285 return (1); 286 } else { 287 s->hassavedcoll = 1; 288 s->savedcoll = nc; 289 } 290 break; 291 case 11: /* Feature */ 292 retkind = hid_feature; 293 goto ret; 294 case 12: /* End collection */ 295 REPORT_SAVED_COLL; 296 c->kind = hid_endcollection; 297 c->collevel--; 298 *h = *c; 299 /*hid_clear_local(c);*/ 300 s->nusage = 0; 301 return (1); 302 default: 303 return (-2); 304 } 305 break; 306 307 case 1: /* Global */ 308 switch (bTag) { 309 case 0: 310 c->_usage_page = dval << 16; 311 break; 312 case 1: 313 c->logical_minimum = dval; 314 s->logminsize = bSize; 315 break; 316 case 2: 317 c->logical_maximum = dval; 318 break; 319 case 3: 320 c->physical_minimum = dval; 321 break; 322 case 4: 323 c->physical_maximum = dval; 324 break; 325 case 5: 326 c->unit_exponent = dval; 327 break; 328 case 6: 329 c->unit = dval; 330 break; 331 case 7: 332 c->report_size = dval; 333 break; 334 case 8: 335 c->report_ID = dval; 336 s->kindpos[hid_input] = 0; 337 s->kindpos[hid_output] = 0; 338 s->kindpos[hid_feature] = 0; 339 break; 340 case 9: 341 c->report_count = dval; 342 break; 343 case 10: /* Push */ 344 hi = malloc(sizeof *hi); 345 /* XXX unchecked malloc */ 346 *hi = s->cur; 347 c->next = hi; 348 break; 349 case 11: /* Pop */ 350 hi = c->next; 351 s->cur = *hi; 352 free(hi); 353 break; 354 default: 355 return (-3); 356 } 357 break; 358 case 2: /* Local */ 359 switch (bTag) { 360 case 0: 361 c->usage = c->_usage_page | dval; 362 if (s->nusage < MAXUSAGE) 363 s->usages[s->nusage++] = c->usage; 364 /* else XXX */ 365 break; 366 case 1: 367 s->minset = 1; 368 c->usage_minimum = c->_usage_page | dval; 369 break; 370 case 2: 371 c->usage_maximum = c->_usage_page | dval; 372 break; 373 case 3: 374 c->designator_index = dval; 375 break; 376 case 4: 377 c->designator_minimum = dval; 378 break; 379 case 5: 380 c->designator_maximum = dval; 381 break; 382 case 7: 383 c->string_index = dval; 384 break; 385 case 8: 386 c->string_minimum = dval; 387 break; 388 case 9: 389 c->string_maximum = dval; 390 break; 391 case 10: 392 c->set_delimiter = dval; 393 break; 394 default: 395 break; 396 } 397 break; 398 default: 399 break; 400 } 401 } 402 return (0); 403 } 404 405 int 406 hid_report_size(report_desc_t r, enum hid_kind k, int id) 407 { 408 struct hid_data *d; 409 struct hid_item h; 410 uint32_t temp; 411 uint32_t hpos; 412 uint32_t lpos; 413 int report_id = 0; 414 415 hpos = 0; 416 lpos = 0xffffffff; 417 418 memset(&h, 0, sizeof h); 419 for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) { 420 if ((h.report_ID == id || id < 0) && h.kind == k) { 421 /* compute minimum */ 422 if (lpos > h.pos) 423 lpos = h.pos; 424 /* compute end position */ 425 temp = h.pos + (h.report_size * h.report_count); 426 /* compute maximum */ 427 if (hpos < temp) 428 hpos = temp; 429 if (h.report_ID != 0) 430 report_id = 1; 431 } 432 } 433 hid_end_parse(d); 434 435 /* safety check - can happen in case of currupt descriptors */ 436 if (lpos > hpos) 437 temp = 0; 438 else 439 temp = hpos - lpos; 440 441 /* return length in bytes rounded up */ 442 return ((temp + 7) / 8); 443 } 444 445 int 446 hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 447 hid_item_t *h, int id) 448 { 449 struct hid_data *d; 450 451 for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) { 452 if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 453 hid_end_parse(d); 454 return (1); 455 } 456 } 457 hid_end_parse(d); 458 h->report_size = 0; 459 return (0); 460 } 461