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