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_port_path_t ugen20_get_port_path; 83 static libusb20_get_power_usage_t ugen20_get_power_usage; 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 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 error = 0; 223 done: 224 close(f); 225 return (error); 226 } 227 228 struct ugen20_urd_state { 229 struct usb_read_dir urd; 230 uint32_t nparsed; 231 int f; 232 uint8_t *ptr; 233 const char *src; 234 const char *dst; 235 uint8_t buf[256]; 236 uint8_t dummy_zero[1]; 237 }; 238 239 static int 240 ugen20_readdir(struct ugen20_urd_state *st) 241 { 242 ; /* style fix */ 243 repeat: 244 if (st->ptr == NULL) { 245 st->urd.urd_startentry += st->nparsed; 246 st->urd.urd_data = libusb20_pass_ptr(st->buf); 247 st->urd.urd_maxlen = sizeof(st->buf); 248 st->nparsed = 0; 249 250 if (ioctl(st->f, IOUSB(USB_READ_DIR), &st->urd)) { 251 return (EINVAL); 252 } 253 st->ptr = st->buf; 254 } 255 if (st->ptr[0] == 0) { 256 if (st->nparsed) { 257 st->ptr = NULL; 258 goto repeat; 259 } else { 260 return (ENXIO); 261 } 262 } 263 st->src = (void *)(st->ptr + 1); 264 st->dst = st->src + strlen(st->src) + 1; 265 st->ptr = st->ptr + st->ptr[0]; 266 st->nparsed++; 267 268 if ((st->ptr < st->buf) || 269 (st->ptr > st->dummy_zero)) { 270 /* invalid entry */ 271 return (EINVAL); 272 } 273 return (0); 274 } 275 276 static int 277 ugen20_init_backend(struct libusb20_backend *pbe) 278 { 279 struct ugen20_urd_state state; 280 struct libusb20_device *pdev; 281 282 memset(&state, 0, sizeof(state)); 283 284 state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 285 if (state.f < 0) 286 return (LIBUSB20_ERROR_OTHER); 287 288 while (ugen20_readdir(&state) == 0) { 289 290 if ((state.src[0] != 'u') || 291 (state.src[1] != 'g') || 292 (state.src[2] != 'e') || 293 (state.src[3] != 'n')) { 294 continue; 295 } 296 pdev = libusb20_dev_alloc(); 297 if (pdev == NULL) { 298 continue; 299 } 300 if (ugen20_enumerate(pdev, state.src + 4)) { 301 libusb20_dev_free(pdev); 302 continue; 303 } 304 /* put the device on the backend list */ 305 libusb20_be_enqueue_device(pbe, pdev); 306 } 307 close(state.f); 308 return (0); /* success */ 309 } 310 311 static void 312 ugen20_tr_release(struct libusb20_device *pdev) 313 { 314 struct usb_fs_uninit fs_uninit; 315 316 if (pdev->nTransfer == 0) { 317 return; 318 } 319 /* release all pending USB transfers */ 320 if (pdev->privBeData != NULL) { 321 memset(&fs_uninit, 0, sizeof(fs_uninit)); 322 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 323 /* ignore any errors of this kind */ 324 } 325 } 326 return; 327 } 328 329 static int 330 ugen20_tr_renew(struct libusb20_device *pdev) 331 { 332 struct usb_fs_init fs_init; 333 struct usb_fs_endpoint *pfse; 334 int error; 335 uint32_t size; 336 uint16_t nMaxTransfer; 337 338 nMaxTransfer = pdev->nTransfer; 339 error = 0; 340 341 if (nMaxTransfer == 0) { 342 goto done; 343 } 344 size = nMaxTransfer * sizeof(*pfse); 345 346 if (pdev->privBeData == NULL) { 347 pfse = malloc(size); 348 if (pfse == NULL) { 349 error = LIBUSB20_ERROR_NO_MEM; 350 goto done; 351 } 352 pdev->privBeData = pfse; 353 } 354 /* reset endpoint data */ 355 memset(pdev->privBeData, 0, size); 356 357 memset(&fs_init, 0, sizeof(fs_init)); 358 359 fs_init.pEndpoints = libusb20_pass_ptr(pdev->privBeData); 360 fs_init.ep_index_max = nMaxTransfer; 361 362 if (ioctl(pdev->file, IOUSB(USB_FS_INIT), &fs_init)) { 363 error = LIBUSB20_ERROR_OTHER; 364 goto done; 365 } 366 done: 367 return (error); 368 } 369 370 static int 371 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer) 372 { 373 uint32_t plugtime; 374 char buf[64]; 375 int f; 376 int g; 377 int error; 378 379 snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u", 380 pdev->bus_number, pdev->device_address); 381 382 /* 383 * We need two file handles, one for the control endpoint and one 384 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised 385 * kernel locking. 386 */ 387 g = open(buf, O_RDWR); 388 if (g < 0) { 389 return (LIBUSB20_ERROR_NO_DEVICE); 390 } 391 f = open(buf, O_RDWR); 392 if (f < 0) { 393 close(g); 394 return (LIBUSB20_ERROR_NO_DEVICE); 395 } 396 if (ioctl(f, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 397 error = LIBUSB20_ERROR_OTHER; 398 goto done; 399 } 400 /* check that the correct device is still plugged */ 401 if (pdev->session_data.plugtime != plugtime) { 402 error = LIBUSB20_ERROR_NO_DEVICE; 403 goto done; 404 } 405 /* need to set this before "tr_renew()" */ 406 pdev->file = f; 407 pdev->file_ctrl = g; 408 409 /* renew all USB transfers */ 410 error = ugen20_tr_renew(pdev); 411 if (error) { 412 goto done; 413 } 414 /* set methods */ 415 pdev->methods = &libusb20_ugen20_device_methods; 416 417 done: 418 if (error) { 419 if (pdev->privBeData) { 420 /* cleanup after "tr_renew()" */ 421 free(pdev->privBeData); 422 pdev->privBeData = NULL; 423 } 424 pdev->file = -1; 425 pdev->file_ctrl = -1; 426 close(f); 427 close(g); 428 } 429 return (error); 430 } 431 432 static int 433 ugen20_close_device(struct libusb20_device *pdev) 434 { 435 struct usb_fs_uninit fs_uninit; 436 437 if (pdev->privBeData) { 438 memset(&fs_uninit, 0, sizeof(fs_uninit)); 439 if (ioctl(pdev->file, IOUSB(USB_FS_UNINIT), &fs_uninit)) { 440 /* ignore this error */ 441 } 442 free(pdev->privBeData); 443 } 444 pdev->nTransfer = 0; 445 pdev->privBeData = NULL; 446 close(pdev->file); 447 close(pdev->file_ctrl); 448 pdev->file = -1; 449 pdev->file_ctrl = -1; 450 return (0); /* success */ 451 } 452 453 static void 454 ugen20_exit_backend(struct libusb20_backend *pbe) 455 { 456 return; /* nothing to do */ 457 } 458 459 static int 460 ugen20_get_config_desc_full(struct libusb20_device *pdev, 461 uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index) 462 { 463 struct usb_gen_descriptor gen_desc; 464 struct usb_config_descriptor cdesc; 465 uint8_t *ptr; 466 uint16_t len; 467 int error; 468 469 /* make sure memory is initialised */ 470 memset(&cdesc, 0, sizeof(cdesc)); 471 memset(&gen_desc, 0, sizeof(gen_desc)); 472 473 gen_desc.ugd_data = libusb20_pass_ptr(&cdesc); 474 gen_desc.ugd_maxlen = sizeof(cdesc); 475 gen_desc.ugd_config_index = cfg_index; 476 477 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 478 if (error) { 479 return (LIBUSB20_ERROR_OTHER); 480 } 481 len = UGETW(cdesc.wTotalLength); 482 if (len < sizeof(cdesc)) { 483 /* corrupt descriptor */ 484 return (LIBUSB20_ERROR_OTHER); 485 } 486 ptr = malloc(len); 487 if (!ptr) { 488 return (LIBUSB20_ERROR_NO_MEM); 489 } 490 491 /* make sure memory is initialised */ 492 memset(ptr, 0, len); 493 494 gen_desc.ugd_data = libusb20_pass_ptr(ptr); 495 gen_desc.ugd_maxlen = len; 496 497 error = ioctl(pdev->file_ctrl, IOUSB(USB_GET_FULL_DESC), &gen_desc); 498 if (error) { 499 free(ptr); 500 return (LIBUSB20_ERROR_OTHER); 501 } 502 /* make sure that the device doesn't fool us */ 503 memcpy(ptr, &cdesc, sizeof(cdesc)); 504 505 *ppbuf = ptr; 506 *plen = len; 507 508 return (0); /* success */ 509 } 510 511 static int 512 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex) 513 { 514 int temp; 515 516 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_CONFIG), &temp)) { 517 return (LIBUSB20_ERROR_OTHER); 518 } 519 *pindex = temp; 520 521 return (0); 522 } 523 524 static int 525 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index) 526 { 527 int temp = cfg_index; 528 529 /* release all active USB transfers */ 530 ugen20_tr_release(pdev); 531 532 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_CONFIG), &temp)) { 533 return (LIBUSB20_ERROR_OTHER); 534 } 535 return (ugen20_tr_renew(pdev)); 536 } 537 538 static int 539 ugen20_set_alt_index(struct libusb20_device *pdev, 540 uint8_t iface_index, uint8_t alt_index) 541 { 542 struct usb_alt_interface alt_iface; 543 544 memset(&alt_iface, 0, sizeof(alt_iface)); 545 546 alt_iface.uai_interface_index = iface_index; 547 alt_iface.uai_alt_index = alt_index; 548 549 /* release all active USB transfers */ 550 ugen20_tr_release(pdev); 551 552 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_ALTINTERFACE), &alt_iface)) { 553 return (LIBUSB20_ERROR_OTHER); 554 } 555 return (ugen20_tr_renew(pdev)); 556 } 557 558 static int 559 ugen20_reset_device(struct libusb20_device *pdev) 560 { 561 int temp = 0; 562 563 /* release all active USB transfers */ 564 ugen20_tr_release(pdev); 565 566 if (ioctl(pdev->file_ctrl, IOUSB(USB_DEVICEENUMERATE), &temp)) { 567 return (LIBUSB20_ERROR_OTHER); 568 } 569 return (ugen20_tr_renew(pdev)); 570 } 571 572 static int 573 ugen20_check_connected(struct libusb20_device *pdev) 574 { 575 uint32_t plugtime; 576 int error = 0; 577 578 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_PLUGTIME), &plugtime)) { 579 error = LIBUSB20_ERROR_NO_DEVICE; 580 goto done; 581 } 582 583 if (pdev->session_data.plugtime != plugtime) { 584 error = LIBUSB20_ERROR_NO_DEVICE; 585 goto done; 586 } 587 done: 588 return (error); 589 } 590 591 static int 592 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode) 593 { 594 int temp; 595 596 switch (power_mode) { 597 case LIBUSB20_POWER_OFF: 598 temp = USB_POWER_MODE_OFF; 599 break; 600 case LIBUSB20_POWER_ON: 601 temp = USB_POWER_MODE_ON; 602 break; 603 case LIBUSB20_POWER_SAVE: 604 temp = USB_POWER_MODE_SAVE; 605 break; 606 case LIBUSB20_POWER_SUSPEND: 607 temp = USB_POWER_MODE_SUSPEND; 608 break; 609 case LIBUSB20_POWER_RESUME: 610 temp = USB_POWER_MODE_RESUME; 611 break; 612 default: 613 return (LIBUSB20_ERROR_INVALID_PARAM); 614 } 615 if (ioctl(pdev->file_ctrl, IOUSB(USB_SET_POWER_MODE), &temp)) { 616 return (LIBUSB20_ERROR_OTHER); 617 } 618 return (0); 619 } 620 621 static int 622 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode) 623 { 624 int temp; 625 626 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_MODE), &temp)) { 627 return (LIBUSB20_ERROR_OTHER); 628 } 629 switch (temp) { 630 case USB_POWER_MODE_OFF: 631 temp = LIBUSB20_POWER_OFF; 632 break; 633 case USB_POWER_MODE_ON: 634 temp = LIBUSB20_POWER_ON; 635 break; 636 case USB_POWER_MODE_SAVE: 637 temp = LIBUSB20_POWER_SAVE; 638 break; 639 case USB_POWER_MODE_SUSPEND: 640 temp = LIBUSB20_POWER_SUSPEND; 641 break; 642 case USB_POWER_MODE_RESUME: 643 temp = LIBUSB20_POWER_RESUME; 644 break; 645 default: 646 temp = LIBUSB20_POWER_ON; 647 break; 648 } 649 *power_mode = temp; 650 return (0); /* success */ 651 } 652 653 static int 654 ugen20_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize) 655 { 656 struct usb_device_port_path udpp; 657 658 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_DEV_PORT_PATH), &udpp)) 659 return (LIBUSB20_ERROR_OTHER); 660 661 if (udpp.udp_port_level > bufsize) 662 return (LIBUSB20_ERROR_OVERFLOW); 663 664 memcpy(buf, udpp.udp_port_no, udpp.udp_port_level); 665 666 return (udpp.udp_port_level); /* success */ 667 } 668 669 static int 670 ugen20_get_power_usage(struct libusb20_device *pdev, uint16_t *power_usage) 671 { 672 int temp; 673 674 if (ioctl(pdev->file_ctrl, IOUSB(USB_GET_POWER_USAGE), &temp)) { 675 return (LIBUSB20_ERROR_OTHER); 676 } 677 *power_usage = temp; 678 return (0); /* success */ 679 } 680 681 static int 682 ugen20_kernel_driver_active(struct libusb20_device *pdev, 683 uint8_t iface_index) 684 { 685 int temp = iface_index; 686 687 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_ACTIVE), &temp)) { 688 return (LIBUSB20_ERROR_OTHER); 689 } 690 return (0); /* kernel driver is active */ 691 } 692 693 static int 694 ugen20_detach_kernel_driver(struct libusb20_device *pdev, 695 uint8_t iface_index) 696 { 697 int temp = iface_index; 698 699 if (ioctl(pdev->file_ctrl, IOUSB(USB_IFACE_DRIVER_DETACH), &temp)) { 700 return (LIBUSB20_ERROR_OTHER); 701 } 702 return (0); /* kernel driver is detached */ 703 } 704 705 static int 706 ugen20_do_request_sync(struct libusb20_device *pdev, 707 struct LIBUSB20_CONTROL_SETUP_DECODED *setup, 708 void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags) 709 { 710 struct usb_ctl_request req; 711 712 memset(&req, 0, sizeof(req)); 713 714 req.ucr_data = libusb20_pass_ptr(data); 715 if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 716 req.ucr_flags |= USB_SHORT_XFER_OK; 717 } 718 if (libusb20_me_encode(&req.ucr_request, 719 sizeof(req.ucr_request), setup)) { 720 /* ignore */ 721 } 722 if (ioctl(pdev->file_ctrl, IOUSB(USB_DO_REQUEST), &req)) { 723 return (LIBUSB20_ERROR_OTHER); 724 } 725 if (pactlen) { 726 /* get actual length */ 727 *pactlen = req.ucr_actlen; 728 } 729 return (0); /* request was successful */ 730 } 731 732 static int 733 ugen20_process(struct libusb20_device *pdev) 734 { 735 struct usb_fs_complete temp; 736 struct usb_fs_endpoint *fsep; 737 struct libusb20_transfer *xfer; 738 739 while (1) { 740 741 if (ioctl(pdev->file, IOUSB(USB_FS_COMPLETE), &temp)) { 742 if (errno == EBUSY) { 743 break; 744 } else { 745 /* device detached */ 746 return (LIBUSB20_ERROR_OTHER); 747 } 748 } 749 fsep = pdev->privBeData; 750 xfer = pdev->pTransfer; 751 fsep += temp.ep_index; 752 xfer += temp.ep_index; 753 754 /* update transfer status */ 755 756 if (fsep->status == 0) { 757 xfer->aFrames = fsep->aFrames; 758 xfer->timeComplete = fsep->isoc_time_complete; 759 xfer->status = LIBUSB20_TRANSFER_COMPLETED; 760 } else if (fsep->status == USB_ERR_CANCELLED) { 761 xfer->aFrames = 0; 762 xfer->timeComplete = 0; 763 xfer->status = LIBUSB20_TRANSFER_CANCELLED; 764 } else if (fsep->status == USB_ERR_STALLED) { 765 xfer->aFrames = 0; 766 xfer->timeComplete = 0; 767 xfer->status = LIBUSB20_TRANSFER_STALL; 768 } else if (fsep->status == USB_ERR_TIMEOUT) { 769 xfer->aFrames = 0; 770 xfer->timeComplete = 0; 771 xfer->status = LIBUSB20_TRANSFER_TIMED_OUT; 772 } else { 773 xfer->aFrames = 0; 774 xfer->timeComplete = 0; 775 xfer->status = LIBUSB20_TRANSFER_ERROR; 776 } 777 libusb20_tr_callback_wrapper(xfer); 778 } 779 return (0); /* done */ 780 } 781 782 static int 783 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, 784 uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id, 785 uint8_t pre_scale) 786 { 787 union { 788 struct usb_fs_open fs_open; 789 struct usb_fs_open_stream fs_open_stream; 790 } temp; 791 struct usb_fs_endpoint *fsep; 792 793 if (pre_scale) 794 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; 795 796 memset(&temp, 0, sizeof(temp)); 797 798 fsep = xfer->pdev->privBeData; 799 fsep += xfer->trIndex; 800 801 temp.fs_open.max_bufsize = MaxBufSize; 802 temp.fs_open.max_frames = MaxFrameCount; 803 temp.fs_open.ep_index = xfer->trIndex; 804 temp.fs_open.ep_no = ep_no; 805 806 if (stream_id != 0) { 807 temp.fs_open_stream.stream_id = stream_id; 808 809 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN_STREAM), &temp.fs_open_stream)) 810 return (LIBUSB20_ERROR_INVALID_PARAM); 811 } else { 812 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_OPEN), &temp.fs_open)) 813 return (LIBUSB20_ERROR_INVALID_PARAM); 814 } 815 /* maximums might have changed - update */ 816 xfer->maxFrames = temp.fs_open.max_frames; 817 818 /* "max_bufsize" should be multiple of "max_packet_length" */ 819 xfer->maxTotalLength = temp.fs_open.max_bufsize; 820 xfer->maxPacketLen = temp.fs_open.max_packet_length; 821 822 /* setup buffer and length lists using zero copy */ 823 fsep->ppBuffer = libusb20_pass_ptr(xfer->ppBuffer); 824 fsep->pLength = libusb20_pass_ptr(xfer->pLength); 825 826 return (0); /* success */ 827 } 828 829 static int 830 ugen20_tr_close(struct libusb20_transfer *xfer) 831 { 832 struct usb_fs_close temp; 833 834 memset(&temp, 0, sizeof(temp)); 835 836 temp.ep_index = xfer->trIndex; 837 838 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLOSE), &temp)) { 839 return (LIBUSB20_ERROR_INVALID_PARAM); 840 } 841 return (0); /* success */ 842 } 843 844 static int 845 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer) 846 { 847 struct usb_fs_clear_stall_sync temp; 848 849 memset(&temp, 0, sizeof(temp)); 850 851 /* if the transfer is active, an error will be returned */ 852 853 temp.ep_index = xfer->trIndex; 854 855 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_CLEAR_STALL_SYNC), &temp)) { 856 return (LIBUSB20_ERROR_INVALID_PARAM); 857 } 858 return (0); /* success */ 859 } 860 861 static void 862 ugen20_tr_submit(struct libusb20_transfer *xfer) 863 { 864 struct usb_fs_start temp; 865 struct usb_fs_endpoint *fsep; 866 867 memset(&temp, 0, sizeof(temp)); 868 869 fsep = xfer->pdev->privBeData; 870 fsep += xfer->trIndex; 871 872 fsep->nFrames = xfer->nFrames; 873 fsep->flags = 0; 874 if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) { 875 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK; 876 } 877 if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) { 878 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK; 879 } 880 if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) { 881 fsep->flags |= USB_FS_FLAG_FORCE_SHORT; 882 } 883 if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) { 884 fsep->flags |= USB_FS_FLAG_CLEAR_STALL; 885 } 886 /* NOTE: The "fsep->timeout" variable is 16-bit. */ 887 if (xfer->timeout > 65535) 888 fsep->timeout = 65535; 889 else 890 fsep->timeout = xfer->timeout; 891 892 temp.ep_index = xfer->trIndex; 893 894 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_START), &temp)) { 895 /* ignore any errors - should never happen */ 896 } 897 return; /* success */ 898 } 899 900 static void 901 ugen20_tr_cancel_async(struct libusb20_transfer *xfer) 902 { 903 struct usb_fs_stop temp; 904 905 memset(&temp, 0, sizeof(temp)); 906 907 temp.ep_index = xfer->trIndex; 908 909 if (ioctl(xfer->pdev->file, IOUSB(USB_FS_STOP), &temp)) { 910 /* ignore any errors - should never happen */ 911 } 912 return; 913 } 914 915 static int 916 ugen20_be_ioctl(uint32_t cmd, void *data) 917 { 918 int f; 919 int error; 920 921 f = open("/dev/" USB_DEVICE_NAME, O_RDONLY); 922 if (f < 0) 923 return (LIBUSB20_ERROR_OTHER); 924 error = ioctl(f, cmd, data); 925 if (error == -1) { 926 if (errno == EPERM) { 927 error = LIBUSB20_ERROR_ACCESS; 928 } else { 929 error = LIBUSB20_ERROR_OTHER; 930 } 931 } 932 close(f); 933 return (error); 934 } 935 936 static int 937 ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 938 uint8_t iface_index, char *buf, uint8_t len) 939 { 940 struct usb_gen_descriptor ugd; 941 942 memset(&ugd, 0, sizeof(ugd)); 943 944 ugd.ugd_data = libusb20_pass_ptr(buf); 945 ugd.ugd_maxlen = len; 946 ugd.ugd_iface_index = iface_index; 947 948 if (ioctl(pdev->file, IOUSB(USB_GET_IFACE_DRIVER), &ugd)) { 949 return (LIBUSB20_ERROR_INVALID_PARAM); 950 } 951 return (0); 952 } 953 954 static int 955 ugen20_dev_get_info(struct libusb20_device *pdev, 956 struct usb_device_info *pinfo) 957 { 958 if (ioctl(pdev->file, IOUSB(USB_GET_DEVICEINFO), pinfo)) { 959 return (LIBUSB20_ERROR_INVALID_PARAM); 960 } 961 return (0); 962 } 963 964 static int 965 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe, 966 uint16_t quirk_index, struct libusb20_quirk *pq) 967 { 968 struct usb_gen_quirk q; 969 int error; 970 971 memset(&q, 0, sizeof(q)); 972 973 q.index = quirk_index; 974 975 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q); 976 977 if (error) { 978 if (errno == EINVAL) { 979 return (LIBUSB20_ERROR_NOT_FOUND); 980 } 981 } else { 982 pq->vid = q.vid; 983 pq->pid = q.pid; 984 pq->bcdDeviceLow = q.bcdDeviceLow; 985 pq->bcdDeviceHigh = q.bcdDeviceHigh; 986 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 987 } 988 return (error); 989 } 990 991 static int 992 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index, 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.index = quirk_index; 1001 1002 error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q); 1003 1004 if (error) { 1005 if (errno == EINVAL) { 1006 return (LIBUSB20_ERROR_NOT_FOUND); 1007 } 1008 } else { 1009 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname)); 1010 } 1011 return (error); 1012 } 1013 1014 static int 1015 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe, 1016 struct libusb20_quirk *pq) 1017 { 1018 struct usb_gen_quirk q; 1019 int error; 1020 1021 memset(&q, 0, sizeof(q)); 1022 1023 q.vid = pq->vid; 1024 q.pid = pq->pid; 1025 q.bcdDeviceLow = pq->bcdDeviceLow; 1026 q.bcdDeviceHigh = pq->bcdDeviceHigh; 1027 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1028 1029 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q); 1030 if (error) { 1031 if (errno == ENOMEM) { 1032 return (LIBUSB20_ERROR_NO_MEM); 1033 } 1034 } 1035 return (error); 1036 } 1037 1038 static int 1039 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe, 1040 struct libusb20_quirk *pq) 1041 { 1042 struct usb_gen_quirk q; 1043 int error; 1044 1045 memset(&q, 0, sizeof(q)); 1046 1047 q.vid = pq->vid; 1048 q.pid = pq->pid; 1049 q.bcdDeviceLow = pq->bcdDeviceLow; 1050 q.bcdDeviceHigh = pq->bcdDeviceHigh; 1051 strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname)); 1052 1053 error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q); 1054 if (error) { 1055 if (errno == EINVAL) { 1056 return (LIBUSB20_ERROR_NOT_FOUND); 1057 } 1058 } 1059 return (error); 1060 } 1061 1062 static int 1063 ugen20_root_set_template(struct libusb20_backend *pbe, int temp) 1064 { 1065 return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp)); 1066 } 1067 1068 static int 1069 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp) 1070 { 1071 return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp)); 1072 } 1073