libusb20.c revision 192984
1/* $FreeBSD: head/lib/libusb/libusb20.c 192984 2009-05-28 17:36:36Z 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 322void 323libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex) 324{ 325 xfer->pLength[frIndex] = length; 326 return; 327} 328 329void 330libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0) 331{ 332 xfer->priv_sc0 = sc0; 333 return; 334} 335 336void 337libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1) 338{ 339 xfer->priv_sc1 = sc1; 340 return; 341} 342 343void 344libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout) 345{ 346 xfer->timeout = timeout; 347 return; 348} 349 350void 351libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames) 352{ 353 if (nFrames > xfer->maxFrames) { 354 /* should not happen */ 355 nFrames = xfer->maxFrames; 356 } 357 xfer->nFrames = nFrames; 358 return; 359} 360 361void 362libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 363{ 364 xfer->ppBuffer[0] = pBuf; 365 xfer->pLength[0] = length; 366 xfer->timeout = timeout; 367 xfer->nFrames = 1; 368 return; 369} 370 371void 372libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout) 373{ 374 uint16_t len; 375 376 xfer->ppBuffer[0] = psetup; 377 xfer->pLength[0] = 8; /* fixed */ 378 xfer->timeout = timeout; 379 380 len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8); 381 382 if (len != 0) { 383 xfer->nFrames = 2; 384 xfer->ppBuffer[1] = pBuf; 385 xfer->pLength[1] = len; 386 } else { 387 xfer->nFrames = 1; 388 } 389 return; 390} 391 392void 393libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout) 394{ 395 xfer->ppBuffer[0] = pBuf; 396 xfer->pLength[0] = length; 397 xfer->timeout = timeout; 398 xfer->nFrames = 1; 399 return; 400} 401 402void 403libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex) 404{ 405 if (frIndex >= xfer->maxFrames) { 406 /* should not happen */ 407 return; 408 } 409 xfer->ppBuffer[frIndex] = pBuf; 410 xfer->pLength[frIndex] = length; 411 return; 412} 413 414void 415libusb20_tr_submit(struct libusb20_transfer *xfer) 416{ 417 if (xfer->is_pending) { 418 /* should not happen */ 419 return; 420 } 421 xfer->is_pending = 1; /* we are pending */ 422 xfer->is_cancel = 0; /* not cancelling */ 423 xfer->is_restart = 0; /* not restarting */ 424 425 xfer->pdev->methods->tr_submit(xfer); 426 return; 427} 428 429void 430libusb20_tr_start(struct libusb20_transfer *xfer) 431{ 432 if (xfer->is_pending) { 433 if (xfer->is_cancel) { 434 /* cancelling - restart */ 435 xfer->is_restart = 1; 436 } 437 /* transfer not pending */ 438 return; 439 } 440 /* get into the callback */ 441 libusb20_tr_callback_wrapper(xfer); 442 return; 443} 444 445/* USB device operations */ 446 447int 448libusb20_dev_claim_interface(struct libusb20_device *pdev, uint8_t ifaceIndex) 449{ 450 int error; 451 452 if (ifaceIndex >= 32) { 453 error = LIBUSB20_ERROR_INVALID_PARAM; 454 } else if (pdev->claimed_interfaces & (1 << ifaceIndex)) { 455 error = LIBUSB20_ERROR_NOT_FOUND; 456 } else { 457 error = pdev->methods->claim_interface(pdev, ifaceIndex); 458 } 459 if (!error) { 460 pdev->claimed_interfaces |= (1 << ifaceIndex); 461 } 462 return (error); 463} 464 465int 466libusb20_dev_close(struct libusb20_device *pdev) 467{ 468 struct libusb20_transfer *xfer; 469 uint16_t x; 470 int error = 0; 471 472 if (!pdev->is_opened) { 473 return (LIBUSB20_ERROR_OTHER); 474 } 475 for (x = 0; x != pdev->nTransfer; x++) { 476 xfer = pdev->pTransfer + x; 477 478 libusb20_tr_drain(xfer); 479 } 480 481 if (pdev->pTransfer != NULL) { 482 free(pdev->pTransfer); 483 pdev->pTransfer = NULL; 484 } 485 error = pdev->beMethods->close_device(pdev); 486 487 pdev->methods = &libusb20_dummy_methods; 488 489 pdev->is_opened = 0; 490 491 pdev->claimed_interfaces = 0; 492 493 return (error); 494} 495 496int 497libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex) 498{ 499 int error; 500 501 error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex); 502 return (error); 503} 504 505struct LIBUSB20_DEVICE_DESC_DECODED * 506libusb20_dev_get_device_desc(struct libusb20_device *pdev) 507{ 508 return (&(pdev->ddesc)); 509} 510 511int 512libusb20_dev_get_fd(struct libusb20_device *pdev) 513{ 514 return (pdev->file); 515} 516 517int 518libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex) 519{ 520 int error; 521 522 error = pdev->methods->kernel_driver_active(pdev, ifaceIndex); 523 return (error); 524} 525 526int 527libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax) 528{ 529 struct libusb20_transfer *xfer; 530 uint32_t size; 531 uint16_t x; 532 int error; 533 534 if (pdev->is_opened) { 535 return (LIBUSB20_ERROR_BUSY); 536 } 537 if (nTransferMax >= 256) { 538 return (LIBUSB20_ERROR_INVALID_PARAM); 539 } else if (nTransferMax != 0) { 540 size = sizeof(pdev->pTransfer[0]) * nTransferMax; 541 pdev->pTransfer = malloc(size); 542 if (pdev->pTransfer == NULL) { 543 return (LIBUSB20_ERROR_NO_MEM); 544 } 545 memset(pdev->pTransfer, 0, size); 546 } 547 /* initialise all transfers */ 548 for (x = 0; x != nTransferMax; x++) { 549 550 xfer = pdev->pTransfer + x; 551 552 xfer->pdev = pdev; 553 xfer->trIndex = x; 554 xfer->callback = &dummy_callback; 555 } 556 557 /* set "nTransfer" early */ 558 pdev->nTransfer = nTransferMax; 559 560 error = pdev->beMethods->open_device(pdev, nTransferMax); 561 562 if (error) { 563 if (pdev->pTransfer != NULL) { 564 free(pdev->pTransfer); 565 pdev->pTransfer = NULL; 566 } 567 pdev->file = -1; 568 pdev->file_ctrl = -1; 569 pdev->nTransfer = 0; 570 } else { 571 pdev->is_opened = 1; 572 } 573 return (error); 574} 575 576int 577libusb20_dev_release_interface(struct libusb20_device *pdev, uint8_t ifaceIndex) 578{ 579 int error; 580 581 if (ifaceIndex >= 32) { 582 error = LIBUSB20_ERROR_INVALID_PARAM; 583 } else if (!(pdev->claimed_interfaces & (1 << ifaceIndex))) { 584 error = LIBUSB20_ERROR_NOT_FOUND; 585 } else { 586 error = pdev->methods->release_interface(pdev, ifaceIndex); 587 } 588 if (!error) { 589 pdev->claimed_interfaces &= ~(1 << ifaceIndex); 590 } 591 return (error); 592} 593 594int 595libusb20_dev_reset(struct libusb20_device *pdev) 596{ 597 int error; 598 599 error = pdev->methods->reset_device(pdev); 600 return (error); 601} 602 603int 604libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 605{ 606 int error; 607 608 error = pdev->methods->set_power_mode(pdev, power_mode); 609 return (error); 610} 611 612uint8_t 613libusb20_dev_get_power_mode(struct libusb20_device *pdev) 614{ 615 int error; 616 uint8_t power_mode; 617 618 error = pdev->methods->get_power_mode(pdev, &power_mode); 619 if (error) 620 power_mode = LIBUSB20_POWER_ON; /* fake power mode */ 621 return (power_mode); 622} 623 624int 625libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex) 626{ 627 int error; 628 629 error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex); 630 return (error); 631} 632 633int 634libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex) 635{ 636 int error; 637 638 error = pdev->methods->set_config_index(pdev, configIndex); 639 return (error); 640} 641 642int 643libusb20_dev_request_sync(struct libusb20_device *pdev, 644 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data, 645 uint16_t *pactlen, uint32_t timeout, uint8_t flags) 646{ 647 int error; 648 649 error = pdev->methods->do_request_sync(pdev, 650 setup, data, pactlen, timeout, flags); 651 return (error); 652} 653 654int 655libusb20_dev_req_string_sync(struct libusb20_device *pdev, 656 uint8_t str_index, uint16_t langid, void *ptr, uint16_t len) 657{ 658 struct LIBUSB20_CONTROL_SETUP_DECODED req; 659 int error; 660 661 if (len < 4) { 662 /* invalid length */ 663 return (LIBUSB20_ERROR_INVALID_PARAM); 664 } 665 LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 666 667 /* 668 * We need to read the USB string in two steps else some USB 669 * devices will complain. 670 */ 671 req.bmRequestType = 672 LIBUSB20_REQUEST_TYPE_STANDARD | 673 LIBUSB20_RECIPIENT_DEVICE | 674 LIBUSB20_ENDPOINT_IN; 675 req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR; 676 req.wValue = (LIBUSB20_DT_STRING << 8) | str_index; 677 req.wIndex = langid; 678 req.wLength = 4; /* bytes */ 679 680 error = libusb20_dev_request_sync(pdev, &req, 681 ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 682 if (error) { 683 return (error); 684 } 685 req.wLength = *(uint8_t *)ptr; /* bytes */ 686 if (req.wLength > len) { 687 /* partial string read */ 688 req.wLength = len; 689 } 690 error = libusb20_dev_request_sync(pdev, &req, 691 ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK); 692 693 if (error) { 694 return (error); 695 } 696 if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) { 697 return (LIBUSB20_ERROR_OTHER); 698 } 699 return (0); /* success */ 700} 701 702int 703libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev, 704 uint8_t str_index, void *ptr, uint16_t len) 705{ 706 char *buf; 707 int error; 708 uint16_t langid; 709 uint16_t n; 710 uint16_t i; 711 uint16_t c; 712 uint8_t temp[255]; 713 uint8_t swap; 714 715 /* the following code derives from the FreeBSD USB kernel */ 716 717 if ((len < 1) || (ptr == NULL)) { 718 /* too short buffer */ 719 return (LIBUSB20_ERROR_INVALID_PARAM); 720 } 721 error = libusb20_dev_req_string_sync(pdev, 722 0, 0, temp, sizeof(temp)); 723 if (error < 0) { 724 *(uint8_t *)ptr = 0; /* zero terminate */ 725 return (error); 726 } 727 langid = temp[2] | (temp[3] << 8); 728 729 error = libusb20_dev_req_string_sync(pdev, str_index, 730 langid, temp, sizeof(temp)); 731 if (error < 0) { 732 *(uint8_t *)ptr = 0; /* zero terminate */ 733 return (error); 734 } 735 if (temp[0] < 2) { 736 /* string length is too short */ 737 *(uint8_t *)ptr = 0; /* zero terminate */ 738 return (LIBUSB20_ERROR_OTHER); 739 } 740 /* reserve one byte for terminating zero */ 741 len--; 742 743 /* find maximum length */ 744 n = (temp[0] / 2) - 1; 745 if (n > len) { 746 n = len; 747 } 748 /* reset swap state */ 749 swap = 3; 750 751 /* setup output buffer pointer */ 752 buf = ptr; 753 754 /* convert and filter */ 755 for (i = 0; (i != n); i++) { 756 c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8); 757 758 /* convert from Unicode, handle buggy strings */ 759 if (((c & 0xff00) == 0) && (swap & 1)) { 760 /* Little Endian, default */ 761 *buf = c; 762 swap = 1; 763 } else if (((c & 0x00ff) == 0) && (swap & 2)) { 764 /* Big Endian */ 765 *buf = c >> 8; 766 swap = 2; 767 } else { 768 /* skip invalid character */ 769 continue; 770 } 771 /* 772 * Filter by default - we don't allow greater and less than 773 * signs because they might confuse the dmesg printouts! 774 */ 775 if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) { 776 /* skip invalid character */ 777 continue; 778 } 779 buf++; 780 } 781 *buf = 0; /* zero terminate string */ 782 783 return (0); 784} 785 786struct libusb20_config * 787libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex) 788{ 789 struct libusb20_config *retval = NULL; 790 uint8_t *ptr; 791 uint16_t len; 792 uint8_t do_close; 793 int error; 794 795 if (!pdev->is_opened) { 796 error = libusb20_dev_open(pdev, 0); 797 if (error) { 798 return (NULL); 799 } 800 do_close = 1; 801 } else { 802 do_close = 0; 803 } 804 error = pdev->methods->get_config_desc_full(pdev, 805 &ptr, &len, configIndex); 806 807 if (error) { 808 goto done; 809 } 810 /* parse new config descriptor */ 811 retval = libusb20_parse_config_desc(ptr); 812 813 /* free config descriptor */ 814 free(ptr); 815 816done: 817 if (do_close) { 818 error = libusb20_dev_close(pdev); 819 } 820 return (retval); 821} 822 823struct libusb20_device * 824libusb20_dev_alloc(void) 825{ 826 struct libusb20_device *pdev; 827 828 pdev = malloc(sizeof(*pdev)); 829 if (pdev == NULL) { 830 return (NULL); 831 } 832 memset(pdev, 0, sizeof(*pdev)); 833 834 pdev->file = -1; 835 pdev->file_ctrl = -1; 836 pdev->methods = &libusb20_dummy_methods; 837 return (pdev); 838} 839 840uint8_t 841libusb20_dev_get_config_index(struct libusb20_device *pdev) 842{ 843 int error; 844 uint8_t cfg_index; 845 uint8_t do_close; 846 847 if (!pdev->is_opened) { 848 error = libusb20_dev_open(pdev, 0); 849 if (error == 0) { 850 do_close = 1; 851 } else { 852 do_close = 0; 853 } 854 } else { 855 do_close = 0; 856 } 857 858 error = pdev->methods->get_config_index(pdev, &cfg_index); 859 if (error) { 860 cfg_index = 0 - 1; /* current config index */ 861 } 862 if (do_close) { 863 if (libusb20_dev_close(pdev)) { 864 /* ignore */ 865 } 866 } 867 return (cfg_index); 868} 869 870uint8_t 871libusb20_dev_get_mode(struct libusb20_device *pdev) 872{ 873 return (pdev->usb_mode); 874} 875 876uint8_t 877libusb20_dev_get_speed(struct libusb20_device *pdev) 878{ 879 return (pdev->usb_speed); 880} 881 882/* if this function returns an error, the device is gone */ 883int 884libusb20_dev_process(struct libusb20_device *pdev) 885{ 886 int error; 887 888 error = pdev->methods->process(pdev); 889 return (error); 890} 891 892void 893libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout) 894{ 895 struct pollfd pfd[1]; 896 897 if (!pdev->is_opened) { 898 return; 899 } 900 pfd[0].fd = pdev->file; 901 pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 902 pfd[0].revents = 0; 903 904 if (poll(pfd, 1, timeout)) { 905 /* ignore any error */ 906 } 907 return; 908} 909 910void 911libusb20_dev_free(struct libusb20_device *pdev) 912{ 913 if (pdev == NULL) { 914 /* be NULL safe */ 915 return; 916 } 917 if (pdev->is_opened) { 918 if (libusb20_dev_close(pdev)) { 919 /* ignore any errors */ 920 } 921 } 922 free(pdev); 923 return; 924} 925 926int 927libusb20_dev_get_info(struct libusb20_device *pdev, 928 struct usb_device_info *pinfo) 929{ 930 if (pinfo == NULL) 931 return (LIBUSB20_ERROR_INVALID_PARAM); 932 933 return (pdev->beMethods->dev_get_info(pdev, pinfo)); 934} 935 936const char * 937libusb20_dev_get_backend_name(struct libusb20_device *pdev) 938{ 939 return (pdev->beMethods->get_backend_name()); 940} 941 942const char * 943libusb20_dev_get_desc(struct libusb20_device *pdev) 944{ 945 return (pdev->usb_desc); 946} 947 948void 949libusb20_dev_set_debug(struct libusb20_device *pdev, int debug) 950{ 951 pdev->debug = debug; 952 return; 953} 954 955int 956libusb20_dev_get_debug(struct libusb20_device *pdev) 957{ 958 return (pdev->debug); 959} 960 961uint8_t 962libusb20_dev_get_address(struct libusb20_device *pdev) 963{ 964 return (pdev->device_address); 965} 966 967uint8_t 968libusb20_dev_get_bus_number(struct libusb20_device *pdev) 969{ 970 return (pdev->bus_number); 971} 972 973int 974libusb20_dev_get_iface_desc(struct libusb20_device *pdev, 975 uint8_t iface_index, char *buf, uint8_t len) 976{ 977 if ((buf == NULL) || (len == 0)) 978 return (LIBUSB20_ERROR_INVALID_PARAM); 979 980 return (pdev->beMethods->dev_get_iface_desc( 981 pdev, iface_index, buf, len)); 982} 983 984/* USB backend operations */ 985 986int 987libusb20_be_get_dev_quirk(struct libusb20_backend *pbe, 988 uint16_t quirk_index, struct libusb20_quirk *pq) 989{ 990 return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq)); 991} 992 993int 994libusb20_be_get_quirk_name(struct libusb20_backend *pbe, 995 uint16_t quirk_index, struct libusb20_quirk *pq) 996{ 997 return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq)); 998} 999 1000int 1001libusb20_be_add_dev_quirk(struct libusb20_backend *pbe, 1002 struct libusb20_quirk *pq) 1003{ 1004 return (pbe->methods->root_add_dev_quirk(pbe, pq)); 1005} 1006 1007int 1008libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe, 1009 struct libusb20_quirk *pq) 1010{ 1011 return (pbe->methods->root_remove_dev_quirk(pbe, pq)); 1012} 1013 1014int 1015libusb20_be_set_template(struct libusb20_backend *pbe, int temp) 1016{ 1017 return (pbe->methods->root_set_template(pbe, temp)); 1018} 1019 1020int 1021libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp) 1022{ 1023 int temp; 1024 1025 if (ptemp == NULL) 1026 ptemp = &temp; 1027 1028 return (pbe->methods->root_get_template(pbe, ptemp)); 1029} 1030 1031struct libusb20_device * 1032libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1033{ 1034 if (pbe == NULL) { 1035 pdev = NULL; 1036 } else if (pdev == NULL) { 1037 pdev = TAILQ_FIRST(&(pbe->usb_devs)); 1038 } else { 1039 pdev = TAILQ_NEXT(pdev, dev_entry); 1040 } 1041 return (pdev); 1042} 1043 1044struct libusb20_backend * 1045libusb20_be_alloc(const struct libusb20_backend_methods *methods) 1046{ 1047 struct libusb20_backend *pbe; 1048 1049 pbe = malloc(sizeof(*pbe)); 1050 if (pbe == NULL) { 1051 return (NULL); 1052 } 1053 memset(pbe, 0, sizeof(*pbe)); 1054 1055 TAILQ_INIT(&(pbe->usb_devs)); 1056 1057 pbe->methods = methods; /* set backend methods */ 1058 1059 /* do the initial device scan */ 1060 if (pbe->methods->init_backend) { 1061 pbe->methods->init_backend(pbe); 1062 } 1063 return (pbe); 1064} 1065 1066struct libusb20_backend * 1067libusb20_be_alloc_linux(void) 1068{ 1069 struct libusb20_backend *pbe; 1070 1071#ifdef __linux__ 1072 pbe = libusb20_be_alloc(&libusb20_linux_backend); 1073#else 1074 pbe = NULL; 1075#endif 1076 return (pbe); 1077} 1078 1079struct libusb20_backend * 1080libusb20_be_alloc_ugen20(void) 1081{ 1082 struct libusb20_backend *pbe; 1083 1084#ifdef __FreeBSD__ 1085 pbe = libusb20_be_alloc(&libusb20_ugen20_backend); 1086#else 1087 pbe = NULL; 1088#endif 1089 return (pbe); 1090} 1091 1092struct libusb20_backend * 1093libusb20_be_alloc_default(void) 1094{ 1095 struct libusb20_backend *pbe; 1096 1097 pbe = libusb20_be_alloc_linux(); 1098 if (pbe) { 1099 return (pbe); 1100 } 1101 pbe = libusb20_be_alloc_ugen20(); 1102 if (pbe) { 1103 return (pbe); 1104 } 1105 return (NULL); /* no backend found */ 1106} 1107 1108void 1109libusb20_be_free(struct libusb20_backend *pbe) 1110{ 1111 struct libusb20_device *pdev; 1112 1113 if (pbe == NULL) { 1114 /* be NULL safe */ 1115 return; 1116 } 1117 while ((pdev = libusb20_be_device_foreach(pbe, NULL))) { 1118 libusb20_be_dequeue_device(pbe, pdev); 1119 libusb20_dev_free(pdev); 1120 } 1121 if (pbe->methods->exit_backend) { 1122 pbe->methods->exit_backend(pbe); 1123 } 1124 return; 1125} 1126 1127void 1128libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev) 1129{ 1130 pdev->beMethods = pbe->methods; /* copy backend methods */ 1131 TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry); 1132 return; 1133} 1134 1135void 1136libusb20_be_dequeue_device(struct libusb20_backend *pbe, 1137 struct libusb20_device *pdev) 1138{ 1139 TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry); 1140 return; 1141} 1142