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 --- 9 unchanged lines hidden (view full) --- 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: head/lib/libusbhid/parse.c 113273 2003-04-09 01:52:49Z mdodd $"); |
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 44struct 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 72static int min(int x, int y) { return x < y ? x : y; } 73 |
74static int hid_get_item_raw(hid_data_t s, hid_item_t *h); 75 |
76static void 77hid_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 92hid_data_t |
93hid_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 107void 108hid_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 118int 119hid_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 143static int 144hid_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; --- 68 unchanged lines hidden (view full) --- 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: --- 5 unchanged lines hidden (view full) --- 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; --- 5 unchanged lines hidden (view full) --- 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: --- 17 unchanged lines hidden (view full) --- 402 break; 403 default: 404 return (-5); 405 } 406 } 407} 408 409int |
410hid_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 427int |
428hid_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} |