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