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 /* 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 = libusb20_pass_ptr(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 = libusb20_pass_ptr(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 = libusb20_pass_ptr(&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 = libusb20_pass_ptr(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_check_connected(struct libusb20_device *pdev) 557 { 558 uint32_t plugtime; 559 int error = 0; 560 561 if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) { 562 error = LIBUSB20_ERROR_NO_DEVICE; 563 goto done; 564 } 565 566 if (pdev->session_data.plugtime != plugtime) { 567 error = LIBUSB20_ERROR_NO_DEVICE; 568 goto done; 569 } 570 done: 571 return (error); 572 } 573 574 static int 575 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 576 { 577 int temp; 578 579 switch (power_mode) { 580 case LIBUSB20_POWER_OFF: 581 temp = USB_POWER_MODE_OFF; 582 break; 583 case LIBUSB20_POWER_ON: 584 temp = USB_POWER_MODE_ON; 585 break; 586 case LIBUSB20_POWER_SAVE: 587 temp = USB_POWER_MODE_SAVE; 588 break; 589 case LIBUSB20_POWER_SUSPEND: 590 temp = USB_POWER_MODE_SUSPEND; 591 break; 592 case LIBUSB20_POWER_RESUME: 593 temp = USB_POWER_MODE_RESUME; 594 break; 595 default: 596 return (LIBUSB20_ERROR_INVALID_PARAM); 597 } 598 if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) { 599 return (LIBUSB20_ERROR_OTHER); 600 } 601 return (0); 602 } 603 604 static int 605 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 606 { 607 int temp; 608 609 if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) { 610 return (LIBUSB20_ERROR_OTHER); 611 } 612 switch (temp) { 613 case USB_POWER_MODE_OFF: 614 temp = LIBUSB20_POWER_OFF; 615 break; 616 case USB_POWER_MODE_ON: 617 temp = LIBUSB20_POWER_ON; 618 break; 619 case USB_POWER_MODE_SAVE: 620 temp = LIBUSB20_POWER_SAVE; 621 break; 622 case USB_POWER_MODE_SUSPEND: 623 temp = LIBUSB20_POWER_SUSPEND; 624 break; 625 case USB_POWER_MODE_RESUME: 626 temp = LIBUSB20_POWER_RESUME; 627 break; 628 default: 629 temp = LIBUSB20_POWER_ON; 630 break; 631 } 632 *power_mode = temp; 633 return (0); /* success */ 634 } 635 636 static int 637 ugen20_kernel_driver_active(struct libusb20_device *pdev, 638 uint8_t iface_index) 639 { 640 int temp = iface_index; 641 642 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) { 643 return (LIBUSB20_ERROR_OTHER); 644 } 645 return (0); /* kernel driver is active */ 646 } 647 648 static int 649 ugen20_detach_kernel_driver(struct libusb20_device *pdev, 650 uint8_t iface_index) 651 { 652 int temp = iface_index; 653 654 if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) { 655 return (LIBUSB20_ERROR_OTHER); 656 } 657 return (0); /* kernel driver is active */ 658 } 659 660 static int 661 ugen20_do_request_sync(struct libusb20_device *pdev, 662 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 663 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 664 { 665 struct usb_ctl_request req; 666 667 memset(&req, 0, sizeof(req)); 668 669 req.ucr_data = libusb20_pass_ptr(data); 670 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 671 req.ucr_flags |= USB_SHORT_XFER_OK; 672 } 673 if (libusb20_me_encode(&req.ucr_request, 674 sizeof(req.ucr_request), setup)) { 675 /* ignore */ 676 } 677 if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) { 678 return (LIBUSB20_ERROR_OTHER); 679 } 680 if (pactlen) { 681 /* get actual length */ 682 *pactlen = req.ucr_actlen; 683 } 684 return (0); /* kernel driver is active */ 685 } 686 687 static int 688 ugen20_process(struct libusb20_device *pdev) 689 { 690 struct usb_fs_complete temp; 691 struct usb_fs_endpoint *fsep; 692 struct libusb20_transfer *xfer; 693 694 while (1) { 695 696 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) { 697 if (errno == EBUSY) { 698 break; 699 } else { 700 /* device detached */ 701 return (LIBUSB20_ERROR_OTHER); 702 } 703 } 704 fsep = pdev->privBeData; 705 xfer = pdev->pTransfer; 706 fsep += temp.ep_index; 707 xfer += temp.ep_index; 708 709 /* update transfer status */ 710 711 if (fsep->status == 0) { 712 xfer->aFrames = fsep->aFrames; 713 xfer->timeComplete = fsep->isoc_time_complete; 714 xfer->status = LIBUSB20_TRANSFER_COMPLETED; 715 } else if (fsep->status == USB_ERR_CANCELLED) { 716 xfer->aFrames = 0; 717 xfer->timeComplete = 0; 718 xfer->status = LIBUSB20_TRANSFER_CANCELLED; 719 } else if (fsep->status == USB_ERR_STALLED) { 720 xfer->aFrames = 0; 721 xfer->timeComplete = 0; 722 xfer->status = LIBUSB20_TRANSFER_STALL; 723 } else if (fsep->status == USB_ERR_TIMEOUT) { 724 xfer->aFrames = 0; 725 xfer->timeComplete = 0; 726 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 727 } else { 728 xfer->aFrames = 0; 729 xfer->timeComplete = 0; 730 xfer->status = LIBUSB20_TRANSFER_ERROR; 731 } 732 libusb20_tr_callback_wrapper(xfer); 733 } 734 return (0); /* done */ 735 } 736 737 static int 738 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 739 uint32_t MaxFrameCount, uint8_t ep_no) 740 { 741 struct usb_fs_open temp; 742 struct usb_fs_endpoint *fsep; 743 744 memset(&temp, 0, sizeof(temp)); 745 746 fsep = xfer->pdev->privBeData; 747 fsep += xfer->trIndex; 748 749 temp.max_bufsize = MaxBufSize; 750 temp.max_frames = MaxFrameCount; 751 temp.ep_index = xfer->trIndex; 752 temp.ep_no = ep_no; 753 754 if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) { 755 return (LIBUSB20_ERROR_INVALID_PARAM); 756 } 757 /* maximums might have changed - update */ 758 xfer->maxFrames = temp.max_frames; 759 760 /* "max_bufsize" should be multiple of "max_packet_length" */ 761 xfer->maxTotalLength = temp.max_bufsize; 762 xfer->maxPacketLen = temp.max_packet_length; 763 764 /* setup buffer and length lists using zero copy */ 765 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer); 766 fsep->pLength = libusb20_pass_ptr(xfer->pLength); 767 768 return (0); /* success */ 769 } 770 771 static int 772 ugen20_tr_close(struct libusb20_transfer *xfer) 773 { 774 struct usb_fs_close temp; 775 776 memset(&temp, 0, sizeof(temp)); 777 778 temp.ep_index = xfer->trIndex; 779 780 if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) { 781 return (LIBUSB20_ERROR_INVALID_PARAM); 782 } 783 return (0); /* success */ 784 } 785 786 static int 787 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 788 { 789 struct usb_fs_clear_stall_sync temp; 790 791 memset(&temp, 0, sizeof(temp)); 792 793 /* if the transfer is active, an error will be returned */ 794 795 temp.ep_index = xfer->trIndex; 796 797 if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) { 798 return (LIBUSB20_ERROR_INVALID_PARAM); 799 } 800 return (0); /* success */ 801 } 802 803 static void 804 ugen20_tr_submit(struct libusb20_transfer *xfer) 805 { 806 struct usb_fs_start temp; 807 struct usb_fs_endpoint *fsep; 808 809 memset(&temp, 0, sizeof(temp)); 810 811 fsep = xfer->pdev->privBeData; 812 fsep += xfer->trIndex; 813 814 fsep->nFrames = xfer->nFrames; 815 fsep->flags = 0; 816 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 817 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 818 } 819 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 820 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 821 } 822 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 823 fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 824 } 825 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 826 fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 827 } 828 /* NOTE: The "fsep->timeout" variable is 16-bit. */ 829 if (xfer->timeout > 65535) 830 fsep->timeout = 65535; 831 else 832 fsep->timeout = xfer->timeout; 833 834 temp.ep_index = xfer->trIndex; 835 836 if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) { 837 /* ignore any errors - should never happen */ 838 } 839 return; /* success */ 840 } 841 842 static void 843 ugen20_tr_cancel_async(struct libusb20_transfer *xfer) 844 { 845 struct usb_fs_stop temp; 846 847 memset(&temp, 0, sizeof(temp)); 848 849 temp.ep_index = xfer->trIndex; 850 851 if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) { 852 /* ignore any errors - should never happen */ 853 } 854 return; 855 } 856 857 static int 858 ugen20_be_ioctl(uint32_t cmd, void *data) 859 { 860 int f; 861 int error; 862 863 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 864 if (f < 0) 865 return (LIBUSB20_ERROR_OTHER); 866 error = ioctl(f, cmd, data); 867 if (error == -1) { 868 if (errno == EPERM) { 869 error = LIBUSB20_ERROR_ACCESS; 870 } else { 871 error = LIBUSB20_ERROR_OTHER; 872 } 873 } 874 close(f); 875 return (error); 876 } 877 878 static int 879 ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 880 uint8_t iface_index, char *buf, uint8_t len) 881 { 882 struct usb_gen_descriptor ugd; 883 884 memset(&ugd, 0, sizeof(ugd)); 885 886 ugd.ugd_data = libusb20_pass_ptr(buf); 887 ugd.ugd_maxlen = len; 888 ugd.ugd_iface_index = iface_index; 889 890 if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) { 891 return (LIBUSB20_ERROR_INVALID_PARAM); 892 } 893 return (0); 894 } 895 896 static int 897 ugen20_dev_get_info(struct libusb20_device *pdev, 898 struct usb_device_info *pinfo) 899 { 900 if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) { 901 return (LIBUSB20_ERROR_INVALID_PARAM); 902 } 903 return (0); 904 } 905 906 static int 907 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 908 uint16_t quirk_index, struct libusb20_quirk *pq) 909 { 910 struct usb_gen_quirk q; 911 int error; 912 913 memset(&q, 0, sizeof(q)); 914 915 q.index = quirk_index; 916 917 error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q); 918 919 if (error) { 920 if (errno == EINVAL) { 921 return (LIBUSB20_ERROR_NOT_FOUND); 922 } 923 } else { 924 pq->vid = q.vid; 925 pq->pid = q.pid; 926 pq->bcdDeviceLow = q.bcdDeviceLow; 927 pq->bcdDeviceHigh = q.bcdDeviceHigh; 928 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 929 } 930 return (error); 931 } 932 933 static int 934 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 935 struct libusb20_quirk *pq) 936 { 937 struct usb_gen_quirk q; 938 int error; 939 940 memset(&q, 0, sizeof(q)); 941 942 q.index = quirk_index; 943 944 error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q); 945 946 if (error) { 947 if (errno == EINVAL) { 948 return (LIBUSB20_ERROR_NOT_FOUND); 949 } 950 } else { 951 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 952 } 953 return (error); 954 } 955 956 static int 957 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 958 struct libusb20_quirk *pq) 959 { 960 struct usb_gen_quirk q; 961 int error; 962 963 memset(&q, 0, sizeof(q)); 964 965 q.vid = pq->vid; 966 q.pid = pq->pid; 967 q.bcdDeviceLow = pq->bcdDeviceLow; 968 q.bcdDeviceHigh = pq->bcdDeviceHigh; 969 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 970 971 error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q); 972 if (error) { 973 if (errno == ENOMEM) { 974 return (LIBUSB20_ERROR_NO_MEM); 975 } 976 } 977 return (error); 978 } 979 980 static int 981 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 982 struct libusb20_quirk *pq) 983 { 984 struct usb_gen_quirk q; 985 int error; 986 987 memset(&q, 0, sizeof(q)); 988 989 q.vid = pq->vid; 990 q.pid = pq->pid; 991 q.bcdDeviceLow = pq->bcdDeviceLow; 992 q.bcdDeviceHigh = pq->bcdDeviceHigh; 993 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 994 995 error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q); 996 if (error) { 997 if (errno == EINVAL) { 998 return (LIBUSB20_ERROR_NOT_FOUND); 999 } 1000 } 1001 return (error); 1002 } 1003 1004 static int 1005 ugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1006 { 1007 return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp)); 1008 } 1009 1010 static int 1011 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1012 { 1013 return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp)); 1014 } 1015