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