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 28f3cba95cSWojciech A. Koszek #include <sys/fcntl.h> 29f3cba95cSWojciech A. Koszek #include <sys/ioctl.h> 30f3cba95cSWojciech A. Koszek #include <sys/queue.h> 31f3cba95cSWojciech A. Koszek 32ac840bfcSWojciech A. Koszek #include <assert.h> 33f3cba95cSWojciech A. Koszek #include <errno.h> 348c8fff31SAndrew Thompson #include <poll.h> 358c8fff31SAndrew Thompson #include <pthread.h> 36f3cba95cSWojciech A. Koszek #include <stdio.h> 37f3cba95cSWojciech A. Koszek #include <stdlib.h> 38f3cba95cSWojciech A. Koszek #include <unistd.h> 398c8fff31SAndrew Thompson 409c087c5aSAndrew Thompson #define libusb_device_handle libusb20_device 419c087c5aSAndrew Thompson 428c8fff31SAndrew Thompson #include "libusb20.h" 438c8fff31SAndrew Thompson #include "libusb20_desc.h" 448c8fff31SAndrew Thompson #include "libusb20_int.h" 458c8fff31SAndrew Thompson #include "libusb.h" 468c8fff31SAndrew Thompson #include "libusb10.h" 478c8fff31SAndrew Thompson 488c8fff31SAndrew Thompson static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 498c8fff31SAndrew Thompson struct libusb_context *usbi_default_context = NULL; 50390065b1SAlfred Perlstein 51390065b1SAlfred Perlstein /* Prototypes */ 52390065b1SAlfred Perlstein 53390065b1SAlfred Perlstein static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 54390065b1SAlfred Perlstein static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 55390065b1SAlfred Perlstein static int libusb10_convert_error(uint8_t status); 56390065b1SAlfred Perlstein static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 57390065b1SAlfred Perlstein static void libusb10_isoc_proxy(struct libusb20_transfer *); 58390065b1SAlfred Perlstein static void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 59390065b1SAlfred Perlstein static void libusb10_ctrl_proxy(struct libusb20_transfer *); 60390065b1SAlfred Perlstein static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 618c8fff31SAndrew Thompson 628c8fff31SAndrew Thompson /* Library initialisation / deinitialisation */ 638c8fff31SAndrew Thompson 648c8fff31SAndrew Thompson void 658c8fff31SAndrew Thompson libusb_set_debug(libusb_context *ctx, int level) 668c8fff31SAndrew Thompson { 67390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 688c8fff31SAndrew Thompson if (ctx) 698c8fff31SAndrew Thompson ctx->debug = level; 708c8fff31SAndrew Thompson } 718c8fff31SAndrew Thompson 72698e791aSHans Petter Selasky static void 73698e791aSHans Petter Selasky libusb_set_nonblocking(int f) 74698e791aSHans Petter Selasky { 75698e791aSHans Petter Selasky int flags; 76698e791aSHans Petter Selasky 77698e791aSHans Petter Selasky /* 78698e791aSHans Petter Selasky * We ignore any failures in this function, hence the 79698e791aSHans Petter Selasky * non-blocking flag is not critical to the operation of 80698e791aSHans Petter Selasky * libUSB. We use F_GETFL and F_SETFL to be compatible with 81698e791aSHans Petter Selasky * Linux. 82698e791aSHans Petter Selasky */ 83698e791aSHans Petter Selasky 84698e791aSHans Petter Selasky flags = fcntl(f, F_GETFL, NULL); 85698e791aSHans Petter Selasky if (flags == -1) 86698e791aSHans Petter Selasky return; 87698e791aSHans Petter Selasky flags |= O_NONBLOCK; 88698e791aSHans Petter Selasky fcntl(f, F_SETFL, flags); 89698e791aSHans Petter Selasky } 90698e791aSHans Petter Selasky 918c8fff31SAndrew Thompson int 928c8fff31SAndrew Thompson libusb_init(libusb_context **context) 938c8fff31SAndrew Thompson { 948c8fff31SAndrew Thompson struct libusb_context *ctx; 958c8fff31SAndrew Thompson char *debug; 968c8fff31SAndrew Thompson int ret; 978c8fff31SAndrew Thompson 988c8fff31SAndrew Thompson ctx = malloc(sizeof(*ctx)); 998c8fff31SAndrew Thompson if (!ctx) 1008c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1018c8fff31SAndrew Thompson 1028c8fff31SAndrew Thompson memset(ctx, 0, sizeof(*ctx)); 1038c8fff31SAndrew Thompson 1048c8fff31SAndrew Thompson debug = getenv("LIBUSB_DEBUG"); 1058c8fff31SAndrew Thompson if (debug != NULL) { 1068c8fff31SAndrew Thompson ctx->debug = atoi(debug); 1078c8fff31SAndrew Thompson if (ctx->debug != 0) 1088c8fff31SAndrew Thompson ctx->debug_fixed = 1; 1098c8fff31SAndrew Thompson } 110c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->pollfds); 111390065b1SAlfred Perlstein TAILQ_INIT(&ctx->tr_done); 112390065b1SAlfred Perlstein 113390065b1SAlfred Perlstein pthread_mutex_init(&ctx->ctx_lock, NULL); 114390065b1SAlfred Perlstein pthread_cond_init(&ctx->ctx_cond, NULL); 115390065b1SAlfred Perlstein 116390065b1SAlfred Perlstein ctx->ctx_handler = NO_THREAD; 1178c8fff31SAndrew Thompson 1188c8fff31SAndrew Thompson ret = pipe(ctx->ctrl_pipe); 1198c8fff31SAndrew Thompson if (ret < 0) { 120390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 121390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 1228c8fff31SAndrew Thompson free(ctx); 1238c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 1248c8fff31SAndrew Thompson } 125390065b1SAlfred Perlstein /* set non-blocking mode on the control pipe to avoid deadlock */ 126698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[0]); 127698e791aSHans Petter Selasky libusb_set_nonblocking(ctx->ctrl_pipe[1]); 1288c8fff31SAndrew Thompson 129390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 1308c8fff31SAndrew Thompson 1318c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 1328c8fff31SAndrew Thompson if (usbi_default_context == NULL) { 1338c8fff31SAndrew Thompson usbi_default_context = ctx; 1348c8fff31SAndrew Thompson } 1358c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 1368c8fff31SAndrew Thompson 1378c8fff31SAndrew Thompson if (context) 1388c8fff31SAndrew Thompson *context = ctx; 1398c8fff31SAndrew Thompson 140390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 141390065b1SAlfred Perlstein 1428c8fff31SAndrew Thompson return (0); 1438c8fff31SAndrew Thompson } 1448c8fff31SAndrew Thompson 1458c8fff31SAndrew Thompson void 1468c8fff31SAndrew Thompson libusb_exit(libusb_context *ctx) 1478c8fff31SAndrew Thompson { 148390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 1498c8fff31SAndrew Thompson 150390065b1SAlfred Perlstein if (ctx == NULL) 151390065b1SAlfred Perlstein return; 152390065b1SAlfred Perlstein 153390065b1SAlfred Perlstein /* XXX cleanup devices */ 154390065b1SAlfred Perlstein 155390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 1568c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 1578c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 158390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 159390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 1608c8fff31SAndrew Thompson 1618c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 1628c8fff31SAndrew Thompson if (ctx == usbi_default_context) { 1638c8fff31SAndrew Thompson usbi_default_context = NULL; 1648c8fff31SAndrew Thompson } 1658c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 1668c8fff31SAndrew Thompson 1678c8fff31SAndrew Thompson free(ctx); 1688c8fff31SAndrew Thompson } 1698c8fff31SAndrew Thompson 1708c8fff31SAndrew Thompson /* Device handling and initialisation. */ 1718c8fff31SAndrew Thompson 1728c8fff31SAndrew Thompson ssize_t 1738c8fff31SAndrew Thompson libusb_get_device_list(libusb_context *ctx, libusb_device ***list) 1748c8fff31SAndrew Thompson { 1758c8fff31SAndrew Thompson struct libusb20_backend *usb_backend; 176390065b1SAlfred Perlstein struct libusb20_device *pdev; 177390065b1SAlfred Perlstein struct libusb_device *dev; 1788c8fff31SAndrew Thompson int i; 1798c8fff31SAndrew Thompson 180390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 181390065b1SAlfred Perlstein 182390065b1SAlfred Perlstein if (ctx == NULL) 183390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 184390065b1SAlfred Perlstein 185390065b1SAlfred Perlstein if (list == NULL) 186390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 1878c8fff31SAndrew Thompson 1888c8fff31SAndrew Thompson usb_backend = libusb20_be_alloc_default(); 1898c8fff31SAndrew Thompson if (usb_backend == NULL) 190390065b1SAlfred Perlstein return (LIBUSB_ERROR_NO_MEM); 1918c8fff31SAndrew Thompson 192390065b1SAlfred Perlstein /* figure out how many USB devices are present */ 1938c8fff31SAndrew Thompson pdev = NULL; 1948c8fff31SAndrew Thompson i = 0; 1958c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 1968c8fff31SAndrew Thompson i++; 1978c8fff31SAndrew Thompson 198390065b1SAlfred Perlstein /* allocate device pointer list */ 1998c8fff31SAndrew Thompson *list = malloc((i + 1) * sizeof(void *)); 2008c8fff31SAndrew Thompson if (*list == NULL) { 2018c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2028c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 2038c8fff31SAndrew Thompson } 204390065b1SAlfred Perlstein /* create libusb v1.0 compliant devices */ 2058c8fff31SAndrew Thompson i = 0; 2068c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 2078c8fff31SAndrew Thompson 2088c8fff31SAndrew Thompson dev = malloc(sizeof(*dev)); 2098c8fff31SAndrew Thompson if (dev == NULL) { 210c500e4ddSAndrew Thompson while (i != 0) { 211c500e4ddSAndrew Thompson libusb_unref_device((*list)[i - 1]); 212c500e4ddSAndrew Thompson i--; 213c500e4ddSAndrew Thompson } 2148c8fff31SAndrew Thompson free(*list); 215390065b1SAlfred Perlstein *list = NULL; 2168c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2178c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 2188c8fff31SAndrew Thompson } 219ccef4ddfSAndrew Thompson 220ccef4ddfSAndrew Thompson /* get device into libUSB v1.0 list */ 221ccef4ddfSAndrew Thompson libusb20_be_dequeue_device(usb_backend, pdev); 222ccef4ddfSAndrew Thompson 2238c8fff31SAndrew Thompson memset(dev, 0, sizeof(*dev)); 2248c8fff31SAndrew Thompson 225390065b1SAlfred Perlstein /* init transfer queues */ 226390065b1SAlfred Perlstein TAILQ_INIT(&dev->tr_head); 227390065b1SAlfred Perlstein 228390065b1SAlfred Perlstein /* set context we belong to */ 2298c8fff31SAndrew Thompson dev->ctx = ctx; 2308c8fff31SAndrew Thompson 2318c8fff31SAndrew Thompson /* link together the two structures */ 2328c8fff31SAndrew Thompson dev->os_priv = pdev; 233390065b1SAlfred Perlstein pdev->privLuData = dev; 2348c8fff31SAndrew Thompson 2358c8fff31SAndrew Thompson (*list)[i] = libusb_ref_device(dev); 2368c8fff31SAndrew Thompson i++; 2378c8fff31SAndrew Thompson } 2388c8fff31SAndrew Thompson (*list)[i] = NULL; 2398c8fff31SAndrew Thompson 2408c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2418c8fff31SAndrew Thompson return (i); 2428c8fff31SAndrew Thompson } 2438c8fff31SAndrew Thompson 2448c8fff31SAndrew Thompson void 2458c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices) 2468c8fff31SAndrew Thompson { 2478c8fff31SAndrew Thompson int i; 2488c8fff31SAndrew Thompson 2498c8fff31SAndrew Thompson if (list == NULL) 250390065b1SAlfred Perlstein return; /* be NULL safe */ 2518c8fff31SAndrew Thompson 2528c8fff31SAndrew Thompson if (unref_devices) { 2538c8fff31SAndrew Thompson for (i = 0; list[i] != NULL; i++) 2548c8fff31SAndrew Thompson libusb_unref_device(list[i]); 2558c8fff31SAndrew Thompson } 2568c8fff31SAndrew Thompson free(list); 2578c8fff31SAndrew Thompson } 2588c8fff31SAndrew Thompson 2598c8fff31SAndrew Thompson uint8_t 2608c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device *dev) 2618c8fff31SAndrew Thompson { 2628c8fff31SAndrew Thompson if (dev == NULL) 263390065b1SAlfred Perlstein return (0); /* should not happen */ 264390065b1SAlfred Perlstein return (libusb20_dev_get_bus_number(dev->os_priv)); 2658c8fff31SAndrew Thompson } 2668c8fff31SAndrew Thompson 2678c8fff31SAndrew Thompson uint8_t 2688c8fff31SAndrew Thompson libusb_get_device_address(libusb_device *dev) 2698c8fff31SAndrew Thompson { 2708c8fff31SAndrew Thompson if (dev == NULL) 271390065b1SAlfred Perlstein return (0); /* should not happen */ 272390065b1SAlfred Perlstein return (libusb20_dev_get_address(dev->os_priv)); 2738c8fff31SAndrew Thompson } 2748c8fff31SAndrew Thompson 2759a46d467SHans Petter Selasky enum libusb_speed 2769a46d467SHans Petter Selasky libusb_get_device_speed(libusb_device *dev) 2779a46d467SHans Petter Selasky { 2789a46d467SHans Petter Selasky if (dev == NULL) 27933ec9f0cSHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); /* should not happen */ 2809a46d467SHans Petter Selasky 2819a46d467SHans Petter Selasky switch (libusb20_dev_get_speed(dev->os_priv)) { 2829a46d467SHans Petter Selasky case LIBUSB20_SPEED_LOW: 2839a46d467SHans Petter Selasky return (LIBUSB_SPEED_LOW); 2849a46d467SHans Petter Selasky case LIBUSB20_SPEED_FULL: 2859a46d467SHans Petter Selasky return (LIBUSB_SPEED_FULL); 2869a46d467SHans Petter Selasky case LIBUSB20_SPEED_HIGH: 2879a46d467SHans Petter Selasky return (LIBUSB_SPEED_HIGH); 2889a46d467SHans Petter Selasky case LIBUSB20_SPEED_SUPER: 2899a46d467SHans Petter Selasky return (LIBUSB_SPEED_SUPER); 2909a46d467SHans Petter Selasky default: 2919a46d467SHans Petter Selasky break; 2929a46d467SHans Petter Selasky } 2939a46d467SHans Petter Selasky return (LIBUSB_SPEED_UNKNOWN); 2949a46d467SHans Petter Selasky } 2959a46d467SHans Petter Selasky 2968c8fff31SAndrew Thompson int 297390065b1SAlfred Perlstein libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 2988c8fff31SAndrew Thompson { 2998c8fff31SAndrew Thompson struct libusb_config_descriptor *pdconf; 3008c8fff31SAndrew Thompson struct libusb_interface *pinf; 3018c8fff31SAndrew Thompson struct libusb_interface_descriptor *pdinf; 3028c8fff31SAndrew Thompson struct libusb_endpoint_descriptor *pdend; 303390065b1SAlfred Perlstein int i; 304390065b1SAlfred Perlstein int j; 305390065b1SAlfred Perlstein int k; 306390065b1SAlfred Perlstein int ret; 3078c8fff31SAndrew Thompson 3088c8fff31SAndrew Thompson if (dev == NULL) 3098c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 3108c8fff31SAndrew Thompson 311390065b1SAlfred Perlstein ret = libusb_get_active_config_descriptor(dev, &pdconf); 312390065b1SAlfred Perlstein if (ret < 0) 313390065b1SAlfred Perlstein return (ret); 3148c8fff31SAndrew Thompson 3158c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 3168c8fff31SAndrew Thompson for (i = 0; i < pdconf->bNumInterfaces; i++) { 3178c8fff31SAndrew Thompson pinf = &pdconf->interface[i]; 3188c8fff31SAndrew Thompson for (j = 0; j < pinf->num_altsetting; j++) { 3198c8fff31SAndrew Thompson pdinf = &pinf->altsetting[j]; 3208c8fff31SAndrew Thompson for (k = 0; k < pdinf->bNumEndpoints; k++) { 3218c8fff31SAndrew Thompson pdend = &pdinf->endpoint[k]; 3228c8fff31SAndrew Thompson if (pdend->bEndpointAddress == endpoint) { 3238c8fff31SAndrew Thompson ret = pdend->wMaxPacketSize; 3248c8fff31SAndrew Thompson goto out; 3258c8fff31SAndrew Thompson } 3268c8fff31SAndrew Thompson } 3278c8fff31SAndrew Thompson } 3288c8fff31SAndrew Thompson } 3298c8fff31SAndrew Thompson 3308c8fff31SAndrew Thompson out: 3318c8fff31SAndrew Thompson libusb_free_config_descriptor(pdconf); 3328c8fff31SAndrew Thompson return (ret); 3338c8fff31SAndrew Thompson } 3348c8fff31SAndrew Thompson 3358c8fff31SAndrew Thompson libusb_device * 3368c8fff31SAndrew Thompson libusb_ref_device(libusb_device *dev) 3378c8fff31SAndrew Thompson { 3388c8fff31SAndrew Thompson if (dev == NULL) 339390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 3408c8fff31SAndrew Thompson 341390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 3428c8fff31SAndrew Thompson dev->refcnt++; 343390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 3448c8fff31SAndrew Thompson 3458c8fff31SAndrew Thompson return (dev); 3468c8fff31SAndrew Thompson } 3478c8fff31SAndrew Thompson 3488c8fff31SAndrew Thompson void 3498c8fff31SAndrew Thompson libusb_unref_device(libusb_device *dev) 3508c8fff31SAndrew Thompson { 3518c8fff31SAndrew Thompson if (dev == NULL) 352390065b1SAlfred Perlstein return; /* be NULL safe */ 3538c8fff31SAndrew Thompson 354390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 3558c8fff31SAndrew Thompson dev->refcnt--; 356390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 3578c8fff31SAndrew Thompson 3588c8fff31SAndrew Thompson if (dev->refcnt == 0) { 3598c8fff31SAndrew Thompson libusb20_dev_free(dev->os_priv); 3608c8fff31SAndrew Thompson free(dev); 3618c8fff31SAndrew Thompson } 3628c8fff31SAndrew Thompson } 3638c8fff31SAndrew Thompson 3648c8fff31SAndrew Thompson int 3658c8fff31SAndrew Thompson libusb_open(libusb_device *dev, libusb_device_handle **devh) 3668c8fff31SAndrew Thompson { 3678c8fff31SAndrew Thompson libusb_context *ctx = dev->ctx; 3688c8fff31SAndrew Thompson struct libusb20_device *pdev = dev->os_priv; 369390065b1SAlfred Perlstein uint8_t dummy; 3708c8fff31SAndrew Thompson int err; 3718c8fff31SAndrew Thompson 3728c8fff31SAndrew Thompson if (devh == NULL) 3738c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 3748c8fff31SAndrew Thompson 375390065b1SAlfred Perlstein /* set default device handle value */ 376390065b1SAlfred Perlstein *devh = NULL; 377390065b1SAlfred Perlstein 378390065b1SAlfred Perlstein dev = libusb_ref_device(dev); 379390065b1SAlfred Perlstein if (dev == NULL) 380390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 3818c8fff31SAndrew Thompson 3828c8fff31SAndrew Thompson err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 3838c8fff31SAndrew Thompson if (err) { 384390065b1SAlfred Perlstein libusb_unref_device(dev); 3858c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3868c8fff31SAndrew Thompson } 387390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 3888c8fff31SAndrew Thompson POLLOUT | POLLRDNORM | POLLWRNORM); 3898c8fff31SAndrew Thompson 390390065b1SAlfred Perlstein /* make sure our event loop detects the new device */ 391390065b1SAlfred Perlstein dummy = 0; 3928c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 393698e791aSHans Petter Selasky if (err < (int)sizeof(dummy)) { 394390065b1SAlfred Perlstein /* ignore error, if any */ 395390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 3968c8fff31SAndrew Thompson } 397390065b1SAlfred Perlstein *devh = pdev; 3988c8fff31SAndrew Thompson 3998c8fff31SAndrew Thompson return (0); 4008c8fff31SAndrew Thompson } 4018c8fff31SAndrew Thompson 4028c8fff31SAndrew Thompson libusb_device_handle * 4038c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 4048c8fff31SAndrew Thompson uint16_t product_id) 4058c8fff31SAndrew Thompson { 4068c8fff31SAndrew Thompson struct libusb_device **devs; 4078c8fff31SAndrew Thompson struct libusb20_device *pdev; 4088c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 409390065b1SAlfred Perlstein int i; 410390065b1SAlfred Perlstein int j; 4118c8fff31SAndrew Thompson 412390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 413390065b1SAlfred Perlstein if (ctx == NULL) 414390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 415390065b1SAlfred Perlstein 416c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 4178c8fff31SAndrew Thompson 4188c8fff31SAndrew Thompson if ((i = libusb_get_device_list(ctx, &devs)) < 0) 4198c8fff31SAndrew Thompson return (NULL); 4208c8fff31SAndrew Thompson 4218c8fff31SAndrew Thompson for (j = 0; j < i; j++) { 422390065b1SAlfred Perlstein pdev = devs[j]->os_priv; 4238c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 424390065b1SAlfred Perlstein /* 425390065b1SAlfred Perlstein * NOTE: The USB library will automatically swap the 426390065b1SAlfred Perlstein * fields in the device descriptor to be of host 427390065b1SAlfred Perlstein * endian type! 428390065b1SAlfred Perlstein */ 4298c8fff31SAndrew Thompson if (pdesc->idVendor == vendor_id && 430c500e4ddSAndrew Thompson pdesc->idProduct == product_id) { 431390065b1SAlfred Perlstein if (libusb_open(devs[j], &pdev) < 0) 432390065b1SAlfred Perlstein pdev = NULL; 433c500e4ddSAndrew Thompson break; 434c500e4ddSAndrew Thompson } 4358c8fff31SAndrew Thompson } 436abdbb3feSSean Farley if (j == i) 437abdbb3feSSean Farley pdev = NULL; 4388c8fff31SAndrew Thompson 4398c8fff31SAndrew Thompson libusb_free_device_list(devs, 1); 440c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 441390065b1SAlfred Perlstein return (pdev); 4428c8fff31SAndrew Thompson } 4438c8fff31SAndrew Thompson 4448c8fff31SAndrew Thompson void 445390065b1SAlfred Perlstein libusb_close(struct libusb20_device *pdev) 4468c8fff31SAndrew Thompson { 4478c8fff31SAndrew Thompson libusb_context *ctx; 448390065b1SAlfred Perlstein struct libusb_device *dev; 449390065b1SAlfred Perlstein uint8_t dummy; 4508c8fff31SAndrew Thompson int err; 4518c8fff31SAndrew Thompson 452390065b1SAlfred Perlstein if (pdev == NULL) 453390065b1SAlfred Perlstein return; /* be NULL safe */ 4548c8fff31SAndrew Thompson 455390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 456390065b1SAlfred Perlstein ctx = dev->ctx; 4578c8fff31SAndrew Thompson 458390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &dev->dev_poll); 4598c8fff31SAndrew Thompson 460390065b1SAlfred Perlstein libusb20_dev_close(pdev); 461ccef4ddfSAndrew Thompson 462ccef4ddfSAndrew Thompson /* unref will free the "pdev" when the refcount reaches zero */ 463390065b1SAlfred Perlstein libusb_unref_device(dev); 4648c8fff31SAndrew Thompson 465390065b1SAlfred Perlstein /* make sure our event loop detects the closed device */ 466390065b1SAlfred Perlstein dummy = 0; 4678c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 468698e791aSHans Petter Selasky if (err < (int)sizeof(dummy)) { 469390065b1SAlfred Perlstein /* ignore error, if any */ 470390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 471c500e4ddSAndrew Thompson } 4728c8fff31SAndrew Thompson } 4738c8fff31SAndrew Thompson 4748c8fff31SAndrew Thompson libusb_device * 475390065b1SAlfred Perlstein libusb_get_device(struct libusb20_device *pdev) 4768c8fff31SAndrew Thompson { 477390065b1SAlfred Perlstein if (pdev == NULL) 4788c8fff31SAndrew Thompson return (NULL); 479390065b1SAlfred Perlstein return ((libusb_device *)pdev->privLuData); 4808c8fff31SAndrew Thompson } 4818c8fff31SAndrew Thompson 4828c8fff31SAndrew Thompson int 483390065b1SAlfred Perlstein libusb_get_configuration(struct libusb20_device *pdev, int *config) 4848c8fff31SAndrew Thompson { 485390065b1SAlfred Perlstein struct libusb20_config *pconf; 4868c8fff31SAndrew Thompson 487390065b1SAlfred Perlstein if (pdev == NULL || config == NULL) 4888c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 4898c8fff31SAndrew Thompson 490390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 491390065b1SAlfred Perlstein if (pconf == NULL) 492c500e4ddSAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 4938c8fff31SAndrew Thompson 494390065b1SAlfred Perlstein *config = pconf->desc.bConfigurationValue; 4958c8fff31SAndrew Thompson 496390065b1SAlfred Perlstein free(pconf); 4978c8fff31SAndrew Thompson 4988c8fff31SAndrew Thompson return (0); 4998c8fff31SAndrew Thompson } 5008c8fff31SAndrew Thompson 5018c8fff31SAndrew Thompson int 502390065b1SAlfred Perlstein libusb_set_configuration(struct libusb20_device *pdev, int configuration) 5038c8fff31SAndrew Thompson { 504390065b1SAlfred Perlstein struct libusb20_config *pconf; 505390065b1SAlfred Perlstein struct libusb_device *dev; 506390065b1SAlfred Perlstein int err; 507390065b1SAlfred Perlstein uint8_t i; 5088c8fff31SAndrew Thompson 509390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 5108c8fff31SAndrew Thompson if (dev == NULL) 511390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 512390065b1SAlfred Perlstein 513390065b1SAlfred Perlstein if (configuration < 1) { 514390065b1SAlfred Perlstein /* unconfigure */ 515390065b1SAlfred Perlstein i = 255; 516390065b1SAlfred Perlstein } else { 517390065b1SAlfred Perlstein for (i = 0; i != 255; i++) { 518390065b1SAlfred Perlstein uint8_t found; 519390065b1SAlfred Perlstein 520390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, i); 521390065b1SAlfred Perlstein if (pconf == NULL) 522390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 523390065b1SAlfred Perlstein found = (pconf->desc.bConfigurationValue 524390065b1SAlfred Perlstein == configuration); 525390065b1SAlfred Perlstein free(pconf); 526390065b1SAlfred Perlstein 527390065b1SAlfred Perlstein if (found) 528390065b1SAlfred Perlstein goto set_config; 529390065b1SAlfred Perlstein } 530390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 531390065b1SAlfred Perlstein } 532390065b1SAlfred Perlstein 533390065b1SAlfred Perlstein set_config: 534390065b1SAlfred Perlstein 535390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 536390065b1SAlfred Perlstein 537390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 538390065b1SAlfred Perlstein 539390065b1SAlfred Perlstein err = libusb20_dev_set_config_index(pdev, i); 540390065b1SAlfred Perlstein 541390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 542390065b1SAlfred Perlstein POLLOUT | POLLRDNORM | POLLWRNORM); 543390065b1SAlfred Perlstein 544390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 545390065b1SAlfred Perlstein } 546390065b1SAlfred Perlstein 547390065b1SAlfred Perlstein int 548390065b1SAlfred Perlstein libusb_claim_interface(struct libusb20_device *pdev, int interface_number) 549390065b1SAlfred Perlstein { 550390065b1SAlfred Perlstein libusb_device *dev; 551390065b1SAlfred Perlstein int err = 0; 552390065b1SAlfred Perlstein 553390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 554390065b1SAlfred Perlstein if (dev == NULL) 555390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 556390065b1SAlfred Perlstein 557390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 558390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 559390065b1SAlfred Perlstein 560390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 561390065b1SAlfred Perlstein if (dev->claimed_interfaces & (1 << interface_number)) 562390065b1SAlfred Perlstein err = LIBUSB_ERROR_BUSY; 563390065b1SAlfred Perlstein 564390065b1SAlfred Perlstein if (!err) 565390065b1SAlfred Perlstein dev->claimed_interfaces |= (1 << interface_number); 566390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 567390065b1SAlfred Perlstein return (err); 568390065b1SAlfred Perlstein } 569390065b1SAlfred Perlstein 570390065b1SAlfred Perlstein int 571390065b1SAlfred Perlstein libusb_release_interface(struct libusb20_device *pdev, int interface_number) 572390065b1SAlfred Perlstein { 573390065b1SAlfred Perlstein libusb_device *dev; 574390065b1SAlfred Perlstein int err = 0; 575390065b1SAlfred Perlstein 576390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 577390065b1SAlfred Perlstein if (dev == NULL) 578390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 579390065b1SAlfred Perlstein 580390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 581390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 582390065b1SAlfred Perlstein 583390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 584390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 585390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 586390065b1SAlfred Perlstein 587390065b1SAlfred Perlstein if (!err) 588390065b1SAlfred Perlstein dev->claimed_interfaces &= ~(1 << interface_number); 589390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 590390065b1SAlfred Perlstein return (err); 591390065b1SAlfred Perlstein } 592390065b1SAlfred Perlstein 593390065b1SAlfred Perlstein int 594390065b1SAlfred Perlstein libusb_set_interface_alt_setting(struct libusb20_device *pdev, 595390065b1SAlfred Perlstein int interface_number, int alternate_setting) 596390065b1SAlfred Perlstein { 597390065b1SAlfred Perlstein libusb_device *dev; 598390065b1SAlfred Perlstein int err = 0; 599390065b1SAlfred Perlstein 600390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 601390065b1SAlfred Perlstein if (dev == NULL) 602390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 603390065b1SAlfred Perlstein 604390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 605390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 606390065b1SAlfred Perlstein 607390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 608390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 609390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 610390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 611390065b1SAlfred Perlstein 612390065b1SAlfred Perlstein if (err) 613390065b1SAlfred Perlstein return (err); 614390065b1SAlfred Perlstein 615390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 616390065b1SAlfred Perlstein 617390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 618390065b1SAlfred Perlstein 619390065b1SAlfred Perlstein err = libusb20_dev_set_alt_index(pdev, 620390065b1SAlfred Perlstein interface_number, alternate_setting); 621390065b1SAlfred Perlstein 622390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 623390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 624390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 625390065b1SAlfred Perlstein 626390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 627390065b1SAlfred Perlstein } 628390065b1SAlfred Perlstein 629390065b1SAlfred Perlstein static struct libusb20_transfer * 630390065b1SAlfred Perlstein libusb10_get_transfer(struct libusb20_device *pdev, 631390065b1SAlfred Perlstein uint8_t endpoint, uint8_t index) 632390065b1SAlfred Perlstein { 633390065b1SAlfred Perlstein index &= 1; /* double buffering */ 634390065b1SAlfred Perlstein 635390065b1SAlfred Perlstein index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 636390065b1SAlfred Perlstein 637390065b1SAlfred Perlstein if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 638390065b1SAlfred Perlstein /* this is an IN endpoint */ 639390065b1SAlfred Perlstein index |= 2; 640390065b1SAlfred Perlstein } 641390065b1SAlfred Perlstein return (libusb20_tr_get_pointer(pdev, index)); 642390065b1SAlfred Perlstein } 643390065b1SAlfred Perlstein 644390065b1SAlfred Perlstein int 645390065b1SAlfred Perlstein libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 646390065b1SAlfred Perlstein { 647390065b1SAlfred Perlstein struct libusb20_transfer *xfer; 648390065b1SAlfred Perlstein struct libusb_device *dev; 649390065b1SAlfred Perlstein int err; 650390065b1SAlfred Perlstein 651390065b1SAlfred Perlstein xfer = libusb10_get_transfer(pdev, endpoint, 0); 652390065b1SAlfred Perlstein if (xfer == NULL) 653390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 654390065b1SAlfred Perlstein 655390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 656698e791aSHans Petter Selasky if (dev == NULL) 657698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 658390065b1SAlfred Perlstein 659390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 660a7e048a2SHans Petter Selasky err = libusb20_tr_open(xfer, 0, 1, endpoint); 661390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 662390065b1SAlfred Perlstein 663390065b1SAlfred Perlstein if (err != 0 && err != LIBUSB20_ERROR_BUSY) 664390065b1SAlfred Perlstein return (LIBUSB_ERROR_OTHER); 665390065b1SAlfred Perlstein 666390065b1SAlfred Perlstein libusb20_tr_clear_stall_sync(xfer); 667390065b1SAlfred Perlstein 668390065b1SAlfred Perlstein /* check if we opened the transfer */ 669390065b1SAlfred Perlstein if (err == 0) { 670390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 671390065b1SAlfred Perlstein libusb20_tr_close(xfer); 672390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 673390065b1SAlfred Perlstein } 674390065b1SAlfred Perlstein return (0); /* success */ 675390065b1SAlfred Perlstein } 676390065b1SAlfred Perlstein 677390065b1SAlfred Perlstein int 678390065b1SAlfred Perlstein libusb_reset_device(struct libusb20_device *pdev) 679390065b1SAlfred Perlstein { 680390065b1SAlfred Perlstein libusb_device *dev; 681390065b1SAlfred Perlstein int err; 682390065b1SAlfred Perlstein 683390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 684390065b1SAlfred Perlstein if (dev == NULL) 685698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 6868c8fff31SAndrew Thompson 687390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 688390065b1SAlfred Perlstein 689390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 690390065b1SAlfred Perlstein 691390065b1SAlfred Perlstein err = libusb20_dev_reset(pdev); 692390065b1SAlfred Perlstein 693390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 694390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 695390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 696390065b1SAlfred Perlstein 697390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 6988c8fff31SAndrew Thompson } 6998c8fff31SAndrew Thompson 7008c8fff31SAndrew Thompson int 701f1b5fa6eSHans Petter Selasky libusb_check_connected(struct libusb20_device *pdev) 702f1b5fa6eSHans Petter Selasky { 703f1b5fa6eSHans Petter Selasky libusb_device *dev; 704f1b5fa6eSHans Petter Selasky int err; 705f1b5fa6eSHans Petter Selasky 706f1b5fa6eSHans Petter Selasky dev = libusb_get_device(pdev); 707f1b5fa6eSHans Petter Selasky if (dev == NULL) 708f1b5fa6eSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 709f1b5fa6eSHans Petter Selasky 710f1b5fa6eSHans Petter Selasky err = libusb20_dev_check_connected(pdev); 711f1b5fa6eSHans Petter Selasky 712f1b5fa6eSHans Petter Selasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 713f1b5fa6eSHans Petter Selasky } 714f1b5fa6eSHans Petter Selasky 715f1b5fa6eSHans Petter Selasky int 716390065b1SAlfred Perlstein libusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 7178c8fff31SAndrew Thompson { 718390065b1SAlfred Perlstein if (pdev == NULL) 7198c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7208c8fff31SAndrew Thompson 721390065b1SAlfred Perlstein return (libusb20_dev_kernel_driver_active( 722390065b1SAlfred Perlstein pdev, interface)); 7238c8fff31SAndrew Thompson } 7248c8fff31SAndrew Thompson 7258c8fff31SAndrew Thompson int 726698e791aSHans Petter Selasky libusb_get_driver_np(struct libusb20_device *pdev, int interface, 727698e791aSHans Petter Selasky char *name, int namelen) 728698e791aSHans Petter Selasky { 729698e791aSHans Petter Selasky return (libusb_get_driver(pdev, interface, name, namelen)); 730698e791aSHans Petter Selasky } 731698e791aSHans Petter Selasky 732698e791aSHans Petter Selasky int 733698e791aSHans Petter Selasky libusb_get_driver(struct libusb20_device *pdev, int interface, 734698e791aSHans Petter Selasky char *name, int namelen) 735698e791aSHans Petter Selasky { 736698e791aSHans Petter Selasky char *ptr; 737698e791aSHans Petter Selasky int err; 738698e791aSHans Petter Selasky 739698e791aSHans Petter Selasky if (pdev == NULL) 740698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 741698e791aSHans Petter Selasky if (namelen < 1) 742698e791aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 7434eb5923dSHans Petter Selasky if (namelen > 255) 7444eb5923dSHans Petter Selasky namelen = 255; 745698e791aSHans Petter Selasky 746698e791aSHans Petter Selasky err = libusb20_dev_get_iface_desc( 747698e791aSHans Petter Selasky pdev, interface, name, namelen); 748698e791aSHans Petter Selasky 749698e791aSHans Petter Selasky if (err != 0) 750698e791aSHans Petter Selasky return (LIBUSB_ERROR_OTHER); 751698e791aSHans Petter Selasky 752698e791aSHans Petter Selasky /* we only want the driver name */ 753698e791aSHans Petter Selasky ptr = strstr(name, ":"); 754698e791aSHans Petter Selasky if (ptr != NULL) 755698e791aSHans Petter Selasky *ptr = 0; 756698e791aSHans Petter Selasky 757698e791aSHans Petter Selasky return (0); 758698e791aSHans Petter Selasky } 759698e791aSHans Petter Selasky 760698e791aSHans Petter Selasky int 761698e791aSHans Petter Selasky libusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface) 762698e791aSHans Petter Selasky { 763698e791aSHans Petter Selasky return (libusb_detach_kernel_driver(pdev, interface)); 764698e791aSHans Petter Selasky } 765698e791aSHans Petter Selasky 766698e791aSHans Petter Selasky int 767390065b1SAlfred Perlstein libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 7688c8fff31SAndrew Thompson { 769390065b1SAlfred Perlstein int err; 7708c8fff31SAndrew Thompson 771390065b1SAlfred Perlstein if (pdev == NULL) 7728c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7738c8fff31SAndrew Thompson 774390065b1SAlfred Perlstein err = libusb20_dev_detach_kernel_driver( 775390065b1SAlfred Perlstein pdev, interface); 7768c8fff31SAndrew Thompson 777698e791aSHans Petter Selasky return (err ? LIBUSB_ERROR_OTHER : 0); 7788c8fff31SAndrew Thompson } 7798c8fff31SAndrew Thompson 7808c8fff31SAndrew Thompson int 781390065b1SAlfred Perlstein libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 7828c8fff31SAndrew Thompson { 783390065b1SAlfred Perlstein if (pdev == NULL) 7848c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 785390065b1SAlfred Perlstein /* stub - currently not supported by libusb20 */ 7868c8fff31SAndrew Thompson return (0); 7878c8fff31SAndrew Thompson } 7888c8fff31SAndrew Thompson 7898c8fff31SAndrew Thompson /* Asynchronous device I/O */ 7908c8fff31SAndrew Thompson 7918c8fff31SAndrew Thompson struct libusb_transfer * 7928c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets) 7938c8fff31SAndrew Thompson { 794390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 795390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 7968c8fff31SAndrew Thompson int len; 7978c8fff31SAndrew Thompson 7988c8fff31SAndrew Thompson len = sizeof(struct libusb_transfer) + 799390065b1SAlfred Perlstein sizeof(struct libusb_super_transfer) + 8008c8fff31SAndrew Thompson (iso_packets * sizeof(libusb_iso_packet_descriptor)); 8018c8fff31SAndrew Thompson 802390065b1SAlfred Perlstein sxfer = malloc(len); 803390065b1SAlfred Perlstein if (sxfer == NULL) 8048c8fff31SAndrew Thompson return (NULL); 8058c8fff31SAndrew Thompson 806390065b1SAlfred Perlstein memset(sxfer, 0, len); 8078c8fff31SAndrew Thompson 808390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 809390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 8108c8fff31SAndrew Thompson 811390065b1SAlfred Perlstein /* set default value */ 812390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 813390065b1SAlfred Perlstein 814390065b1SAlfred Perlstein return (uxfer); 8158c8fff31SAndrew Thompson } 8168c8fff31SAndrew Thompson 8178c8fff31SAndrew Thompson void 818390065b1SAlfred Perlstein libusb_free_transfer(struct libusb_transfer *uxfer) 8198c8fff31SAndrew Thompson { 820390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 8218c8fff31SAndrew Thompson 822390065b1SAlfred Perlstein if (uxfer == NULL) 823390065b1SAlfred Perlstein return; /* be NULL safe */ 8248c8fff31SAndrew Thompson 82531f7072cSHans Petter Selasky /* check if we should free the transfer buffer */ 82631f7072cSHans Petter Selasky if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) 82731f7072cSHans Petter Selasky free(uxfer->buffer); 82831f7072cSHans Petter Selasky 829390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 830390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 8318c8fff31SAndrew Thompson 832390065b1SAlfred Perlstein free(sxfer); 8338c8fff31SAndrew Thompson } 8348c8fff31SAndrew Thompson 8351c497368SHans Petter Selasky static uint32_t 836390065b1SAlfred Perlstein libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 8378c8fff31SAndrew Thompson { 8381c497368SHans Petter Selasky uint32_t ret; 8398c8fff31SAndrew Thompson 8408c8fff31SAndrew Thompson switch (xfer->type) { 8418c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 8421c497368SHans Petter Selasky ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */ 8438c8fff31SAndrew Thompson break; 8448c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 8458c8fff31SAndrew Thompson ret = 2; 8468c8fff31SAndrew Thompson break; 8478c8fff31SAndrew Thompson default: 8488c8fff31SAndrew Thompson ret = 1; 8498c8fff31SAndrew Thompson break; 8508c8fff31SAndrew Thompson } 851390065b1SAlfred Perlstein return (ret); 8528c8fff31SAndrew Thompson } 8538c8fff31SAndrew Thompson 8548c8fff31SAndrew Thompson static int 855390065b1SAlfred Perlstein libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 8568c8fff31SAndrew Thompson { 8578c8fff31SAndrew Thompson int ret; 8588c8fff31SAndrew Thompson int usb_speed; 8598c8fff31SAndrew Thompson 8608c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 8618c8fff31SAndrew Thompson 8628c8fff31SAndrew Thompson switch (xfer->type) { 8638c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 864390065b1SAlfred Perlstein ret = 0; /* kernel will auto-select */ 8658c8fff31SAndrew Thompson break; 8668c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 867390065b1SAlfred Perlstein ret = 1024; 8688c8fff31SAndrew Thompson break; 8698c8fff31SAndrew Thompson default: 8708c8fff31SAndrew Thompson switch (usb_speed) { 8718c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 8728c8fff31SAndrew Thompson ret = 256; 8738c8fff31SAndrew Thompson break; 8748c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 8758c8fff31SAndrew Thompson ret = 4096; 8768c8fff31SAndrew Thompson break; 8778c8fff31SAndrew Thompson default: 8788c8fff31SAndrew Thompson ret = 16384; 8798c8fff31SAndrew Thompson break; 8808c8fff31SAndrew Thompson } 8818c8fff31SAndrew Thompson break; 8828c8fff31SAndrew Thompson } 883390065b1SAlfred Perlstein return (ret); 8848c8fff31SAndrew Thompson } 8858c8fff31SAndrew Thompson 886390065b1SAlfred Perlstein static int 887390065b1SAlfred Perlstein libusb10_convert_error(uint8_t status) 888390065b1SAlfred Perlstein { 889390065b1SAlfred Perlstein ; /* indent fix */ 890390065b1SAlfred Perlstein 891390065b1SAlfred Perlstein switch (status) { 892390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 893390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 894390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_COMPLETED); 895390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_OVERFLOW: 896390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_OVERFLOW); 897390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_NO_DEVICE: 898390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_NO_DEVICE); 899390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_STALL: 900390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_STALL); 901390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_CANCELLED: 902390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_CANCELLED); 903390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_TIMED_OUT: 904390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_TIMED_OUT); 905390065b1SAlfred Perlstein default: 906390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_ERROR); 907390065b1SAlfred Perlstein } 908390065b1SAlfred Perlstein } 909390065b1SAlfred Perlstein 910390065b1SAlfred Perlstein /* This function must be called locked */ 911390065b1SAlfred Perlstein 912c500e4ddSAndrew Thompson static void 913390065b1SAlfred Perlstein libusb10_complete_transfer(struct libusb20_transfer *pxfer, 914390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer, int status) 915c500e4ddSAndrew Thompson { 916390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 917390065b1SAlfred Perlstein struct libusb_device *dev; 918c500e4ddSAndrew Thompson 919390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 920390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 921390065b1SAlfred Perlstein 922390065b1SAlfred Perlstein if (pxfer != NULL) 923390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer, NULL); 924390065b1SAlfred Perlstein 9254594d907SAndrew Thompson /* set transfer status */ 926390065b1SAlfred Perlstein uxfer->status = status; 927390065b1SAlfred Perlstein 9284594d907SAndrew Thompson /* update super transfer state */ 9294594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 9304594d907SAndrew Thompson 931390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 932390065b1SAlfred Perlstein 933390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 934390065b1SAlfred Perlstein } 935390065b1SAlfred Perlstein 936390065b1SAlfred Perlstein /* This function must be called locked */ 937390065b1SAlfred Perlstein 938390065b1SAlfred Perlstein static void 939390065b1SAlfred Perlstein libusb10_isoc_proxy(struct libusb20_transfer *pxfer) 940390065b1SAlfred Perlstein { 941390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 942390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 943390065b1SAlfred Perlstein uint32_t actlen; 944390065b1SAlfred Perlstein uint16_t iso_packets; 945390065b1SAlfred Perlstein uint16_t i; 946390065b1SAlfred Perlstein uint8_t status; 947390065b1SAlfred Perlstein uint8_t flags; 948390065b1SAlfred Perlstein 949390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 950390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 951390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 952390065b1SAlfred Perlstein iso_packets = libusb20_tr_get_max_frames(pxfer); 953390065b1SAlfred Perlstein 954390065b1SAlfred Perlstein if (sxfer == NULL) 955390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 956390065b1SAlfred Perlstein 957390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 958390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 959390065b1SAlfred Perlstein 960390065b1SAlfred Perlstein if (iso_packets > uxfer->num_iso_packets) 961390065b1SAlfred Perlstein iso_packets = uxfer->num_iso_packets; 962390065b1SAlfred Perlstein 963390065b1SAlfred Perlstein if (iso_packets == 0) 964390065b1SAlfred Perlstein return; /* nothing to do */ 965390065b1SAlfred Perlstein 966390065b1SAlfred Perlstein /* make sure that the number of ISOCHRONOUS packets is valid */ 967390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 968390065b1SAlfred Perlstein 969390065b1SAlfred Perlstein flags = uxfer->flags; 970c500e4ddSAndrew Thompson 971c500e4ddSAndrew Thompson switch (status) { 972c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 973c500e4ddSAndrew Thompson 974390065b1SAlfred Perlstein /* update actual length */ 975390065b1SAlfred Perlstein uxfer->actual_length = actlen; 976390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 977390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].actual_length = 978390065b1SAlfred Perlstein libusb20_tr_get_length(pxfer, i); 979390065b1SAlfred Perlstein } 980390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 981c500e4ddSAndrew Thompson break; 982390065b1SAlfred Perlstein 983c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_START: 984390065b1SAlfred Perlstein 985390065b1SAlfred Perlstein /* setup length(s) */ 986390065b1SAlfred Perlstein actlen = 0; 987390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 988390065b1SAlfred Perlstein libusb20_tr_setup_isoc(pxfer, 989390065b1SAlfred Perlstein &uxfer->buffer[actlen], 990390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].length, i); 991390065b1SAlfred Perlstein actlen += uxfer->iso_packet_desc[i].length; 992c500e4ddSAndrew Thompson } 993390065b1SAlfred Perlstein 994390065b1SAlfred Perlstein /* no remainder */ 995390065b1SAlfred Perlstein sxfer->rem_len = 0; 996390065b1SAlfred Perlstein 997390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, iso_packets); 998390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 999390065b1SAlfred Perlstein 1000390065b1SAlfred Perlstein /* fork another USB transfer, if any */ 1001390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1002c500e4ddSAndrew Thompson break; 1003390065b1SAlfred Perlstein 1004390065b1SAlfred Perlstein default: 1005390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1006c500e4ddSAndrew Thompson break; 1007c500e4ddSAndrew Thompson } 1008390065b1SAlfred Perlstein } 1009390065b1SAlfred Perlstein 1010390065b1SAlfred Perlstein /* This function must be called locked */ 1011390065b1SAlfred Perlstein 1012390065b1SAlfred Perlstein static void 1013390065b1SAlfred Perlstein libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 1014390065b1SAlfred Perlstein { 1015390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1016390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1017390065b1SAlfred Perlstein uint32_t max_bulk; 1018390065b1SAlfred Perlstein uint32_t actlen; 1019390065b1SAlfred Perlstein uint8_t status; 1020390065b1SAlfred Perlstein uint8_t flags; 1021390065b1SAlfred Perlstein 1022390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1023390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1024390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1025390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1026390065b1SAlfred Perlstein 1027390065b1SAlfred Perlstein if (sxfer == NULL) 1028390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1029390065b1SAlfred Perlstein 1030390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1031390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1032390065b1SAlfred Perlstein 1033390065b1SAlfred Perlstein flags = uxfer->flags; 1034390065b1SAlfred Perlstein 1035390065b1SAlfred Perlstein switch (status) { 1036390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1037390065b1SAlfred Perlstein 1038390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1039390065b1SAlfred Perlstein 1040390065b1SAlfred Perlstein /* check for short packet */ 1041390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1042390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1043390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1044390065b1SAlfred Perlstein } else { 1045390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1046390065b1SAlfred Perlstein } 1047390065b1SAlfred Perlstein break; 1048390065b1SAlfred Perlstein } 1049390065b1SAlfred Perlstein /* check for end of data */ 1050390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1051390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1052390065b1SAlfred Perlstein break; 1053390065b1SAlfred Perlstein } 1054390065b1SAlfred Perlstein /* FALLTHROUGH */ 1055390065b1SAlfred Perlstein 1056390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1057390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1058390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1059390065b1SAlfred Perlstein } 1060390065b1SAlfred Perlstein /* setup new BULK or INTERRUPT transaction */ 1061390065b1SAlfred Perlstein libusb20_tr_setup_bulk(pxfer, 1062390065b1SAlfred Perlstein sxfer->curr_data, max_bulk, uxfer->timeout); 1063390065b1SAlfred Perlstein 1064390065b1SAlfred Perlstein /* update counters */ 1065390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1066390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1067390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1068390065b1SAlfred Perlstein 1069390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1070390065b1SAlfred Perlstein 1071390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1072390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1073390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1074390065b1SAlfred Perlstein break; 1075390065b1SAlfred Perlstein 1076390065b1SAlfred Perlstein default: 1077390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1078390065b1SAlfred Perlstein break; 1079390065b1SAlfred Perlstein } 1080390065b1SAlfred Perlstein } 1081390065b1SAlfred Perlstein 1082390065b1SAlfred Perlstein /* This function must be called locked */ 1083390065b1SAlfred Perlstein 1084390065b1SAlfred Perlstein static void 1085390065b1SAlfred Perlstein libusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1086390065b1SAlfred Perlstein { 1087390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1088390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1089390065b1SAlfred Perlstein uint32_t max_bulk; 1090390065b1SAlfred Perlstein uint32_t actlen; 1091390065b1SAlfred Perlstein uint8_t status; 1092390065b1SAlfred Perlstein uint8_t flags; 1093390065b1SAlfred Perlstein 1094390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1095390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1096390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1097390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1098390065b1SAlfred Perlstein 1099390065b1SAlfred Perlstein if (sxfer == NULL) 1100390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1101390065b1SAlfred Perlstein 1102390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1103390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1104390065b1SAlfred Perlstein 1105390065b1SAlfred Perlstein flags = uxfer->flags; 1106390065b1SAlfred Perlstein 1107390065b1SAlfred Perlstein switch (status) { 1108390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1109390065b1SAlfred Perlstein 1110390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1111390065b1SAlfred Perlstein 1112390065b1SAlfred Perlstein /* subtract length of SETUP packet, if any */ 1113390065b1SAlfred Perlstein actlen -= libusb20_tr_get_length(pxfer, 0); 1114390065b1SAlfred Perlstein 1115390065b1SAlfred Perlstein /* check for short packet */ 1116390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1117390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1118390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1119390065b1SAlfred Perlstein } else { 1120390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1121390065b1SAlfred Perlstein } 1122390065b1SAlfred Perlstein break; 1123390065b1SAlfred Perlstein } 1124390065b1SAlfred Perlstein /* check for end of data */ 1125390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1126390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1127390065b1SAlfred Perlstein break; 1128390065b1SAlfred Perlstein } 1129390065b1SAlfred Perlstein /* FALLTHROUGH */ 1130390065b1SAlfred Perlstein 1131390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1132390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1133390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1134390065b1SAlfred Perlstein } 1135390065b1SAlfred Perlstein /* setup new CONTROL transaction */ 1136390065b1SAlfred Perlstein if (status == LIBUSB20_TRANSFER_COMPLETED) { 1137390065b1SAlfred Perlstein /* next fragment - don't send SETUP packet */ 1138390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 0, 0); 1139390065b1SAlfred Perlstein } else { 1140390065b1SAlfred Perlstein /* first fragment - send SETUP packet */ 1141390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 8, 0); 1142390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1143390065b1SAlfred Perlstein } 1144390065b1SAlfred Perlstein 1145390065b1SAlfred Perlstein if (max_bulk != 0) { 1146390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, max_bulk, 1); 1147390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1148390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 2); 1149390065b1SAlfred Perlstein } else { 1150390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 1); 1151390065b1SAlfred Perlstein } 1152390065b1SAlfred Perlstein 1153390065b1SAlfred Perlstein /* update counters */ 1154390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1155390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1156390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1157390065b1SAlfred Perlstein 1158390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1159390065b1SAlfred Perlstein 1160390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1161390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1162390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1163390065b1SAlfred Perlstein break; 1164390065b1SAlfred Perlstein 1165390065b1SAlfred Perlstein default: 1166390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1167390065b1SAlfred Perlstein break; 1168390065b1SAlfred Perlstein } 1169390065b1SAlfred Perlstein } 1170390065b1SAlfred Perlstein 1171390065b1SAlfred Perlstein /* The following function must be called locked */ 1172390065b1SAlfred Perlstein 1173390065b1SAlfred Perlstein static void 1174390065b1SAlfred Perlstein libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1175390065b1SAlfred Perlstein { 1176390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1177390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1178390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1179390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1180390065b1SAlfred Perlstein struct libusb_device *dev; 1181390065b1SAlfred Perlstein int err; 1182390065b1SAlfred Perlstein int buffsize; 1183390065b1SAlfred Perlstein int maxframe; 1184390065b1SAlfred Perlstein int temp; 1185390065b1SAlfred Perlstein uint8_t dummy; 1186390065b1SAlfred Perlstein 1187390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 1188390065b1SAlfred Perlstein 1189390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1190390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1191390065b1SAlfred Perlstein 1192390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) 1193390065b1SAlfred Perlstein return; /* shouldn't happen */ 1194390065b1SAlfred Perlstein 1195390065b1SAlfred Perlstein temp = 0; 1196390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer0)) 1197390065b1SAlfred Perlstein temp |= 1; 1198390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer1)) 1199390065b1SAlfred Perlstein temp |= 2; 1200390065b1SAlfred Perlstein 1201390065b1SAlfred Perlstein switch (temp) { 1202390065b1SAlfred Perlstein case 3: 1203390065b1SAlfred Perlstein /* wait till one of the transfers complete */ 1204390065b1SAlfred Perlstein return; 1205390065b1SAlfred Perlstein case 2: 1206390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer1); 12074594d907SAndrew Thompson if (sxfer == NULL) 12084594d907SAndrew Thompson return; /* cancelling */ 1209390065b1SAlfred Perlstein if (sxfer->rem_len) 1210390065b1SAlfred Perlstein return; /* cannot queue another one */ 1211390065b1SAlfred Perlstein /* swap transfers */ 1212390065b1SAlfred Perlstein pxfer1 = pxfer0; 1213390065b1SAlfred Perlstein break; 1214390065b1SAlfred Perlstein case 1: 1215390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer0); 12164594d907SAndrew Thompson if (sxfer == NULL) 12174594d907SAndrew Thompson return; /* cancelling */ 1218390065b1SAlfred Perlstein if (sxfer->rem_len) 1219390065b1SAlfred Perlstein return; /* cannot queue another one */ 1220390065b1SAlfred Perlstein /* swap transfers */ 1221390065b1SAlfred Perlstein pxfer0 = pxfer1; 1222c500e4ddSAndrew Thompson break; 1223c500e4ddSAndrew Thompson default: 1224c500e4ddSAndrew Thompson break; 1225c500e4ddSAndrew Thompson } 1226c500e4ddSAndrew Thompson 1227390065b1SAlfred Perlstein /* find next transfer on same endpoint */ 1228390065b1SAlfred Perlstein TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1229390065b1SAlfred Perlstein 1230390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1231390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1232390065b1SAlfred Perlstein 1233390065b1SAlfred Perlstein if (uxfer->endpoint == endpoint) { 1234390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1235390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 1236390065b1SAlfred Perlstein goto found; 1237c500e4ddSAndrew Thompson } 1238c500e4ddSAndrew Thompson } 1239390065b1SAlfred Perlstein return; /* success */ 1240390065b1SAlfred Perlstein 1241390065b1SAlfred Perlstein found: 1242390065b1SAlfred Perlstein 1243390065b1SAlfred Perlstein libusb20_tr_set_priv_sc0(pxfer0, pdev); 1244390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1245390065b1SAlfred Perlstein 1246390065b1SAlfred Perlstein /* reset super transfer state */ 1247390065b1SAlfred Perlstein sxfer->rem_len = uxfer->length; 1248390065b1SAlfred Perlstein sxfer->curr_data = uxfer->buffer; 1249390065b1SAlfred Perlstein uxfer->actual_length = 0; 1250390065b1SAlfred Perlstein 1251390065b1SAlfred Perlstein switch (uxfer->type) { 1252390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1253390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1254390065b1SAlfred Perlstein break; 1255390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_BULK: 1256390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1257390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1258390065b1SAlfred Perlstein break; 1259390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_CONTROL: 1260390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1261390065b1SAlfred Perlstein if (sxfer->rem_len < 8) 1262390065b1SAlfred Perlstein goto failure; 1263390065b1SAlfred Perlstein 1264390065b1SAlfred Perlstein /* remove SETUP packet from data */ 1265390065b1SAlfred Perlstein sxfer->rem_len -= 8; 1266390065b1SAlfred Perlstein sxfer->curr_data += 8; 1267390065b1SAlfred Perlstein break; 1268390065b1SAlfred Perlstein default: 1269390065b1SAlfred Perlstein goto failure; 1270390065b1SAlfred Perlstein } 1271390065b1SAlfred Perlstein 1272390065b1SAlfred Perlstein buffsize = libusb10_get_buffsize(pdev, uxfer); 1273390065b1SAlfred Perlstein maxframe = libusb10_get_maxframe(pdev, uxfer); 1274390065b1SAlfred Perlstein 1275390065b1SAlfred Perlstein /* make sure the transfer is opened */ 1276390065b1SAlfred Perlstein err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1277390065b1SAlfred Perlstein if (err && (err != LIBUSB20_ERROR_BUSY)) { 1278390065b1SAlfred Perlstein goto failure; 1279390065b1SAlfred Perlstein } 1280390065b1SAlfred Perlstein libusb20_tr_start(pxfer0); 1281390065b1SAlfred Perlstein return; 1282390065b1SAlfred Perlstein 1283390065b1SAlfred Perlstein failure: 1284390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1285390065b1SAlfred Perlstein 1286390065b1SAlfred Perlstein /* make sure our event loop spins the done handler */ 1287390065b1SAlfred Perlstein dummy = 0; 1288390065b1SAlfred Perlstein write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1289390065b1SAlfred Perlstein } 1290390065b1SAlfred Perlstein 1291390065b1SAlfred Perlstein /* The following function must be called unlocked */ 1292c500e4ddSAndrew Thompson 12938c8fff31SAndrew Thompson int 1294390065b1SAlfred Perlstein libusb_submit_transfer(struct libusb_transfer *uxfer) 12958c8fff31SAndrew Thompson { 1296390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1297390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1298390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1299390065b1SAlfred Perlstein struct libusb_device *dev; 1300ccef4ddfSAndrew Thompson uint32_t endpoint; 1301390065b1SAlfred Perlstein int err; 13028c8fff31SAndrew Thompson 1303390065b1SAlfred Perlstein if (uxfer == NULL) 1304390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 13058c8fff31SAndrew Thompson 1306390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 1307390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 13088c8fff31SAndrew Thompson 1309390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 13108c8fff31SAndrew Thompson 1311390065b1SAlfred Perlstein if (endpoint > 255) 1312390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 13138c8fff31SAndrew Thompson 1314390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 13158c8fff31SAndrew Thompson 1316390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 13178c8fff31SAndrew Thompson 1318390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1319390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1320390065b1SAlfred Perlstein 1321390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1322390065b1SAlfred Perlstein 1323390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1324390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1325390065b1SAlfred Perlstein 1326390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) { 1327390065b1SAlfred Perlstein err = LIBUSB_ERROR_OTHER; 1328390065b1SAlfred Perlstein } else if ((sxfer->entry.tqe_prev != NULL) || 1329390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1330390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1331390065b1SAlfred Perlstein err = LIBUSB_ERROR_BUSY; 1332390065b1SAlfred Perlstein } else { 13334594d907SAndrew Thompson 13344594d907SAndrew Thompson /* set pending state */ 13354594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 13364594d907SAndrew Thompson 13374594d907SAndrew Thompson /* insert transfer into transfer head list */ 1338390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1339390065b1SAlfred Perlstein 13404594d907SAndrew Thompson /* start work transfers */ 1341390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1342390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1343390065b1SAlfred Perlstein 1344390065b1SAlfred Perlstein err = 0; /* success */ 13458c8fff31SAndrew Thompson } 13468c8fff31SAndrew Thompson 1347390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 1348390065b1SAlfred Perlstein 1349390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1350390065b1SAlfred Perlstein 1351390065b1SAlfred Perlstein return (err); 13528c8fff31SAndrew Thompson } 13538c8fff31SAndrew Thompson 1354390065b1SAlfred Perlstein /* Asynchronous transfer cancel */ 13558c8fff31SAndrew Thompson 1356390065b1SAlfred Perlstein int 1357390065b1SAlfred Perlstein libusb_cancel_transfer(struct libusb_transfer *uxfer) 1358390065b1SAlfred Perlstein { 1359390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1360390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1361390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1362390065b1SAlfred Perlstein struct libusb_device *dev; 1363ccef4ddfSAndrew Thompson uint32_t endpoint; 13644594d907SAndrew Thompson int retval; 13658c8fff31SAndrew Thompson 1366390065b1SAlfred Perlstein if (uxfer == NULL) 1367390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 13688c8fff31SAndrew Thompson 13694594d907SAndrew Thompson /* check if not initialised */ 1370390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 13714594d907SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 13728c8fff31SAndrew Thompson 1373390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 13748c8fff31SAndrew Thompson 1375390065b1SAlfred Perlstein if (endpoint > 255) 1376390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 13778c8fff31SAndrew Thompson 1378390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 13798c8fff31SAndrew Thompson 1380390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 13818c8fff31SAndrew Thompson 1382390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1383390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1384390065b1SAlfred Perlstein 13854594d907SAndrew Thompson retval = 0; 13864594d907SAndrew Thompson 1387390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1388390065b1SAlfred Perlstein 1389390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1390390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1391390065b1SAlfred Perlstein 13924594d907SAndrew Thompson if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 13934594d907SAndrew Thompson /* only update the transfer status */ 13944594d907SAndrew Thompson uxfer->status = LIBUSB_TRANSFER_CANCELLED; 13954594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 13964594d907SAndrew Thompson } else if (sxfer->entry.tqe_prev != NULL) { 1397390065b1SAlfred Perlstein /* we are lucky - transfer is on a queue */ 1398390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1399390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 14004594d907SAndrew Thompson libusb10_complete_transfer(NULL, 14014594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1402390065b1SAlfred Perlstein } else if (pxfer0 == NULL || pxfer1 == NULL) { 1403390065b1SAlfred Perlstein /* not started */ 14044594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1405390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 14064594d907SAndrew Thompson libusb10_complete_transfer(pxfer0, 14074594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1408390065b1SAlfred Perlstein libusb20_tr_stop(pxfer0); 1409390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1410390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1411390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1412390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 14134594d907SAndrew Thompson libusb10_complete_transfer(pxfer1, 14144594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1415390065b1SAlfred Perlstein libusb20_tr_stop(pxfer1); 1416390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1417390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1418390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1419390065b1SAlfred Perlstein } else { 1420390065b1SAlfred Perlstein /* not started */ 14214594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1422c500e4ddSAndrew Thompson } 14238c8fff31SAndrew Thompson 1424390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 14258c8fff31SAndrew Thompson 1426390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 14278c8fff31SAndrew Thompson 14284594d907SAndrew Thompson return (retval); 14298c8fff31SAndrew Thompson } 14308c8fff31SAndrew Thompson 1431390065b1SAlfred Perlstein UNEXPORTED void 1432390065b1SAlfred Perlstein libusb10_cancel_all_transfer(libusb_device *dev) 14338c8fff31SAndrew Thompson { 1434390065b1SAlfred Perlstein /* TODO */ 14358c8fff31SAndrew Thompson } 1436ccef4ddfSAndrew Thompson 1437ccef4ddfSAndrew Thompson uint16_t 1438ccef4ddfSAndrew Thompson libusb_cpu_to_le16(uint16_t x) 1439ccef4ddfSAndrew Thompson { 1440ccef4ddfSAndrew Thompson return (htole16(x)); 1441ccef4ddfSAndrew Thompson } 1442ccef4ddfSAndrew Thompson 1443ccef4ddfSAndrew Thompson uint16_t 1444ccef4ddfSAndrew Thompson libusb_le16_to_cpu(uint16_t x) 1445ccef4ddfSAndrew Thompson { 1446ccef4ddfSAndrew Thompson return (le16toh(x)); 1447ccef4ddfSAndrew Thompson } 1448ccef4ddfSAndrew Thompson 1449698e791aSHans Petter Selasky const char * 1450698e791aSHans Petter Selasky libusb_strerror(int code) 1451698e791aSHans Petter Selasky { 1452*c61f2561SHans Petter Selasky switch (code) { 1453*c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1454*c61f2561SHans Petter Selasky return ("Success"); 1455*c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1456*c61f2561SHans Petter Selasky return ("I/O error"); 1457*c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1458*c61f2561SHans Petter Selasky return ("Invalid parameter"); 1459*c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1460*c61f2561SHans Petter Selasky return ("Permissions error"); 1461*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1462*c61f2561SHans Petter Selasky return ("No device"); 1463*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1464*c61f2561SHans Petter Selasky return ("Not found"); 1465*c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1466*c61f2561SHans Petter Selasky return ("Device busy"); 1467*c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1468*c61f2561SHans Petter Selasky return ("Timeout"); 1469*c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1470*c61f2561SHans Petter Selasky return ("Overflow"); 1471*c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1472*c61f2561SHans Petter Selasky return ("Pipe error"); 1473*c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1474*c61f2561SHans Petter Selasky return ("Interrupted"); 1475*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1476*c61f2561SHans Petter Selasky return ("Out of memory"); 1477*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1478*c61f2561SHans Petter Selasky return ("Not supported"); 1479*c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1480*c61f2561SHans Petter Selasky return ("Other error"); 1481*c61f2561SHans Petter Selasky default: 1482698e791aSHans Petter Selasky return ("Unknown error"); 1483698e791aSHans Petter Selasky } 1484*c61f2561SHans Petter Selasky } 1485*c61f2561SHans Petter Selasky 1486*c61f2561SHans Petter Selasky const char * 1487*c61f2561SHans Petter Selasky libusb_error_name(int code) 1488*c61f2561SHans Petter Selasky { 1489*c61f2561SHans Petter Selasky switch (code) { 1490*c61f2561SHans Petter Selasky case LIBUSB_SUCCESS: 1491*c61f2561SHans Petter Selasky return ("LIBUSB_SUCCESS"); 1492*c61f2561SHans Petter Selasky case LIBUSB_ERROR_IO: 1493*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_IO"); 1494*c61f2561SHans Petter Selasky case LIBUSB_ERROR_INVALID_PARAM: 1495*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INVALID_PARAM"); 1496*c61f2561SHans Petter Selasky case LIBUSB_ERROR_ACCESS: 1497*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_ACCESS"); 1498*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_DEVICE: 1499*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_DEVICE"); 1500*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_FOUND: 1501*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_FOUND"); 1502*c61f2561SHans Petter Selasky case LIBUSB_ERROR_BUSY: 1503*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_BUSY"); 1504*c61f2561SHans Petter Selasky case LIBUSB_ERROR_TIMEOUT: 1505*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_TIMEOUT"); 1506*c61f2561SHans Petter Selasky case LIBUSB_ERROR_OVERFLOW: 1507*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OVERFLOW"); 1508*c61f2561SHans Petter Selasky case LIBUSB_ERROR_PIPE: 1509*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_PIPE"); 1510*c61f2561SHans Petter Selasky case LIBUSB_ERROR_INTERRUPTED: 1511*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_INTERRUPTED"); 1512*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NO_MEM: 1513*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NO_MEM"); 1514*c61f2561SHans Petter Selasky case LIBUSB_ERROR_NOT_SUPPORTED: 1515*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_NOT_SUPPORTED"); 1516*c61f2561SHans Petter Selasky case LIBUSB_ERROR_OTHER: 1517*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_OTHER"); 1518*c61f2561SHans Petter Selasky default: 1519*c61f2561SHans Petter Selasky return ("LIBUSB_ERROR_UNKNOWN"); 1520*c61f2561SHans Petter Selasky } 1521*c61f2561SHans Petter Selasky } 1522