1 /* $OpenBSD: parse.c,v 1.2 2002/05/10 00:09:17 nate 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 memset(s, 0, sizeof *s); 97 s->start = s->p = d->data; 98 s->end = d->data + d->size; 99 s->kindset = kindset; 100 s->reportid = id; 101 s->hassavedcoll = 0; 102 return (s); 103 } 104 105 void 106 hid_end_parse(hid_data_t s) 107 { 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 = /*(int8_t)*/*data++; 217 break; 218 case 2: 219 dval = *data++; 220 dval |= *data++ << 8; 221 dval = /*(int16_t)*/dval; 222 break; 223 case 4: 224 dval = *data++; 225 dval |= *data++ << 8; 226 dval |= *data++ << 16; 227 dval |= *data++ << 24; 228 break; 229 default: 230 return (-1); 231 } 232 233 switch (bType) { 234 case 0: /* Main */ 235 switch (bTag) { 236 case 8: /* Input */ 237 retkind = hid_input; 238 ret: 239 if (!(s->kindset & (1 << retkind))) { 240 /* Drop the items of this kind */ 241 s->nusage = 0; 242 continue; 243 } 244 c->kind = retkind; 245 c->flags = dval; 246 if (c->flags & HIO_VARIABLE) { 247 s->multimax = c->report_count; 248 s->multi = 0; 249 c->report_count = 1; 250 if (s->minset) { 251 for (i = c->usage_minimum; 252 i <= c->usage_maximum; 253 i++) { 254 s->usages[s->nusage] = i; 255 if (s->nusage < MAXUSAGE-1) 256 s->nusage++; 257 } 258 c->usage_minimum = 0; 259 c->usage_maximum = 0; 260 s->minset = 0; 261 } 262 goto top; 263 } else { 264 if (s->minset) 265 c->usage = c->usage_minimum; 266 *h = *c; 267 h->next = 0; 268 h->pos = s->kindpos[c->kind]; 269 s->kindpos[c->kind] += 270 c->report_size * c->report_count; 271 hid_clear_local(c); 272 s->minset = 0; 273 return (1); 274 } 275 case 9: /* Output */ 276 retkind = hid_output; 277 goto ret; 278 case 10: /* Collection */ 279 c->kind = hid_collection; 280 c->collection = dval; 281 c->collevel++; 282 nc = *c; 283 hid_clear_local(c); 284 /*c->report_ID = NO_REPORT_ID;*/ 285 s->nusage = 0; 286 if (s->hassavedcoll) { 287 *h = s->savedcoll; 288 h->report_ID = nc.report_ID; 289 s->savedcoll = nc; 290 return (1); 291 } else { 292 s->hassavedcoll = 1; 293 s->savedcoll = nc; 294 } 295 break; 296 case 11: /* Feature */ 297 retkind = hid_feature; 298 goto ret; 299 case 12: /* End collection */ 300 REPORT_SAVED_COLL; 301 c->kind = hid_endcollection; 302 c->collevel--; 303 *h = *c; 304 /*hid_clear_local(c);*/ 305 s->nusage = 0; 306 return (1); 307 default: 308 return (-2); 309 } 310 break; 311 312 case 1: /* Global */ 313 switch (bTag) { 314 case 0: 315 c->_usage_page = dval << 16; 316 break; 317 case 1: 318 c->logical_minimum = dval; 319 s->logminsize = bSize; 320 break; 321 case 2: 322 c->logical_maximum = dval; 323 break; 324 case 3: 325 c->physical_maximum = dval; 326 break; 327 case 4: 328 c->physical_maximum = dval; 329 break; 330 case 5: 331 c->unit_exponent = dval; 332 break; 333 case 6: 334 c->unit = dval; 335 break; 336 case 7: 337 c->report_size = dval; 338 break; 339 case 8: 340 c->report_ID = dval; 341 s->kindpos[hid_input] = 342 s->kindpos[hid_output] = 343 s->kindpos[hid_feature] = 0; 344 break; 345 case 9: 346 c->report_count = dval; 347 break; 348 case 10: /* Push */ 349 hi = malloc(sizeof *hi); 350 *hi = s->cur; 351 c->next = hi; 352 break; 353 case 11: /* Pop */ 354 hi = c->next; 355 s->cur = *hi; 356 free(hi); 357 break; 358 default: 359 return (-3); 360 } 361 break; 362 case 2: /* Local */ 363 switch (bTag) { 364 case 0: 365 c->usage = c->_usage_page | dval; 366 if (s->nusage < MAXUSAGE) 367 s->usages[s->nusage++] = c->usage; 368 /* else XXX */ 369 break; 370 case 1: 371 s->minset = 1; 372 c->usage_minimum = c->_usage_page | dval; 373 break; 374 case 2: 375 c->usage_maximum = c->_usage_page | dval; 376 break; 377 case 3: 378 c->designator_index = dval; 379 break; 380 case 4: 381 c->designator_minimum = dval; 382 break; 383 case 5: 384 c->designator_maximum = dval; 385 break; 386 case 7: 387 c->string_index = dval; 388 break; 389 case 8: 390 c->string_minimum = dval; 391 break; 392 case 9: 393 c->string_maximum = dval; 394 break; 395 case 10: 396 c->set_delimiter = dval; 397 break; 398 default: 399 return (-4); 400 } 401 break; 402 default: 403 return (-5); 404 } 405 } 406 } 407 408 int 409 hid_report_size(report_desc_t r, enum hid_kind k, int id) 410 { 411 struct hid_data *d; 412 hid_item_t h; 413 int size; 414 415 memset(&h, 0, sizeof h); 416 size = 0; 417 for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) { 418 if (h.report_ID == id && h.kind == k) { 419 size = d->kindpos[k]; 420 } 421 } 422 hid_end_parse(d); 423 return ((size + 7) / 8); 424 } 425 426 int 427 hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, 428 hid_item_t *h, int id) 429 { 430 hid_data_t d; 431 432 for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) { 433 if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) { 434 hid_end_parse(d); 435 return (1); 436 } 437 } 438 hid_end_parse(d); 439 h->report_size = 0; 440 return (0); 441 } 442