18c8fff31SAndrew Thompson /* $FreeBSD$ */ 28c8fff31SAndrew Thompson /*- 35e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 45e53a4f9SPedro F. Giffuni * 58c8fff31SAndrew Thompson * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 6390065b1SAlfred Perlstein * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 78c8fff31SAndrew Thompson * 88c8fff31SAndrew Thompson * Redistribution and use in source and binary forms, with or without 98c8fff31SAndrew Thompson * modification, are permitted provided that the following conditions 108c8fff31SAndrew Thompson * are met: 118c8fff31SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 128c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer. 138c8fff31SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 148c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 158c8fff31SAndrew Thompson * documentation and/or other materials provided with the distribution. 168c8fff31SAndrew Thompson * 178c8fff31SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 188c8fff31SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198c8fff31SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208c8fff31SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 218c8fff31SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228c8fff31SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238c8fff31SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248c8fff31SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258c8fff31SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268c8fff31SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278c8fff31SAndrew Thompson * SUCH DAMAGE. 288c8fff31SAndrew Thompson */ 298c8fff31SAndrew Thompson 3066194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE 3166194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE 3266194130SHans Petter Selasky #else 33ac840bfcSWojciech A. Koszek #include <assert.h> 34f3cba95cSWojciech A. Koszek #include <errno.h> 358c8fff31SAndrew Thompson #include <poll.h> 368c8fff31SAndrew Thompson #include <pthread.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); 948c8fff31SAndrew Thompson if (ctx) 958c8fff31SAndrew Thompson ctx->debug = level; 968c8fff31SAndrew Thompson } 978c8fff31SAndrew Thompson 98698e791aSHans Petter Selasky static void 99698e791aSHans Petter Selasky libusb_set_nonblocking(int f) 100698e791aSHans Petter Selasky { 101698e791aSHans Petter Selasky int flags; 102698e791aSHans Petter Selasky 103698e791aSHans Petter Selasky /* 104698e791aSHans Petter Selasky * We ignore any failures in this function, hence the 105698e791aSHans Petter Selasky * non-blocking flag is not critical to the operation of 106698e791aSHans Petter Selasky * libUSB. We use F_GETFL and F_SETFL to be compatible with 107698e791aSHans Petter Selasky * Linux. 108698e791aSHans Petter Selasky */ 109698e791aSHans Petter Selasky 110698e791aSHans Petter Selasky flags = fcntl(f, F_GETFL, NULL); 111698e791aSHans Petter Selasky if (flags == -1) 112698e791aSHans Petter Selasky return; 113698e791aSHans Petter Selasky flags |= O_NONBLOCK; 114698e791aSHans Petter Selasky fcntl(f, F_SETFL, flags); 115698e791aSHans Petter Selasky } 116698e791aSHans Petter Selasky 117540c7229SHans Petter Selasky static void 118540c7229SHans Petter Selasky libusb10_wakeup_event_loop(libusb_context *ctx) 119540c7229SHans Petter Selasky { 120540c7229SHans Petter Selasky uint8_t dummy = 0; 121540c7229SHans Petter Selasky int err; 122540c7229SHans Petter Selasky 123540c7229SHans Petter Selasky err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 124540c7229SHans Petter Selasky if (err < (int)sizeof(dummy)) { 125540c7229SHans Petter Selasky /* ignore error, if any */ 126540c7229SHans Petter Selasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "Waking up event loop failed!"); 127540c7229SHans Petter Selasky } 128540c7229SHans Petter Selasky } 129540c7229SHans Petter Selasky 1308c8fff31SAndrew Thompson int 1318c8fff31SAndrew Thompson libusb_init(libusb_context **context) 1328c8fff31SAndrew Thompson { 1338c8fff31SAndrew Thompson struct libusb_context *ctx; 134f7287225SHans Petter Selasky pthread_condattr_t attr; 1358c8fff31SAndrew Thompson char *debug; 1368c8fff31SAndrew Thompson int ret; 1378c8fff31SAndrew Thompson 1388c8fff31SAndrew Thompson ctx = malloc(sizeof(*ctx)); 1398c8fff31SAndrew Thompson if (!ctx) 1408c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1418c8fff31SAndrew Thompson 1428c8fff31SAndrew Thompson memset(ctx, 0, sizeof(*ctx)); 1438c8fff31SAndrew Thompson 1448c8fff31SAndrew Thompson debug = getenv("LIBUSB_DEBUG"); 1458c8fff31SAndrew Thompson if (debug != NULL) { 1468c8fff31SAndrew Thompson ctx->debug = atoi(debug); 1478c8fff31SAndrew Thompson if (ctx->debug != 0) 1488c8fff31SAndrew Thompson ctx->debug_fixed = 1; 1498c8fff31SAndrew Thompson } 150c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->pollfds); 151390065b1SAlfred Perlstein TAILQ_INIT(&ctx->tr_done); 1527bdc064bSHans Petter Selasky TAILQ_INIT(&ctx->hotplug_cbh); 1537bdc064bSHans Petter Selasky TAILQ_INIT(&ctx->hotplug_devs); 154390065b1SAlfred Perlstein 155f7287225SHans Petter Selasky if (pthread_mutex_init(&ctx->ctx_lock, NULL) != 0) { 156f7287225SHans Petter Selasky free(ctx); 157f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 158f7287225SHans Petter Selasky } 1597bdc064bSHans Petter Selasky if (pthread_mutex_init(&ctx->hotplug_lock, NULL) != 0) { 1607bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 1617bdc064bSHans Petter Selasky free(ctx); 1627bdc064bSHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 1637bdc064bSHans Petter Selasky } 164f7287225SHans Petter Selasky if (pthread_condattr_init(&attr) != 0) { 165f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 1667bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 167f7287225SHans Petter Selasky free(ctx); 168f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 169f7287225SHans Petter Selasky } 170f7287225SHans Petter Selasky if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) { 171f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 1727bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 173f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 174f7287225SHans Petter Selasky free(ctx); 175f7287225SHans Petter Selasky return (LIBUSB_ERROR_OTHER); 176f7287225SHans Petter Selasky } 177f7287225SHans Petter Selasky if (pthread_cond_init(&ctx->ctx_cond, &attr) != 0) { 178f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 1797bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 180f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 181f7287225SHans Petter Selasky free(ctx); 182f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 183f7287225SHans Petter Selasky } 184f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 185390065b1SAlfred Perlstein 186390065b1SAlfred Perlstein ctx->ctx_handler = NO_THREAD; 1877bdc064bSHans Petter Selasky ctx->hotplug_handler = NO_THREAD; 1888c8fff31SAndrew Thompson 1898c8fff31SAndrew Thompson ret = pipe(ctx->ctrl_pipe); 1908c8fff31SAndrew Thompson if (ret < 0) { 191390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 1927bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 193390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 1948c8fff31SAndrew Thompson free(ctx); 1958c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 1968c8fff31SAndrew Thompson } 197390065b1SAlfred Perlstein /* set non-blocking mode on the control pipe to avoid deadlock */ 198698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[0]); 199698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[1]); 2008c8fff31SAndrew Thompson 201390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 2028c8fff31SAndrew Thompson 2038c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 2048c8fff31SAndrew Thompson if (usbi_default_context == NULL) { 2058c8fff31SAndrew Thompson usbi_default_context = ctx; 2068c8fff31SAndrew Thompson } 2078c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 2088c8fff31SAndrew Thompson 2098c8fff31SAndrew Thompson if (context) 2108c8fff31SAndrew Thompson *context = ctx; 2118c8fff31SAndrew Thompson 212390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 213390065b1SAlfred Perlstein 2148c8fff31SAndrew Thompson return (0); 2158c8fff31SAndrew Thompson } 2168c8fff31SAndrew Thompson 2178c8fff31SAndrew Thompson void 2188c8fff31SAndrew Thompson libusb_exit(libusb_context *ctx) 2198c8fff31SAndrew Thompson { 220390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 2218c8fff31SAndrew Thompson 222390065b1SAlfred Perlstein if (ctx == NULL) 223390065b1SAlfred Perlstein return; 224390065b1SAlfred Perlstein 2257bdc064bSHans Petter Selasky /* stop hotplug thread, if any */ 2267bdc064bSHans Petter Selasky 2277bdc064bSHans Petter Selasky if (ctx->hotplug_handler != NO_THREAD) { 2287bdc064bSHans Petter Selasky pthread_t td; 2297bdc064bSHans Petter Selasky void *ptr; 2307bdc064bSHans Petter Selasky 2317bdc064bSHans Petter Selasky HOTPLUG_LOCK(ctx); 2327bdc064bSHans Petter Selasky td = ctx->hotplug_handler; 2337bdc064bSHans Petter Selasky ctx->hotplug_handler = NO_THREAD; 2347bdc064bSHans Petter Selasky HOTPLUG_UNLOCK(ctx); 2357bdc064bSHans Petter Selasky 2367bdc064bSHans Petter Selasky pthread_join(td, &ptr); 2377bdc064bSHans Petter Selasky } 2387bdc064bSHans Petter Selasky 239390065b1SAlfred Perlstein /* XXX cleanup devices */ 240390065b1SAlfred Perlstein 241390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 2428c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 2438c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 244390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 2457bdc064bSHans Petter Selasky pthread_mutex_destroy(&ctx->hotplug_lock); 246390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 2478c8fff31SAndrew Thompson 2488c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 2498c8fff31SAndrew Thompson if (ctx == usbi_default_context) { 2508c8fff31SAndrew Thompson usbi_default_context = NULL; 2518c8fff31SAndrew Thompson } 2528c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 2538c8fff31SAndrew Thompson 2548c8fff31SAndrew Thompson free(ctx); 2558c8fff31SAndrew Thompson } 2568c8fff31SAndrew Thompson 2578c8fff31SAndrew Thompson /* Device handling and initialisation. */ 2588c8fff31SAndrew Thompson 2598c8fff31SAndrew Thompson ssize_t 2608c8fff31SAndrew Thompson libusb_get_device_list(libusb_context *ctx, libusb_device ***list) 2618c8fff31SAndrew Thompson { 2628c8fff31SAndrew Thompson struct libusb20_backend *usb_backend; 263390065b1SAlfred Perlstein struct libusb20_device *pdev; 264390065b1SAlfred Perlstein struct libusb_device *dev; 2658c8fff31SAndrew Thompson int i; 2668c8fff31SAndrew Thompson 267390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 268390065b1SAlfred Perlstein 269390065b1SAlfred Perlstein if (ctx == NULL) 270390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 271390065b1SAlfred Perlstein 272390065b1SAlfred Perlstein if (list == NULL) 273390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 2748c8fff31SAndrew Thompson 2758c8fff31SAndrew Thompson usb_backend = libusb20_be_alloc_default(); 2768c8fff31SAndrew Thompson if (usb_backend == NULL) 277390065b1SAlfred Perlstein return (LIBUSB_ERROR_NO_MEM); 2788c8fff31SAndrew Thompson 279390065b1SAlfred Perlstein /* figure out how many USB devices are present */ 2808c8fff31SAndrew Thompson pdev = NULL; 2818c8fff31SAndrew Thompson i = 0; 2828c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 2838c8fff31SAndrew Thompson i++; 2848c8fff31SAndrew Thompson 285390065b1SAlfred Perlstein /* allocate device pointer list */ 2868c8fff31SAndrew Thompson *list = malloc((i + 1) * sizeof(void *)); 2878c8fff31SAndrew Thompson if (*list == NULL) { 2888c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2898c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 2908c8fff31SAndrew Thompson } 291390065b1SAlfred Perlstein /* create libusb v1.0 compliant devices */ 2928c8fff31SAndrew Thompson i = 0; 2938c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 2948c8fff31SAndrew Thompson 2958c8fff31SAndrew Thompson dev = malloc(sizeof(*dev)); 2968c8fff31SAndrew Thompson if (dev == NULL) { 297c500e4ddSAndrew Thompson while (i != 0) { 298c500e4ddSAndrew Thompson libusb_unref_device((*list)[i - 1]); 299c500e4ddSAndrew Thompson i--; 300c500e4ddSAndrew Thompson } 3018c8fff31SAndrew Thompson free(*list); 302390065b1SAlfred Perlstein *list = NULL; 3038c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 3048c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3058c8fff31SAndrew Thompson } 306ccef4ddfSAndrew Thompson /* get device into libUSB v1.0 list */ 307ccef4ddfSAndrew Thompson libusb20_be_dequeue_device(usb_backend, pdev); 308ccef4ddfSAndrew Thompson 3098c8fff31SAndrew Thompson memset(dev, 0, sizeof(*dev)); 3108c8fff31SAndrew Thompson 311390065b1SAlfred Perlstein /* init transfer queues */ 312390065b1SAlfred Perlstein TAILQ_INIT(&dev->tr_head); 313390065b1SAlfred Perlstein 314390065b1SAlfred Perlstein /* set context we belong to */ 3158c8fff31SAndrew Thompson dev->ctx = ctx; 3168c8fff31SAndrew Thompson 3178c8fff31SAndrew Thompson /* link together the two structures */ 3188c8fff31SAndrew Thompson dev->os_priv = pdev; 319390065b1SAlfred Perlstein pdev->privLuData = dev; 3208c8fff31SAndrew Thompson 3218c8fff31SAndrew Thompson (*list)[i] = libusb_ref_device(dev); 3228c8fff31SAndrew Thompson i++; 3238c8fff31SAndrew Thompson } 3248c8fff31SAndrew Thompson (*list)[i] = NULL; 3258c8fff31SAndrew Thompson 3268c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 3278c8fff31SAndrew Thompson return (i); 3288c8fff31SAndrew Thompson } 3298c8fff31SAndrew Thompson 3308c8fff31SAndrew Thompson void 3318c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices) 3328c8fff31SAndrew Thompson { 3338c8fff31SAndrew Thompson int i; 3348c8fff31SAndrew Thompson 3358c8fff31SAndrew Thompson if (list == NULL) 336390065b1SAlfred Perlstein return; /* be NULL safe */ 3378c8fff31SAndrew Thompson 3388c8fff31SAndrew Thompson if (unref_devices) { 3398c8fff31SAndrew Thompson for (i = 0; list[i] != NULL; i++) 3408c8fff31SAndrew Thompson libusb_unref_device(list[i]); 3418c8fff31SAndrew Thompson } 3428c8fff31SAndrew Thompson free(list); 3438c8fff31SAndrew Thompson } 3448c8fff31SAndrew Thompson 3458c8fff31SAndrew Thompson uint8_t 3468c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device *dev) 3478c8fff31SAndrew Thompson { 3488c8fff31SAndrew Thompson if (dev == NULL) 349390065b1SAlfred Perlstein return (0); /* should not happen */ 350390065b1SAlfred Perlstein return (libusb20_dev_get_bus_number(dev->os_priv)); 3518c8fff31SAndrew Thompson } 3528c8fff31SAndrew Thompson 3530f2c7066SHans Petter Selasky uint8_t 3540f2c7066SHans Petter Selasky libusb_get_port_number(libusb_device *dev) 3550f2c7066SHans Petter Selasky { 3560f2c7066SHans Petter Selasky if (dev == NULL) 3570f2c7066SHans Petter Selasky return (0); /* should not happen */ 3580f2c7066SHans Petter Selasky return (libusb20_dev_get_parent_port(dev->os_priv)); 3590f2c7066SHans Petter Selasky } 3600f2c7066SHans Petter Selasky 3615906bf49SEd Maste int 362a9205626SEd Maste libusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize) 363a9205626SEd Maste { 364a9205626SEd Maste return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize)); 365a9205626SEd Maste } 366a9205626SEd Maste 367a9205626SEd Maste int 3685906bf49SEd Maste libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t *buf, 3695906bf49SEd Maste uint8_t bufsize) 3705906bf49SEd Maste { 3715906bf49SEd Maste return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize)); 3725906bf49SEd Maste } 3735906bf49SEd Maste 3748c8fff31SAndrew Thompson uint8_t 3758c8fff31SAndrew Thompson libusb_get_device_address(libusb_device *dev) 3768c8fff31SAndrew Thompson { 3778c8fff31SAndrew Thompson if (dev == NULL) 378390065b1SAlfred Perlstein return (0); /* should not happen */ 379390065b1SAlfred Perlstein return (libusb20_dev_get_address(dev->os_priv)); 3808c8fff31SAndrew Thompson } 3818c8fff31SAndrew Thompson 3829a46d467SHans Petter Selasky enum libusb_speed 3839a46d467SHans Petter Selasky libusb_get_device_speed(libusb_device *dev) 3849a46d467SHans Petter Selasky { 3859a46d467SHans Petter Selasky if (dev == NULL) 38633ec9f0cSHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); /* should not happen */ 3879a46d467SHans Petter Selasky 3889a46d467SHans Petter Selasky switch (libusb20_dev_get_speed(dev->os_priv)) { 3899a46d467SHans Petter Selasky case LIBUSB20_SPEED_LOW: 3909a46d467SHans Petter Selasky return (LIBUSB_SPEED_LOW); 3919a46d467SHans Petter Selasky case LIBUSB20_SPEED_FULL: 3929a46d467SHans Petter Selasky return (LIBUSB_SPEED_FULL); 3939a46d467SHans Petter Selasky case LIBUSB20_SPEED_HIGH: 3949a46d467SHans Petter Selasky return (LIBUSB_SPEED_HIGH); 3959a46d467SHans Petter Selasky case LIBUSB20_SPEED_SUPER: 3969a46d467SHans Petter Selasky return (LIBUSB_SPEED_SUPER); 3979a46d467SHans Petter Selasky default: 3989a46d467SHans Petter Selasky break; 3999a46d467SHans Petter Selasky } 4009a46d467SHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); 4019a46d467SHans Petter Selasky } 4029a46d467SHans Petter Selasky 4038c8fff31SAndrew Thompson int 404390065b1SAlfred Perlstein libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 4058c8fff31SAndrew Thompson { 4068c8fff31SAndrew Thompson struct libusb_config_descriptor *pdconf; 4078c8fff31SAndrew Thompson struct libusb_interface *pinf; 4088c8fff31SAndrew Thompson struct libusb_interface_descriptor *pdinf; 4098c8fff31SAndrew Thompson struct libusb_endpoint_descriptor *pdend; 410390065b1SAlfred Perlstein int i; 411390065b1SAlfred Perlstein int j; 412390065b1SAlfred Perlstein int k; 413390065b1SAlfred Perlstein int ret; 4148c8fff31SAndrew Thompson 4158c8fff31SAndrew Thompson if (dev == NULL) 4168c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 4178c8fff31SAndrew Thompson 418390065b1SAlfred Perlstein ret = libusb_get_active_config_descriptor(dev, &pdconf); 419390065b1SAlfred Perlstein if (ret < 0) 420390065b1SAlfred Perlstein return (ret); 4218c8fff31SAndrew Thompson 4228c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 4238c8fff31SAndrew Thompson for (i = 0; i < pdconf->bNumInterfaces; i++) { 4248c8fff31SAndrew Thompson pinf = &pdconf->interface[i]; 4258c8fff31SAndrew Thompson for (j = 0; j < pinf->num_altsetting; j++) { 4268c8fff31SAndrew Thompson pdinf = &pinf->altsetting[j]; 4278c8fff31SAndrew Thompson for (k = 0; k < pdinf->bNumEndpoints; k++) { 4288c8fff31SAndrew Thompson pdend = &pdinf->endpoint[k]; 4298c8fff31SAndrew Thompson if (pdend->bEndpointAddress == endpoint) { 4308c8fff31SAndrew Thompson ret = pdend->wMaxPacketSize; 4318c8fff31SAndrew Thompson goto out; 4328c8fff31SAndrew Thompson } 4338c8fff31SAndrew Thompson } 4348c8fff31SAndrew Thompson } 4358c8fff31SAndrew Thompson } 4368c8fff31SAndrew Thompson 4378c8fff31SAndrew Thompson out: 4388c8fff31SAndrew Thompson libusb_free_config_descriptor(pdconf); 4398c8fff31SAndrew Thompson return (ret); 4408c8fff31SAndrew Thompson } 4418c8fff31SAndrew Thompson 442748205a3SHans Petter Selasky int 443748205a3SHans Petter Selasky libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint) 444748205a3SHans Petter Selasky { 445748205a3SHans Petter Selasky int multiplier; 446748205a3SHans Petter Selasky int ret; 447748205a3SHans Petter Selasky 448748205a3SHans Petter Selasky ret = libusb_get_max_packet_size(dev, endpoint); 449748205a3SHans Petter Selasky 450748205a3SHans Petter Selasky switch (libusb20_dev_get_speed(dev->os_priv)) { 451748205a3SHans Petter Selasky case LIBUSB20_SPEED_LOW: 452748205a3SHans Petter Selasky case LIBUSB20_SPEED_FULL: 453748205a3SHans Petter Selasky break; 454748205a3SHans Petter Selasky default: 455748205a3SHans Petter Selasky if (ret > -1) { 456748205a3SHans Petter Selasky multiplier = (1 + ((ret >> 11) & 3)); 457748205a3SHans Petter Selasky if (multiplier > 3) 458748205a3SHans Petter Selasky multiplier = 3; 459748205a3SHans Petter Selasky ret = (ret & 0x7FF) * multiplier; 460748205a3SHans Petter Selasky } 461748205a3SHans Petter Selasky break; 462748205a3SHans Petter Selasky } 463748205a3SHans Petter Selasky return (ret); 464748205a3SHans Petter Selasky } 465748205a3SHans Petter Selasky 4668c8fff31SAndrew Thompson libusb_device * 4678c8fff31SAndrew Thompson libusb_ref_device(libusb_device *dev) 4688c8fff31SAndrew Thompson { 4698c8fff31SAndrew Thompson if (dev == NULL) 470390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 4718c8fff31SAndrew Thompson 472390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 4738c8fff31SAndrew Thompson dev->refcnt++; 474390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 4758c8fff31SAndrew Thompson 4768c8fff31SAndrew Thompson return (dev); 4778c8fff31SAndrew Thompson } 4788c8fff31SAndrew Thompson 4798c8fff31SAndrew Thompson void 4808c8fff31SAndrew Thompson libusb_unref_device(libusb_device *dev) 4818c8fff31SAndrew Thompson { 4828c8fff31SAndrew Thompson if (dev == NULL) 483390065b1SAlfred Perlstein return; /* be NULL safe */ 4848c8fff31SAndrew Thompson 485390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 4868c8fff31SAndrew Thompson dev->refcnt--; 487390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 4888c8fff31SAndrew Thompson 4898c8fff31SAndrew Thompson if (dev->refcnt == 0) { 4908c8fff31SAndrew Thompson libusb20_dev_free(dev->os_priv); 4918c8fff31SAndrew Thompson free(dev); 4928c8fff31SAndrew Thompson } 4938c8fff31SAndrew Thompson } 4948c8fff31SAndrew Thompson 4958c8fff31SAndrew Thompson int 4968c8fff31SAndrew Thompson libusb_open(libusb_device *dev, libusb_device_handle **devh) 4978c8fff31SAndrew Thompson { 4988c8fff31SAndrew Thompson libusb_context *ctx = dev->ctx; 4998c8fff31SAndrew Thompson struct libusb20_device *pdev = dev->os_priv; 5008c8fff31SAndrew Thompson int err; 5018c8fff31SAndrew Thompson 5028c8fff31SAndrew Thompson if (devh == NULL) 5038c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5048c8fff31SAndrew Thompson 505390065b1SAlfred Perlstein /* set default device handle value */ 506390065b1SAlfred Perlstein *devh = NULL; 507390065b1SAlfred Perlstein 508390065b1SAlfred Perlstein dev = libusb_ref_device(dev); 509390065b1SAlfred Perlstein if (dev == NULL) 510390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 5118c8fff31SAndrew Thompson 51290988efdSHans Petter Selasky err = libusb20_dev_open(pdev, LIBUSB_NUM_SW_ENDPOINTS); 5138c8fff31SAndrew Thompson if (err) { 514390065b1SAlfred Perlstein libusb_unref_device(dev); 5158c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 5168c8fff31SAndrew Thompson } 517390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 5188c8fff31SAndrew Thompson POLLOUT | POLLRDNORM | POLLWRNORM); 5198c8fff31SAndrew Thompson 520390065b1SAlfred Perlstein /* make sure our event loop detects the new device */ 521540c7229SHans Petter Selasky libusb10_wakeup_event_loop(ctx); 522540c7229SHans Petter Selasky 523390065b1SAlfred Perlstein *devh = pdev; 5248c8fff31SAndrew Thompson 5258c8fff31SAndrew Thompson return (0); 5268c8fff31SAndrew Thompson } 5278c8fff31SAndrew Thompson 5288c8fff31SAndrew Thompson libusb_device_handle * 5298c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 5308c8fff31SAndrew Thompson uint16_t product_id) 5318c8fff31SAndrew Thompson { 5328c8fff31SAndrew Thompson struct libusb_device **devs; 5338c8fff31SAndrew Thompson struct libusb20_device *pdev; 5348c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 535390065b1SAlfred Perlstein int i; 536390065b1SAlfred Perlstein int j; 5378c8fff31SAndrew Thompson 538390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 539390065b1SAlfred Perlstein if (ctx == NULL) 540390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 541390065b1SAlfred Perlstein 542*1efeb40dSHans Petter Selasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid enter"); 5438c8fff31SAndrew Thompson 5448c8fff31SAndrew Thompson if ((i = libusb_get_device_list(ctx, &devs)) < 0) 5458c8fff31SAndrew Thompson return (NULL); 5468c8fff31SAndrew Thompson 5473f709d07SHans Petter Selasky pdev = NULL; 5488c8fff31SAndrew Thompson for (j = 0; j < i; j++) { 5493f709d07SHans Petter Selasky struct libusb20_device *tdev; 5503f709d07SHans Petter Selasky 5513f709d07SHans Petter Selasky tdev = devs[j]->os_priv; 5523f709d07SHans Petter Selasky pdesc = libusb20_dev_get_device_desc(tdev); 553390065b1SAlfred Perlstein /* 554390065b1SAlfred Perlstein * NOTE: The USB library will automatically swap the 555390065b1SAlfred Perlstein * fields in the device descriptor to be of host 556390065b1SAlfred Perlstein * endian type! 557390065b1SAlfred Perlstein */ 5588c8fff31SAndrew Thompson if (pdesc->idVendor == vendor_id && 559c500e4ddSAndrew Thompson pdesc->idProduct == product_id) { 560dc934803SHans Petter Selasky libusb_open(devs[j], &pdev); 561c500e4ddSAndrew Thompson break; 562c500e4ddSAndrew Thompson } 5638c8fff31SAndrew Thompson } 5648c8fff31SAndrew Thompson 5658c8fff31SAndrew Thompson libusb_free_device_list(devs, 1); 566*1efeb40dSHans Petter Selasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid leave"); 567390065b1SAlfred Perlstein return (pdev); 5688c8fff31SAndrew Thompson } 5698c8fff31SAndrew Thompson 5708c8fff31SAndrew Thompson void 571390065b1SAlfred Perlstein libusb_close(struct libusb20_device *pdev) 5728c8fff31SAndrew Thompson { 5738c8fff31SAndrew Thompson libusb_context *ctx; 574390065b1SAlfred Perlstein struct libusb_device *dev; 5758c8fff31SAndrew Thompson 576390065b1SAlfred Perlstein if (pdev == NULL) 577390065b1SAlfred Perlstein return; /* be NULL safe */ 5788c8fff31SAndrew Thompson 579390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 580390065b1SAlfred Perlstein ctx = dev->ctx; 5818c8fff31SAndrew Thompson 582390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &dev->dev_poll); 5838c8fff31SAndrew Thompson 584390065b1SAlfred Perlstein libusb20_dev_close(pdev); 585ccef4ddfSAndrew Thompson 586ccef4ddfSAndrew Thompson /* unref will free the "pdev" when the refcount reaches zero */ 587390065b1SAlfred Perlstein libusb_unref_device(dev); 5888c8fff31SAndrew Thompson 589390065b1SAlfred Perlstein /* make sure our event loop detects the closed device */ 590540c7229SHans Petter Selasky libusb10_wakeup_event_loop(ctx); 5918c8fff31SAndrew Thompson } 5928c8fff31SAndrew Thompson 5938c8fff31SAndrew Thompson libusb_device * 594390065b1SAlfred Perlstein libusb_get_device(struct libusb20_device *pdev) 5958c8fff31SAndrew Thompson { 596390065b1SAlfred Perlstein if (pdev == NULL) 5978c8fff31SAndrew Thompson return (NULL); 598390065b1SAlfred Perlstein return ((libusb_device *)pdev->privLuData); 5998c8fff31SAndrew Thompson } 6008c8fff31SAndrew Thompson 6018c8fff31SAndrew Thompson int 602390065b1SAlfred Perlstein libusb_get_configuration(struct libusb20_device *pdev, int *config) 6038c8fff31SAndrew Thompson { 604390065b1SAlfred Perlstein struct libusb20_config *pconf; 6058c8fff31SAndrew Thompson 606390065b1SAlfred Perlstein if (pdev == NULL || config == NULL) 6078c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6088c8fff31SAndrew Thompson 609390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 610390065b1SAlfred Perlstein if (pconf == NULL) 611c500e4ddSAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 6128c8fff31SAndrew Thompson 613390065b1SAlfred Perlstein *config = pconf->desc.bConfigurationValue; 6148c8fff31SAndrew Thompson 615390065b1SAlfred Perlstein free(pconf); 6168c8fff31SAndrew Thompson 6178c8fff31SAndrew Thompson return (0); 6188c8fff31SAndrew Thompson } 6198c8fff31SAndrew Thompson 6208c8fff31SAndrew Thompson int 621390065b1SAlfred Perlstein libusb_set_configuration(struct libusb20_device *pdev, int configuration) 6228c8fff31SAndrew Thompson { 623390065b1SAlfred Perlstein struct libusb20_config *pconf; 624390065b1SAlfred Perlstein struct libusb_device *dev; 625390065b1SAlfred Perlstein int err; 626390065b1SAlfred Perlstein uint8_t i; 6278c8fff31SAndrew Thompson 628390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 6298c8fff31SAndrew Thompson if (dev == NULL) 630390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 631390065b1SAlfred Perlstein 632390065b1SAlfred Perlstein if (configuration < 1) { 633390065b1SAlfred Perlstein /* unconfigure */ 634390065b1SAlfred Perlstein i = 255; 635390065b1SAlfred Perlstein } else { 636390065b1SAlfred Perlstein for (i = 0; i != 255; i++) { 637390065b1SAlfred Perlstein uint8_t found; 638390065b1SAlfred Perlstein 639390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, i); 640390065b1SAlfred Perlstein if (pconf == NULL) 641390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 642390065b1SAlfred Perlstein found = (pconf->desc.bConfigurationValue 643390065b1SAlfred Perlstein == configuration); 644390065b1SAlfred Perlstein free(pconf); 645390065b1SAlfred Perlstein 646390065b1SAlfred Perlstein if (found) 647390065b1SAlfred Perlstein goto set_config; 648390065b1SAlfred Perlstein } 649390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 650390065b1SAlfred Perlstein } 651390065b1SAlfred Perlstein 652390065b1SAlfred Perlstein set_config: 653390065b1SAlfred Perlstein 654390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 655390065b1SAlfred Perlstein 656390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 657390065b1SAlfred Perlstein 658390065b1SAlfred Perlstein err = libusb20_dev_set_config_index(pdev, i); 659390065b1SAlfred Perlstein 660390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 661390065b1SAlfred Perlstein POLLOUT | POLLRDNORM | POLLWRNORM); 662390065b1SAlfred Perlstein 663390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 664390065b1SAlfred Perlstein } 665390065b1SAlfred Perlstein 666390065b1SAlfred Perlstein int 667390065b1SAlfred Perlstein libusb_claim_interface(struct libusb20_device *pdev, int interface_number) 668390065b1SAlfred Perlstein { 669390065b1SAlfred Perlstein libusb_device *dev; 6705b40d960SHans Petter Selasky int err = 0; 671390065b1SAlfred Perlstein 672390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 673390065b1SAlfred Perlstein if (dev == NULL) 674390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 675390065b1SAlfred Perlstein 676390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 677390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 678390065b1SAlfred Perlstein 6795b40d960SHans Petter Selasky if (pdev->auto_detach != 0) { 6805b40d960SHans Petter Selasky err = libusb_detach_kernel_driver(pdev, interface_number); 6815b40d960SHans Petter Selasky if (err != 0) 6825b40d960SHans Petter Selasky goto done; 6835b40d960SHans Petter Selasky } 6845b40d960SHans Petter Selasky 685390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 686390065b1SAlfred Perlstein dev->claimed_interfaces |= (1 << interface_number); 687390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 6885b40d960SHans Petter Selasky done: 6895b40d960SHans Petter Selasky return (err); 690390065b1SAlfred Perlstein } 691390065b1SAlfred Perlstein 692390065b1SAlfred Perlstein int 693390065b1SAlfred Perlstein libusb_release_interface(struct libusb20_device *pdev, int interface_number) 694390065b1SAlfred Perlstein { 695390065b1SAlfred Perlstein libusb_device *dev; 696390065b1SAlfred Perlstein int err = 0; 697390065b1SAlfred Perlstein 698390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 699390065b1SAlfred Perlstein if (dev == NULL) 700390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 701390065b1SAlfred Perlstein 702390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 703390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 704390065b1SAlfred Perlstein 7055b40d960SHans Petter Selasky if (pdev->auto_detach != 0) { 7065b40d960SHans Petter Selasky err = libusb_attach_kernel_driver(pdev, interface_number); 7075b40d960SHans Petter Selasky if (err != 0) 7085b40d960SHans Petter Selasky goto done; 7095b40d960SHans Petter Selasky } 7105b40d960SHans Petter Selasky 711390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 712390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 713390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 7145b40d960SHans Petter Selasky else 715390065b1SAlfred Perlstein dev->claimed_interfaces &= ~(1 << interface_number); 716390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 7175b40d960SHans Petter Selasky done: 718390065b1SAlfred Perlstein return (err); 719390065b1SAlfred Perlstein } 720390065b1SAlfred Perlstein 721390065b1SAlfred Perlstein int 722390065b1SAlfred Perlstein libusb_set_interface_alt_setting(struct libusb20_device *pdev, 723390065b1SAlfred Perlstein int interface_number, int alternate_setting) 724390065b1SAlfred Perlstein { 725390065b1SAlfred Perlstein libusb_device *dev; 726390065b1SAlfred Perlstein int err = 0; 727390065b1SAlfred Perlstein 728390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 729390065b1SAlfred Perlstein if (dev == NULL) 730390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 731390065b1SAlfred Perlstein 732390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 733390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 734390065b1SAlfred Perlstein 735390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 736390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 737390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 738390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 739390065b1SAlfred Perlstein 740390065b1SAlfred Perlstein if (err) 741390065b1SAlfred Perlstein return (err); 742390065b1SAlfred Perlstein 743390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 744390065b1SAlfred Perlstein 745390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 746390065b1SAlfred Perlstein 747390065b1SAlfred Perlstein err = libusb20_dev_set_alt_index(pdev, 748390065b1SAlfred Perlstein interface_number, alternate_setting); 749390065b1SAlfred Perlstein 750390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 751390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 752390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 753390065b1SAlfred Perlstein 754390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 755390065b1SAlfred Perlstein } 756390065b1SAlfred Perlstein 757390065b1SAlfred Perlstein static struct libusb20_transfer * 758390065b1SAlfred Perlstein libusb10_get_transfer(struct libusb20_device *pdev, 759d81535d1SHans Petter Selasky uint8_t endpoint, uint8_t xfer_index) 760390065b1SAlfred Perlstein { 761d81535d1SHans Petter Selasky xfer_index &= 1; /* double buffering */ 762390065b1SAlfred Perlstein 763d81535d1SHans Petter Selasky xfer_index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 764390065b1SAlfred Perlstein 765390065b1SAlfred Perlstein if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 766390065b1SAlfred Perlstein /* this is an IN endpoint */ 767d81535d1SHans Petter Selasky xfer_index |= 2; 768390065b1SAlfred Perlstein } 769d81535d1SHans Petter Selasky return (libusb20_tr_get_pointer(pdev, xfer_index)); 770390065b1SAlfred Perlstein } 771390065b1SAlfred Perlstein 772390065b1SAlfred Perlstein int 773390065b1SAlfred Perlstein libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 774390065b1SAlfred Perlstein { 775390065b1SAlfred Perlstein struct libusb20_transfer *xfer; 776390065b1SAlfred Perlstein struct libusb_device *dev; 777390065b1SAlfred Perlstein int err; 778390065b1SAlfred Perlstein 779390065b1SAlfred Perlstein xfer = libusb10_get_transfer(pdev, endpoint, 0); 780390065b1SAlfred Perlstein if (xfer == NULL) 781390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 782390065b1SAlfred Perlstein 783390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 784698e791aSHans Petter Selasky if (dev == NULL) 785698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 786390065b1SAlfred Perlstein 787390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 788a7e048a2SHans Petter Selasky err = libusb20_tr_open(xfer, 0, 1, endpoint); 789390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 790390065b1SAlfred Perlstein 791390065b1SAlfred Perlstein if (err != 0 && err != LIBUSB20_ERROR_BUSY) 792390065b1SAlfred Perlstein return (LIBUSB_ERROR_OTHER); 793390065b1SAlfred Perlstein 794390065b1SAlfred Perlstein libusb20_tr_clear_stall_sync(xfer); 795390065b1SAlfred Perlstein 796390065b1SAlfred Perlstein /* check if we opened the transfer */ 797390065b1SAlfred Perlstein if (err == 0) { 798390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 799390065b1SAlfred Perlstein libusb20_tr_close(xfer); 800390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 801390065b1SAlfred Perlstein } 802390065b1SAlfred Perlstein return (0); /* success */ 803390065b1SAlfred Perlstein } 804390065b1SAlfred Perlstein 805390065b1SAlfred Perlstein int 806390065b1SAlfred Perlstein libusb_reset_device(struct libusb20_device *pdev) 807390065b1SAlfred Perlstein { 808390065b1SAlfred Perlstein libusb_device *dev; 809390065b1SAlfred Perlstein int err; 810390065b1SAlfred Perlstein 811390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 812390065b1SAlfred Perlstein if (dev == NULL) 813698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 8148c8fff31SAndrew Thompson 815390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 816390065b1SAlfred Perlstein 817390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 818390065b1SAlfred Perlstein 819390065b1SAlfred Perlstein err = libusb20_dev_reset(pdev); 820390065b1SAlfred Perlstein 821390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 822390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 823390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 824390065b1SAlfred Perlstein 825390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 8268c8fff31SAndrew Thompson } 8278c8fff31SAndrew Thompson 8288c8fff31SAndrew Thompson int 829f1b5fa6eSHans Petter Selasky libusb_check_connected(struct libusb20_device *pdev) 830f1b5fa6eSHans Petter Selasky { 831f1b5fa6eSHans Petter Selasky libusb_device *dev; 832f1b5fa6eSHans Petter Selasky int err; 833f1b5fa6eSHans Petter Selasky 834f1b5fa6eSHans Petter Selasky dev = libusb_get_device(pdev); 835f1b5fa6eSHans Petter Selasky if (dev == NULL) 836f1b5fa6eSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 837f1b5fa6eSHans Petter Selasky 838f1b5fa6eSHans Petter Selasky err = libusb20_dev_check_connected(pdev); 839f1b5fa6eSHans Petter Selasky 840f1b5fa6eSHans Petter Selasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 841f1b5fa6eSHans Petter Selasky } 842f1b5fa6eSHans Petter Selasky 843f1b5fa6eSHans Petter Selasky int 844390065b1SAlfred Perlstein libusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 8458c8fff31SAndrew Thompson { 846390065b1SAlfred Perlstein if (pdev == NULL) 8478c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 8488c8fff31SAndrew Thompson 8494d2472aaSHans Petter Selasky if (libusb20_dev_kernel_driver_active(pdev, interface)) 8504d2472aaSHans Petter Selasky return (0); /* no kernel driver is active */ 8514d2472aaSHans Petter Selasky else 8524d2472aaSHans Petter Selasky return (1); /* kernel driver is active */ 8538c8fff31SAndrew Thompson } 8548c8fff31SAndrew Thompson 8558c8fff31SAndrew Thompson int 856698e791aSHans Petter Selasky libusb_get_driver_np(struct libusb20_device *pdev, int interface, 857698e791aSHans Petter Selasky char *name, int namelen) 858698e791aSHans Petter Selasky { 859698e791aSHans Petter Selasky return (libusb_get_driver(pdev, interface, name, namelen)); 860698e791aSHans Petter Selasky } 861698e791aSHans Petter Selasky 862698e791aSHans Petter Selasky int 863698e791aSHans Petter Selasky libusb_get_driver(struct libusb20_device *pdev, int interface, 864698e791aSHans Petter Selasky char *name, int namelen) 865698e791aSHans Petter Selasky { 866698e791aSHans Petter Selasky char *ptr; 867698e791aSHans Petter Selasky int err; 868698e791aSHans Petter Selasky 869698e791aSHans Petter Selasky if (pdev == NULL) 870698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 871698e791aSHans Petter Selasky if (namelen < 1) 872698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 8734eb5923dSHans Petter Selasky if (namelen > 255) 8744eb5923dSHans Petter Selasky namelen = 255; 875698e791aSHans Petter Selasky 876698e791aSHans Petter Selasky err = libusb20_dev_get_iface_desc( 877698e791aSHans Petter Selasky pdev, interface, name, namelen); 878698e791aSHans Petter Selasky 879698e791aSHans Petter Selasky if (err != 0) 880698e791aSHans Petter Selasky return (LIBUSB_ERROR_OTHER); 881698e791aSHans Petter Selasky 882698e791aSHans Petter Selasky /* we only want the driver name */ 883698e791aSHans Petter Selasky ptr = strstr(name, ":"); 884698e791aSHans Petter Selasky if (ptr != NULL) 885698e791aSHans Petter Selasky *ptr = 0; 886698e791aSHans Petter Selasky 887698e791aSHans Petter Selasky return (0); 888698e791aSHans Petter Selasky } 889698e791aSHans Petter Selasky 890698e791aSHans Petter Selasky int 891698e791aSHans Petter Selasky libusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface) 892698e791aSHans Petter Selasky { 893698e791aSHans Petter Selasky return (libusb_detach_kernel_driver(pdev, interface)); 894698e791aSHans Petter Selasky } 895698e791aSHans Petter Selasky 896698e791aSHans Petter Selasky int 897390065b1SAlfred Perlstein libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 8988c8fff31SAndrew Thompson { 899390065b1SAlfred Perlstein int err; 9008c8fff31SAndrew Thompson 901390065b1SAlfred Perlstein if (pdev == NULL) 9028c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 9038c8fff31SAndrew Thompson 904390065b1SAlfred Perlstein err = libusb20_dev_detach_kernel_driver( 905390065b1SAlfred Perlstein pdev, interface); 9068c8fff31SAndrew Thompson 907698e791aSHans Petter Selasky return (err ? LIBUSB_ERROR_OTHER : 0); 9088c8fff31SAndrew Thompson } 9098c8fff31SAndrew Thompson 9108c8fff31SAndrew Thompson int 911390065b1SAlfred Perlstein libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 9128c8fff31SAndrew Thompson { 913390065b1SAlfred Perlstein if (pdev == NULL) 9148c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 915390065b1SAlfred Perlstein /* stub - currently not supported by libusb20 */ 9168c8fff31SAndrew Thompson return (0); 9178c8fff31SAndrew Thompson } 9188c8fff31SAndrew Thompson 9195b40d960SHans Petter Selasky int 9205b40d960SHans Petter Selasky libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable) 9215b40d960SHans Petter Selasky { 9225b40d960SHans Petter Selasky dev->auto_detach = (enable ? 1 : 0); 923a3d81a8aSHans Petter Selasky return (0); 9245b40d960SHans Petter Selasky } 9255b40d960SHans Petter Selasky 9268c8fff31SAndrew Thompson /* Asynchronous device I/O */ 9278c8fff31SAndrew Thompson 9288c8fff31SAndrew Thompson struct libusb_transfer * 9298c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets) 9308c8fff31SAndrew Thompson { 931390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 932390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 9338c8fff31SAndrew Thompson int len; 9348c8fff31SAndrew Thompson 9358c8fff31SAndrew Thompson len = sizeof(struct libusb_transfer) + 936390065b1SAlfred Perlstein sizeof(struct libusb_super_transfer) + 9378c8fff31SAndrew Thompson (iso_packets * sizeof(libusb_iso_packet_descriptor)); 9388c8fff31SAndrew Thompson 939390065b1SAlfred Perlstein sxfer = malloc(len); 940390065b1SAlfred Perlstein if (sxfer == NULL) 9418c8fff31SAndrew Thompson return (NULL); 9428c8fff31SAndrew Thompson 943390065b1SAlfred Perlstein memset(sxfer, 0, len); 9448c8fff31SAndrew Thompson 945390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 946390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 9478c8fff31SAndrew Thompson 948390065b1SAlfred Perlstein /* set default value */ 949390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 950390065b1SAlfred Perlstein 951390065b1SAlfred Perlstein return (uxfer); 9528c8fff31SAndrew Thompson } 9538c8fff31SAndrew Thompson 9548c8fff31SAndrew Thompson void 955390065b1SAlfred Perlstein libusb_free_transfer(struct libusb_transfer *uxfer) 9568c8fff31SAndrew Thompson { 957390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 9588c8fff31SAndrew Thompson 959390065b1SAlfred Perlstein if (uxfer == NULL) 960390065b1SAlfred Perlstein return; /* be NULL safe */ 9618c8fff31SAndrew Thompson 96231f7072cSHans Petter Selasky /* check if we should free the transfer buffer */ 96331f7072cSHans Petter Selasky if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) 96431f7072cSHans Petter Selasky free(uxfer->buffer); 96531f7072cSHans Petter Selasky 966390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 967390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 9688c8fff31SAndrew Thompson 969390065b1SAlfred Perlstein free(sxfer); 9708c8fff31SAndrew Thompson } 9718c8fff31SAndrew Thompson 9721c497368SHans Petter Selasky static uint32_t 973390065b1SAlfred Perlstein libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 9748c8fff31SAndrew Thompson { 9751c497368SHans Petter Selasky uint32_t ret; 9768c8fff31SAndrew Thompson 9778c8fff31SAndrew Thompson switch (xfer->type) { 9788c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 9791c497368SHans Petter Selasky ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */ 9808c8fff31SAndrew Thompson break; 9818c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 9828c8fff31SAndrew Thompson ret = 2; 9838c8fff31SAndrew Thompson break; 9848c8fff31SAndrew Thompson default: 9858c8fff31SAndrew Thompson ret = 1; 9868c8fff31SAndrew Thompson break; 9878c8fff31SAndrew Thompson } 988390065b1SAlfred Perlstein return (ret); 9898c8fff31SAndrew Thompson } 9908c8fff31SAndrew Thompson 9918c8fff31SAndrew Thompson static int 992390065b1SAlfred Perlstein libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 9938c8fff31SAndrew Thompson { 9948c8fff31SAndrew Thompson int ret; 9958c8fff31SAndrew Thompson int usb_speed; 9968c8fff31SAndrew Thompson 9978c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 9988c8fff31SAndrew Thompson 9998c8fff31SAndrew Thompson switch (xfer->type) { 10008c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1001390065b1SAlfred Perlstein ret = 0; /* kernel will auto-select */ 10028c8fff31SAndrew Thompson break; 10038c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 1004390065b1SAlfred Perlstein ret = 1024; 10058c8fff31SAndrew Thompson break; 10068c8fff31SAndrew Thompson default: 10078c8fff31SAndrew Thompson switch (usb_speed) { 10088c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 10098c8fff31SAndrew Thompson ret = 256; 10108c8fff31SAndrew Thompson break; 10118c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 10128c8fff31SAndrew Thompson ret = 4096; 10138c8fff31SAndrew Thompson break; 1014f355a4ddSHans Petter Selasky case LIBUSB20_SPEED_SUPER: 1015f355a4ddSHans Petter Selasky ret = 65536; 1016f355a4ddSHans Petter Selasky break; 10178c8fff31SAndrew Thompson default: 10188c8fff31SAndrew Thompson ret = 16384; 10198c8fff31SAndrew Thompson break; 10208c8fff31SAndrew Thompson } 10218c8fff31SAndrew Thompson break; 10228c8fff31SAndrew Thompson } 1023390065b1SAlfred Perlstein return (ret); 10248c8fff31SAndrew Thompson } 10258c8fff31SAndrew Thompson 1026390065b1SAlfred Perlstein static int 1027390065b1SAlfred Perlstein libusb10_convert_error(uint8_t status) 1028390065b1SAlfred Perlstein { 1029390065b1SAlfred Perlstein ; /* indent fix */ 1030390065b1SAlfred Perlstein 1031390065b1SAlfred Perlstein switch (status) { 1032390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1033390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1034390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_COMPLETED); 1035390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_OVERFLOW: 1036390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_OVERFLOW); 1037390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_NO_DEVICE: 1038390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_NO_DEVICE); 1039390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_STALL: 1040390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_STALL); 1041390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_CANCELLED: 1042390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_CANCELLED); 1043390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_TIMED_OUT: 1044390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_TIMED_OUT); 1045390065b1SAlfred Perlstein default: 1046390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_ERROR); 1047390065b1SAlfred Perlstein } 1048390065b1SAlfred Perlstein } 1049390065b1SAlfred Perlstein 1050390065b1SAlfred Perlstein /* This function must be called locked */ 1051390065b1SAlfred Perlstein 1052c500e4ddSAndrew Thompson static void 1053390065b1SAlfred Perlstein libusb10_complete_transfer(struct libusb20_transfer *pxfer, 1054390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer, int status) 1055c500e4ddSAndrew Thompson { 1056390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1057390065b1SAlfred Perlstein struct libusb_device *dev; 1058c500e4ddSAndrew Thompson 1059390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1060390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1061390065b1SAlfred Perlstein 1062390065b1SAlfred Perlstein if (pxfer != NULL) 1063390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer, NULL); 1064390065b1SAlfred Perlstein 10654594d907SAndrew Thompson /* set transfer status */ 1066390065b1SAlfred Perlstein uxfer->status = status; 1067390065b1SAlfred Perlstein 10684594d907SAndrew Thompson /* update super transfer state */ 10694594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 10704594d907SAndrew Thompson 1071390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 1072390065b1SAlfred Perlstein 1073390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 1074390065b1SAlfred Perlstein } 1075390065b1SAlfred Perlstein 1076390065b1SAlfred Perlstein /* This function must be called locked */ 1077390065b1SAlfred Perlstein 1078390065b1SAlfred Perlstein static void 1079390065b1SAlfred Perlstein libusb10_isoc_proxy(struct libusb20_transfer *pxfer) 1080390065b1SAlfred Perlstein { 1081390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1082390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1083390065b1SAlfred Perlstein uint32_t actlen; 1084390065b1SAlfred Perlstein uint16_t iso_packets; 1085390065b1SAlfred Perlstein uint16_t i; 1086390065b1SAlfred Perlstein uint8_t status; 1087390065b1SAlfred Perlstein 1088390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1089390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1090390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1091390065b1SAlfred Perlstein iso_packets = libusb20_tr_get_max_frames(pxfer); 1092390065b1SAlfred Perlstein 1093390065b1SAlfred Perlstein if (sxfer == NULL) 1094390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1095390065b1SAlfred Perlstein 1096390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1097390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1098390065b1SAlfred Perlstein 1099390065b1SAlfred Perlstein if (iso_packets > uxfer->num_iso_packets) 1100390065b1SAlfred Perlstein iso_packets = uxfer->num_iso_packets; 1101390065b1SAlfred Perlstein 1102390065b1SAlfred Perlstein if (iso_packets == 0) 1103390065b1SAlfred Perlstein return; /* nothing to do */ 1104390065b1SAlfred Perlstein 1105390065b1SAlfred Perlstein /* make sure that the number of ISOCHRONOUS packets is valid */ 1106390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 1107390065b1SAlfred Perlstein 1108c500e4ddSAndrew Thompson switch (status) { 1109c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 1110390065b1SAlfred Perlstein /* update actual length */ 1111390065b1SAlfred Perlstein uxfer->actual_length = actlen; 1112390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 1113390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].actual_length = 1114390065b1SAlfred Perlstein libusb20_tr_get_length(pxfer, i); 1115390065b1SAlfred Perlstein } 1116390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1117c500e4ddSAndrew Thompson break; 1118c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_START: 1119390065b1SAlfred Perlstein /* setup length(s) */ 1120390065b1SAlfred Perlstein actlen = 0; 1121390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 1122390065b1SAlfred Perlstein libusb20_tr_setup_isoc(pxfer, 1123390065b1SAlfred Perlstein &uxfer->buffer[actlen], 1124390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].length, i); 1125390065b1SAlfred Perlstein actlen += uxfer->iso_packet_desc[i].length; 1126c500e4ddSAndrew Thompson } 1127390065b1SAlfred Perlstein 1128390065b1SAlfred Perlstein /* no remainder */ 1129390065b1SAlfred Perlstein sxfer->rem_len = 0; 1130390065b1SAlfred Perlstein 1131390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, iso_packets); 1132390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1133390065b1SAlfred Perlstein 1134390065b1SAlfred Perlstein /* fork another USB transfer, if any */ 1135390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1136c500e4ddSAndrew Thompson break; 1137390065b1SAlfred Perlstein default: 1138390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1139c500e4ddSAndrew Thompson break; 1140c500e4ddSAndrew Thompson } 1141390065b1SAlfred Perlstein } 1142390065b1SAlfred Perlstein 1143390065b1SAlfred Perlstein /* This function must be called locked */ 1144390065b1SAlfred Perlstein 1145390065b1SAlfred Perlstein static void 1146390065b1SAlfred Perlstein libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 1147390065b1SAlfred Perlstein { 1148390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1149390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1150390065b1SAlfred Perlstein uint32_t max_bulk; 1151390065b1SAlfred Perlstein uint32_t actlen; 1152390065b1SAlfred Perlstein uint8_t status; 1153390065b1SAlfred Perlstein uint8_t flags; 1154390065b1SAlfred Perlstein 1155390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1156390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1157390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1158390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1159390065b1SAlfred Perlstein 1160390065b1SAlfred Perlstein if (sxfer == NULL) 1161390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1162390065b1SAlfred Perlstein 1163390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1164390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1165390065b1SAlfred Perlstein 1166390065b1SAlfred Perlstein flags = uxfer->flags; 1167390065b1SAlfred Perlstein 1168390065b1SAlfred Perlstein switch (status) { 1169390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1170390065b1SAlfred Perlstein 1171390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1172390065b1SAlfred Perlstein 1173390065b1SAlfred Perlstein /* check for short packet */ 1174390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1175390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1176390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1177390065b1SAlfred Perlstein } else { 1178390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1179390065b1SAlfred Perlstein } 1180390065b1SAlfred Perlstein break; 1181390065b1SAlfred Perlstein } 1182390065b1SAlfred Perlstein /* check for end of data */ 1183390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1184390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1185390065b1SAlfred Perlstein break; 1186390065b1SAlfred Perlstein } 1187390065b1SAlfred Perlstein /* FALLTHROUGH */ 1188390065b1SAlfred Perlstein 1189390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1190390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1191390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1192390065b1SAlfred Perlstein } 1193390065b1SAlfred Perlstein /* setup new BULK or INTERRUPT transaction */ 1194390065b1SAlfred Perlstein libusb20_tr_setup_bulk(pxfer, 1195390065b1SAlfred Perlstein sxfer->curr_data, max_bulk, uxfer->timeout); 1196390065b1SAlfred Perlstein 1197390065b1SAlfred Perlstein /* update counters */ 1198390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1199390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1200390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1201390065b1SAlfred Perlstein 1202390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1203390065b1SAlfred Perlstein 1204390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1205390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1206390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1207390065b1SAlfred Perlstein break; 1208390065b1SAlfred Perlstein 1209390065b1SAlfred Perlstein default: 1210390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1211390065b1SAlfred Perlstein break; 1212390065b1SAlfred Perlstein } 1213390065b1SAlfred Perlstein } 1214390065b1SAlfred Perlstein 1215390065b1SAlfred Perlstein /* This function must be called locked */ 1216390065b1SAlfred Perlstein 1217390065b1SAlfred Perlstein static void 1218390065b1SAlfred Perlstein libusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1219390065b1SAlfred Perlstein { 1220390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1221390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1222390065b1SAlfred Perlstein uint32_t max_bulk; 1223390065b1SAlfred Perlstein uint32_t actlen; 1224390065b1SAlfred Perlstein uint8_t status; 1225390065b1SAlfred Perlstein uint8_t flags; 1226390065b1SAlfred Perlstein 1227390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1228390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1229390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1230390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1231390065b1SAlfred Perlstein 1232390065b1SAlfred Perlstein if (sxfer == NULL) 1233390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1234390065b1SAlfred Perlstein 1235390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1236390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1237390065b1SAlfred Perlstein 1238390065b1SAlfred Perlstein flags = uxfer->flags; 1239390065b1SAlfred Perlstein 1240390065b1SAlfred Perlstein switch (status) { 1241390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1242390065b1SAlfred Perlstein 1243390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1244390065b1SAlfred Perlstein 1245390065b1SAlfred Perlstein /* subtract length of SETUP packet, if any */ 1246390065b1SAlfred Perlstein actlen -= libusb20_tr_get_length(pxfer, 0); 1247390065b1SAlfred Perlstein 1248390065b1SAlfred Perlstein /* check for short packet */ 1249390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1250390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1251390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1252390065b1SAlfred Perlstein } else { 1253390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1254390065b1SAlfred Perlstein } 1255390065b1SAlfred Perlstein break; 1256390065b1SAlfred Perlstein } 1257390065b1SAlfred Perlstein /* check for end of data */ 1258390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1259390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1260390065b1SAlfred Perlstein break; 1261390065b1SAlfred Perlstein } 1262390065b1SAlfred Perlstein /* FALLTHROUGH */ 1263390065b1SAlfred Perlstein 1264390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1265390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1266390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1267390065b1SAlfred Perlstein } 1268390065b1SAlfred Perlstein /* setup new CONTROL transaction */ 1269390065b1SAlfred Perlstein if (status == LIBUSB20_TRANSFER_COMPLETED) { 1270390065b1SAlfred Perlstein /* next fragment - don't send SETUP packet */ 1271390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 0, 0); 1272390065b1SAlfred Perlstein } else { 1273390065b1SAlfred Perlstein /* first fragment - send SETUP packet */ 1274390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 8, 0); 1275390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1276390065b1SAlfred Perlstein } 1277390065b1SAlfred Perlstein 1278390065b1SAlfred Perlstein if (max_bulk != 0) { 1279390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, max_bulk, 1); 1280390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1281390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 2); 1282390065b1SAlfred Perlstein } else { 1283390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 1); 1284390065b1SAlfred Perlstein } 1285390065b1SAlfred Perlstein 1286390065b1SAlfred Perlstein /* update counters */ 1287390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1288390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1289390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1290390065b1SAlfred Perlstein 1291390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1292390065b1SAlfred Perlstein 1293390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1294390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1295390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1296390065b1SAlfred Perlstein break; 1297390065b1SAlfred Perlstein 1298390065b1SAlfred Perlstein default: 1299390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1300390065b1SAlfred Perlstein break; 1301390065b1SAlfred Perlstein } 1302390065b1SAlfred Perlstein } 1303390065b1SAlfred Perlstein 1304390065b1SAlfred Perlstein /* The following function must be called locked */ 1305390065b1SAlfred Perlstein 1306390065b1SAlfred Perlstein static void 1307390065b1SAlfred Perlstein libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1308390065b1SAlfred Perlstein { 1309390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1310390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1311390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1312390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1313390065b1SAlfred Perlstein struct libusb_device *dev; 1314390065b1SAlfred Perlstein int err; 1315390065b1SAlfred Perlstein int buffsize; 1316390065b1SAlfred Perlstein int maxframe; 1317390065b1SAlfred Perlstein int temp; 1318390065b1SAlfred Perlstein 1319390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 1320390065b1SAlfred Perlstein 1321390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1322390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1323390065b1SAlfred Perlstein 1324390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) 1325390065b1SAlfred Perlstein return; /* shouldn't happen */ 1326390065b1SAlfred Perlstein 1327390065b1SAlfred Perlstein temp = 0; 1328390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer0)) 1329390065b1SAlfred Perlstein temp |= 1; 1330390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer1)) 1331390065b1SAlfred Perlstein temp |= 2; 1332390065b1SAlfred Perlstein 1333390065b1SAlfred Perlstein switch (temp) { 1334390065b1SAlfred Perlstein case 3: 1335390065b1SAlfred Perlstein /* wait till one of the transfers complete */ 1336390065b1SAlfred Perlstein return; 1337390065b1SAlfred Perlstein case 2: 1338390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer1); 13394594d907SAndrew Thompson if (sxfer == NULL) 13404594d907SAndrew Thompson return; /* cancelling */ 1341390065b1SAlfred Perlstein if (sxfer->rem_len) 1342390065b1SAlfred Perlstein return; /* cannot queue another one */ 1343390065b1SAlfred Perlstein /* swap transfers */ 1344390065b1SAlfred Perlstein pxfer1 = pxfer0; 1345390065b1SAlfred Perlstein break; 1346390065b1SAlfred Perlstein case 1: 1347390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer0); 13484594d907SAndrew Thompson if (sxfer == NULL) 13494594d907SAndrew Thompson return; /* cancelling */ 1350390065b1SAlfred Perlstein if (sxfer->rem_len) 1351390065b1SAlfred Perlstein return; /* cannot queue another one */ 1352390065b1SAlfred Perlstein /* swap transfers */ 1353390065b1SAlfred Perlstein pxfer0 = pxfer1; 1354c500e4ddSAndrew Thompson break; 1355c500e4ddSAndrew Thompson default: 1356c500e4ddSAndrew Thompson break; 1357c500e4ddSAndrew Thompson } 1358c500e4ddSAndrew Thompson 1359390065b1SAlfred Perlstein /* find next transfer on same endpoint */ 1360390065b1SAlfred Perlstein TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1361390065b1SAlfred Perlstein 1362390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1363390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1364390065b1SAlfred Perlstein 1365390065b1SAlfred Perlstein if (uxfer->endpoint == endpoint) { 1366390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1367390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 1368390065b1SAlfred Perlstein goto found; 1369c500e4ddSAndrew Thompson } 1370c500e4ddSAndrew Thompson } 1371390065b1SAlfred Perlstein return; /* success */ 1372390065b1SAlfred Perlstein 1373390065b1SAlfred Perlstein found: 1374390065b1SAlfred Perlstein 1375390065b1SAlfred Perlstein libusb20_tr_set_priv_sc0(pxfer0, pdev); 1376390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1377390065b1SAlfred Perlstein 1378390065b1SAlfred Perlstein /* reset super transfer state */ 1379390065b1SAlfred Perlstein sxfer->rem_len = uxfer->length; 1380390065b1SAlfred Perlstein sxfer->curr_data = uxfer->buffer; 1381390065b1SAlfred Perlstein uxfer->actual_length = 0; 1382390065b1SAlfred Perlstein 1383390065b1SAlfred Perlstein switch (uxfer->type) { 1384390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1385390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1386390065b1SAlfred Perlstein break; 1387390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_BULK: 1388390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1389390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1390390065b1SAlfred Perlstein break; 1391390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_CONTROL: 1392390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1393390065b1SAlfred Perlstein if (sxfer->rem_len < 8) 1394390065b1SAlfred Perlstein goto failure; 1395390065b1SAlfred Perlstein 1396390065b1SAlfred Perlstein /* remove SETUP packet from data */ 1397390065b1SAlfred Perlstein sxfer->rem_len -= 8; 1398390065b1SAlfred Perlstein sxfer->curr_data += 8; 1399390065b1SAlfred Perlstein break; 1400390065b1SAlfred Perlstein default: 1401390065b1SAlfred Perlstein goto failure; 1402390065b1SAlfred Perlstein } 1403390065b1SAlfred Perlstein 1404390065b1SAlfred Perlstein buffsize = libusb10_get_buffsize(pdev, uxfer); 1405390065b1SAlfred Perlstein maxframe = libusb10_get_maxframe(pdev, uxfer); 1406390065b1SAlfred Perlstein 1407390065b1SAlfred Perlstein /* make sure the transfer is opened */ 1408a0c93fa3SHans Petter Selasky err = libusb20_tr_open_stream(pxfer0, buffsize, maxframe, 1409a0c93fa3SHans Petter Selasky endpoint, sxfer->stream_id); 1410390065b1SAlfred Perlstein if (err && (err != LIBUSB20_ERROR_BUSY)) { 1411390065b1SAlfred Perlstein goto failure; 1412390065b1SAlfred Perlstein } 1413390065b1SAlfred Perlstein libusb20_tr_start(pxfer0); 1414390065b1SAlfred Perlstein return; 1415390065b1SAlfred Perlstein 1416390065b1SAlfred Perlstein failure: 1417390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1418390065b1SAlfred Perlstein /* make sure our event loop spins the done handler */ 1419540c7229SHans Petter Selasky libusb10_wakeup_event_loop(dev->ctx); 1420390065b1SAlfred Perlstein } 1421390065b1SAlfred Perlstein 1422390065b1SAlfred Perlstein /* The following function must be called unlocked */ 1423c500e4ddSAndrew Thompson 14248c8fff31SAndrew Thompson int 1425390065b1SAlfred Perlstein libusb_submit_transfer(struct libusb_transfer *uxfer) 14268c8fff31SAndrew Thompson { 1427390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1428390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1429390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1430390065b1SAlfred Perlstein struct libusb_device *dev; 143185ff9a03SHans Petter Selasky uint8_t endpoint; 1432390065b1SAlfred Perlstein int err; 14338c8fff31SAndrew Thompson 1434390065b1SAlfred Perlstein if (uxfer == NULL) 1435390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 14368c8fff31SAndrew Thompson 1437390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 1438390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 14398c8fff31SAndrew Thompson 1440390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 14418c8fff31SAndrew Thompson 1442390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 14438c8fff31SAndrew Thompson 1444390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 14458c8fff31SAndrew Thompson 1446390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1447390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1448390065b1SAlfred Perlstein 1449390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1450390065b1SAlfred Perlstein 1451390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1452390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1453390065b1SAlfred Perlstein 1454390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) { 1455390065b1SAlfred Perlstein err = LIBUSB_ERROR_OTHER; 1456390065b1SAlfred Perlstein } else if ((sxfer->entry.tqe_prev != NULL) || 1457390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1458390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1459390065b1SAlfred Perlstein err = LIBUSB_ERROR_BUSY; 1460540c7229SHans Petter Selasky } else if (dev->device_is_gone != 0) { 1461540c7229SHans Petter Selasky err = LIBUSB_ERROR_NO_DEVICE; 1462390065b1SAlfred Perlstein } else { 14634594d907SAndrew Thompson 14644594d907SAndrew Thompson /* set pending state */ 14654594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 14664594d907SAndrew Thompson 14674594d907SAndrew Thompson /* insert transfer into transfer head list */ 1468390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1469390065b1SAlfred Perlstein 14704594d907SAndrew Thompson /* start work transfers */ 1471390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1472390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1473390065b1SAlfred Perlstein 1474390065b1SAlfred Perlstein err = 0; /* success */ 14758c8fff31SAndrew Thompson } 14768c8fff31SAndrew Thompson 1477390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 1478390065b1SAlfred Perlstein 1479390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1480390065b1SAlfred Perlstein 1481390065b1SAlfred Perlstein return (err); 14828c8fff31SAndrew Thompson } 14838c8fff31SAndrew Thompson 1484390065b1SAlfred Perlstein /* Asynchronous transfer cancel */ 14858c8fff31SAndrew Thompson 1486390065b1SAlfred Perlstein int 1487390065b1SAlfred Perlstein libusb_cancel_transfer(struct libusb_transfer *uxfer) 1488390065b1SAlfred Perlstein { 1489390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1490390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1491390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1492390065b1SAlfred Perlstein struct libusb_device *dev; 1493540c7229SHans Petter Selasky struct libusb_device_handle *devh; 149485ff9a03SHans Petter Selasky uint8_t endpoint; 14954594d907SAndrew Thompson int retval; 14968c8fff31SAndrew Thompson 1497390065b1SAlfred Perlstein if (uxfer == NULL) 1498390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 14998c8fff31SAndrew Thompson 15004594d907SAndrew Thompson /* check if not initialised */ 1501540c7229SHans Petter Selasky if ((devh = uxfer->dev_handle) == NULL) 15024594d907SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 15038c8fff31SAndrew Thompson 1504390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 15058c8fff31SAndrew Thompson 1506540c7229SHans Petter Selasky dev = libusb_get_device(devh); 15078c8fff31SAndrew Thompson 1508390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 15098c8fff31SAndrew Thompson 1510390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1511390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1512390065b1SAlfred Perlstein 15134594d907SAndrew Thompson retval = 0; 15144594d907SAndrew Thompson 1515390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1516390065b1SAlfred Perlstein 1517540c7229SHans Petter Selasky pxfer0 = libusb10_get_transfer(devh, endpoint, 0); 1518540c7229SHans Petter Selasky pxfer1 = libusb10_get_transfer(devh, endpoint, 1); 1519390065b1SAlfred Perlstein 15204594d907SAndrew Thompson if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 15214594d907SAndrew Thompson /* only update the transfer status */ 15224594d907SAndrew Thompson uxfer->status = LIBUSB_TRANSFER_CANCELLED; 15234594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 15244594d907SAndrew Thompson } else if (sxfer->entry.tqe_prev != NULL) { 1525390065b1SAlfred Perlstein /* we are lucky - transfer is on a queue */ 1526390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1527390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 15284594d907SAndrew Thompson libusb10_complete_transfer(NULL, 15294594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1530540c7229SHans Petter Selasky /* make sure our event loop spins the done handler */ 1531540c7229SHans Petter Selasky libusb10_wakeup_event_loop(dev->ctx); 1532390065b1SAlfred Perlstein } else if (pxfer0 == NULL || pxfer1 == NULL) { 1533390065b1SAlfred Perlstein /* not started */ 15344594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1535390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 15364594d907SAndrew Thompson libusb10_complete_transfer(pxfer0, 15374594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1538540c7229SHans Petter Selasky if (dev->device_is_gone != 0) { 1539540c7229SHans Petter Selasky /* clear transfer pointer */ 1540540c7229SHans Petter Selasky libusb20_tr_set_priv_sc1(pxfer0, NULL); 1541540c7229SHans Petter Selasky /* make sure our event loop spins the done handler */ 1542540c7229SHans Petter Selasky libusb10_wakeup_event_loop(dev->ctx); 1543540c7229SHans Petter Selasky } else { 1544390065b1SAlfred Perlstein libusb20_tr_stop(pxfer0); 1545390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1546540c7229SHans Petter Selasky libusb10_submit_transfer_sub(devh, endpoint); 1547540c7229SHans Petter Selasky } 1548390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 15494594d907SAndrew Thompson libusb10_complete_transfer(pxfer1, 15504594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1551540c7229SHans Petter Selasky /* check if handle is still active */ 1552540c7229SHans Petter Selasky if (dev->device_is_gone != 0) { 1553540c7229SHans Petter Selasky /* clear transfer pointer */ 1554540c7229SHans Petter Selasky libusb20_tr_set_priv_sc1(pxfer1, NULL); 1555540c7229SHans Petter Selasky /* make sure our event loop spins the done handler */ 1556540c7229SHans Petter Selasky libusb10_wakeup_event_loop(dev->ctx); 1557540c7229SHans Petter Selasky } else { 1558390065b1SAlfred Perlstein libusb20_tr_stop(pxfer1); 1559390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1560540c7229SHans Petter Selasky libusb10_submit_transfer_sub(devh, endpoint); 1561540c7229SHans Petter Selasky } 1562390065b1SAlfred Perlstein } else { 1563390065b1SAlfred Perlstein /* not started */ 15644594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1565c500e4ddSAndrew Thompson } 15668c8fff31SAndrew Thompson 1567390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 15688c8fff31SAndrew Thompson 1569390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 15708c8fff31SAndrew Thompson 15714594d907SAndrew Thompson return (retval); 15728c8fff31SAndrew Thompson } 15738c8fff31SAndrew Thompson 1574390065b1SAlfred Perlstein UNEXPORTED void 1575390065b1SAlfred Perlstein libusb10_cancel_all_transfer(libusb_device *dev) 15768c8fff31SAndrew Thompson { 157790988efdSHans Petter Selasky struct libusb20_device *pdev = dev->os_priv; 157890988efdSHans Petter Selasky unsigned x; 157990988efdSHans Petter Selasky 158090988efdSHans Petter Selasky for (x = 0; x != LIBUSB_NUM_SW_ENDPOINTS; x++) { 158190988efdSHans Petter Selasky struct libusb20_transfer *xfer; 158290988efdSHans Petter Selasky 158390988efdSHans Petter Selasky xfer = libusb20_tr_get_pointer(pdev, x); 158490988efdSHans Petter Selasky if (xfer == NULL) 158590988efdSHans Petter Selasky continue; 158690988efdSHans Petter Selasky libusb20_tr_close(xfer); 158790988efdSHans Petter Selasky } 15888c8fff31SAndrew Thompson } 1589ccef4ddfSAndrew Thompson 1590540c7229SHans Petter Selasky UNEXPORTED void 1591540c7229SHans Petter Selasky libusb10_cancel_all_transfer_locked(struct libusb20_device *pdev, struct libusb_device *dev) 1592540c7229SHans Petter Selasky { 1593540c7229SHans Petter Selasky struct libusb_super_transfer *sxfer; 1594540c7229SHans Petter Selasky unsigned x; 1595540c7229SHans Petter Selasky 1596540c7229SHans Petter Selasky for (x = 0; x != LIBUSB_NUM_SW_ENDPOINTS; x++) { 1597540c7229SHans Petter Selasky struct libusb20_transfer *xfer; 1598540c7229SHans Petter Selasky 1599540c7229SHans Petter Selasky xfer = libusb20_tr_get_pointer(pdev, x); 1600540c7229SHans Petter Selasky if (xfer == NULL) 1601540c7229SHans Petter Selasky continue; 1602540c7229SHans Petter Selasky if (libusb20_tr_pending(xfer) == 0) 1603540c7229SHans Petter Selasky continue; 1604540c7229SHans Petter Selasky sxfer = libusb20_tr_get_priv_sc1(xfer); 1605540c7229SHans Petter Selasky if (sxfer == NULL) 1606540c7229SHans Petter Selasky continue; 1607540c7229SHans Petter Selasky /* complete pending transfer */ 1608540c7229SHans Petter Selasky libusb10_complete_transfer(xfer, sxfer, LIBUSB_TRANSFER_ERROR); 1609540c7229SHans Petter Selasky } 1610540c7229SHans Petter Selasky 1611540c7229SHans Petter Selasky while ((sxfer = TAILQ_FIRST(&dev->tr_head))) { 1612540c7229SHans Petter Selasky TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1613540c7229SHans Petter Selasky 1614540c7229SHans Petter Selasky /* complete pending transfer */ 1615540c7229SHans Petter Selasky libusb10_complete_transfer(NULL, sxfer, LIBUSB_TRANSFER_ERROR); 1616540c7229SHans Petter Selasky } 1617540c7229SHans Petter Selasky } 1618540c7229SHans Petter Selasky 1619ccef4ddfSAndrew Thompson uint16_t 1620ccef4ddfSAndrew Thompson libusb_cpu_to_le16(uint16_t x) 1621ccef4ddfSAndrew Thompson { 1622ccef4ddfSAndrew Thompson return (htole16(x)); 1623ccef4ddfSAndrew Thompson } 1624ccef4ddfSAndrew Thompson 1625ccef4ddfSAndrew Thompson uint16_t 1626ccef4ddfSAndrew Thompson libusb_le16_to_cpu(uint16_t x) 1627ccef4ddfSAndrew Thompson { 1628ccef4ddfSAndrew Thompson return (le16toh(x)); 1629ccef4ddfSAndrew Thompson } 1630ccef4ddfSAndrew Thompson 1631698e791aSHans Petter Selasky const char * 1632698e791aSHans Petter Selasky libusb_strerror(int code) 1633698e791aSHans Petter Selasky { 1634c61f2561SHans Petter Selasky switch (code) { 1635c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1636c61f2561SHans Petter Selasky return ("Success"); 1637c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1638c61f2561SHans Petter Selasky return ("I/O error"); 1639c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1640c61f2561SHans Petter Selasky return ("Invalid parameter"); 1641c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1642c61f2561SHans Petter Selasky return ("Permissions error"); 1643c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1644c61f2561SHans Petter Selasky return ("No device"); 1645c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1646c61f2561SHans Petter Selasky return ("Not found"); 1647c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1648c61f2561SHans Petter Selasky return ("Device busy"); 1649c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1650c61f2561SHans Petter Selasky return ("Timeout"); 1651c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1652c61f2561SHans Petter Selasky return ("Overflow"); 1653c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1654c61f2561SHans Petter Selasky return ("Pipe error"); 1655c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1656c61f2561SHans Petter Selasky return ("Interrupted"); 1657c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1658c61f2561SHans Petter Selasky return ("Out of memory"); 1659c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1660c61f2561SHans Petter Selasky return ("Not supported"); 1661c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1662c61f2561SHans Petter Selasky return ("Other error"); 1663c61f2561SHans Petter Selasky default: 1664698e791aSHans Petter Selasky return ("Unknown error"); 1665698e791aSHans Petter Selasky } 1666c61f2561SHans Petter Selasky } 1667c61f2561SHans Petter Selasky 1668c61f2561SHans Petter Selasky const char * 1669c61f2561SHans Petter Selasky libusb_error_name(int code) 1670c61f2561SHans Petter Selasky { 1671c61f2561SHans Petter Selasky switch (code) { 1672c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1673c61f2561SHans Petter Selasky return ("LIBUSB_SUCCESS"); 1674c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1675c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_IO"); 1676c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1677c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INVALID_PARAM"); 1678c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1679c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_ACCESS"); 1680c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1681c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_DEVICE"); 1682c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1683c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_FOUND"); 1684c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1685c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_BUSY"); 1686c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1687c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_TIMEOUT"); 1688c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1689c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OVERFLOW"); 1690c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1691c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_PIPE"); 1692c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1693c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INTERRUPTED"); 1694c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1695c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_MEM"); 1696c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1697c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_SUPPORTED"); 1698c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1699c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OTHER"); 1700c61f2561SHans Petter Selasky default: 1701c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_UNKNOWN"); 1702c61f2561SHans Petter Selasky } 1703c61f2561SHans Petter Selasky } 1704