18c8fff31SAndrew Thompson /* $FreeBSD$ */ 28c8fff31SAndrew Thompson /*- 38c8fff31SAndrew Thompson * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4390065b1SAlfred Perlstein * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 58c8fff31SAndrew Thompson * 68c8fff31SAndrew Thompson * Redistribution and use in source and binary forms, with or without 78c8fff31SAndrew Thompson * modification, are permitted provided that the following conditions 88c8fff31SAndrew Thompson * are met: 98c8fff31SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 108c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer. 118c8fff31SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 128c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 138c8fff31SAndrew Thompson * documentation and/or other materials provided with the distribution. 148c8fff31SAndrew Thompson * 158c8fff31SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 168c8fff31SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 178c8fff31SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 188c8fff31SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 198c8fff31SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 208c8fff31SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 218c8fff31SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 228c8fff31SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 238c8fff31SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 248c8fff31SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 258c8fff31SAndrew Thompson * SUCH DAMAGE. 268c8fff31SAndrew Thompson */ 278c8fff31SAndrew Thompson 2866194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE 2966194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE 3066194130SHans Petter Selasky #else 31ac840bfcSWojciech A. Koszek #include <assert.h> 32f3cba95cSWojciech A. Koszek #include <errno.h> 338c8fff31SAndrew Thompson #include <poll.h> 348c8fff31SAndrew Thompson #include <pthread.h> 35f3cba95cSWojciech A. Koszek #include <stdio.h> 36f3cba95cSWojciech A. Koszek #include <stdlib.h> 3766194130SHans Petter Selasky #include <string.h> 38f3cba95cSWojciech A. Koszek #include <unistd.h> 3966194130SHans Petter Selasky #include <time.h> 4066194130SHans Petter Selasky #include <sys/fcntl.h> 4166194130SHans Petter Selasky #include <sys/ioctl.h> 4266194130SHans Petter Selasky #include <sys/queue.h> 4366194130SHans Petter Selasky #include <sys/endian.h> 4466194130SHans Petter Selasky #endif 458c8fff31SAndrew Thompson 469c087c5aSAndrew Thompson #define libusb_device_handle libusb20_device 479c087c5aSAndrew Thompson 488c8fff31SAndrew Thompson #include "libusb20.h" 498c8fff31SAndrew Thompson #include "libusb20_desc.h" 508c8fff31SAndrew Thompson #include "libusb20_int.h" 518c8fff31SAndrew Thompson #include "libusb.h" 528c8fff31SAndrew Thompson #include "libusb10.h" 538c8fff31SAndrew Thompson 5490988efdSHans Petter Selasky #define LIBUSB_NUM_SW_ENDPOINTS (16 * 4) 5590988efdSHans Petter Selasky 568c8fff31SAndrew Thompson static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 578c8fff31SAndrew Thompson struct libusb_context *usbi_default_context = NULL; 58390065b1SAlfred Perlstein 59390065b1SAlfred Perlstein /* Prototypes */ 60390065b1SAlfred Perlstein 61390065b1SAlfred Perlstein static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 62390065b1SAlfred Perlstein static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 63390065b1SAlfred Perlstein static int libusb10_convert_error(uint8_t status); 64390065b1SAlfred Perlstein static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 65390065b1SAlfred Perlstein static void libusb10_isoc_proxy(struct libusb20_transfer *); 66390065b1SAlfred Perlstein static void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 67390065b1SAlfred Perlstein static void libusb10_ctrl_proxy(struct libusb20_transfer *); 68390065b1SAlfred Perlstein static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 698c8fff31SAndrew Thompson 708c8fff31SAndrew Thompson /* Library initialisation / deinitialisation */ 718c8fff31SAndrew Thompson 7214b896ceSHans Petter Selasky static const struct libusb_version libusb_version = { 7314b896ceSHans Petter Selasky .major = 1, 7414b896ceSHans Petter Selasky .minor = 0, 7514b896ceSHans Petter Selasky .micro = 0, 7614b896ceSHans Petter Selasky .nano = 2016, 7714b896ceSHans Petter Selasky .rc = "", 7814b896ceSHans Petter Selasky .describe = "http://www.freebsd.org" 7914b896ceSHans Petter Selasky }; 8014b896ceSHans Petter Selasky 8114b896ceSHans Petter Selasky const struct libusb_version * 8214b896ceSHans Petter Selasky libusb_get_version(void) 8314b896ceSHans Petter Selasky { 8414b896ceSHans Petter Selasky 8514b896ceSHans Petter Selasky return (&libusb_version); 8614b896ceSHans Petter Selasky } 8714b896ceSHans Petter Selasky 888c8fff31SAndrew Thompson void 898c8fff31SAndrew Thompson libusb_set_debug(libusb_context *ctx, int level) 908c8fff31SAndrew Thompson { 91390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 928c8fff31SAndrew Thompson if (ctx) 938c8fff31SAndrew Thompson ctx->debug = level; 948c8fff31SAndrew Thompson } 958c8fff31SAndrew Thompson 96698e791aSHans Petter Selasky static void 97698e791aSHans Petter Selasky libusb_set_nonblocking(int f) 98698e791aSHans Petter Selasky { 99698e791aSHans Petter Selasky int flags; 100698e791aSHans Petter Selasky 101698e791aSHans Petter Selasky /* 102698e791aSHans Petter Selasky * We ignore any failures in this function, hence the 103698e791aSHans Petter Selasky * non-blocking flag is not critical to the operation of 104698e791aSHans Petter Selasky * libUSB. We use F_GETFL and F_SETFL to be compatible with 105698e791aSHans Petter Selasky * Linux. 106698e791aSHans Petter Selasky */ 107698e791aSHans Petter Selasky 108698e791aSHans Petter Selasky flags = fcntl(f, F_GETFL, NULL); 109698e791aSHans Petter Selasky if (flags == -1) 110698e791aSHans Petter Selasky return; 111698e791aSHans Petter Selasky flags |= O_NONBLOCK; 112698e791aSHans Petter Selasky fcntl(f, F_SETFL, flags); 113698e791aSHans Petter Selasky } 114698e791aSHans Petter Selasky 1158c8fff31SAndrew Thompson int 1168c8fff31SAndrew Thompson libusb_init(libusb_context **context) 1178c8fff31SAndrew Thompson { 1188c8fff31SAndrew Thompson struct libusb_context *ctx; 119f7287225SHans Petter Selasky pthread_condattr_t attr; 1208c8fff31SAndrew Thompson char *debug; 1218c8fff31SAndrew Thompson int ret; 1228c8fff31SAndrew Thompson 1238c8fff31SAndrew Thompson ctx = malloc(sizeof(*ctx)); 1248c8fff31SAndrew Thompson if (!ctx) 1258c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1268c8fff31SAndrew Thompson 1278c8fff31SAndrew Thompson memset(ctx, 0, sizeof(*ctx)); 1288c8fff31SAndrew Thompson 1298c8fff31SAndrew Thompson debug = getenv("LIBUSB_DEBUG"); 1308c8fff31SAndrew Thompson if (debug != NULL) { 1318c8fff31SAndrew Thompson ctx->debug = atoi(debug); 1328c8fff31SAndrew Thompson if (ctx->debug != 0) 1338c8fff31SAndrew Thompson ctx->debug_fixed = 1; 1348c8fff31SAndrew Thompson } 135c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->pollfds); 136390065b1SAlfred Perlstein TAILQ_INIT(&ctx->tr_done); 137390065b1SAlfred Perlstein 138f7287225SHans Petter Selasky if (pthread_mutex_init(&ctx->ctx_lock, NULL) != 0) { 139f7287225SHans Petter Selasky free(ctx); 140f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 141f7287225SHans Petter Selasky } 142f7287225SHans Petter Selasky if (pthread_condattr_init(&attr) != 0) { 143f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 144f7287225SHans Petter Selasky free(ctx); 145f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 146f7287225SHans Petter Selasky } 147f7287225SHans Petter Selasky if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) { 148f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 149f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 150f7287225SHans Petter Selasky free(ctx); 151f7287225SHans Petter Selasky return (LIBUSB_ERROR_OTHER); 152f7287225SHans Petter Selasky } 153f7287225SHans Petter Selasky if (pthread_cond_init(&ctx->ctx_cond, &attr) != 0) { 154f7287225SHans Petter Selasky pthread_mutex_destroy(&ctx->ctx_lock); 155f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 156f7287225SHans Petter Selasky free(ctx); 157f7287225SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 158f7287225SHans Petter Selasky } 159f7287225SHans Petter Selasky pthread_condattr_destroy(&attr); 160390065b1SAlfred Perlstein 161390065b1SAlfred Perlstein ctx->ctx_handler = NO_THREAD; 1628c8fff31SAndrew Thompson 1638c8fff31SAndrew Thompson ret = pipe(ctx->ctrl_pipe); 1648c8fff31SAndrew Thompson if (ret < 0) { 165390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 166390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 1678c8fff31SAndrew Thompson free(ctx); 1688c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 1698c8fff31SAndrew Thompson } 170390065b1SAlfred Perlstein /* set non-blocking mode on the control pipe to avoid deadlock */ 171698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[0]); 172698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[1]); 1738c8fff31SAndrew Thompson 174390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 1758c8fff31SAndrew Thompson 1768c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 1778c8fff31SAndrew Thompson if (usbi_default_context == NULL) { 1788c8fff31SAndrew Thompson usbi_default_context = ctx; 1798c8fff31SAndrew Thompson } 1808c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 1818c8fff31SAndrew Thompson 1828c8fff31SAndrew Thompson if (context) 1838c8fff31SAndrew Thompson *context = ctx; 1848c8fff31SAndrew Thompson 185390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 186390065b1SAlfred Perlstein 1878c8fff31SAndrew Thompson return (0); 1888c8fff31SAndrew Thompson } 1898c8fff31SAndrew Thompson 1908c8fff31SAndrew Thompson void 1918c8fff31SAndrew Thompson libusb_exit(libusb_context *ctx) 1928c8fff31SAndrew Thompson { 193390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 1948c8fff31SAndrew Thompson 195390065b1SAlfred Perlstein if (ctx == NULL) 196390065b1SAlfred Perlstein return; 197390065b1SAlfred Perlstein 198390065b1SAlfred Perlstein /* XXX cleanup devices */ 199390065b1SAlfred Perlstein 200390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 2018c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 2028c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 203390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 204390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 2058c8fff31SAndrew Thompson 2068c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 2078c8fff31SAndrew Thompson if (ctx == usbi_default_context) { 2088c8fff31SAndrew Thompson usbi_default_context = NULL; 2098c8fff31SAndrew Thompson } 2108c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 2118c8fff31SAndrew Thompson 2128c8fff31SAndrew Thompson free(ctx); 2138c8fff31SAndrew Thompson } 2148c8fff31SAndrew Thompson 2158c8fff31SAndrew Thompson /* Device handling and initialisation. */ 2168c8fff31SAndrew Thompson 2178c8fff31SAndrew Thompson ssize_t 2188c8fff31SAndrew Thompson libusb_get_device_list(libusb_context *ctx, libusb_device ***list) 2198c8fff31SAndrew Thompson { 2208c8fff31SAndrew Thompson struct libusb20_backend *usb_backend; 221390065b1SAlfred Perlstein struct libusb20_device *pdev; 222390065b1SAlfred Perlstein struct libusb_device *dev; 2238c8fff31SAndrew Thompson int i; 2248c8fff31SAndrew Thompson 225390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 226390065b1SAlfred Perlstein 227390065b1SAlfred Perlstein if (ctx == NULL) 228390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 229390065b1SAlfred Perlstein 230390065b1SAlfred Perlstein if (list == NULL) 231390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 2328c8fff31SAndrew Thompson 2338c8fff31SAndrew Thompson usb_backend = libusb20_be_alloc_default(); 2348c8fff31SAndrew Thompson if (usb_backend == NULL) 235390065b1SAlfred Perlstein return (LIBUSB_ERROR_NO_MEM); 2368c8fff31SAndrew Thompson 237390065b1SAlfred Perlstein /* figure out how many USB devices are present */ 2388c8fff31SAndrew Thompson pdev = NULL; 2398c8fff31SAndrew Thompson i = 0; 2408c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 2418c8fff31SAndrew Thompson i++; 2428c8fff31SAndrew Thompson 243390065b1SAlfred Perlstein /* allocate device pointer list */ 2448c8fff31SAndrew Thompson *list = malloc((i + 1) * sizeof(void *)); 2458c8fff31SAndrew Thompson if (*list == NULL) { 2468c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2478c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 2488c8fff31SAndrew Thompson } 249390065b1SAlfred Perlstein /* create libusb v1.0 compliant devices */ 2508c8fff31SAndrew Thompson i = 0; 2518c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 2528c8fff31SAndrew Thompson 2538c8fff31SAndrew Thompson dev = malloc(sizeof(*dev)); 2548c8fff31SAndrew Thompson if (dev == NULL) { 255c500e4ddSAndrew Thompson while (i != 0) { 256c500e4ddSAndrew Thompson libusb_unref_device((*list)[i - 1]); 257c500e4ddSAndrew Thompson i--; 258c500e4ddSAndrew Thompson } 2598c8fff31SAndrew Thompson free(*list); 260390065b1SAlfred Perlstein *list = NULL; 2618c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2628c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 2638c8fff31SAndrew Thompson } 264ccef4ddfSAndrew Thompson /* get device into libUSB v1.0 list */ 265ccef4ddfSAndrew Thompson libusb20_be_dequeue_device(usb_backend, pdev); 266ccef4ddfSAndrew Thompson 2678c8fff31SAndrew Thompson memset(dev, 0, sizeof(*dev)); 2688c8fff31SAndrew Thompson 269390065b1SAlfred Perlstein /* init transfer queues */ 270390065b1SAlfred Perlstein TAILQ_INIT(&dev->tr_head); 271390065b1SAlfred Perlstein 272390065b1SAlfred Perlstein /* set context we belong to */ 2738c8fff31SAndrew Thompson dev->ctx = ctx; 2748c8fff31SAndrew Thompson 2758c8fff31SAndrew Thompson /* link together the two structures */ 2768c8fff31SAndrew Thompson dev->os_priv = pdev; 277390065b1SAlfred Perlstein pdev->privLuData = dev; 2788c8fff31SAndrew Thompson 2798c8fff31SAndrew Thompson (*list)[i] = libusb_ref_device(dev); 2808c8fff31SAndrew Thompson i++; 2818c8fff31SAndrew Thompson } 2828c8fff31SAndrew Thompson (*list)[i] = NULL; 2838c8fff31SAndrew Thompson 2848c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2858c8fff31SAndrew Thompson return (i); 2868c8fff31SAndrew Thompson } 2878c8fff31SAndrew Thompson 2888c8fff31SAndrew Thompson void 2898c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices) 2908c8fff31SAndrew Thompson { 2918c8fff31SAndrew Thompson int i; 2928c8fff31SAndrew Thompson 2938c8fff31SAndrew Thompson if (list == NULL) 294390065b1SAlfred Perlstein return; /* be NULL safe */ 2958c8fff31SAndrew Thompson 2968c8fff31SAndrew Thompson if (unref_devices) { 2978c8fff31SAndrew Thompson for (i = 0; list[i] != NULL; i++) 2988c8fff31SAndrew Thompson libusb_unref_device(list[i]); 2998c8fff31SAndrew Thompson } 3008c8fff31SAndrew Thompson free(list); 3018c8fff31SAndrew Thompson } 3028c8fff31SAndrew Thompson 3038c8fff31SAndrew Thompson uint8_t 3048c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device *dev) 3058c8fff31SAndrew Thompson { 3068c8fff31SAndrew Thompson if (dev == NULL) 307390065b1SAlfred Perlstein return (0); /* should not happen */ 308390065b1SAlfred Perlstein return (libusb20_dev_get_bus_number(dev->os_priv)); 3098c8fff31SAndrew Thompson } 3108c8fff31SAndrew Thompson 3110f2c7066SHans Petter Selasky uint8_t 3120f2c7066SHans Petter Selasky libusb_get_port_number(libusb_device *dev) 3130f2c7066SHans Petter Selasky { 3140f2c7066SHans Petter Selasky if (dev == NULL) 3150f2c7066SHans Petter Selasky return (0); /* should not happen */ 3160f2c7066SHans Petter Selasky return (libusb20_dev_get_parent_port(dev->os_priv)); 3170f2c7066SHans Petter Selasky } 3180f2c7066SHans Petter Selasky 3195906bf49SEd Maste int 320a9205626SEd Maste libusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize) 321a9205626SEd Maste { 322a9205626SEd Maste return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize)); 323a9205626SEd Maste } 324a9205626SEd Maste 325a9205626SEd Maste int 3265906bf49SEd Maste libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t *buf, 3275906bf49SEd Maste uint8_t bufsize) 3285906bf49SEd Maste { 3295906bf49SEd Maste return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize)); 3305906bf49SEd Maste } 3315906bf49SEd Maste 3328c8fff31SAndrew Thompson uint8_t 3338c8fff31SAndrew Thompson libusb_get_device_address(libusb_device *dev) 3348c8fff31SAndrew Thompson { 3358c8fff31SAndrew Thompson if (dev == NULL) 336390065b1SAlfred Perlstein return (0); /* should not happen */ 337390065b1SAlfred Perlstein return (libusb20_dev_get_address(dev->os_priv)); 3388c8fff31SAndrew Thompson } 3398c8fff31SAndrew Thompson 3409a46d467SHans Petter Selasky enum libusb_speed 3419a46d467SHans Petter Selasky libusb_get_device_speed(libusb_device *dev) 3429a46d467SHans Petter Selasky { 3439a46d467SHans Petter Selasky if (dev == NULL) 34433ec9f0cSHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); /* should not happen */ 3459a46d467SHans Petter Selasky 3469a46d467SHans Petter Selasky switch (libusb20_dev_get_speed(dev->os_priv)) { 3479a46d467SHans Petter Selasky case LIBUSB20_SPEED_LOW: 3489a46d467SHans Petter Selasky return (LIBUSB_SPEED_LOW); 3499a46d467SHans Petter Selasky case LIBUSB20_SPEED_FULL: 3509a46d467SHans Petter Selasky return (LIBUSB_SPEED_FULL); 3519a46d467SHans Petter Selasky case LIBUSB20_SPEED_HIGH: 3529a46d467SHans Petter Selasky return (LIBUSB_SPEED_HIGH); 3539a46d467SHans Petter Selasky case LIBUSB20_SPEED_SUPER: 3549a46d467SHans Petter Selasky return (LIBUSB_SPEED_SUPER); 3559a46d467SHans Petter Selasky default: 3569a46d467SHans Petter Selasky break; 3579a46d467SHans Petter Selasky } 3589a46d467SHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); 3599a46d467SHans Petter Selasky } 3609a46d467SHans Petter Selasky 3618c8fff31SAndrew Thompson int 362390065b1SAlfred Perlstein libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 3638c8fff31SAndrew Thompson { 3648c8fff31SAndrew Thompson struct libusb_config_descriptor *pdconf; 3658c8fff31SAndrew Thompson struct libusb_interface *pinf; 3668c8fff31SAndrew Thompson struct libusb_interface_descriptor *pdinf; 3678c8fff31SAndrew Thompson struct libusb_endpoint_descriptor *pdend; 368390065b1SAlfred Perlstein int i; 369390065b1SAlfred Perlstein int j; 370390065b1SAlfred Perlstein int k; 371390065b1SAlfred Perlstein int ret; 3728c8fff31SAndrew Thompson 3738c8fff31SAndrew Thompson if (dev == NULL) 3748c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 3758c8fff31SAndrew Thompson 376390065b1SAlfred Perlstein ret = libusb_get_active_config_descriptor(dev, &pdconf); 377390065b1SAlfred Perlstein if (ret < 0) 378390065b1SAlfred Perlstein return (ret); 3798c8fff31SAndrew Thompson 3808c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 3818c8fff31SAndrew Thompson for (i = 0; i < pdconf->bNumInterfaces; i++) { 3828c8fff31SAndrew Thompson pinf = &pdconf->interface[i]; 3838c8fff31SAndrew Thompson for (j = 0; j < pinf->num_altsetting; j++) { 3848c8fff31SAndrew Thompson pdinf = &pinf->altsetting[j]; 3858c8fff31SAndrew Thompson for (k = 0; k < pdinf->bNumEndpoints; k++) { 3868c8fff31SAndrew Thompson pdend = &pdinf->endpoint[k]; 3878c8fff31SAndrew Thompson if (pdend->bEndpointAddress == endpoint) { 3888c8fff31SAndrew Thompson ret = pdend->wMaxPacketSize; 3898c8fff31SAndrew Thompson goto out; 3908c8fff31SAndrew Thompson } 3918c8fff31SAndrew Thompson } 3928c8fff31SAndrew Thompson } 3938c8fff31SAndrew Thompson } 3948c8fff31SAndrew Thompson 3958c8fff31SAndrew Thompson out: 3968c8fff31SAndrew Thompson libusb_free_config_descriptor(pdconf); 3978c8fff31SAndrew Thompson return (ret); 3988c8fff31SAndrew Thompson } 3998c8fff31SAndrew Thompson 400748205a3SHans Petter Selasky int 401748205a3SHans Petter Selasky libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint) 402748205a3SHans Petter Selasky { 403748205a3SHans Petter Selasky int multiplier; 404748205a3SHans Petter Selasky int ret; 405748205a3SHans Petter Selasky 406748205a3SHans Petter Selasky ret = libusb_get_max_packet_size(dev, endpoint); 407748205a3SHans Petter Selasky 408748205a3SHans Petter Selasky switch (libusb20_dev_get_speed(dev->os_priv)) { 409748205a3SHans Petter Selasky case LIBUSB20_SPEED_LOW: 410748205a3SHans Petter Selasky case LIBUSB20_SPEED_FULL: 411748205a3SHans Petter Selasky break; 412748205a3SHans Petter Selasky default: 413748205a3SHans Petter Selasky if (ret > -1) { 414748205a3SHans Petter Selasky multiplier = (1 + ((ret >> 11) & 3)); 415748205a3SHans Petter Selasky if (multiplier > 3) 416748205a3SHans Petter Selasky multiplier = 3; 417748205a3SHans Petter Selasky ret = (ret & 0x7FF) * multiplier; 418748205a3SHans Petter Selasky } 419748205a3SHans Petter Selasky break; 420748205a3SHans Petter Selasky } 421748205a3SHans Petter Selasky return (ret); 422748205a3SHans Petter Selasky } 423748205a3SHans Petter Selasky 4248c8fff31SAndrew Thompson libusb_device * 4258c8fff31SAndrew Thompson libusb_ref_device(libusb_device *dev) 4268c8fff31SAndrew Thompson { 4278c8fff31SAndrew Thompson if (dev == NULL) 428390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 4298c8fff31SAndrew Thompson 430390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 4318c8fff31SAndrew Thompson dev->refcnt++; 432390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 4338c8fff31SAndrew Thompson 4348c8fff31SAndrew Thompson return (dev); 4358c8fff31SAndrew Thompson } 4368c8fff31SAndrew Thompson 4378c8fff31SAndrew Thompson void 4388c8fff31SAndrew Thompson libusb_unref_device(libusb_device *dev) 4398c8fff31SAndrew Thompson { 4408c8fff31SAndrew Thompson if (dev == NULL) 441390065b1SAlfred Perlstein return; /* be NULL safe */ 4428c8fff31SAndrew Thompson 443390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 4448c8fff31SAndrew Thompson dev->refcnt--; 445390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 4468c8fff31SAndrew Thompson 4478c8fff31SAndrew Thompson if (dev->refcnt == 0) { 4488c8fff31SAndrew Thompson libusb20_dev_free(dev->os_priv); 4498c8fff31SAndrew Thompson free(dev); 4508c8fff31SAndrew Thompson } 4518c8fff31SAndrew Thompson } 4528c8fff31SAndrew Thompson 4538c8fff31SAndrew Thompson int 4548c8fff31SAndrew Thompson libusb_open(libusb_device *dev, libusb_device_handle **devh) 4558c8fff31SAndrew Thompson { 4568c8fff31SAndrew Thompson libusb_context *ctx = dev->ctx; 4578c8fff31SAndrew Thompson struct libusb20_device *pdev = dev->os_priv; 458390065b1SAlfred Perlstein uint8_t dummy; 4598c8fff31SAndrew Thompson int err; 4608c8fff31SAndrew Thompson 4618c8fff31SAndrew Thompson if (devh == NULL) 4628c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 4638c8fff31SAndrew Thompson 464390065b1SAlfred Perlstein /* set default device handle value */ 465390065b1SAlfred Perlstein *devh = NULL; 466390065b1SAlfred Perlstein 467390065b1SAlfred Perlstein dev = libusb_ref_device(dev); 468390065b1SAlfred Perlstein if (dev == NULL) 469390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 4708c8fff31SAndrew Thompson 47190988efdSHans Petter Selasky err = libusb20_dev_open(pdev, LIBUSB_NUM_SW_ENDPOINTS); 4728c8fff31SAndrew Thompson if (err) { 473390065b1SAlfred Perlstein libusb_unref_device(dev); 4748c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 4758c8fff31SAndrew Thompson } 476390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 4778c8fff31SAndrew Thompson POLLOUT | POLLRDNORM | POLLWRNORM); 4788c8fff31SAndrew Thompson 479390065b1SAlfred Perlstein /* make sure our event loop detects the new device */ 480390065b1SAlfred Perlstein dummy = 0; 4818c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 482698e791aSHans Petter Selasky if (err < (int)sizeof(dummy)) { 483390065b1SAlfred Perlstein /* ignore error, if any */ 484390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 4858c8fff31SAndrew Thompson } 486390065b1SAlfred Perlstein *devh = pdev; 4878c8fff31SAndrew Thompson 4888c8fff31SAndrew Thompson return (0); 4898c8fff31SAndrew Thompson } 4908c8fff31SAndrew Thompson 4918c8fff31SAndrew Thompson libusb_device_handle * 4928c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 4938c8fff31SAndrew Thompson uint16_t product_id) 4948c8fff31SAndrew Thompson { 4958c8fff31SAndrew Thompson struct libusb_device **devs; 4968c8fff31SAndrew Thompson struct libusb20_device *pdev; 4978c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 498390065b1SAlfred Perlstein int i; 499390065b1SAlfred Perlstein int j; 5008c8fff31SAndrew Thompson 501390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 502390065b1SAlfred Perlstein if (ctx == NULL) 503390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 504390065b1SAlfred Perlstein 505c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 5068c8fff31SAndrew Thompson 5078c8fff31SAndrew Thompson if ((i = libusb_get_device_list(ctx, &devs)) < 0) 5088c8fff31SAndrew Thompson return (NULL); 5098c8fff31SAndrew Thompson 5103f709d07SHans Petter Selasky pdev = NULL; 5118c8fff31SAndrew Thompson for (j = 0; j < i; j++) { 5123f709d07SHans Petter Selasky struct libusb20_device *tdev; 5133f709d07SHans Petter Selasky 5143f709d07SHans Petter Selasky tdev = devs[j]->os_priv; 5153f709d07SHans Petter Selasky pdesc = libusb20_dev_get_device_desc(tdev); 516390065b1SAlfred Perlstein /* 517390065b1SAlfred Perlstein * NOTE: The USB library will automatically swap the 518390065b1SAlfred Perlstein * fields in the device descriptor to be of host 519390065b1SAlfred Perlstein * endian type! 520390065b1SAlfred Perlstein */ 5218c8fff31SAndrew Thompson if (pdesc->idVendor == vendor_id && 522c500e4ddSAndrew Thompson pdesc->idProduct == product_id) { 523dc934803SHans Petter Selasky libusb_open(devs[j], &pdev); 524c500e4ddSAndrew Thompson break; 525c500e4ddSAndrew Thompson } 5268c8fff31SAndrew Thompson } 5278c8fff31SAndrew Thompson 5288c8fff31SAndrew Thompson libusb_free_device_list(devs, 1); 529c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 530390065b1SAlfred Perlstein return (pdev); 5318c8fff31SAndrew Thompson } 5328c8fff31SAndrew Thompson 5338c8fff31SAndrew Thompson void 534390065b1SAlfred Perlstein libusb_close(struct libusb20_device *pdev) 5358c8fff31SAndrew Thompson { 5368c8fff31SAndrew Thompson libusb_context *ctx; 537390065b1SAlfred Perlstein struct libusb_device *dev; 538390065b1SAlfred Perlstein uint8_t dummy; 5398c8fff31SAndrew Thompson int err; 5408c8fff31SAndrew Thompson 541390065b1SAlfred Perlstein if (pdev == NULL) 542390065b1SAlfred Perlstein return; /* be NULL safe */ 5438c8fff31SAndrew Thompson 544390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 545390065b1SAlfred Perlstein ctx = dev->ctx; 5468c8fff31SAndrew Thompson 547390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &dev->dev_poll); 5488c8fff31SAndrew Thompson 549390065b1SAlfred Perlstein libusb20_dev_close(pdev); 550ccef4ddfSAndrew Thompson 551ccef4ddfSAndrew Thompson /* unref will free the "pdev" when the refcount reaches zero */ 552390065b1SAlfred Perlstein libusb_unref_device(dev); 5538c8fff31SAndrew Thompson 554390065b1SAlfred Perlstein /* make sure our event loop detects the closed device */ 555390065b1SAlfred Perlstein dummy = 0; 5568c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 557698e791aSHans Petter Selasky if (err < (int)sizeof(dummy)) { 558390065b1SAlfred Perlstein /* ignore error, if any */ 559390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 560c500e4ddSAndrew Thompson } 5618c8fff31SAndrew Thompson } 5628c8fff31SAndrew Thompson 5638c8fff31SAndrew Thompson libusb_device * 564390065b1SAlfred Perlstein libusb_get_device(struct libusb20_device *pdev) 5658c8fff31SAndrew Thompson { 566390065b1SAlfred Perlstein if (pdev == NULL) 5678c8fff31SAndrew Thompson return (NULL); 568390065b1SAlfred Perlstein return ((libusb_device *)pdev->privLuData); 5698c8fff31SAndrew Thompson } 5708c8fff31SAndrew Thompson 5718c8fff31SAndrew Thompson int 572390065b1SAlfred Perlstein libusb_get_configuration(struct libusb20_device *pdev, int *config) 5738c8fff31SAndrew Thompson { 574390065b1SAlfred Perlstein struct libusb20_config *pconf; 5758c8fff31SAndrew Thompson 576390065b1SAlfred Perlstein if (pdev == NULL || config == NULL) 5778c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5788c8fff31SAndrew Thompson 579390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 580390065b1SAlfred Perlstein if (pconf == NULL) 581c500e4ddSAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 5828c8fff31SAndrew Thompson 583390065b1SAlfred Perlstein *config = pconf->desc.bConfigurationValue; 5848c8fff31SAndrew Thompson 585390065b1SAlfred Perlstein free(pconf); 5868c8fff31SAndrew Thompson 5878c8fff31SAndrew Thompson return (0); 5888c8fff31SAndrew Thompson } 5898c8fff31SAndrew Thompson 5908c8fff31SAndrew Thompson int 591390065b1SAlfred Perlstein libusb_set_configuration(struct libusb20_device *pdev, int configuration) 5928c8fff31SAndrew Thompson { 593390065b1SAlfred Perlstein struct libusb20_config *pconf; 594390065b1SAlfred Perlstein struct libusb_device *dev; 595390065b1SAlfred Perlstein int err; 596390065b1SAlfred Perlstein uint8_t i; 5978c8fff31SAndrew Thompson 598390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 5998c8fff31SAndrew Thompson if (dev == NULL) 600390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 601390065b1SAlfred Perlstein 602390065b1SAlfred Perlstein if (configuration < 1) { 603390065b1SAlfred Perlstein /* unconfigure */ 604390065b1SAlfred Perlstein i = 255; 605390065b1SAlfred Perlstein } else { 606390065b1SAlfred Perlstein for (i = 0; i != 255; i++) { 607390065b1SAlfred Perlstein uint8_t found; 608390065b1SAlfred Perlstein 609390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, i); 610390065b1SAlfred Perlstein if (pconf == NULL) 611390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 612390065b1SAlfred Perlstein found = (pconf->desc.bConfigurationValue 613390065b1SAlfred Perlstein == configuration); 614390065b1SAlfred Perlstein free(pconf); 615390065b1SAlfred Perlstein 616390065b1SAlfred Perlstein if (found) 617390065b1SAlfred Perlstein goto set_config; 618390065b1SAlfred Perlstein } 619390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 620390065b1SAlfred Perlstein } 621390065b1SAlfred Perlstein 622390065b1SAlfred Perlstein set_config: 623390065b1SAlfred Perlstein 624390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 625390065b1SAlfred Perlstein 626390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 627390065b1SAlfred Perlstein 628390065b1SAlfred Perlstein err = libusb20_dev_set_config_index(pdev, i); 629390065b1SAlfred Perlstein 630390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 631390065b1SAlfred Perlstein POLLOUT | POLLRDNORM | POLLWRNORM); 632390065b1SAlfred Perlstein 633390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 634390065b1SAlfred Perlstein } 635390065b1SAlfred Perlstein 636390065b1SAlfred Perlstein int 637390065b1SAlfred Perlstein libusb_claim_interface(struct libusb20_device *pdev, int interface_number) 638390065b1SAlfred Perlstein { 639390065b1SAlfred Perlstein libusb_device *dev; 640*5b40d960SHans Petter Selasky int err = 0; 641390065b1SAlfred Perlstein 642390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 643390065b1SAlfred Perlstein if (dev == NULL) 644390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 645390065b1SAlfred Perlstein 646390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 647390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 648390065b1SAlfred Perlstein 649*5b40d960SHans Petter Selasky if (pdev->auto_detach != 0) { 650*5b40d960SHans Petter Selasky err = libusb_detach_kernel_driver(pdev, interface_number); 651*5b40d960SHans Petter Selasky if (err != 0) 652*5b40d960SHans Petter Selasky goto done; 653*5b40d960SHans Petter Selasky } 654*5b40d960SHans Petter Selasky 655390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 656390065b1SAlfred Perlstein dev->claimed_interfaces |= (1 << interface_number); 657390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 658*5b40d960SHans Petter Selasky done: 659*5b40d960SHans Petter Selasky return (err); 660390065b1SAlfred Perlstein } 661390065b1SAlfred Perlstein 662390065b1SAlfred Perlstein int 663390065b1SAlfred Perlstein libusb_release_interface(struct libusb20_device *pdev, int interface_number) 664390065b1SAlfred Perlstein { 665390065b1SAlfred Perlstein libusb_device *dev; 666390065b1SAlfred Perlstein int err = 0; 667390065b1SAlfred Perlstein 668390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 669390065b1SAlfred Perlstein if (dev == NULL) 670390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 671390065b1SAlfred Perlstein 672390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 673390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 674390065b1SAlfred Perlstein 675*5b40d960SHans Petter Selasky if (pdev->auto_detach != 0) { 676*5b40d960SHans Petter Selasky err = libusb_attach_kernel_driver(pdev, interface_number); 677*5b40d960SHans Petter Selasky if (err != 0) 678*5b40d960SHans Petter Selasky goto done; 679*5b40d960SHans Petter Selasky } 680*5b40d960SHans Petter Selasky 681390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 682390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 683390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 684*5b40d960SHans Petter Selasky else 685390065b1SAlfred Perlstein dev->claimed_interfaces &= ~(1 << interface_number); 686390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 687*5b40d960SHans Petter Selasky done: 688390065b1SAlfred Perlstein return (err); 689390065b1SAlfred Perlstein } 690390065b1SAlfred Perlstein 691390065b1SAlfred Perlstein int 692390065b1SAlfred Perlstein libusb_set_interface_alt_setting(struct libusb20_device *pdev, 693390065b1SAlfred Perlstein int interface_number, int alternate_setting) 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 705390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 706390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 707390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 708390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 709390065b1SAlfred Perlstein 710390065b1SAlfred Perlstein if (err) 711390065b1SAlfred Perlstein return (err); 712390065b1SAlfred Perlstein 713390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 714390065b1SAlfred Perlstein 715390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 716390065b1SAlfred Perlstein 717390065b1SAlfred Perlstein err = libusb20_dev_set_alt_index(pdev, 718390065b1SAlfred Perlstein interface_number, alternate_setting); 719390065b1SAlfred Perlstein 720390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 721390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 722390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 723390065b1SAlfred Perlstein 724390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 725390065b1SAlfred Perlstein } 726390065b1SAlfred Perlstein 727390065b1SAlfred Perlstein static struct libusb20_transfer * 728390065b1SAlfred Perlstein libusb10_get_transfer(struct libusb20_device *pdev, 729d81535d1SHans Petter Selasky uint8_t endpoint, uint8_t xfer_index) 730390065b1SAlfred Perlstein { 731d81535d1SHans Petter Selasky xfer_index &= 1; /* double buffering */ 732390065b1SAlfred Perlstein 733d81535d1SHans Petter Selasky xfer_index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 734390065b1SAlfred Perlstein 735390065b1SAlfred Perlstein if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 736390065b1SAlfred Perlstein /* this is an IN endpoint */ 737d81535d1SHans Petter Selasky xfer_index |= 2; 738390065b1SAlfred Perlstein } 739d81535d1SHans Petter Selasky return (libusb20_tr_get_pointer(pdev, xfer_index)); 740390065b1SAlfred Perlstein } 741390065b1SAlfred Perlstein 742390065b1SAlfred Perlstein int 743390065b1SAlfred Perlstein libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 744390065b1SAlfred Perlstein { 745390065b1SAlfred Perlstein struct libusb20_transfer *xfer; 746390065b1SAlfred Perlstein struct libusb_device *dev; 747390065b1SAlfred Perlstein int err; 748390065b1SAlfred Perlstein 749390065b1SAlfred Perlstein xfer = libusb10_get_transfer(pdev, endpoint, 0); 750390065b1SAlfred Perlstein if (xfer == NULL) 751390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 752390065b1SAlfred Perlstein 753390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 754698e791aSHans Petter Selasky if (dev == NULL) 755698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 756390065b1SAlfred Perlstein 757390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 758a7e048a2SHans Petter Selasky err = libusb20_tr_open(xfer, 0, 1, endpoint); 759390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 760390065b1SAlfred Perlstein 761390065b1SAlfred Perlstein if (err != 0 && err != LIBUSB20_ERROR_BUSY) 762390065b1SAlfred Perlstein return (LIBUSB_ERROR_OTHER); 763390065b1SAlfred Perlstein 764390065b1SAlfred Perlstein libusb20_tr_clear_stall_sync(xfer); 765390065b1SAlfred Perlstein 766390065b1SAlfred Perlstein /* check if we opened the transfer */ 767390065b1SAlfred Perlstein if (err == 0) { 768390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 769390065b1SAlfred Perlstein libusb20_tr_close(xfer); 770390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 771390065b1SAlfred Perlstein } 772390065b1SAlfred Perlstein return (0); /* success */ 773390065b1SAlfred Perlstein } 774390065b1SAlfred Perlstein 775390065b1SAlfred Perlstein int 776390065b1SAlfred Perlstein libusb_reset_device(struct libusb20_device *pdev) 777390065b1SAlfred Perlstein { 778390065b1SAlfred Perlstein libusb_device *dev; 779390065b1SAlfred Perlstein int err; 780390065b1SAlfred Perlstein 781390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 782390065b1SAlfred Perlstein if (dev == NULL) 783698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 7848c8fff31SAndrew Thompson 785390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 786390065b1SAlfred Perlstein 787390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 788390065b1SAlfred Perlstein 789390065b1SAlfred Perlstein err = libusb20_dev_reset(pdev); 790390065b1SAlfred Perlstein 791390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 792390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 793390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 794390065b1SAlfred Perlstein 795390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 7968c8fff31SAndrew Thompson } 7978c8fff31SAndrew Thompson 7988c8fff31SAndrew Thompson int 799f1b5fa6eSHans Petter Selasky libusb_check_connected(struct libusb20_device *pdev) 800f1b5fa6eSHans Petter Selasky { 801f1b5fa6eSHans Petter Selasky libusb_device *dev; 802f1b5fa6eSHans Petter Selasky int err; 803f1b5fa6eSHans Petter Selasky 804f1b5fa6eSHans Petter Selasky dev = libusb_get_device(pdev); 805f1b5fa6eSHans Petter Selasky if (dev == NULL) 806f1b5fa6eSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 807f1b5fa6eSHans Petter Selasky 808f1b5fa6eSHans Petter Selasky err = libusb20_dev_check_connected(pdev); 809f1b5fa6eSHans Petter Selasky 810f1b5fa6eSHans Petter Selasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 811f1b5fa6eSHans Petter Selasky } 812f1b5fa6eSHans Petter Selasky 813f1b5fa6eSHans Petter Selasky int 814390065b1SAlfred Perlstein libusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 8158c8fff31SAndrew Thompson { 816390065b1SAlfred Perlstein if (pdev == NULL) 8178c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 8188c8fff31SAndrew Thompson 8194d2472aaSHans Petter Selasky if (libusb20_dev_kernel_driver_active(pdev, interface)) 8204d2472aaSHans Petter Selasky return (0); /* no kernel driver is active */ 8214d2472aaSHans Petter Selasky else 8224d2472aaSHans Petter Selasky return (1); /* kernel driver is active */ 8238c8fff31SAndrew Thompson } 8248c8fff31SAndrew Thompson 8258c8fff31SAndrew Thompson int 826698e791aSHans Petter Selasky libusb_get_driver_np(struct libusb20_device *pdev, int interface, 827698e791aSHans Petter Selasky char *name, int namelen) 828698e791aSHans Petter Selasky { 829698e791aSHans Petter Selasky return (libusb_get_driver(pdev, interface, name, namelen)); 830698e791aSHans Petter Selasky } 831698e791aSHans Petter Selasky 832698e791aSHans Petter Selasky int 833698e791aSHans Petter Selasky libusb_get_driver(struct libusb20_device *pdev, int interface, 834698e791aSHans Petter Selasky char *name, int namelen) 835698e791aSHans Petter Selasky { 836698e791aSHans Petter Selasky char *ptr; 837698e791aSHans Petter Selasky int err; 838698e791aSHans Petter Selasky 839698e791aSHans Petter Selasky if (pdev == NULL) 840698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 841698e791aSHans Petter Selasky if (namelen < 1) 842698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 8434eb5923dSHans Petter Selasky if (namelen > 255) 8444eb5923dSHans Petter Selasky namelen = 255; 845698e791aSHans Petter Selasky 846698e791aSHans Petter Selasky err = libusb20_dev_get_iface_desc( 847698e791aSHans Petter Selasky pdev, interface, name, namelen); 848698e791aSHans Petter Selasky 849698e791aSHans Petter Selasky if (err != 0) 850698e791aSHans Petter Selasky return (LIBUSB_ERROR_OTHER); 851698e791aSHans Petter Selasky 852698e791aSHans Petter Selasky /* we only want the driver name */ 853698e791aSHans Petter Selasky ptr = strstr(name, ":"); 854698e791aSHans Petter Selasky if (ptr != NULL) 855698e791aSHans Petter Selasky *ptr = 0; 856698e791aSHans Petter Selasky 857698e791aSHans Petter Selasky return (0); 858698e791aSHans Petter Selasky } 859698e791aSHans Petter Selasky 860698e791aSHans Petter Selasky int 861698e791aSHans Petter Selasky libusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface) 862698e791aSHans Petter Selasky { 863698e791aSHans Petter Selasky return (libusb_detach_kernel_driver(pdev, interface)); 864698e791aSHans Petter Selasky } 865698e791aSHans Petter Selasky 866698e791aSHans Petter Selasky int 867390065b1SAlfred Perlstein libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 8688c8fff31SAndrew Thompson { 869390065b1SAlfred Perlstein int err; 8708c8fff31SAndrew Thompson 871390065b1SAlfred Perlstein if (pdev == NULL) 8728c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 8738c8fff31SAndrew Thompson 874390065b1SAlfred Perlstein err = libusb20_dev_detach_kernel_driver( 875390065b1SAlfred Perlstein pdev, interface); 8768c8fff31SAndrew Thompson 877698e791aSHans Petter Selasky return (err ? LIBUSB_ERROR_OTHER : 0); 8788c8fff31SAndrew Thompson } 8798c8fff31SAndrew Thompson 8808c8fff31SAndrew Thompson int 881390065b1SAlfred Perlstein libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 8828c8fff31SAndrew Thompson { 883390065b1SAlfred Perlstein if (pdev == NULL) 8848c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 885390065b1SAlfred Perlstein /* stub - currently not supported by libusb20 */ 8868c8fff31SAndrew Thompson return (0); 8878c8fff31SAndrew Thompson } 8888c8fff31SAndrew Thompson 889*5b40d960SHans Petter Selasky int 890*5b40d960SHans Petter Selasky libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable) 891*5b40d960SHans Petter Selasky { 892*5b40d960SHans Petter Selasky dev->auto_detach = (enable ? 1 : 0); 893*5b40d960SHans Petter Selasky } 894*5b40d960SHans Petter Selasky 8958c8fff31SAndrew Thompson /* Asynchronous device I/O */ 8968c8fff31SAndrew Thompson 8978c8fff31SAndrew Thompson struct libusb_transfer * 8988c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets) 8998c8fff31SAndrew Thompson { 900390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 901390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 9028c8fff31SAndrew Thompson int len; 9038c8fff31SAndrew Thompson 9048c8fff31SAndrew Thompson len = sizeof(struct libusb_transfer) + 905390065b1SAlfred Perlstein sizeof(struct libusb_super_transfer) + 9068c8fff31SAndrew Thompson (iso_packets * sizeof(libusb_iso_packet_descriptor)); 9078c8fff31SAndrew Thompson 908390065b1SAlfred Perlstein sxfer = malloc(len); 909390065b1SAlfred Perlstein if (sxfer == NULL) 9108c8fff31SAndrew Thompson return (NULL); 9118c8fff31SAndrew Thompson 912390065b1SAlfred Perlstein memset(sxfer, 0, len); 9138c8fff31SAndrew Thompson 914390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 915390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 9168c8fff31SAndrew Thompson 917390065b1SAlfred Perlstein /* set default value */ 918390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 919390065b1SAlfred Perlstein 920390065b1SAlfred Perlstein return (uxfer); 9218c8fff31SAndrew Thompson } 9228c8fff31SAndrew Thompson 9238c8fff31SAndrew Thompson void 924390065b1SAlfred Perlstein libusb_free_transfer(struct libusb_transfer *uxfer) 9258c8fff31SAndrew Thompson { 926390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 9278c8fff31SAndrew Thompson 928390065b1SAlfred Perlstein if (uxfer == NULL) 929390065b1SAlfred Perlstein return; /* be NULL safe */ 9308c8fff31SAndrew Thompson 93131f7072cSHans Petter Selasky /* check if we should free the transfer buffer */ 93231f7072cSHans Petter Selasky if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) 93331f7072cSHans Petter Selasky free(uxfer->buffer); 93431f7072cSHans Petter Selasky 935390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 936390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 9378c8fff31SAndrew Thompson 938390065b1SAlfred Perlstein free(sxfer); 9398c8fff31SAndrew Thompson } 9408c8fff31SAndrew Thompson 9411c497368SHans Petter Selasky static uint32_t 942390065b1SAlfred Perlstein libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 9438c8fff31SAndrew Thompson { 9441c497368SHans Petter Selasky uint32_t ret; 9458c8fff31SAndrew Thompson 9468c8fff31SAndrew Thompson switch (xfer->type) { 9478c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 9481c497368SHans Petter Selasky ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */ 9498c8fff31SAndrew Thompson break; 9508c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 9518c8fff31SAndrew Thompson ret = 2; 9528c8fff31SAndrew Thompson break; 9538c8fff31SAndrew Thompson default: 9548c8fff31SAndrew Thompson ret = 1; 9558c8fff31SAndrew Thompson break; 9568c8fff31SAndrew Thompson } 957390065b1SAlfred Perlstein return (ret); 9588c8fff31SAndrew Thompson } 9598c8fff31SAndrew Thompson 9608c8fff31SAndrew Thompson static int 961390065b1SAlfred Perlstein libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 9628c8fff31SAndrew Thompson { 9638c8fff31SAndrew Thompson int ret; 9648c8fff31SAndrew Thompson int usb_speed; 9658c8fff31SAndrew Thompson 9668c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 9678c8fff31SAndrew Thompson 9688c8fff31SAndrew Thompson switch (xfer->type) { 9698c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 970390065b1SAlfred Perlstein ret = 0; /* kernel will auto-select */ 9718c8fff31SAndrew Thompson break; 9728c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 973390065b1SAlfred Perlstein ret = 1024; 9748c8fff31SAndrew Thompson break; 9758c8fff31SAndrew Thompson default: 9768c8fff31SAndrew Thompson switch (usb_speed) { 9778c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 9788c8fff31SAndrew Thompson ret = 256; 9798c8fff31SAndrew Thompson break; 9808c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 9818c8fff31SAndrew Thompson ret = 4096; 9828c8fff31SAndrew Thompson break; 983f355a4ddSHans Petter Selasky case LIBUSB20_SPEED_SUPER: 984f355a4ddSHans Petter Selasky ret = 65536; 985f355a4ddSHans Petter Selasky break; 9868c8fff31SAndrew Thompson default: 9878c8fff31SAndrew Thompson ret = 16384; 9888c8fff31SAndrew Thompson break; 9898c8fff31SAndrew Thompson } 9908c8fff31SAndrew Thompson break; 9918c8fff31SAndrew Thompson } 992390065b1SAlfred Perlstein return (ret); 9938c8fff31SAndrew Thompson } 9948c8fff31SAndrew Thompson 995390065b1SAlfred Perlstein static int 996390065b1SAlfred Perlstein libusb10_convert_error(uint8_t status) 997390065b1SAlfred Perlstein { 998390065b1SAlfred Perlstein ; /* indent fix */ 999390065b1SAlfred Perlstein 1000390065b1SAlfred Perlstein switch (status) { 1001390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1002390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1003390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_COMPLETED); 1004390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_OVERFLOW: 1005390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_OVERFLOW); 1006390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_NO_DEVICE: 1007390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_NO_DEVICE); 1008390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_STALL: 1009390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_STALL); 1010390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_CANCELLED: 1011390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_CANCELLED); 1012390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_TIMED_OUT: 1013390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_TIMED_OUT); 1014390065b1SAlfred Perlstein default: 1015390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_ERROR); 1016390065b1SAlfred Perlstein } 1017390065b1SAlfred Perlstein } 1018390065b1SAlfred Perlstein 1019390065b1SAlfred Perlstein /* This function must be called locked */ 1020390065b1SAlfred Perlstein 1021c500e4ddSAndrew Thompson static void 1022390065b1SAlfred Perlstein libusb10_complete_transfer(struct libusb20_transfer *pxfer, 1023390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer, int status) 1024c500e4ddSAndrew Thompson { 1025390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1026390065b1SAlfred Perlstein struct libusb_device *dev; 1027c500e4ddSAndrew Thompson 1028390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1029390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1030390065b1SAlfred Perlstein 1031390065b1SAlfred Perlstein if (pxfer != NULL) 1032390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer, NULL); 1033390065b1SAlfred Perlstein 10344594d907SAndrew Thompson /* set transfer status */ 1035390065b1SAlfred Perlstein uxfer->status = status; 1036390065b1SAlfred Perlstein 10374594d907SAndrew Thompson /* update super transfer state */ 10384594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 10394594d907SAndrew Thompson 1040390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 1041390065b1SAlfred Perlstein 1042390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 1043390065b1SAlfred Perlstein } 1044390065b1SAlfred Perlstein 1045390065b1SAlfred Perlstein /* This function must be called locked */ 1046390065b1SAlfred Perlstein 1047390065b1SAlfred Perlstein static void 1048390065b1SAlfred Perlstein libusb10_isoc_proxy(struct libusb20_transfer *pxfer) 1049390065b1SAlfred Perlstein { 1050390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1051390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1052390065b1SAlfred Perlstein uint32_t actlen; 1053390065b1SAlfred Perlstein uint16_t iso_packets; 1054390065b1SAlfred Perlstein uint16_t i; 1055390065b1SAlfred Perlstein uint8_t status; 1056390065b1SAlfred Perlstein 1057390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1058390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1059390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1060390065b1SAlfred Perlstein iso_packets = libusb20_tr_get_max_frames(pxfer); 1061390065b1SAlfred Perlstein 1062390065b1SAlfred Perlstein if (sxfer == NULL) 1063390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1064390065b1SAlfred Perlstein 1065390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1066390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1067390065b1SAlfred Perlstein 1068390065b1SAlfred Perlstein if (iso_packets > uxfer->num_iso_packets) 1069390065b1SAlfred Perlstein iso_packets = uxfer->num_iso_packets; 1070390065b1SAlfred Perlstein 1071390065b1SAlfred Perlstein if (iso_packets == 0) 1072390065b1SAlfred Perlstein return; /* nothing to do */ 1073390065b1SAlfred Perlstein 1074390065b1SAlfred Perlstein /* make sure that the number of ISOCHRONOUS packets is valid */ 1075390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 1076390065b1SAlfred Perlstein 1077c500e4ddSAndrew Thompson switch (status) { 1078c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 1079390065b1SAlfred Perlstein /* update actual length */ 1080390065b1SAlfred Perlstein uxfer->actual_length = actlen; 1081390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 1082390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].actual_length = 1083390065b1SAlfred Perlstein libusb20_tr_get_length(pxfer, i); 1084390065b1SAlfred Perlstein } 1085390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1086c500e4ddSAndrew Thompson break; 1087c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_START: 1088390065b1SAlfred Perlstein /* setup length(s) */ 1089390065b1SAlfred Perlstein actlen = 0; 1090390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 1091390065b1SAlfred Perlstein libusb20_tr_setup_isoc(pxfer, 1092390065b1SAlfred Perlstein &uxfer->buffer[actlen], 1093390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].length, i); 1094390065b1SAlfred Perlstein actlen += uxfer->iso_packet_desc[i].length; 1095c500e4ddSAndrew Thompson } 1096390065b1SAlfred Perlstein 1097390065b1SAlfred Perlstein /* no remainder */ 1098390065b1SAlfred Perlstein sxfer->rem_len = 0; 1099390065b1SAlfred Perlstein 1100390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, iso_packets); 1101390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1102390065b1SAlfred Perlstein 1103390065b1SAlfred Perlstein /* fork another USB transfer, if any */ 1104390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1105c500e4ddSAndrew Thompson break; 1106390065b1SAlfred Perlstein default: 1107390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1108c500e4ddSAndrew Thompson break; 1109c500e4ddSAndrew Thompson } 1110390065b1SAlfred Perlstein } 1111390065b1SAlfred Perlstein 1112390065b1SAlfred Perlstein /* This function must be called locked */ 1113390065b1SAlfred Perlstein 1114390065b1SAlfred Perlstein static void 1115390065b1SAlfred Perlstein libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 1116390065b1SAlfred Perlstein { 1117390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1118390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1119390065b1SAlfred Perlstein uint32_t max_bulk; 1120390065b1SAlfred Perlstein uint32_t actlen; 1121390065b1SAlfred Perlstein uint8_t status; 1122390065b1SAlfred Perlstein uint8_t flags; 1123390065b1SAlfred Perlstein 1124390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1125390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1126390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1127390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1128390065b1SAlfred Perlstein 1129390065b1SAlfred Perlstein if (sxfer == NULL) 1130390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1131390065b1SAlfred Perlstein 1132390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1133390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1134390065b1SAlfred Perlstein 1135390065b1SAlfred Perlstein flags = uxfer->flags; 1136390065b1SAlfred Perlstein 1137390065b1SAlfred Perlstein switch (status) { 1138390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1139390065b1SAlfred Perlstein 1140390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1141390065b1SAlfred Perlstein 1142390065b1SAlfred Perlstein /* check for short packet */ 1143390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1144390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1145390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1146390065b1SAlfred Perlstein } else { 1147390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1148390065b1SAlfred Perlstein } 1149390065b1SAlfred Perlstein break; 1150390065b1SAlfred Perlstein } 1151390065b1SAlfred Perlstein /* check for end of data */ 1152390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1153390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1154390065b1SAlfred Perlstein break; 1155390065b1SAlfred Perlstein } 1156390065b1SAlfred Perlstein /* FALLTHROUGH */ 1157390065b1SAlfred Perlstein 1158390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1159390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1160390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1161390065b1SAlfred Perlstein } 1162390065b1SAlfred Perlstein /* setup new BULK or INTERRUPT transaction */ 1163390065b1SAlfred Perlstein libusb20_tr_setup_bulk(pxfer, 1164390065b1SAlfred Perlstein sxfer->curr_data, max_bulk, uxfer->timeout); 1165390065b1SAlfred Perlstein 1166390065b1SAlfred Perlstein /* update counters */ 1167390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1168390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1169390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1170390065b1SAlfred Perlstein 1171390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1172390065b1SAlfred Perlstein 1173390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1174390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1175390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1176390065b1SAlfred Perlstein break; 1177390065b1SAlfred Perlstein 1178390065b1SAlfred Perlstein default: 1179390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1180390065b1SAlfred Perlstein break; 1181390065b1SAlfred Perlstein } 1182390065b1SAlfred Perlstein } 1183390065b1SAlfred Perlstein 1184390065b1SAlfred Perlstein /* This function must be called locked */ 1185390065b1SAlfred Perlstein 1186390065b1SAlfred Perlstein static void 1187390065b1SAlfred Perlstein libusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1188390065b1SAlfred Perlstein { 1189390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1190390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1191390065b1SAlfred Perlstein uint32_t max_bulk; 1192390065b1SAlfred Perlstein uint32_t actlen; 1193390065b1SAlfred Perlstein uint8_t status; 1194390065b1SAlfred Perlstein uint8_t flags; 1195390065b1SAlfred Perlstein 1196390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1197390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1198390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1199390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1200390065b1SAlfred Perlstein 1201390065b1SAlfred Perlstein if (sxfer == NULL) 1202390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1203390065b1SAlfred Perlstein 1204390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1205390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1206390065b1SAlfred Perlstein 1207390065b1SAlfred Perlstein flags = uxfer->flags; 1208390065b1SAlfred Perlstein 1209390065b1SAlfred Perlstein switch (status) { 1210390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1211390065b1SAlfred Perlstein 1212390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1213390065b1SAlfred Perlstein 1214390065b1SAlfred Perlstein /* subtract length of SETUP packet, if any */ 1215390065b1SAlfred Perlstein actlen -= libusb20_tr_get_length(pxfer, 0); 1216390065b1SAlfred Perlstein 1217390065b1SAlfred Perlstein /* check for short packet */ 1218390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1219390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1220390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1221390065b1SAlfred Perlstein } else { 1222390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1223390065b1SAlfred Perlstein } 1224390065b1SAlfred Perlstein break; 1225390065b1SAlfred Perlstein } 1226390065b1SAlfred Perlstein /* check for end of data */ 1227390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1228390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1229390065b1SAlfred Perlstein break; 1230390065b1SAlfred Perlstein } 1231390065b1SAlfred Perlstein /* FALLTHROUGH */ 1232390065b1SAlfred Perlstein 1233390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1234390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1235390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1236390065b1SAlfred Perlstein } 1237390065b1SAlfred Perlstein /* setup new CONTROL transaction */ 1238390065b1SAlfred Perlstein if (status == LIBUSB20_TRANSFER_COMPLETED) { 1239390065b1SAlfred Perlstein /* next fragment - don't send SETUP packet */ 1240390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 0, 0); 1241390065b1SAlfred Perlstein } else { 1242390065b1SAlfred Perlstein /* first fragment - send SETUP packet */ 1243390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 8, 0); 1244390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1245390065b1SAlfred Perlstein } 1246390065b1SAlfred Perlstein 1247390065b1SAlfred Perlstein if (max_bulk != 0) { 1248390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, max_bulk, 1); 1249390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1250390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 2); 1251390065b1SAlfred Perlstein } else { 1252390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 1); 1253390065b1SAlfred Perlstein } 1254390065b1SAlfred Perlstein 1255390065b1SAlfred Perlstein /* update counters */ 1256390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1257390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1258390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1259390065b1SAlfred Perlstein 1260390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1261390065b1SAlfred Perlstein 1262390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1263390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1264390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1265390065b1SAlfred Perlstein break; 1266390065b1SAlfred Perlstein 1267390065b1SAlfred Perlstein default: 1268390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1269390065b1SAlfred Perlstein break; 1270390065b1SAlfred Perlstein } 1271390065b1SAlfred Perlstein } 1272390065b1SAlfred Perlstein 1273390065b1SAlfred Perlstein /* The following function must be called locked */ 1274390065b1SAlfred Perlstein 1275390065b1SAlfred Perlstein static void 1276390065b1SAlfred Perlstein libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1277390065b1SAlfred Perlstein { 1278390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1279390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1280390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1281390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1282390065b1SAlfred Perlstein struct libusb_device *dev; 1283390065b1SAlfred Perlstein int err; 1284390065b1SAlfred Perlstein int buffsize; 1285390065b1SAlfred Perlstein int maxframe; 1286390065b1SAlfred Perlstein int temp; 1287390065b1SAlfred Perlstein uint8_t dummy; 1288390065b1SAlfred Perlstein 1289390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 1290390065b1SAlfred Perlstein 1291390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1292390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1293390065b1SAlfred Perlstein 1294390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) 1295390065b1SAlfred Perlstein return; /* shouldn't happen */ 1296390065b1SAlfred Perlstein 1297390065b1SAlfred Perlstein temp = 0; 1298390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer0)) 1299390065b1SAlfred Perlstein temp |= 1; 1300390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer1)) 1301390065b1SAlfred Perlstein temp |= 2; 1302390065b1SAlfred Perlstein 1303390065b1SAlfred Perlstein switch (temp) { 1304390065b1SAlfred Perlstein case 3: 1305390065b1SAlfred Perlstein /* wait till one of the transfers complete */ 1306390065b1SAlfred Perlstein return; 1307390065b1SAlfred Perlstein case 2: 1308390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer1); 13094594d907SAndrew Thompson if (sxfer == NULL) 13104594d907SAndrew Thompson return; /* cancelling */ 1311390065b1SAlfred Perlstein if (sxfer->rem_len) 1312390065b1SAlfred Perlstein return; /* cannot queue another one */ 1313390065b1SAlfred Perlstein /* swap transfers */ 1314390065b1SAlfred Perlstein pxfer1 = pxfer0; 1315390065b1SAlfred Perlstein break; 1316390065b1SAlfred Perlstein case 1: 1317390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer0); 13184594d907SAndrew Thompson if (sxfer == NULL) 13194594d907SAndrew Thompson return; /* cancelling */ 1320390065b1SAlfred Perlstein if (sxfer->rem_len) 1321390065b1SAlfred Perlstein return; /* cannot queue another one */ 1322390065b1SAlfred Perlstein /* swap transfers */ 1323390065b1SAlfred Perlstein pxfer0 = pxfer1; 1324c500e4ddSAndrew Thompson break; 1325c500e4ddSAndrew Thompson default: 1326c500e4ddSAndrew Thompson break; 1327c500e4ddSAndrew Thompson } 1328c500e4ddSAndrew Thompson 1329390065b1SAlfred Perlstein /* find next transfer on same endpoint */ 1330390065b1SAlfred Perlstein TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1331390065b1SAlfred Perlstein 1332390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1333390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1334390065b1SAlfred Perlstein 1335390065b1SAlfred Perlstein if (uxfer->endpoint == endpoint) { 1336390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1337390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 1338390065b1SAlfred Perlstein goto found; 1339c500e4ddSAndrew Thompson } 1340c500e4ddSAndrew Thompson } 1341390065b1SAlfred Perlstein return; /* success */ 1342390065b1SAlfred Perlstein 1343390065b1SAlfred Perlstein found: 1344390065b1SAlfred Perlstein 1345390065b1SAlfred Perlstein libusb20_tr_set_priv_sc0(pxfer0, pdev); 1346390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1347390065b1SAlfred Perlstein 1348390065b1SAlfred Perlstein /* reset super transfer state */ 1349390065b1SAlfred Perlstein sxfer->rem_len = uxfer->length; 1350390065b1SAlfred Perlstein sxfer->curr_data = uxfer->buffer; 1351390065b1SAlfred Perlstein uxfer->actual_length = 0; 1352390065b1SAlfred Perlstein 1353390065b1SAlfred Perlstein switch (uxfer->type) { 1354390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1355390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1356390065b1SAlfred Perlstein break; 1357390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_BULK: 1358390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1359390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1360390065b1SAlfred Perlstein break; 1361390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_CONTROL: 1362390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1363390065b1SAlfred Perlstein if (sxfer->rem_len < 8) 1364390065b1SAlfred Perlstein goto failure; 1365390065b1SAlfred Perlstein 1366390065b1SAlfred Perlstein /* remove SETUP packet from data */ 1367390065b1SAlfred Perlstein sxfer->rem_len -= 8; 1368390065b1SAlfred Perlstein sxfer->curr_data += 8; 1369390065b1SAlfred Perlstein break; 1370390065b1SAlfred Perlstein default: 1371390065b1SAlfred Perlstein goto failure; 1372390065b1SAlfred Perlstein } 1373390065b1SAlfred Perlstein 1374390065b1SAlfred Perlstein buffsize = libusb10_get_buffsize(pdev, uxfer); 1375390065b1SAlfred Perlstein maxframe = libusb10_get_maxframe(pdev, uxfer); 1376390065b1SAlfred Perlstein 1377390065b1SAlfred Perlstein /* make sure the transfer is opened */ 1378390065b1SAlfred Perlstein err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1379390065b1SAlfred Perlstein if (err && (err != LIBUSB20_ERROR_BUSY)) { 1380390065b1SAlfred Perlstein goto failure; 1381390065b1SAlfred Perlstein } 1382390065b1SAlfred Perlstein libusb20_tr_start(pxfer0); 1383390065b1SAlfred Perlstein return; 1384390065b1SAlfred Perlstein 1385390065b1SAlfred Perlstein failure: 1386390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1387390065b1SAlfred Perlstein 1388390065b1SAlfred Perlstein /* make sure our event loop spins the done handler */ 1389390065b1SAlfred Perlstein dummy = 0; 139066194130SHans Petter Selasky err = write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1391390065b1SAlfred Perlstein } 1392390065b1SAlfred Perlstein 1393390065b1SAlfred Perlstein /* The following function must be called unlocked */ 1394c500e4ddSAndrew Thompson 13958c8fff31SAndrew Thompson int 1396390065b1SAlfred Perlstein libusb_submit_transfer(struct libusb_transfer *uxfer) 13978c8fff31SAndrew Thompson { 1398390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1399390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1400390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1401390065b1SAlfred Perlstein struct libusb_device *dev; 140285ff9a03SHans Petter Selasky uint8_t endpoint; 1403390065b1SAlfred Perlstein int err; 14048c8fff31SAndrew Thompson 1405390065b1SAlfred Perlstein if (uxfer == NULL) 1406390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 14078c8fff31SAndrew Thompson 1408390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 1409390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 14108c8fff31SAndrew Thompson 1411390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 14128c8fff31SAndrew Thompson 1413390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 14148c8fff31SAndrew Thompson 1415390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 14168c8fff31SAndrew Thompson 1417390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1418390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1419390065b1SAlfred Perlstein 1420390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1421390065b1SAlfred Perlstein 1422390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1423390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1424390065b1SAlfred Perlstein 1425390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) { 1426390065b1SAlfred Perlstein err = LIBUSB_ERROR_OTHER; 1427390065b1SAlfred Perlstein } else if ((sxfer->entry.tqe_prev != NULL) || 1428390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1429390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1430390065b1SAlfred Perlstein err = LIBUSB_ERROR_BUSY; 1431390065b1SAlfred Perlstein } else { 14324594d907SAndrew Thompson 14334594d907SAndrew Thompson /* set pending state */ 14344594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 14354594d907SAndrew Thompson 14364594d907SAndrew Thompson /* insert transfer into transfer head list */ 1437390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1438390065b1SAlfred Perlstein 14394594d907SAndrew Thompson /* start work transfers */ 1440390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1441390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1442390065b1SAlfred Perlstein 1443390065b1SAlfred Perlstein err = 0; /* success */ 14448c8fff31SAndrew Thompson } 14458c8fff31SAndrew Thompson 1446390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 1447390065b1SAlfred Perlstein 1448390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1449390065b1SAlfred Perlstein 1450390065b1SAlfred Perlstein return (err); 14518c8fff31SAndrew Thompson } 14528c8fff31SAndrew Thompson 1453390065b1SAlfred Perlstein /* Asynchronous transfer cancel */ 14548c8fff31SAndrew Thompson 1455390065b1SAlfred Perlstein int 1456390065b1SAlfred Perlstein libusb_cancel_transfer(struct libusb_transfer *uxfer) 1457390065b1SAlfred Perlstein { 1458390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1459390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1460390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1461390065b1SAlfred Perlstein struct libusb_device *dev; 146285ff9a03SHans Petter Selasky uint8_t endpoint; 14634594d907SAndrew Thompson int retval; 14648c8fff31SAndrew Thompson 1465390065b1SAlfred Perlstein if (uxfer == NULL) 1466390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 14678c8fff31SAndrew Thompson 14684594d907SAndrew Thompson /* check if not initialised */ 1469390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 14704594d907SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 14718c8fff31SAndrew Thompson 1472390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 14738c8fff31SAndrew Thompson 1474390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 14758c8fff31SAndrew Thompson 1476390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 14778c8fff31SAndrew Thompson 1478390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1479390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1480390065b1SAlfred Perlstein 14814594d907SAndrew Thompson retval = 0; 14824594d907SAndrew Thompson 1483390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1484390065b1SAlfred Perlstein 1485390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1486390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1487390065b1SAlfred Perlstein 14884594d907SAndrew Thompson if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 14894594d907SAndrew Thompson /* only update the transfer status */ 14904594d907SAndrew Thompson uxfer->status = LIBUSB_TRANSFER_CANCELLED; 14914594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 14924594d907SAndrew Thompson } else if (sxfer->entry.tqe_prev != NULL) { 1493390065b1SAlfred Perlstein /* we are lucky - transfer is on a queue */ 1494390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1495390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 14964594d907SAndrew Thompson libusb10_complete_transfer(NULL, 14974594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1498390065b1SAlfred Perlstein } else if (pxfer0 == NULL || pxfer1 == NULL) { 1499390065b1SAlfred Perlstein /* not started */ 15004594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1501390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 15024594d907SAndrew Thompson libusb10_complete_transfer(pxfer0, 15034594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1504390065b1SAlfred Perlstein libusb20_tr_stop(pxfer0); 1505390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1506390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1507390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1508390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 15094594d907SAndrew Thompson libusb10_complete_transfer(pxfer1, 15104594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1511390065b1SAlfred Perlstein libusb20_tr_stop(pxfer1); 1512390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1513390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1514390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1515390065b1SAlfred Perlstein } else { 1516390065b1SAlfred Perlstein /* not started */ 15174594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1518c500e4ddSAndrew Thompson } 15198c8fff31SAndrew Thompson 1520390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 15218c8fff31SAndrew Thompson 1522390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 15238c8fff31SAndrew Thompson 15244594d907SAndrew Thompson return (retval); 15258c8fff31SAndrew Thompson } 15268c8fff31SAndrew Thompson 1527390065b1SAlfred Perlstein UNEXPORTED void 1528390065b1SAlfred Perlstein libusb10_cancel_all_transfer(libusb_device *dev) 15298c8fff31SAndrew Thompson { 153090988efdSHans Petter Selasky struct libusb20_device *pdev = dev->os_priv; 153190988efdSHans Petter Selasky unsigned x; 153290988efdSHans Petter Selasky 153390988efdSHans Petter Selasky for (x = 0; x != LIBUSB_NUM_SW_ENDPOINTS; x++) { 153490988efdSHans Petter Selasky struct libusb20_transfer *xfer; 153590988efdSHans Petter Selasky 153690988efdSHans Petter Selasky xfer = libusb20_tr_get_pointer(pdev, x); 153790988efdSHans Petter Selasky if (xfer == NULL) 153890988efdSHans Petter Selasky continue; 153990988efdSHans Petter Selasky libusb20_tr_close(xfer); 154090988efdSHans Petter Selasky } 15418c8fff31SAndrew Thompson } 1542ccef4ddfSAndrew Thompson 1543ccef4ddfSAndrew Thompson uint16_t 1544ccef4ddfSAndrew Thompson libusb_cpu_to_le16(uint16_t x) 1545ccef4ddfSAndrew Thompson { 1546ccef4ddfSAndrew Thompson return (htole16(x)); 1547ccef4ddfSAndrew Thompson } 1548ccef4ddfSAndrew Thompson 1549ccef4ddfSAndrew Thompson uint16_t 1550ccef4ddfSAndrew Thompson libusb_le16_to_cpu(uint16_t x) 1551ccef4ddfSAndrew Thompson { 1552ccef4ddfSAndrew Thompson return (le16toh(x)); 1553ccef4ddfSAndrew Thompson } 1554ccef4ddfSAndrew Thompson 1555698e791aSHans Petter Selasky const char * 1556698e791aSHans Petter Selasky libusb_strerror(int code) 1557698e791aSHans Petter Selasky { 1558c61f2561SHans Petter Selasky switch (code) { 1559c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1560c61f2561SHans Petter Selasky return ("Success"); 1561c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1562c61f2561SHans Petter Selasky return ("I/O error"); 1563c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1564c61f2561SHans Petter Selasky return ("Invalid parameter"); 1565c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1566c61f2561SHans Petter Selasky return ("Permissions error"); 1567c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1568c61f2561SHans Petter Selasky return ("No device"); 1569c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1570c61f2561SHans Petter Selasky return ("Not found"); 1571c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1572c61f2561SHans Petter Selasky return ("Device busy"); 1573c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1574c61f2561SHans Petter Selasky return ("Timeout"); 1575c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1576c61f2561SHans Petter Selasky return ("Overflow"); 1577c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1578c61f2561SHans Petter Selasky return ("Pipe error"); 1579c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1580c61f2561SHans Petter Selasky return ("Interrupted"); 1581c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1582c61f2561SHans Petter Selasky return ("Out of memory"); 1583c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1584c61f2561SHans Petter Selasky return ("Not supported"); 1585c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1586c61f2561SHans Petter Selasky return ("Other error"); 1587c61f2561SHans Petter Selasky default: 1588698e791aSHans Petter Selasky return ("Unknown error"); 1589698e791aSHans Petter Selasky } 1590c61f2561SHans Petter Selasky } 1591c61f2561SHans Petter Selasky 1592c61f2561SHans Petter Selasky const char * 1593c61f2561SHans Petter Selasky libusb_error_name(int code) 1594c61f2561SHans Petter Selasky { 1595c61f2561SHans Petter Selasky switch (code) { 1596c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1597c61f2561SHans Petter Selasky return ("LIBUSB_SUCCESS"); 1598c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1599c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_IO"); 1600c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1601c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INVALID_PARAM"); 1602c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1603c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_ACCESS"); 1604c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1605c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_DEVICE"); 1606c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1607c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_FOUND"); 1608c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1609c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_BUSY"); 1610c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1611c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_TIMEOUT"); 1612c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1613c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OVERFLOW"); 1614c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1615c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_PIPE"); 1616c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1617c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INTERRUPTED"); 1618c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1619c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_MEM"); 1620c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1621c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_SUPPORTED"); 1622c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1623c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OTHER"); 1624c61f2561SHans Petter Selasky default: 1625c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_UNKNOWN"); 1626c61f2561SHans Petter Selasky } 1627c61f2561SHans Petter Selasky } 1628