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 /* make sure memory is initialised */ 453 memset(&cdesc, 0, sizeof(cdesc)); 454 memset(&gen_desc, 0, sizeof(gen_desc)); 455 456 gen_desc.ugd_data = &cdesc; 457 gen_desc.ugd_maxlen = sizeof(cdesc); 458 gen_desc.ugd_config_index = cfg_index; 459 460 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 461 if (error) { 462 return (LIBUSB20_ERROR_OTHER); 463 } 464 len = UGETW(cdesc.wTotalLength); 465 if (len < sizeof(cdesc)) { 466 /* corrupt descriptor */ 467 return (LIBUSB20_ERROR_OTHER); 468 } 469 ptr = malloc(len); 470 if (!ptr) { 471 return (LIBUSB20_ERROR_NO_MEM); 472 } 473 474 /* make sure memory is initialised */ 475 memset(ptr, 0, len); 476 477 gen_desc.ugd_data = ptr; 478 gen_desc.ugd_maxlen = len; 479 480 error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc); 481 if (error) { 482 free(ptr); 483 return (LIBUSB20_ERROR_OTHER); 484 } 485 /* make sure that the device doesn't fool us */ 486 memcpy(ptr, &cdesc, sizeof(cdesc)); 487 488 *ppbuf = ptr; 489 *plen = len; 490 491 return (0); /* success */ 492 } 493 494 static int 495 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 496 { 497 int temp; 498 499 if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) { 500 return (LIBUSB20_ERROR_OTHER); 501 } 502 *pindex = temp; 503 504 return (0); 505 } 506 507 static int 508 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 509 { 510 int temp = cfg_index; 511 512 /* release all active USB transfers */ 513 ugen20_tr_release(pdev); 514 515 if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) { 516 return (LIBUSB20_ERROR_OTHER); 517 } 518 return (ugen20_tr_renew(pdev)); 519 } 520 521 static int 522 ugen20_set_alt_index(struct libusb20_device *pdev, 523 uint8_t iface_index, uint8_t alt_index) 524 { 525 struct usb_alt_interface alt_iface; 526 527 memset(&alt_iface, 0, sizeof(alt_iface)); 528 529 alt_iface.uai_interface_index = iface_index; 530 alt_iface.uai_alt_index = alt_index; 531 532 /* release all active USB transfers */ 533 ugen20_tr_release(pdev); 534 535 if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) { 536 return (LIBUSB20_ERROR_OTHER); 537 } 538 return (ugen20_tr_renew(pdev)); 539 } 540 541 static int 542 ugen20_reset_device(struct libusb20_device *pdev) 543 { 544 int temp = 0; 545 546 /* release all active USB transfers */ 547 ugen20_tr_release(pdev); 548 549 if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) { 550 return (LIBUSB20_ERROR_OTHER); 551 } 552 return (ugen20_tr_renew(pdev)); 553 } 554 555 static int 556 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 557 { 558 int temp; 559 560 switch (power_mode) { 561 case LIBUSB20_POWER_OFF: 562 temp = USB_POWER_MODE_OFF; 563 break; 564 case LIBUSB20_POWER_ON: 565 temp = USB_POWER_MODE_ON; 566 break; 567 case LIBUSB20_POWER_SAVE: 568 temp = USB_POWER_MODE_SAVE; 569 break; 570 case LIBUSB20_POWER_SUSPEND: 571 temp = USB_POWER_MODE_SUSPEND; 572 break; 573 case LIBUSB20_POWER_RESUME: 574 temp = USB_POWER_MODE_RESUME; 575 break; 576 default: 577 return (LIBUSB20_ERROR_INVALID_PARAM); 578 } 579 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) { 580 return (LIBUSB20_ERROR_OTHER); 581 } 582 return (0); 583 } 584 585 static int 586 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 587 { 588 int temp; 589 590 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) { 591 return (LIBUSB20_ERROR_OTHER); 592 } 593 switch (temp) { 594 case USB_POWER_MODE_OFF: 595 temp = LIBUSB20_POWER_OFF; 596 break; 597 case USB_POWER_MODE_ON: 598 temp = LIBUSB20_POWER_ON; 599 break; 600 case USB_POWER_MODE_SAVE: 601 temp = LIBUSB20_POWER_SAVE; 602 break; 603 case USB_POWER_MODE_SUSPEND: 604 temp = LIBUSB20_POWER_SUSPEND; 605 break; 606 case USB_POWER_MODE_RESUME: 607 temp = LIBUSB20_POWER_RESUME; 608 break; 609 default: 610 temp = LIBUSB20_POWER_ON; 611 break; 612 } 613 *power_mode = temp; 614 return (0); /* success */ 615 } 616 617 static int 618 ugen20_kernel_driver_active(struct libusb20_device *pdev, 619 uint8_t iface_index) 620 { 621 int temp = iface_index; 622 623 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) { 624 return (LIBUSB20_ERROR_OTHER); 625 } 626 return (0); /* kernel driver is active */ 627 } 628 629 static int 630 ugen20_detach_kernel_driver(struct libusb20_device *pdev, 631 uint8_t iface_index) 632 { 633 int temp = iface_index; 634 635 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) { 636 return (LIBUSB20_ERROR_OTHER); 637 } 638 return (0); /* kernel driver is active */ 639 } 640 641 static int 642 ugen20_do_request_sync(struct libusb20_device *pdev, 643 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 644 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 645 { 646 struct usb_ctl_request req; 647 648 memset(&req, 0, sizeof(req)); 649 650 req.ucr_data = data; 651 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 652 req.ucr_flags |= USB_SHORT_XFER_OK; 653 } 654 if (libusb20_me_encode(&req.ucr_request, 655 sizeof(req.ucr_request), setup)) { 656 /* ignore */ 657 } 658 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) { 659 return (LIBUSB20_ERROR_OTHER); 660 } 661 if (pactlen) { 662 /* get actual length */ 663 *pactlen = req.ucr_actlen; 664 } 665 return (0); /* kernel driver is active */ 666 } 667 668 static int 669 ugen20_process(struct libusb20_device *pdev) 670 { 671 struct usb_fs_complete temp; 672 struct usb_fs_endpoint *fsep; 673 struct libusb20_transfer *xfer; 674 675 while (1) { 676 677 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) { 678 if (errno == EBUSY) { 679 break; 680 } else { 681 /* device detached */ 682 return (LIBUSB20_ERROR_OTHER); 683 } 684 } 685 fsep = pdev->privBeData; 686 xfer = pdev->pTransfer; 687 fsep += temp.ep_index; 688 xfer += temp.ep_index; 689 690 /* update transfer status */ 691 692 if (fsep->status == 0) { 693 xfer->aFrames = fsep->aFrames; 694 xfer->timeComplete = fsep->isoc_time_complete; 695 xfer->status = LIBUSB20_TRANSFER_COMPLETED; 696 } else if (fsep->status == USB_ERR_CANCELLED) { 697 xfer->aFrames = 0; 698 xfer->timeComplete = 0; 699 xfer->status = LIBUSB20_TRANSFER_CANCELLED; 700 } else if (fsep->status == USB_ERR_STALLED) { 701 xfer->aFrames = 0; 702 xfer->timeComplete = 0; 703 xfer->status = LIBUSB20_TRANSFER_STALL; 704 } else if (fsep->status == USB_ERR_TIMEOUT) { 705 xfer->aFrames = 0; 706 xfer->timeComplete = 0; 707 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 708 } else { 709 xfer->aFrames = 0; 710 xfer->timeComplete = 0; 711 xfer->status = LIBUSB20_TRANSFER_ERROR; 712 } 713 libusb20_tr_callback_wrapper(xfer); 714 } 715 return (0); /* done */ 716 } 717 718 static int 719 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 720 uint32_t MaxFrameCount, uint8_t ep_no) 721 { 722 struct usb_fs_open temp; 723 struct usb_fs_endpoint *fsep; 724 725 memset(&temp, 0, sizeof(temp)); 726 727 fsep = xfer->pdev->privBeData; 728 fsep += xfer->trIndex; 729 730 temp.max_bufsize = MaxBufSize; 731 temp.max_frames = MaxFrameCount; 732 temp.ep_index = xfer->trIndex; 733 temp.ep_no = ep_no; 734 735 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) { 736 return (LIBUSB20_ERROR_INVALID_PARAM); 737 } 738 /* maximums might have changed - update */ 739 xfer->maxFrames = temp.max_frames; 740 741 /* "max_bufsize" should be multiple of "max_packet_length" */ 742 xfer->maxTotalLength = temp.max_bufsize; 743 xfer->maxPacketLen = temp.max_packet_length; 744 745 /* setup buffer and length lists */ 746 fsep->ppBuffer = xfer->ppBuffer;/* zero copy */ 747 fsep->pLength = xfer->pLength; /* zero copy */ 748 749 return (0); /* success */ 750 } 751 752 static int 753 ugen20_tr_close(struct libusb20_transfer *xfer) 754 { 755 struct usb_fs_close temp; 756 757 memset(&temp, 0, sizeof(temp)); 758 759 temp.ep_index = xfer->trIndex; 760 761 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) { 762 return (LIBUSB20_ERROR_INVALID_PARAM); 763 } 764 return (0); /* success */ 765 } 766 767 static int 768 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 769 { 770 struct usb_fs_clear_stall_sync temp; 771 772 memset(&temp, 0, sizeof(temp)); 773 774 /* if the transfer is active, an error will be returned */ 775 776 temp.ep_index = xfer->trIndex; 777 778 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) { 779 return (LIBUSB20_ERROR_INVALID_PARAM); 780 } 781 return (0); /* success */ 782 } 783 784 static void 785 ugen20_tr_submit(struct libusb20_transfer *xfer) 786 { 787 struct usb_fs_start temp; 788 struct usb_fs_endpoint *fsep; 789 790 memset(&temp, 0, sizeof(temp)); 791 792 fsep = xfer->pdev->privBeData; 793 fsep += xfer->trIndex; 794 795 fsep->nFrames = xfer->nFrames; 796 fsep->flags = 0; 797 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 798 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 799 } 800 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 801 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 802 } 803 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 804 fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 805 } 806 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 807 fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 808 } 809 /* NOTE: The "fsep->timeout" variable is 16-bit. */ 810 if (xfer->timeout > 65535) 811 fsep->timeout = 65535; 812 else 813 fsep->timeout = xfer->timeout; 814 815 temp.ep_index = xfer->trIndex; 816 817 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) { 818 /* ignore any errors - should never happen */ 819 } 820 return; /* success */ 821 } 822 823 static void 824 ugen20_tr_cancel_async(struct libusb20_transfer *xfer) 825 { 826 struct usb_fs_stop temp; 827 828 memset(&temp, 0, sizeof(temp)); 829 830 temp.ep_index = xfer->trIndex; 831 832 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) { 833 /* ignore any errors - should never happen */ 834 } 835 return; 836 } 837 838 static int 839 ugen20_be_ioctl(uint32_t cmd, void *data) 840 { 841 int f; 842 int error; 843 844 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 845 if (f < 0) 846 return (LIBUSB20_ERROR_OTHER); 847 error = ioctl(f, cmd, data); 848 if (error == -1) { 849 if (errno == EPERM) { 850 error = LIBUSB20_ERROR_ACCESS; 851 } else { 852 error = LIBUSB20_ERROR_OTHER; 853 } 854 } 855 close(f); 856 return (error); 857 } 858 859 static int 860 ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 861 uint8_t iface_index, char *buf, uint8_t len) 862 { 863 struct usb_gen_descriptor ugd; 864 865 memset(&ugd, 0, sizeof(ugd)); 866 867 ugd.ugd_data = buf; 868 ugd.ugd_maxlen = len; 869 ugd.ugd_iface_index = iface_index; 870 871 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) { 872 return (LIBUSB20_ERROR_INVALID_PARAM); 873 } 874 return (0); 875 } 876 877 static int 878 ugen20_dev_get_info(struct libusb20_device *pdev, 879 struct usb_device_info *pinfo) 880 { 881 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) { 882 return (LIBUSB20_ERROR_INVALID_PARAM); 883 } 884 return (0); 885 } 886 887 static int 888 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 889 uint16_t quirk_index, struct libusb20_quirk *pq) 890 { 891 struct usb_gen_quirk q; 892 int error; 893 894 memset(&q, 0, sizeof(q)); 895 896 q.index = quirk_index; 897 898 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q); 899 900 if (error) { 901 if (errno == EINVAL) { 902 return (LIBUSB20_ERROR_NOT_FOUND); 903 } 904 } else { 905 pq->vid = q.vid; 906 pq->pid = q.pid; 907 pq->bcdDeviceLow = q.bcdDeviceLow; 908 pq->bcdDeviceHigh = q.bcdDeviceHigh; 909 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 910 } 911 return (error); 912 } 913 914 static int 915 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 916 struct libusb20_quirk *pq) 917 { 918 struct usb_gen_quirk q; 919 int error; 920 921 memset(&q, 0, sizeof(q)); 922 923 q.index = quirk_index; 924 925 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q); 926 927 if (error) { 928 if (errno == EINVAL) { 929 return (LIBUSB20_ERROR_NOT_FOUND); 930 } 931 } else { 932 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 933 } 934 return (error); 935 } 936 937 static int 938 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 939 struct libusb20_quirk *pq) 940 { 941 struct usb_gen_quirk q; 942 int error; 943 944 memset(&q, 0, sizeof(q)); 945 946 q.vid = pq->vid; 947 q.pid = pq->pid; 948 q.bcdDeviceLow = pq->bcdDeviceLow; 949 q.bcdDeviceHigh = pq->bcdDeviceHigh; 950 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 951 952 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q); 953 if (error) { 954 if (errno == ENOMEM) { 955 return (LIBUSB20_ERROR_NO_MEM); 956 } 957 } 958 return (error); 959 } 960 961 static int 962 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 963 struct libusb20_quirk *pq) 964 { 965 struct usb_gen_quirk q; 966 int error; 967 968 memset(&q, 0, sizeof(q)); 969 970 q.vid = pq->vid; 971 q.pid = pq->pid; 972 q.bcdDeviceLow = pq->bcdDeviceLow; 973 q.bcdDeviceHigh = pq->bcdDeviceHigh; 974 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 975 976 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q); 977 if (error) { 978 if (errno == EINVAL) { 979 return (LIBUSB20_ERROR_NOT_FOUND); 980 } 981 } 982 return (error); 983 } 984 985 static int 986 ugen20_root_set_template(struct libusb20_backend *pbe, int temp) 987 { 988 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp)); 989 } 990 991 static int 992 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 993 { 994 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp)); 995 } 996