1 /* $OpenBSD: parse.c,v 1.3 2004/06/04 00:47:32 deraadt 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 c->report_size = 0; 88 } 89 90 hid_data_t 91 hid_start_parse(report_desc_t d, int kindset, int id) 92 { 93 struct hid_data *s; 94 95 s = malloc(sizeof *s); 96 if (s == NULL) 97 return (NULL); 98 memset(s, 0, sizeof *s); 99 s->start = s->p = d->data; 100 s->end = d->data + d->size; 101 s->kindset = kindset; 102 s->reportid = id; 103 s->hassavedcoll = 0; 104 return (s); 105 } 106 107 void 108 hid_end_parse(hid_data_t s) 109 { 110 111 while (s->cur.next) { 112 hid_item_t *hi = s->cur.next->next; 113 free(s->cur.next); 114 s->cur.next = hi; 115 } 116 free(s); 117 } 118 119 int 120 hid_get_item(hid_data_t s, hid_item_t *h) 121 { 122 int r; 123 124 for (;;) { 125 r = hid_get_item_raw(s, h); 126 if (r <= 0) 127 break; 128 if (h->report_ID == s->reportid || s->reportid == -1) 129 break; 130 } 131 return (r); 132 } 133 134 #define REPORT_SAVED_COLL \ 135 do { \ 136 if (s->hassavedcoll) { \ 137 *h = s->savedcoll; \ 138 h->report_ID = c->report_ID; \ 139 s->hassavedcoll = 0; \ 140 return (1); \ 141 } \ 142 } while(/*LINTED*/ 0) 143 144 static int 145 hid_get_item_raw(hid_data_t s, hid_item_t *h) 146 { 147 hid_item_t *c = &s->cur, *hi, nc; 148 unsigned int bTag = 0, bType = 0, bSize; 149 unsigned char *data; 150 hid_kind_t retkind; 151 unsigned char *p; 152 int dval, i; 153 154 top: 155 if (s->multimax) { 156 REPORT_SAVED_COLL; 157 if (c->logical_minimum >= c->logical_maximum) { 158 if (s->logminsize == 1) 159 c->logical_minimum =(int8_t)c->logical_minimum; 160 else if (s->logminsize == 2) 161 c->logical_minimum =(int16_t)c->logical_minimum; 162 } 163 if (s->multi < s->multimax) { 164 c->usage = s->usages[min(s->multi, s->nusage-1)]; 165 s->multi++; 166 *h = *c; 167 /* 168 * 'multimax' is only non-zero if the current 169 * item kind is input/output/feature 170 */ 171 h->pos = s->kindpos[c->kind]; 172 s->kindpos[c->kind] += c->report_size; 173 h->next = 0; 174 return (1); 175 } else { 176 c->report_count = s->multimax; 177 s->multimax = 0; 178 s->nusage = 0; 179 hid_clear_local(c); 180 } 181 } 182 for (;;) { 183 p = s->p; 184 if (p >= s->end) 185 return (0); 186 187 bSize = *p++; 188 if (bSize == 0xfe) { 189 /* long item */ 190 bSize = *p++; 191 bSize |= *p++ << 8; 192 bTag = *p++; 193 data = p; 194 p += bSize; 195 } else { 196 /* short item */ 197 bTag = bSize >> 4; 198 bType = (bSize >> 2) & 3; 199 bSize &= 3; 200 if (bSize == 3) bSize = 4; 201 data = p; 202 p += bSize; 203 } 204 s->p = p; 205 /* 206 * The spec is unclear if the data is signed or unsigned. 207 */ 208 switch(bSize) { 209 case 0: 210 dval = 0; 211 break; 212 case 1: 213 dval = /*(int8_t)*/*data++; 214 break; 215 case 2: 216 dval = *data++; 217 dval |= *data++ << 8; 218 dval = /*(int16_t)*/dval; 219 break; 220 case 4: 221 dval = *data++; 222 dval |= *data++ << 8; 223 dval |= *data++ << 16; 224 dval |= *data++ << 24; 225 break; 226 default: 227 return (-1); 228 } 229 230 switch (bType) { 231 case 0: /* Main */ 232 switch (bTag) { 233 case 8: /* Input */ 234 retkind = hid_input; 235 ret: 236 if (!(s->kindset & (1 << retkind))) { 237 /* Drop the items of this kind */ 238 s->nusage = 0; 239 continue; 240 } 241 c->kind = retkind; 242 c->flags = dval; 243 if (c->flags & HIO_VARIABLE) { 244 s->multimax = c->report_count; 245 s->multi = 0; 246 c->report_count = 1; 247 if (s->minset) { 248 for (i = c->usage_minimum; 249 i <= c->usage_maximum; i++) { 250 s->usages[s->nusage] = i; 251 if (s->nusage < MAXUSAGE-1) 252 s->nusage++; 253 } 254 c->usage_minimum = 0; 255 c->usage_maximum = 0; 256 s->minset = 0; 257 } 258 goto top; 259 } else { 260 if (s->minset) 261 c->usage = c->usage_minimum; 262 *h = *c; 263 h->next = 0; 264 h->pos = s->kindpos[c->kind]; 265 s->kindpos[c->kind] += 266 c->report_size * c->report_count; 267 hid_clear_local(c); 268 s->minset = 0; 269 return (1); 270 } 271 case 9: /* Output */ 272 retkind = hid_output; 273 goto ret; 274 case 10: /* Collection */ 275 c->kind = hid_collection; 276 c->collection = dval; 277 c->collevel++; 278 nc = *c; 279 hid_clear_local(c); 280 /*c->report_ID = NO_REPORT_ID;*/ 281 s->nusage = 0; 282 if (s->hassavedcoll) { 283 *h = s->savedcoll; 284 h->report_ID = nc.report_ID; 285 s->savedcoll = nc; 286 return (1); 287 } else { 288 s->hassavedcoll = 1; 289 s->savedcoll = nc; 290 } 291 break; 292 case 11: /* Feature */ 293 retkind = hid_feature; 294 goto ret; 295 case 12: /* End collection */ 296 REPORT_SAVED_COLL; 297 c->kind = hid_endcollection; 298 c->collevel--; 299 *h = *c; 300 /*hid_clear_local(c);*/ 301 s->nusage = 0; 302 return (1); 303 default: 304 return (-2); 305 } 306 break; 307 308 case 1: /* Global */ 309 switch (bTag) { 310 case 0: 311 c->_usage_page = dval << 16; 312 break; 313 case 1: 314 c->logical_minimum = dval; 315 s->logminsize = bSize; 316 break; 317 case 2: 318 c->logical_maximum = dval; 319 break; 320 case 3: 321 c->physical_maximum = dval; 322 break; 323 case 4: 324 c->physical_maximum = dval; 325 break; 326 case 5: 327 c->unit_exponent = dval; 328 break; 329 case 6: 330 c->unit = dval; 331 break; 332 case 7: 333 c->report_size = dval; 334 break; 335 case 8: 336 c->report_ID = dval; 337 s->kindpos[hid_input] = 0; 338 s->kindpos[hid_output] = 0; 339 s->kindpos[hid_feature] = 0; 340 break; 341 case 9: 342 c->report_count = dval; 343 break; 344 case 10: /* Push */ 345 hi = malloc(sizeof *hi); 346 /* XXX unchecked malloc */ 347 *hi = s->cur; 348 c->next = hi; 349 break; 350 case 11: /* Pop */ 351 hi = c->next; 352 s->cur = *hi; 353 free(hi); 354 break; 355 default: 356 return (-3); 357 } 358 break; 359 case 2: /* Local */ 360 switch (bTag) { 361 case 0: 362 c->usage = c->_usage_page | dval; 363 if (s->nusage < MAXUSAGE) 364 s->usages[s->nusage++] = c->usage; 365 /* else XXX */ 366 break; 367 case 1: 368 s->minset = 1; 369 c->usage_minimum = c->_usage_page | dval; 370 break; 371 case 2: 372 c->usage_maximum = c->_usage_page | dval; 373 break; 374 case 3: 375 c->designator_index = dval; 376 break; 377 case 4: 378 c->designator_minimum = dval; 379 break; 380 case 5: 381 c->designator_maximum = dval; 382 break; 383 case 7: 384 c->string_index = dval; 385 break; 386 case 8: 387 c->string_minimum = dval; 388 break; 389 case 9: 390 c->string_maximum = dval; 391 break; 392 case 10: 393 c->set_delimiter = dval; 394 break; 395 default: 396 return (-4); 397 } 398 break; 399 default: 400 return (-5); 401 } 402 } 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 hid_item_t h; 410 int size; 411 412 memset(&h, 0, sizeof h); 413 size = 0; 414 for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) { 415 if (h.report_ID == id && h.kind == k) { 416 size = d->kindpos[k]; 417 } 418 } 419 hid_end_parse(d); 420 return ((size + 7) / 8); 421 } 422 423 int 424 hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 425 hid_item_t *h, int id) 426 { 427 hid_data_t d; 428 429 for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) { 430 if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 431 hid_end_parse(d); 432 return (1); 433 } 434 } 435 hid_end_parse(d); 436 h->report_size = 0; 437 return (0); 438 } 439