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