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/capsicum.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 struct libusb20_be_ctx * 74 libusb20_be_ctx_alloc(void) 75 { 76 cap_rights_t rights; 77 struct libusb20_be_ctx *pctx; 78 int fd; 79 80 pctx = malloc(sizeof(*pctx)); 81 if (pctx == NULL) 82 return (NULL); 83 84 /* 85 * The context is immutable once this function returns, which 86 * makes it safe to share between threads without any locking. 87 * Open failures are tolerated, so that allocation also 88 * succeeds on systems without USB support. 89 */ 90 fd = open("/dev/" USB_DEVICE_NAME, O_RDONLY | O_CLOEXEC); 91 if (fd > -1) { 92 cap_rights_init(&rights, CAP_READ, CAP_EVENT, CAP_IOCTL); 93 if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) { 94 close(fd); 95 fd = -1; 96 } 97 } 98 pctx->ctrl_fd = fd; 99 100 fd = open("/dev/" USB_DEVICE_DIR, O_DIRECTORY | O_PATH | O_CLOEXEC); 101 if (fd > -1) { 102 /* 103 * Device descriptors derived through openat(2) 104 * inherit these rights, so they must cover all 105 * operations performed on open devices, including by 106 * applications using libusb20_dev_get_fd(). 107 */ 108 cap_rights_init(&rights, CAP_LOOKUP, CAP_PREAD, CAP_PWRITE, 109 CAP_EVENT, CAP_IOCTL); 110 if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) { 111 close(fd); 112 fd = -1; 113 } 114 } 115 pctx->usb_dfd = fd; 116 117 return (pctx); 118 } 119 120 void 121 libusb20_be_ctx_free(struct libusb20_be_ctx *pctx) 122 { 123 if (pctx == NULL) { 124 /* be NULL safe */ 125 return; 126 } 127 if (pctx->ctrl_fd > -1) 128 close(pctx->ctrl_fd); 129 if (pctx->usb_dfd > -1) 130 close(pctx->usb_dfd); 131 free(pctx); 132 } 133 134 /* USB device specific */ 135 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full; 136 static libusb20_get_config_index_t ugen20_get_config_index; 137 static libusb20_set_config_index_t ugen20_set_config_index; 138 static libusb20_set_alt_index_t ugen20_set_alt_index; 139 static libusb20_reset_device_t ugen20_reset_device; 140 static libusb20_check_connected_t ugen20_check_connected; 141 static libusb20_set_power_mode_t ugen20_set_power_mode; 142 static libusb20_get_power_mode_t ugen20_get_power_mode; 143 static libusb20_get_power_usage_t ugen20_get_power_usage; 144 static libusb20_get_stats_t ugen20_get_stats; 145 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active; 146 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver; 147 static libusb20_attach_kernel_driver_t ugen20_attach_kernel_driver; 148 static libusb20_do_request_sync_t ugen20_do_request_sync; 149 static libusb20_process_t ugen20_process; 150 151 /* USB transfer specific */ 152 static libusb20_tr_open_t ugen20_tr_open; 153 static libusb20_tr_close_t ugen20_tr_close; 154 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync; 155 static libusb20_tr_submit_t ugen20_tr_submit; 156 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async; 157 158 static const struct libusb20_device_methods libusb20_ugen20_device_methods = { 159 LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20) 160 }; 161 162 static int 163 errno_to_libusb_error(int uerr) 164 { 165 switch (uerr) { 166 case 0: 167 return (LIBUSB20_SUCCESS); 168 case EIO: 169 case ERANGE: 170 return (LIBUSB20_ERROR_IO); 171 case EINVAL: 172 case EFAULT: 173 case ENOBUFS: 174 return (LIBUSB20_ERROR_INVALID_PARAM); 175 case EACCES: 176 case EPERM: 177 return (LIBUSB20_ERROR_ACCESS); 178 case ENXIO: 179 case ENODEV: 180 return (LIBUSB20_ERROR_NO_DEVICE); 181 case ENOENT: 182 return (LIBUSB20_ERROR_NOT_FOUND); 183 case EBUSY: 184 case EALREADY: 185 case EADDRINUSE: 186 return (LIBUSB20_ERROR_BUSY); 187 case ETIMEDOUT: 188 return (LIBUSB20_ERROR_TIMEOUT); 189 case EMSGSIZE: 190 return (LIBUSB20_ERROR_OVERFLOW); 191 case EPIPE: 192 return (LIBUSB20_ERROR_PIPE); 193 case EINTR: 194 case ECANCELED: 195 return (LIBUSB20_ERROR_INTERRUPTED); 196 case ENOMEM: 197 return (LIBUSB20_ERROR_NO_MEM); 198 case ENOTSUP: 199 return (LIBUSB20_ERROR_NOT_SUPPORTED); 200 default: 201 return (LIBUSB20_ERROR_OTHER); 202 } 203 } 204 205 static const char * 206 ugen20_get_backend_name(void) 207 { 208 return ("FreeBSD UGEN 2.0"); 209 } 210 211 static uint32_t 212 ugen20_path_convert_one(const char **pp) 213 { 214 const char *ptr; 215 uint32_t temp = 0; 216 217 ptr = *pp; 218 219 while ((*ptr >= '0') && (*ptr <= '9')) { 220 temp *= 10; 221 temp += (*ptr - '0'); 222 if (temp >= 1000000) { 223 /* catch overflow early */ 224 return (0xFFFFFFFF); 225 } 226 ptr++; 227 } 228 229 if (*ptr == '.') { 230 /* skip dot */ 231 ptr++; 232 } 233 *pp = ptr; 234 235 return (temp); 236 } 237 238 static int 239 ugen20_open_dev(struct libusb20_be_ctx *pctx, int bus_num, int dev_addr, 240 int flag) 241 { 242 char path[48]; 243 int usb_dfd; 244 245 usb_dfd = pctx->usb_dfd; 246 if (usb_dfd > -1) { 247 snprintf(path, sizeof(path), "%u.%u.0", bus_num, dev_addr); 248 return (openat(usb_dfd, path, flag)); 249 } 250 251 /* fall back when the /dev/usb directory is not available */ 252 snprintf(path, sizeof(path), "/dev/" USB_GENERIC_NAME "%u.%u", 253 bus_num, dev_addr); 254 return (open(path, flag)); 255 } 256 257 static int 258 ugen20_enumerate(struct libusb20_device *pdev, const char *id) 259 { 260 const char *tmp = id; 261 struct usb_device_descriptor ddesc; 262 struct usb_device_info devinfo; 263 struct usb_device_port_path udpp; 264 uint32_t plugtime; 265 int f; 266 int error; 267 268 pdev->bus_number = ugen20_path_convert_one(&tmp); 269 pdev->device_address = ugen20_path_convert_one(&tmp); 270 271 f = ugen20_open_dev(pdev->be_ctx, pdev->bus_number, 272 pdev->device_address, O_RDWR); 273 if (f < 0) { 274 return (LIBUSB20_ERROR_OTHER); 275 } 276 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 277 error = LIBUSB20_ERROR_OTHER; 278 goto done; 279 } 280 /* store when the device was plugged */ 281 pdev->session_data.plugtime = plugtime; 282 283 if (ioctl(f, IOUSB(USB_GET_DEVICE_DESC), &ddesc)) { 284 error = LIBUSB20_ERROR_OTHER; 285 goto done; 286 } 287 LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc)); 288 289 libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc)); 290 291 if (pdev->ddesc.bNumConfigurations == 0) { 292 error = LIBUSB20_ERROR_OTHER; 293 goto done; 294 } else if (pdev->ddesc.bNumConfigurations >= 8) { 295 error = LIBUSB20_ERROR_OTHER; 296 goto done; 297 } 298 if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo)) { 299 error = LIBUSB20_ERROR_OTHER; 300 goto done; 301 } 302 switch (devinfo.udi_mode) { 303 case USB_MODE_DEVICE: 304 pdev->usb_mode = LIBUSB20_MODE_DEVICE; 305 break; 306 default: 307 pdev->usb_mode = LIBUSB20_MODE_HOST; 308 break; 309 } 310 311 switch (devinfo.udi_speed) { 312 case USB_SPEED_LOW: 313 pdev->usb_speed = LIBUSB20_SPEED_LOW; 314 break; 315 case USB_SPEED_FULL: 316 pdev->usb_speed = LIBUSB20_SPEED_FULL; 317 break; 318 case USB_SPEED_HIGH: 319 pdev->usb_speed = LIBUSB20_SPEED_HIGH; 320 break; 321 case USB_SPEED_VARIABLE: 322 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE; 323 break; 324 case USB_SPEED_SUPER: 325 pdev->usb_speed = LIBUSB20_SPEED_SUPER; 326 break; 327 default: 328 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN; 329 break; 330 } 331 332 /* get parent HUB index and port */ 333 334 pdev->parent_address = devinfo.udi_hubindex; 335 pdev->parent_port = devinfo.udi_hubport; 336 337 /* generate a nice description for printout */ 338 339 snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), 340 USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number, 341 pdev->device_address, devinfo.udi_vendor, 342 devinfo.udi_product, pdev->bus_number); 343 344 /* get device port path, if any */ 345 if (ioctl(f, IOUSB(USB_GET_DEV_PORT_PATH), &udpp) == 0 && 346 udpp.udp_port_level < LIBUSB20_DEVICE_PORT_PATH_MAX) { 347 memcpy(pdev->port_path, udpp.udp_port_no, udpp.udp_port_level); 348 pdev->port_level = udpp.udp_port_level; 349 } 350 351 error = 0; 352 done: 353 close(f); 354 return (error); 355 } 356 357 struct ugen20_urd_state { 358 struct usb_read_dir urd; 359 uint32_t nparsed; 360 int f; 361 uint8_t *ptr; 362 const char *src; 363 const char *dst; 364 uint8_t buf[256]; 365 uint8_t dummy_zero[1]; 366 }; 367 368 static int 369 ugen20_readdir(struct ugen20_urd_state *st) 370 { 371 ; /* style fix */ 372 repeat: 373 if (st->ptr == NULL) { 374 st->urd.urd_startentry += st->nparsed; 375 st->urd.urd_data = st->buf; 376 st->urd.urd_maxlen = sizeof(st->buf); 377 st->nparsed = 0; 378 379 if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) { 380 return (EINVAL); 381 } 382 st->ptr = st->buf; 383 } 384 if (st->ptr[0] == 0) { 385 if (st->nparsed) { 386 st->ptr = NULL; 387 goto repeat; 388 } else { 389 return (ENXIO); 390 } 391 } 392 st->src = (void *)(st->ptr + 1); 393 st->dst = st->src + strlen(st->src) + 1; 394 st->ptr = st->ptr + st->ptr[0]; 395 st->nparsed++; 396 397 if ((st->ptr < st->buf) || 398 (st->ptr > st->dummy_zero)) { 399 /* invalid entry */ 400 return (EINVAL); 401 } 402 return (0); 403 } 404 405 static int 406 ugen20_init_backend(struct libusb20_backend *pbe) 407 { 408 struct ugen20_urd_state state; 409 struct libusb20_device *pdev; 410 411 memset(&state, 0, sizeof(state)); 412 413 state.f = pbe->be_ctx->ctrl_fd; 414 if (state.f < 0) 415 return (LIBUSB20_ERROR_OTHER); 416 417 while (ugen20_readdir(&state) == 0) { 418 419 if ((state.src[0] != 'u') || 420 (state.src[1] != 'g') || 421 (state.src[2] != 'e') || 422 (state.src[3] != 'n')) { 423 continue; 424 } 425 pdev = libusb20_dev_alloc(); 426 if (pdev == NULL) { 427 continue; 428 } 429 /* 430 * The device borrows the backend context, which must 431 * stay alive for as long as the device is in use. 432 */ 433 pdev->be_ctx = pbe->be_ctx; 434 435 if (ugen20_enumerate(pdev, state.src + 4)) { 436 libusb20_dev_free(pdev); 437 continue; 438 } 439 /* put the device on the backend list */ 440 libusb20_be_enqueue_device(pbe, pdev); 441 } 442 return (0); /* success */ 443 } 444 445 static void 446 ugen20_tr_release(struct libusb20_device *pdev) 447 { 448 struct usb_fs_uninit fs_uninit; 449 450 if (pdev->nTransfer == 0) { 451 return; 452 } 453 /* release all pending USB transfers */ 454 if (pdev->privBeData != NULL) { 455 memset(&fs_uninit, 0, sizeof(fs_uninit)); 456 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 457 /* ignore any errors of this kind */ 458 } 459 } 460 return; 461 } 462 463 static int 464 ugen20_tr_renew(struct libusb20_device *pdev) 465 { 466 struct usb_fs_init fs_init; 467 struct usb_fs_endpoint *pfse; 468 int error; 469 uint32_t size; 470 uint16_t nMaxTransfer; 471 472 nMaxTransfer = pdev->nTransfer; 473 error = 0; 474 475 if (nMaxTransfer == 0) { 476 goto done; 477 } 478 size = nMaxTransfer * sizeof(*pfse); 479 480 if (pdev->privBeData == NULL) { 481 pfse = malloc(size); 482 if (pfse == NULL) { 483 error = LIBUSB20_ERROR_NO_MEM; 484 goto done; 485 } 486 pdev->privBeData = pfse; 487 } 488 /* reset endpoint data */ 489 memset(pdev->privBeData, 0, size); 490 491 memset(&fs_init, 0, sizeof(fs_init)); 492 493 fs_init.pEndpoints = pdev->privBeData; 494 fs_init.ep_index_max = nMaxTransfer; 495 496 if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) { 497 error = LIBUSB20_ERROR_OTHER; 498 goto done; 499 } 500 done: 501 return (error); 502 } 503 504 static int 505 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 506 { 507 uint32_t plugtime; 508 int f; 509 int g; 510 int error; 511 512 /* 513 * We need two file handles, one for the control endpoint and one 514 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 515 * kernel locking. 516 */ 517 g = ugen20_open_dev(pdev->be_ctx, pdev->bus_number, 518 pdev->device_address, O_RDWR); 519 if (g < 0) { 520 return (LIBUSB20_ERROR_NO_DEVICE); 521 } 522 f = ugen20_open_dev(pdev->be_ctx, pdev->bus_number, 523 pdev->device_address, O_RDWR); 524 if (f < 0) { 525 close(g); 526 return (LIBUSB20_ERROR_NO_DEVICE); 527 } 528 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 529 error = LIBUSB20_ERROR_OTHER; 530 goto done; 531 } 532 /* check that the correct device is still plugged */ 533 if (pdev->session_data.plugtime != plugtime) { 534 error = LIBUSB20_ERROR_NO_DEVICE; 535 goto done; 536 } 537 /* need to set this before "tr_renew()" */ 538 pdev->file = f; 539 pdev->file_ctrl = g; 540 541 /* renew all USB transfers */ 542 error = ugen20_tr_renew(pdev); 543 if (error) { 544 goto done; 545 } 546 /* set methods */ 547 pdev->methods = &libusb20_ugen20_device_methods; 548 549 done: 550 if (error) { 551 if (pdev->privBeData) { 552 /* cleanup after "tr_renew()" */ 553 free(pdev->privBeData); 554 pdev->privBeData = NULL; 555 } 556 pdev->file = -1; 557 pdev->file_ctrl = -1; 558 close(f); 559 close(g); 560 } 561 return (error); 562 } 563 564 static int 565 ugen20_close_device(struct libusb20_device *pdev) 566 { 567 struct usb_fs_uninit fs_uninit; 568 569 if (pdev->privBeData) { 570 memset(&fs_uninit, 0, sizeof(fs_uninit)); 571 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 572 /* ignore this error */ 573 } 574 free(pdev->privBeData); 575 } 576 pdev->nTransfer = 0; 577 pdev->privBeData = NULL; 578 close(pdev->file); 579 close(pdev->file_ctrl); 580 pdev->file = -1; 581 pdev->file_ctrl = -1; 582 return (0); /* success */ 583 } 584 585 static void 586 ugen20_exit_backend(struct libusb20_backend *pbe) 587 { 588 return; /* nothing to do */ 589 } 590 591 static int 592 ugen20_get_config_desc_full(struct libusb20_device *pdev, 593 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 594 { 595 struct usb_gen_descriptor gen_desc; 596 struct usb_config_descriptor cdesc; 597 uint8_t *ptr; 598 uint16_t len; 599 int error; 600 601 /* make sure memory is initialised */ 602 memset(&cdesc, 0, sizeof(cdesc)); 603 memset(&gen_desc, 0, sizeof(gen_desc)); 604 605 gen_desc.ugd_data = &cdesc; 606 gen_desc.ugd_maxlen = sizeof(cdesc); 607 gen_desc.ugd_config_index = cfg_index; 608 609 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 610 if (error) { 611 return (LIBUSB20_ERROR_OTHER); 612 } 613 len = UGETW(cdesc.wTotalLength); 614 if (len < sizeof(cdesc)) { 615 /* corrupt descriptor */ 616 return (LIBUSB20_ERROR_OTHER); 617 } 618 ptr = malloc(len); 619 if (!ptr) { 620 return (LIBUSB20_ERROR_NO_MEM); 621 } 622 623 /* make sure memory is initialised */ 624 memset(ptr, 0, len); 625 626 gen_desc.ugd_data = ptr; 627 gen_desc.ugd_maxlen = len; 628 629 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 630 if (error) { 631 free(ptr); 632 return (LIBUSB20_ERROR_OTHER); 633 } 634 /* make sure that the device doesn't fool us */ 635 memcpy(ptr, &cdesc, sizeof(cdesc)); 636 637 *ppbuf = ptr; 638 *plen = len; 639 640 return (0); /* success */ 641 } 642 643 static int 644 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 645 { 646 int temp; 647 648 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) { 649 return (LIBUSB20_ERROR_OTHER); 650 } 651 *pindex = temp; 652 653 return (0); 654 } 655 656 static int 657 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 658 { 659 int temp = cfg_index; 660 661 /* release all active USB transfers */ 662 ugen20_tr_release(pdev); 663 664 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) { 665 return (LIBUSB20_ERROR_OTHER); 666 } 667 return (ugen20_tr_renew(pdev)); 668 } 669 670 static int 671 ugen20_set_alt_index(struct libusb20_device *pdev, 672 uint8_t iface_index, uint8_t alt_index) 673 { 674 struct usb_alt_interface alt_iface; 675 676 memset(&alt_iface, 0, sizeof(alt_iface)); 677 678 alt_iface.uai_interface_index = iface_index; 679 alt_iface.uai_alt_index = alt_index; 680 681 /* release all active USB transfers */ 682 ugen20_tr_release(pdev); 683 684 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) { 685 return (LIBUSB20_ERROR_OTHER); 686 } 687 return (ugen20_tr_renew(pdev)); 688 } 689 690 static int 691 ugen20_reset_device(struct libusb20_device *pdev) 692 { 693 int temp = 0; 694 695 /* release all active USB transfers */ 696 ugen20_tr_release(pdev); 697 698 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) { 699 return (LIBUSB20_ERROR_OTHER); 700 } 701 return (ugen20_tr_renew(pdev)); 702 } 703 704 static int 705 ugen20_check_connected(struct libusb20_device *pdev) 706 { 707 uint32_t plugtime; 708 int error = 0; 709 710 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 711 error = LIBUSB20_ERROR_NO_DEVICE; 712 goto done; 713 } 714 715 if (pdev->session_data.plugtime != plugtime) { 716 error = LIBUSB20_ERROR_NO_DEVICE; 717 goto done; 718 } 719 done: 720 return (error); 721 } 722 723 static int 724 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 725 { 726 int temp; 727 728 switch (power_mode) { 729 case LIBUSB20_POWER_OFF: 730 temp = USB_POWER_MODE_OFF; 731 break; 732 case LIBUSB20_POWER_ON: 733 temp = USB_POWER_MODE_ON; 734 break; 735 case LIBUSB20_POWER_SAVE: 736 temp = USB_POWER_MODE_SAVE; 737 break; 738 case LIBUSB20_POWER_SUSPEND: 739 temp = USB_POWER_MODE_SUSPEND; 740 break; 741 case LIBUSB20_POWER_RESUME: 742 temp = USB_POWER_MODE_RESUME; 743 break; 744 default: 745 return (LIBUSB20_ERROR_INVALID_PARAM); 746 } 747 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) { 748 return (LIBUSB20_ERROR_OTHER); 749 } 750 return (0); 751 } 752 753 static int 754 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 755 { 756 int temp; 757 758 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) { 759 return (LIBUSB20_ERROR_OTHER); 760 } 761 switch (temp) { 762 case USB_POWER_MODE_OFF: 763 temp = LIBUSB20_POWER_OFF; 764 break; 765 case USB_POWER_MODE_ON: 766 temp = LIBUSB20_POWER_ON; 767 break; 768 case USB_POWER_MODE_SAVE: 769 temp = LIBUSB20_POWER_SAVE; 770 break; 771 case USB_POWER_MODE_SUSPEND: 772 temp = LIBUSB20_POWER_SUSPEND; 773 break; 774 case USB_POWER_MODE_RESUME: 775 temp = LIBUSB20_POWER_RESUME; 776 break; 777 default: 778 temp = LIBUSB20_POWER_ON; 779 break; 780 } 781 *power_mode = temp; 782 return (0); /* success */ 783 } 784 785 static int 786 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) 787 { 788 int temp; 789 790 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) { 791 return (LIBUSB20_ERROR_OTHER); 792 } 793 *power_usage = temp; 794 return (0); /* success */ 795 } 796 797 static int 798 ugen20_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats) 799 { 800 struct usb_device_stats st; 801 802 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICESTATS), &st)) 803 return (LIBUSB20_ERROR_OTHER); 804 805 memset(pstats, 0, sizeof(*pstats)); 806 807 pstats->xfer_ok[0] = st.uds_requests_ok[0]; 808 pstats->xfer_ok[1] = st.uds_requests_ok[1]; 809 pstats->xfer_ok[2] = st.uds_requests_ok[2]; 810 pstats->xfer_ok[3] = st.uds_requests_ok[3]; 811 812 pstats->xfer_fail[0] = st.uds_requests_fail[0]; 813 pstats->xfer_fail[1] = st.uds_requests_fail[1]; 814 pstats->xfer_fail[2] = st.uds_requests_fail[2]; 815 pstats->xfer_fail[3] = st.uds_requests_fail[3]; 816 817 return (0); /* success */ 818 } 819 820 static int 821 ugen20_kernel_driver_active(struct libusb20_device *pdev, 822 uint8_t iface_index) 823 { 824 int temp = iface_index; 825 826 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) { 827 return (LIBUSB20_ERROR_OTHER); 828 } 829 return (0); /* kernel driver is active */ 830 } 831 832 static int 833 ugen20_detach_kernel_driver(struct libusb20_device *pdev, 834 uint8_t iface_index) 835 { 836 int temp = iface_index; 837 838 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) { 839 return (LIBUSB20_ERROR_OTHER); 840 } 841 return (0); /* kernel driver is detached */ 842 } 843 844 static int 845 ugen20_attach_kernel_driver(struct libusb20_device *pdev, uint8_t iface_index) 846 { 847 int temp = iface_index; 848 849 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ATTACH), &temp)) { 850 return (LIBUSB20_ERROR_OTHER); 851 } 852 return (0); /* kernel driver is attached */ 853 } 854 855 static int 856 ugen20_do_request_sync(struct libusb20_device *pdev, 857 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 858 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 859 { 860 struct usb_ctl_request req; 861 862 memset(&req, 0, sizeof(req)); 863 864 req.ucr_data = data; 865 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 866 req.ucr_flags |= USB_SHORT_XFER_OK; 867 } 868 if (libusb20_me_encode(&req.ucr_request, 869 sizeof(req.ucr_request), setup)) { 870 /* ignore */ 871 } 872 if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) { 873 return (errno_to_libusb_error(errno)); 874 } 875 if (pactlen) { 876 /* get actual length */ 877 *pactlen = req.ucr_actlen; 878 } 879 return (0); /* request was successful */ 880 } 881 882 static int 883 ugen20_process(struct libusb20_device *pdev) 884 { 885 struct usb_fs_complete temp; 886 struct usb_fs_endpoint *fsep; 887 struct libusb20_transfer *xfer; 888 889 while (1) { 890 891 if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) { 892 if (errno == EBUSY || errno == EINVAL) { 893 /* 894 * EBUSY: no completion is pending. 895 * EINVAL: a dequeued completion referenced an 896 * endpoint that no longer exists, e.g. a stale 897 * completion left over after a SET_INTERFACE / 898 * SET_CONFIG tore the endpoints down. This is not 899 * a device detach, so stop draining rather than 900 * declaring the device gone. 901 */ 902 break; 903 } else { 904 /* device detached */ 905 return (LIBUSB20_ERROR_OTHER); 906 } 907 } 908 fsep = pdev->privBeData; 909 xfer = pdev->pTransfer; 910 fsep += temp.ep_index; 911 xfer += temp.ep_index; 912 913 /* update transfer status */ 914 915 if (fsep->status == 0) { 916 xfer->aFrames = fsep->aFrames; 917 xfer->timeComplete = fsep->isoc_time_complete; 918 xfer->status = LIBUSB20_TRANSFER_COMPLETED; 919 } else if (fsep->status == USB_ERR_CANCELLED) { 920 xfer->aFrames = 0; 921 xfer->timeComplete = 0; 922 xfer->status = LIBUSB20_TRANSFER_CANCELLED; 923 } else if (fsep->status == USB_ERR_STALLED) { 924 xfer->aFrames = 0; 925 xfer->timeComplete = 0; 926 xfer->status = LIBUSB20_TRANSFER_STALL; 927 } else if (fsep->status == USB_ERR_TIMEOUT) { 928 xfer->aFrames = 0; 929 xfer->timeComplete = 0; 930 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 931 } else { 932 xfer->aFrames = 0; 933 xfer->timeComplete = 0; 934 xfer->status = LIBUSB20_TRANSFER_ERROR; 935 } 936 libusb20_tr_callback_wrapper(xfer); 937 } 938 return (0); /* done */ 939 } 940 941 static int 942 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 943 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id, 944 uint8_t pre_scale) 945 { 946 union { 947 struct usb_fs_open fs_open; 948 struct usb_fs_open_stream fs_open_stream; 949 } temp; 950 struct usb_fs_endpoint *fsep; 951 952 if (pre_scale) 953 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; 954 955 memset(&temp, 0, sizeof(temp)); 956 957 fsep = xfer->pdev->privBeData; 958 fsep += xfer->trIndex; 959 960 temp.fs_open.max_bufsize = MaxBufSize; 961 temp.fs_open.max_frames = MaxFrameCount; 962 temp.fs_open.ep_index = xfer->trIndex; 963 temp.fs_open.ep_no = ep_no; 964 965 if (stream_id != 0) { 966 temp.fs_open_stream.stream_id = stream_id; 967 968 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream)) 969 return (LIBUSB20_ERROR_INVALID_PARAM); 970 } else { 971 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open)) 972 return (LIBUSB20_ERROR_INVALID_PARAM); 973 } 974 /* maximums might have changed - update */ 975 xfer->maxFrames = temp.fs_open.max_frames; 976 977 /* "max_bufsize" should be multiple of "max_packet_length" */ 978 xfer->maxTotalLength = temp.fs_open.max_bufsize; 979 xfer->maxPacketLen = temp.fs_open.max_packet_length; 980 981 /* setup buffer and length lists using zero copy */ 982 fsep->ppBuffer = xfer->ppBuffer; 983 fsep->pLength = xfer->pLength; 984 985 return (0); /* success */ 986 } 987 988 static int 989 ugen20_tr_close(struct libusb20_transfer *xfer) 990 { 991 struct usb_fs_close temp; 992 993 memset(&temp, 0, sizeof(temp)); 994 995 temp.ep_index = xfer->trIndex; 996 997 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) { 998 return (LIBUSB20_ERROR_INVALID_PARAM); 999 } 1000 return (0); /* success */ 1001 } 1002 1003 static int 1004 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 1005 { 1006 struct usb_fs_clear_stall_sync temp; 1007 1008 memset(&temp, 0, sizeof(temp)); 1009 1010 /* if the transfer is active, an error will be returned */ 1011 1012 temp.ep_index = xfer->trIndex; 1013 1014 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) { 1015 return (LIBUSB20_ERROR_INVALID_PARAM); 1016 } 1017 return (0); /* success */ 1018 } 1019 1020 static void 1021 ugen20_tr_submit(struct libusb20_transfer *xfer) 1022 { 1023 struct usb_fs_start temp; 1024 struct usb_fs_endpoint *fsep; 1025 1026 memset(&temp, 0, sizeof(temp)); 1027 1028 fsep = xfer->pdev->privBeData; 1029 fsep += xfer->trIndex; 1030 1031 fsep->nFrames = xfer->nFrames; 1032 fsep->flags = 0; 1033 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 1034 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 1035 } 1036 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 1037 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 1038 } 1039 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 1040 fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 1041 } 1042 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 1043 fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 1044 } 1045 /* NOTE: The "fsep->timeout" variable is 16-bit. */ 1046 if (xfer->timeout > 65535) 1047 fsep->timeout = 65535; 1048 else 1049 fsep->timeout = xfer->timeout; 1050 1051 temp.ep_index = xfer->trIndex; 1052 1053 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) { 1054 /* ignore any errors - should never happen */ 1055 } 1056 return; /* success */ 1057 } 1058 1059 static void 1060 ugen20_tr_cancel_async(struct libusb20_transfer *xfer) 1061 { 1062 struct usb_fs_stop temp; 1063 1064 memset(&temp, 0, sizeof(temp)); 1065 1066 temp.ep_index = xfer->trIndex; 1067 1068 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) { 1069 /* ignore any errors - should never happen */ 1070 } 1071 return; 1072 } 1073 1074 static int 1075 ugen20_be_ioctl(struct libusb20_be_ctx *pctx, uint32_t cmd, void *data) 1076 { 1077 int f; 1078 int error; 1079 1080 f = pctx->ctrl_fd; 1081 if (f < 0) 1082 return (LIBUSB20_ERROR_OTHER); 1083 error = ioctl(f, cmd, data); 1084 if (error == -1) { 1085 if (errno == EPERM) { 1086 error = LIBUSB20_ERROR_ACCESS; 1087 } else { 1088 error = LIBUSB20_ERROR_OTHER; 1089 } 1090 } 1091 return (error); 1092 } 1093 1094 static int 1095 ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 1096 uint8_t iface_index, char *buf, uint8_t len) 1097 { 1098 struct usb_gen_descriptor ugd; 1099 1100 memset(&ugd, 0, sizeof(ugd)); 1101 1102 ugd.ugd_data = buf; 1103 ugd.ugd_maxlen = len; 1104 ugd.ugd_iface_index = iface_index; 1105 1106 if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) { 1107 return (LIBUSB20_ERROR_INVALID_PARAM); 1108 } 1109 return (0); 1110 } 1111 1112 static int 1113 ugen20_dev_get_info(struct libusb20_device *pdev, 1114 struct usb_device_info *pinfo) 1115 { 1116 if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) { 1117 return (LIBUSB20_ERROR_INVALID_PARAM); 1118 } 1119 return (0); 1120 } 1121 1122 static int 1123 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 1124 uint16_t quirk_index, struct libusb20_quirk *pq) 1125 { 1126 struct usb_gen_quirk q; 1127 int error; 1128 1129 memset(&q, 0, sizeof(q)); 1130 1131 q.index = quirk_index; 1132 1133 error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_DEV_QUIRK_GET), &q); 1134 1135 if (error) { 1136 if (errno == EINVAL) { 1137 return (LIBUSB20_ERROR_NOT_FOUND); 1138 } 1139 } else { 1140 pq->vid = q.vid; 1141 pq->pid = q.pid; 1142 pq->bcdDeviceLow = q.bcdDeviceLow; 1143 pq->bcdDeviceHigh = q.bcdDeviceHigh; 1144 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1145 } 1146 return (error); 1147 } 1148 1149 static int 1150 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 1151 struct libusb20_quirk *pq) 1152 { 1153 struct usb_gen_quirk q; 1154 int error; 1155 1156 memset(&q, 0, sizeof(q)); 1157 1158 q.index = quirk_index; 1159 1160 error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_QUIRK_NAME_GET), &q); 1161 1162 if (error) { 1163 if (errno == EINVAL) { 1164 return (LIBUSB20_ERROR_NOT_FOUND); 1165 } 1166 } else { 1167 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1168 } 1169 return (error); 1170 } 1171 1172 static int 1173 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 1174 struct libusb20_quirk *pq) 1175 { 1176 struct usb_gen_quirk q; 1177 int error; 1178 1179 memset(&q, 0, sizeof(q)); 1180 1181 q.vid = pq->vid; 1182 q.pid = pq->pid; 1183 q.bcdDeviceLow = pq->bcdDeviceLow; 1184 q.bcdDeviceHigh = pq->bcdDeviceHigh; 1185 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1186 1187 error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_DEV_QUIRK_ADD), &q); 1188 if (error) { 1189 if (errno == ENOMEM) { 1190 return (LIBUSB20_ERROR_NO_MEM); 1191 } 1192 } 1193 return (error); 1194 } 1195 1196 static int 1197 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 1198 struct libusb20_quirk *pq) 1199 { 1200 struct usb_gen_quirk q; 1201 int error; 1202 1203 memset(&q, 0, sizeof(q)); 1204 1205 q.vid = pq->vid; 1206 q.pid = pq->pid; 1207 q.bcdDeviceLow = pq->bcdDeviceLow; 1208 q.bcdDeviceHigh = pq->bcdDeviceHigh; 1209 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1210 1211 error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_DEV_QUIRK_REMOVE), &q); 1212 if (error) { 1213 if (errno == EINVAL) { 1214 return (LIBUSB20_ERROR_NOT_FOUND); 1215 } 1216 } 1217 return (error); 1218 } 1219 1220 static int 1221 ugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1222 { 1223 return (ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_SET_TEMPLATE), &temp)); 1224 } 1225 1226 static int 1227 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1228 { 1229 return (ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_GET_TEMPLATE), ptemp)); 1230 } 1231