18c8fff31SAndrew Thompson /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35e53a4f9SPedro F. Giffuni * 48c8fff31SAndrew Thompson * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 54c6bcffdSHans Petter Selasky * Copyright (c) 2009-2023 Hans Petter Selasky 68c8fff31SAndrew Thompson * 78c8fff31SAndrew Thompson * Redistribution and use in source and binary forms, with or without 88c8fff31SAndrew Thompson * modification, are permitted provided that the following conditions 98c8fff31SAndrew Thompson * are met: 108c8fff31SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 118c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer. 128c8fff31SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 138c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 148c8fff31SAndrew Thompson * documentation and/or other materials provided with the distribution. 158c8fff31SAndrew Thompson * 168c8fff31SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 178c8fff31SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188c8fff31SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198c8fff31SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 208c8fff31SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 218c8fff31SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228c8fff31SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 238c8fff31SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 248c8fff31SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258c8fff31SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268c8fff31SAndrew Thompson * SUCH DAMAGE. 278c8fff31SAndrew Thompson */ 288c8fff31SAndrew Thompson 2966194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE 3066194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE 3166194130SHans Petter Selasky #else 32ac840bfcSWojciech A. Koszek #include <assert.h> 33f3cba95cSWojciech A. Koszek #include <errno.h> 348c8fff31SAndrew Thompson #include <poll.h> 358c8fff31SAndrew Thompson #include <pthread.h> 36d94d94e2SHans Petter Selasky #include <signal.h> 37f3cba95cSWojciech A. Koszek #include <stdio.h> 38f3cba95cSWojciech A. Koszek #include <stdlib.h> 3966194130SHans Petter Selasky #include <string.h> 40f3cba95cSWojciech A. Koszek #include <unistd.h> 4166194130SHans Petter Selasky #include <time.h> 4266194130SHans Petter Selasky #include <sys/fcntl.h> 4366194130SHans Petter Selasky #include <sys/ioctl.h> 4466194130SHans Petter Selasky #include <sys/queue.h> 4566194130SHans Petter Selasky #include <sys/endian.h> 4666194130SHans Petter Selasky #endif 478c8fff31SAndrew Thompson 489c087c5aSAndrew Thompson #define libusb_device_handle libusb20_device 499c087c5aSAndrew Thompson 508c8fff31SAndrew Thompson #include "libusb20.h" 518c8fff31SAndrew Thompson #include "libusb20_desc.h" 528c8fff31SAndrew Thompson #include "libusb20_int.h" 538c8fff31SAndrew Thompson #include "libusb.h" 548c8fff31SAndrew Thompson #include "libusb10.h" 558c8fff31SAndrew Thompson 5690988efdSHans Petter Selasky #define LIBUSB_NUM_SW_ENDPOINTS (16 * 4) 5790988efdSHans Petter Selasky 588c8fff31SAndrew Thompson static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 598c8fff31SAndrew Thompson struct libusb_context *usbi_default_context = NULL; 60390065b1SAlfred Perlstein 61390065b1SAlfred Perlstein /* Prototypes */ 62390065b1SAlfred Perlstein 63390065b1SAlfred Perlstein static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 64390065b1SAlfred Perlstein static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 65390065b1SAlfred Perlstein static int libusb10_convert_error(uint8_t status); 66390065b1SAlfred Perlstein static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 67390065b1SAlfred Perlstein static void libusb10_isoc_proxy(struct libusb20_transfer *); 68390065b1SAlfred Perlstein static void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 69390065b1SAlfred Perlstein static void libusb10_ctrl_proxy(struct libusb20_transfer *); 70390065b1SAlfred Perlstein static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 718c8fff31SAndrew Thompson 728c8fff31SAndrew Thompson /* Library initialisation / deinitialisation */ 738c8fff31SAndrew Thompson 7414b896ceSHans Petter Selasky static const struct libusb_version libusb_version = { 7514b896ceSHans Petter Selasky .major = 1, 7614b896ceSHans Petter Selasky .minor = 0, 7714b896ceSHans Petter Selasky .micro = 0, 7814b896ceSHans Petter Selasky .nano = 2016, 7914b896ceSHans Petter Selasky .rc = "", 80a2aef24aSEitan Adler .describe = "https://www.freebsd.org" 8114b896ceSHans Petter Selasky }; 8214b896ceSHans Petter Selasky 8314b896ceSHans Petter Selasky const struct libusb_version * 8414b896ceSHans Petter Selasky libusb_get_version(void) 8514b896ceSHans Petter Selasky { 8614b896ceSHans Petter Selasky 8714b896ceSHans Petter Selasky return (&libusb_version); 8814b896ceSHans Petter Selasky } 8914b896ceSHans Petter Selasky 908c8fff31SAndrew Thompson void 918c8fff31SAndrew Thompson libusb_set_debug(libusb_context *ctx, int level) 928c8fff31SAndrew Thompson { 93390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 948495fa08SKyle Evans /* debug_fixed is set when the environment overrides libusb_set_debug */ 958495fa08SKyle Evans if (ctx && ctx->debug_fixed == 0) 968c8fff31SAndrew Thompson ctx->debug = level; 978c8fff31SAndrew Thompson } 988c8fff31SAndrew Thompson 99698e791aSHans Petter Selasky static void 100698e791aSHans Petter Selasky libusb_set_nonblocking(int f) 101698e791aSHans Petter Selasky { 102698e791aSHans Petter Selasky int flags; 103698e791aSHans Petter Selasky 104698e791aSHans Petter Selasky /* 105698e791aSHans Petter Selasky * We ignore any failures in this function, hence the 106698e791aSHans Petter Selasky * non-blocking flag is not critical to the operation of 107698e791aSHans Petter Selasky * libUSB. We use F_GETFL and F_SETFL to be compatible with 108698e791aSHans Petter Selasky * Linux. 109698e791aSHans Petter Selasky */ 110698e791aSHans Petter Selasky 111698e791aSHans Petter Selasky flags = fcntl(f, F_GETFL, NULL); 112698e791aSHans Petter Selasky if (flags == -1) 113698e791aSHans Petter Selasky return; 114698e791aSHans Petter Selasky flags |= O_NONBLOCK; 115698e791aSHans Petter Selasky fcntl(f, F_SETFL, flags); 116698e791aSHans Petter Selasky } 117698e791aSHans Petter Selasky 118aa87aa52SHans Petter Selasky void 119aa87aa52SHans Petter Selasky libusb_interrupt_event_handler(libusb_context *ctx) 120540c7229SHans Petter Selasky { 121aa87aa52SHans Petter Selasky uint8_t dummy; 122540c7229SHans Petter Selasky int err; 123540c7229SHans Petter Selasky 124aa87aa52SHans Petter Selasky if (ctx == NULL) 125aa87aa52SHans Petter Selasky return; 126aa87aa52SHans Petter Selasky 127aa87aa52SHans Petter Selasky dummy = 0; 128540c7229SHans Petter Selasky err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 129540c7229SHans Petter Selasky if (err < (int)sizeof(dummy)) { 130540c7229SHans Petter Selasky /* ignore error, if any */ 131540c7229SHans Petter Selasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "Waking up event loop failed!"); 132540c7229SHans Petter Selasky } 133540c7229SHans Petter Selasky } 134540c7229SHans Petter Selasky 1358c8fff31SAndrew Thompson int 1368c8fff31SAndrew Thompson libusb_init(libusb_context **context) 1378c8fff31SAndrew Thompson { 1384c6bcffdSHans Petter Selasky return (libusb_init_context(context, NULL, 0)); 1394c6bcffdSHans Petter Selasky } 1404c6bcffdSHans Petter Selasky 1414c6bcffdSHans Petter Selasky int 1424c6bcffdSHans Petter Selasky libusb_init_context(libusb_context **context, 1434c6bcffdSHans Petter Selasky const struct libusb_init_option option[], int num_options) 1444c6bcffdSHans Petter Selasky { 1458c8fff31SAndrew Thompson struct libusb_context *ctx; 146f7287225SHans Petter Selasky pthread_condattr_t attr; 1478495fa08SKyle Evans char *debug, *ep; 1488c8fff31SAndrew Thompson int ret; 1498c8fff31SAndrew Thompson 1504c6bcffdSHans Petter Selasky if (num_options < 0) 1514c6bcffdSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 1524c6bcffdSHans Petter Selasky 1538c8fff31SAndrew Thompson ctx = malloc(sizeof(*ctx)); 1548c8fff31SAndrew Thompson if (!ctx) 1558c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1568c8fff31SAndrew Thompson 1578c8fff31SAndrew Thompson memset(ctx, 0, sizeof(*ctx)); 158*9dc96d8bSBaptiste Daroussin ctx->devd_pipe = -1; 1598c8fff31SAndrew Thompson 1608c8fff31SAndrew Thompson debug = getenv("LIBUSB_DEBUG"); 1618c8fff31SAndrew Thompson if (debug != NULL) { 1628495fa08SKyle Evans /* 1634c6bcffdSHans Petter Selasky * If LIBUSB_DEBUG is set, we'll honor that first and 1644c6bcffdSHans Petter Selasky * use it to override any future libusb_set_debug() 1654c6bcffdSHans Petter Selasky * calls or init options. 1668495fa08SKyle Evans */ 1678495fa08SKyle Evans errno = 0; 1688495fa08SKyle Evans ctx->debug = strtol(debug, &ep, 10); 1698495fa08SKyle Evans if (errno == 0 && *ep == '\0') { 1708c8fff31SAndrew Thompson ctx->debug_fixed = 1; 1718495fa08SKyle Evans } else { 1728495fa08SKyle Evans /* 1738495fa08SKyle Evans * LIBUSB_DEBUG conversion failed for some reason, but 1748495fa08SKyle Evans * we don't care about the specifics all that much. We 1758495fa08SKyle Evans * can't use it either way. Force it to the default, 1768495fa08SKyle Evans * 0, in case we had a partial number. 1778495fa08SKyle Evans */ 1788495fa08SKyle Evans ctx->debug = 0; 1798495fa08SKyle Evans } 1804c6bcffdSHans Petter Selasky } else { 1814c6bcffdSHans Petter Selasky /* 1824c6bcffdSHans Petter Selasky * If the LIBUSB_OPTION_LOG_LEVEL is set, honor that. 1834c6bcffdSHans Petter Selasky */ 1844c6bcffdSHans Petter Selasky for (int i = 0; i != num_options; i++) { 1854c6bcffdSHans Petter Selasky if (option[i].option != LIBUSB_OPTION_LOG_LEVEL) 1864c6bcffdSHans Petter Selasky continue; 1874c6bcffdSHans Petter Selasky 1884c6bcffdSHans Petter Selasky ctx->debug = (int)option[i].value.ival; 1894c6bcffdSHans Petter Selasky if ((int64_t)ctx->debug == option[i].value.ival) { 1904c6bcffdSHans Petter Selasky ctx->debug_fixed = 1; 1914c6bcffdSHans Petter Selasky } else { 1924c6bcffdSHans Petter Selasky free(ctx); 1934c6bcffdSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 1948c8fff31SAndrew Thompson } 1954c6bcffdSHans Petter Selasky } 1964c6bcffdSHans Petter Selasky } 1974c6bcffdSHans Petter Selasky 198c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->pollfds); 199390065b1SAlfred Perlstein TAILQ_INIT(&ctx->tr_done); 2007bdc064bSHans Petter Selasky TAILQ_INIT(&ctx->hotplug_cbh); 2017bdc064bSHans Petter Selasky TAILQ_INIT(&ctx->hotplug_devs); 202390065b1SAlfred Perlstein 203f7287225SHans Petter Selasky if (pthread_mutex_init(&ctx->ctx_lock, NULL) != 0) { 204f7287225SHans Petter Selasky free(ctx); 205f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 206f7287225SHans Petter Selasky } 2077bdc064bSHans Petter Selasky if (pthread_mutex_init(&ctx->hotplug_lock, NULL) != 0) { 2087bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 2097bdc064bSHans Petter Selasky free(ctx); 2107bdc064bSHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 2117bdc064bSHans Petter Selasky } 212f7287225SHans Petter Selasky if (pthread_condattr_init(&attr) != 0) { 213f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 2147bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 215f7287225SHans Petter Selasky free(ctx); 216f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 217f7287225SHans Petter Selasky } 218f7287225SHans Petter Selasky if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) { 219f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 2207bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 221f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 222f7287225SHans Petter Selasky free(ctx); 223f7287225SHans Petter Selasky return (LIBUSB_ERROR_OTHER); 224f7287225SHans Petter Selasky } 225f7287225SHans Petter Selasky if (pthread_cond_init(&ctx->ctx_cond, &attr) != 0) { 226f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 2277bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 228f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 229f7287225SHans Petter Selasky free(ctx); 230f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 231f7287225SHans Petter Selasky } 232f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 233390065b1SAlfred Perlstein 234390065b1SAlfred Perlstein ctx->ctx_handler = NO_THREAD; 2357bdc064bSHans Petter Selasky ctx->hotplug_handler = NO_THREAD; 2368c8fff31SAndrew Thompson 2378c8fff31SAndrew Thompson ret = pipe(ctx->ctrl_pipe); 2388c8fff31SAndrew Thompson if (ret < 0) { 239390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 2407bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 241390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 2428c8fff31SAndrew Thompson free(ctx); 2438c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 2448c8fff31SAndrew Thompson } 245390065b1SAlfred Perlstein /* set non-blocking mode on the control pipe to avoid deadlock */ 246698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[0]); 247698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[1]); 2488c8fff31SAndrew Thompson 249390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 2508c8fff31SAndrew Thompson 2518c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 2528c8fff31SAndrew Thompson if (usbi_default_context == NULL) { 2538c8fff31SAndrew Thompson usbi_default_context = ctx; 2548c8fff31SAndrew Thompson } 2558c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 2568c8fff31SAndrew Thompson 2578c8fff31SAndrew Thompson if (context) 2588c8fff31SAndrew Thompson *context = ctx; 2598c8fff31SAndrew Thompson 260390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 261390065b1SAlfred Perlstein 262d94d94e2SHans Petter Selasky signal(SIGPIPE, SIG_IGN); 263d94d94e2SHans Petter Selasky 2648c8fff31SAndrew Thompson return (0); 2658c8fff31SAndrew Thompson } 2668c8fff31SAndrew Thompson 2678c8fff31SAndrew Thompson void 2688c8fff31SAndrew Thompson libusb_exit(libusb_context *ctx) 2698c8fff31SAndrew Thompson { 270390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 2718c8fff31SAndrew Thompson 272390065b1SAlfred Perlstein if (ctx == NULL) 273390065b1SAlfred Perlstein return; 274390065b1SAlfred Perlstein 2757bdc064bSHans Petter Selasky /* stop hotplug thread, if any */ 2767bdc064bSHans Petter Selasky 2777bdc064bSHans Petter Selasky if (ctx->hotplug_handler != NO_THREAD) { 2787bdc064bSHans Petter Selasky pthread_t td; 2797bdc064bSHans Petter Selasky void *ptr; 2807bdc064bSHans Petter Selasky 2817bdc064bSHans Petter Selasky HOTPLUG_LOCK(ctx); 2827bdc064bSHans Petter Selasky td = ctx->hotplug_handler; 2837bdc064bSHans Petter Selasky ctx->hotplug_handler = NO_THREAD; 284*9dc96d8bSBaptiste Daroussin if (ctx->usb_event_mode == usb_event_devd) { 285*9dc96d8bSBaptiste Daroussin close(ctx->devd_pipe); 286*9dc96d8bSBaptiste Daroussin ctx->devd_pipe = -1; 287*9dc96d8bSBaptiste Daroussin } else if (ctx->usb_event_mode == usb_event_netlink) { 288*9dc96d8bSBaptiste Daroussin close(ctx->ss.fd); 289*9dc96d8bSBaptiste Daroussin ctx->ss.fd = -1; 290*9dc96d8bSBaptiste Daroussin } 2917bdc064bSHans Petter Selasky HOTPLUG_UNLOCK(ctx); 2927bdc064bSHans Petter Selasky 2937bdc064bSHans Petter Selasky pthread_join(td, &ptr); 2947bdc064bSHans Petter Selasky } 2957bdc064bSHans Petter Selasky 296390065b1SAlfred Perlstein /* XXX cleanup devices */ 297390065b1SAlfred Perlstein 298390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 2998c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 3008c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 301390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 3027bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 303390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 3048c8fff31SAndrew Thompson 3058c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 3068c8fff31SAndrew Thompson if (ctx == usbi_default_context) { 3078c8fff31SAndrew Thompson usbi_default_context = NULL; 3088c8fff31SAndrew Thompson } 3098c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 3108c8fff31SAndrew Thompson 3118c8fff31SAndrew Thompson free(ctx); 3128c8fff31SAndrew Thompson } 3138c8fff31SAndrew Thompson 3148c8fff31SAndrew Thompson /* Device handling and initialisation. */ 3158c8fff31SAndrew Thompson 3168c8fff31SAndrew Thompson ssize_t 3178c8fff31SAndrew Thompson libusb_get_device_list(libusb_context *ctx, libusb_device ***list) 3188c8fff31SAndrew Thompson { 3198c8fff31SAndrew Thompson struct libusb20_backend *usb_backend; 320390065b1SAlfred Perlstein struct libusb20_device *pdev; 321390065b1SAlfred Perlstein struct libusb_device *dev; 3228c8fff31SAndrew Thompson int i; 3238c8fff31SAndrew Thompson 324390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 325390065b1SAlfred Perlstein 326390065b1SAlfred Perlstein if (ctx == NULL) 327390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 328390065b1SAlfred Perlstein 329390065b1SAlfred Perlstein if (list == NULL) 330390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 3318c8fff31SAndrew Thompson 3328c8fff31SAndrew Thompson usb_backend = libusb20_be_alloc_default(); 3338c8fff31SAndrew Thompson if (usb_backend == NULL) 334390065b1SAlfred Perlstein return (LIBUSB_ERROR_NO_MEM); 3358c8fff31SAndrew Thompson 336390065b1SAlfred Perlstein /* figure out how many USB devices are present */ 3378c8fff31SAndrew Thompson pdev = NULL; 3388c8fff31SAndrew Thompson i = 0; 3398c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 3408c8fff31SAndrew Thompson i++; 3418c8fff31SAndrew Thompson 342390065b1SAlfred Perlstein /* allocate device pointer list */ 3438c8fff31SAndrew Thompson *list = malloc((i + 1) * sizeof(void *)); 3448c8fff31SAndrew Thompson if (*list == NULL) { 3458c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 3468c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3478c8fff31SAndrew Thompson } 348390065b1SAlfred Perlstein /* create libusb v1.0 compliant devices */ 3498c8fff31SAndrew Thompson i = 0; 3508c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 3518c8fff31SAndrew Thompson 3528c8fff31SAndrew Thompson dev = malloc(sizeof(*dev)); 3538c8fff31SAndrew Thompson if (dev == NULL) { 354c500e4ddSAndrew Thompson while (i != 0) { 355c500e4ddSAndrew Thompson libusb_unref_device((*list)[i - 1]); 356c500e4ddSAndrew Thompson i--; 357c500e4ddSAndrew Thompson } 3588c8fff31SAndrew Thompson free(*list); 359390065b1SAlfred Perlstein *list = NULL; 3608c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 3618c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3628c8fff31SAndrew Thompson } 363ccef4ddfSAndrew Thompson /* get device into libUSB v1.0 list */ 364ccef4ddfSAndrew Thompson libusb20_be_dequeue_device(usb_backend, pdev); 365ccef4ddfSAndrew Thompson 3668c8fff31SAndrew Thompson memset(dev, 0, sizeof(*dev)); 3678c8fff31SAndrew Thompson 368390065b1SAlfred Perlstein /* init transfer queues */ 369390065b1SAlfred Perlstein TAILQ_INIT(&dev->tr_head); 370390065b1SAlfred Perlstein 371390065b1SAlfred Perlstein /* set context we belong to */ 3728c8fff31SAndrew Thompson dev->ctx = ctx; 3738c8fff31SAndrew Thompson 3748c8fff31SAndrew Thompson /* link together the two structures */ 3758c8fff31SAndrew Thompson dev->os_priv = pdev; 376390065b1SAlfred Perlstein pdev->privLuData = dev; 3778c8fff31SAndrew Thompson 3788c8fff31SAndrew Thompson (*list)[i] = libusb_ref_device(dev); 3798c8fff31SAndrew Thompson i++; 3808c8fff31SAndrew Thompson } 3818c8fff31SAndrew Thompson (*list)[i] = NULL; 3828c8fff31SAndrew Thompson 3838c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 3848c8fff31SAndrew Thompson return (i); 3858c8fff31SAndrew Thompson } 3868c8fff31SAndrew Thompson 3878c8fff31SAndrew Thompson void 3888c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices) 3898c8fff31SAndrew Thompson { 3908c8fff31SAndrew Thompson int i; 3918c8fff31SAndrew Thompson 3928c8fff31SAndrew Thompson if (list == NULL) 393390065b1SAlfred Perlstein return; /* be NULL safe */ 3948c8fff31SAndrew Thompson 3958c8fff31SAndrew Thompson if (unref_devices) { 3968c8fff31SAndrew Thompson for (i = 0; list[i] != NULL; i++) 3978c8fff31SAndrew Thompson libusb_unref_device(list[i]); 3988c8fff31SAndrew Thompson } 3998c8fff31SAndrew Thompson free(list); 4008c8fff31SAndrew Thompson } 4018c8fff31SAndrew Thompson 4028c8fff31SAndrew Thompson uint8_t 4038c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device *dev) 4048c8fff31SAndrew Thompson { 4058c8fff31SAndrew Thompson if (dev == NULL) 406390065b1SAlfred Perlstein return (0); /* should not happen */ 407390065b1SAlfred Perlstein return (libusb20_dev_get_bus_number(dev->os_priv)); 4088c8fff31SAndrew Thompson } 4098c8fff31SAndrew Thompson 4100f2c7066SHans Petter Selasky uint8_t 4110f2c7066SHans Petter Selasky libusb_get_port_number(libusb_device *dev) 4120f2c7066SHans Petter Selasky { 4130f2c7066SHans Petter Selasky if (dev == NULL) 4140f2c7066SHans Petter Selasky return (0); /* should not happen */ 4150f2c7066SHans Petter Selasky return (libusb20_dev_get_parent_port(dev->os_priv)); 4160f2c7066SHans Petter Selasky } 4170f2c7066SHans Petter Selasky 4185906bf49SEd Maste int 419a9205626SEd Maste libusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize) 420a9205626SEd Maste { 421a9205626SEd Maste return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize)); 422a9205626SEd Maste } 423a9205626SEd Maste 424a9205626SEd Maste int 4255906bf49SEd Maste libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t *buf, 4265906bf49SEd Maste uint8_t bufsize) 4275906bf49SEd Maste { 4285906bf49SEd Maste return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize)); 4295906bf49SEd Maste } 4305906bf49SEd Maste 4318c8fff31SAndrew Thompson uint8_t 4328c8fff31SAndrew Thompson libusb_get_device_address(libusb_device *dev) 4338c8fff31SAndrew Thompson { 4348c8fff31SAndrew Thompson if (dev == NULL) 435390065b1SAlfred Perlstein return (0); /* should not happen */ 436390065b1SAlfred Perlstein return (libusb20_dev_get_address(dev->os_priv)); 4378c8fff31SAndrew Thompson } 4388c8fff31SAndrew Thompson 4399a46d467SHans Petter Selasky enum libusb_speed 4409a46d467SHans Petter Selasky libusb_get_device_speed(libusb_device *dev) 4419a46d467SHans Petter Selasky { 4429a46d467SHans Petter Selasky if (dev == NULL) 44333ec9f0cSHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); /* should not happen */ 4449a46d467SHans Petter Selasky 4459a46d467SHans Petter Selasky switch (libusb20_dev_get_speed(dev->os_priv)) { 4469a46d467SHans Petter Selasky case LIBUSB20_SPEED_LOW: 4479a46d467SHans Petter Selasky return (LIBUSB_SPEED_LOW); 4489a46d467SHans Petter Selasky case LIBUSB20_SPEED_FULL: 4499a46d467SHans Petter Selasky return (LIBUSB_SPEED_FULL); 4509a46d467SHans Petter Selasky case LIBUSB20_SPEED_HIGH: 4519a46d467SHans Petter Selasky return (LIBUSB_SPEED_HIGH); 4529a46d467SHans Petter Selasky case LIBUSB20_SPEED_SUPER: 4539a46d467SHans Petter Selasky return (LIBUSB_SPEED_SUPER); 4549a46d467SHans Petter Selasky default: 4559a46d467SHans Petter Selasky break; 4569a46d467SHans Petter Selasky } 4579a46d467SHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); 4589a46d467SHans Petter Selasky } 4599a46d467SHans Petter Selasky 4608c8fff31SAndrew Thompson int 461390065b1SAlfred Perlstein libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 4628c8fff31SAndrew Thompson { 4638c8fff31SAndrew Thompson struct libusb_config_descriptor *pdconf; 4648c8fff31SAndrew Thompson struct libusb_interface *pinf; 4658c8fff31SAndrew Thompson struct libusb_interface_descriptor *pdinf; 4668c8fff31SAndrew Thompson struct libusb_endpoint_descriptor *pdend; 467390065b1SAlfred Perlstein int i; 468390065b1SAlfred Perlstein int j; 469390065b1SAlfred Perlstein int k; 470390065b1SAlfred Perlstein int ret; 4718c8fff31SAndrew Thompson 4728c8fff31SAndrew Thompson if (dev == NULL) 4738c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 4748c8fff31SAndrew Thompson 475390065b1SAlfred Perlstein ret = libusb_get_active_config_descriptor(dev, &pdconf); 476390065b1SAlfred Perlstein if (ret < 0) 477390065b1SAlfred Perlstein return (ret); 4788c8fff31SAndrew Thompson 4798c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 4808c8fff31SAndrew Thompson for (i = 0; i < pdconf->bNumInterfaces; i++) { 4818c8fff31SAndrew Thompson pinf = &pdconf->interface[i]; 4828c8fff31SAndrew Thompson for (j = 0; j < pinf->num_altsetting; j++) { 4838c8fff31SAndrew Thompson pdinf = &pinf->altsetting[j]; 4848c8fff31SAndrew Thompson for (k = 0; k < pdinf->bNumEndpoints; k++) { 4858c8fff31SAndrew Thompson pdend = &pdinf->endpoint[k]; 4868c8fff31SAndrew Thompson if (pdend->bEndpointAddress == endpoint) { 4878c8fff31SAndrew Thompson ret = pdend->wMaxPacketSize; 4888c8fff31SAndrew Thompson goto out; 4898c8fff31SAndrew Thompson } 4908c8fff31SAndrew Thompson } 4918c8fff31SAndrew Thompson } 4928c8fff31SAndrew Thompson } 4938c8fff31SAndrew Thompson 4948c8fff31SAndrew Thompson out: 4958c8fff31SAndrew Thompson libusb_free_config_descriptor(pdconf); 4968c8fff31SAndrew Thompson return (ret); 4978c8fff31SAndrew Thompson } 4988c8fff31SAndrew Thompson 499748205a3SHans Petter Selasky int 500748205a3SHans Petter Selasky libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint) 501748205a3SHans Petter Selasky { 502748205a3SHans Petter Selasky int multiplier; 503748205a3SHans Petter Selasky int ret; 504748205a3SHans Petter Selasky 505748205a3SHans Petter Selasky ret = libusb_get_max_packet_size(dev, endpoint); 506748205a3SHans Petter Selasky 507748205a3SHans Petter Selasky switch (libusb20_dev_get_speed(dev->os_priv)) { 508748205a3SHans Petter Selasky case LIBUSB20_SPEED_LOW: 509748205a3SHans Petter Selasky case LIBUSB20_SPEED_FULL: 510748205a3SHans Petter Selasky break; 511748205a3SHans Petter Selasky default: 512748205a3SHans Petter Selasky if (ret > -1) { 513748205a3SHans Petter Selasky multiplier = (1 + ((ret >> 11) & 3)); 514748205a3SHans Petter Selasky if (multiplier > 3) 515748205a3SHans Petter Selasky multiplier = 3; 516748205a3SHans Petter Selasky ret = (ret & 0x7FF) * multiplier; 517748205a3SHans Petter Selasky } 518748205a3SHans Petter Selasky break; 519748205a3SHans Petter Selasky } 520748205a3SHans Petter Selasky return (ret); 521748205a3SHans Petter Selasky } 522748205a3SHans Petter Selasky 5238c8fff31SAndrew Thompson libusb_device * 5248c8fff31SAndrew Thompson libusb_ref_device(libusb_device *dev) 5258c8fff31SAndrew Thompson { 5268c8fff31SAndrew Thompson if (dev == NULL) 527390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 5288c8fff31SAndrew Thompson 529390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 5308c8fff31SAndrew Thompson dev->refcnt++; 531390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 5328c8fff31SAndrew Thompson 5338c8fff31SAndrew Thompson return (dev); 5348c8fff31SAndrew Thompson } 5358c8fff31SAndrew Thompson 5368c8fff31SAndrew Thompson void 5378c8fff31SAndrew Thompson libusb_unref_device(libusb_device *dev) 5388c8fff31SAndrew Thompson { 5398c8fff31SAndrew Thompson if (dev == NULL) 540390065b1SAlfred Perlstein return; /* be NULL safe */ 5418c8fff31SAndrew Thompson 542390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 5438c8fff31SAndrew Thompson dev->refcnt--; 544390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 5458c8fff31SAndrew Thompson 5468c8fff31SAndrew Thompson if (dev->refcnt == 0) { 5478c8fff31SAndrew Thompson libusb20_dev_free(dev->os_priv); 5488c8fff31SAndrew Thompson free(dev); 5498c8fff31SAndrew Thompson } 5508c8fff31SAndrew Thompson } 5518c8fff31SAndrew Thompson 5528c8fff31SAndrew Thompson int 5538c8fff31SAndrew Thompson libusb_open(libusb_device *dev, libusb_device_handle **devh) 5548c8fff31SAndrew Thompson { 5558c8fff31SAndrew Thompson libusb_context *ctx = dev->ctx; 5568c8fff31SAndrew Thompson struct libusb20_device *pdev = dev->os_priv; 5578c8fff31SAndrew Thompson int err; 5588c8fff31SAndrew Thompson 5598c8fff31SAndrew Thompson if (devh == NULL) 5608c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5618c8fff31SAndrew Thompson 562390065b1SAlfred Perlstein /* set default device handle value */ 563390065b1SAlfred Perlstein *devh = NULL; 564390065b1SAlfred Perlstein 565390065b1SAlfred Perlstein dev = libusb_ref_device(dev); 566390065b1SAlfred Perlstein if (dev == NULL) 567390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 5688c8fff31SAndrew Thompson 56990988efdSHans Petter Selasky err = libusb20_dev_open(pdev, LIBUSB_NUM_SW_ENDPOINTS); 5708c8fff31SAndrew Thompson if (err) { 571390065b1SAlfred Perlstein libusb_unref_device(dev); 5728c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 5738c8fff31SAndrew Thompson } 5746847ea50SHans Petter Selasky 5756847ea50SHans Petter Selasky /* 5766847ea50SHans Petter Selasky * Clear the device gone flag, in case the device was opened 5776847ea50SHans Petter Selasky * after a re-attach, to allow new transaction: 5786847ea50SHans Petter Selasky */ 5796847ea50SHans Petter Selasky CTX_LOCK(ctx); 5806847ea50SHans Petter Selasky dev->device_is_gone = 0; 5816847ea50SHans Petter Selasky CTX_UNLOCK(ctx); 5826847ea50SHans Petter Selasky 583390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 5848c8fff31SAndrew Thompson POLLOUT | POLLRDNORM | POLLWRNORM); 5858c8fff31SAndrew Thompson 586390065b1SAlfred Perlstein /* make sure our event loop detects the new device */ 587aa87aa52SHans Petter Selasky libusb_interrupt_event_handler(ctx); 588540c7229SHans Petter Selasky 589390065b1SAlfred Perlstein *devh = pdev; 5908c8fff31SAndrew Thompson 5918c8fff31SAndrew Thompson return (0); 5928c8fff31SAndrew Thompson } 5938c8fff31SAndrew Thompson 5948c8fff31SAndrew Thompson libusb_device_handle * 5958c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 5968c8fff31SAndrew Thompson uint16_t product_id) 5978c8fff31SAndrew Thompson { 5988c8fff31SAndrew Thompson struct libusb_device **devs; 5998c8fff31SAndrew Thompson struct libusb20_device *pdev; 6008c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 601390065b1SAlfred Perlstein int i; 602390065b1SAlfred Perlstein int j; 6038c8fff31SAndrew Thompson 604390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 605390065b1SAlfred Perlstein if (ctx == NULL) 606390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 607390065b1SAlfred Perlstein 6081efeb40dSHans Petter Selasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid enter"); 6098c8fff31SAndrew Thompson 6108c8fff31SAndrew Thompson if ((i = libusb_get_device_list(ctx, &devs)) < 0) 6118c8fff31SAndrew Thompson return (NULL); 6128c8fff31SAndrew Thompson 6133f709d07SHans Petter Selasky pdev = NULL; 6148c8fff31SAndrew Thompson for (j = 0; j < i; j++) { 6153f709d07SHans Petter Selasky struct libusb20_device *tdev; 6163f709d07SHans Petter Selasky 6173f709d07SHans Petter Selasky tdev = devs[j]->os_priv; 6183f709d07SHans Petter Selasky pdesc = libusb20_dev_get_device_desc(tdev); 619390065b1SAlfred Perlstein /* 620390065b1SAlfred Perlstein * NOTE: The USB library will automatically swap the 621390065b1SAlfred Perlstein * fields in the device descriptor to be of host 622390065b1SAlfred Perlstein * endian type! 623390065b1SAlfred Perlstein */ 6248c8fff31SAndrew Thompson if (pdesc->idVendor == vendor_id && 625c500e4ddSAndrew Thompson pdesc->idProduct == product_id) { 626dc934803SHans Petter Selasky libusb_open(devs[j], &pdev); 627c500e4ddSAndrew Thompson break; 628c500e4ddSAndrew Thompson } 6298c8fff31SAndrew Thompson } 6308c8fff31SAndrew Thompson 6318c8fff31SAndrew Thompson libusb_free_device_list(devs, 1); 6321efeb40dSHans Petter Selasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid leave"); 633390065b1SAlfred Perlstein return (pdev); 6348c8fff31SAndrew Thompson } 6358c8fff31SAndrew Thompson 6368c8fff31SAndrew Thompson void 637390065b1SAlfred Perlstein libusb_close(struct libusb20_device *pdev) 6388c8fff31SAndrew Thompson { 6398c8fff31SAndrew Thompson libusb_context *ctx; 640390065b1SAlfred Perlstein struct libusb_device *dev; 6418c8fff31SAndrew Thompson 642390065b1SAlfred Perlstein if (pdev == NULL) 643390065b1SAlfred Perlstein return; /* be NULL safe */ 6448c8fff31SAndrew Thompson 645390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 646390065b1SAlfred Perlstein ctx = dev->ctx; 6478c8fff31SAndrew Thompson 648390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &dev->dev_poll); 6498c8fff31SAndrew Thompson 650390065b1SAlfred Perlstein libusb20_dev_close(pdev); 651ccef4ddfSAndrew Thompson 652ccef4ddfSAndrew Thompson /* unref will free the "pdev" when the refcount reaches zero */ 653390065b1SAlfred Perlstein libusb_unref_device(dev); 6548c8fff31SAndrew Thompson 655390065b1SAlfred Perlstein /* make sure our event loop detects the closed device */ 656aa87aa52SHans Petter Selasky libusb_interrupt_event_handler(ctx); 6578c8fff31SAndrew Thompson } 6588c8fff31SAndrew Thompson 6598c8fff31SAndrew Thompson libusb_device * 660390065b1SAlfred Perlstein libusb_get_device(struct libusb20_device *pdev) 6618c8fff31SAndrew Thompson { 662390065b1SAlfred Perlstein if (pdev == NULL) 6638c8fff31SAndrew Thompson return (NULL); 664390065b1SAlfred Perlstein return ((libusb_device *)pdev->privLuData); 6658c8fff31SAndrew Thompson } 6668c8fff31SAndrew Thompson 6678c8fff31SAndrew Thompson int 668390065b1SAlfred Perlstein libusb_get_configuration(struct libusb20_device *pdev, int *config) 6698c8fff31SAndrew Thompson { 670390065b1SAlfred Perlstein struct libusb20_config *pconf; 6718c8fff31SAndrew Thompson 672390065b1SAlfred Perlstein if (pdev == NULL || config == NULL) 6738c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6748c8fff31SAndrew Thompson 675390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 676390065b1SAlfred Perlstein if (pconf == NULL) 677c500e4ddSAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 6788c8fff31SAndrew Thompson 679390065b1SAlfred Perlstein *config = pconf->desc.bConfigurationValue; 6808c8fff31SAndrew Thompson 681390065b1SAlfred Perlstein free(pconf); 6828c8fff31SAndrew Thompson 6838c8fff31SAndrew Thompson return (0); 6848c8fff31SAndrew Thompson } 6858c8fff31SAndrew Thompson 6868c8fff31SAndrew Thompson int 687390065b1SAlfred Perlstein libusb_set_configuration(struct libusb20_device *pdev, int configuration) 6888c8fff31SAndrew Thompson { 689390065b1SAlfred Perlstein struct libusb20_config *pconf; 690390065b1SAlfred Perlstein struct libusb_device *dev; 691390065b1SAlfred Perlstein int err; 692390065b1SAlfred Perlstein uint8_t i; 6938c8fff31SAndrew Thompson 694390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 6958c8fff31SAndrew Thompson if (dev == NULL) 696390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 697390065b1SAlfred Perlstein 698390065b1SAlfred Perlstein if (configuration < 1) { 699390065b1SAlfred Perlstein /* unconfigure */ 700390065b1SAlfred Perlstein i = 255; 701390065b1SAlfred Perlstein } else { 702390065b1SAlfred Perlstein for (i = 0; i != 255; i++) { 703390065b1SAlfred Perlstein uint8_t found; 704390065b1SAlfred Perlstein 705390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, i); 706390065b1SAlfred Perlstein if (pconf == NULL) 707390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 708390065b1SAlfred Perlstein found = (pconf->desc.bConfigurationValue 709390065b1SAlfred Perlstein == configuration); 710390065b1SAlfred Perlstein free(pconf); 711390065b1SAlfred Perlstein 712390065b1SAlfred Perlstein if (found) 713390065b1SAlfred Perlstein goto set_config; 714390065b1SAlfred Perlstein } 715390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 716390065b1SAlfred Perlstein } 717390065b1SAlfred Perlstein 718390065b1SAlfred Perlstein set_config: 719390065b1SAlfred Perlstein 720390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 721390065b1SAlfred Perlstein 722390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 723390065b1SAlfred Perlstein 724390065b1SAlfred Perlstein err = libusb20_dev_set_config_index(pdev, i); 725390065b1SAlfred Perlstein 726390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 727390065b1SAlfred Perlstein POLLOUT | POLLRDNORM | POLLWRNORM); 728390065b1SAlfred Perlstein 729390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 730390065b1SAlfred Perlstein } 731390065b1SAlfred Perlstein 732390065b1SAlfred Perlstein int 733390065b1SAlfred Perlstein libusb_claim_interface(struct libusb20_device *pdev, int interface_number) 734390065b1SAlfred Perlstein { 735390065b1SAlfred Perlstein libusb_device *dev; 7365b40d960SHans Petter Selasky int err = 0; 737390065b1SAlfred Perlstein 738390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 739390065b1SAlfred Perlstein if (dev == NULL) 740390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 741390065b1SAlfred Perlstein 742390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 743390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 744390065b1SAlfred Perlstein 7455b40d960SHans Petter Selasky if (pdev->auto_detach != 0) { 7465b40d960SHans Petter Selasky err = libusb_detach_kernel_driver(pdev, interface_number); 7475b40d960SHans Petter Selasky if (err != 0) 7485b40d960SHans Petter Selasky goto done; 7495b40d960SHans Petter Selasky } 7505b40d960SHans Petter Selasky 751390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 752390065b1SAlfred Perlstein dev->claimed_interfaces |= (1 << interface_number); 753390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 7545b40d960SHans Petter Selasky done: 7555b40d960SHans Petter Selasky return (err); 756390065b1SAlfred Perlstein } 757390065b1SAlfred Perlstein 758390065b1SAlfred Perlstein int 759390065b1SAlfred Perlstein libusb_release_interface(struct libusb20_device *pdev, int interface_number) 760390065b1SAlfred Perlstein { 761390065b1SAlfred Perlstein libusb_device *dev; 762390065b1SAlfred Perlstein int err = 0; 763390065b1SAlfred Perlstein 764390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 765390065b1SAlfred Perlstein if (dev == NULL) 766390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 767390065b1SAlfred Perlstein 768390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 769390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 770390065b1SAlfred Perlstein 7715b40d960SHans Petter Selasky if (pdev->auto_detach != 0) { 7725b40d960SHans Petter Selasky err = libusb_attach_kernel_driver(pdev, interface_number); 7735b40d960SHans Petter Selasky if (err != 0) 7745b40d960SHans Petter Selasky goto done; 7755b40d960SHans Petter Selasky } 7765b40d960SHans Petter Selasky 777390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 778390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 779390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 7805b40d960SHans Petter Selasky else 781390065b1SAlfred Perlstein dev->claimed_interfaces &= ~(1 << interface_number); 782390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 7835b40d960SHans Petter Selasky done: 784390065b1SAlfred Perlstein return (err); 785390065b1SAlfred Perlstein } 786390065b1SAlfred Perlstein 787390065b1SAlfred Perlstein int 788390065b1SAlfred Perlstein libusb_set_interface_alt_setting(struct libusb20_device *pdev, 789390065b1SAlfred Perlstein int interface_number, int alternate_setting) 790390065b1SAlfred Perlstein { 791390065b1SAlfred Perlstein libusb_device *dev; 792390065b1SAlfred Perlstein int err = 0; 793390065b1SAlfred Perlstein 794390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 795390065b1SAlfred Perlstein if (dev == NULL) 796390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 797390065b1SAlfred Perlstein 798390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 799390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 800390065b1SAlfred Perlstein 801390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 802390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 803390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 804390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 805390065b1SAlfred Perlstein 806390065b1SAlfred Perlstein if (err) 807390065b1SAlfred Perlstein return (err); 808390065b1SAlfred Perlstein 809390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 810390065b1SAlfred Perlstein 811390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 812390065b1SAlfred Perlstein 813390065b1SAlfred Perlstein err = libusb20_dev_set_alt_index(pdev, 814390065b1SAlfred Perlstein interface_number, alternate_setting); 815390065b1SAlfred Perlstein 816390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 817390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 818390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 819390065b1SAlfred Perlstein 820390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 821390065b1SAlfred Perlstein } 822390065b1SAlfred Perlstein 823390065b1SAlfred Perlstein static struct libusb20_transfer * 824390065b1SAlfred Perlstein libusb10_get_transfer(struct libusb20_device *pdev, 825d81535d1SHans Petter Selasky uint8_t endpoint, uint8_t xfer_index) 826390065b1SAlfred Perlstein { 827d81535d1SHans Petter Selasky xfer_index &= 1; /* double buffering */ 828390065b1SAlfred Perlstein 829d81535d1SHans Petter Selasky xfer_index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 830390065b1SAlfred Perlstein 831390065b1SAlfred Perlstein if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 832390065b1SAlfred Perlstein /* this is an IN endpoint */ 833d81535d1SHans Petter Selasky xfer_index |= 2; 834390065b1SAlfred Perlstein } 835d81535d1SHans Petter Selasky return (libusb20_tr_get_pointer(pdev, xfer_index)); 836390065b1SAlfred Perlstein } 837390065b1SAlfred Perlstein 838390065b1SAlfred Perlstein int 839390065b1SAlfred Perlstein libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 840390065b1SAlfred Perlstein { 841390065b1SAlfred Perlstein struct libusb20_transfer *xfer; 842390065b1SAlfred Perlstein struct libusb_device *dev; 843390065b1SAlfred Perlstein int err; 844390065b1SAlfred Perlstein 845390065b1SAlfred Perlstein xfer = libusb10_get_transfer(pdev, endpoint, 0); 846390065b1SAlfred Perlstein if (xfer == NULL) 847390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 848390065b1SAlfred Perlstein 849390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 850698e791aSHans Petter Selasky if (dev == NULL) 851698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 852390065b1SAlfred Perlstein 853390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 854a7e048a2SHans Petter Selasky err = libusb20_tr_open(xfer, 0, 1, endpoint); 855390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 856390065b1SAlfred Perlstein 857390065b1SAlfred Perlstein if (err != 0 && err != LIBUSB20_ERROR_BUSY) 858390065b1SAlfred Perlstein return (LIBUSB_ERROR_OTHER); 859390065b1SAlfred Perlstein 860390065b1SAlfred Perlstein libusb20_tr_clear_stall_sync(xfer); 861390065b1SAlfred Perlstein 862390065b1SAlfred Perlstein /* check if we opened the transfer */ 863390065b1SAlfred Perlstein if (err == 0) { 864390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 865390065b1SAlfred Perlstein libusb20_tr_close(xfer); 866390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 867390065b1SAlfred Perlstein } 868390065b1SAlfred Perlstein return (0); /* success */ 869390065b1SAlfred Perlstein } 870390065b1SAlfred Perlstein 871390065b1SAlfred Perlstein int 872390065b1SAlfred Perlstein libusb_reset_device(struct libusb20_device *pdev) 873390065b1SAlfred Perlstein { 874390065b1SAlfred Perlstein libusb_device *dev; 875390065b1SAlfred Perlstein int err; 876390065b1SAlfred Perlstein 877390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 878390065b1SAlfred Perlstein if (dev == NULL) 879698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 8808c8fff31SAndrew Thompson 881390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 882390065b1SAlfred Perlstein 883390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 884390065b1SAlfred Perlstein 885390065b1SAlfred Perlstein err = libusb20_dev_reset(pdev); 886390065b1SAlfred Perlstein 887390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 888390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 889390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 890390065b1SAlfred Perlstein 891390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 8928c8fff31SAndrew Thompson } 8938c8fff31SAndrew Thompson 8948c8fff31SAndrew Thompson int 895f1b5fa6eSHans Petter Selasky libusb_check_connected(struct libusb20_device *pdev) 896f1b5fa6eSHans Petter Selasky { 897f1b5fa6eSHans Petter Selasky libusb_device *dev; 898f1b5fa6eSHans Petter Selasky int err; 899f1b5fa6eSHans Petter Selasky 900f1b5fa6eSHans Petter Selasky dev = libusb_get_device(pdev); 901f1b5fa6eSHans Petter Selasky if (dev == NULL) 902f1b5fa6eSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 903f1b5fa6eSHans Petter Selasky 904f1b5fa6eSHans Petter Selasky err = libusb20_dev_check_connected(pdev); 905f1b5fa6eSHans Petter Selasky 906f1b5fa6eSHans Petter Selasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 907f1b5fa6eSHans Petter Selasky } 908f1b5fa6eSHans Petter Selasky 909f1b5fa6eSHans Petter Selasky int 910390065b1SAlfred Perlstein libusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 9118c8fff31SAndrew Thompson { 912390065b1SAlfred Perlstein if (pdev == NULL) 9138c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 9148c8fff31SAndrew Thompson 9154d2472aaSHans Petter Selasky if (libusb20_dev_kernel_driver_active(pdev, interface)) 9164d2472aaSHans Petter Selasky return (0); /* no kernel driver is active */ 9174d2472aaSHans Petter Selasky else 9184d2472aaSHans Petter Selasky return (1); /* kernel driver is active */ 9198c8fff31SAndrew Thompson } 9208c8fff31SAndrew Thompson 9218c8fff31SAndrew Thompson int 922698e791aSHans Petter Selasky libusb_get_driver_np(struct libusb20_device *pdev, int interface, 923698e791aSHans Petter Selasky char *name, int namelen) 924698e791aSHans Petter Selasky { 925698e791aSHans Petter Selasky return (libusb_get_driver(pdev, interface, name, namelen)); 926698e791aSHans Petter Selasky } 927698e791aSHans Petter Selasky 928698e791aSHans Petter Selasky int 929698e791aSHans Petter Selasky libusb_get_driver(struct libusb20_device *pdev, int interface, 930698e791aSHans Petter Selasky char *name, int namelen) 931698e791aSHans Petter Selasky { 932698e791aSHans Petter Selasky char *ptr; 933698e791aSHans Petter Selasky int err; 934698e791aSHans Petter Selasky 935698e791aSHans Petter Selasky if (pdev == NULL) 936698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 937698e791aSHans Petter Selasky if (namelen < 1) 938698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 9394eb5923dSHans Petter Selasky if (namelen > 255) 9404eb5923dSHans Petter Selasky namelen = 255; 941698e791aSHans Petter Selasky 942698e791aSHans Petter Selasky err = libusb20_dev_get_iface_desc( 943698e791aSHans Petter Selasky pdev, interface, name, namelen); 944698e791aSHans Petter Selasky 945698e791aSHans Petter Selasky if (err != 0) 946698e791aSHans Petter Selasky return (LIBUSB_ERROR_OTHER); 947698e791aSHans Petter Selasky 948698e791aSHans Petter Selasky /* we only want the driver name */ 949698e791aSHans Petter Selasky ptr = strstr(name, ":"); 950698e791aSHans Petter Selasky if (ptr != NULL) 951698e791aSHans Petter Selasky *ptr = 0; 952698e791aSHans Petter Selasky 953698e791aSHans Petter Selasky return (0); 954698e791aSHans Petter Selasky } 955698e791aSHans Petter Selasky 956698e791aSHans Petter Selasky int 957698e791aSHans Petter Selasky libusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface) 958698e791aSHans Petter Selasky { 959698e791aSHans Petter Selasky return (libusb_detach_kernel_driver(pdev, interface)); 960698e791aSHans Petter Selasky } 961698e791aSHans Petter Selasky 962698e791aSHans Petter Selasky int 963390065b1SAlfred Perlstein libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 9648c8fff31SAndrew Thompson { 965390065b1SAlfred Perlstein int err; 9668c8fff31SAndrew Thompson 967390065b1SAlfred Perlstein if (pdev == NULL) 9688c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 9698c8fff31SAndrew Thompson 970390065b1SAlfred Perlstein err = libusb20_dev_detach_kernel_driver( 971390065b1SAlfred Perlstein pdev, interface); 9728c8fff31SAndrew Thompson 973698e791aSHans Petter Selasky return (err ? LIBUSB_ERROR_OTHER : 0); 9748c8fff31SAndrew Thompson } 9758c8fff31SAndrew Thompson 9768c8fff31SAndrew Thompson int 977390065b1SAlfred Perlstein libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 9788c8fff31SAndrew Thompson { 979390065b1SAlfred Perlstein if (pdev == NULL) 9808c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 981390065b1SAlfred Perlstein /* stub - currently not supported by libusb20 */ 9828c8fff31SAndrew Thompson return (0); 9838c8fff31SAndrew Thompson } 9848c8fff31SAndrew Thompson 9855b40d960SHans Petter Selasky int 9865b40d960SHans Petter Selasky libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable) 9875b40d960SHans Petter Selasky { 9885b40d960SHans Petter Selasky dev->auto_detach = (enable ? 1 : 0); 989a3d81a8aSHans Petter Selasky return (0); 9905b40d960SHans Petter Selasky } 9915b40d960SHans Petter Selasky 9928c8fff31SAndrew Thompson /* Asynchronous device I/O */ 9938c8fff31SAndrew Thompson 9948c8fff31SAndrew Thompson struct libusb_transfer * 9958c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets) 9968c8fff31SAndrew Thompson { 997390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 998390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 9998c8fff31SAndrew Thompson int len; 10008c8fff31SAndrew Thompson 10018c8fff31SAndrew Thompson len = sizeof(struct libusb_transfer) + 1002390065b1SAlfred Perlstein sizeof(struct libusb_super_transfer) + 10038c8fff31SAndrew Thompson (iso_packets * sizeof(libusb_iso_packet_descriptor)); 10048c8fff31SAndrew Thompson 1005390065b1SAlfred Perlstein sxfer = malloc(len); 1006390065b1SAlfred Perlstein if (sxfer == NULL) 10078c8fff31SAndrew Thompson return (NULL); 10088c8fff31SAndrew Thompson 1009390065b1SAlfred Perlstein memset(sxfer, 0, len); 10108c8fff31SAndrew Thompson 1011390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1012390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 10138c8fff31SAndrew Thompson 1014390065b1SAlfred Perlstein /* set default value */ 1015390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 1016390065b1SAlfred Perlstein 1017390065b1SAlfred Perlstein return (uxfer); 10188c8fff31SAndrew Thompson } 10198c8fff31SAndrew Thompson 10208c8fff31SAndrew Thompson void 1021390065b1SAlfred Perlstein libusb_free_transfer(struct libusb_transfer *uxfer) 10228c8fff31SAndrew Thompson { 1023390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 10248c8fff31SAndrew Thompson 1025390065b1SAlfred Perlstein if (uxfer == NULL) 1026390065b1SAlfred Perlstein return; /* be NULL safe */ 10278c8fff31SAndrew Thompson 102831f7072cSHans Petter Selasky /* check if we should free the transfer buffer */ 102931f7072cSHans Petter Selasky if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) 103031f7072cSHans Petter Selasky free(uxfer->buffer); 103131f7072cSHans Petter Selasky 1032390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1033390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 10348c8fff31SAndrew Thompson 1035390065b1SAlfred Perlstein free(sxfer); 10368c8fff31SAndrew Thompson } 10378c8fff31SAndrew Thompson 10381c497368SHans Petter Selasky static uint32_t 1039390065b1SAlfred Perlstein libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 10408c8fff31SAndrew Thompson { 10411c497368SHans Petter Selasky uint32_t ret; 10428c8fff31SAndrew Thompson 10438c8fff31SAndrew Thompson switch (xfer->type) { 10448c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 10451c497368SHans Petter Selasky ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */ 10468c8fff31SAndrew Thompson break; 10478c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 10488c8fff31SAndrew Thompson ret = 2; 10498c8fff31SAndrew Thompson break; 10508c8fff31SAndrew Thompson default: 10518c8fff31SAndrew Thompson ret = 1; 10528c8fff31SAndrew Thompson break; 10538c8fff31SAndrew Thompson } 1054390065b1SAlfred Perlstein return (ret); 10558c8fff31SAndrew Thompson } 10568c8fff31SAndrew Thompson 10578c8fff31SAndrew Thompson static int 1058390065b1SAlfred Perlstein libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 10598c8fff31SAndrew Thompson { 10608c8fff31SAndrew Thompson int ret; 10618c8fff31SAndrew Thompson int usb_speed; 10628c8fff31SAndrew Thompson 10638c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 10648c8fff31SAndrew Thompson 10658c8fff31SAndrew Thompson switch (xfer->type) { 10668c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1067390065b1SAlfred Perlstein ret = 0; /* kernel will auto-select */ 10688c8fff31SAndrew Thompson break; 10698c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 1070390065b1SAlfred Perlstein ret = 1024; 10718c8fff31SAndrew Thompson break; 10728c8fff31SAndrew Thompson default: 10738c8fff31SAndrew Thompson switch (usb_speed) { 10748c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 10758c8fff31SAndrew Thompson ret = 256; 10768c8fff31SAndrew Thompson break; 10778c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 10788c8fff31SAndrew Thompson ret = 4096; 10798c8fff31SAndrew Thompson break; 1080f355a4ddSHans Petter Selasky case LIBUSB20_SPEED_SUPER: 1081f355a4ddSHans Petter Selasky ret = 65536; 1082f355a4ddSHans Petter Selasky break; 10838c8fff31SAndrew Thompson default: 10848c8fff31SAndrew Thompson ret = 16384; 10858c8fff31SAndrew Thompson break; 10868c8fff31SAndrew Thompson } 10878c8fff31SAndrew Thompson break; 10888c8fff31SAndrew Thompson } 1089390065b1SAlfred Perlstein return (ret); 10908c8fff31SAndrew Thompson } 10918c8fff31SAndrew Thompson 1092390065b1SAlfred Perlstein static int 1093390065b1SAlfred Perlstein libusb10_convert_error(uint8_t status) 1094390065b1SAlfred Perlstein { 1095390065b1SAlfred Perlstein ; /* indent fix */ 1096390065b1SAlfred Perlstein 1097390065b1SAlfred Perlstein switch (status) { 1098390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1099390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1100390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_COMPLETED); 1101390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_OVERFLOW: 1102390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_OVERFLOW); 1103390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_NO_DEVICE: 1104390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_NO_DEVICE); 1105390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_STALL: 1106390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_STALL); 1107390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_CANCELLED: 1108390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_CANCELLED); 1109390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_TIMED_OUT: 1110390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_TIMED_OUT); 1111390065b1SAlfred Perlstein default: 1112390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_ERROR); 1113390065b1SAlfred Perlstein } 1114390065b1SAlfred Perlstein } 1115390065b1SAlfred Perlstein 1116390065b1SAlfred Perlstein /* This function must be called locked */ 1117390065b1SAlfred Perlstein 1118c500e4ddSAndrew Thompson static void 1119390065b1SAlfred Perlstein libusb10_complete_transfer(struct libusb20_transfer *pxfer, 1120390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer, int status) 1121c500e4ddSAndrew Thompson { 1122390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1123390065b1SAlfred Perlstein struct libusb_device *dev; 1124c500e4ddSAndrew Thompson 1125390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1126390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1127390065b1SAlfred Perlstein 1128390065b1SAlfred Perlstein if (pxfer != NULL) 1129390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer, NULL); 1130390065b1SAlfred Perlstein 11314594d907SAndrew Thompson /* set transfer status */ 1132390065b1SAlfred Perlstein uxfer->status = status; 1133390065b1SAlfred Perlstein 11344594d907SAndrew Thompson /* update super transfer state */ 11354594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 11364594d907SAndrew Thompson 1137390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 1138390065b1SAlfred Perlstein 1139390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 1140390065b1SAlfred Perlstein } 1141390065b1SAlfred Perlstein 1142390065b1SAlfred Perlstein /* This function must be called locked */ 1143390065b1SAlfred Perlstein 1144390065b1SAlfred Perlstein static void 1145390065b1SAlfred Perlstein libusb10_isoc_proxy(struct libusb20_transfer *pxfer) 1146390065b1SAlfred Perlstein { 1147390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1148390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1149390065b1SAlfred Perlstein uint32_t actlen; 1150390065b1SAlfred Perlstein uint16_t iso_packets; 1151390065b1SAlfred Perlstein uint16_t i; 1152390065b1SAlfred Perlstein uint8_t status; 1153390065b1SAlfred Perlstein 1154390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1155390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1156390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1157390065b1SAlfred Perlstein iso_packets = libusb20_tr_get_max_frames(pxfer); 1158390065b1SAlfred Perlstein 1159390065b1SAlfred Perlstein if (sxfer == NULL) 1160390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1161390065b1SAlfred Perlstein 1162390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1163390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1164390065b1SAlfred Perlstein 1165390065b1SAlfred Perlstein if (iso_packets > uxfer->num_iso_packets) 1166390065b1SAlfred Perlstein iso_packets = uxfer->num_iso_packets; 1167390065b1SAlfred Perlstein 1168390065b1SAlfred Perlstein if (iso_packets == 0) 1169390065b1SAlfred Perlstein return; /* nothing to do */ 1170390065b1SAlfred Perlstein 1171390065b1SAlfred Perlstein /* make sure that the number of ISOCHRONOUS packets is valid */ 1172390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 1173390065b1SAlfred Perlstein 1174c500e4ddSAndrew Thompson switch (status) { 1175c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 1176390065b1SAlfred Perlstein /* update actual length */ 1177390065b1SAlfred Perlstein uxfer->actual_length = actlen; 1178390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 1179390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].actual_length = 1180390065b1SAlfred Perlstein libusb20_tr_get_length(pxfer, i); 1181390065b1SAlfred Perlstein } 1182390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1183c500e4ddSAndrew Thompson break; 1184c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_START: 1185390065b1SAlfred Perlstein /* setup length(s) */ 1186390065b1SAlfred Perlstein actlen = 0; 1187390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 1188390065b1SAlfred Perlstein libusb20_tr_setup_isoc(pxfer, 1189390065b1SAlfred Perlstein &uxfer->buffer[actlen], 1190390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].length, i); 1191390065b1SAlfred Perlstein actlen += uxfer->iso_packet_desc[i].length; 1192c500e4ddSAndrew Thompson } 1193390065b1SAlfred Perlstein 1194390065b1SAlfred Perlstein /* no remainder */ 1195390065b1SAlfred Perlstein sxfer->rem_len = 0; 1196390065b1SAlfred Perlstein 1197390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, iso_packets); 1198390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1199390065b1SAlfred Perlstein 1200390065b1SAlfred Perlstein /* fork another USB transfer, if any */ 1201390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1202c500e4ddSAndrew Thompson break; 1203390065b1SAlfred Perlstein default: 1204390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1205c500e4ddSAndrew Thompson break; 1206c500e4ddSAndrew Thompson } 1207390065b1SAlfred Perlstein } 1208390065b1SAlfred Perlstein 1209390065b1SAlfred Perlstein /* This function must be called locked */ 1210390065b1SAlfred Perlstein 1211390065b1SAlfred Perlstein static void 1212390065b1SAlfred Perlstein libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 1213390065b1SAlfred Perlstein { 1214390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1215390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1216390065b1SAlfred Perlstein uint32_t max_bulk; 1217390065b1SAlfred Perlstein uint32_t actlen; 1218390065b1SAlfred Perlstein uint8_t status; 1219390065b1SAlfred Perlstein uint8_t flags; 1220390065b1SAlfred Perlstein 1221390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1222390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1223390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1224390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1225390065b1SAlfred Perlstein 1226390065b1SAlfred Perlstein if (sxfer == NULL) 1227390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1228390065b1SAlfred Perlstein 1229390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1230390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1231390065b1SAlfred Perlstein 1232390065b1SAlfred Perlstein flags = uxfer->flags; 1233390065b1SAlfred Perlstein 1234390065b1SAlfred Perlstein switch (status) { 1235390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1236390065b1SAlfred Perlstein 1237390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1238390065b1SAlfred Perlstein 1239390065b1SAlfred Perlstein /* check for short packet */ 1240390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1241390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1242390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1243390065b1SAlfred Perlstein } else { 1244390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1245390065b1SAlfred Perlstein } 1246390065b1SAlfred Perlstein break; 1247390065b1SAlfred Perlstein } 1248390065b1SAlfred Perlstein /* check for end of data */ 1249390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1250390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1251390065b1SAlfred Perlstein break; 1252390065b1SAlfred Perlstein } 1253390065b1SAlfred Perlstein /* FALLTHROUGH */ 1254390065b1SAlfred Perlstein 1255390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1256390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1257390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1258390065b1SAlfred Perlstein } 1259390065b1SAlfred Perlstein /* setup new BULK or INTERRUPT transaction */ 1260390065b1SAlfred Perlstein libusb20_tr_setup_bulk(pxfer, 1261390065b1SAlfred Perlstein sxfer->curr_data, max_bulk, uxfer->timeout); 1262390065b1SAlfred Perlstein 1263390065b1SAlfred Perlstein /* update counters */ 1264390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1265390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1266390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1267390065b1SAlfred Perlstein 1268390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1269390065b1SAlfred Perlstein 1270390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1271390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1272390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1273390065b1SAlfred Perlstein break; 1274390065b1SAlfred Perlstein 1275390065b1SAlfred Perlstein default: 1276390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1277390065b1SAlfred Perlstein break; 1278390065b1SAlfred Perlstein } 1279390065b1SAlfred Perlstein } 1280390065b1SAlfred Perlstein 1281390065b1SAlfred Perlstein /* This function must be called locked */ 1282390065b1SAlfred Perlstein 1283390065b1SAlfred Perlstein static void 1284390065b1SAlfred Perlstein libusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1285390065b1SAlfred Perlstein { 1286390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1287390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1288390065b1SAlfred Perlstein uint32_t max_bulk; 1289390065b1SAlfred Perlstein uint32_t actlen; 1290390065b1SAlfred Perlstein uint8_t status; 1291390065b1SAlfred Perlstein uint8_t flags; 1292390065b1SAlfred Perlstein 1293390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1294390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1295390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1296390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1297390065b1SAlfred Perlstein 1298390065b1SAlfred Perlstein if (sxfer == NULL) 1299390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1300390065b1SAlfred Perlstein 1301390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1302390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1303390065b1SAlfred Perlstein 1304390065b1SAlfred Perlstein flags = uxfer->flags; 1305390065b1SAlfred Perlstein 1306390065b1SAlfred Perlstein switch (status) { 1307390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1308390065b1SAlfred Perlstein 1309390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1310390065b1SAlfred Perlstein 1311390065b1SAlfred Perlstein /* subtract length of SETUP packet, if any */ 1312390065b1SAlfred Perlstein actlen -= libusb20_tr_get_length(pxfer, 0); 1313390065b1SAlfred Perlstein 1314390065b1SAlfred Perlstein /* check for short packet */ 1315390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1316390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1317390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1318390065b1SAlfred Perlstein } else { 1319390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1320390065b1SAlfred Perlstein } 1321390065b1SAlfred Perlstein break; 1322390065b1SAlfred Perlstein } 1323390065b1SAlfred Perlstein /* check for end of data */ 1324390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1325390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1326390065b1SAlfred Perlstein break; 1327390065b1SAlfred Perlstein } 1328390065b1SAlfred Perlstein /* FALLTHROUGH */ 1329390065b1SAlfred Perlstein 1330390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1331390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1332390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1333390065b1SAlfred Perlstein } 1334390065b1SAlfred Perlstein /* setup new CONTROL transaction */ 1335390065b1SAlfred Perlstein if (status == LIBUSB20_TRANSFER_COMPLETED) { 1336390065b1SAlfred Perlstein /* next fragment - don't send SETUP packet */ 1337390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 0, 0); 1338390065b1SAlfred Perlstein } else { 1339390065b1SAlfred Perlstein /* first fragment - send SETUP packet */ 1340390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 8, 0); 1341390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1342390065b1SAlfred Perlstein } 1343390065b1SAlfred Perlstein 1344390065b1SAlfred Perlstein if (max_bulk != 0) { 1345390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, max_bulk, 1); 1346390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1347390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 2); 1348390065b1SAlfred Perlstein } else { 1349390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 1); 1350390065b1SAlfred Perlstein } 1351390065b1SAlfred Perlstein 1352390065b1SAlfred Perlstein /* update counters */ 1353390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1354390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1355390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1356390065b1SAlfred Perlstein 1357390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1358390065b1SAlfred Perlstein 1359390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1360390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1361390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1362390065b1SAlfred Perlstein break; 1363390065b1SAlfred Perlstein 1364390065b1SAlfred Perlstein default: 1365390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1366390065b1SAlfred Perlstein break; 1367390065b1SAlfred Perlstein } 1368390065b1SAlfred Perlstein } 1369390065b1SAlfred Perlstein 1370390065b1SAlfred Perlstein /* The following function must be called locked */ 1371390065b1SAlfred Perlstein 1372390065b1SAlfred Perlstein static void 1373390065b1SAlfred Perlstein libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1374390065b1SAlfred Perlstein { 1375390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1376390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1377390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1378390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1379390065b1SAlfred Perlstein struct libusb_device *dev; 1380390065b1SAlfred Perlstein int err; 1381390065b1SAlfred Perlstein int buffsize; 1382390065b1SAlfred Perlstein int maxframe; 1383390065b1SAlfred Perlstein int temp; 1384390065b1SAlfred Perlstein 1385390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 1386390065b1SAlfred Perlstein 1387390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1388390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1389390065b1SAlfred Perlstein 1390390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) 1391390065b1SAlfred Perlstein return; /* shouldn't happen */ 1392390065b1SAlfred Perlstein 1393390065b1SAlfred Perlstein temp = 0; 1394390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer0)) 1395390065b1SAlfred Perlstein temp |= 1; 1396390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer1)) 1397390065b1SAlfred Perlstein temp |= 2; 1398390065b1SAlfred Perlstein 1399390065b1SAlfred Perlstein switch (temp) { 1400390065b1SAlfred Perlstein case 3: 1401390065b1SAlfred Perlstein /* wait till one of the transfers complete */ 1402390065b1SAlfred Perlstein return; 1403390065b1SAlfred Perlstein case 2: 1404390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer1); 14054594d907SAndrew Thompson if (sxfer == NULL) 14064594d907SAndrew Thompson return; /* cancelling */ 1407390065b1SAlfred Perlstein if (sxfer->rem_len) 1408390065b1SAlfred Perlstein return; /* cannot queue another one */ 1409390065b1SAlfred Perlstein /* swap transfers */ 1410390065b1SAlfred Perlstein pxfer1 = pxfer0; 1411390065b1SAlfred Perlstein break; 1412390065b1SAlfred Perlstein case 1: 1413390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer0); 14144594d907SAndrew Thompson if (sxfer == NULL) 14154594d907SAndrew Thompson return; /* cancelling */ 1416390065b1SAlfred Perlstein if (sxfer->rem_len) 1417390065b1SAlfred Perlstein return; /* cannot queue another one */ 1418390065b1SAlfred Perlstein /* swap transfers */ 1419390065b1SAlfred Perlstein pxfer0 = pxfer1; 1420c500e4ddSAndrew Thompson break; 1421c500e4ddSAndrew Thompson default: 1422c500e4ddSAndrew Thompson break; 1423c500e4ddSAndrew Thompson } 1424c500e4ddSAndrew Thompson 1425390065b1SAlfred Perlstein /* find next transfer on same endpoint */ 1426390065b1SAlfred Perlstein TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1427390065b1SAlfred Perlstein 1428390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1429390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1430390065b1SAlfred Perlstein 1431390065b1SAlfred Perlstein if (uxfer->endpoint == endpoint) { 1432390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1433390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 1434390065b1SAlfred Perlstein goto found; 1435c500e4ddSAndrew Thompson } 1436c500e4ddSAndrew Thompson } 1437390065b1SAlfred Perlstein return; /* success */ 1438390065b1SAlfred Perlstein 1439390065b1SAlfred Perlstein found: 1440390065b1SAlfred Perlstein 1441390065b1SAlfred Perlstein libusb20_tr_set_priv_sc0(pxfer0, pdev); 1442390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1443390065b1SAlfred Perlstein 1444390065b1SAlfred Perlstein /* reset super transfer state */ 1445390065b1SAlfred Perlstein sxfer->rem_len = uxfer->length; 1446390065b1SAlfred Perlstein sxfer->curr_data = uxfer->buffer; 1447390065b1SAlfred Perlstein uxfer->actual_length = 0; 1448390065b1SAlfred Perlstein 1449390065b1SAlfred Perlstein switch (uxfer->type) { 1450390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1451390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1452390065b1SAlfred Perlstein break; 1453390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_BULK: 1454390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1455390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1456390065b1SAlfred Perlstein break; 1457390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_CONTROL: 1458390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1459390065b1SAlfred Perlstein if (sxfer->rem_len < 8) 1460390065b1SAlfred Perlstein goto failure; 1461390065b1SAlfred Perlstein 1462390065b1SAlfred Perlstein /* remove SETUP packet from data */ 1463390065b1SAlfred Perlstein sxfer->rem_len -= 8; 1464390065b1SAlfred Perlstein sxfer->curr_data += 8; 1465390065b1SAlfred Perlstein break; 1466390065b1SAlfred Perlstein default: 1467390065b1SAlfred Perlstein goto failure; 1468390065b1SAlfred Perlstein } 1469390065b1SAlfred Perlstein 1470390065b1SAlfred Perlstein buffsize = libusb10_get_buffsize(pdev, uxfer); 1471390065b1SAlfred Perlstein maxframe = libusb10_get_maxframe(pdev, uxfer); 1472390065b1SAlfred Perlstein 1473390065b1SAlfred Perlstein /* make sure the transfer is opened */ 1474a0c93fa3SHans Petter Selasky err = libusb20_tr_open_stream(pxfer0, buffsize, maxframe, 1475a0c93fa3SHans Petter Selasky endpoint, sxfer->stream_id); 1476390065b1SAlfred Perlstein if (err && (err != LIBUSB20_ERROR_BUSY)) { 1477390065b1SAlfred Perlstein goto failure; 1478390065b1SAlfred Perlstein } 1479390065b1SAlfred Perlstein libusb20_tr_start(pxfer0); 1480390065b1SAlfred Perlstein return; 1481390065b1SAlfred Perlstein 1482390065b1SAlfred Perlstein failure: 1483390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1484390065b1SAlfred Perlstein /* make sure our event loop spins the done handler */ 1485aa87aa52SHans Petter Selasky libusb_interrupt_event_handler(dev->ctx); 1486390065b1SAlfred Perlstein } 1487390065b1SAlfred Perlstein 1488390065b1SAlfred Perlstein /* The following function must be called unlocked */ 1489c500e4ddSAndrew Thompson 14908c8fff31SAndrew Thompson int 1491390065b1SAlfred Perlstein libusb_submit_transfer(struct libusb_transfer *uxfer) 14928c8fff31SAndrew Thompson { 1493390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1494390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1495390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1496390065b1SAlfred Perlstein struct libusb_device *dev; 149785ff9a03SHans Petter Selasky uint8_t endpoint; 1498390065b1SAlfred Perlstein int err; 14998c8fff31SAndrew Thompson 1500390065b1SAlfred Perlstein if (uxfer == NULL) 1501390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 15028c8fff31SAndrew Thompson 1503390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 1504390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 15058c8fff31SAndrew Thompson 1506390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 15078c8fff31SAndrew Thompson 1508390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 15098c8fff31SAndrew Thompson 1510390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 15118c8fff31SAndrew Thompson 1512390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1513390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1514390065b1SAlfred Perlstein 1515390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1516390065b1SAlfred Perlstein 1517390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1518390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1519390065b1SAlfred Perlstein 1520390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) { 1521390065b1SAlfred Perlstein err = LIBUSB_ERROR_OTHER; 1522390065b1SAlfred Perlstein } else if ((sxfer->entry.tqe_prev != NULL) || 1523390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1524390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1525390065b1SAlfred Perlstein err = LIBUSB_ERROR_BUSY; 1526540c7229SHans Petter Selasky } else if (dev->device_is_gone != 0) { 1527540c7229SHans Petter Selasky err = LIBUSB_ERROR_NO_DEVICE; 1528390065b1SAlfred Perlstein } else { 15294594d907SAndrew Thompson 15304594d907SAndrew Thompson /* set pending state */ 15314594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 15324594d907SAndrew Thompson 15334594d907SAndrew Thompson /* insert transfer into transfer head list */ 1534390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1535390065b1SAlfred Perlstein 15364594d907SAndrew Thompson /* start work transfers */ 1537390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1538390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1539390065b1SAlfred Perlstein 1540390065b1SAlfred Perlstein err = 0; /* success */ 15418c8fff31SAndrew Thompson } 15428c8fff31SAndrew Thompson 1543390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 1544390065b1SAlfred Perlstein 1545390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1546390065b1SAlfred Perlstein 1547390065b1SAlfred Perlstein return (err); 15488c8fff31SAndrew Thompson } 15498c8fff31SAndrew Thompson 1550390065b1SAlfred Perlstein /* Asynchronous transfer cancel */ 15518c8fff31SAndrew Thompson 1552390065b1SAlfred Perlstein int 1553390065b1SAlfred Perlstein libusb_cancel_transfer(struct libusb_transfer *uxfer) 1554390065b1SAlfred Perlstein { 1555390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1556390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1557390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1558390065b1SAlfred Perlstein struct libusb_device *dev; 1559540c7229SHans Petter Selasky struct libusb_device_handle *devh; 156085ff9a03SHans Petter Selasky uint8_t endpoint; 15614594d907SAndrew Thompson int retval; 15628c8fff31SAndrew Thompson 1563390065b1SAlfred Perlstein if (uxfer == NULL) 1564390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 15658c8fff31SAndrew Thompson 15664594d907SAndrew Thompson /* check if not initialised */ 1567540c7229SHans Petter Selasky if ((devh = uxfer->dev_handle) == NULL) 15684594d907SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 15698c8fff31SAndrew Thompson 1570390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 15718c8fff31SAndrew Thompson 1572540c7229SHans Petter Selasky dev = libusb_get_device(devh); 15738c8fff31SAndrew Thompson 1574390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 15758c8fff31SAndrew Thompson 1576390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1577390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1578390065b1SAlfred Perlstein 15794594d907SAndrew Thompson retval = 0; 15804594d907SAndrew Thompson 1581390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1582390065b1SAlfred Perlstein 1583540c7229SHans Petter Selasky pxfer0 = libusb10_get_transfer(devh, endpoint, 0); 1584540c7229SHans Petter Selasky pxfer1 = libusb10_get_transfer(devh, endpoint, 1); 1585390065b1SAlfred Perlstein 15864594d907SAndrew Thompson if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 15874594d907SAndrew Thompson /* only update the transfer status */ 15884594d907SAndrew Thompson uxfer->status = LIBUSB_TRANSFER_CANCELLED; 15894594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 15904594d907SAndrew Thompson } else if (sxfer->entry.tqe_prev != NULL) { 1591390065b1SAlfred Perlstein /* we are lucky - transfer is on a queue */ 1592390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1593390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 15944594d907SAndrew Thompson libusb10_complete_transfer(NULL, 15954594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1596540c7229SHans Petter Selasky /* make sure our event loop spins the done handler */ 1597aa87aa52SHans Petter Selasky libusb_interrupt_event_handler(dev->ctx); 1598390065b1SAlfred Perlstein } else if (pxfer0 == NULL || pxfer1 == NULL) { 1599390065b1SAlfred Perlstein /* not started */ 16004594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1601390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 16024594d907SAndrew Thompson libusb10_complete_transfer(pxfer0, 16034594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1604540c7229SHans Petter Selasky if (dev->device_is_gone != 0) { 1605540c7229SHans Petter Selasky /* clear transfer pointer */ 1606540c7229SHans Petter Selasky libusb20_tr_set_priv_sc1(pxfer0, NULL); 1607540c7229SHans Petter Selasky /* make sure our event loop spins the done handler */ 1608aa87aa52SHans Petter Selasky libusb_interrupt_event_handler(dev->ctx); 1609540c7229SHans Petter Selasky } else { 1610390065b1SAlfred Perlstein libusb20_tr_stop(pxfer0); 1611390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1612540c7229SHans Petter Selasky libusb10_submit_transfer_sub(devh, endpoint); 1613540c7229SHans Petter Selasky } 1614390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 16154594d907SAndrew Thompson libusb10_complete_transfer(pxfer1, 16164594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1617540c7229SHans Petter Selasky /* check if handle is still active */ 1618540c7229SHans Petter Selasky if (dev->device_is_gone != 0) { 1619540c7229SHans Petter Selasky /* clear transfer pointer */ 1620540c7229SHans Petter Selasky libusb20_tr_set_priv_sc1(pxfer1, NULL); 1621540c7229SHans Petter Selasky /* make sure our event loop spins the done handler */ 1622aa87aa52SHans Petter Selasky libusb_interrupt_event_handler(dev->ctx); 1623540c7229SHans Petter Selasky } else { 1624390065b1SAlfred Perlstein libusb20_tr_stop(pxfer1); 1625390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1626540c7229SHans Petter Selasky libusb10_submit_transfer_sub(devh, endpoint); 1627540c7229SHans Petter Selasky } 1628390065b1SAlfred Perlstein } else { 1629390065b1SAlfred Perlstein /* not started */ 16304594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1631c500e4ddSAndrew Thompson } 16328c8fff31SAndrew Thompson 1633390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 16348c8fff31SAndrew Thompson 1635390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 16368c8fff31SAndrew Thompson 16374594d907SAndrew Thompson return (retval); 16388c8fff31SAndrew Thompson } 16398c8fff31SAndrew Thompson 1640390065b1SAlfred Perlstein UNEXPORTED void 1641390065b1SAlfred Perlstein libusb10_cancel_all_transfer(libusb_device *dev) 16428c8fff31SAndrew Thompson { 164390988efdSHans Petter Selasky struct libusb20_device *pdev = dev->os_priv; 164490988efdSHans Petter Selasky unsigned x; 164590988efdSHans Petter Selasky 164690988efdSHans Petter Selasky for (x = 0; x != LIBUSB_NUM_SW_ENDPOINTS; x++) { 164790988efdSHans Petter Selasky struct libusb20_transfer *xfer; 164890988efdSHans Petter Selasky 164990988efdSHans Petter Selasky xfer = libusb20_tr_get_pointer(pdev, x); 165090988efdSHans Petter Selasky if (xfer == NULL) 165190988efdSHans Petter Selasky continue; 165290988efdSHans Petter Selasky libusb20_tr_close(xfer); 165390988efdSHans Petter Selasky } 16548c8fff31SAndrew Thompson } 1655ccef4ddfSAndrew Thompson 1656540c7229SHans Petter Selasky UNEXPORTED void 1657540c7229SHans Petter Selasky libusb10_cancel_all_transfer_locked(struct libusb20_device *pdev, struct libusb_device *dev) 1658540c7229SHans Petter Selasky { 1659540c7229SHans Petter Selasky struct libusb_super_transfer *sxfer; 1660540c7229SHans Petter Selasky unsigned x; 1661540c7229SHans Petter Selasky 1662540c7229SHans Petter Selasky for (x = 0; x != LIBUSB_NUM_SW_ENDPOINTS; x++) { 1663540c7229SHans Petter Selasky struct libusb20_transfer *xfer; 1664540c7229SHans Petter Selasky 1665540c7229SHans Petter Selasky xfer = libusb20_tr_get_pointer(pdev, x); 1666540c7229SHans Petter Selasky if (xfer == NULL) 1667540c7229SHans Petter Selasky continue; 1668540c7229SHans Petter Selasky if (libusb20_tr_pending(xfer) == 0) 1669540c7229SHans Petter Selasky continue; 1670540c7229SHans Petter Selasky sxfer = libusb20_tr_get_priv_sc1(xfer); 1671540c7229SHans Petter Selasky if (sxfer == NULL) 1672540c7229SHans Petter Selasky continue; 1673540c7229SHans Petter Selasky /* complete pending transfer */ 1674540c7229SHans Petter Selasky libusb10_complete_transfer(xfer, sxfer, LIBUSB_TRANSFER_ERROR); 1675540c7229SHans Petter Selasky } 1676540c7229SHans Petter Selasky 1677540c7229SHans Petter Selasky while ((sxfer = TAILQ_FIRST(&dev->tr_head))) { 1678540c7229SHans Petter Selasky TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1679540c7229SHans Petter Selasky 1680540c7229SHans Petter Selasky /* complete pending transfer */ 1681540c7229SHans Petter Selasky libusb10_complete_transfer(NULL, sxfer, LIBUSB_TRANSFER_ERROR); 1682540c7229SHans Petter Selasky } 1683540c7229SHans Petter Selasky } 1684540c7229SHans Petter Selasky 1685ccef4ddfSAndrew Thompson uint16_t 1686ccef4ddfSAndrew Thompson libusb_cpu_to_le16(uint16_t x) 1687ccef4ddfSAndrew Thompson { 1688ccef4ddfSAndrew Thompson return (htole16(x)); 1689ccef4ddfSAndrew Thompson } 1690ccef4ddfSAndrew Thompson 1691ccef4ddfSAndrew Thompson uint16_t 1692ccef4ddfSAndrew Thompson libusb_le16_to_cpu(uint16_t x) 1693ccef4ddfSAndrew Thompson { 1694ccef4ddfSAndrew Thompson return (le16toh(x)); 1695ccef4ddfSAndrew Thompson } 1696ccef4ddfSAndrew Thompson 1697698e791aSHans Petter Selasky const char * 1698698e791aSHans Petter Selasky libusb_strerror(int code) 1699698e791aSHans Petter Selasky { 1700c61f2561SHans Petter Selasky switch (code) { 1701c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1702c61f2561SHans Petter Selasky return ("Success"); 1703c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1704c61f2561SHans Petter Selasky return ("I/O error"); 1705c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1706c61f2561SHans Petter Selasky return ("Invalid parameter"); 1707c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1708c61f2561SHans Petter Selasky return ("Permissions error"); 1709c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1710c61f2561SHans Petter Selasky return ("No device"); 1711c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1712c61f2561SHans Petter Selasky return ("Not found"); 1713c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1714c61f2561SHans Petter Selasky return ("Device busy"); 1715c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1716c61f2561SHans Petter Selasky return ("Timeout"); 1717c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1718c61f2561SHans Petter Selasky return ("Overflow"); 1719c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1720c61f2561SHans Petter Selasky return ("Pipe error"); 1721c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1722c61f2561SHans Petter Selasky return ("Interrupted"); 1723c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1724c61f2561SHans Petter Selasky return ("Out of memory"); 1725c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1726c61f2561SHans Petter Selasky return ("Not supported"); 1727c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1728c61f2561SHans Petter Selasky return ("Other error"); 1729c61f2561SHans Petter Selasky default: 1730698e791aSHans Petter Selasky return ("Unknown error"); 1731698e791aSHans Petter Selasky } 1732c61f2561SHans Petter Selasky } 1733c61f2561SHans Petter Selasky 1734c61f2561SHans Petter Selasky const char * 1735c61f2561SHans Petter Selasky libusb_error_name(int code) 1736c61f2561SHans Petter Selasky { 1737c61f2561SHans Petter Selasky switch (code) { 1738c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1739c61f2561SHans Petter Selasky return ("LIBUSB_SUCCESS"); 1740c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1741c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_IO"); 1742c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1743c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INVALID_PARAM"); 1744c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1745c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_ACCESS"); 1746c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1747c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_DEVICE"); 1748c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1749c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_FOUND"); 1750c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1751c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_BUSY"); 1752c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1753c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_TIMEOUT"); 1754c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1755c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OVERFLOW"); 1756c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1757c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_PIPE"); 1758c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1759c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INTERRUPTED"); 1760c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1761c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_MEM"); 1762c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1763c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_SUPPORTED"); 1764c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1765c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OTHER"); 1766c61f2561SHans Petter Selasky default: 1767c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_UNKNOWN"); 1768c61f2561SHans Petter Selasky } 1769c61f2561SHans Petter Selasky } 177004391da3SKyle Evans 177104391da3SKyle Evans int 177204391da3SKyle Evans libusb_has_capability(uint32_t capability) 177304391da3SKyle Evans { 177404391da3SKyle Evans 177504391da3SKyle Evans switch (capability) { 177604391da3SKyle Evans case LIBUSB_CAP_HAS_CAPABILITY: 177704391da3SKyle Evans case LIBUSB_CAP_HAS_HOTPLUG: 177804391da3SKyle Evans case LIBUSB_CAP_HAS_HID_ACCESS: 177904391da3SKyle Evans case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER: 178004391da3SKyle Evans return (1); 178104391da3SKyle Evans default: 178204391da3SKyle Evans return (0); 178304391da3SKyle Evans } 178404391da3SKyle Evans } 1785