1 /* $NetBSD: parse.c,v 1.2 2001/12/29 20:44:22 augustss Exp $ */ 2 3 /* 4 * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <assert.h> 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 _DIAGASSERT(c != NULL); 78 79 c->usage = 0; 80 c->usage_minimum = 0; 81 c->usage_maximum = 0; 82 c->designator_index = 0; 83 c->designator_minimum = 0; 84 c->designator_maximum = 0; 85 c->string_index = 0; 86 c->string_minimum = 0; 87 c->string_maximum = 0; 88 c->set_delimiter = 0; 89 c->report_size = 0; 90 } 91 92 hid_data_t 93 hid_start_parse(report_desc_t d, int kindset, int id) 94 { 95 struct hid_data *s; 96 97 _DIAGASSERT(d != NULL); 98 99 s = malloc(sizeof *s); 100 memset(s, 0, sizeof *s); 101 s->start = s->p = d->data; 102 s->end = d->data + d->size; 103 s->kindset = kindset; 104 s->reportid = id; 105 s->hassavedcoll = 0; 106 return (s); 107 } 108 109 void 110 hid_end_parse(hid_data_t s) 111 { 112 113 _DIAGASSERT(s != NULL); 114 115 while (s->cur.next) { 116 hid_item_t *hi = s->cur.next->next; 117 free(s->cur.next); 118 s->cur.next = hi; 119 } 120 free(s); 121 } 122 123 int 124 hid_get_item(hid_data_t s, hid_item_t *h) 125 { 126 int r; 127 128 for (;;) { 129 r = hid_get_item_raw(s, h); 130 if (r <= 0) 131 break; 132 if (h->report_ID == s->reportid || s->reportid == -1) 133 break; 134 } 135 return (r); 136 } 137 138 #define REPORT_SAVED_COLL \ 139 do { \ 140 if (s->hassavedcoll) { \ 141 *h = s->savedcoll; \ 142 h->report_ID = c->report_ID; \ 143 s->hassavedcoll = 0; \ 144 return (1); \ 145 } \ 146 } while(/*LINTED*/ 0) 147 148 static int 149 hid_get_item_raw(hid_data_t s, hid_item_t *h) 150 { 151 hid_item_t *c; 152 unsigned int bTag = 0, bType = 0, bSize; 153 unsigned char *data; 154 int dval; 155 unsigned char *p; 156 hid_item_t *hi; 157 hid_item_t nc; 158 int i; 159 hid_kind_t retkind; 160 161 _DIAGASSERT(s != NULL); 162 _DIAGASSERT(h != NULL); 163 164 c = &s->cur; 165 166 top: 167 if (s->multimax) { 168 REPORT_SAVED_COLL; 169 if (c->logical_minimum >= c->logical_maximum) { 170 if (s->logminsize == 1) 171 c->logical_minimum =(int8_t)c->logical_minimum; 172 else if (s->logminsize == 2) 173 c->logical_minimum =(int16_t)c->logical_minimum; 174 } 175 if (s->multi < s->multimax) { 176 c->usage = s->usages[min(s->multi, s->nusage-1)]; 177 s->multi++; 178 *h = *c; 179 /* 180 * 'multimax' is only non-zero if the current 181 * item kind is input/output/feature 182 */ 183 h->pos = s->kindpos[c->kind]; 184 s->kindpos[c->kind] += c->report_size; 185 h->next = 0; 186 return (1); 187 } else { 188 c->report_count = s->multimax; 189 s->multimax = 0; 190 s->nusage = 0; 191 hid_clear_local(c); 192 } 193 } 194 for (;;) { 195 p = s->p; 196 if (p >= s->end) 197 return (0); 198 199 bSize = *p++; 200 if (bSize == 0xfe) { 201 /* long item */ 202 bSize = *p++; 203 bSize |= *p++ << 8; 204 bTag = *p++; 205 data = p; 206 p += bSize; 207 } else { 208 /* short item */ 209 bTag = bSize >> 4; 210 bType = (bSize >> 2) & 3; 211 bSize &= 3; 212 if (bSize == 3) bSize = 4; 213 data = p; 214 p += bSize; 215 } 216 s->p = p; 217 /* 218 * The spec is unclear if the data is signed or unsigned. 219 */ 220 switch(bSize) { 221 case 0: 222 dval = 0; 223 break; 224 case 1: 225 dval = /*(int8_t)*/*data++; 226 break; 227 case 2: 228 dval = *data++; 229 dval |= *data++ << 8; 230 dval = /*(int16_t)*/dval; 231 break; 232 case 4: 233 dval = *data++; 234 dval |= *data++ << 8; 235 dval |= *data++ << 16; 236 dval |= *data++ << 24; 237 break; 238 default: 239 return (-1); 240 } 241 242 switch (bType) { 243 case 0: /* Main */ 244 switch (bTag) { 245 case 8: /* Input */ 246 retkind = hid_input; 247 ret: 248 if (!(s->kindset & (1 << retkind))) { 249 /* Drop the items of this kind */ 250 s->nusage = 0; 251 continue; 252 } 253 c->kind = retkind; 254 c->flags = dval; 255 if (c->flags & HIO_VARIABLE) { 256 s->multimax = c->report_count; 257 s->multi = 0; 258 c->report_count = 1; 259 if (s->minset) { 260 for (i = c->usage_minimum; 261 i <= c->usage_maximum; 262 i++) { 263 s->usages[s->nusage] = i; 264 if (s->nusage < MAXUSAGE-1) 265 s->nusage++; 266 } 267 c->usage_minimum = 0; 268 c->usage_maximum = 0; 269 s->minset = 0; 270 } 271 goto top; 272 } else { 273 if (s->minset) 274 c->usage = c->usage_minimum; 275 *h = *c; 276 h->next = 0; 277 h->pos = s->kindpos[c->kind]; 278 s->kindpos[c->kind] += 279 c->report_size * c->report_count; 280 hid_clear_local(c); 281 s->minset = 0; 282 return (1); 283 } 284 case 9: /* Output */ 285 retkind = hid_output; 286 goto ret; 287 case 10: /* Collection */ 288 c->kind = hid_collection; 289 c->collection = dval; 290 c->collevel++; 291 nc = *c; 292 hid_clear_local(c); 293 /*c->report_ID = NO_REPORT_ID;*/ 294 s->nusage = 0; 295 if (s->hassavedcoll) { 296 *h = s->savedcoll; 297 h->report_ID = nc.report_ID; 298 s->savedcoll = nc; 299 return (1); 300 } else { 301 s->hassavedcoll = 1; 302 s->savedcoll = nc; 303 } 304 break; 305 case 11: /* Feature */ 306 retkind = hid_feature; 307 goto ret; 308 case 12: /* End collection */ 309 REPORT_SAVED_COLL; 310 c->kind = hid_endcollection; 311 c->collevel--; 312 *h = *c; 313 /*hid_clear_local(c);*/ 314 s->nusage = 0; 315 return (1); 316 default: 317 return (-2); 318 } 319 break; 320 321 case 1: /* Global */ 322 switch (bTag) { 323 case 0: 324 c->_usage_page = dval << 16; 325 break; 326 case 1: 327 c->logical_minimum = dval; 328 s->logminsize = bSize; 329 break; 330 case 2: 331 c->logical_maximum = dval; 332 break; 333 case 3: 334 c->physical_maximum = dval; 335 break; 336 case 4: 337 c->physical_maximum = dval; 338 break; 339 case 5: 340 c->unit_exponent = dval; 341 break; 342 case 6: 343 c->unit = dval; 344 break; 345 case 7: 346 c->report_size = dval; 347 break; 348 case 8: 349 c->report_ID = dval; 350 s->kindpos[hid_input] = 351 s->kindpos[hid_output] = 352 s->kindpos[hid_feature] = 0; 353 break; 354 case 9: 355 c->report_count = dval; 356 break; 357 case 10: /* Push */ 358 hi = malloc(sizeof *hi); 359 *hi = s->cur; 360 c->next = hi; 361 break; 362 case 11: /* Pop */ 363 hi = c->next; 364 s->cur = *hi; 365 free(hi); 366 break; 367 default: 368 return (-3); 369 } 370 break; 371 case 2: /* Local */ 372 switch (bTag) { 373 case 0: 374 c->usage = c->_usage_page | dval; 375 if (s->nusage < MAXUSAGE) 376 s->usages[s->nusage++] = c->usage; 377 /* else XXX */ 378 break; 379 case 1: 380 s->minset = 1; 381 c->usage_minimum = c->_usage_page | dval; 382 break; 383 case 2: 384 c->usage_maximum = c->_usage_page | dval; 385 break; 386 case 3: 387 c->designator_index = dval; 388 break; 389 case 4: 390 c->designator_minimum = dval; 391 break; 392 case 5: 393 c->designator_maximum = dval; 394 break; 395 case 7: 396 c->string_index = dval; 397 break; 398 case 8: 399 c->string_minimum = dval; 400 break; 401 case 9: 402 c->string_maximum = dval; 403 break; 404 case 10: 405 c->set_delimiter = dval; 406 break; 407 default: 408 return (-4); 409 } 410 break; 411 default: 412 return (-5); 413 } 414 } 415 } 416 417 int 418 hid_report_size(report_desc_t r, enum hid_kind k, int id) 419 { 420 struct hid_data *d; 421 hid_item_t h; 422 int size; 423 424 _DIAGASSERT(r != NULL); 425 426 memset(&h, 0, sizeof h); 427 size = 0; 428 for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) { 429 if (h.report_ID == id && h.kind == k) { 430 size = d->kindpos[k]; 431 } 432 } 433 hid_end_parse(d); 434 return ((size + 7) / 8); 435 } 436 437 int 438 hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 439 hid_item_t *h, int id) 440 { 441 hid_data_t d; 442 443 _DIAGASSERT(desc != NULL); 444 _DIAGASSERT(h != NULL); 445 446 for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) { 447 if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 448 hid_end_parse(d); 449 return (1); 450 } 451 } 452 hid_end_parse(d); 453 h->report_size = 0; 454 return (0); 455 } 456