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