18c8fff31SAndrew Thompson /* $FreeBSD$ */ 28c8fff31SAndrew Thompson /*- 38c8fff31SAndrew Thompson * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 48c8fff31SAndrew Thompson * 58c8fff31SAndrew Thompson * Redistribution and use in source and binary forms, with or without 68c8fff31SAndrew Thompson * modification, are permitted provided that the following conditions 78c8fff31SAndrew Thompson * are met: 88c8fff31SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 98c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer. 108c8fff31SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 118c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 128c8fff31SAndrew Thompson * documentation and/or other materials provided with the distribution. 138c8fff31SAndrew Thompson * 148c8fff31SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158c8fff31SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168c8fff31SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178c8fff31SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188c8fff31SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198c8fff31SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208c8fff31SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218c8fff31SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228c8fff31SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238c8fff31SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248c8fff31SAndrew Thompson * SUCH DAMAGE. 258c8fff31SAndrew Thompson */ 268c8fff31SAndrew Thompson 278c8fff31SAndrew Thompson #include <sys/queue.h> 288c8fff31SAndrew Thompson #include <stdlib.h> 298c8fff31SAndrew Thompson #include <unistd.h> 308c8fff31SAndrew Thompson #include <stdio.h> 318c8fff31SAndrew Thompson #include <poll.h> 328c8fff31SAndrew Thompson #include <pthread.h> 338c8fff31SAndrew Thompson #include <time.h> 348c8fff31SAndrew Thompson #include <errno.h> 358c8fff31SAndrew Thompson 368c8fff31SAndrew Thompson #include "libusb20.h" 378c8fff31SAndrew Thompson #include "libusb20_desc.h" 388c8fff31SAndrew Thompson #include "libusb20_int.h" 398c8fff31SAndrew Thompson #include "libusb.h" 408c8fff31SAndrew Thompson #include "libusb10.h" 418c8fff31SAndrew Thompson 428c8fff31SAndrew Thompson static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 438c8fff31SAndrew Thompson struct libusb_context *usbi_default_context = NULL; 448c8fff31SAndrew Thompson pthread_mutex_t libusb20_lock = PTHREAD_MUTEX_INITIALIZER; 458c8fff31SAndrew Thompson 468c8fff31SAndrew Thompson /* Library initialisation / deinitialisation */ 478c8fff31SAndrew Thompson 488c8fff31SAndrew Thompson void 498c8fff31SAndrew Thompson libusb_set_debug(libusb_context * ctx, int level) 508c8fff31SAndrew Thompson { 518c8fff31SAndrew Thompson GET_CONTEXT(ctx); 528c8fff31SAndrew Thompson if (ctx) 538c8fff31SAndrew Thompson ctx->debug = level; 548c8fff31SAndrew Thompson } 558c8fff31SAndrew Thompson 568c8fff31SAndrew Thompson int 578c8fff31SAndrew Thompson libusb_init(libusb_context ** context) 588c8fff31SAndrew Thompson { 598c8fff31SAndrew Thompson struct libusb_context *ctx; 608c8fff31SAndrew Thompson char * debug; 618c8fff31SAndrew Thompson int ret; 628c8fff31SAndrew Thompson 638c8fff31SAndrew Thompson ctx = malloc(sizeof(*ctx)); 648c8fff31SAndrew Thompson if (!ctx) 658c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 668c8fff31SAndrew Thompson 678c8fff31SAndrew Thompson memset(ctx, 0, sizeof(*ctx)); 688c8fff31SAndrew Thompson 698c8fff31SAndrew Thompson debug = getenv("LIBUSB_DEBUG"); 708c8fff31SAndrew Thompson if (debug != NULL) { 718c8fff31SAndrew Thompson ctx->debug = atoi(debug); 728c8fff31SAndrew Thompson if (ctx->debug != 0) 738c8fff31SAndrew Thompson ctx->debug_fixed = 1; 748c8fff31SAndrew Thompson } 758c8fff31SAndrew Thompson 768c8fff31SAndrew Thompson pthread_mutex_init(&ctx->usb_devs_lock, NULL); 778c8fff31SAndrew Thompson pthread_mutex_init(&ctx->open_devs_lock, NULL); 78c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->usb_devs); 79c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->open_devs); 808c8fff31SAndrew Thompson 818c8fff31SAndrew Thompson pthread_mutex_init(&ctx->flying_transfers_lock, NULL); 828c8fff31SAndrew Thompson pthread_mutex_init(&ctx->pollfds_lock, NULL); 838c8fff31SAndrew Thompson pthread_mutex_init(&ctx->pollfd_modify_lock, NULL); 848c8fff31SAndrew Thompson pthread_mutex_init(&ctx->events_lock, NULL); 858c8fff31SAndrew Thompson pthread_mutex_init(&ctx->event_waiters_lock, NULL); 868c8fff31SAndrew Thompson pthread_cond_init(&ctx->event_waiters_cond, NULL); 878c8fff31SAndrew Thompson 88c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->flying_transfers); 89c500e4ddSAndrew Thompson TAILQ_INIT(&ctx->pollfds); 908c8fff31SAndrew Thompson 918c8fff31SAndrew Thompson ret = pipe(ctx->ctrl_pipe); 928c8fff31SAndrew Thompson if (ret < 0) { 938c8fff31SAndrew Thompson usb_remove_pollfd(ctx, ctx->ctrl_pipe[0]); 948c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 958c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 968c8fff31SAndrew Thompson free(ctx); 978c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 988c8fff31SAndrew Thompson } 998c8fff31SAndrew Thompson 1008c8fff31SAndrew Thompson ret = usb_add_pollfd(ctx, ctx->ctrl_pipe[0], POLLIN); 1018c8fff31SAndrew Thompson if (ret < 0) { 1028c8fff31SAndrew Thompson usb_remove_pollfd(ctx, ctx->ctrl_pipe[0]); 1038c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 1048c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 1058c8fff31SAndrew Thompson free(ctx); 1068c8fff31SAndrew Thompson return ret; 1078c8fff31SAndrew Thompson } 1088c8fff31SAndrew Thompson 1098c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 1108c8fff31SAndrew Thompson if (usbi_default_context == NULL) { 1118c8fff31SAndrew Thompson usbi_default_context = ctx; 1128c8fff31SAndrew Thompson } 1138c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 1148c8fff31SAndrew Thompson 1158c8fff31SAndrew Thompson if (context) 1168c8fff31SAndrew Thompson *context = ctx; 1178c8fff31SAndrew Thompson 1188c8fff31SAndrew Thompson return (0); 1198c8fff31SAndrew Thompson } 1208c8fff31SAndrew Thompson 1218c8fff31SAndrew Thompson void 1228c8fff31SAndrew Thompson libusb_exit(libusb_context * ctx) 1238c8fff31SAndrew Thompson { 1248c8fff31SAndrew Thompson GET_CONTEXT(ctx); 1258c8fff31SAndrew Thompson 126c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_exit enter"); 1278c8fff31SAndrew Thompson usb_remove_pollfd(ctx, ctx->ctrl_pipe[0]); 1288c8fff31SAndrew Thompson close(ctx->ctrl_pipe[0]); 1298c8fff31SAndrew Thompson close(ctx->ctrl_pipe[1]); 1308c8fff31SAndrew Thompson 1318c8fff31SAndrew Thompson pthread_mutex_lock(&default_context_lock); 1328c8fff31SAndrew Thompson if (ctx == usbi_default_context) { 1338c8fff31SAndrew Thompson usbi_default_context = NULL; 1348c8fff31SAndrew Thompson } 1358c8fff31SAndrew Thompson pthread_mutex_unlock(&default_context_lock); 1368c8fff31SAndrew Thompson 1378c8fff31SAndrew Thompson free(ctx); 138c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_exit leave"); 1398c8fff31SAndrew Thompson } 1408c8fff31SAndrew Thompson 1418c8fff31SAndrew Thompson /* Device handling and initialisation. */ 1428c8fff31SAndrew Thompson 1438c8fff31SAndrew Thompson ssize_t 1448c8fff31SAndrew Thompson libusb_get_device_list(libusb_context * ctx, libusb_device *** list) 1458c8fff31SAndrew Thompson { 1468c8fff31SAndrew Thompson struct libusb20_device *pdev; 1478c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 1488c8fff31SAndrew Thompson struct libusb_device *dev; 1498c8fff31SAndrew Thompson struct libusb20_backend *usb_backend; 1508c8fff31SAndrew Thompson int i; 1518c8fff31SAndrew Thompson 1528c8fff31SAndrew Thompson GET_CONTEXT(ctx); 153c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_list enter"); 1548c8fff31SAndrew Thompson 1558c8fff31SAndrew Thompson usb_backend = libusb20_be_alloc_default(); 1568c8fff31SAndrew Thompson if (usb_backend == NULL) 1578c8fff31SAndrew Thompson return (-1); 1588c8fff31SAndrew Thompson 1598c8fff31SAndrew Thompson pdev = NULL; 1608c8fff31SAndrew Thompson i = 0; 1618c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 1628c8fff31SAndrew Thompson i++; 1638c8fff31SAndrew Thompson 1648c8fff31SAndrew Thompson if (list == NULL) { 1658c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 1668c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1678c8fff31SAndrew Thompson } 1688c8fff31SAndrew Thompson *list = malloc((i + 1) * sizeof(void *)); 1698c8fff31SAndrew Thompson if (*list == NULL) { 1708c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 1718c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1728c8fff31SAndrew Thompson } 1738c8fff31SAndrew Thompson i = 0; 1748c8fff31SAndrew Thompson while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 1758c8fff31SAndrew Thompson /* get device into libUSB v1.0 list */ 1768c8fff31SAndrew Thompson libusb20_be_dequeue_device(usb_backend, pdev); 1778c8fff31SAndrew Thompson 1788c8fff31SAndrew Thompson ddesc = libusb20_dev_get_device_desc(pdev); 1798c8fff31SAndrew Thompson dev = malloc(sizeof(*dev)); 1808c8fff31SAndrew Thompson if (dev == NULL) { 181c500e4ddSAndrew Thompson while (i != 0) { 182c500e4ddSAndrew Thompson libusb_unref_device((*list)[i - 1]); 183c500e4ddSAndrew Thompson i--; 184c500e4ddSAndrew Thompson } 1858c8fff31SAndrew Thompson free(*list); 1868c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 1878c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1888c8fff31SAndrew Thompson } 1898c8fff31SAndrew Thompson memset(dev, 0, sizeof(*dev)); 1908c8fff31SAndrew Thompson 1918c8fff31SAndrew Thompson pthread_mutex_init(&dev->lock, NULL); 1928c8fff31SAndrew Thompson dev->ctx = ctx; 1938c8fff31SAndrew Thompson dev->bus_number = pdev->bus_number; 1948c8fff31SAndrew Thompson dev->device_address = pdev->device_address; 1958c8fff31SAndrew Thompson dev->num_configurations = ddesc->bNumConfigurations; 1968c8fff31SAndrew Thompson 1978c8fff31SAndrew Thompson /* link together the two structures */ 1988c8fff31SAndrew Thompson dev->os_priv = pdev; 1998c8fff31SAndrew Thompson 2008c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->usb_devs_lock); 201c500e4ddSAndrew Thompson TAILQ_INSERT_HEAD(&ctx->usb_devs, dev, list); 2028c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->usb_devs_lock); 2038c8fff31SAndrew Thompson 2048c8fff31SAndrew Thompson (*list)[i] = libusb_ref_device(dev); 2058c8fff31SAndrew Thompson i++; 2068c8fff31SAndrew Thompson } 2078c8fff31SAndrew Thompson (*list)[i] = NULL; 2088c8fff31SAndrew Thompson 2098c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 210c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_list leave"); 2118c8fff31SAndrew Thompson return (i); 2128c8fff31SAndrew Thompson } 2138c8fff31SAndrew Thompson 2148c8fff31SAndrew Thompson /* 2158c8fff31SAndrew Thompson * In this function we cant free all the device contained into list because 2168c8fff31SAndrew Thompson * open_with_pid_vid use some node of list after the free_device_list. 2178c8fff31SAndrew Thompson */ 2188c8fff31SAndrew Thompson void 2198c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices) 2208c8fff31SAndrew Thompson { 2218c8fff31SAndrew Thompson int i; 2228c8fff31SAndrew Thompson libusb_context *ctx; 2238c8fff31SAndrew Thompson 2248c8fff31SAndrew Thompson ctx = NULL; 2258c8fff31SAndrew Thompson GET_CONTEXT(ctx); 226c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_device_list enter"); 2278c8fff31SAndrew Thompson 2288c8fff31SAndrew Thompson if (list == NULL) 2298c8fff31SAndrew Thompson return ; 2308c8fff31SAndrew Thompson 2318c8fff31SAndrew Thompson if (unref_devices) { 2328c8fff31SAndrew Thompson for (i = 0; list[i] != NULL; i++) 2338c8fff31SAndrew Thompson libusb_unref_device(list[i]); 2348c8fff31SAndrew Thompson } 2358c8fff31SAndrew Thompson free(list); 236c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_device_list leave"); 2378c8fff31SAndrew Thompson } 2388c8fff31SAndrew Thompson 2398c8fff31SAndrew Thompson uint8_t 2408c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device * dev) 2418c8fff31SAndrew Thompson { 2428c8fff31SAndrew Thompson libusb_context *ctx; 2438c8fff31SAndrew Thompson 2448c8fff31SAndrew Thompson ctx = NULL; 2458c8fff31SAndrew Thompson GET_CONTEXT(ctx); 246c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_bus_number enter"); 2478c8fff31SAndrew Thompson 2488c8fff31SAndrew Thompson if (dev == NULL) 2498c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 250c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_bus_number leave"); 2518c8fff31SAndrew Thompson return (dev->bus_number); 2528c8fff31SAndrew Thompson } 2538c8fff31SAndrew Thompson 2548c8fff31SAndrew Thompson uint8_t 2558c8fff31SAndrew Thompson libusb_get_device_address(libusb_device * dev) 2568c8fff31SAndrew Thompson { 2578c8fff31SAndrew Thompson libusb_context *ctx; 2588c8fff31SAndrew Thompson 2598c8fff31SAndrew Thompson ctx = NULL; 2608c8fff31SAndrew Thompson GET_CONTEXT(ctx); 261c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_address enter"); 2628c8fff31SAndrew Thompson 2638c8fff31SAndrew Thompson if (dev == NULL) 2648c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 265c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_address leave"); 2668c8fff31SAndrew Thompson return (dev->device_address); 2678c8fff31SAndrew Thompson } 2688c8fff31SAndrew Thompson 2698c8fff31SAndrew Thompson int 2708c8fff31SAndrew Thompson libusb_get_max_packet_size(libusb_device *dev, unsigned char endpoint) 2718c8fff31SAndrew Thompson { 2728c8fff31SAndrew Thompson struct libusb_config_descriptor *pdconf; 2738c8fff31SAndrew Thompson struct libusb_interface *pinf; 2748c8fff31SAndrew Thompson struct libusb_interface_descriptor *pdinf; 2758c8fff31SAndrew Thompson struct libusb_endpoint_descriptor *pdend; 2768c8fff31SAndrew Thompson libusb_context *ctx; 2778c8fff31SAndrew Thompson int i, j, k, ret; 2788c8fff31SAndrew Thompson 2798c8fff31SAndrew Thompson ctx = NULL; 2808c8fff31SAndrew Thompson GET_CONTEXT(ctx); 281c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_max_packet_size enter"); 2828c8fff31SAndrew Thompson 2838c8fff31SAndrew Thompson if (dev == NULL) 2848c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 2858c8fff31SAndrew Thompson 2868c8fff31SAndrew Thompson if (libusb_get_active_config_descriptor(dev, &pdconf) < 0) 2878c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 2888c8fff31SAndrew Thompson 2898c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 2908c8fff31SAndrew Thompson for (i = 0 ; i < pdconf->bNumInterfaces ; i++) { 2918c8fff31SAndrew Thompson pinf = &pdconf->interface[i]; 2928c8fff31SAndrew Thompson for (j = 0 ; j < pinf->num_altsetting ; j++) { 2938c8fff31SAndrew Thompson pdinf = &pinf->altsetting[j]; 2948c8fff31SAndrew Thompson for (k = 0 ; k < pdinf->bNumEndpoints ; k++) { 2958c8fff31SAndrew Thompson pdend = &pdinf->endpoint[k]; 2968c8fff31SAndrew Thompson if (pdend->bEndpointAddress == endpoint) { 2978c8fff31SAndrew Thompson ret = pdend->wMaxPacketSize; 2988c8fff31SAndrew Thompson goto out; 2998c8fff31SAndrew Thompson } 3008c8fff31SAndrew Thompson } 3018c8fff31SAndrew Thompson } 3028c8fff31SAndrew Thompson } 3038c8fff31SAndrew Thompson 3048c8fff31SAndrew Thompson out: 3058c8fff31SAndrew Thompson libusb_free_config_descriptor(pdconf); 306c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_max_packet_size leave"); 3078c8fff31SAndrew Thompson return (ret); 3088c8fff31SAndrew Thompson } 3098c8fff31SAndrew Thompson 3108c8fff31SAndrew Thompson libusb_device * 3118c8fff31SAndrew Thompson libusb_ref_device(libusb_device * dev) 3128c8fff31SAndrew Thompson { 3138c8fff31SAndrew Thompson libusb_context *ctx; 3148c8fff31SAndrew Thompson 3158c8fff31SAndrew Thompson ctx = NULL; 3168c8fff31SAndrew Thompson GET_CONTEXT(ctx); 317c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_ref_device enter"); 3188c8fff31SAndrew Thompson 3198c8fff31SAndrew Thompson if (dev == NULL) 3208c8fff31SAndrew Thompson return (NULL); 3218c8fff31SAndrew Thompson 3228c8fff31SAndrew Thompson pthread_mutex_lock(&dev->lock); 3238c8fff31SAndrew Thompson dev->refcnt++; 3248c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 3258c8fff31SAndrew Thompson 326c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_ref_device leave"); 3278c8fff31SAndrew Thompson return (dev); 3288c8fff31SAndrew Thompson } 3298c8fff31SAndrew Thompson 3308c8fff31SAndrew Thompson void 3318c8fff31SAndrew Thompson libusb_unref_device(libusb_device * dev) 3328c8fff31SAndrew Thompson { 3338c8fff31SAndrew Thompson libusb_context *ctx; 3348c8fff31SAndrew Thompson 3358c8fff31SAndrew Thompson ctx = NULL; 3368c8fff31SAndrew Thompson GET_CONTEXT(ctx); 337c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unref_device enter"); 3388c8fff31SAndrew Thompson 3398c8fff31SAndrew Thompson if (dev == NULL) 3408c8fff31SAndrew Thompson return; 3418c8fff31SAndrew Thompson 3428c8fff31SAndrew Thompson pthread_mutex_lock(&dev->lock); 3438c8fff31SAndrew Thompson dev->refcnt--; 3448c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 3458c8fff31SAndrew Thompson 3468c8fff31SAndrew Thompson if (dev->refcnt == 0) { 3478c8fff31SAndrew Thompson pthread_mutex_lock(&dev->ctx->usb_devs_lock); 348c500e4ddSAndrew Thompson TAILQ_REMOVE(&ctx->usb_devs, dev, list); 3498c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->ctx->usb_devs_lock); 3508c8fff31SAndrew Thompson 3518c8fff31SAndrew Thompson libusb20_dev_free(dev->os_priv); 3528c8fff31SAndrew Thompson free(dev); 3538c8fff31SAndrew Thompson } 354c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unref_device leave"); 3558c8fff31SAndrew Thompson } 3568c8fff31SAndrew Thompson 3578c8fff31SAndrew Thompson int 3588c8fff31SAndrew Thompson libusb_open(libusb_device * dev, libusb_device_handle **devh) 3598c8fff31SAndrew Thompson { 3608c8fff31SAndrew Thompson libusb_context *ctx = dev->ctx; 3618c8fff31SAndrew Thompson struct libusb20_device *pdev = dev->os_priv; 3628c8fff31SAndrew Thompson libusb_device_handle *hdl; 3638c8fff31SAndrew Thompson unsigned char dummy; 3648c8fff31SAndrew Thompson int err; 3658c8fff31SAndrew Thompson 3668c8fff31SAndrew Thompson GET_CONTEXT(ctx); 367c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open enter"); 3688c8fff31SAndrew Thompson 3698c8fff31SAndrew Thompson dummy = 1; 3708c8fff31SAndrew Thompson if (devh == NULL) 3718c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 3728c8fff31SAndrew Thompson 3738c8fff31SAndrew Thompson hdl = malloc(sizeof(*hdl)); 3748c8fff31SAndrew Thompson if (hdl == NULL) 3758c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3768c8fff31SAndrew Thompson 3778c8fff31SAndrew Thompson err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 3788c8fff31SAndrew Thompson if (err) { 3798c8fff31SAndrew Thompson free(hdl); 3808c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3818c8fff31SAndrew Thompson } 3828c8fff31SAndrew Thompson memset(hdl, 0, sizeof(*hdl)); 3838c8fff31SAndrew Thompson pthread_mutex_init(&hdl->lock, NULL); 3848c8fff31SAndrew Thompson 385c500e4ddSAndrew Thompson TAILQ_INIT(&hdl->ep_list); 3868c8fff31SAndrew Thompson hdl->dev = libusb_ref_device(dev); 3878c8fff31SAndrew Thompson hdl->claimed_interfaces = 0; 3888c8fff31SAndrew Thompson hdl->os_priv = dev->os_priv; 3898c8fff31SAndrew Thompson err = usb_add_pollfd(ctx, libusb20_dev_get_fd(pdev), POLLIN | 3908c8fff31SAndrew Thompson POLLOUT | POLLRDNORM | POLLWRNORM); 3918c8fff31SAndrew Thompson if (err < 0) { 3928c8fff31SAndrew Thompson libusb_unref_device(dev); 3938c8fff31SAndrew Thompson free(hdl); 3948c8fff31SAndrew Thompson return (err); 3958c8fff31SAndrew Thompson } 3968c8fff31SAndrew Thompson 3978c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->open_devs_lock); 398c500e4ddSAndrew Thompson TAILQ_INSERT_HEAD(&ctx->open_devs, hdl, list); 3998c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->open_devs_lock); 4008c8fff31SAndrew Thompson 4018c8fff31SAndrew Thompson *devh = hdl; 4028c8fff31SAndrew Thompson 4038c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4048c8fff31SAndrew Thompson ctx->pollfd_modify++; 4058c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4068c8fff31SAndrew Thompson 4078c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 4088c8fff31SAndrew Thompson if (err <= 0) { 4098c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4108c8fff31SAndrew Thompson ctx->pollfd_modify--; 4118c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4128c8fff31SAndrew Thompson return 0; 4138c8fff31SAndrew Thompson } 4148c8fff31SAndrew Thompson 4158c8fff31SAndrew Thompson libusb_lock_events(ctx); 4168c8fff31SAndrew Thompson read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); 4178c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4188c8fff31SAndrew Thompson ctx->pollfd_modify--; 4198c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4208c8fff31SAndrew Thompson libusb_unlock_events(ctx); 4218c8fff31SAndrew Thompson 422c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open leave"); 4238c8fff31SAndrew Thompson return (0); 4248c8fff31SAndrew Thompson } 4258c8fff31SAndrew Thompson 4268c8fff31SAndrew Thompson libusb_device_handle * 4278c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context * ctx, uint16_t vendor_id, 4288c8fff31SAndrew Thompson uint16_t product_id) 4298c8fff31SAndrew Thompson { 4308c8fff31SAndrew Thompson struct libusb_device **devs; 4318c8fff31SAndrew Thompson struct libusb_device_handle *devh; 4328c8fff31SAndrew Thompson struct libusb20_device *pdev; 4338c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 4348c8fff31SAndrew Thompson int i, j; 4358c8fff31SAndrew Thompson 4368c8fff31SAndrew Thompson GET_CONTEXT(ctx); 437c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 4388c8fff31SAndrew Thompson 4398c8fff31SAndrew Thompson devh = NULL; 4408c8fff31SAndrew Thompson 4418c8fff31SAndrew Thompson if ((i = libusb_get_device_list(ctx, &devs)) < 0) 4428c8fff31SAndrew Thompson return (NULL); 4438c8fff31SAndrew Thompson 4448c8fff31SAndrew Thompson for (j = 0; j < i; j++) { 4458c8fff31SAndrew Thompson pdev = (struct libusb20_device *)devs[j]->os_priv; 4468c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 4478c8fff31SAndrew Thompson if (pdesc->idVendor == vendor_id && 448c500e4ddSAndrew Thompson pdesc->idProduct == product_id) { 4498c8fff31SAndrew Thompson if (libusb_open(devs[j], &devh) < 0) 4508c8fff31SAndrew Thompson devh = NULL; 451c500e4ddSAndrew Thompson break ; 452c500e4ddSAndrew Thompson } 4538c8fff31SAndrew Thompson } 4548c8fff31SAndrew Thompson 4558c8fff31SAndrew Thompson libusb_free_device_list(devs, 1); 456c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 4578c8fff31SAndrew Thompson return (devh); 4588c8fff31SAndrew Thompson } 4598c8fff31SAndrew Thompson 4608c8fff31SAndrew Thompson void 4618c8fff31SAndrew Thompson libusb_close(libusb_device_handle * devh) 4628c8fff31SAndrew Thompson { 4638c8fff31SAndrew Thompson libusb_context *ctx; 4648c8fff31SAndrew Thompson struct libusb20_device *pdev; 465c500e4ddSAndrew Thompson struct usb_ep_tr *eptr; 4668c8fff31SAndrew Thompson unsigned char dummy = 1; 4678c8fff31SAndrew Thompson int err; 4688c8fff31SAndrew Thompson 4698c8fff31SAndrew Thompson if (devh == NULL) 4708c8fff31SAndrew Thompson return ; 4718c8fff31SAndrew Thompson 4728c8fff31SAndrew Thompson ctx = devh->dev->ctx; 4738c8fff31SAndrew Thompson pdev = devh->os_priv; 4748c8fff31SAndrew Thompson 4758c8fff31SAndrew Thompson GET_CONTEXT(ctx); 476c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close enter"); 4778c8fff31SAndrew Thompson 4788c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4798c8fff31SAndrew Thompson ctx->pollfd_modify++; 4808c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4818c8fff31SAndrew Thompson 4828c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 4838c8fff31SAndrew Thompson 4848c8fff31SAndrew Thompson if (err <= 0) { 4858c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->open_devs_lock); 486c500e4ddSAndrew Thompson TAILQ_REMOVE(&ctx->open_devs, devh, list); 4878c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->open_devs_lock); 4888c8fff31SAndrew Thompson 4898c8fff31SAndrew Thompson usb_remove_pollfd(ctx, libusb20_dev_get_fd(pdev)); 4908c8fff31SAndrew Thompson libusb20_dev_close(pdev); 491c500e4ddSAndrew Thompson libusb_unref_device(devh->dev); 492c500e4ddSAndrew Thompson TAILQ_FOREACH(eptr, &devh->ep_list, list) { 493c500e4ddSAndrew Thompson TAILQ_REMOVE(&devh->ep_list, eptr, list); 494c500e4ddSAndrew Thompson libusb20_tr_close(((struct libusb20_transfer **) 495c500e4ddSAndrew Thompson eptr->os_priv)[0]); 496c500e4ddSAndrew Thompson if (eptr->flags) 497c500e4ddSAndrew Thompson libusb20_tr_close(((struct libusb20_transfer **) 498c500e4ddSAndrew Thompson eptr->os_priv)[1]); 499c500e4ddSAndrew Thompson free((struct libusb20_transfer **)eptr->os_priv); 500c500e4ddSAndrew Thompson } 5018c8fff31SAndrew Thompson free(devh); 5028c8fff31SAndrew Thompson 5038c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 5048c8fff31SAndrew Thompson ctx->pollfd_modify--; 5058c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 5068c8fff31SAndrew Thompson return ; 5078c8fff31SAndrew Thompson } 5088c8fff31SAndrew Thompson libusb_lock_events(ctx); 5098c8fff31SAndrew Thompson 5108c8fff31SAndrew Thompson read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); 5118c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->open_devs_lock); 512c500e4ddSAndrew Thompson TAILQ_REMOVE(&ctx->open_devs, devh, list); 5138c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->open_devs_lock); 5148c8fff31SAndrew Thompson 5158c8fff31SAndrew Thompson usb_remove_pollfd(ctx, libusb20_dev_get_fd(pdev)); 5168c8fff31SAndrew Thompson libusb20_dev_close(pdev); 517c500e4ddSAndrew Thompson libusb_unref_device(devh->dev); 518c500e4ddSAndrew Thompson TAILQ_FOREACH(eptr, &devh->ep_list, list) { 519c500e4ddSAndrew Thompson TAILQ_REMOVE(&devh->ep_list, eptr, list); 520c500e4ddSAndrew Thompson libusb20_tr_close(((struct libusb20_transfer **) 521c500e4ddSAndrew Thompson eptr->os_priv)[0]); 522c500e4ddSAndrew Thompson if (eptr->flags) 523c500e4ddSAndrew Thompson libusb20_tr_close(((struct libusb20_transfer **) 524c500e4ddSAndrew Thompson eptr->os_priv)[1]); 525c500e4ddSAndrew Thompson free((struct libusb20_transfer **)eptr->os_priv); 526c500e4ddSAndrew Thompson } 5278c8fff31SAndrew Thompson free(devh); 5288c8fff31SAndrew Thompson 5298c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 5308c8fff31SAndrew Thompson ctx->pollfd_modify--; 5318c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 5328c8fff31SAndrew Thompson 5338c8fff31SAndrew Thompson libusb_unlock_events(ctx); 534c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close leave"); 5358c8fff31SAndrew Thompson } 5368c8fff31SAndrew Thompson 5378c8fff31SAndrew Thompson libusb_device * 5388c8fff31SAndrew Thompson libusb_get_device(libusb_device_handle * devh) 5398c8fff31SAndrew Thompson { 5408c8fff31SAndrew Thompson libusb_context *ctx; 5418c8fff31SAndrew Thompson 5428c8fff31SAndrew Thompson ctx = NULL; 5438c8fff31SAndrew Thompson GET_CONTEXT(ctx); 544c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device enter"); 5458c8fff31SAndrew Thompson 5468c8fff31SAndrew Thompson if (devh == NULL) 5478c8fff31SAndrew Thompson return (NULL); 5488c8fff31SAndrew Thompson 549c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device leave"); 5508c8fff31SAndrew Thompson return (devh->dev); 5518c8fff31SAndrew Thompson } 5528c8fff31SAndrew Thompson 5538c8fff31SAndrew Thompson int 5548c8fff31SAndrew Thompson libusb_get_configuration(libusb_device_handle * devh, int *config) 5558c8fff31SAndrew Thompson { 5568c8fff31SAndrew Thompson libusb_context *ctx; 5578c8fff31SAndrew Thompson 5588c8fff31SAndrew Thompson ctx = NULL; 5598c8fff31SAndrew Thompson GET_CONTEXT(ctx); 560c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_configuration enter"); 5618c8fff31SAndrew Thompson 5628c8fff31SAndrew Thompson if (devh == NULL || config == NULL) 5638c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5648c8fff31SAndrew Thompson 5658c8fff31SAndrew Thompson *config = libusb20_dev_get_config_index((struct libusb20_device *) 5668c8fff31SAndrew Thompson devh->dev->os_priv); 5678c8fff31SAndrew Thompson 568c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_configuration leave"); 5698c8fff31SAndrew Thompson return (0); 5708c8fff31SAndrew Thompson } 5718c8fff31SAndrew Thompson 5728c8fff31SAndrew Thompson int 5738c8fff31SAndrew Thompson libusb_set_configuration(libusb_device_handle * devh, int configuration) 5748c8fff31SAndrew Thompson { 5758c8fff31SAndrew Thompson struct libusb20_device *pdev; 5768c8fff31SAndrew Thompson libusb_context *ctx; 5778c8fff31SAndrew Thompson 5788c8fff31SAndrew Thompson ctx = NULL; 5798c8fff31SAndrew Thompson GET_CONTEXT(ctx); 580c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_configuration enter"); 5818c8fff31SAndrew Thompson 5828c8fff31SAndrew Thompson if (devh == NULL) 5838c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5848c8fff31SAndrew Thompson 5858c8fff31SAndrew Thompson pdev = (struct libusb20_device *)devh->dev->os_priv; 5868c8fff31SAndrew Thompson 587c500e4ddSAndrew Thompson libusb20_dev_set_config_index(pdev, configuration); 588c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_configuration leave"); 5898c8fff31SAndrew Thompson return (0); 5908c8fff31SAndrew Thompson } 5918c8fff31SAndrew Thompson 5928c8fff31SAndrew Thompson int 5938c8fff31SAndrew Thompson libusb_claim_interface(libusb_device_handle * dev, int interface_number) 5948c8fff31SAndrew Thompson { 5958c8fff31SAndrew Thompson libusb_context *ctx; 5968c8fff31SAndrew Thompson int ret = 0; 5978c8fff31SAndrew Thompson 5988c8fff31SAndrew Thompson ctx = NULL; 5998c8fff31SAndrew Thompson GET_CONTEXT(ctx); 600c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_claim_interface enter"); 6018c8fff31SAndrew Thompson 6028c8fff31SAndrew Thompson if (dev == NULL) 6038c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6048c8fff31SAndrew Thompson 6058c8fff31SAndrew Thompson if (interface_number >= sizeof(dev->claimed_interfaces) * 8) 6068c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6078c8fff31SAndrew Thompson 6088c8fff31SAndrew Thompson pthread_mutex_lock(&(dev->lock)); 6098c8fff31SAndrew Thompson if (dev->claimed_interfaces & (1 << interface_number)) 6108c8fff31SAndrew Thompson ret = LIBUSB_ERROR_BUSY; 6118c8fff31SAndrew Thompson 6128c8fff31SAndrew Thompson if (!ret) 6138c8fff31SAndrew Thompson dev->claimed_interfaces |= (1 << interface_number); 6148c8fff31SAndrew Thompson pthread_mutex_unlock(&(dev->lock)); 6158c8fff31SAndrew Thompson 616c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_claim_interface leave"); 6178c8fff31SAndrew Thompson return (ret); 6188c8fff31SAndrew Thompson } 6198c8fff31SAndrew Thompson 6208c8fff31SAndrew Thompson int 6218c8fff31SAndrew Thompson libusb_release_interface(libusb_device_handle * dev, int interface_number) 6228c8fff31SAndrew Thompson { 6238c8fff31SAndrew Thompson libusb_context *ctx; 6248c8fff31SAndrew Thompson int ret; 6258c8fff31SAndrew Thompson 6268c8fff31SAndrew Thompson ctx = NULL; 6278c8fff31SAndrew Thompson GET_CONTEXT(ctx); 628c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_release_interface enter"); 6298c8fff31SAndrew Thompson 6308c8fff31SAndrew Thompson ret = 0; 6318c8fff31SAndrew Thompson if (dev == NULL) 6328c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6338c8fff31SAndrew Thompson 6348c8fff31SAndrew Thompson if (interface_number >= sizeof(dev->claimed_interfaces) * 8) 6358c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6368c8fff31SAndrew Thompson 6378c8fff31SAndrew Thompson pthread_mutex_lock(&(dev->lock)); 6388c8fff31SAndrew Thompson if (!(dev->claimed_interfaces & (1 << interface_number))) 6398c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 6408c8fff31SAndrew Thompson 6418c8fff31SAndrew Thompson if (!ret) 6428c8fff31SAndrew Thompson dev->claimed_interfaces &= ~(1 << interface_number); 6438c8fff31SAndrew Thompson pthread_mutex_unlock(&(dev->lock)); 6448c8fff31SAndrew Thompson 645c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_release_interface leave"); 6468c8fff31SAndrew Thompson return (ret); 6478c8fff31SAndrew Thompson } 6488c8fff31SAndrew Thompson 6498c8fff31SAndrew Thompson int 6508c8fff31SAndrew Thompson libusb_set_interface_alt_setting(libusb_device_handle * dev, 6518c8fff31SAndrew Thompson int interface_number, int alternate_setting) 6528c8fff31SAndrew Thompson { 6538c8fff31SAndrew Thompson libusb_context *ctx; 6548c8fff31SAndrew Thompson 6558c8fff31SAndrew Thompson ctx = NULL; 6568c8fff31SAndrew Thompson GET_CONTEXT(ctx); 657c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_interface_alt_setting enter"); 6588c8fff31SAndrew Thompson 6598c8fff31SAndrew Thompson if (dev == NULL) 6608c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6618c8fff31SAndrew Thompson 6628c8fff31SAndrew Thompson if (interface_number >= sizeof(dev->claimed_interfaces) *8) 6638c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6648c8fff31SAndrew Thompson 6658c8fff31SAndrew Thompson pthread_mutex_lock(&dev->lock); 6668c8fff31SAndrew Thompson if (!(dev->claimed_interfaces & (1 << interface_number))) { 6678c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 6688c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 6698c8fff31SAndrew Thompson } 6708c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 6718c8fff31SAndrew Thompson 6728c8fff31SAndrew Thompson if (libusb20_dev_set_alt_index(dev->os_priv, interface_number, 6738c8fff31SAndrew Thompson alternate_setting) != 0) 6748c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 6758c8fff31SAndrew Thompson 676c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_interface_alt_setting leave"); 6778c8fff31SAndrew Thompson return (0); 6788c8fff31SAndrew Thompson } 6798c8fff31SAndrew Thompson 6808c8fff31SAndrew Thompson int 6818c8fff31SAndrew Thompson libusb_clear_halt(libusb_device_handle * devh, unsigned char endpoint) 6828c8fff31SAndrew Thompson { 6838c8fff31SAndrew Thompson struct libusb20_transfer *xfer; 684c500e4ddSAndrew Thompson struct libusb20_device *pdev; 6858c8fff31SAndrew Thompson libusb_context *ctx; 6868c8fff31SAndrew Thompson int ret; 6878c8fff31SAndrew Thompson 6888c8fff31SAndrew Thompson ctx = NULL; 6898c8fff31SAndrew Thompson GET_CONTEXT(ctx); 690c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_clear_halt enter"); 6918c8fff31SAndrew Thompson 692c500e4ddSAndrew Thompson pdev = devh->os_priv; 693c500e4ddSAndrew Thompson xfer = libusb20_tr_get_pointer(pdev, 694c500e4ddSAndrew Thompson ((endpoint / 0x40) | (endpoint * 4)) % (16 * 4)); 695c500e4ddSAndrew Thompson if (xfer == NULL) 696c500e4ddSAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 6978c8fff31SAndrew Thompson 6988c8fff31SAndrew Thompson pthread_mutex_lock(&libusb20_lock); 6998c8fff31SAndrew Thompson ret = libusb20_tr_open(xfer, 0, 0, endpoint); 7008c8fff31SAndrew Thompson if (ret != 0 && ret != LIBUSB20_ERROR_BUSY) { 7018c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 7028c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 7038c8fff31SAndrew Thompson } 7048c8fff31SAndrew Thompson 7058c8fff31SAndrew Thompson libusb20_tr_clear_stall_sync(xfer); 7068c8fff31SAndrew Thompson if (ret == 0) /* check if we have open the device */ 7078c8fff31SAndrew Thompson libusb20_tr_close(xfer); 7088c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 7098c8fff31SAndrew Thompson 710c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_clear_halt leave"); 7118c8fff31SAndrew Thompson return (0); 7128c8fff31SAndrew Thompson } 7138c8fff31SAndrew Thompson 7148c8fff31SAndrew Thompson int 7158c8fff31SAndrew Thompson libusb_reset_device(libusb_device_handle * dev) 7168c8fff31SAndrew Thompson { 7178c8fff31SAndrew Thompson libusb_context *ctx; 7188c8fff31SAndrew Thompson 7198c8fff31SAndrew Thompson ctx = NULL; 7208c8fff31SAndrew Thompson GET_CONTEXT(ctx); 721c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_reset_device enter"); 7228c8fff31SAndrew Thompson 7238c8fff31SAndrew Thompson if (dev == NULL) 7248c8fff31SAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 7258c8fff31SAndrew Thompson 7268c8fff31SAndrew Thompson libusb20_dev_reset(dev->os_priv); 727c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_reset_device leave"); 7288c8fff31SAndrew Thompson return (0); 7298c8fff31SAndrew Thompson } 7308c8fff31SAndrew Thompson 7318c8fff31SAndrew Thompson int 7328c8fff31SAndrew Thompson libusb_kernel_driver_active(libusb_device_handle * devh, int interface) 7338c8fff31SAndrew Thompson { 7348c8fff31SAndrew Thompson libusb_context *ctx; 7358c8fff31SAndrew Thompson 7368c8fff31SAndrew Thompson ctx = NULL; 7378c8fff31SAndrew Thompson GET_CONTEXT(ctx); 738c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_kernel_driver_active enter"); 7398c8fff31SAndrew Thompson 7408c8fff31SAndrew Thompson if (devh == NULL) 7418c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7428c8fff31SAndrew Thompson 743c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_kernel_driver_active leave"); 7448c8fff31SAndrew Thompson return (libusb20_dev_kernel_driver_active(devh->os_priv, interface)); 7458c8fff31SAndrew Thompson } 7468c8fff31SAndrew Thompson 7478c8fff31SAndrew Thompson int 7488c8fff31SAndrew Thompson libusb_detach_kernel_driver(libusb_device_handle * devh, int interface) 7498c8fff31SAndrew Thompson { 7508c8fff31SAndrew Thompson struct libusb20_device *pdev; 7518c8fff31SAndrew Thompson libusb_context *ctx; 7528c8fff31SAndrew Thompson 7538c8fff31SAndrew Thompson ctx = NULL; 7548c8fff31SAndrew Thompson GET_CONTEXT(ctx); 755c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_detach_kernel_driver enter"); 7568c8fff31SAndrew Thompson 7578c8fff31SAndrew Thompson if (devh == NULL) 7588c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7598c8fff31SAndrew Thompson 7608c8fff31SAndrew Thompson pdev = (struct libusb20_device *)devh->dev->os_priv; 7618c8fff31SAndrew Thompson if (libusb20_dev_detach_kernel_driver(pdev, interface) == LIBUSB20_ERROR_OTHER) 7628c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 7638c8fff31SAndrew Thompson 764c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_detach_kernel_driver leave"); 7658c8fff31SAndrew Thompson return (0); 7668c8fff31SAndrew Thompson } 7678c8fff31SAndrew Thompson 7688c8fff31SAndrew Thompson /* 7698c8fff31SAndrew Thompson * stub function. 7708c8fff31SAndrew Thompson * libusb20 doesn't support this feature. 7718c8fff31SAndrew Thompson */ 7728c8fff31SAndrew Thompson int 7738c8fff31SAndrew Thompson libusb_attach_kernel_driver(libusb_device_handle * devh, int interface) 7748c8fff31SAndrew Thompson { 7758c8fff31SAndrew Thompson libusb_context *ctx; 7768c8fff31SAndrew Thompson 7778c8fff31SAndrew Thompson ctx = NULL; 7788c8fff31SAndrew Thompson GET_CONTEXT(ctx); 779c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_attach_kernel_driver enter"); 7808c8fff31SAndrew Thompson 7818c8fff31SAndrew Thompson if (devh == NULL) 7828c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7838c8fff31SAndrew Thompson 784c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_attach_kernel_driver leave"); 7858c8fff31SAndrew Thompson return (0); 7868c8fff31SAndrew Thompson } 7878c8fff31SAndrew Thompson 7888c8fff31SAndrew Thompson /* Asynchronous device I/O */ 7898c8fff31SAndrew Thompson 7908c8fff31SAndrew Thompson struct libusb_transfer * 7918c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets) 7928c8fff31SAndrew Thompson { 7938c8fff31SAndrew Thompson struct libusb_transfer *xfer; 7948c8fff31SAndrew Thompson struct usb_transfer *bxfer; 7958c8fff31SAndrew Thompson libusb_context *ctx; 7968c8fff31SAndrew Thompson int len; 7978c8fff31SAndrew Thompson 7988c8fff31SAndrew Thompson ctx = NULL; 7998c8fff31SAndrew Thompson GET_CONTEXT(ctx); 800c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_alloc_transfer enter"); 8018c8fff31SAndrew Thompson 8028c8fff31SAndrew Thompson len = sizeof(struct libusb_transfer) + 8038c8fff31SAndrew Thompson sizeof(struct usb_transfer) + 8048c8fff31SAndrew Thompson (iso_packets * sizeof(libusb_iso_packet_descriptor)); 8058c8fff31SAndrew Thompson 8068c8fff31SAndrew Thompson bxfer = malloc(len); 8078c8fff31SAndrew Thompson if (bxfer == NULL) 8088c8fff31SAndrew Thompson return (NULL); 8098c8fff31SAndrew Thompson 8108c8fff31SAndrew Thompson memset(bxfer, 0, len); 8118c8fff31SAndrew Thompson bxfer->num_iso_packets = iso_packets; 8128c8fff31SAndrew Thompson 8138c8fff31SAndrew Thompson xfer = (struct libusb_transfer *) ((uint8_t *)bxfer + 8148c8fff31SAndrew Thompson sizeof(struct usb_transfer)); 8158c8fff31SAndrew Thompson 816c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_alloc_transfer leave"); 8178c8fff31SAndrew Thompson return (xfer); 8188c8fff31SAndrew Thompson } 8198c8fff31SAndrew Thompson 8208c8fff31SAndrew Thompson void 8218c8fff31SAndrew Thompson libusb_free_transfer(struct libusb_transfer *xfer) 8228c8fff31SAndrew Thompson { 8238c8fff31SAndrew Thompson struct usb_transfer *bxfer; 8248c8fff31SAndrew Thompson libusb_context *ctx; 8258c8fff31SAndrew Thompson 8268c8fff31SAndrew Thompson ctx = NULL; 8278c8fff31SAndrew Thompson GET_CONTEXT(ctx); 828c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_transfer enter"); 8298c8fff31SAndrew Thompson 8308c8fff31SAndrew Thompson if (xfer == NULL) 8318c8fff31SAndrew Thompson return ; 8328c8fff31SAndrew Thompson 8338c8fff31SAndrew Thompson bxfer = (struct usb_transfer *) ((uint8_t *)xfer - 8348c8fff31SAndrew Thompson sizeof(struct usb_transfer)); 8358c8fff31SAndrew Thompson 8368c8fff31SAndrew Thompson free(bxfer); 837c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_transfer leave"); 8388c8fff31SAndrew Thompson return; 8398c8fff31SAndrew Thompson } 8408c8fff31SAndrew Thompson 8418c8fff31SAndrew Thompson static int 8428c8fff31SAndrew Thompson libusb_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 8438c8fff31SAndrew Thompson { 8448c8fff31SAndrew Thompson int ret; 8458c8fff31SAndrew Thompson int usb_speed; 8468c8fff31SAndrew Thompson 8478c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 8488c8fff31SAndrew Thompson 8498c8fff31SAndrew Thompson switch (xfer->type) { 8508c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 8518c8fff31SAndrew Thompson switch (usb_speed) { 8528c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 8538c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 8548c8fff31SAndrew Thompson ret = 60 * 1; 8558c8fff31SAndrew Thompson break ; 8568c8fff31SAndrew Thompson default : 8578c8fff31SAndrew Thompson ret = 60 * 8; 8588c8fff31SAndrew Thompson break ; 8598c8fff31SAndrew Thompson } 8608c8fff31SAndrew Thompson break ; 8618c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 8628c8fff31SAndrew Thompson ret = 2; 8638c8fff31SAndrew Thompson break ; 8648c8fff31SAndrew Thompson default: 8658c8fff31SAndrew Thompson ret = 1; 8668c8fff31SAndrew Thompson break ; 8678c8fff31SAndrew Thompson } 8688c8fff31SAndrew Thompson 8698c8fff31SAndrew Thompson return ret; 8708c8fff31SAndrew Thompson } 8718c8fff31SAndrew Thompson 8728c8fff31SAndrew Thompson static int 8738c8fff31SAndrew Thompson libusb_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 8748c8fff31SAndrew Thompson { 8758c8fff31SAndrew Thompson int ret; 8768c8fff31SAndrew Thompson int usb_speed; 8778c8fff31SAndrew Thompson 8788c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 8798c8fff31SAndrew Thompson 8808c8fff31SAndrew Thompson switch (xfer->type) { 8818c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 8828c8fff31SAndrew Thompson ret = 0; 8838c8fff31SAndrew Thompson break ; 8848c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 8858c8fff31SAndrew Thompson switch (usb_speed) { 8868c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 8878c8fff31SAndrew Thompson ret = 8; 8888c8fff31SAndrew Thompson break ; 8898c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 8908c8fff31SAndrew Thompson ret = 64; 8918c8fff31SAndrew Thompson break ; 892c500e4ddSAndrew Thompson default: 8938c8fff31SAndrew Thompson ret = 64; 8948c8fff31SAndrew Thompson break ; 8958c8fff31SAndrew Thompson } 8968c8fff31SAndrew Thompson ret += 8; 8978c8fff31SAndrew Thompson break ; 8988c8fff31SAndrew Thompson default : 8998c8fff31SAndrew Thompson switch (usb_speed) { 9008c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 9018c8fff31SAndrew Thompson ret = 256; 9028c8fff31SAndrew Thompson break ; 9038c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 9048c8fff31SAndrew Thompson ret = 4096; 9058c8fff31SAndrew Thompson break ; 9068c8fff31SAndrew Thompson default: 9078c8fff31SAndrew Thompson ret = 16384; 9088c8fff31SAndrew Thompson break ; 9098c8fff31SAndrew Thompson } 9108c8fff31SAndrew Thompson break ; 9118c8fff31SAndrew Thompson } 9128c8fff31SAndrew Thompson 9138c8fff31SAndrew Thompson return ret; 9148c8fff31SAndrew Thompson } 9158c8fff31SAndrew Thompson 916c500e4ddSAndrew Thompson static void 917c500e4ddSAndrew Thompson libusb10_proxy(struct libusb20_transfer *xfer) 918c500e4ddSAndrew Thompson { 919c500e4ddSAndrew Thompson struct usb_transfer *usb_backend; 920c500e4ddSAndrew Thompson struct libusb20_device *pdev; 921c500e4ddSAndrew Thompson libusb_transfer *usb_xfer; 922c500e4ddSAndrew Thompson libusb_context *ctx; 923c500e4ddSAndrew Thompson uint32_t pos; 924c500e4ddSAndrew Thompson uint32_t max; 925c500e4ddSAndrew Thompson uint32_t size; 926c500e4ddSAndrew Thompson uint8_t status; 927c500e4ddSAndrew Thompson uint32_t iso_packets; 928c500e4ddSAndrew Thompson int i; 929c500e4ddSAndrew Thompson 930c500e4ddSAndrew Thompson status = libusb20_tr_get_status(xfer); 931c500e4ddSAndrew Thompson usb_xfer = libusb20_tr_get_priv_sc0(xfer); 932c500e4ddSAndrew Thompson usb_backend = (struct usb_transfer *) ((uint8_t *)usb_xfer - 933c500e4ddSAndrew Thompson sizeof(struct usb_transfer)); 934c500e4ddSAndrew Thompson pdev = usb_xfer->dev_handle->dev->os_priv; 935c500e4ddSAndrew Thompson ctx = usb_xfer->dev_handle->dev->ctx; 936c500e4ddSAndrew Thompson GET_CONTEXT(ctx); 937c500e4ddSAndrew Thompson 938c500e4ddSAndrew Thompson switch (status) { 939c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 940c500e4ddSAndrew Thompson usb_backend->transferred += libusb20_tr_get_actual_length(xfer); 941c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 TRANSFER %i bytes", 942c500e4ddSAndrew Thompson usb_backend->transferred); 943c500e4ddSAndrew Thompson if (usb_backend->transferred != usb_xfer->length) 944c500e4ddSAndrew Thompson goto tr_start; 945c500e4ddSAndrew Thompson 946c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 TRANSFER COMPLETE"); 947c500e4ddSAndrew Thompson usb_handle_transfer_completion(usb_backend, LIBUSB_TRANSFER_COMPLETED); 948c500e4ddSAndrew Thompson 949c500e4ddSAndrew Thompson break ; 950c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_START: 951c500e4ddSAndrew Thompson tr_start: 952c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 START"); 953c500e4ddSAndrew Thompson max = libusb_get_buffsize(pdev, usb_xfer); 954c500e4ddSAndrew Thompson pos = usb_backend->transferred; 955c500e4ddSAndrew Thompson size = (usb_xfer->length - pos); 956c500e4ddSAndrew Thompson size = (size > max) ? max : size; 957c500e4ddSAndrew Thompson usb_xfer->actual_length = 0; 958c500e4ddSAndrew Thompson switch (usb_xfer->type) { 959c500e4ddSAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 960c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE CTR"); 961c500e4ddSAndrew Thompson libusb20_tr_setup_control(xfer, usb_xfer->buffer, 962c500e4ddSAndrew Thompson (void *)(((uint8_t *) &usb_xfer->buffer[pos]) + 963c500e4ddSAndrew Thompson sizeof(libusb_control_setup)), 964c500e4ddSAndrew Thompson usb_xfer->timeout); 965c500e4ddSAndrew Thompson break ; 966c500e4ddSAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 967c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE ISO"); 968c500e4ddSAndrew Thompson iso_packets = libusb20_tr_get_max_frames(xfer); 969c500e4ddSAndrew Thompson if (usb_xfer->num_iso_packets > iso_packets) 970c500e4ddSAndrew Thompson usb_xfer->num_iso_packets = iso_packets; 971c500e4ddSAndrew Thompson for (i = 0 ; i < usb_xfer->num_iso_packets ; i++) { 972c500e4ddSAndrew Thompson libusb20_tr_setup_isoc(xfer, 973c500e4ddSAndrew Thompson &usb_xfer->buffer[pos], size, i); 974c500e4ddSAndrew Thompson } 975c500e4ddSAndrew Thompson libusb20_tr_set_total_frames(xfer, i); 976c500e4ddSAndrew Thompson break ; 977c500e4ddSAndrew Thompson case LIBUSB_TRANSFER_TYPE_BULK: 978c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE BULK"); 979c500e4ddSAndrew Thompson libusb20_tr_setup_bulk(xfer, &usb_xfer->buffer[pos], 980c500e4ddSAndrew Thompson size, usb_xfer->timeout); 981c500e4ddSAndrew Thompson break ; 982c500e4ddSAndrew Thompson case LIBUSB_TRANSFER_TYPE_INTERRUPT: 983c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE INTR"); 984c500e4ddSAndrew Thompson libusb20_tr_setup_intr(xfer, &usb_xfer->buffer[pos], 985c500e4ddSAndrew Thompson size, usb_xfer->timeout); 986c500e4ddSAndrew Thompson break ; 987c500e4ddSAndrew Thompson } 988c500e4ddSAndrew Thompson libusb20_tr_submit(xfer); 989c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 SUBMITED"); 990c500e4ddSAndrew Thompson break ; 991c500e4ddSAndrew Thompson default: 992c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TRANSFER DEFAULT 0x%x\n", 993c500e4ddSAndrew Thompson status); 994c500e4ddSAndrew Thompson usb_backend->transferred = 0; 995c500e4ddSAndrew Thompson usb_handle_transfer_completion(usb_backend, LIBUSB_TRANSFER_CANCELLED); 996c500e4ddSAndrew Thompson break ; 997c500e4ddSAndrew Thompson } 998c500e4ddSAndrew Thompson 999c500e4ddSAndrew Thompson switch (status) { 1000c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 1001c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS COMPLETED"); 1002c500e4ddSAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_COMPLETED; 1003c500e4ddSAndrew Thompson break ; 1004c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_OVERFLOW: 1005c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR OVERFLOW"); 1006c500e4ddSAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_OVERFLOW; 1007c500e4ddSAndrew Thompson break ; 1008c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_NO_DEVICE: 1009c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR NO DEVICE"); 1010c500e4ddSAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_NO_DEVICE; 1011c500e4ddSAndrew Thompson break ; 1012c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_STALL: 1013c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR STALL"); 1014c500e4ddSAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_STALL; 1015c500e4ddSAndrew Thompson break ; 1016c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_CANCELLED: 1017c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR CANCELLED"); 1018c500e4ddSAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_CANCELLED; 1019c500e4ddSAndrew Thompson break ; 1020c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_TIMED_OUT: 1021c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR TIMEOUT"); 1022c500e4ddSAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_TIMED_OUT; 1023c500e4ddSAndrew Thompson break ; 1024c500e4ddSAndrew Thompson case LIBUSB20_TRANSFER_ERROR: 1025c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "ERROR"); 1026c500e4ddSAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_ERROR; 1027c500e4ddSAndrew Thompson break ; 1028c500e4ddSAndrew Thompson } 1029c500e4ddSAndrew Thompson } 1030c500e4ddSAndrew Thompson 10318c8fff31SAndrew Thompson int 10328c8fff31SAndrew Thompson libusb_submit_transfer(struct libusb_transfer *xfer) 10338c8fff31SAndrew Thompson { 10348c8fff31SAndrew Thompson struct libusb20_transfer **usb20_xfer; 10358c8fff31SAndrew Thompson struct usb_transfer *usb_backend; 10368c8fff31SAndrew Thompson struct usb_transfer *usb_node; 10378c8fff31SAndrew Thompson struct libusb20_device *pdev; 1038c500e4ddSAndrew Thompson struct usb_ep_tr *eptr; 10398c8fff31SAndrew Thompson struct timespec cur_ts; 10408c8fff31SAndrew Thompson struct timeval *cur_tv; 1041c500e4ddSAndrew Thompson libusb_device_handle *devh; 1042c500e4ddSAndrew Thompson libusb_context *ctx; 10438c8fff31SAndrew Thompson int maxframe; 10448c8fff31SAndrew Thompson int buffsize; 10458c8fff31SAndrew Thompson int ep_idx; 10468c8fff31SAndrew Thompson int ret; 10478c8fff31SAndrew Thompson 10488c8fff31SAndrew Thompson if (xfer == NULL) 10498c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 10508c8fff31SAndrew Thompson 10518c8fff31SAndrew Thompson usb20_xfer = malloc(2 * sizeof(struct libusb20_transfer *)); 10528c8fff31SAndrew Thompson if (usb20_xfer == NULL) 10538c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 10548c8fff31SAndrew Thompson 10558c8fff31SAndrew Thompson ctx = xfer->dev_handle->dev->ctx; 10568c8fff31SAndrew Thompson pdev = xfer->dev_handle->os_priv; 1057c500e4ddSAndrew Thompson devh = xfer->dev_handle; 10588c8fff31SAndrew Thompson 1059c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 10608c8fff31SAndrew Thompson 10618c8fff31SAndrew Thompson usb_backend = (struct usb_transfer *) ((uint8_t *)xfer - 10628c8fff31SAndrew Thompson sizeof(struct usb_transfer)); 10638c8fff31SAndrew Thompson usb_backend->transferred = 0; 10648c8fff31SAndrew Thompson usb_backend->flags = 0; 10658c8fff31SAndrew Thompson 10668c8fff31SAndrew Thompson if (xfer->timeout != 0) { 10678c8fff31SAndrew Thompson clock_gettime(CLOCK_MONOTONIC, &cur_ts); 10688c8fff31SAndrew Thompson cur_ts.tv_sec += xfer->timeout / 1000; 10698c8fff31SAndrew Thompson cur_ts.tv_nsec += (xfer->timeout % 1000) * 1000000; 10708c8fff31SAndrew Thompson 10718c8fff31SAndrew Thompson if (cur_ts.tv_nsec > 1000000000) { 10728c8fff31SAndrew Thompson cur_ts.tv_nsec -= 1000000000; 10738c8fff31SAndrew Thompson cur_ts.tv_sec++; 10748c8fff31SAndrew Thompson } 10758c8fff31SAndrew Thompson 10768c8fff31SAndrew Thompson TIMESPEC_TO_TIMEVAL(&usb_backend->timeout, &cur_ts); 10778c8fff31SAndrew Thompson } 10788c8fff31SAndrew Thompson 10798c8fff31SAndrew Thompson /*Add to flying list*/ 10808c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->flying_transfers_lock); 1081c500e4ddSAndrew Thompson if (TAILQ_EMPTY(&ctx->flying_transfers)) { 1082c500e4ddSAndrew Thompson TAILQ_INSERT_HEAD(&ctx->flying_transfers, usb_backend, list); 10838c8fff31SAndrew Thompson goto out; 10848c8fff31SAndrew Thompson } 10858c8fff31SAndrew Thompson if (timerisset(&usb_backend->timeout) == 0) { 1086c500e4ddSAndrew Thompson TAILQ_INSERT_HEAD(&ctx->flying_transfers, usb_backend, list); 10878c8fff31SAndrew Thompson goto out; 10888c8fff31SAndrew Thompson } 1089c500e4ddSAndrew Thompson TAILQ_FOREACH(usb_node, &ctx->flying_transfers, list) { 10908c8fff31SAndrew Thompson cur_tv = &usb_node->timeout; 10918c8fff31SAndrew Thompson if (timerisset(cur_tv) == 0 || 10928c8fff31SAndrew Thompson (cur_tv->tv_sec > usb_backend->timeout.tv_sec) || 10938c8fff31SAndrew Thompson (cur_tv->tv_sec == usb_backend->timeout.tv_sec && 10948c8fff31SAndrew Thompson cur_tv->tv_usec > usb_backend->timeout.tv_usec)) { 1095c500e4ddSAndrew Thompson TAILQ_INSERT_TAIL(&ctx->flying_transfers, usb_backend, list); 10968c8fff31SAndrew Thompson goto out; 10978c8fff31SAndrew Thompson } 10988c8fff31SAndrew Thompson } 1099c500e4ddSAndrew Thompson TAILQ_INSERT_TAIL(&ctx->flying_transfers, usb_backend, list); 11008c8fff31SAndrew Thompson 11018c8fff31SAndrew Thompson out: 11028c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->flying_transfers_lock); 11038c8fff31SAndrew Thompson 1104c500e4ddSAndrew Thompson ep_idx = (xfer->endpoint / 0x40) | (xfer->endpoint * 4) % (16 * 4); 1105c500e4ddSAndrew Thompson usb20_xfer[0] = libusb20_tr_get_pointer(pdev, ep_idx); 1106c500e4ddSAndrew Thompson usb20_xfer[1] = libusb20_tr_get_pointer(pdev, ep_idx + 1); 11078c8fff31SAndrew Thompson 11088c8fff31SAndrew Thompson if (usb20_xfer[0] == NULL) 11098c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 11108c8fff31SAndrew Thompson 11118c8fff31SAndrew Thompson xfer->os_priv = usb20_xfer; 11128c8fff31SAndrew Thompson 11138c8fff31SAndrew Thompson pthread_mutex_lock(&libusb20_lock); 11148c8fff31SAndrew Thompson 11158c8fff31SAndrew Thompson buffsize = libusb_get_buffsize(pdev, xfer); 11168c8fff31SAndrew Thompson maxframe = libusb_get_maxframe(pdev, xfer); 11178c8fff31SAndrew Thompson 1118c500e4ddSAndrew Thompson ret = 0; 1119c500e4ddSAndrew Thompson TAILQ_FOREACH(eptr, &devh->ep_list, list) { 1120c500e4ddSAndrew Thompson if (xfer->endpoint == eptr->addr) 1121c500e4ddSAndrew Thompson ret++; 1122c500e4ddSAndrew Thompson } 1123c500e4ddSAndrew Thompson if (ret == 0) { 1124c500e4ddSAndrew Thompson eptr = malloc(sizeof(struct usb_ep_tr)); 1125c500e4ddSAndrew Thompson eptr->addr = xfer->endpoint; 1126c500e4ddSAndrew Thompson eptr->idx = ep_idx; 1127c500e4ddSAndrew Thompson eptr->os_priv = usb20_xfer; 1128c500e4ddSAndrew Thompson eptr->flags = (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)?1:0; 1129c500e4ddSAndrew Thompson TAILQ_INSERT_HEAD(&devh->ep_list, eptr, list); 11308c8fff31SAndrew Thompson ret = libusb20_tr_open(usb20_xfer[0], buffsize, 11318c8fff31SAndrew Thompson maxframe, xfer->endpoint); 11328c8fff31SAndrew Thompson if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) 11338c8fff31SAndrew Thompson ret |= libusb20_tr_open(usb20_xfer[1], buffsize, 11348c8fff31SAndrew Thompson maxframe, xfer->endpoint); 11358c8fff31SAndrew Thompson 11368c8fff31SAndrew Thompson if (ret != 0) { 11378c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 11388c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->flying_transfers_lock); 1139c500e4ddSAndrew Thompson TAILQ_REMOVE(&ctx->flying_transfers, usb_backend, list); 11408c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->flying_transfers_lock); 11418c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 11428c8fff31SAndrew Thompson } 1143c500e4ddSAndrew Thompson } 11448c8fff31SAndrew Thompson 11458c8fff31SAndrew Thompson libusb20_tr_set_priv_sc0(usb20_xfer[0], xfer); 11468c8fff31SAndrew Thompson libusb20_tr_set_callback(usb20_xfer[0], libusb10_proxy); 11478c8fff31SAndrew Thompson if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { 11488c8fff31SAndrew Thompson libusb20_tr_set_priv_sc0(usb20_xfer[1], xfer); 11498c8fff31SAndrew Thompson libusb20_tr_set_callback(usb20_xfer[1], libusb10_proxy); 11508c8fff31SAndrew Thompson } 11518c8fff31SAndrew Thompson 1152c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20_TR_START"); 11538c8fff31SAndrew Thompson libusb20_tr_start(usb20_xfer[0]); 11548c8fff31SAndrew Thompson if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) 11558c8fff31SAndrew Thompson libusb20_tr_start(usb20_xfer[1]); 11568c8fff31SAndrew Thompson 11578c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 11588c8fff31SAndrew Thompson 1159c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave"); 11608c8fff31SAndrew Thompson return (0); 11618c8fff31SAndrew Thompson } 11628c8fff31SAndrew Thompson 11638c8fff31SAndrew Thompson int 11648c8fff31SAndrew Thompson libusb_cancel_transfer(struct libusb_transfer *xfer) 11658c8fff31SAndrew Thompson { 11668c8fff31SAndrew Thompson libusb_context *ctx; 11678c8fff31SAndrew Thompson 11688c8fff31SAndrew Thompson ctx = NULL; 11698c8fff31SAndrew Thompson GET_CONTEXT(ctx); 1170c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 11718c8fff31SAndrew Thompson 11728c8fff31SAndrew Thompson if (xfer == NULL) 11738c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 11748c8fff31SAndrew Thompson 11758c8fff31SAndrew Thompson pthread_mutex_lock(&libusb20_lock); 11768c8fff31SAndrew Thompson libusb20_tr_stop(xfer->os_priv); 11778c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 11788c8fff31SAndrew Thompson 1179c500e4ddSAndrew Thompson DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 11808c8fff31SAndrew Thompson return (0); 11818c8fff31SAndrew Thompson } 11828c8fff31SAndrew Thompson 1183