libusb20_desc.c revision 203775
1/* $FreeBSD: head/lib/libusb/libusb20_desc.c 203775 2010-02-11 08:34:41Z wkoszek $ */ 2/*- 3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#include <sys/queue.h> 31 32#include "libusb20.h" 33#include "libusb20_desc.h" 34#include "libusb20_int.h" 35 36static const uint32_t libusb20_me_encode_empty[2]; /* dummy */ 37 38LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC); 39LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC); 40LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC); 41LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC); 42LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP); 43 44/*------------------------------------------------------------------------* 45 * libusb20_parse_config_desc 46 * 47 * Return values: 48 * NULL: Out of memory. 49 * Else: A valid config structure pointer which must be passed to "free()" 50 *------------------------------------------------------------------------*/ 51struct libusb20_config * 52libusb20_parse_config_desc(const void *config_desc) 53{ 54 struct libusb20_config *lub_config; 55 struct libusb20_interface *lub_interface; 56 struct libusb20_interface *lub_alt_interface; 57 struct libusb20_interface *last_if; 58 struct libusb20_endpoint *lub_endpoint; 59 struct libusb20_endpoint *last_ep; 60 61 struct libusb20_me_struct pcdesc; 62 const uint8_t *ptr; 63 uint32_t size; 64 uint16_t niface_no_alt; 65 uint16_t niface; 66 uint16_t nendpoint; 67 uint8_t iface_no; 68 69 ptr = config_desc; 70 if (ptr[1] != LIBUSB20_DT_CONFIG) { 71 return (NULL); /* not config descriptor */ 72 } 73 /* 74 * The first "bInterfaceNumber" should never have the value 0xff. 75 * Then it is corrupt. 76 */ 77 niface_no_alt = 0; 78 nendpoint = 0; 79 niface = 0; 80 iface_no = 0 - 1; 81 ptr = NULL; 82 83 /* get "wTotalLength" and setup "pcdesc" */ 84 pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0); 85 pcdesc.len = 86 ((const uint8_t *)config_desc)[2] | 87 (((const uint8_t *)config_desc)[3] << 8); 88 pcdesc.type = LIBUSB20_ME_IS_RAW; 89 90 /* descriptor pre-scan */ 91 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) { 92 if (ptr[1] == LIBUSB20_DT_ENDPOINT) { 93 nendpoint++; 94 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) { 95 niface++; 96 /* check "bInterfaceNumber" */ 97 if (ptr[2] != iface_no) { 98 iface_no = ptr[2]; 99 niface_no_alt++; 100 } 101 } 102 } 103 104 /* sanity checking */ 105 if (niface >= 256) { 106 return (NULL); /* corrupt */ 107 } 108 if (nendpoint >= 256) { 109 return (NULL); /* corrupt */ 110 } 111 size = sizeof(*lub_config) + 112 (niface * sizeof(*lub_interface)) + 113 (nendpoint * sizeof(*lub_endpoint)) + 114 pcdesc.len; 115 116 lub_config = malloc(size); 117 if (lub_config == NULL) { 118 return (NULL); /* out of memory */ 119 } 120 /* make sure memory is initialised */ 121 memset(lub_config, 0, size); 122 123 lub_interface = (void *)(lub_config + 1); 124 lub_alt_interface = (void *)(lub_interface + niface_no_alt); 125 lub_endpoint = (void *)(lub_interface + niface); 126 127 /* 128 * Make a copy of the config descriptor, so that the caller can free 129 * the inital config descriptor pointer! 130 */ 131 ptr = (void *)(lub_endpoint + nendpoint); 132 memcpy(LIBUSB20_ADD_BYTES(ptr, 0), config_desc, pcdesc.len); 133 pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0); 134 config_desc = LIBUSB20_ADD_BYTES(ptr, 0); 135 136 /* init config structure */ 137 138 ptr = config_desc; 139 140 LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc); 141 142 if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) { 143 /* ignore */ 144 } 145 lub_config->num_interface = 0; 146 lub_config->interface = lub_interface; 147 lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]); 148 lub_config->extra.len = -ptr[0]; 149 lub_config->extra.type = LIBUSB20_ME_IS_RAW; 150 151 /* reset states */ 152 niface = 0; 153 iface_no = 0 - 1; 154 ptr = NULL; 155 lub_interface--; 156 lub_endpoint--; 157 last_if = NULL; 158 last_ep = NULL; 159 160 /* descriptor pre-scan */ 161 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) { 162 if (ptr[1] == LIBUSB20_DT_ENDPOINT) { 163 if (last_if) { 164 lub_endpoint++; 165 last_ep = lub_endpoint; 166 last_if->num_endpoints++; 167 168 LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc); 169 170 if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) { 171 /* ignore */ 172 } 173 last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]); 174 last_ep->extra.len = 0; 175 last_ep->extra.type = LIBUSB20_ME_IS_RAW; 176 } else { 177 lub_config->extra.len += ptr[0]; 178 } 179 180 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) { 181 if (ptr[2] != iface_no) { 182 /* new interface */ 183 iface_no = ptr[2]; 184 lub_interface++; 185 lub_config->num_interface++; 186 last_if = lub_interface; 187 niface++; 188 } else { 189 /* one more alternate setting */ 190 lub_interface->num_altsetting++; 191 last_if = lub_alt_interface; 192 lub_alt_interface++; 193 } 194 195 LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc); 196 197 if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) { 198 /* ignore */ 199 } 200 /* 201 * Sometimes USB devices have corrupt interface 202 * descriptors and we need to overwrite the provided 203 * interface number! 204 */ 205 last_if->desc.bInterfaceNumber = niface - 1; 206 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]); 207 last_if->extra.len = 0; 208 last_if->extra.type = LIBUSB20_ME_IS_RAW; 209 last_if->endpoints = lub_endpoint + 1; 210 last_if->altsetting = lub_alt_interface; 211 last_if->num_altsetting = 0; 212 last_if->num_endpoints = 0; 213 last_ep = NULL; 214 } else { 215 /* unknown descriptor */ 216 if (last_if) { 217 if (last_ep) { 218 last_ep->extra.len += ptr[0]; 219 } else { 220 last_if->extra.len += ptr[0]; 221 } 222 } else { 223 lub_config->extra.len += ptr[0]; 224 } 225 } 226 } 227 return (lub_config); 228} 229 230/*------------------------------------------------------------------------* 231 * libusb20_desc_foreach 232 * 233 * Safe traversal of USB descriptors. 234 * 235 * Return values: 236 * NULL: End of descriptors 237 * Else: Pointer to next descriptor 238 *------------------------------------------------------------------------*/ 239const uint8_t * 240libusb20_desc_foreach(const struct libusb20_me_struct *pdesc, 241 const uint8_t *psubdesc) 242{ 243 const uint8_t *start; 244 const uint8_t *end; 245 const uint8_t *desc_next; 246 247 /* be NULL safe */ 248 if (pdesc == NULL) 249 return (NULL); 250 251 start = (const uint8_t *)pdesc->ptr; 252 end = LIBUSB20_ADD_BYTES(start, pdesc->len); 253 254 /* get start of next descriptor */ 255 if (psubdesc == NULL) 256 psubdesc = start; 257 else 258 psubdesc = psubdesc + psubdesc[0]; 259 260 /* check that the next USB descriptor is within the range */ 261 if ((psubdesc < start) || (psubdesc >= end)) 262 return (NULL); /* out of range, or EOD */ 263 264 /* check start of the second next USB descriptor, if any */ 265 desc_next = psubdesc + psubdesc[0]; 266 if ((desc_next < start) || (desc_next > end)) 267 return (NULL); /* out of range */ 268 269 /* check minimum descriptor length */ 270 if (psubdesc[0] < 3) 271 return (NULL); /* too short descriptor */ 272 273 return (psubdesc); /* return start of next descriptor */ 274} 275 276/*------------------------------------------------------------------------* 277 * libusb20_me_get_1 - safety wrapper to read out one byte 278 *------------------------------------------------------------------------*/ 279uint8_t 280libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset) 281{ 282 if (offset < ie->len) { 283 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset))); 284 } 285 return (0); 286} 287 288/*------------------------------------------------------------------------* 289 * libusb20_me_get_2 - safety wrapper to read out one word 290 *------------------------------------------------------------------------*/ 291uint16_t 292libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset) 293{ 294 return (libusb20_me_get_1(ie, offset) | 295 (libusb20_me_get_1(ie, offset + 1) << 8)); 296} 297 298/*------------------------------------------------------------------------* 299 * libusb20_me_encode - encode a message structure 300 * 301 * Description of parameters: 302 * "len" - maximum length of output buffer 303 * "ptr" - pointer to output buffer. If NULL, no data will be written 304 * "pd" - source structure 305 * 306 * Return values: 307 * 0..65535 - Number of bytes used, limited by the "len" input parameter. 308 *------------------------------------------------------------------------*/ 309uint16_t 310libusb20_me_encode(void *ptr, uint16_t len, const void *pd) 311{ 312 const uint8_t *pf; /* pointer to format data */ 313 uint8_t *buf; /* pointer to output buffer */ 314 315 uint32_t pd_offset; /* decoded structure offset */ 316 uint16_t len_old; /* old length */ 317 uint16_t pd_count; /* decoded element count */ 318 uint8_t me; /* message element */ 319 320 /* initialise */ 321 322 len_old = len; 323 buf = ptr; 324 pd_offset = sizeof(void *); 325 pf = (*((struct libusb20_me_format *const *)pd))->format; 326 327 /* scan */ 328 329 while (1) { 330 331 /* get information element */ 332 333 me = (pf[0]) & LIBUSB20_ME_MASK; 334 pd_count = pf[1] | (pf[2] << 8); 335 pf += 3; 336 337 /* encode the message element */ 338 339 switch (me) { 340 case LIBUSB20_ME_INT8: 341 while (pd_count--) { 342 uint8_t temp; 343 344 if (len < 1) /* overflow */ 345 goto done; 346 if (buf) { 347 temp = *((const uint8_t *) 348 LIBUSB20_ADD_BYTES(pd, pd_offset)); 349 buf[0] = temp; 350 buf += 1; 351 } 352 pd_offset += 1; 353 len -= 1; 354 } 355 break; 356 357 case LIBUSB20_ME_INT16: 358 pd_offset = -((-pd_offset) & ~1); /* align */ 359 while (pd_count--) { 360 uint16_t temp; 361 362 if (len < 2) /* overflow */ 363 goto done; 364 365 if (buf) { 366 temp = *((const uint16_t *) 367 LIBUSB20_ADD_BYTES(pd, pd_offset)); 368 buf[1] = (temp >> 8) & 0xFF; 369 buf[0] = temp & 0xFF; 370 buf += 2; 371 } 372 pd_offset += 2; 373 len -= 2; 374 } 375 break; 376 377 case LIBUSB20_ME_INT32: 378 pd_offset = -((-pd_offset) & ~3); /* align */ 379 while (pd_count--) { 380 uint32_t temp; 381 382 if (len < 4) /* overflow */ 383 goto done; 384 if (buf) { 385 temp = *((const uint32_t *) 386 LIBUSB20_ADD_BYTES(pd, pd_offset)); 387 buf[3] = (temp >> 24) & 0xFF; 388 buf[2] = (temp >> 16) & 0xFF; 389 buf[1] = (temp >> 8) & 0xFF; 390 buf[0] = temp & 0xFF; 391 buf += 4; 392 } 393 pd_offset += 4; 394 len -= 4; 395 } 396 break; 397 398 case LIBUSB20_ME_INT64: 399 pd_offset = -((-pd_offset) & ~7); /* align */ 400 while (pd_count--) { 401 uint64_t temp; 402 403 if (len < 8) /* overflow */ 404 goto done; 405 if (buf) { 406 407 temp = *((const uint64_t *) 408 LIBUSB20_ADD_BYTES(pd, pd_offset)); 409 buf[7] = (temp >> 56) & 0xFF; 410 buf[6] = (temp >> 48) & 0xFF; 411 buf[5] = (temp >> 40) & 0xFF; 412 buf[4] = (temp >> 32) & 0xFF; 413 buf[3] = (temp >> 24) & 0xFF; 414 buf[2] = (temp >> 16) & 0xFF; 415 buf[1] = (temp >> 8) & 0xFF; 416 buf[0] = temp & 0xFF; 417 buf += 8; 418 } 419 pd_offset += 8; 420 len -= 8; 421 } 422 break; 423 424 case LIBUSB20_ME_STRUCT: 425 pd_offset = -((-pd_offset) & 426 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */ 427 while (pd_count--) { 428 void *src_ptr; 429 uint16_t src_len; 430 struct libusb20_me_struct *ps; 431 432 ps = LIBUSB20_ADD_BYTES(pd, pd_offset); 433 434 switch (ps->type) { 435 case LIBUSB20_ME_IS_RAW: 436 src_len = ps->len; 437 src_ptr = ps->ptr; 438 break; 439 440 case LIBUSB20_ME_IS_ENCODED: 441 if (ps->len == 0) { 442 /* 443 * Length is encoded 444 * in the data itself 445 * and should be 446 * correct: 447 */ 448 ps->len = 0 - 1; 449 } 450 src_len = libusb20_me_get_1(pd, 0); 451 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1); 452 if (src_len == 0xFF) { 453 /* length is escaped */ 454 src_len = libusb20_me_get_2(pd, 1); 455 src_ptr = 456 LIBUSB20_ADD_BYTES(ps->ptr, 3); 457 } 458 break; 459 460 case LIBUSB20_ME_IS_DECODED: 461 /* reserve 3 length bytes */ 462 src_len = libusb20_me_encode(NULL, 463 0 - 1 - 3, ps->ptr); 464 src_ptr = NULL; 465 break; 466 467 default: /* empty structure */ 468 src_len = 0; 469 src_ptr = NULL; 470 break; 471 } 472 473 if (src_len > 0xFE) { 474 if (src_len > (uint16_t)(0 - 1 - 3)) 475 /* overflow */ 476 goto done; 477 478 if (len < (src_len + 3)) 479 /* overflow */ 480 goto done; 481 482 if (buf) { 483 buf[0] = 0xFF; 484 buf[1] = (src_len & 0xFF); 485 buf[2] = (src_len >> 8) & 0xFF; 486 buf += 3; 487 } 488 len -= (src_len + 3); 489 } else { 490 if (len < (src_len + 1)) 491 /* overflow */ 492 goto done; 493 494 if (buf) { 495 buf[0] = (src_len & 0xFF); 496 buf += 1; 497 } 498 len -= (src_len + 1); 499 } 500 501 /* check for buffer and non-zero length */ 502 503 if (buf && src_len) { 504 if (ps->type == LIBUSB20_ME_IS_DECODED) { 505 /* 506 * Repeat encode 507 * procedure - we have 508 * room for the 509 * complete structure: 510 */ 511 uint16_t dummy; 512 513 dummy = libusb20_me_encode(buf, 514 0 - 1 - 3, ps->ptr); 515 } else { 516 bcopy(src_ptr, buf, src_len); 517 } 518 buf += src_len; 519 } 520 pd_offset += sizeof(struct libusb20_me_struct); 521 } 522 break; 523 524 default: 525 goto done; 526 } 527 } 528done: 529 return (len_old - len); 530} 531 532/*------------------------------------------------------------------------* 533 * libusb20_me_decode - decode a message into a decoded structure 534 * 535 * Description of parameters: 536 * "ptr" - message pointer 537 * "len" - message length 538 * "pd" - pointer to decoded structure 539 * 540 * Returns: 541 * "0..65535" - number of bytes decoded, limited by "len" 542 *------------------------------------------------------------------------*/ 543uint16_t 544libusb20_me_decode(const void *ptr, uint16_t len, void *pd) 545{ 546 const uint8_t *pf; /* pointer to format data */ 547 const uint8_t *buf; /* pointer to input buffer */ 548 549 uint32_t pd_offset; /* decoded structure offset */ 550 uint16_t len_old; /* old length */ 551 uint16_t pd_count; /* decoded element count */ 552 uint8_t me; /* message element */ 553 554 /* initialise */ 555 556 len_old = len; 557 buf = ptr; 558 pd_offset = sizeof(void *); 559 pf = (*((struct libusb20_me_format **)pd))->format; 560 561 /* scan */ 562 563 while (1) { 564 565 /* get information element */ 566 567 me = (pf[0]) & LIBUSB20_ME_MASK; 568 pd_count = pf[1] | (pf[2] << 8); 569 pf += 3; 570 571 /* decode the message element by type */ 572 573 switch (me) { 574 case LIBUSB20_ME_INT8: 575 while (pd_count--) { 576 uint8_t temp; 577 578 if (len < 1) { 579 len = 0; 580 temp = 0; 581 } else { 582 len -= 1; 583 temp = buf[0]; 584 buf++; 585 } 586 *((uint8_t *)LIBUSB20_ADD_BYTES(pd, 587 pd_offset)) = temp; 588 pd_offset += 1; 589 } 590 break; 591 592 case LIBUSB20_ME_INT16: 593 pd_offset = -((-pd_offset) & ~1); /* align */ 594 while (pd_count--) { 595 uint16_t temp; 596 597 if (len < 2) { 598 len = 0; 599 temp = 0; 600 } else { 601 len -= 2; 602 temp = buf[1] << 8; 603 temp |= buf[0]; 604 buf += 2; 605 } 606 *((uint16_t *)LIBUSB20_ADD_BYTES(pd, 607 pd_offset)) = temp; 608 pd_offset += 2; 609 } 610 break; 611 612 case LIBUSB20_ME_INT32: 613 pd_offset = -((-pd_offset) & ~3); /* align */ 614 while (pd_count--) { 615 uint32_t temp; 616 617 if (len < 4) { 618 len = 0; 619 temp = 0; 620 } else { 621 len -= 4; 622 temp = buf[3] << 24; 623 temp |= buf[2] << 16; 624 temp |= buf[1] << 8; 625 temp |= buf[0]; 626 buf += 4; 627 } 628 629 *((uint32_t *)LIBUSB20_ADD_BYTES(pd, 630 pd_offset)) = temp; 631 pd_offset += 4; 632 } 633 break; 634 635 case LIBUSB20_ME_INT64: 636 pd_offset = -((-pd_offset) & ~7); /* align */ 637 while (pd_count--) { 638 uint64_t temp; 639 640 if (len < 8) { 641 len = 0; 642 temp = 0; 643 } else { 644 len -= 8; 645 temp = ((uint64_t)buf[7]) << 56; 646 temp |= ((uint64_t)buf[6]) << 48; 647 temp |= ((uint64_t)buf[5]) << 40; 648 temp |= ((uint64_t)buf[4]) << 32; 649 temp |= buf[3] << 24; 650 temp |= buf[2] << 16; 651 temp |= buf[1] << 8; 652 temp |= buf[0]; 653 buf += 8; 654 } 655 656 *((uint64_t *)LIBUSB20_ADD_BYTES(pd, 657 pd_offset)) = temp; 658 pd_offset += 8; 659 } 660 break; 661 662 case LIBUSB20_ME_STRUCT: 663 pd_offset = -((-pd_offset) & 664 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */ 665 while (pd_count--) { 666 uint16_t temp; 667 uint16_t dummy; 668 struct libusb20_me_struct *ps; 669 670 ps = LIBUSB20_ADD_BYTES(pd, pd_offset); 671 672 if (ps->type == LIBUSB20_ME_IS_ENCODED) { 673 /* 674 * Pre-store a de-constified 675 * pointer to the raw 676 * structure: 677 */ 678 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0); 679 680 /* 681 * Get the correct number of 682 * length bytes: 683 */ 684 if (len != 0) { 685 if (buf[0] == 0xFF) { 686 ps->len = 3; 687 } else { 688 ps->len = 1; 689 } 690 } else { 691 ps->len = 0; 692 } 693 } 694 /* get the structure length */ 695 696 if (len != 0) { 697 if (buf[0] == 0xFF) { 698 if (len < 3) { 699 len = 0; 700 temp = 0; 701 } else { 702 len -= 3; 703 temp = buf[1] | 704 (buf[2] << 8); 705 buf += 3; 706 } 707 } else { 708 len -= 1; 709 temp = buf[0]; 710 buf += 1; 711 } 712 } else { 713 len = 0; 714 temp = 0; 715 } 716 /* check for invalid length */ 717 718 if (temp > len) { 719 len = 0; 720 temp = 0; 721 } 722 /* check wanted structure type */ 723 724 switch (ps->type) { 725 case LIBUSB20_ME_IS_ENCODED: 726 /* check for zero length */ 727 if (temp == 0) { 728 /* 729 * The pointer must 730 * be valid: 731 */ 732 ps->ptr = LIBUSB20_ADD_BYTES( 733 libusb20_me_encode_empty, 0); 734 ps->len = 1; 735 } else { 736 ps->len += temp; 737 } 738 break; 739 740 case LIBUSB20_ME_IS_RAW: 741 /* update length and pointer */ 742 ps->len = temp; 743 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0); 744 break; 745 746 case LIBUSB20_ME_IS_EMPTY: 747 case LIBUSB20_ME_IS_DECODED: 748 /* check for non-zero length */ 749 if (temp != 0) { 750 /* update type */ 751 ps->type = LIBUSB20_ME_IS_DECODED; 752 ps->len = 0; 753 /* 754 * Recursivly decode 755 * the next structure 756 */ 757 dummy = libusb20_me_decode(buf, 758 temp, ps->ptr); 759 } else { 760 /* update type */ 761 ps->type = LIBUSB20_ME_IS_EMPTY; 762 ps->len = 0; 763 } 764 break; 765 766 default: 767 /* 768 * nothing to do - should 769 * not happen 770 */ 771 ps->ptr = NULL; 772 ps->len = 0; 773 break; 774 } 775 buf += temp; 776 len -= temp; 777 pd_offset += sizeof(struct libusb20_me_struct); 778 } 779 break; 780 781 default: 782 goto done; 783 } 784 } 785done: 786 return (len_old - len); 787} 788