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 408c8fff31SAndrew Thompson #include "libusb20.h" 418c8fff31SAndrew Thompson #include "libusb20_desc.h" 428c8fff31SAndrew Thompson #include "libusb20_int.h" 438c8fff31SAndrew Thompson #include "libusb.h" 448c8fff31SAndrew Thompson #include "libusb10.h" 458c8fff31SAndrew Thompson 468c8fff31SAndrew Thompson static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 478c8fff31SAndrew Thompson struct libusb_context *usbi_default_context = NULL; 48390065b1SAlfred Perlstein 49390065b1SAlfred Perlstein /* Prototypes */ 50390065b1SAlfred Perlstein 51390065b1SAlfred Perlstein static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 52390065b1SAlfred Perlstein static int libusb10_get_maxframe(struct libusb20_device *, libusb_transfer *); 53390065b1SAlfred Perlstein static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 54390065b1SAlfred Perlstein static int libusb10_convert_error(uint8_t status); 55390065b1SAlfred Perlstein static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 56390065b1SAlfred Perlstein static void libusb10_isoc_proxy(struct libusb20_transfer *); 57390065b1SAlfred Perlstein static void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 58390065b1SAlfred Perlstein static void libusb10_ctrl_proxy(struct libusb20_transfer *); 59390065b1SAlfred Perlstein static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 608c8fff31SAndrew Thompson 618c8fff31SAndrew Thompson /* Library initialisation / deinitialisation */ 628c8fff31SAndrew Thompson 638c8fff31SAndrew Thompson void 648c8fff31SAndrew Thompson libusb_set_debug(libusb_context *ctx, int level) 658c8fff31SAndrew Thompson { 66390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 678c8fff31SAndrew Thompson if (ctx) 688c8fff31SAndrew Thompson ctx->debug = level; 698c8fff31SAndrew Thompson } 708c8fff31SAndrew Thompson 718c8fff31SAndrew Thompson int 728c8fff31SAndrew Thompson libusb_init(libusb_context **context) 738c8fff31SAndrew Thompson { 748c8fff31SAndrew Thompson struct libusb_context *ctx; 758c8fff31SAndrew Thompson char *debug; 76ac840bfcSWojciech A. Koszek int flag; 778c8fff31SAndrew Thompson int ret; 788c8fff31SAndrew Thompson 798c8fff31SAndrew Thompson ctx = malloc(sizeof(*ctx)); 808c8fff31SAndrew Thompson if (!ctx) 818c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 828c8fff31SAndrew Thompson 838c8fff31SAndrew Thompson memset(ctx, 0, sizeof(*ctx)); 848c8fff31SAndrew Thompson 858c8fff31SAndrew Thompson debug = getenv("LIBUSB_DEBUG"); 868c8fff31SAndrew Thompson if (debug != NULL) { 878c8fff31SAndrew Thompson ctx->debug = atoi(debug); 888c8fff31SAndrew Thompson if (ctx->debug != 0) 898c8fff31SAndrew Thompson ctx->debug_fixed = 1; 908c8fff31SAndrew Thompson } 91c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->pollfds); 92390065b1SAlfred Perlstein TAILQ_INIT(&ctx->tr_done); 93390065b1SAlfred Perlstein 94390065b1SAlfred Perlstein pthread_mutex_init(&ctx->ctx_lock, NULL); 95390065b1SAlfred Perlstein pthread_cond_init(&ctx->ctx_cond, NULL); 96390065b1SAlfred Perlstein 97390065b1SAlfred Perlstein ctx->ctx_handler = NO_THREAD; 988c8fff31SAndrew Thompson 998c8fff31SAndrew Thompson ret = pipe(ctx->ctrl_pipe); 1008c8fff31SAndrew Thompson if (ret < 0) { 101390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 102390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 1038c8fff31SAndrew Thompson free(ctx); 1048c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 1058c8fff31SAndrew Thompson } 106390065b1SAlfred Perlstein /* set non-blocking mode on the control pipe to avoid deadlock */ 107ac840bfcSWojciech A. Koszek flag = 1; 108ac840bfcSWojciech A. Koszek ret = fcntl(ctx->ctrl_pipe[0], O_NONBLOCK, &flag); 109ac840bfcSWojciech A. Koszek assert(ret != -1 && "Couldn't set O_NONBLOCK for ctx->ctrl_pipe[0]"); 110ac840bfcSWojciech A. Koszek flag = 1; 111ac840bfcSWojciech A. Koszek ret = fcntl(ctx->ctrl_pipe[1], O_NONBLOCK, &flag); 112ac840bfcSWojciech A. Koszek assert(ret != -1 && "Couldn't set O_NONBLOCK for ctx->ctrl_pipe[1]"); 1138c8fff31SAndrew Thompson 114390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 1158c8fff31SAndrew Thompson 1168c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 1178c8fff31SAndrew Thompson if (usbi_default_context == NULL) { 1188c8fff31SAndrew Thompson usbi_default_context = ctx; 1198c8fff31SAndrew Thompson } 1208c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 1218c8fff31SAndrew Thompson 1228c8fff31SAndrew Thompson if (context) 1238c8fff31SAndrew Thompson *context = ctx; 1248c8fff31SAndrew Thompson 125390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 126390065b1SAlfred Perlstein 1278c8fff31SAndrew Thompson return (0); 1288c8fff31SAndrew Thompson } 1298c8fff31SAndrew Thompson 1308c8fff31SAndrew Thompson void 1318c8fff31SAndrew Thompson libusb_exit(libusb_context *ctx) 1328c8fff31SAndrew Thompson { 133390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 1348c8fff31SAndrew Thompson 135390065b1SAlfred Perlstein if (ctx == NULL) 136390065b1SAlfred Perlstein return; 137390065b1SAlfred Perlstein 138390065b1SAlfred Perlstein /* XXX cleanup devices */ 139390065b1SAlfred Perlstein 140390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 1418c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 1428c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 143390065b1SAlfred Perlstein pthread_mutex_destroy(&ctx->ctx_lock); 144390065b1SAlfred Perlstein pthread_cond_destroy(&ctx->ctx_cond); 1458c8fff31SAndrew Thompson 1468c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 1478c8fff31SAndrew Thompson if (ctx == usbi_default_context) { 1488c8fff31SAndrew Thompson usbi_default_context = NULL; 1498c8fff31SAndrew Thompson } 1508c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 1518c8fff31SAndrew Thompson 1528c8fff31SAndrew Thompson free(ctx); 1538c8fff31SAndrew Thompson } 1548c8fff31SAndrew Thompson 1558c8fff31SAndrew Thompson /* Device handling and initialisation. */ 1568c8fff31SAndrew Thompson 1578c8fff31SAndrew Thompson ssize_t 1588c8fff31SAndrew Thompson libusb_get_device_list(libusb_context *ctx, libusb_device ***list) 1598c8fff31SAndrew Thompson { 1608c8fff31SAndrew Thompson struct libusb20_backend *usb_backend; 161390065b1SAlfred Perlstein struct libusb20_device *pdev; 162390065b1SAlfred Perlstein struct libusb_device *dev; 1638c8fff31SAndrew Thompson int i; 1648c8fff31SAndrew Thompson 165390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 166390065b1SAlfred Perlstein 167390065b1SAlfred Perlstein if (ctx == NULL) 168390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 169390065b1SAlfred Perlstein 170390065b1SAlfred Perlstein if (list == NULL) 171390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 1728c8fff31SAndrew Thompson 1738c8fff31SAndrew Thompson usb_backend = libusb20_be_alloc_default(); 1748c8fff31SAndrew Thompson if (usb_backend == NULL) 175390065b1SAlfred Perlstein return (LIBUSB_ERROR_NO_MEM); 1768c8fff31SAndrew Thompson 177390065b1SAlfred Perlstein /* figure out how many USB devices are present */ 1788c8fff31SAndrew Thompson pdev = NULL; 1798c8fff31SAndrew Thompson i = 0; 1808c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 1818c8fff31SAndrew Thompson i++; 1828c8fff31SAndrew Thompson 183390065b1SAlfred Perlstein /* allocate device pointer list */ 1848c8fff31SAndrew Thompson *list = malloc((i + 1) * sizeof(void *)); 1858c8fff31SAndrew Thompson if (*list == NULL) { 1868c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 1878c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1888c8fff31SAndrew Thompson } 189390065b1SAlfred Perlstein /* create libusb v1.0 compliant devices */ 1908c8fff31SAndrew Thompson i = 0; 1918c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 1928c8fff31SAndrew Thompson 1938c8fff31SAndrew Thompson dev = malloc(sizeof(*dev)); 1948c8fff31SAndrew Thompson if (dev == NULL) { 195c500e4ddSAndrew Thompson while (i != 0) { 196c500e4ddSAndrew Thompson libusb_unref_device((*list)[i - 1]); 197c500e4ddSAndrew Thompson i--; 198c500e4ddSAndrew Thompson } 1998c8fff31SAndrew Thompson free(*list); 200390065b1SAlfred Perlstein *list = NULL; 2018c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2028c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 2038c8fff31SAndrew Thompson } 204ccef4ddfSAndrew Thompson 205ccef4ddfSAndrew Thompson /* get device into libUSB v1.0 list */ 206ccef4ddfSAndrew Thompson libusb20_be_dequeue_device(usb_backend, pdev); 207ccef4ddfSAndrew Thompson 2088c8fff31SAndrew Thompson memset(dev, 0, sizeof(*dev)); 2098c8fff31SAndrew Thompson 210390065b1SAlfred Perlstein /* init transfer queues */ 211390065b1SAlfred Perlstein TAILQ_INIT(&dev->tr_head); 212390065b1SAlfred Perlstein 213390065b1SAlfred Perlstein /* set context we belong to */ 2148c8fff31SAndrew Thompson dev->ctx = ctx; 2158c8fff31SAndrew Thompson 2168c8fff31SAndrew Thompson /* link together the two structures */ 2178c8fff31SAndrew Thompson dev->os_priv = pdev; 218390065b1SAlfred Perlstein pdev->privLuData = dev; 2198c8fff31SAndrew Thompson 2208c8fff31SAndrew Thompson (*list)[i] = libusb_ref_device(dev); 2218c8fff31SAndrew Thompson i++; 2228c8fff31SAndrew Thompson } 2238c8fff31SAndrew Thompson (*list)[i] = NULL; 2248c8fff31SAndrew Thompson 2258c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2268c8fff31SAndrew Thompson return (i); 2278c8fff31SAndrew Thompson } 2288c8fff31SAndrew Thompson 2298c8fff31SAndrew Thompson void 2308c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices) 2318c8fff31SAndrew Thompson { 2328c8fff31SAndrew Thompson int i; 2338c8fff31SAndrew Thompson 2348c8fff31SAndrew Thompson if (list == NULL) 235390065b1SAlfred Perlstein return; /* be NULL safe */ 2368c8fff31SAndrew Thompson 2378c8fff31SAndrew Thompson if (unref_devices) { 2388c8fff31SAndrew Thompson for (i = 0; list[i] != NULL; i++) 2398c8fff31SAndrew Thompson libusb_unref_device(list[i]); 2408c8fff31SAndrew Thompson } 2418c8fff31SAndrew Thompson free(list); 2428c8fff31SAndrew Thompson } 2438c8fff31SAndrew Thompson 2448c8fff31SAndrew Thompson uint8_t 2458c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device *dev) 2468c8fff31SAndrew Thompson { 2478c8fff31SAndrew Thompson if (dev == NULL) 248390065b1SAlfred Perlstein return (0); /* should not happen */ 249390065b1SAlfred Perlstein return (libusb20_dev_get_bus_number(dev->os_priv)); 2508c8fff31SAndrew Thompson } 2518c8fff31SAndrew Thompson 2528c8fff31SAndrew Thompson uint8_t 2538c8fff31SAndrew Thompson libusb_get_device_address(libusb_device *dev) 2548c8fff31SAndrew Thompson { 2558c8fff31SAndrew Thompson if (dev == NULL) 256390065b1SAlfred Perlstein return (0); /* should not happen */ 257390065b1SAlfred Perlstein return (libusb20_dev_get_address(dev->os_priv)); 2588c8fff31SAndrew Thompson } 2598c8fff31SAndrew Thompson 2608c8fff31SAndrew Thompson int 261390065b1SAlfred Perlstein libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 2628c8fff31SAndrew Thompson { 2638c8fff31SAndrew Thompson struct libusb_config_descriptor *pdconf; 2648c8fff31SAndrew Thompson struct libusb_interface *pinf; 2658c8fff31SAndrew Thompson struct libusb_interface_descriptor *pdinf; 2668c8fff31SAndrew Thompson struct libusb_endpoint_descriptor *pdend; 267390065b1SAlfred Perlstein int i; 268390065b1SAlfred Perlstein int j; 269390065b1SAlfred Perlstein int k; 270390065b1SAlfred Perlstein int ret; 2718c8fff31SAndrew Thompson 2728c8fff31SAndrew Thompson if (dev == NULL) 2738c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 2748c8fff31SAndrew Thompson 275390065b1SAlfred Perlstein ret = libusb_get_active_config_descriptor(dev, &pdconf); 276390065b1SAlfred Perlstein if (ret < 0) 277390065b1SAlfred Perlstein return (ret); 2788c8fff31SAndrew Thompson 2798c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 2808c8fff31SAndrew Thompson for (i = 0; i < pdconf->bNumInterfaces; i++) { 2818c8fff31SAndrew Thompson pinf = &pdconf->interface[i]; 2828c8fff31SAndrew Thompson for (j = 0; j < pinf->num_altsetting; j++) { 2838c8fff31SAndrew Thompson pdinf = &pinf->altsetting[j]; 2848c8fff31SAndrew Thompson for (k = 0; k < pdinf->bNumEndpoints; k++) { 2858c8fff31SAndrew Thompson pdend = &pdinf->endpoint[k]; 2868c8fff31SAndrew Thompson if (pdend->bEndpointAddress == endpoint) { 2878c8fff31SAndrew Thompson ret = pdend->wMaxPacketSize; 2888c8fff31SAndrew Thompson goto out; 2898c8fff31SAndrew Thompson } 2908c8fff31SAndrew Thompson } 2918c8fff31SAndrew Thompson } 2928c8fff31SAndrew Thompson } 2938c8fff31SAndrew Thompson 2948c8fff31SAndrew Thompson out: 2958c8fff31SAndrew Thompson libusb_free_config_descriptor(pdconf); 2968c8fff31SAndrew Thompson return (ret); 2978c8fff31SAndrew Thompson } 2988c8fff31SAndrew Thompson 2998c8fff31SAndrew Thompson libusb_device * 3008c8fff31SAndrew Thompson libusb_ref_device(libusb_device *dev) 3018c8fff31SAndrew Thompson { 3028c8fff31SAndrew Thompson if (dev == NULL) 303390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 3048c8fff31SAndrew Thompson 305390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 3068c8fff31SAndrew Thompson dev->refcnt++; 307390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 3088c8fff31SAndrew Thompson 3098c8fff31SAndrew Thompson return (dev); 3108c8fff31SAndrew Thompson } 3118c8fff31SAndrew Thompson 3128c8fff31SAndrew Thompson void 3138c8fff31SAndrew Thompson libusb_unref_device(libusb_device *dev) 3148c8fff31SAndrew Thompson { 3158c8fff31SAndrew Thompson if (dev == NULL) 316390065b1SAlfred Perlstein return; /* be NULL safe */ 3178c8fff31SAndrew Thompson 318390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 3198c8fff31SAndrew Thompson dev->refcnt--; 320390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 3218c8fff31SAndrew Thompson 3228c8fff31SAndrew Thompson if (dev->refcnt == 0) { 3238c8fff31SAndrew Thompson libusb20_dev_free(dev->os_priv); 3248c8fff31SAndrew Thompson free(dev); 3258c8fff31SAndrew Thompson } 3268c8fff31SAndrew Thompson } 3278c8fff31SAndrew Thompson 3288c8fff31SAndrew Thompson int 3298c8fff31SAndrew Thompson libusb_open(libusb_device *dev, libusb_device_handle **devh) 3308c8fff31SAndrew Thompson { 3318c8fff31SAndrew Thompson libusb_context *ctx = dev->ctx; 3328c8fff31SAndrew Thompson struct libusb20_device *pdev = dev->os_priv; 333390065b1SAlfred Perlstein uint8_t dummy; 3348c8fff31SAndrew Thompson int err; 3358c8fff31SAndrew Thompson 3368c8fff31SAndrew Thompson if (devh == NULL) 3378c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 3388c8fff31SAndrew Thompson 339390065b1SAlfred Perlstein /* set default device handle value */ 340390065b1SAlfred Perlstein *devh = NULL; 341390065b1SAlfred Perlstein 342390065b1SAlfred Perlstein dev = libusb_ref_device(dev); 343390065b1SAlfred Perlstein if (dev == NULL) 344390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 3458c8fff31SAndrew Thompson 3468c8fff31SAndrew Thompson err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 3478c8fff31SAndrew Thompson if (err) { 348390065b1SAlfred Perlstein libusb_unref_device(dev); 3498c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3508c8fff31SAndrew Thompson } 351390065b1SAlfred Perlstein libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 3528c8fff31SAndrew Thompson POLLOUT | POLLRDNORM | POLLWRNORM); 3538c8fff31SAndrew Thompson 354390065b1SAlfred Perlstein /* make sure our event loop detects the new device */ 355390065b1SAlfred Perlstein dummy = 0; 3568c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 357390065b1SAlfred Perlstein if (err < sizeof(dummy)) { 358390065b1SAlfred Perlstein /* ignore error, if any */ 359390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 3608c8fff31SAndrew Thompson } 361390065b1SAlfred Perlstein *devh = pdev; 3628c8fff31SAndrew Thompson 3638c8fff31SAndrew Thompson return (0); 3648c8fff31SAndrew Thompson } 3658c8fff31SAndrew Thompson 3668c8fff31SAndrew Thompson libusb_device_handle * 3678c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 3688c8fff31SAndrew Thompson uint16_t product_id) 3698c8fff31SAndrew Thompson { 3708c8fff31SAndrew Thompson struct libusb_device **devs; 3718c8fff31SAndrew Thompson struct libusb20_device *pdev; 3728c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 373390065b1SAlfred Perlstein int i; 374390065b1SAlfred Perlstein int j; 3758c8fff31SAndrew Thompson 376390065b1SAlfred Perlstein ctx = GET_CONTEXT(ctx); 377390065b1SAlfred Perlstein if (ctx == NULL) 378390065b1SAlfred Perlstein return (NULL); /* be NULL safe */ 379390065b1SAlfred Perlstein 380c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 3818c8fff31SAndrew Thompson 3828c8fff31SAndrew Thompson if ((i = libusb_get_device_list(ctx, &devs)) < 0) 3838c8fff31SAndrew Thompson return (NULL); 3848c8fff31SAndrew Thompson 3858c8fff31SAndrew Thompson for (j = 0; j < i; j++) { 386390065b1SAlfred Perlstein pdev = devs[j]->os_priv; 3878c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 388390065b1SAlfred Perlstein /* 389390065b1SAlfred Perlstein * NOTE: The USB library will automatically swap the 390390065b1SAlfred Perlstein * fields in the device descriptor to be of host 391390065b1SAlfred Perlstein * endian type! 392390065b1SAlfred Perlstein */ 3938c8fff31SAndrew Thompson if (pdesc->idVendor == vendor_id && 394c500e4ddSAndrew Thompson pdesc->idProduct == product_id) { 395390065b1SAlfred Perlstein if (libusb_open(devs[j], &pdev) < 0) 396390065b1SAlfred Perlstein pdev = NULL; 397c500e4ddSAndrew Thompson break; 398c500e4ddSAndrew Thompson } 3998c8fff31SAndrew Thompson } 400abdbb3feSSean Farley if (j == i) 401abdbb3feSSean Farley pdev = NULL; 4028c8fff31SAndrew Thompson 4038c8fff31SAndrew Thompson libusb_free_device_list(devs, 1); 404c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 405390065b1SAlfred Perlstein return (pdev); 4068c8fff31SAndrew Thompson } 4078c8fff31SAndrew Thompson 4088c8fff31SAndrew Thompson void 409390065b1SAlfred Perlstein libusb_close(struct libusb20_device *pdev) 4108c8fff31SAndrew Thompson { 4118c8fff31SAndrew Thompson libusb_context *ctx; 412390065b1SAlfred Perlstein struct libusb_device *dev; 413390065b1SAlfred Perlstein uint8_t dummy; 4148c8fff31SAndrew Thompson int err; 4158c8fff31SAndrew Thompson 416390065b1SAlfred Perlstein if (pdev == NULL) 417390065b1SAlfred Perlstein return; /* be NULL safe */ 4188c8fff31SAndrew Thompson 419390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 420390065b1SAlfred Perlstein ctx = dev->ctx; 4218c8fff31SAndrew Thompson 422390065b1SAlfred Perlstein libusb10_remove_pollfd(ctx, &dev->dev_poll); 4238c8fff31SAndrew Thompson 424390065b1SAlfred Perlstein libusb20_dev_close(pdev); 425ccef4ddfSAndrew Thompson 426ccef4ddfSAndrew Thompson /* unref will free the "pdev" when the refcount reaches zero */ 427390065b1SAlfred Perlstein libusb_unref_device(dev); 4288c8fff31SAndrew Thompson 429390065b1SAlfred Perlstein /* make sure our event loop detects the closed device */ 430390065b1SAlfred Perlstein dummy = 0; 4318c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 432390065b1SAlfred Perlstein if (err < sizeof(dummy)) { 433390065b1SAlfred Perlstein /* ignore error, if any */ 434390065b1SAlfred Perlstein DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 435c500e4ddSAndrew Thompson } 4368c8fff31SAndrew Thompson } 4378c8fff31SAndrew Thompson 4388c8fff31SAndrew Thompson libusb_device * 439390065b1SAlfred Perlstein libusb_get_device(struct libusb20_device *pdev) 4408c8fff31SAndrew Thompson { 441390065b1SAlfred Perlstein if (pdev == NULL) 4428c8fff31SAndrew Thompson return (NULL); 443390065b1SAlfred Perlstein return ((libusb_device *)pdev->privLuData); 4448c8fff31SAndrew Thompson } 4458c8fff31SAndrew Thompson 4468c8fff31SAndrew Thompson int 447390065b1SAlfred Perlstein libusb_get_configuration(struct libusb20_device *pdev, int *config) 4488c8fff31SAndrew Thompson { 449390065b1SAlfred Perlstein struct libusb20_config *pconf; 4508c8fff31SAndrew Thompson 451390065b1SAlfred Perlstein if (pdev == NULL || config == NULL) 4528c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 4538c8fff31SAndrew Thompson 454390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 455390065b1SAlfred Perlstein if (pconf == NULL) 456c500e4ddSAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 4578c8fff31SAndrew Thompson 458390065b1SAlfred Perlstein *config = pconf->desc.bConfigurationValue; 4598c8fff31SAndrew Thompson 460390065b1SAlfred Perlstein free(pconf); 4618c8fff31SAndrew Thompson 4628c8fff31SAndrew Thompson return (0); 4638c8fff31SAndrew Thompson } 4648c8fff31SAndrew Thompson 4658c8fff31SAndrew Thompson int 466390065b1SAlfred Perlstein libusb_set_configuration(struct libusb20_device *pdev, int configuration) 4678c8fff31SAndrew Thompson { 468390065b1SAlfred Perlstein struct libusb20_config *pconf; 469390065b1SAlfred Perlstein struct libusb_device *dev; 470390065b1SAlfred Perlstein int err; 471390065b1SAlfred Perlstein uint8_t i; 4728c8fff31SAndrew Thompson 473390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 4748c8fff31SAndrew Thompson 4758c8fff31SAndrew Thompson if (dev == NULL) 476390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 477390065b1SAlfred Perlstein 478390065b1SAlfred Perlstein if (configuration < 1) { 479390065b1SAlfred Perlstein /* unconfigure */ 480390065b1SAlfred Perlstein i = 255; 481390065b1SAlfred Perlstein } else { 482390065b1SAlfred Perlstein for (i = 0; i != 255; i++) { 483390065b1SAlfred Perlstein uint8_t found; 484390065b1SAlfred Perlstein 485390065b1SAlfred Perlstein pconf = libusb20_dev_alloc_config(pdev, i); 486390065b1SAlfred Perlstein if (pconf == NULL) 487390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 488390065b1SAlfred Perlstein found = (pconf->desc.bConfigurationValue 489390065b1SAlfred Perlstein == configuration); 490390065b1SAlfred Perlstein free(pconf); 491390065b1SAlfred Perlstein 492390065b1SAlfred Perlstein if (found) 493390065b1SAlfred Perlstein goto set_config; 494390065b1SAlfred Perlstein } 495390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 496390065b1SAlfred Perlstein } 497390065b1SAlfred Perlstein 498390065b1SAlfred Perlstein set_config: 499390065b1SAlfred Perlstein 500390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 501390065b1SAlfred Perlstein 502390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 503390065b1SAlfred Perlstein 504390065b1SAlfred Perlstein err = libusb20_dev_set_config_index(pdev, i); 505390065b1SAlfred Perlstein 506390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 507390065b1SAlfred Perlstein POLLOUT | POLLRDNORM | POLLWRNORM); 508390065b1SAlfred Perlstein 509390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 510390065b1SAlfred Perlstein } 511390065b1SAlfred Perlstein 512390065b1SAlfred Perlstein int 513390065b1SAlfred Perlstein libusb_claim_interface(struct libusb20_device *pdev, int interface_number) 514390065b1SAlfred Perlstein { 515390065b1SAlfred Perlstein libusb_device *dev; 516390065b1SAlfred Perlstein int err = 0; 517390065b1SAlfred Perlstein 518390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 519390065b1SAlfred Perlstein if (dev == NULL) 520390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 521390065b1SAlfred Perlstein 522390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 523390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 524390065b1SAlfred Perlstein 525390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 526390065b1SAlfred Perlstein if (dev->claimed_interfaces & (1 << interface_number)) 527390065b1SAlfred Perlstein err = LIBUSB_ERROR_BUSY; 528390065b1SAlfred Perlstein 529390065b1SAlfred Perlstein if (!err) 530390065b1SAlfred Perlstein dev->claimed_interfaces |= (1 << interface_number); 531390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 532390065b1SAlfred Perlstein return (err); 533390065b1SAlfred Perlstein } 534390065b1SAlfred Perlstein 535390065b1SAlfred Perlstein int 536390065b1SAlfred Perlstein libusb_release_interface(struct libusb20_device *pdev, int interface_number) 537390065b1SAlfred Perlstein { 538390065b1SAlfred Perlstein libusb_device *dev; 539390065b1SAlfred Perlstein int err = 0; 540390065b1SAlfred Perlstein 541390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 542390065b1SAlfred Perlstein if (dev == NULL) 543390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 544390065b1SAlfred Perlstein 545390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 546390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 547390065b1SAlfred Perlstein 548390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 549390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 550390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 551390065b1SAlfred Perlstein 552390065b1SAlfred Perlstein if (!err) 553390065b1SAlfred Perlstein dev->claimed_interfaces &= ~(1 << interface_number); 554390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 555390065b1SAlfred Perlstein return (err); 556390065b1SAlfred Perlstein } 557390065b1SAlfred Perlstein 558390065b1SAlfred Perlstein int 559390065b1SAlfred Perlstein libusb_set_interface_alt_setting(struct libusb20_device *pdev, 560390065b1SAlfred Perlstein int interface_number, int alternate_setting) 561390065b1SAlfred Perlstein { 562390065b1SAlfred Perlstein libusb_device *dev; 563390065b1SAlfred Perlstein int err = 0; 564390065b1SAlfred Perlstein 565390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 566390065b1SAlfred Perlstein if (dev == NULL) 567390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 568390065b1SAlfred Perlstein 569390065b1SAlfred Perlstein if (interface_number < 0 || interface_number > 31) 570390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 571390065b1SAlfred Perlstein 572390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 573390065b1SAlfred Perlstein if (!(dev->claimed_interfaces & (1 << interface_number))) 574390065b1SAlfred Perlstein err = LIBUSB_ERROR_NOT_FOUND; 575390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 576390065b1SAlfred Perlstein 577390065b1SAlfred Perlstein if (err) 578390065b1SAlfred Perlstein return (err); 579390065b1SAlfred Perlstein 580390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 581390065b1SAlfred Perlstein 582390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 583390065b1SAlfred Perlstein 584390065b1SAlfred Perlstein err = libusb20_dev_set_alt_index(pdev, 585390065b1SAlfred Perlstein interface_number, alternate_setting); 586390065b1SAlfred Perlstein 587390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 588390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 589390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 590390065b1SAlfred Perlstein 591390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 592390065b1SAlfred Perlstein } 593390065b1SAlfred Perlstein 594390065b1SAlfred Perlstein static struct libusb20_transfer * 595390065b1SAlfred Perlstein libusb10_get_transfer(struct libusb20_device *pdev, 596390065b1SAlfred Perlstein uint8_t endpoint, uint8_t index) 597390065b1SAlfred Perlstein { 598390065b1SAlfred Perlstein index &= 1; /* double buffering */ 599390065b1SAlfred Perlstein 600390065b1SAlfred Perlstein index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 601390065b1SAlfred Perlstein 602390065b1SAlfred Perlstein if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 603390065b1SAlfred Perlstein /* this is an IN endpoint */ 604390065b1SAlfred Perlstein index |= 2; 605390065b1SAlfred Perlstein } 606390065b1SAlfred Perlstein return (libusb20_tr_get_pointer(pdev, index)); 607390065b1SAlfred Perlstein } 608390065b1SAlfred Perlstein 609390065b1SAlfred Perlstein int 610390065b1SAlfred Perlstein libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 611390065b1SAlfred Perlstein { 612390065b1SAlfred Perlstein struct libusb20_transfer *xfer; 613390065b1SAlfred Perlstein struct libusb_device *dev; 614390065b1SAlfred Perlstein int err; 615390065b1SAlfred Perlstein 616390065b1SAlfred Perlstein xfer = libusb10_get_transfer(pdev, endpoint, 0); 617390065b1SAlfred Perlstein if (xfer == NULL) 618390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 619390065b1SAlfred Perlstein 620390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 621390065b1SAlfred Perlstein 622390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 623390065b1SAlfred Perlstein err = libusb20_tr_open(xfer, 0, 0, endpoint); 624390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 625390065b1SAlfred Perlstein 626390065b1SAlfred Perlstein if (err != 0 && err != LIBUSB20_ERROR_BUSY) 627390065b1SAlfred Perlstein return (LIBUSB_ERROR_OTHER); 628390065b1SAlfred Perlstein 629390065b1SAlfred Perlstein libusb20_tr_clear_stall_sync(xfer); 630390065b1SAlfred Perlstein 631390065b1SAlfred Perlstein /* check if we opened the transfer */ 632390065b1SAlfred Perlstein if (err == 0) { 633390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 634390065b1SAlfred Perlstein libusb20_tr_close(xfer); 635390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 636390065b1SAlfred Perlstein } 637390065b1SAlfred Perlstein return (0); /* success */ 638390065b1SAlfred Perlstein } 639390065b1SAlfred Perlstein 640390065b1SAlfred Perlstein int 641390065b1SAlfred Perlstein libusb_reset_device(struct libusb20_device *pdev) 642390065b1SAlfred Perlstein { 643390065b1SAlfred Perlstein libusb_device *dev; 644390065b1SAlfred Perlstein int err; 645390065b1SAlfred Perlstein 646390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 647390065b1SAlfred Perlstein if (dev == NULL) 6488c8fff31SAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 6498c8fff31SAndrew Thompson 650390065b1SAlfred Perlstein libusb10_cancel_all_transfer(dev); 651390065b1SAlfred Perlstein 652390065b1SAlfred Perlstein libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 653390065b1SAlfred Perlstein 654390065b1SAlfred Perlstein err = libusb20_dev_reset(pdev); 655390065b1SAlfred Perlstein 656390065b1SAlfred Perlstein libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 657390065b1SAlfred Perlstein pdev, libusb20_dev_get_fd(pdev), 658390065b1SAlfred Perlstein POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 659390065b1SAlfred Perlstein 660390065b1SAlfred Perlstein return (err ? LIBUSB_ERROR_OTHER : 0); 6618c8fff31SAndrew Thompson } 6628c8fff31SAndrew Thompson 6638c8fff31SAndrew Thompson int 664390065b1SAlfred Perlstein libusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 6658c8fff31SAndrew Thompson { 666390065b1SAlfred Perlstein if (pdev == NULL) 6678c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6688c8fff31SAndrew Thompson 669390065b1SAlfred Perlstein return (libusb20_dev_kernel_driver_active( 670390065b1SAlfred Perlstein pdev, interface)); 6718c8fff31SAndrew Thompson } 6728c8fff31SAndrew Thompson 6738c8fff31SAndrew Thompson int 674390065b1SAlfred Perlstein libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 6758c8fff31SAndrew Thompson { 676390065b1SAlfred Perlstein int err; 6778c8fff31SAndrew Thompson 678390065b1SAlfred Perlstein if (pdev == NULL) 6798c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6808c8fff31SAndrew Thompson 681390065b1SAlfred Perlstein err = libusb20_dev_detach_kernel_driver( 682390065b1SAlfred Perlstein pdev, interface); 6838c8fff31SAndrew Thompson 684390065b1SAlfred Perlstein return (err ? LIBUSB20_ERROR_OTHER : 0); 6858c8fff31SAndrew Thompson } 6868c8fff31SAndrew Thompson 6878c8fff31SAndrew Thompson int 688390065b1SAlfred Perlstein libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 6898c8fff31SAndrew Thompson { 690390065b1SAlfred Perlstein if (pdev == NULL) 6918c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 692390065b1SAlfred Perlstein /* stub - currently not supported by libusb20 */ 6938c8fff31SAndrew Thompson return (0); 6948c8fff31SAndrew Thompson } 6958c8fff31SAndrew Thompson 6968c8fff31SAndrew Thompson /* Asynchronous device I/O */ 6978c8fff31SAndrew Thompson 6988c8fff31SAndrew Thompson struct libusb_transfer * 6998c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets) 7008c8fff31SAndrew Thompson { 701390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 702390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 7038c8fff31SAndrew Thompson int len; 7048c8fff31SAndrew Thompson 7058c8fff31SAndrew Thompson len = sizeof(struct libusb_transfer) + 706390065b1SAlfred Perlstein sizeof(struct libusb_super_transfer) + 7078c8fff31SAndrew Thompson (iso_packets * sizeof(libusb_iso_packet_descriptor)); 7088c8fff31SAndrew Thompson 709390065b1SAlfred Perlstein sxfer = malloc(len); 710390065b1SAlfred Perlstein if (sxfer == NULL) 7118c8fff31SAndrew Thompson return (NULL); 7128c8fff31SAndrew Thompson 713390065b1SAlfred Perlstein memset(sxfer, 0, len); 7148c8fff31SAndrew Thompson 715390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 716390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 7178c8fff31SAndrew Thompson 718390065b1SAlfred Perlstein /* set default value */ 719390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 720390065b1SAlfred Perlstein 721390065b1SAlfred Perlstein return (uxfer); 7228c8fff31SAndrew Thompson } 7238c8fff31SAndrew Thompson 7248c8fff31SAndrew Thompson void 725390065b1SAlfred Perlstein libusb_free_transfer(struct libusb_transfer *uxfer) 7268c8fff31SAndrew Thompson { 727390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 7288c8fff31SAndrew Thompson 729390065b1SAlfred Perlstein if (uxfer == NULL) 730390065b1SAlfred Perlstein return; /* be NULL safe */ 7318c8fff31SAndrew Thompson 732390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 733390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 7348c8fff31SAndrew Thompson 735390065b1SAlfred Perlstein free(sxfer); 7368c8fff31SAndrew Thompson } 7378c8fff31SAndrew Thompson 7388c8fff31SAndrew Thompson static int 739390065b1SAlfred Perlstein libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 7408c8fff31SAndrew Thompson { 7418c8fff31SAndrew Thompson int ret; 7428c8fff31SAndrew Thompson int usb_speed; 7438c8fff31SAndrew Thompson 7448c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 7458c8fff31SAndrew Thompson 7468c8fff31SAndrew Thompson switch (xfer->type) { 7478c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 7488c8fff31SAndrew Thompson switch (usb_speed) { 7498c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 7508c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 7518c8fff31SAndrew Thompson ret = 60 * 1; 7528c8fff31SAndrew Thompson break; 7538c8fff31SAndrew Thompson default: 7548c8fff31SAndrew Thompson ret = 60 * 8; 7558c8fff31SAndrew Thompson break; 7568c8fff31SAndrew Thompson } 7578c8fff31SAndrew Thompson break; 7588c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 7598c8fff31SAndrew Thompson ret = 2; 7608c8fff31SAndrew Thompson break; 7618c8fff31SAndrew Thompson default: 7628c8fff31SAndrew Thompson ret = 1; 7638c8fff31SAndrew Thompson break; 7648c8fff31SAndrew Thompson } 765390065b1SAlfred Perlstein return (ret); 7668c8fff31SAndrew Thompson } 7678c8fff31SAndrew Thompson 7688c8fff31SAndrew Thompson static int 769390065b1SAlfred Perlstein libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 7708c8fff31SAndrew Thompson { 7718c8fff31SAndrew Thompson int ret; 7728c8fff31SAndrew Thompson int usb_speed; 7738c8fff31SAndrew Thompson 7748c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 7758c8fff31SAndrew Thompson 7768c8fff31SAndrew Thompson switch (xfer->type) { 7778c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 778390065b1SAlfred Perlstein ret = 0; /* kernel will auto-select */ 7798c8fff31SAndrew Thompson break; 7808c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 781390065b1SAlfred Perlstein ret = 1024; 7828c8fff31SAndrew Thompson break; 7838c8fff31SAndrew Thompson default: 7848c8fff31SAndrew Thompson switch (usb_speed) { 7858c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 7868c8fff31SAndrew Thompson ret = 256; 7878c8fff31SAndrew Thompson break; 7888c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 7898c8fff31SAndrew Thompson ret = 4096; 7908c8fff31SAndrew Thompson break; 7918c8fff31SAndrew Thompson default: 7928c8fff31SAndrew Thompson ret = 16384; 7938c8fff31SAndrew Thompson break; 7948c8fff31SAndrew Thompson } 7958c8fff31SAndrew Thompson break; 7968c8fff31SAndrew Thompson } 797390065b1SAlfred Perlstein return (ret); 7988c8fff31SAndrew Thompson } 7998c8fff31SAndrew Thompson 800390065b1SAlfred Perlstein static int 801390065b1SAlfred Perlstein libusb10_convert_error(uint8_t status) 802390065b1SAlfred Perlstein { 803390065b1SAlfred Perlstein ; /* indent fix */ 804390065b1SAlfred Perlstein 805390065b1SAlfred Perlstein switch (status) { 806390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 807390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 808390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_COMPLETED); 809390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_OVERFLOW: 810390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_OVERFLOW); 811390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_NO_DEVICE: 812390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_NO_DEVICE); 813390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_STALL: 814390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_STALL); 815390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_CANCELLED: 816390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_CANCELLED); 817390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_TIMED_OUT: 818390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_TIMED_OUT); 819390065b1SAlfred Perlstein default: 820390065b1SAlfred Perlstein return (LIBUSB_TRANSFER_ERROR); 821390065b1SAlfred Perlstein } 822390065b1SAlfred Perlstein } 823390065b1SAlfred Perlstein 824390065b1SAlfred Perlstein /* This function must be called locked */ 825390065b1SAlfred Perlstein 826c500e4ddSAndrew Thompson static void 827390065b1SAlfred Perlstein libusb10_complete_transfer(struct libusb20_transfer *pxfer, 828390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer, int status) 829c500e4ddSAndrew Thompson { 830390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 831390065b1SAlfred Perlstein struct libusb_device *dev; 832c500e4ddSAndrew Thompson 833390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 834390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 835390065b1SAlfred Perlstein 836390065b1SAlfred Perlstein if (pxfer != NULL) 837390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer, NULL); 838390065b1SAlfred Perlstein 8394594d907SAndrew Thompson /* set transfer status */ 840390065b1SAlfred Perlstein uxfer->status = status; 841390065b1SAlfred Perlstein 8424594d907SAndrew Thompson /* update super transfer state */ 8434594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 8444594d907SAndrew Thompson 845390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 846390065b1SAlfred Perlstein 847390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 848390065b1SAlfred Perlstein } 849390065b1SAlfred Perlstein 850390065b1SAlfred Perlstein /* This function must be called locked */ 851390065b1SAlfred Perlstein 852390065b1SAlfred Perlstein static void 853390065b1SAlfred Perlstein libusb10_isoc_proxy(struct libusb20_transfer *pxfer) 854390065b1SAlfred Perlstein { 855390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 856390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 857390065b1SAlfred Perlstein uint32_t actlen; 858390065b1SAlfred Perlstein uint16_t iso_packets; 859390065b1SAlfred Perlstein uint16_t i; 860390065b1SAlfred Perlstein uint8_t status; 861390065b1SAlfred Perlstein uint8_t flags; 862390065b1SAlfred Perlstein 863390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 864390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 865390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 866390065b1SAlfred Perlstein iso_packets = libusb20_tr_get_max_frames(pxfer); 867390065b1SAlfred Perlstein 868390065b1SAlfred Perlstein if (sxfer == NULL) 869390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 870390065b1SAlfred Perlstein 871390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 872390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 873390065b1SAlfred Perlstein 874390065b1SAlfred Perlstein if (iso_packets > uxfer->num_iso_packets) 875390065b1SAlfred Perlstein iso_packets = uxfer->num_iso_packets; 876390065b1SAlfred Perlstein 877390065b1SAlfred Perlstein if (iso_packets == 0) 878390065b1SAlfred Perlstein return; /* nothing to do */ 879390065b1SAlfred Perlstein 880390065b1SAlfred Perlstein /* make sure that the number of ISOCHRONOUS packets is valid */ 881390065b1SAlfred Perlstein uxfer->num_iso_packets = iso_packets; 882390065b1SAlfred Perlstein 883390065b1SAlfred Perlstein flags = uxfer->flags; 884c500e4ddSAndrew Thompson 885c500e4ddSAndrew Thompson switch (status) { 886c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 887c500e4ddSAndrew Thompson 888390065b1SAlfred Perlstein /* update actual length */ 889390065b1SAlfred Perlstein uxfer->actual_length = actlen; 890390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 891390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].actual_length = 892390065b1SAlfred Perlstein libusb20_tr_get_length(pxfer, i); 893390065b1SAlfred Perlstein } 894390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 895c500e4ddSAndrew Thompson break; 896390065b1SAlfred Perlstein 897c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_START: 898390065b1SAlfred Perlstein 899390065b1SAlfred Perlstein /* setup length(s) */ 900390065b1SAlfred Perlstein actlen = 0; 901390065b1SAlfred Perlstein for (i = 0; i != iso_packets; i++) { 902390065b1SAlfred Perlstein libusb20_tr_setup_isoc(pxfer, 903390065b1SAlfred Perlstein &uxfer->buffer[actlen], 904390065b1SAlfred Perlstein uxfer->iso_packet_desc[i].length, i); 905390065b1SAlfred Perlstein actlen += uxfer->iso_packet_desc[i].length; 906c500e4ddSAndrew Thompson } 907390065b1SAlfred Perlstein 908390065b1SAlfred Perlstein /* no remainder */ 909390065b1SAlfred Perlstein sxfer->rem_len = 0; 910390065b1SAlfred Perlstein 911390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, iso_packets); 912390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 913390065b1SAlfred Perlstein 914390065b1SAlfred Perlstein /* fork another USB transfer, if any */ 915390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 916c500e4ddSAndrew Thompson break; 917390065b1SAlfred Perlstein 918390065b1SAlfred Perlstein default: 919390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 920c500e4ddSAndrew Thompson break; 921c500e4ddSAndrew Thompson } 922390065b1SAlfred Perlstein } 923390065b1SAlfred Perlstein 924390065b1SAlfred Perlstein /* This function must be called locked */ 925390065b1SAlfred Perlstein 926390065b1SAlfred Perlstein static void 927390065b1SAlfred Perlstein libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 928390065b1SAlfred Perlstein { 929390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 930390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 931390065b1SAlfred Perlstein uint32_t max_bulk; 932390065b1SAlfred Perlstein uint32_t actlen; 933390065b1SAlfred Perlstein uint8_t status; 934390065b1SAlfred Perlstein uint8_t flags; 935390065b1SAlfred Perlstein 936390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 937390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 938390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 939390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 940390065b1SAlfred Perlstein 941390065b1SAlfred Perlstein if (sxfer == NULL) 942390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 943390065b1SAlfred Perlstein 944390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 945390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 946390065b1SAlfred Perlstein 947390065b1SAlfred Perlstein flags = uxfer->flags; 948390065b1SAlfred Perlstein 949390065b1SAlfred Perlstein switch (status) { 950390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 951390065b1SAlfred Perlstein 952390065b1SAlfred Perlstein uxfer->actual_length += actlen; 953390065b1SAlfred Perlstein 954390065b1SAlfred Perlstein /* check for short packet */ 955390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 956390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 957390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 958390065b1SAlfred Perlstein } else { 959390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 960390065b1SAlfred Perlstein } 961390065b1SAlfred Perlstein break; 962390065b1SAlfred Perlstein } 963390065b1SAlfred Perlstein /* check for end of data */ 964390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 965390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 966390065b1SAlfred Perlstein break; 967390065b1SAlfred Perlstein } 968390065b1SAlfred Perlstein /* FALLTHROUGH */ 969390065b1SAlfred Perlstein 970390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 971390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 972390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 973390065b1SAlfred Perlstein } 974390065b1SAlfred Perlstein /* setup new BULK or INTERRUPT transaction */ 975390065b1SAlfred Perlstein libusb20_tr_setup_bulk(pxfer, 976390065b1SAlfred Perlstein sxfer->curr_data, max_bulk, uxfer->timeout); 977390065b1SAlfred Perlstein 978390065b1SAlfred Perlstein /* update counters */ 979390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 980390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 981390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 982390065b1SAlfred Perlstein 983390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 984390065b1SAlfred Perlstein 985390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 986390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 987390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 988390065b1SAlfred Perlstein break; 989390065b1SAlfred Perlstein 990390065b1SAlfred Perlstein default: 991390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 992390065b1SAlfred Perlstein break; 993390065b1SAlfred Perlstein } 994390065b1SAlfred Perlstein } 995390065b1SAlfred Perlstein 996390065b1SAlfred Perlstein /* This function must be called locked */ 997390065b1SAlfred Perlstein 998390065b1SAlfred Perlstein static void 999390065b1SAlfred Perlstein libusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1000390065b1SAlfred Perlstein { 1001390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1002390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1003390065b1SAlfred Perlstein uint32_t max_bulk; 1004390065b1SAlfred Perlstein uint32_t actlen; 1005390065b1SAlfred Perlstein uint8_t status; 1006390065b1SAlfred Perlstein uint8_t flags; 1007390065b1SAlfred Perlstein 1008390065b1SAlfred Perlstein status = libusb20_tr_get_status(pxfer); 1009390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer); 1010390065b1SAlfred Perlstein max_bulk = libusb20_tr_get_max_total_length(pxfer); 1011390065b1SAlfred Perlstein actlen = libusb20_tr_get_actual_length(pxfer); 1012390065b1SAlfred Perlstein 1013390065b1SAlfred Perlstein if (sxfer == NULL) 1014390065b1SAlfred Perlstein return; /* cancelled - nothing to do */ 1015390065b1SAlfred Perlstein 1016390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1017390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1018390065b1SAlfred Perlstein 1019390065b1SAlfred Perlstein flags = uxfer->flags; 1020390065b1SAlfred Perlstein 1021390065b1SAlfred Perlstein switch (status) { 1022390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_COMPLETED: 1023390065b1SAlfred Perlstein 1024390065b1SAlfred Perlstein uxfer->actual_length += actlen; 1025390065b1SAlfred Perlstein 1026390065b1SAlfred Perlstein /* subtract length of SETUP packet, if any */ 1027390065b1SAlfred Perlstein actlen -= libusb20_tr_get_length(pxfer, 0); 1028390065b1SAlfred Perlstein 1029390065b1SAlfred Perlstein /* check for short packet */ 1030390065b1SAlfred Perlstein if (sxfer->last_len != actlen) { 1031390065b1SAlfred Perlstein if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1032390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1033390065b1SAlfred Perlstein } else { 1034390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1035390065b1SAlfred Perlstein } 1036390065b1SAlfred Perlstein break; 1037390065b1SAlfred Perlstein } 1038390065b1SAlfred Perlstein /* check for end of data */ 1039390065b1SAlfred Perlstein if (sxfer->rem_len == 0) { 1040390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1041390065b1SAlfred Perlstein break; 1042390065b1SAlfred Perlstein } 1043390065b1SAlfred Perlstein /* FALLTHROUGH */ 1044390065b1SAlfred Perlstein 1045390065b1SAlfred Perlstein case LIBUSB20_TRANSFER_START: 1046390065b1SAlfred Perlstein if (max_bulk > sxfer->rem_len) { 1047390065b1SAlfred Perlstein max_bulk = sxfer->rem_len; 1048390065b1SAlfred Perlstein } 1049390065b1SAlfred Perlstein /* setup new CONTROL transaction */ 1050390065b1SAlfred Perlstein if (status == LIBUSB20_TRANSFER_COMPLETED) { 1051390065b1SAlfred Perlstein /* next fragment - don't send SETUP packet */ 1052390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 0, 0); 1053390065b1SAlfred Perlstein } else { 1054390065b1SAlfred Perlstein /* first fragment - send SETUP packet */ 1055390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, 8, 0); 1056390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1057390065b1SAlfred Perlstein } 1058390065b1SAlfred Perlstein 1059390065b1SAlfred Perlstein if (max_bulk != 0) { 1060390065b1SAlfred Perlstein libusb20_tr_set_length(pxfer, max_bulk, 1); 1061390065b1SAlfred Perlstein libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1062390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 2); 1063390065b1SAlfred Perlstein } else { 1064390065b1SAlfred Perlstein libusb20_tr_set_total_frames(pxfer, 1); 1065390065b1SAlfred Perlstein } 1066390065b1SAlfred Perlstein 1067390065b1SAlfred Perlstein /* update counters */ 1068390065b1SAlfred Perlstein sxfer->last_len = max_bulk; 1069390065b1SAlfred Perlstein sxfer->curr_data += max_bulk; 1070390065b1SAlfred Perlstein sxfer->rem_len -= max_bulk; 1071390065b1SAlfred Perlstein 1072390065b1SAlfred Perlstein libusb20_tr_submit(pxfer); 1073390065b1SAlfred Perlstein 1074390065b1SAlfred Perlstein /* check if we can fork another USB transfer */ 1075390065b1SAlfred Perlstein if (sxfer->rem_len == 0) 1076390065b1SAlfred Perlstein libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1077390065b1SAlfred Perlstein break; 1078390065b1SAlfred Perlstein 1079390065b1SAlfred Perlstein default: 1080390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1081390065b1SAlfred Perlstein break; 1082390065b1SAlfred Perlstein } 1083390065b1SAlfred Perlstein } 1084390065b1SAlfred Perlstein 1085390065b1SAlfred Perlstein /* The following function must be called locked */ 1086390065b1SAlfred Perlstein 1087390065b1SAlfred Perlstein static void 1088390065b1SAlfred Perlstein libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1089390065b1SAlfred Perlstein { 1090390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1091390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1092390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1093390065b1SAlfred Perlstein struct libusb_transfer *uxfer; 1094390065b1SAlfred Perlstein struct libusb_device *dev; 1095390065b1SAlfred Perlstein int err; 1096390065b1SAlfred Perlstein int buffsize; 1097390065b1SAlfred Perlstein int maxframe; 1098390065b1SAlfred Perlstein int temp; 1099390065b1SAlfred Perlstein uint8_t dummy; 1100390065b1SAlfred Perlstein 1101390065b1SAlfred Perlstein dev = libusb_get_device(pdev); 1102390065b1SAlfred Perlstein 1103390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1104390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1105390065b1SAlfred Perlstein 1106390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) 1107390065b1SAlfred Perlstein return; /* shouldn't happen */ 1108390065b1SAlfred Perlstein 1109390065b1SAlfred Perlstein temp = 0; 1110390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer0)) 1111390065b1SAlfred Perlstein temp |= 1; 1112390065b1SAlfred Perlstein if (libusb20_tr_pending(pxfer1)) 1113390065b1SAlfred Perlstein temp |= 2; 1114390065b1SAlfred Perlstein 1115390065b1SAlfred Perlstein switch (temp) { 1116390065b1SAlfred Perlstein case 3: 1117390065b1SAlfred Perlstein /* wait till one of the transfers complete */ 1118390065b1SAlfred Perlstein return; 1119390065b1SAlfred Perlstein case 2: 1120390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer1); 11214594d907SAndrew Thompson if (sxfer == NULL) 11224594d907SAndrew Thompson return; /* cancelling */ 1123390065b1SAlfred Perlstein if (sxfer->rem_len) 1124390065b1SAlfred Perlstein return; /* cannot queue another one */ 1125390065b1SAlfred Perlstein /* swap transfers */ 1126390065b1SAlfred Perlstein pxfer1 = pxfer0; 1127390065b1SAlfred Perlstein break; 1128390065b1SAlfred Perlstein case 1: 1129390065b1SAlfred Perlstein sxfer = libusb20_tr_get_priv_sc1(pxfer0); 11304594d907SAndrew Thompson if (sxfer == NULL) 11314594d907SAndrew Thompson return; /* cancelling */ 1132390065b1SAlfred Perlstein if (sxfer->rem_len) 1133390065b1SAlfred Perlstein return; /* cannot queue another one */ 1134390065b1SAlfred Perlstein /* swap transfers */ 1135390065b1SAlfred Perlstein pxfer0 = pxfer1; 1136c500e4ddSAndrew Thompson break; 1137c500e4ddSAndrew Thompson default: 1138c500e4ddSAndrew Thompson break; 1139c500e4ddSAndrew Thompson } 1140c500e4ddSAndrew Thompson 1141390065b1SAlfred Perlstein /* find next transfer on same endpoint */ 1142390065b1SAlfred Perlstein TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1143390065b1SAlfred Perlstein 1144390065b1SAlfred Perlstein uxfer = (struct libusb_transfer *)( 1145390065b1SAlfred Perlstein ((uint8_t *)sxfer) + sizeof(*sxfer)); 1146390065b1SAlfred Perlstein 1147390065b1SAlfred Perlstein if (uxfer->endpoint == endpoint) { 1148390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1149390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 1150390065b1SAlfred Perlstein goto found; 1151c500e4ddSAndrew Thompson } 1152c500e4ddSAndrew Thompson } 1153390065b1SAlfred Perlstein return; /* success */ 1154390065b1SAlfred Perlstein 1155390065b1SAlfred Perlstein found: 1156390065b1SAlfred Perlstein 1157390065b1SAlfred Perlstein libusb20_tr_set_priv_sc0(pxfer0, pdev); 1158390065b1SAlfred Perlstein libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1159390065b1SAlfred Perlstein 1160390065b1SAlfred Perlstein /* reset super transfer state */ 1161390065b1SAlfred Perlstein sxfer->rem_len = uxfer->length; 1162390065b1SAlfred Perlstein sxfer->curr_data = uxfer->buffer; 1163390065b1SAlfred Perlstein uxfer->actual_length = 0; 1164390065b1SAlfred Perlstein 1165390065b1SAlfred Perlstein switch (uxfer->type) { 1166390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1167390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1168390065b1SAlfred Perlstein break; 1169390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_BULK: 1170390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1171390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1172390065b1SAlfred Perlstein break; 1173390065b1SAlfred Perlstein case LIBUSB_TRANSFER_TYPE_CONTROL: 1174390065b1SAlfred Perlstein libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1175390065b1SAlfred Perlstein if (sxfer->rem_len < 8) 1176390065b1SAlfred Perlstein goto failure; 1177390065b1SAlfred Perlstein 1178390065b1SAlfred Perlstein /* remove SETUP packet from data */ 1179390065b1SAlfred Perlstein sxfer->rem_len -= 8; 1180390065b1SAlfred Perlstein sxfer->curr_data += 8; 1181390065b1SAlfred Perlstein break; 1182390065b1SAlfred Perlstein default: 1183390065b1SAlfred Perlstein goto failure; 1184390065b1SAlfred Perlstein } 1185390065b1SAlfred Perlstein 1186390065b1SAlfred Perlstein buffsize = libusb10_get_buffsize(pdev, uxfer); 1187390065b1SAlfred Perlstein maxframe = libusb10_get_maxframe(pdev, uxfer); 1188390065b1SAlfred Perlstein 1189390065b1SAlfred Perlstein /* make sure the transfer is opened */ 1190390065b1SAlfred Perlstein err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1191390065b1SAlfred Perlstein if (err && (err != LIBUSB20_ERROR_BUSY)) { 1192390065b1SAlfred Perlstein goto failure; 1193390065b1SAlfred Perlstein } 1194390065b1SAlfred Perlstein libusb20_tr_start(pxfer0); 1195390065b1SAlfred Perlstein return; 1196390065b1SAlfred Perlstein 1197390065b1SAlfred Perlstein failure: 1198390065b1SAlfred Perlstein libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1199390065b1SAlfred Perlstein 1200390065b1SAlfred Perlstein /* make sure our event loop spins the done handler */ 1201390065b1SAlfred Perlstein dummy = 0; 1202390065b1SAlfred Perlstein write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1203390065b1SAlfred Perlstein } 1204390065b1SAlfred Perlstein 1205390065b1SAlfred Perlstein /* The following function must be called unlocked */ 1206c500e4ddSAndrew Thompson 12078c8fff31SAndrew Thompson int 1208390065b1SAlfred Perlstein libusb_submit_transfer(struct libusb_transfer *uxfer) 12098c8fff31SAndrew Thompson { 1210390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1211390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1212390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1213390065b1SAlfred Perlstein struct libusb_device *dev; 1214ccef4ddfSAndrew Thompson uint32_t endpoint; 1215390065b1SAlfred Perlstein int err; 12168c8fff31SAndrew Thompson 1217390065b1SAlfred Perlstein if (uxfer == NULL) 1218390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 12198c8fff31SAndrew Thompson 1220390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 1221390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 12228c8fff31SAndrew Thompson 1223390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 12248c8fff31SAndrew Thompson 1225390065b1SAlfred Perlstein if (endpoint > 255) 1226390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 12278c8fff31SAndrew Thompson 1228390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 12298c8fff31SAndrew Thompson 1230390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 12318c8fff31SAndrew Thompson 1232390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1233390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1234390065b1SAlfred Perlstein 1235390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1236390065b1SAlfred Perlstein 1237390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1238390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1239390065b1SAlfred Perlstein 1240390065b1SAlfred Perlstein if (pxfer0 == NULL || pxfer1 == NULL) { 1241390065b1SAlfred Perlstein err = LIBUSB_ERROR_OTHER; 1242390065b1SAlfred Perlstein } else if ((sxfer->entry.tqe_prev != NULL) || 1243390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1244390065b1SAlfred Perlstein (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1245390065b1SAlfred Perlstein err = LIBUSB_ERROR_BUSY; 1246390065b1SAlfred Perlstein } else { 12474594d907SAndrew Thompson 12484594d907SAndrew Thompson /* set pending state */ 12494594d907SAndrew Thompson sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 12504594d907SAndrew Thompson 12514594d907SAndrew Thompson /* insert transfer into transfer head list */ 1252390065b1SAlfred Perlstein TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1253390065b1SAlfred Perlstein 12544594d907SAndrew Thompson /* start work transfers */ 1255390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1256390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1257390065b1SAlfred Perlstein 1258390065b1SAlfred Perlstein err = 0; /* success */ 12598c8fff31SAndrew Thompson } 12608c8fff31SAndrew Thompson 1261390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 1262390065b1SAlfred Perlstein 1263390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1264390065b1SAlfred Perlstein 1265390065b1SAlfred Perlstein return (err); 12668c8fff31SAndrew Thompson } 12678c8fff31SAndrew Thompson 1268390065b1SAlfred Perlstein /* Asynchronous transfer cancel */ 12698c8fff31SAndrew Thompson 1270390065b1SAlfred Perlstein int 1271390065b1SAlfred Perlstein libusb_cancel_transfer(struct libusb_transfer *uxfer) 1272390065b1SAlfred Perlstein { 1273390065b1SAlfred Perlstein struct libusb20_transfer *pxfer0; 1274390065b1SAlfred Perlstein struct libusb20_transfer *pxfer1; 1275390065b1SAlfred Perlstein struct libusb_super_transfer *sxfer; 1276390065b1SAlfred Perlstein struct libusb_device *dev; 1277ccef4ddfSAndrew Thompson uint32_t endpoint; 12784594d907SAndrew Thompson int retval; 12798c8fff31SAndrew Thompson 1280390065b1SAlfred Perlstein if (uxfer == NULL) 1281390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 12828c8fff31SAndrew Thompson 12834594d907SAndrew Thompson /* check if not initialised */ 1284390065b1SAlfred Perlstein if (uxfer->dev_handle == NULL) 12854594d907SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 12868c8fff31SAndrew Thompson 1287390065b1SAlfred Perlstein endpoint = uxfer->endpoint; 12888c8fff31SAndrew Thompson 1289390065b1SAlfred Perlstein if (endpoint > 255) 1290390065b1SAlfred Perlstein return (LIBUSB_ERROR_INVALID_PARAM); 12918c8fff31SAndrew Thompson 1292390065b1SAlfred Perlstein dev = libusb_get_device(uxfer->dev_handle); 12938c8fff31SAndrew Thompson 1294390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 12958c8fff31SAndrew Thompson 1296390065b1SAlfred Perlstein sxfer = (struct libusb_super_transfer *)( 1297390065b1SAlfred Perlstein (uint8_t *)uxfer - sizeof(*sxfer)); 1298390065b1SAlfred Perlstein 12994594d907SAndrew Thompson retval = 0; 13004594d907SAndrew Thompson 1301390065b1SAlfred Perlstein CTX_LOCK(dev->ctx); 1302390065b1SAlfred Perlstein 1303390065b1SAlfred Perlstein pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1304390065b1SAlfred Perlstein pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1305390065b1SAlfred Perlstein 13064594d907SAndrew Thompson if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 13074594d907SAndrew Thompson /* only update the transfer status */ 13084594d907SAndrew Thompson uxfer->status = LIBUSB_TRANSFER_CANCELLED; 13094594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 13104594d907SAndrew Thompson } else if (sxfer->entry.tqe_prev != NULL) { 1311390065b1SAlfred Perlstein /* we are lucky - transfer is on a queue */ 1312390065b1SAlfred Perlstein TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1313390065b1SAlfred Perlstein sxfer->entry.tqe_prev = NULL; 13144594d907SAndrew Thompson libusb10_complete_transfer(NULL, 13154594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1316390065b1SAlfred Perlstein } else if (pxfer0 == NULL || pxfer1 == NULL) { 1317390065b1SAlfred Perlstein /* not started */ 13184594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1319390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 13204594d907SAndrew Thompson libusb10_complete_transfer(pxfer0, 13214594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1322390065b1SAlfred Perlstein libusb20_tr_stop(pxfer0); 1323390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1324390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1325390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1326390065b1SAlfred Perlstein } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 13274594d907SAndrew Thompson libusb10_complete_transfer(pxfer1, 13284594d907SAndrew Thompson sxfer, LIBUSB_TRANSFER_CANCELLED); 1329390065b1SAlfred Perlstein libusb20_tr_stop(pxfer1); 1330390065b1SAlfred Perlstein /* make sure the queue doesn't stall */ 1331390065b1SAlfred Perlstein libusb10_submit_transfer_sub( 1332390065b1SAlfred Perlstein uxfer->dev_handle, endpoint); 1333390065b1SAlfred Perlstein } else { 1334390065b1SAlfred Perlstein /* not started */ 13354594d907SAndrew Thompson retval = LIBUSB_ERROR_NOT_FOUND; 1336c500e4ddSAndrew Thompson } 13378c8fff31SAndrew Thompson 1338390065b1SAlfred Perlstein CTX_UNLOCK(dev->ctx); 13398c8fff31SAndrew Thompson 1340390065b1SAlfred Perlstein DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 13418c8fff31SAndrew Thompson 13424594d907SAndrew Thompson return (retval); 13438c8fff31SAndrew Thompson } 13448c8fff31SAndrew Thompson 1345390065b1SAlfred Perlstein UNEXPORTED void 1346390065b1SAlfred Perlstein libusb10_cancel_all_transfer(libusb_device *dev) 13478c8fff31SAndrew Thompson { 1348390065b1SAlfred Perlstein /* TODO */ 13498c8fff31SAndrew Thompson } 1350ccef4ddfSAndrew Thompson 1351ccef4ddfSAndrew Thompson uint16_t 1352ccef4ddfSAndrew Thompson libusb_cpu_to_le16(uint16_t x) 1353ccef4ddfSAndrew Thompson { 1354ccef4ddfSAndrew Thompson return (htole16(x)); 1355ccef4ddfSAndrew Thompson } 1356ccef4ddfSAndrew Thompson 1357ccef4ddfSAndrew Thompson uint16_t 1358ccef4ddfSAndrew Thompson libusb_le16_to_cpu(uint16_t x) 1359ccef4ddfSAndrew Thompson { 1360ccef4ddfSAndrew Thompson return (le16toh(x)); 1361ccef4ddfSAndrew Thompson } 1362ccef4ddfSAndrew Thompson 1363