1 /* $FreeBSD$ */ 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 <sys/queue.h> 28 #include <sys/types.h> 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <poll.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 38 #include "libusb20.h" 39 #include "libusb20_desc.h" 40 #include "libusb20_int.h" 41 42 #include <dev/usb/usb.h> 43 #include <dev/usb/usbdi.h> 44 #include <dev/usb/usb_ioctl.h> 45 46 static libusb20_init_backend_t ugen20_init_backend; 47 static libusb20_open_device_t ugen20_open_device; 48 static libusb20_close_device_t ugen20_close_device; 49 static libusb20_get_backend_name_t ugen20_get_backend_name; 50 static libusb20_exit_backend_t ugen20_exit_backend; 51 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc; 52 static libusb20_dev_get_info_t ugen20_dev_get_info; 53 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk; 54 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name; 55 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk; 56 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk; 57 static libusb20_root_set_template_t ugen20_root_set_template; 58 static libusb20_root_get_template_t ugen20_root_get_template; 59 60 const struct libusb20_backend_methods libusb20_ugen20_backend = { 61 LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20) 62 }; 63 64 /* USB device specific */ 65 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 66 static libusb20_get_config_index_t ugen20_get_config_index; 67 static libusb20_set_config_index_t ugen20_set_config_index; 68 static libusb20_set_alt_index_t ugen20_set_alt_index; 69 static libusb20_reset_device_t ugen20_reset_device; 70 static libusb20_set_power_mode_t ugen20_set_power_mode; 71 static libusb20_get_power_mode_t ugen20_get_power_mode; 72 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 73 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 74 static libusb20_do_request_sync_t ugen20_do_request_sync; 75 static libusb20_process_t ugen20_process; 76 77 /* USB transfer specific */ 78 static libusb20_tr_open_t ugen20_tr_open; 79 static libusb20_tr_close_t ugen20_tr_close; 80 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 81 static libusb20_tr_submit_t ugen20_tr_submit; 82 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 83 84 static const struct libusb20_device_methods libusb20_ugen20_device_methods = { 85 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 86 }; 87 88 static const char * 89 ugen20_get_backend_name(void) 90 { 91 return ("FreeBSD UGEN 2.0"); 92 } 93 94 static uint32_t 95 ugen20_path_convert_one(const char **pp) 96 { 97 const char *ptr; 98 uint32_t temp = 0; 99 100 ptr = *pp; 101 102 while ((*ptr >= '0') && (*ptr <= '9')) { 103 temp *= 10; 104 temp += (*ptr - '0'); 105 if (temp >= 1000000) { 106 /* catch overflow early */ 107 return (0 - 1); 108 } 109 ptr++; 110 } 111 112 if (*ptr == '.') { 113 /* skip dot */ 114 ptr++; 115 } 116 *pp = ptr; 117 118 return (temp); 119 } 120 121 static int 122 ugen20_enumerate(struct libusb20_device *pdev, const char *id) 123 { 124 const char *tmp = id; 125 struct usb_device_descriptor ddesc; 126 struct usb_device_info devinfo; 127 uint32_t plugtime; 128 char buf[64]; 129 int f; 130 int error; 131 132 pdev->bus_number = ugen20_path_convert_one(&tmp); 133 pdev->device_address = ugen20_path_convert_one(&tmp); 134 135 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 136 pdev->bus_number, pdev->device_address); 137 138 f = open(buf, O_RDWR); 139 if (f < 0) { 140 return (LIBUSB20_ERROR_OTHER); 141 } 142 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 143 error = LIBUSB20_ERROR_OTHER; 144 goto done; 145 } 146 /* store when the device was plugged */ 147 pdev->session_data.plugtime = plugtime; 148 149 if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) { 150 error = LIBUSB20_ERROR_OTHER; 151 goto done; 152 } 153 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 154 155 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 156 157 if (pdev->ddesc.bNumConfigurations == 0) { 158 error = LIBUSB20_ERROR_OTHER; 159 goto done; 160 } else if (pdev->ddesc.bNumConfigurations >= 8) { 161 error = LIBUSB20_ERROR_OTHER; 162 goto done; 163 } 164 if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) { 165 error = LIBUSB20_ERROR_OTHER; 166 goto done; 167 } 168 switch (devinfo.udi_mode) { 169 case USB_MODE_DEVICE: 170 pdev->usb_mode = LIBUSB20_MODE_DEVICE; 171 break; 172 default: 173 pdev->usb_mode = LIBUSB20_MODE_HOST; 174 break; 175 } 176 177 switch (devinfo.udi_speed) { 178 case USB_SPEED_LOW: 179 pdev->usb_speed = LIBUSB20_SPEED_LOW; 180 break; 181 case USB_SPEED_FULL: 182 pdev->usb_speed = LIBUSB20_SPEED_FULL; 183 break; 184 case USB_SPEED_HIGH: 185 pdev->usb_speed = LIBUSB20_SPEED_HIGH; 186 break; 187 case USB_SPEED_VARIABLE: 188 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 189 break; 190 case USB_SPEED_SUPER: 191 pdev->usb_speed = LIBUSB20_SPEED_SUPER; 192 break; 193 default: 194 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 195 break; 196 } 197 198 /* generate a nice description for printout */ 199 200 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 201 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 202 pdev->device_address, devinfo.udi_product, 203 devinfo.udi_vendor, pdev->bus_number); 204 205 error = 0; 206 done: 207 close(f); 208 return (error); 209 } 210 211 struct ugen20_urd_state { 212 struct usb_read_dir urd; 213 uint32_t nparsed; 214 int f; 215 uint8_t *ptr; 216 const char *src; 217 const char *dst; 218 uint8_t buf[256]; 219 uint8_t dummy_zero[1]; 220 }; 221 222 static int 223 ugen20_readdir(struct ugen20_urd_state *st) 224 { 225 ; /* style fix */ 226 repeat: 227 if (st->ptr == NULL) { 228 st->urd.urd_startentry += st->nparsed; 229 st->urd.urd_data = st->buf; 230 st->urd.urd_maxlen = sizeof(st->buf); 231 st->nparsed = 0; 232 233 if (ioctl(st->f, USB_READ_DIR, &st->urd)) { 234 return (EINVAL); 235 } 236 st->ptr = st->buf; 237 } 238 if (st->ptr[0] == 0) { 239 if (st->nparsed) { 240 st->ptr = NULL; 241 goto repeat; 242 } else { 243 return (ENXIO); 244 } 245 } 246 st->src = (void *)(st->ptr + 1); 247 st->dst = st->src + strlen(st->src) + 1; 248 st->ptr = st->ptr + st->ptr[0]; 249 st->nparsed++; 250 251 if ((st->ptr < st->buf) || 252 (st->ptr > st->dummy_zero)) { 253 /* invalid entry */ 254 return (EINVAL); 255 } 256 return (0); 257 } 258 259 static int 260 ugen20_init_backend(struct libusb20_backend *pbe) 261 { 262 struct ugen20_urd_state state; 263 struct libusb20_device *pdev; 264 265 memset(&state, 0, sizeof(state)); 266 267 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 268 if (state.f < 0) 269 return (LIBUSB20_ERROR_OTHER); 270 271 while (ugen20_readdir(&state) == 0) { 272 273 if ((state.src[0] != 'u') || 274 (state.src[1] != 'g') || 275 (state.src[2] != 'e') || 276 (state.src[3] != 'n')) { 277 continue; 278 } 279 pdev = libusb20_dev_alloc(); 280 if (pdev == NULL) { 281 continue; 282 } 283 if (ugen20_enumerate(pdev, state.src + 4)) { 284 libusb20_dev_free(pdev); 285 continue; 286 } 287 /* put the device on the backend list */ 288 libusb20_be_enqueue_device(pbe, pdev); 289 } 290 close(state.f); 291 return (0); /* success */ 292 } 293 294 static void 295 ugen20_tr_release(struct libusb20_device *pdev) 296 { 297 struct usb_fs_uninit fs_uninit; 298 299 if (pdev->nTransfer == 0) { 300 return; 301 } 302 /* release all pending USB transfers */ 303 if (pdev->privBeData != NULL) { 304 memset(&fs_uninit, 0, sizeof(fs_uninit)); 305 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 306 /* ignore any errors of this kind */ 307 } 308 } 309 return; 310 } 311 312 static int 313 ugen20_tr_renew(struct libusb20_device *pdev) 314 { 315 struct usb_fs_init fs_init; 316 struct usb_fs_endpoint *pfse; 317 int error; 318 uint32_t size; 319 uint16_t nMaxTransfer; 320 321 nMaxTransfer = pdev->nTransfer; 322 error = 0; 323 324 if (nMaxTransfer == 0) { 325 goto done; 326 } 327 size = nMaxTransfer * sizeof(*pfse); 328 329 if (pdev->privBeData == NULL) { 330 pfse = malloc(size); 331 if (pfse == NULL) { 332 error = LIBUSB20_ERROR_NO_MEM; 333 goto done; 334 } 335 pdev->privBeData = pfse; 336 } 337 /* reset endpoint data */ 338 memset(pdev->privBeData, 0, size); 339 340 memset(&fs_init, 0, sizeof(fs_init)); 341 342 fs_init.pEndpoints = pdev->privBeData; 343 fs_init.ep_index_max = nMaxTransfer; 344 345 if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) { 346 error = LIBUSB20_ERROR_OTHER; 347 goto done; 348 } 349 done: 350 return (error); 351 } 352 353 static int 354 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 355 { 356 uint32_t plugtime; 357 char buf[64]; 358 int f; 359 int g; 360 int error; 361 362 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 363 pdev->bus_number, pdev->device_address); 364 365 /* 366 * We need two file handles, one for the control endpoint and one 367 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 368 * kernel locking. 369 */ 370 g = open(buf, O_RDWR); 371 if (g < 0) { 372 return (LIBUSB20_ERROR_NO_DEVICE); 373 } 374 f = open(buf, O_RDWR); 375 if (f < 0) { 376 close(g); 377 return (LIBUSB20_ERROR_NO_DEVICE); 378 } 379 if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) { 380 error = LIBUSB20_ERROR_OTHER; 381 goto done; 382 } 383 /* check that the correct device is still plugged */ 384 if (pdev->session_data.plugtime != plugtime) { 385 error = LIBUSB20_ERROR_NO_DEVICE; 386 goto done; 387 } 388 /* need to set this before "tr_renew()" */ 389 pdev->file = f; 390 pdev->file_ctrl = g; 391 392 /* renew all USB transfers */ 393 error = ugen20_tr_renew(pdev); 394 if (error) { 395 goto done; 396 } 397 /* set methods */ 398 pdev->methods = &libusb20_ugen20_device_methods; 399 400 done: 401 if (error) { 402 if (pdev->privBeData) { 403 /* cleanup after "tr_renew()" */ 404 free(pdev->privBeData); 405 pdev->privBeData = NULL; 406 } 407 pdev->file = -1; 408 pdev->file_ctrl = -1; 409 close(f); 410 close(g); 411 } 412 return (error); 413 } 414 415 static int 416 ugen20_close_device(struct libusb20_device *pdev) 417 { 418 struct usb_fs_uninit fs_uninit; 419 420 if (pdev->privBeData) { 421 memset(&fs_uninit, 0, sizeof(fs_uninit)); 422 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) { 423 /* ignore this error */ 424 } 425 free(pdev->privBeData); 426 } 427 pdev->nTransfer = 0; 428 pdev->privBeData = NULL; 429 close(pdev->file); 430 close(pdev->file_ctrl); 431 pdev->file = -1; 432 pdev->file_ctrl = -1; 433 return (0); /* success */ 434 } 435 436 static void 437 ugen20_exit_backend(struct libusb20_backend *pbe) 438 { 439 return; /* nothing to do */ 440 } 441 442 static int 443 ugen20_get_config_desc_full(struct libusb20_device *pdev, 444 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 445 { 446 struct usb_gen_descriptor gen_desc; 447 struct usb_config_descriptor cdesc; 448 uint8_t *ptr; 449 uint16_t len; 450 int error; 451 452 memset(&gen_desc, 0, sizeof(gen_desc)); 453 454 gen_desc.ugd_data = &cdesc; 455 gen_desc.ugd_maxlen = sizeof(cdesc); 456 gen_desc.ugd_config_index = cfg_index; 457 458 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 459 if (error) { 460 return (LIBUSB20_ERROR_OTHER); 461 } 462 len = UGETW(cdesc.wTotalLength); 463 if (len < sizeof(cdesc)) { 464 /* corrupt descriptor */ 465 return (LIBUSB20_ERROR_OTHER); 466 } 467 ptr = malloc(len); 468 if (!ptr) { 469 return (LIBUSB20_ERROR_NO_MEM); 470 } 471 gen_desc.ugd_data = ptr; 472 gen_desc.ugd_maxlen = len; 473 474 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 475 if (error) { 476 free(ptr); 477 return (LIBUSB20_ERROR_OTHER); 478 } 479 /* make sure that the device doesn't fool us */ 480 memcpy(ptr, &cdesc, sizeof(cdesc)); 481 482 *ppbuf = ptr; 483 *plen = len; 484 485 return (0); /* success */ 486 } 487 488 static int 489 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 490 { 491 int temp; 492 493 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) { 494 return (LIBUSB20_ERROR_OTHER); 495 } 496 *pindex = temp; 497 498 return (0); 499 } 500 501 static int 502 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 503 { 504 int temp = cfg_index; 505 506 /* release all active USB transfers */ 507 ugen20_tr_release(pdev); 508 509 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) { 510 return (LIBUSB20_ERROR_OTHER); 511 } 512 return (ugen20_tr_renew(pdev)); 513 } 514 515 static int 516 ugen20_set_alt_index(struct libusb20_device *pdev, 517 uint8_t iface_index, uint8_t alt_index) 518 { 519 struct usb_alt_interface alt_iface; 520 521 memset(&alt_iface, 0, sizeof(alt_iface)); 522 523 alt_iface.uai_interface_index = iface_index; 524 alt_iface.uai_alt_index = alt_index; 525 526 /* release all active USB transfers */ 527 ugen20_tr_release(pdev); 528 529 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) { 530 return (LIBUSB20_ERROR_OTHER); 531 } 532 return (ugen20_tr_renew(pdev)); 533 } 534 535 static int 536 ugen20_reset_device(struct libusb20_device *pdev) 537 { 538 int temp = 0; 539 540 /* release all active USB transfers */ 541 ugen20_tr_release(pdev); 542 543 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) { 544 return (LIBUSB20_ERROR_OTHER); 545 } 546 return (ugen20_tr_renew(pdev)); 547 } 548 549 static int 550 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 551 { 552 int temp; 553 554 switch (power_mode) { 555 case LIBUSB20_POWER_OFF: 556 temp = USB_POWER_MODE_OFF; 557 break; 558 case LIBUSB20_POWER_ON: 559 temp = USB_POWER_MODE_ON; 560 break; 561 case LIBUSB20_POWER_SAVE: 562 temp = USB_POWER_MODE_SAVE; 563 break; 564 case LIBUSB20_POWER_SUSPEND: 565 temp = USB_POWER_MODE_SUSPEND; 566 break; 567 case LIBUSB20_POWER_RESUME: 568 temp = USB_POWER_MODE_RESUME; 569 break; 570 default: 571 return (LIBUSB20_ERROR_INVALID_PARAM); 572 } 573 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) { 574 return (LIBUSB20_ERROR_OTHER); 575 } 576 return (0); 577 } 578 579 static int 580 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 581 { 582 int temp; 583 584 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) { 585 return (LIBUSB20_ERROR_OTHER); 586 } 587 switch (temp) { 588 case USB_POWER_MODE_OFF: 589 temp = LIBUSB20_POWER_OFF; 590 break; 591 case USB_POWER_MODE_ON: 592 temp = LIBUSB20_POWER_ON; 593 break; 594 case USB_POWER_MODE_SAVE: 595 temp = LIBUSB20_POWER_SAVE; 596 break; 597 case USB_POWER_MODE_SUSPEND: 598 temp = LIBUSB20_POWER_SUSPEND; 599 break; 600 case USB_POWER_MODE_RESUME: 601 temp = LIBUSB20_POWER_RESUME; 602 break; 603 default: 604 temp = LIBUSB20_POWER_ON; 605 break; 606 } 607 *power_mode = temp; 608 return (0); /* success */ 609 } 610 611 static int 612 ugen20_kernel_driver_active(struct libusb20_device *pdev, 613 uint8_t iface_index) 614 { 615 int temp = iface_index; 616 617 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) { 618 return (LIBUSB20_ERROR_OTHER); 619 } 620 return (0); /* kernel driver is active */ 621 } 622 623 static int 624 ugen20_detach_kernel_driver(struct libusb20_device *pdev, 625 uint8_t iface_index) 626 { 627 int temp = iface_index; 628 629 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) { 630 return (LIBUSB20_ERROR_OTHER); 631 } 632 return (0); /* kernel driver is active */ 633 } 634 635 static int 636 ugen20_do_request_sync(struct libusb20_device *pdev, 637 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 638 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 639 { 640 struct usb_ctl_request req; 641 642 memset(&req, 0, sizeof(req)); 643 644 req.ucr_data = data; 645 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 646 req.ucr_flags |= USB_SHORT_XFER_OK; 647 } 648 if (libusb20_me_encode(&req.ucr_request, 649 sizeof(req.ucr_request), setup)) { 650 /* ignore */ 651 } 652 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) { 653 return (LIBUSB20_ERROR_OTHER); 654 } 655 if (pactlen) { 656 /* get actual length */ 657 *pactlen = req.ucr_actlen; 658 } 659 return (0); /* kernel driver is active */ 660 } 661 662 static int 663 ugen20_process(struct libusb20_device *pdev) 664 { 665 struct usb_fs_complete temp; 666 struct usb_fs_endpoint *fsep; 667 struct libusb20_transfer *xfer; 668 669 while (1) { 670 671 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) { 672 if (errno == EBUSY) { 673 break; 674 } else { 675 /* device detached */ 676 return (LIBUSB20_ERROR_OTHER); 677 } 678 } 679 fsep = pdev->privBeData; 680 xfer = pdev->pTransfer; 681 fsep += temp.ep_index; 682 xfer += temp.ep_index; 683 684 /* update transfer status */ 685 686 if (fsep->status == 0) { 687 xfer->aFrames = fsep->aFrames; 688 xfer->timeComplete = fsep->isoc_time_complete; 689 xfer->status = LIBUSB20_TRANSFER_COMPLETED; 690 } else if (fsep->status == USB_ERR_CANCELLED) { 691 xfer->aFrames = 0; 692 xfer->timeComplete = 0; 693 xfer->status = LIBUSB20_TRANSFER_CANCELLED; 694 } else if (fsep->status == USB_ERR_STALLED) { 695 xfer->aFrames = 0; 696 xfer->timeComplete = 0; 697 xfer->status = LIBUSB20_TRANSFER_STALL; 698 } else if (fsep->status == USB_ERR_TIMEOUT) { 699 xfer->aFrames = 0; 700 xfer->timeComplete = 0; 701 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 702 } else { 703 xfer->aFrames = 0; 704 xfer->timeComplete = 0; 705 xfer->status = LIBUSB20_TRANSFER_ERROR; 706 } 707 libusb20_tr_callback_wrapper(xfer); 708 } 709 return (0); /* done */ 710 } 711 712 static int 713 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 714 uint32_t MaxFrameCount, uint8_t ep_no) 715 { 716 struct usb_fs_open temp; 717 struct usb_fs_endpoint *fsep; 718 719 memset(&temp, 0, sizeof(temp)); 720 721 fsep = xfer->pdev->privBeData; 722 fsep += xfer->trIndex; 723 724 temp.max_bufsize = MaxBufSize; 725 temp.max_frames = MaxFrameCount; 726 temp.ep_index = xfer->trIndex; 727 temp.ep_no = ep_no; 728 729 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) { 730 return (LIBUSB20_ERROR_INVALID_PARAM); 731 } 732 /* maximums might have changed - update */ 733 xfer->maxFrames = temp.max_frames; 734 735 /* "max_bufsize" should be multiple of "max_packet_length" */ 736 xfer->maxTotalLength = temp.max_bufsize; 737 xfer->maxPacketLen = temp.max_packet_length; 738 739 /* setup buffer and length lists */ 740 fsep->ppBuffer = xfer->ppBuffer;/* zero copy */ 741 fsep->pLength = xfer->pLength; /* zero copy */ 742 743 return (0); /* success */ 744 } 745 746 static int 747 ugen20_tr_close(struct libusb20_transfer *xfer) 748 { 749 struct usb_fs_close temp; 750 751 memset(&temp, 0, sizeof(temp)); 752 753 temp.ep_index = xfer->trIndex; 754 755 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) { 756 return (LIBUSB20_ERROR_INVALID_PARAM); 757 } 758 return (0); /* success */ 759 } 760 761 static int 762 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 763 { 764 struct usb_fs_clear_stall_sync temp; 765 766 memset(&temp, 0, sizeof(temp)); 767 768 /* if the transfer is active, an error will be returned */ 769 770 temp.ep_index = xfer->trIndex; 771 772 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) { 773 return (LIBUSB20_ERROR_INVALID_PARAM); 774 } 775 return (0); /* success */ 776 } 777 778 static void 779 ugen20_tr_submit(struct libusb20_transfer *xfer) 780 { 781 struct usb_fs_start temp; 782 struct usb_fs_endpoint *fsep; 783 784 memset(&temp, 0, sizeof(temp)); 785 786 fsep = xfer->pdev->privBeData; 787 fsep += xfer->trIndex; 788 789 fsep->nFrames = xfer->nFrames; 790 fsep->flags = 0; 791 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 792 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 793 } 794 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 795 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 796 } 797 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 798 fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 799 } 800 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 801 fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 802 } 803 fsep->timeout = xfer->timeout; 804 805 temp.ep_index = xfer->trIndex; 806 807 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) { 808 /* ignore any errors - should never happen */ 809 } 810 return; /* success */ 811 } 812 813 static void 814 ugen20_tr_cancel_async(struct libusb20_transfer *xfer) 815 { 816 struct usb_fs_stop temp; 817 818 memset(&temp, 0, sizeof(temp)); 819 820 temp.ep_index = xfer->trIndex; 821 822 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) { 823 /* ignore any errors - should never happen */ 824 } 825 return; 826 } 827 828 static int 829 ugen20_be_ioctl(uint32_t cmd, void *data) 830 { 831 int f; 832 int error; 833 834 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 835 if (f < 0) 836 return (LIBUSB20_ERROR_OTHER); 837 error = ioctl(f, cmd, data); 838 if (error == -1) { 839 if (errno == EPERM) { 840 error = LIBUSB20_ERROR_ACCESS; 841 } else { 842 error = LIBUSB20_ERROR_OTHER; 843 } 844 } 845 close(f); 846 return (error); 847 } 848 849 static int 850 ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 851 uint8_t iface_index, char *buf, uint8_t len) 852 { 853 struct usb_gen_descriptor ugd; 854 855 memset(&ugd, 0, sizeof(ugd)); 856 857 ugd.ugd_data = buf; 858 ugd.ugd_maxlen = len; 859 ugd.ugd_iface_index = iface_index; 860 861 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) { 862 return (LIBUSB20_ERROR_INVALID_PARAM); 863 } 864 return (0); 865 } 866 867 static int 868 ugen20_dev_get_info(struct libusb20_device *pdev, 869 struct usb_device_info *pinfo) 870 { 871 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) { 872 return (LIBUSB20_ERROR_INVALID_PARAM); 873 } 874 return (0); 875 } 876 877 static int 878 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 879 uint16_t quirk_index, struct libusb20_quirk *pq) 880 { 881 struct usb_gen_quirk q; 882 int error; 883 884 memset(&q, 0, sizeof(q)); 885 886 q.index = quirk_index; 887 888 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q); 889 890 if (error) { 891 if (errno == EINVAL) { 892 return (LIBUSB20_ERROR_NOT_FOUND); 893 } 894 } else { 895 pq->vid = q.vid; 896 pq->pid = q.pid; 897 pq->bcdDeviceLow = q.bcdDeviceLow; 898 pq->bcdDeviceHigh = q.bcdDeviceHigh; 899 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 900 } 901 return (error); 902 } 903 904 static int 905 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 906 struct libusb20_quirk *pq) 907 { 908 struct usb_gen_quirk q; 909 int error; 910 911 memset(&q, 0, sizeof(q)); 912 913 q.index = quirk_index; 914 915 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q); 916 917 if (error) { 918 if (errno == EINVAL) { 919 return (LIBUSB20_ERROR_NOT_FOUND); 920 } 921 } else { 922 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 923 } 924 return (error); 925 } 926 927 static int 928 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 929 struct libusb20_quirk *pq) 930 { 931 struct usb_gen_quirk q; 932 int error; 933 934 memset(&q, 0, sizeof(q)); 935 936 q.vid = pq->vid; 937 q.pid = pq->pid; 938 q.bcdDeviceLow = pq->bcdDeviceLow; 939 q.bcdDeviceHigh = pq->bcdDeviceHigh; 940 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 941 942 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q); 943 if (error) { 944 if (errno == ENOMEM) { 945 return (LIBUSB20_ERROR_NO_MEM); 946 } 947 } 948 return (error); 949 } 950 951 static int 952 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 953 struct libusb20_quirk *pq) 954 { 955 struct usb_gen_quirk q; 956 int error; 957 958 memset(&q, 0, sizeof(q)); 959 960 q.vid = pq->vid; 961 q.pid = pq->pid; 962 q.bcdDeviceLow = pq->bcdDeviceLow; 963 q.bcdDeviceHigh = pq->bcdDeviceHigh; 964 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 965 966 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q); 967 if (error) { 968 if (errno == EINVAL) { 969 return (LIBUSB20_ERROR_NOT_FOUND); 970 } 971 } 972 return (error); 973 } 974 975 static int 976 ugen20_root_set_template(struct libusb20_backend *pbe, int temp) 977 { 978 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp)); 979 } 980 981 static int 982 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 983 { 984 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp)); 985 } 986