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