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