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