libusb20.c revision 193313
1/* $FreeBSD: head/lib/libusb/libusb20.c 193313 2009-06-02 17:27:51Z thompsa $ */ 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 <ctype.h> 32#include <sys/queue.h> 33 34#include "libusb20.h" 35#include "libusb20_desc.h" 36#include "libusb20_int.h" 37 38static int 39dummy_int(void) 40{ 41 return (LIBUSB20_ERROR_NOT_SUPPORTED); 42} 43 44static void 45dummy_void(void) 46{ 47 return; 48} 49 50static void 51dummy_callback(struct libusb20_transfer *xfer) 52{ 53 ; /* style fix */ 54 switch (libusb20_tr_get_status(xfer)) { 55 case LIBUSB20_TRANSFER_START: 56 libusb20_tr_submit(xfer); 57 break; 58 default: 59 /* complete or error */ 60 break; 61 } 62 return; 63} 64 65#define dummy_get_config_desc_full (void *)dummy_int 66#define dummy_get_config_index (void *)dummy_int 67#define dummy_set_config_index (void *)dummy_int 68#define dummy_claim_interface (void *)dummy_int 69#define dummy_release_interface (void *)dummy_int 70#define dummy_set_alt_index (void *)dummy_int 71#define dummy_reset_device (void *)dummy_int 72#define dummy_set_power_mode (void *)dummy_int 73#define dummy_get_power_mode (void *)dummy_int 74#define dummy_kernel_driver_active (void *)dummy_int 75#define dummy_detach_kernel_driver (void *)dummy_int 76#define dummy_do_request_sync (void *)dummy_int 77#define dummy_tr_open (void *)dummy_int 78#define dummy_tr_close (void *)dummy_int 79#define dummy_tr_clear_stall_sync (void *)dummy_int 80#define dummy_process (void *)dummy_int 81#define dummy_dev_info (void *)dummy_int 82#define dummy_dev_get_iface_driver (void *)dummy_int 83 84#define dummy_tr_submit (void *)dummy_void 85#define dummy_tr_cancel_async (void *)dummy_void 86 87static const struct libusb20_device_methods libusb20_dummy_methods = { 88 LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy) 89}; 90 91void 92libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer) 93{ 94 ; /* style fix */ 95 96repeat: 97 98 if (!xfer->is_pending) { 99 xfer->status = LIBUSB20_TRANSFER_START; 100 } else { 101 xfer->is_pending = 0; 102 } 103 104 xfer->callback(xfer); 105 106 if (xfer->is_restart) { 107 xfer->is_restart = 0; 108 goto repeat; 109 } 110 if (xfer->is_draining && 111 (!xfer->is_pending)) { 112 xfer->is_draining = 0; 113 xfer->status = LIBUSB20_TRANSFER_DRAINED; 114 xfer->callback(xfer); 115 } 116 return; 117} 118 119int 120libusb20_tr_close(struct libusb20_transfer *xfer) 121{ 122 int error; 123 124 if (!xfer->is_opened) { 125 return (LIBUSB20_ERROR_OTHER); 126 } 127 error = xfer->pdev->methods->tr_close(xfer); 128 129 if (xfer->pLength) { 130 free(xfer->pLength); 131 } 132 if (xfer->ppBuffer) { 133 free(xfer->ppBuffer); 134 } 135 /* clear some fields */ 136 xfer->is_opened = 0; 137 xfer->maxFrames = 0; 138 xfer->maxTotalLength = 0; 139 xfer->maxPacketLen = 0; 140 return (error); 141} 142 143int 144libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 145 uint32_t MaxFrameCount, uint8_t ep_no) 146{ 147 uint32_t size; 148 int error; 149 150 if (xfer->is_opened) { 151 return (LIBUSB20_ERROR_BUSY); 152 } 153 if (MaxFrameCount == 0) { 154 return (LIBUSB20_ERROR_INVALID_PARAM); 155 } 156 xfer->maxFrames = MaxFrameCount; 157 158 size = MaxFrameCount * sizeof(xfer->pLength[0]); 159 xfer->pLength = malloc(size); 160 if (xfer->pLength == NULL) { 161 return (LIBUSB20_ERROR_NO_MEM); 162 } 163 memset(xfer->pLength, 0, size); 164 165 size = MaxFrameCount * sizeof(xfer->ppBuffer[0]); 166 xfer->ppBuffer = malloc(size); 167 if (xfer->ppBuffer == NULL) { 168 free(xfer->pLength); 169 return (LIBUSB20_ERROR_NO_MEM); 170 } 171 memset(xfer->ppBuffer, 0, size); 172 173 error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, 174 MaxFrameCount, ep_no); 175 176 if (error) { 177 free(xfer->ppBuffer); 178 free(xfer->pLength); 179 } else { 180 xfer->is_opened = 1; 181 } 182 return (error); 183} 184 185struct libusb20_transfer * 186libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex) 187{ 188 if (trIndex >= pdev->nTransfer) { 189 return (NULL); 190 } 191 return (pdev->pTransfer + trIndex); 192} 193 194uint32_t 195libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer) 196{ 197 return (xfer->aFrames); 198} 199 200uint16_t 201libusb20_tr_get_time_complete(struct libusb20_transfer *xfer) 202{ 203 return (xfer->timeComplete); 204} 205 206uint32_t 207libusb20_tr_get_actual_length(struct libusb20_transfer *xfer) 208{ 209 uint32_t x; 210 uint32_t actlen = 0; 211 212 for (x = 0; x != xfer->aFrames; x++) { 213 actlen += xfer->pLength[x]; 214 } 215 return (actlen); 216} 217 218uint32_t 219libusb20_tr_get_max_frames(struct libusb20_transfer *xfer) 220{ 221 return (xfer->maxFrames); 222} 223 224uint32_t 225libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer) 226{ 227 /* 228 * Special Case NOTE: If the packet multiplier is non-zero for 229 * High Speed USB, the value returned is equal to 230 * "wMaxPacketSize * multiplier" ! 231 */ 232 return (xfer->maxPacketLen); 233} 234 235uint32_t 236libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer) 237{ 238 return (xfer->maxTotalLength); 239} 240 241uint8_t 242libusb20_tr_get_status(struct libusb20_transfer *xfer) 243{ 244 return (xfer->status); 245} 246 247uint8_t 248libusb20_tr_pending(struct libusb20_transfer *xfer) 249{ 250 return (xfer->is_pending); 251} 252 253void * 254libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer) 255{ 256 return (xfer->priv_sc0); 257} 258 259void * 260libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer) 261{ 262 return (xfer->priv_sc1); 263} 264 265void 266libusb20_tr_stop(struct libusb20_transfer *xfer) 267{ 268 if (!xfer->is_pending) { 269 /* transfer not pending */ 270 return; 271 } 272 if (xfer->is_cancel) { 273 /* already cancelling */ 274 return; 275 } 276 xfer->is_cancel = 1; /* we are cancelling */ 277 278 xfer->pdev->methods->tr_cancel_async(xfer); 279 return; 280} 281 282void 283libusb20_tr_drain(struct libusb20_transfer *xfer) 284{ 285 /* make sure that we are cancelling */ 286 libusb20_tr_stop(xfer); 287 288 if (xfer->is_pending) { 289 xfer->is_draining = 1; 290 } 291 return; 292} 293 294void 295libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 296{ 297 xfer->pdev->methods->tr_clear_stall_sync(xfer); 298 return; 299} 300 301void 302libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex) 303{ 304 xfer->ppBuffer[frIndex] = buffer; 305 return; 306} 307 308void 309libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb) 310{ 311 xfer->callback = cb; 312 return; 313} 314 315void 316libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags) 317{ 318 xfer->flags = flags; 319 return; 320} 321 322uint32_t 323libusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex) 324{ 325 return (xfer->pLength[frIndex]); 326} 327 328void 329libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 330{ 331 xfer->pLength[frIndex] = length; 332 return; 333} 334 335void 336libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 337{ 338 xfer->priv_sc0 = sc0; 339 return; 340} 341 342void 343libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 344{ 345 xfer->priv_sc1 = sc1; 346 return; 347} 348 349void 350libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 351{ 352 xfer->timeout = timeout; 353 return; 354} 355 356void 357libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 358{ 359 if (nFrames > xfer->maxFrames) { 360 /* should not happen */ 361 nFrames = xfer->maxFrames; 362 } 363 xfer->nFrames = nFrames; 364 return; 365} 366 367void 368libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 369{ 370 xfer->ppBuffer[0] = pBuf; 371 xfer->pLength[0] = length; 372 xfer->timeout = timeout; 373 xfer->nFrames = 1; 374 return; 375} 376 377void 378libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 379{ 380 uint16_t len; 381 382 xfer->ppBuffer[0] = psetup; 383 xfer->pLength[0] = 8; /* fixed */ 384 xfer->timeout = timeout; 385 386 len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 387 388 if (len != 0) { 389 xfer->nFrames = 2; 390 xfer->ppBuffer[1] = pBuf; 391 xfer->pLength[1] = len; 392 } else { 393 xfer->nFrames = 1; 394 } 395 return; 396} 397 398void 399libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 400{ 401 xfer->ppBuffer[0] = pBuf; 402 xfer->pLength[0] = length; 403 xfer->timeout = timeout; 404 xfer->nFrames = 1; 405 return; 406} 407 408void 409libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 410{ 411 if (frIndex >= xfer->maxFrames) { 412 /* should not happen */ 413 return; 414 } 415 xfer->ppBuffer[frIndex] = pBuf; 416 xfer->pLength[frIndex] = length; 417 return; 418} 419 420void 421libusb20_tr_submit(struct libusb20_transfer *xfer) 422{ 423 if (xfer->is_pending) { 424 /* should not happen */ 425 return; 426 } 427 xfer->is_pending = 1; /* we are pending */ 428 xfer->is_cancel = 0; /* not cancelling */ 429 xfer->is_restart = 0; /* not restarting */ 430 431 xfer->pdev->methods->tr_submit(xfer); 432 return; 433} 434 435void 436libusb20_tr_start(struct libusb20_transfer *xfer) 437{ 438 if (xfer->is_pending) { 439 if (xfer->is_cancel) { 440 /* cancelling - restart */ 441 xfer->is_restart = 1; 442 } 443 /* transfer not pending */ 444 return; 445 } 446 /* get into the callback */ 447 libusb20_tr_callback_wrapper(xfer); 448 return; 449} 450 451/* USB device operations */ 452 453int 454libusb20_dev_claim_interface(struct libusb20_device *pdev, uint8_t ifaceIndex) 455{ 456 int error; 457 458 if (ifaceIndex >= 32) { 459 error = LIBUSB20_ERROR_INVALID_PARAM; 460 } else if (pdev->claimed_interfaces & (1 << ifaceIndex)) { 461 error = LIBUSB20_ERROR_NOT_FOUND; 462 } else { 463 error = pdev->methods->claim_interface(pdev, ifaceIndex); 464 } 465 if (!error) { 466 pdev->claimed_interfaces |= (1 << ifaceIndex); 467 } 468 return (error); 469} 470 471int 472libusb20_dev_close(struct libusb20_device *pdev) 473{ 474 struct libusb20_transfer *xfer; 475 uint16_t x; 476 int error = 0; 477 478 if (!pdev->is_opened) { 479 return (LIBUSB20_ERROR_OTHER); 480 } 481 for (x = 0; x != pdev->nTransfer; x++) { 482 xfer = pdev->pTransfer + x; 483 484 libusb20_tr_drain(xfer); 485 } 486 487 if (pdev->pTransfer != NULL) { 488 free(pdev->pTransfer); 489 pdev->pTransfer = NULL; 490 } 491 error = pdev->beMethods->close_device(pdev); 492 493 pdev->methods = &libusb20_dummy_methods; 494 495 pdev->is_opened = 0; 496 497 pdev->claimed_interfaces = 0; 498 499 return (error); 500} 501 502int 503libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 504{ 505 int error; 506 507 error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 508 return (error); 509} 510 511struct LIBUSB20_DEVICE_DESC_DECODED * 512libusb20_dev_get_device_desc(struct libusb20_device *pdev) 513{ 514 return (&(pdev->ddesc)); 515} 516 517int 518libusb20_dev_get_fd(struct libusb20_device *pdev) 519{ 520 return (pdev->file); 521} 522 523int 524libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 525{ 526 int error; 527 528 error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 529 return (error); 530} 531 532int 533libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 534{ 535 struct libusb20_transfer *xfer; 536 uint32_t size; 537 uint16_t x; 538 int error; 539 540 if (pdev->is_opened) { 541 return (LIBUSB20_ERROR_BUSY); 542 } 543 if (nTransferMax >= 256) { 544 return (LIBUSB20_ERROR_INVALID_PARAM); 545 } else if (nTransferMax != 0) { 546 size = sizeof(pdev->pTransfer[0]) * nTransferMax; 547 pdev->pTransfer = malloc(size); 548 if (pdev->pTransfer == NULL) { 549 return (LIBUSB20_ERROR_NO_MEM); 550 } 551 memset(pdev->pTransfer, 0, size); 552 } 553 /* initialise all transfers */ 554 for (x = 0; x != nTransferMax; x++) { 555 556 xfer = pdev->pTransfer + x; 557 558 xfer->pdev = pdev; 559 xfer->trIndex = x; 560 xfer->callback = &dummy_callback; 561 } 562 563 /* set "nTransfer" early */ 564 pdev->nTransfer = nTransferMax; 565 566 error = pdev->beMethods->open_device(pdev, nTransferMax); 567 568 if (error) { 569 if (pdev->pTransfer != NULL) { 570 free(pdev->pTransfer); 571 pdev->pTransfer = NULL; 572 } 573 pdev->file = -1; 574 pdev->file_ctrl = -1; 575 pdev->nTransfer = 0; 576 } else { 577 pdev->is_opened = 1; 578 } 579 return (error); 580} 581 582int 583libusb20_dev_release_interface(struct libusb20_device *pdev, uint8_t ifaceIndex) 584{ 585 int error; 586 587 if (ifaceIndex >= 32) { 588 error = LIBUSB20_ERROR_INVALID_PARAM; 589 } else if (!(pdev->claimed_interfaces & (1 << ifaceIndex))) { 590 error = LIBUSB20_ERROR_NOT_FOUND; 591 } else { 592 error = pdev->methods->release_interface(pdev, ifaceIndex); 593 } 594 if (!error) { 595 pdev->claimed_interfaces &= ~(1 << ifaceIndex); 596 } 597 return (error); 598} 599 600int 601libusb20_dev_reset(struct libusb20_device *pdev) 602{ 603 int error; 604 605 error = pdev->methods->reset_device(pdev); 606 return (error); 607} 608 609int 610libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 611{ 612 int error; 613 614 error = pdev->methods->set_power_mode(pdev, power_mode); 615 return (error); 616} 617 618uint8_t 619libusb20_dev_get_power_mode(struct libusb20_device *pdev) 620{ 621 int error; 622 uint8_t power_mode; 623 624 error = pdev->methods->get_power_mode(pdev, &power_mode); 625 if (error) 626 power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 627 return (power_mode); 628} 629 630int 631libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 632{ 633 int error; 634 635 error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 636 return (error); 637} 638 639int 640libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 641{ 642 int error; 643 644 error = pdev->methods->set_config_index(pdev, configIndex); 645 return (error); 646} 647 648int 649libusb20_dev_request_sync(struct libusb20_device *pdev, 650 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 651 uint16_t *pactlen, uint32_t timeout, uint8_t flags) 652{ 653 int error; 654 655 error = pdev->methods->do_request_sync(pdev, 656 setup, data, pactlen, timeout, flags); 657 return (error); 658} 659 660int 661libusb20_dev_req_string_sync(struct libusb20_device *pdev, 662 uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 663{ 664 struct LIBUSB20_CONTROL_SETUP_DECODED req; 665 int error; 666 667 if (len < 4) { 668 /* invalid length */ 669 return (LIBUSB20_ERROR_INVALID_PARAM); 670 } 671 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 672 673 /* 674 * We need to read the USB string in two steps else some USB 675 * devices will complain. 676 */ 677 req.bmRequestType = 678 LIBUSB20_REQUEST_TYPE_STANDARD | 679 LIBUSB20_RECIPIENT_DEVICE | 680 LIBUSB20_ENDPOINT_IN; 681 req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 682 req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 683 req.wIndex = langid; 684 req.wLength = 4; /* bytes */ 685 686 error = libusb20_dev_request_sync(pdev, &req, 687 ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 688 if (error) { 689 return (error); 690 } 691 req.wLength = *(uint8_t *)ptr; /* bytes */ 692 if (req.wLength > len) { 693 /* partial string read */ 694 req.wLength = len; 695 } 696 error = libusb20_dev_request_sync(pdev, &req, 697 ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 698 699 if (error) { 700 return (error); 701 } 702 if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) { 703 return (LIBUSB20_ERROR_OTHER); 704 } 705 return (0); /* success */ 706} 707 708int 709libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 710 uint8_t str_index, void *ptr, uint16_t len) 711{ 712 char *buf; 713 int error; 714 uint16_t langid; 715 uint16_t n; 716 uint16_t i; 717 uint16_t c; 718 uint8_t temp[255]; 719 uint8_t swap; 720 721 /* the following code derives from the FreeBSD USB kernel */ 722 723 if ((len < 1) || (ptr == NULL)) { 724 /* too short buffer */ 725 return (LIBUSB20_ERROR_INVALID_PARAM); 726 } 727 error = libusb20_dev_req_string_sync(pdev, 728 0, 0, temp, sizeof(temp)); 729 if (error < 0) { 730 *(uint8_t *)ptr = 0; /* zero terminate */ 731 return (error); 732 } 733 langid = temp[2] | (temp[3] << 8); 734 735 error = libusb20_dev_req_string_sync(pdev, str_index, 736 langid, temp, sizeof(temp)); 737 if (error < 0) { 738 *(uint8_t *)ptr = 0; /* zero terminate */ 739 return (error); 740 } 741 if (temp[0] < 2) { 742 /* string length is too short */ 743 *(uint8_t *)ptr = 0; /* zero terminate */ 744 return (LIBUSB20_ERROR_OTHER); 745 } 746 /* reserve one byte for terminating zero */ 747 len--; 748 749 /* find maximum length */ 750 n = (temp[0] / 2) - 1; 751 if (n > len) { 752 n = len; 753 } 754 /* reset swap state */ 755 swap = 3; 756 757 /* setup output buffer pointer */ 758 buf = ptr; 759 760 /* convert and filter */ 761 for (i = 0; (i != n); i++) { 762 c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 763 764 /* convert from Unicode, handle buggy strings */ 765 if (((c & 0xff00) == 0) && (swap & 1)) { 766 /* Little Endian, default */ 767 *buf = c; 768 swap = 1; 769 } else if (((c & 0x00ff) == 0) && (swap & 2)) { 770 /* Big Endian */ 771 *buf = c >> 8; 772 swap = 2; 773 } else { 774 /* skip invalid character */ 775 continue; 776 } 777 /* 778 * Filter by default - we don't allow greater and less than 779 * signs because they might confuse the dmesg printouts! 780 */ 781 if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 782 /* skip invalid character */ 783 continue; 784 } 785 buf++; 786 } 787 *buf = 0; /* zero terminate string */ 788 789 return (0); 790} 791 792struct libusb20_config * 793libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 794{ 795 struct libusb20_config *retval = NULL; 796 uint8_t *ptr; 797 uint16_t len; 798 uint8_t do_close; 799 int error; 800 801 if (!pdev->is_opened) { 802 error = libusb20_dev_open(pdev, 0); 803 if (error) { 804 return (NULL); 805 } 806 do_close = 1; 807 } else { 808 do_close = 0; 809 } 810 error = pdev->methods->get_config_desc_full(pdev, 811 &ptr, &len, configIndex); 812 813 if (error) { 814 goto done; 815 } 816 /* parse new config descriptor */ 817 retval = libusb20_parse_config_desc(ptr); 818 819 /* free config descriptor */ 820 free(ptr); 821 822done: 823 if (do_close) { 824 error = libusb20_dev_close(pdev); 825 } 826 return (retval); 827} 828 829struct libusb20_device * 830libusb20_dev_alloc(void) 831{ 832 struct libusb20_device *pdev; 833 834 pdev = malloc(sizeof(*pdev)); 835 if (pdev == NULL) { 836 return (NULL); 837 } 838 memset(pdev, 0, sizeof(*pdev)); 839 840 pdev->file = -1; 841 pdev->file_ctrl = -1; 842 pdev->methods = &libusb20_dummy_methods; 843 return (pdev); 844} 845 846uint8_t 847libusb20_dev_get_config_index(struct libusb20_device *pdev) 848{ 849 int error; 850 uint8_t cfg_index; 851 uint8_t do_close; 852 853 if (!pdev->is_opened) { 854 error = libusb20_dev_open(pdev, 0); 855 if (error == 0) { 856 do_close = 1; 857 } else { 858 do_close = 0; 859 } 860 } else { 861 do_close = 0; 862 } 863 864 error = pdev->methods->get_config_index(pdev, &cfg_index); 865 if (error) { 866 cfg_index = 0 - 1; /* current config index */ 867 } 868 if (do_close) { 869 if (libusb20_dev_close(pdev)) { 870 /* ignore */ 871 } 872 } 873 return (cfg_index); 874} 875 876uint8_t 877libusb20_dev_get_mode(struct libusb20_device *pdev) 878{ 879 return (pdev->usb_mode); 880} 881 882uint8_t 883libusb20_dev_get_speed(struct libusb20_device *pdev) 884{ 885 return (pdev->usb_speed); 886} 887 888/* if this function returns an error, the device is gone */ 889int 890libusb20_dev_process(struct libusb20_device *pdev) 891{ 892 int error; 893 894 error = pdev->methods->process(pdev); 895 return (error); 896} 897 898void 899libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 900{ 901 struct pollfd pfd[1]; 902 903 if (!pdev->is_opened) { 904 return; 905 } 906 pfd[0].fd = pdev->file; 907 pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 908 pfd[0].revents = 0; 909 910 if (poll(pfd, 1, timeout)) { 911 /* ignore any error */ 912 } 913 return; 914} 915 916void 917libusb20_dev_free(struct libusb20_device *pdev) 918{ 919 if (pdev == NULL) { 920 /* be NULL safe */ 921 return; 922 } 923 if (pdev->is_opened) { 924 if (libusb20_dev_close(pdev)) { 925 /* ignore any errors */ 926 } 927 } 928 free(pdev); 929 return; 930} 931 932int 933libusb20_dev_get_info(struct libusb20_device *pdev, 934 struct usb_device_info *pinfo) 935{ 936 if (pinfo == NULL) 937 return (LIBUSB20_ERROR_INVALID_PARAM); 938 939 return (pdev->beMethods->dev_get_info(pdev, pinfo)); 940} 941 942const char * 943libusb20_dev_get_backend_name(struct libusb20_device *pdev) 944{ 945 return (pdev->beMethods->get_backend_name()); 946} 947 948const char * 949libusb20_dev_get_desc(struct libusb20_device *pdev) 950{ 951 return (pdev->usb_desc); 952} 953 954void 955libusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 956{ 957 pdev->debug = debug; 958 return; 959} 960 961int 962libusb20_dev_get_debug(struct libusb20_device *pdev) 963{ 964 return (pdev->debug); 965} 966 967uint8_t 968libusb20_dev_get_address(struct libusb20_device *pdev) 969{ 970 return (pdev->device_address); 971} 972 973uint8_t 974libusb20_dev_get_bus_number(struct libusb20_device *pdev) 975{ 976 return (pdev->bus_number); 977} 978 979int 980libusb20_dev_get_iface_desc(struct libusb20_device *pdev, 981 uint8_t iface_index, char *buf, uint8_t len) 982{ 983 if ((buf == NULL) || (len == 0)) 984 return (LIBUSB20_ERROR_INVALID_PARAM); 985 986 return (pdev->beMethods->dev_get_iface_desc( 987 pdev, iface_index, buf, len)); 988} 989 990/* USB backend operations */ 991 992int 993libusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 994 uint16_t quirk_index, struct libusb20_quirk *pq) 995{ 996 return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 997} 998 999int 1000libusb20_be_get_quirk_name(struct libusb20_backend *pbe, 1001 uint16_t quirk_index, struct libusb20_quirk *pq) 1002{ 1003 return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 1004} 1005 1006int 1007libusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 1008 struct libusb20_quirk *pq) 1009{ 1010 return (pbe->methods->root_add_dev_quirk(pbe, pq)); 1011} 1012 1013int 1014libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 1015 struct libusb20_quirk *pq) 1016{ 1017 return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 1018} 1019 1020int 1021libusb20_be_set_template(struct libusb20_backend *pbe, int temp) 1022{ 1023 return (pbe->methods->root_set_template(pbe, temp)); 1024} 1025 1026int 1027libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 1028{ 1029 int temp; 1030 1031 if (ptemp == NULL) 1032 ptemp = &temp; 1033 1034 return (pbe->methods->root_get_template(pbe, ptemp)); 1035} 1036 1037struct libusb20_device * 1038libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1039{ 1040 if (pbe == NULL) { 1041 pdev = NULL; 1042 } else if (pdev == NULL) { 1043 pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1044 } else { 1045 pdev = TAILQ_NEXT(pdev, dev_entry); 1046 } 1047 return (pdev); 1048} 1049 1050struct libusb20_backend * 1051libusb20_be_alloc(const struct libusb20_backend_methods *methods) 1052{ 1053 struct libusb20_backend *pbe; 1054 1055 pbe = malloc(sizeof(*pbe)); 1056 if (pbe == NULL) { 1057 return (NULL); 1058 } 1059 memset(pbe, 0, sizeof(*pbe)); 1060 1061 TAILQ_INIT(&(pbe->usb_devs)); 1062 1063 pbe->methods = methods; /* set backend methods */ 1064 1065 /* do the initial device scan */ 1066 if (pbe->methods->init_backend) { 1067 pbe->methods->init_backend(pbe); 1068 } 1069 return (pbe); 1070} 1071 1072struct libusb20_backend * 1073libusb20_be_alloc_linux(void) 1074{ 1075 struct libusb20_backend *pbe; 1076 1077#ifdef __linux__ 1078 pbe = libusb20_be_alloc(&libusb20_linux_backend); 1079#else 1080 pbe = NULL; 1081#endif 1082 return (pbe); 1083} 1084 1085struct libusb20_backend * 1086libusb20_be_alloc_ugen20(void) 1087{ 1088 struct libusb20_backend *pbe; 1089 1090#ifdef __FreeBSD__ 1091 pbe = libusb20_be_alloc(&libusb20_ugen20_backend); 1092#else 1093 pbe = NULL; 1094#endif 1095 return (pbe); 1096} 1097 1098struct libusb20_backend * 1099libusb20_be_alloc_default(void) 1100{ 1101 struct libusb20_backend *pbe; 1102 1103 pbe = libusb20_be_alloc_linux(); 1104 if (pbe) { 1105 return (pbe); 1106 } 1107 pbe = libusb20_be_alloc_ugen20(); 1108 if (pbe) { 1109 return (pbe); 1110 } 1111 return (NULL); /* no backend found */ 1112} 1113 1114void 1115libusb20_be_free(struct libusb20_backend *pbe) 1116{ 1117 struct libusb20_device *pdev; 1118 1119 if (pbe == NULL) { 1120 /* be NULL safe */ 1121 return; 1122 } 1123 while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1124 libusb20_be_dequeue_device(pbe, pdev); 1125 libusb20_dev_free(pdev); 1126 } 1127 if (pbe->methods->exit_backend) { 1128 pbe->methods->exit_backend(pbe); 1129 } 1130 return; 1131} 1132 1133void 1134libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1135{ 1136 pdev->beMethods = pbe->methods; /* copy backend methods */ 1137 TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1138 return; 1139} 1140 1141void 1142libusb20_be_dequeue_device(struct libusb20_backend *pbe, 1143 struct libusb20_device *pdev) 1144{ 1145 TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1146 return; 1147} 1148