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