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