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