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