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); 788c8fff31SAndrew Thompson USB_LIST_INIT(&ctx->usb_devs); 798c8fff31SAndrew Thompson USB_LIST_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 888c8fff31SAndrew Thompson USB_LIST_INIT(&ctx->flying_transfers); 898c8fff31SAndrew Thompson USB_LIST_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 1268c8fff31SAndrew 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); 1388c8fff31SAndrew 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); 1538c8fff31SAndrew 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) { 1818c8fff31SAndrew Thompson free(*list); 1828c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 1838c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1848c8fff31SAndrew Thompson } 1858c8fff31SAndrew Thompson memset(dev, 0, sizeof(*dev)); 1868c8fff31SAndrew Thompson 1878c8fff31SAndrew Thompson pthread_mutex_init(&dev->lock, NULL); 1888c8fff31SAndrew Thompson dev->ctx = ctx; 1898c8fff31SAndrew Thompson dev->bus_number = pdev->bus_number; 1908c8fff31SAndrew Thompson dev->device_address = pdev->device_address; 1918c8fff31SAndrew Thompson dev->num_configurations = ddesc->bNumConfigurations; 1928c8fff31SAndrew Thompson 1938c8fff31SAndrew Thompson /* link together the two structures */ 1948c8fff31SAndrew Thompson dev->os_priv = pdev; 1958c8fff31SAndrew Thompson 1968c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->usb_devs_lock); 1978c8fff31SAndrew Thompson LIST_ADD(&dev->list, &ctx->usb_devs); 1988c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->usb_devs_lock); 1998c8fff31SAndrew Thompson 2008c8fff31SAndrew Thompson (*list)[i] = libusb_ref_device(dev); 2018c8fff31SAndrew Thompson i++; 2028c8fff31SAndrew Thompson } 2038c8fff31SAndrew Thompson (*list)[i] = NULL; 2048c8fff31SAndrew Thompson 2058c8fff31SAndrew Thompson libusb20_be_free(usb_backend); 2068c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_list leave"); 2078c8fff31SAndrew Thompson return (i); 2088c8fff31SAndrew Thompson } 2098c8fff31SAndrew Thompson 2108c8fff31SAndrew Thompson /* 2118c8fff31SAndrew Thompson * In this function we cant free all the device contained into list because 2128c8fff31SAndrew Thompson * open_with_pid_vid use some node of list after the free_device_list. 2138c8fff31SAndrew Thompson */ 2148c8fff31SAndrew Thompson void 2158c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices) 2168c8fff31SAndrew Thompson { 2178c8fff31SAndrew Thompson int i; 2188c8fff31SAndrew Thompson libusb_context *ctx; 2198c8fff31SAndrew Thompson 2208c8fff31SAndrew Thompson ctx = NULL; 2218c8fff31SAndrew Thompson GET_CONTEXT(ctx); 2228c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_device_list enter"); 2238c8fff31SAndrew Thompson 2248c8fff31SAndrew Thompson if (list == NULL) 2258c8fff31SAndrew Thompson return ; 2268c8fff31SAndrew Thompson 2278c8fff31SAndrew Thompson if (unref_devices) { 2288c8fff31SAndrew Thompson for (i = 0; list[i] != NULL; i++) 2298c8fff31SAndrew Thompson libusb_unref_device(list[i]); 2308c8fff31SAndrew Thompson } 2318c8fff31SAndrew Thompson free(list); 2328c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_device_list leave"); 2338c8fff31SAndrew Thompson } 2348c8fff31SAndrew Thompson 2358c8fff31SAndrew Thompson uint8_t 2368c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device * dev) 2378c8fff31SAndrew Thompson { 2388c8fff31SAndrew Thompson libusb_context *ctx; 2398c8fff31SAndrew Thompson 2408c8fff31SAndrew Thompson ctx = NULL; 2418c8fff31SAndrew Thompson GET_CONTEXT(ctx); 2428c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_bus_number enter"); 2438c8fff31SAndrew Thompson 2448c8fff31SAndrew Thompson if (dev == NULL) 2458c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 2468c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_bus_number leave"); 2478c8fff31SAndrew Thompson return (dev->bus_number); 2488c8fff31SAndrew Thompson } 2498c8fff31SAndrew Thompson 2508c8fff31SAndrew Thompson uint8_t 2518c8fff31SAndrew Thompson libusb_get_device_address(libusb_device * dev) 2528c8fff31SAndrew Thompson { 2538c8fff31SAndrew Thompson libusb_context *ctx; 2548c8fff31SAndrew Thompson 2558c8fff31SAndrew Thompson ctx = NULL; 2568c8fff31SAndrew Thompson GET_CONTEXT(ctx); 2578c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_address enter"); 2588c8fff31SAndrew Thompson 2598c8fff31SAndrew Thompson if (dev == NULL) 2608c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 2618c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_address leave"); 2628c8fff31SAndrew Thompson return (dev->device_address); 2638c8fff31SAndrew Thompson } 2648c8fff31SAndrew Thompson 2658c8fff31SAndrew Thompson int 2668c8fff31SAndrew Thompson libusb_get_max_packet_size(libusb_device *dev, unsigned char endpoint) 2678c8fff31SAndrew Thompson { 2688c8fff31SAndrew Thompson struct libusb_config_descriptor *pdconf; 2698c8fff31SAndrew Thompson struct libusb_interface *pinf; 2708c8fff31SAndrew Thompson struct libusb_interface_descriptor *pdinf; 2718c8fff31SAndrew Thompson struct libusb_endpoint_descriptor *pdend; 2728c8fff31SAndrew Thompson libusb_context *ctx; 2738c8fff31SAndrew Thompson int i, j, k, ret; 2748c8fff31SAndrew Thompson 2758c8fff31SAndrew Thompson ctx = NULL; 2768c8fff31SAndrew Thompson GET_CONTEXT(ctx); 2778c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_max_packet_size enter"); 2788c8fff31SAndrew Thompson 2798c8fff31SAndrew Thompson if (dev == NULL) 2808c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_DEVICE); 2818c8fff31SAndrew Thompson 2828c8fff31SAndrew Thompson if (libusb_get_active_config_descriptor(dev, &pdconf) < 0) 2838c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 2848c8fff31SAndrew Thompson 2858c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 2868c8fff31SAndrew Thompson for (i = 0 ; i < pdconf->bNumInterfaces ; i++) { 2878c8fff31SAndrew Thompson pinf = &pdconf->interface[i]; 2888c8fff31SAndrew Thompson for (j = 0 ; j < pinf->num_altsetting ; j++) { 2898c8fff31SAndrew Thompson pdinf = &pinf->altsetting[j]; 2908c8fff31SAndrew Thompson for (k = 0 ; k < pdinf->bNumEndpoints ; k++) { 2918c8fff31SAndrew Thompson pdend = &pdinf->endpoint[k]; 2928c8fff31SAndrew Thompson if (pdend->bEndpointAddress == endpoint) { 2938c8fff31SAndrew Thompson ret = pdend->wMaxPacketSize; 2948c8fff31SAndrew Thompson goto out; 2958c8fff31SAndrew Thompson } 2968c8fff31SAndrew Thompson } 2978c8fff31SAndrew Thompson } 2988c8fff31SAndrew Thompson } 2998c8fff31SAndrew Thompson 3008c8fff31SAndrew Thompson out: 3018c8fff31SAndrew Thompson libusb_free_config_descriptor(pdconf); 3028c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_max_packet_size leave"); 3038c8fff31SAndrew Thompson return (ret); 3048c8fff31SAndrew Thompson } 3058c8fff31SAndrew Thompson 3068c8fff31SAndrew Thompson libusb_device * 3078c8fff31SAndrew Thompson libusb_ref_device(libusb_device * dev) 3088c8fff31SAndrew Thompson { 3098c8fff31SAndrew Thompson libusb_context *ctx; 3108c8fff31SAndrew Thompson 3118c8fff31SAndrew Thompson ctx = NULL; 3128c8fff31SAndrew Thompson GET_CONTEXT(ctx); 3138c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_ref_device enter"); 3148c8fff31SAndrew Thompson 3158c8fff31SAndrew Thompson if (dev == NULL) 3168c8fff31SAndrew Thompson return (NULL); 3178c8fff31SAndrew Thompson 3188c8fff31SAndrew Thompson pthread_mutex_lock(&dev->lock); 3198c8fff31SAndrew Thompson dev->refcnt++; 3208c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 3218c8fff31SAndrew Thompson 3228c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_ref_device leave"); 3238c8fff31SAndrew Thompson return (dev); 3248c8fff31SAndrew Thompson } 3258c8fff31SAndrew Thompson 3268c8fff31SAndrew Thompson void 3278c8fff31SAndrew Thompson libusb_unref_device(libusb_device * dev) 3288c8fff31SAndrew Thompson { 3298c8fff31SAndrew Thompson libusb_context *ctx; 3308c8fff31SAndrew Thompson 3318c8fff31SAndrew Thompson ctx = NULL; 3328c8fff31SAndrew Thompson GET_CONTEXT(ctx); 3338c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unref_device enter"); 3348c8fff31SAndrew Thompson 3358c8fff31SAndrew Thompson if (dev == NULL) 3368c8fff31SAndrew Thompson return; 3378c8fff31SAndrew Thompson 3388c8fff31SAndrew Thompson pthread_mutex_lock(&dev->lock); 3398c8fff31SAndrew Thompson dev->refcnt--; 3408c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 3418c8fff31SAndrew Thompson 3428c8fff31SAndrew Thompson if (dev->refcnt == 0) { 3438c8fff31SAndrew Thompson pthread_mutex_lock(&dev->ctx->usb_devs_lock); 3448c8fff31SAndrew Thompson LIST_DEL(&dev->list); 3458c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->ctx->usb_devs_lock); 3468c8fff31SAndrew Thompson 3478c8fff31SAndrew Thompson libusb20_dev_free(dev->os_priv); 3488c8fff31SAndrew Thompson free(dev); 3498c8fff31SAndrew Thompson } 3508c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unref_device leave"); 3518c8fff31SAndrew Thompson } 3528c8fff31SAndrew Thompson 3538c8fff31SAndrew Thompson int 3548c8fff31SAndrew Thompson libusb_open(libusb_device * dev, libusb_device_handle **devh) 3558c8fff31SAndrew Thompson { 3568c8fff31SAndrew Thompson libusb_context *ctx = dev->ctx; 3578c8fff31SAndrew Thompson struct libusb20_device *pdev = dev->os_priv; 3588c8fff31SAndrew Thompson libusb_device_handle *hdl; 3598c8fff31SAndrew Thompson unsigned char dummy; 3608c8fff31SAndrew Thompson int err; 3618c8fff31SAndrew Thompson 3628c8fff31SAndrew Thompson GET_CONTEXT(ctx); 3638c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open enter"); 3648c8fff31SAndrew Thompson 3658c8fff31SAndrew Thompson dummy = 1; 3668c8fff31SAndrew Thompson if (devh == NULL) 3678c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 3688c8fff31SAndrew Thompson 3698c8fff31SAndrew Thompson hdl = malloc(sizeof(*hdl)); 3708c8fff31SAndrew Thompson if (hdl == NULL) 3718c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3728c8fff31SAndrew Thompson 3738c8fff31SAndrew Thompson err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 3748c8fff31SAndrew Thompson if (err) { 3758c8fff31SAndrew Thompson free(hdl); 3768c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 3778c8fff31SAndrew Thompson } 3788c8fff31SAndrew Thompson memset(hdl, 0, sizeof(*hdl)); 3798c8fff31SAndrew Thompson pthread_mutex_init(&hdl->lock, NULL); 3808c8fff31SAndrew Thompson 3818c8fff31SAndrew Thompson hdl->dev = libusb_ref_device(dev); 3828c8fff31SAndrew Thompson hdl->claimed_interfaces = 0; 3838c8fff31SAndrew Thompson hdl->os_priv = dev->os_priv; 3848c8fff31SAndrew Thompson err = usb_add_pollfd(ctx, libusb20_dev_get_fd(pdev), POLLIN | 3858c8fff31SAndrew Thompson POLLOUT | POLLRDNORM | POLLWRNORM); 3868c8fff31SAndrew Thompson if (err < 0) { 3878c8fff31SAndrew Thompson libusb_unref_device(dev); 3888c8fff31SAndrew Thompson free(hdl); 3898c8fff31SAndrew Thompson return (err); 3908c8fff31SAndrew Thompson } 3918c8fff31SAndrew Thompson 3928c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->open_devs_lock); 3938c8fff31SAndrew Thompson LIST_ADD(&hdl->list, &ctx->open_devs); 3948c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->open_devs_lock); 3958c8fff31SAndrew Thompson 3968c8fff31SAndrew Thompson *devh = hdl; 3978c8fff31SAndrew Thompson 3988c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 3998c8fff31SAndrew Thompson ctx->pollfd_modify++; 4008c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4018c8fff31SAndrew Thompson 4028c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 4038c8fff31SAndrew Thompson if (err <= 0) { 4048c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4058c8fff31SAndrew Thompson ctx->pollfd_modify--; 4068c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4078c8fff31SAndrew Thompson return 0; 4088c8fff31SAndrew Thompson } 4098c8fff31SAndrew Thompson 4108c8fff31SAndrew Thompson libusb_lock_events(ctx); 4118c8fff31SAndrew Thompson read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); 4128c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4138c8fff31SAndrew Thompson ctx->pollfd_modify--; 4148c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4158c8fff31SAndrew Thompson libusb_unlock_events(ctx); 4168c8fff31SAndrew Thompson 4178c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open leave"); 4188c8fff31SAndrew Thompson return (0); 4198c8fff31SAndrew Thompson } 4208c8fff31SAndrew Thompson 4218c8fff31SAndrew Thompson libusb_device_handle * 4228c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context * ctx, uint16_t vendor_id, 4238c8fff31SAndrew Thompson uint16_t product_id) 4248c8fff31SAndrew Thompson { 4258c8fff31SAndrew Thompson struct libusb_device **devs; 4268c8fff31SAndrew Thompson struct libusb_device_handle *devh; 4278c8fff31SAndrew Thompson struct libusb20_device *pdev; 4288c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 4298c8fff31SAndrew Thompson int i, j; 4308c8fff31SAndrew Thompson 4318c8fff31SAndrew Thompson GET_CONTEXT(ctx); 4328c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 4338c8fff31SAndrew Thompson 4348c8fff31SAndrew Thompson devh = NULL; 4358c8fff31SAndrew Thompson 4368c8fff31SAndrew Thompson if ((i = libusb_get_device_list(ctx, &devs)) < 0) 4378c8fff31SAndrew Thompson return (NULL); 4388c8fff31SAndrew Thompson 4398c8fff31SAndrew Thompson for (j = 0; j < i; j++) { 4408c8fff31SAndrew Thompson pdev = (struct libusb20_device *)devs[j]->os_priv; 4418c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 4428c8fff31SAndrew Thompson if (pdesc->idVendor == vendor_id && 4438c8fff31SAndrew Thompson pdesc->idProduct == product_id) 4448c8fff31SAndrew Thompson if (libusb_open(devs[j], &devh) < 0) 4458c8fff31SAndrew Thompson devh = NULL; 4468c8fff31SAndrew Thompson } 4478c8fff31SAndrew Thompson 4488c8fff31SAndrew Thompson libusb_free_device_list(devs, 1); 4498c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 4508c8fff31SAndrew Thompson return (devh); 4518c8fff31SAndrew Thompson } 4528c8fff31SAndrew Thompson 4538c8fff31SAndrew Thompson void 4548c8fff31SAndrew Thompson libusb_close(libusb_device_handle * devh) 4558c8fff31SAndrew Thompson { 4568c8fff31SAndrew Thompson libusb_context *ctx; 4578c8fff31SAndrew Thompson struct libusb20_device *pdev; 4588c8fff31SAndrew Thompson unsigned char dummy = 1; 4598c8fff31SAndrew Thompson int err; 4608c8fff31SAndrew Thompson 4618c8fff31SAndrew Thompson if (devh == NULL) 4628c8fff31SAndrew Thompson return ; 4638c8fff31SAndrew Thompson 4648c8fff31SAndrew Thompson ctx = devh->dev->ctx; 4658c8fff31SAndrew Thompson pdev = devh->os_priv; 4668c8fff31SAndrew Thompson 4678c8fff31SAndrew Thompson GET_CONTEXT(ctx); 4688c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close enter"); 4698c8fff31SAndrew Thompson 4708c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4718c8fff31SAndrew Thompson ctx->pollfd_modify++; 4728c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4738c8fff31SAndrew Thompson 4748c8fff31SAndrew Thompson err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 4758c8fff31SAndrew Thompson 4768c8fff31SAndrew Thompson if (err <= 0) { 4778c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->open_devs_lock); 4788c8fff31SAndrew Thompson LIST_DEL(&devh->list); 4798c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->open_devs_lock); 4808c8fff31SAndrew Thompson 4818c8fff31SAndrew Thompson usb_remove_pollfd(ctx, libusb20_dev_get_fd(pdev)); 4828c8fff31SAndrew Thompson libusb_unref_device(devh->dev); 4838c8fff31SAndrew Thompson libusb20_dev_close(pdev); 4848c8fff31SAndrew Thompson free(devh); 4858c8fff31SAndrew Thompson 4868c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->pollfd_modify_lock); 4878c8fff31SAndrew Thompson ctx->pollfd_modify--; 4888c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->pollfd_modify_lock); 4898c8fff31SAndrew Thompson return ; 4908c8fff31SAndrew Thompson } 4918c8fff31SAndrew Thompson libusb_lock_events(ctx); 4928c8fff31SAndrew Thompson 4938c8fff31SAndrew Thompson read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); 4948c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->open_devs_lock); 4958c8fff31SAndrew Thompson LIST_DEL(&devh->list); 4968c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->open_devs_lock); 4978c8fff31SAndrew Thompson 4988c8fff31SAndrew Thompson usb_remove_pollfd(ctx, libusb20_dev_get_fd(pdev)); 4998c8fff31SAndrew Thompson libusb_unref_device(devh->dev); 5008c8fff31SAndrew Thompson libusb20_dev_close(pdev); 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 5078c8fff31SAndrew Thompson libusb_unlock_events(ctx); 5088c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close leave"); 5098c8fff31SAndrew Thompson } 5108c8fff31SAndrew Thompson 5118c8fff31SAndrew Thompson libusb_device * 5128c8fff31SAndrew Thompson libusb_get_device(libusb_device_handle * devh) 5138c8fff31SAndrew Thompson { 5148c8fff31SAndrew Thompson libusb_context *ctx; 5158c8fff31SAndrew Thompson 5168c8fff31SAndrew Thompson ctx = NULL; 5178c8fff31SAndrew Thompson GET_CONTEXT(ctx); 5188c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device enter"); 5198c8fff31SAndrew Thompson 5208c8fff31SAndrew Thompson if (devh == NULL) 5218c8fff31SAndrew Thompson return (NULL); 5228c8fff31SAndrew Thompson 5238c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device leave"); 5248c8fff31SAndrew Thompson return (devh->dev); 5258c8fff31SAndrew Thompson } 5268c8fff31SAndrew Thompson 5278c8fff31SAndrew Thompson int 5288c8fff31SAndrew Thompson libusb_get_configuration(libusb_device_handle * devh, int *config) 5298c8fff31SAndrew Thompson { 5308c8fff31SAndrew Thompson libusb_context *ctx; 5318c8fff31SAndrew Thompson 5328c8fff31SAndrew Thompson ctx = NULL; 5338c8fff31SAndrew Thompson GET_CONTEXT(ctx); 5348c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_configuration enter"); 5358c8fff31SAndrew Thompson 5368c8fff31SAndrew Thompson if (devh == NULL || config == NULL) 5378c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5388c8fff31SAndrew Thompson 5398c8fff31SAndrew Thompson *config = libusb20_dev_get_config_index((struct libusb20_device *) 5408c8fff31SAndrew Thompson devh->dev->os_priv); 5418c8fff31SAndrew Thompson 5428c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_configuration leave"); 5438c8fff31SAndrew Thompson return (0); 5448c8fff31SAndrew Thompson } 5458c8fff31SAndrew Thompson 5468c8fff31SAndrew Thompson /* 5478c8fff31SAndrew Thompson * XXX this code is wrong. need update. 5488c8fff31SAndrew Thompson */ 5498c8fff31SAndrew Thompson 5508c8fff31SAndrew Thompson int 5518c8fff31SAndrew Thompson libusb_set_configuration(libusb_device_handle * devh, int configuration) 5528c8fff31SAndrew Thompson { 5538c8fff31SAndrew Thompson struct libusb20_device *pdev; 5548c8fff31SAndrew Thompson libusb_context *ctx; 5558c8fff31SAndrew Thompson 5568c8fff31SAndrew Thompson ctx = NULL; 5578c8fff31SAndrew Thompson GET_CONTEXT(ctx); 5588c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_configuration enter"); 5598c8fff31SAndrew Thompson 5608c8fff31SAndrew Thompson if (devh == NULL) 5618c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5628c8fff31SAndrew Thompson 5638c8fff31SAndrew Thompson pdev = (struct libusb20_device *)devh->dev->os_priv; 5648c8fff31SAndrew Thompson 5658c8fff31SAndrew Thompson libusb20_dev_set_alt_index(pdev, libusb20_dev_get_config_index(pdev), 5668c8fff31SAndrew Thompson configuration); 5678c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_configuration leave"); 5688c8fff31SAndrew Thompson return (0); 5698c8fff31SAndrew Thompson } 5708c8fff31SAndrew Thompson 5718c8fff31SAndrew Thompson int 5728c8fff31SAndrew Thompson libusb_claim_interface(libusb_device_handle * dev, int interface_number) 5738c8fff31SAndrew Thompson { 5748c8fff31SAndrew Thompson libusb_context *ctx; 5758c8fff31SAndrew Thompson int ret = 0; 5768c8fff31SAndrew Thompson 5778c8fff31SAndrew Thompson ctx = NULL; 5788c8fff31SAndrew Thompson GET_CONTEXT(ctx); 5798c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_claim_interface enter"); 5808c8fff31SAndrew Thompson 5818c8fff31SAndrew Thompson if (dev == NULL) 5828c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5838c8fff31SAndrew Thompson 5848c8fff31SAndrew Thompson if (interface_number >= sizeof(dev->claimed_interfaces) * 8) 5858c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 5868c8fff31SAndrew Thompson 5878c8fff31SAndrew Thompson pthread_mutex_lock(&(dev->lock)); 5888c8fff31SAndrew Thompson if (dev->claimed_interfaces & (1 << interface_number)) 5898c8fff31SAndrew Thompson ret = LIBUSB_ERROR_BUSY; 5908c8fff31SAndrew Thompson 5918c8fff31SAndrew Thompson if (!ret) 5928c8fff31SAndrew Thompson dev->claimed_interfaces |= (1 << interface_number); 5938c8fff31SAndrew Thompson pthread_mutex_unlock(&(dev->lock)); 5948c8fff31SAndrew Thompson 5958c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_claim_interface leave"); 5968c8fff31SAndrew Thompson return (ret); 5978c8fff31SAndrew Thompson } 5988c8fff31SAndrew Thompson 5998c8fff31SAndrew Thompson int 6008c8fff31SAndrew Thompson libusb_release_interface(libusb_device_handle * dev, int interface_number) 6018c8fff31SAndrew Thompson { 6028c8fff31SAndrew Thompson libusb_context *ctx; 6038c8fff31SAndrew Thompson int ret; 6048c8fff31SAndrew Thompson 6058c8fff31SAndrew Thompson ctx = NULL; 6068c8fff31SAndrew Thompson GET_CONTEXT(ctx); 6078c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_release_interface enter"); 6088c8fff31SAndrew Thompson 6098c8fff31SAndrew Thompson ret = 0; 6108c8fff31SAndrew Thompson if (dev == NULL) 6118c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6128c8fff31SAndrew Thompson 6138c8fff31SAndrew Thompson if (interface_number >= sizeof(dev->claimed_interfaces) * 8) 6148c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6158c8fff31SAndrew Thompson 6168c8fff31SAndrew Thompson pthread_mutex_lock(&(dev->lock)); 6178c8fff31SAndrew Thompson if (!(dev->claimed_interfaces & (1 << interface_number))) 6188c8fff31SAndrew Thompson ret = LIBUSB_ERROR_NOT_FOUND; 6198c8fff31SAndrew Thompson 6208c8fff31SAndrew Thompson if (!ret) 6218c8fff31SAndrew Thompson dev->claimed_interfaces &= ~(1 << interface_number); 6228c8fff31SAndrew Thompson pthread_mutex_unlock(&(dev->lock)); 6238c8fff31SAndrew Thompson 6248c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_release_interface leave"); 6258c8fff31SAndrew Thompson return (ret); 6268c8fff31SAndrew Thompson } 6278c8fff31SAndrew Thompson 6288c8fff31SAndrew Thompson int 6298c8fff31SAndrew Thompson libusb_set_interface_alt_setting(libusb_device_handle * dev, 6308c8fff31SAndrew Thompson int interface_number, int alternate_setting) 6318c8fff31SAndrew Thompson { 6328c8fff31SAndrew Thompson libusb_context *ctx; 6338c8fff31SAndrew Thompson int ret; 6348c8fff31SAndrew Thompson 6358c8fff31SAndrew Thompson ctx = NULL; 6368c8fff31SAndrew Thompson GET_CONTEXT(ctx); 6378c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_interface_alt_setting enter"); 6388c8fff31SAndrew Thompson 6398c8fff31SAndrew Thompson if (dev == NULL) 6408c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6418c8fff31SAndrew Thompson 6428c8fff31SAndrew Thompson if (interface_number >= sizeof(dev->claimed_interfaces) *8) 6438c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 6448c8fff31SAndrew Thompson 6458c8fff31SAndrew Thompson pthread_mutex_lock(&dev->lock); 6468c8fff31SAndrew Thompson if (!(dev->claimed_interfaces & (1 << interface_number))) { 6478c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 6488c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 6498c8fff31SAndrew Thompson } 6508c8fff31SAndrew Thompson pthread_mutex_unlock(&dev->lock); 6518c8fff31SAndrew Thompson 6528c8fff31SAndrew Thompson if (libusb20_dev_set_alt_index(dev->os_priv, interface_number, 6538c8fff31SAndrew Thompson alternate_setting) != 0) 6548c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 6558c8fff31SAndrew Thompson 6568c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_interface_alt_setting leave"); 6578c8fff31SAndrew Thompson return (0); 6588c8fff31SAndrew Thompson } 6598c8fff31SAndrew Thompson 6608c8fff31SAndrew Thompson int 6618c8fff31SAndrew Thompson libusb_clear_halt(libusb_device_handle * devh, unsigned char endpoint) 6628c8fff31SAndrew Thompson { 6638c8fff31SAndrew Thompson struct libusb20_transfer *xfer; 6648c8fff31SAndrew Thompson libusb_context *ctx; 6658c8fff31SAndrew Thompson int ret; 6668c8fff31SAndrew Thompson 6678c8fff31SAndrew Thompson ctx = NULL; 6688c8fff31SAndrew Thompson GET_CONTEXT(ctx); 6698c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_clear_halt enter"); 6708c8fff31SAndrew Thompson 6718c8fff31SAndrew Thompson GET_XFER(xfer, endpoint, devh->os_priv); 6728c8fff31SAndrew Thompson 6738c8fff31SAndrew Thompson pthread_mutex_lock(&libusb20_lock); 6748c8fff31SAndrew Thompson ret = libusb20_tr_open(xfer, 0, 0, endpoint); 6758c8fff31SAndrew Thompson if (ret != 0 && ret != LIBUSB20_ERROR_BUSY) { 6768c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 6778c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 6788c8fff31SAndrew Thompson } 6798c8fff31SAndrew Thompson 6808c8fff31SAndrew Thompson libusb20_tr_clear_stall_sync(xfer); 6818c8fff31SAndrew Thompson if (ret == 0) /* check if we have open the device */ 6828c8fff31SAndrew Thompson libusb20_tr_close(xfer); 6838c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 6848c8fff31SAndrew Thompson 6858c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_clear_halt leave"); 6868c8fff31SAndrew Thompson return (0); 6878c8fff31SAndrew Thompson } 6888c8fff31SAndrew Thompson 6898c8fff31SAndrew Thompson int 6908c8fff31SAndrew Thompson libusb_reset_device(libusb_device_handle * dev) 6918c8fff31SAndrew Thompson { 6928c8fff31SAndrew Thompson libusb_context *ctx; 6938c8fff31SAndrew Thompson 6948c8fff31SAndrew Thompson ctx = NULL; 6958c8fff31SAndrew Thompson GET_CONTEXT(ctx); 6968c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_reset_device enter"); 6978c8fff31SAndrew Thompson 6988c8fff31SAndrew Thompson if (dev == NULL) 6998c8fff31SAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 7008c8fff31SAndrew Thompson 7018c8fff31SAndrew Thompson libusb20_dev_reset(dev->os_priv); 7028c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_reset_device leave"); 7038c8fff31SAndrew Thompson return (0); 7048c8fff31SAndrew Thompson } 7058c8fff31SAndrew Thompson 7068c8fff31SAndrew Thompson int 7078c8fff31SAndrew Thompson libusb_kernel_driver_active(libusb_device_handle * devh, int interface) 7088c8fff31SAndrew Thompson { 7098c8fff31SAndrew Thompson libusb_context *ctx; 7108c8fff31SAndrew Thompson 7118c8fff31SAndrew Thompson ctx = NULL; 7128c8fff31SAndrew Thompson GET_CONTEXT(ctx); 7138c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_kernel_driver_active enter"); 7148c8fff31SAndrew Thompson 7158c8fff31SAndrew Thompson if (devh == NULL) 7168c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7178c8fff31SAndrew Thompson 7188c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_kernel_driver_active leave"); 7198c8fff31SAndrew Thompson return (libusb20_dev_kernel_driver_active(devh->os_priv, interface)); 7208c8fff31SAndrew Thompson } 7218c8fff31SAndrew Thompson 7228c8fff31SAndrew Thompson int 7238c8fff31SAndrew Thompson libusb_detach_kernel_driver(libusb_device_handle * devh, int interface) 7248c8fff31SAndrew Thompson { 7258c8fff31SAndrew Thompson struct libusb20_device *pdev; 7268c8fff31SAndrew Thompson libusb_context *ctx; 7278c8fff31SAndrew Thompson 7288c8fff31SAndrew Thompson ctx = NULL; 7298c8fff31SAndrew Thompson GET_CONTEXT(ctx); 7308c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_detach_kernel_driver enter"); 7318c8fff31SAndrew Thompson 7328c8fff31SAndrew Thompson if (devh == NULL) 7338c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7348c8fff31SAndrew Thompson 7358c8fff31SAndrew Thompson pdev = (struct libusb20_device *)devh->dev->os_priv; 7368c8fff31SAndrew Thompson if (libusb20_dev_detach_kernel_driver(pdev, interface) == LIBUSB20_ERROR_OTHER) 7378c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 7388c8fff31SAndrew Thompson 7398c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_detach_kernel_driver leave"); 7408c8fff31SAndrew Thompson return (0); 7418c8fff31SAndrew Thompson } 7428c8fff31SAndrew Thompson 7438c8fff31SAndrew Thompson /* 7448c8fff31SAndrew Thompson * stub function. 7458c8fff31SAndrew Thompson * libusb20 doesn't support this feature. 7468c8fff31SAndrew Thompson */ 7478c8fff31SAndrew Thompson int 7488c8fff31SAndrew Thompson libusb_attach_kernel_driver(libusb_device_handle * devh, int interface) 7498c8fff31SAndrew Thompson { 7508c8fff31SAndrew Thompson libusb_context *ctx; 7518c8fff31SAndrew Thompson 7528c8fff31SAndrew Thompson ctx = NULL; 7538c8fff31SAndrew Thompson GET_CONTEXT(ctx); 7548c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_attach_kernel_driver enter"); 7558c8fff31SAndrew Thompson 7568c8fff31SAndrew Thompson if (devh == NULL) 7578c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 7588c8fff31SAndrew Thompson 7598c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_attach_kernel_driver leave"); 7608c8fff31SAndrew Thompson return (0); 7618c8fff31SAndrew Thompson } 7628c8fff31SAndrew Thompson 7638c8fff31SAndrew Thompson /* Asynchronous device I/O */ 7648c8fff31SAndrew Thompson 7658c8fff31SAndrew Thompson struct libusb_transfer * 7668c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets) 7678c8fff31SAndrew Thompson { 7688c8fff31SAndrew Thompson struct libusb_transfer *xfer; 7698c8fff31SAndrew Thompson struct usb_transfer *bxfer; 7708c8fff31SAndrew Thompson libusb_context *ctx; 7718c8fff31SAndrew Thompson int len; 7728c8fff31SAndrew Thompson 7738c8fff31SAndrew Thompson ctx = NULL; 7748c8fff31SAndrew Thompson GET_CONTEXT(ctx); 7758c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_alloc_transfer enter"); 7768c8fff31SAndrew Thompson 7778c8fff31SAndrew Thompson len = sizeof(struct libusb_transfer) + 7788c8fff31SAndrew Thompson sizeof(struct usb_transfer) + 7798c8fff31SAndrew Thompson (iso_packets * sizeof(libusb_iso_packet_descriptor)); 7808c8fff31SAndrew Thompson 7818c8fff31SAndrew Thompson bxfer = malloc(len); 7828c8fff31SAndrew Thompson if (bxfer == NULL) 7838c8fff31SAndrew Thompson return (NULL); 7848c8fff31SAndrew Thompson 7858c8fff31SAndrew Thompson memset(bxfer, 0, len); 7868c8fff31SAndrew Thompson bxfer->num_iso_packets = iso_packets; 7878c8fff31SAndrew Thompson 7888c8fff31SAndrew Thompson xfer = (struct libusb_transfer *) ((uint8_t *)bxfer + 7898c8fff31SAndrew Thompson sizeof(struct usb_transfer)); 7908c8fff31SAndrew Thompson 7918c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_alloc_transfer leave"); 7928c8fff31SAndrew Thompson return (xfer); 7938c8fff31SAndrew Thompson } 7948c8fff31SAndrew Thompson 7958c8fff31SAndrew Thompson void 7968c8fff31SAndrew Thompson libusb_free_transfer(struct libusb_transfer *xfer) 7978c8fff31SAndrew Thompson { 7988c8fff31SAndrew Thompson struct usb_transfer *bxfer; 7998c8fff31SAndrew Thompson libusb_context *ctx; 8008c8fff31SAndrew Thompson 8018c8fff31SAndrew Thompson ctx = NULL; 8028c8fff31SAndrew Thompson GET_CONTEXT(ctx); 8038c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_transfer enter"); 8048c8fff31SAndrew Thompson 8058c8fff31SAndrew Thompson if (xfer == NULL) 8068c8fff31SAndrew Thompson return ; 8078c8fff31SAndrew Thompson 8088c8fff31SAndrew Thompson bxfer = (struct usb_transfer *) ((uint8_t *)xfer - 8098c8fff31SAndrew Thompson sizeof(struct usb_transfer)); 8108c8fff31SAndrew Thompson 8118c8fff31SAndrew Thompson free(bxfer); 8128c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_transfer leave"); 8138c8fff31SAndrew Thompson return; 8148c8fff31SAndrew Thompson } 8158c8fff31SAndrew Thompson 8168c8fff31SAndrew Thompson static void 8178c8fff31SAndrew Thompson libusb10_proxy(struct libusb20_transfer *xfer) 8188c8fff31SAndrew Thompson { 8198c8fff31SAndrew Thompson struct usb_transfer *usb_backend; 8208c8fff31SAndrew Thompson struct libusb20_device *pdev; 8218c8fff31SAndrew Thompson libusb_transfer *usb_xfer; 8228c8fff31SAndrew Thompson libusb_context *ctx; 8238c8fff31SAndrew Thompson uint8_t status; 8248c8fff31SAndrew Thompson uint32_t iso_packets; 8258c8fff31SAndrew Thompson int i; 8268c8fff31SAndrew Thompson 8278c8fff31SAndrew Thompson status = libusb20_tr_get_status(xfer); 8288c8fff31SAndrew Thompson usb_xfer = libusb20_tr_get_priv_sc0(xfer); 8298c8fff31SAndrew Thompson usb_backend = (struct usb_transfer *) ((uint8_t *)usb_xfer - 8308c8fff31SAndrew Thompson sizeof(struct usb_transfer)); 8318c8fff31SAndrew Thompson pdev = usb_xfer->dev_handle->dev->os_priv; 8328c8fff31SAndrew Thompson ctx = usb_xfer->dev_handle->dev->ctx; 8338c8fff31SAndrew Thompson GET_CONTEXT(ctx); 8348c8fff31SAndrew Thompson 8358c8fff31SAndrew Thompson switch (status) { 8368c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 8378c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 SUBMIT"); 8388c8fff31SAndrew Thompson usb_xfer->actual_length += libusb20_tr_get_actual_length(xfer); 8398c8fff31SAndrew Thompson usb_xfer->callback(usb_xfer); 8408c8fff31SAndrew Thompson 8418c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->flying_transfers_lock); 8428c8fff31SAndrew Thompson LIST_DEL(&usb_backend->list); 8438c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->flying_transfers_lock); 8448c8fff31SAndrew Thompson break ; 8458c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_START: 8468c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 START"); 8478c8fff31SAndrew Thompson usb_xfer->actual_length = 0; 8488c8fff31SAndrew Thompson switch (usb_xfer->type) { 8498c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 8508c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE CTR"); 8518c8fff31SAndrew Thompson libusb20_tr_setup_control(xfer, usb_xfer->buffer, 8528c8fff31SAndrew Thompson (void *)(((uint8_t *) usb_xfer->buffer) + 8538c8fff31SAndrew Thompson sizeof(libusb_control_setup)), 8548c8fff31SAndrew Thompson usb_xfer->timeout); 8558c8fff31SAndrew Thompson break ; 8568c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 8578c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE ISO"); 8588c8fff31SAndrew Thompson iso_packets = libusb20_tr_get_max_frames(xfer); 8598c8fff31SAndrew Thompson if (usb_xfer->num_iso_packets > iso_packets) 8608c8fff31SAndrew Thompson usb_xfer->num_iso_packets = iso_packets; 8618c8fff31SAndrew Thompson for (i = 0 ; i < usb_xfer->num_iso_packets ; i++) { 8628c8fff31SAndrew Thompson libusb20_tr_setup_isoc(xfer, 8638c8fff31SAndrew Thompson usb_xfer->buffer, usb_xfer->length, i); 8648c8fff31SAndrew Thompson } 8658c8fff31SAndrew Thompson libusb20_tr_set_total_frames(xfer, i); 8668c8fff31SAndrew Thompson break ; 8678c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_BULK: 8688c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE BULK"); 8698c8fff31SAndrew Thompson libusb20_tr_setup_bulk(xfer, usb_xfer->buffer, 8708c8fff31SAndrew Thompson usb_xfer->length, usb_xfer->timeout); 8718c8fff31SAndrew Thompson break ; 8728c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_INTERRUPT: 8738c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE INTR"); 8748c8fff31SAndrew Thompson libusb20_tr_setup_intr(xfer, usb_xfer->buffer, 8758c8fff31SAndrew Thompson usb_xfer->length, usb_xfer->timeout); 8768c8fff31SAndrew Thompson break ; 8778c8fff31SAndrew Thompson } 8788c8fff31SAndrew Thompson libusb20_tr_submit(xfer); 8798c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 SUBMITED"); 8808c8fff31SAndrew Thompson break ; 8818c8fff31SAndrew Thompson default: 8828c8fff31SAndrew Thompson if (ctx->debug == LIBUSB_DEBUG_TRANSFER) 8838c8fff31SAndrew Thompson printf("LIBUSB TRANSFER DEFAULT 0x%x\n", status); 8848c8fff31SAndrew Thompson usb_xfer->actual_length = 0; 8858c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_CANCELLED; 8868c8fff31SAndrew Thompson 8878c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->flying_transfers_lock); 8888c8fff31SAndrew Thompson LIST_DEL(&usb_backend->list); 8898c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->flying_transfers_lock); 8908c8fff31SAndrew Thompson usb_xfer->callback(usb_xfer); 8918c8fff31SAndrew Thompson 8928c8fff31SAndrew Thompson break ; 8938c8fff31SAndrew Thompson } 8948c8fff31SAndrew Thompson 8958c8fff31SAndrew Thompson switch (status) { 8968c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_COMPLETED: 8978c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS COMPLETED"); 8988c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_COMPLETED; 8998c8fff31SAndrew Thompson break ; 9008c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_OVERFLOW: 9018c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR OVERFLOW"); 9028c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_OVERFLOW; 9038c8fff31SAndrew Thompson break ; 9048c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_NO_DEVICE: 9058c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR NO DEVICE"); 9068c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_NO_DEVICE; 9078c8fff31SAndrew Thompson break ; 9088c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_STALL: 9098c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR STALL"); 9108c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_STALL; 9118c8fff31SAndrew Thompson break ; 9128c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_CANCELLED: 9138c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR CANCELLED"); 9148c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_CANCELLED; 9158c8fff31SAndrew Thompson break ; 9168c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_TIMED_OUT: 9178c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR TIMEOUT"); 9188c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_TIMED_OUT; 9198c8fff31SAndrew Thompson break ; 9208c8fff31SAndrew Thompson case LIBUSB20_TRANSFER_ERROR: 9218c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "ERROR"); 9228c8fff31SAndrew Thompson usb_xfer->status = LIBUSB_TRANSFER_ERROR; 9238c8fff31SAndrew Thompson break ; 9248c8fff31SAndrew Thompson } 9258c8fff31SAndrew Thompson } 9268c8fff31SAndrew Thompson 9278c8fff31SAndrew Thompson static int 9288c8fff31SAndrew Thompson libusb_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 9298c8fff31SAndrew Thompson { 9308c8fff31SAndrew Thompson int ret; 9318c8fff31SAndrew Thompson int usb_speed; 9328c8fff31SAndrew Thompson 9338c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 9348c8fff31SAndrew Thompson 9358c8fff31SAndrew Thompson switch (xfer->type) { 9368c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 9378c8fff31SAndrew Thompson switch (usb_speed) { 9388c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 9398c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 9408c8fff31SAndrew Thompson ret = 60 * 1; 9418c8fff31SAndrew Thompson break ; 9428c8fff31SAndrew Thompson default : 9438c8fff31SAndrew Thompson ret = 60 * 8; 9448c8fff31SAndrew Thompson break ; 9458c8fff31SAndrew Thompson } 9468c8fff31SAndrew Thompson break ; 9478c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 9488c8fff31SAndrew Thompson ret = 2; 9498c8fff31SAndrew Thompson break ; 9508c8fff31SAndrew Thompson default: 9518c8fff31SAndrew Thompson ret = 1; 9528c8fff31SAndrew Thompson break ; 9538c8fff31SAndrew Thompson } 9548c8fff31SAndrew Thompson 9558c8fff31SAndrew Thompson return ret; 9568c8fff31SAndrew Thompson } 9578c8fff31SAndrew Thompson 9588c8fff31SAndrew Thompson static int 9598c8fff31SAndrew Thompson libusb_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 9608c8fff31SAndrew Thompson { 9618c8fff31SAndrew Thompson int ret; 9628c8fff31SAndrew Thompson int usb_speed; 9638c8fff31SAndrew Thompson 9648c8fff31SAndrew Thompson usb_speed = libusb20_dev_get_speed(pdev); 9658c8fff31SAndrew Thompson 9668c8fff31SAndrew Thompson switch (xfer->type) { 9678c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 9688c8fff31SAndrew Thompson ret = 0; 9698c8fff31SAndrew Thompson break ; 9708c8fff31SAndrew Thompson case LIBUSB_TRANSFER_TYPE_CONTROL: 9718c8fff31SAndrew Thompson switch (usb_speed) { 9728c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 9738c8fff31SAndrew Thompson ret = 8; 9748c8fff31SAndrew Thompson break ; 9758c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 9768c8fff31SAndrew Thompson ret = 64; 9778c8fff31SAndrew Thompson break ; 9788c8fff31SAndrew Thompson case LIBUSB20_SPEED_HIGH: 9798c8fff31SAndrew Thompson ret = 64; 9808c8fff31SAndrew Thompson break ; 9818c8fff31SAndrew Thompson } 9828c8fff31SAndrew Thompson /*add */ 9838c8fff31SAndrew Thompson ret += 8; 9848c8fff31SAndrew Thompson break ; 9858c8fff31SAndrew Thompson default : 9868c8fff31SAndrew Thompson switch (usb_speed) { 9878c8fff31SAndrew Thompson case LIBUSB20_SPEED_LOW: 9888c8fff31SAndrew Thompson ret = 256; 9898c8fff31SAndrew Thompson break ; 9908c8fff31SAndrew Thompson case LIBUSB20_SPEED_FULL: 9918c8fff31SAndrew Thompson ret = 4096; 9928c8fff31SAndrew Thompson break ; 9938c8fff31SAndrew Thompson default: 9948c8fff31SAndrew Thompson ret = 16384; 9958c8fff31SAndrew Thompson break ; 9968c8fff31SAndrew Thompson } 9978c8fff31SAndrew Thompson break ; 9988c8fff31SAndrew Thompson } 9998c8fff31SAndrew Thompson 10008c8fff31SAndrew Thompson return ret; 10018c8fff31SAndrew Thompson } 10028c8fff31SAndrew Thompson 10038c8fff31SAndrew Thompson int 10048c8fff31SAndrew Thompson libusb_submit_transfer(struct libusb_transfer *xfer) 10058c8fff31SAndrew Thompson { 10068c8fff31SAndrew Thompson struct libusb20_transfer **usb20_xfer; 10078c8fff31SAndrew Thompson struct usb_transfer *usb_backend; 10088c8fff31SAndrew Thompson struct usb_transfer *usb_node; 10098c8fff31SAndrew Thompson struct libusb20_device *pdev; 10108c8fff31SAndrew Thompson struct libusb_context *ctx; 10118c8fff31SAndrew Thompson struct timespec cur_ts; 10128c8fff31SAndrew Thompson struct timeval *cur_tv; 10138c8fff31SAndrew Thompson int maxframe; 10148c8fff31SAndrew Thompson int buffsize; 10158c8fff31SAndrew Thompson int num_frame; 10168c8fff31SAndrew Thompson int ep_idx; 10178c8fff31SAndrew Thompson int ret; 10188c8fff31SAndrew Thompson int i; 10198c8fff31SAndrew Thompson 10208c8fff31SAndrew Thompson if (xfer == NULL) 10218c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 10228c8fff31SAndrew Thompson 10238c8fff31SAndrew Thompson usb20_xfer = malloc(2 * sizeof(struct libusb20_transfer *)); 10248c8fff31SAndrew Thompson if (usb20_xfer == NULL) 10258c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 10268c8fff31SAndrew Thompson 10278c8fff31SAndrew Thompson ctx = xfer->dev_handle->dev->ctx; 10288c8fff31SAndrew Thompson pdev = xfer->dev_handle->os_priv; 10298c8fff31SAndrew Thompson 10308c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 10318c8fff31SAndrew Thompson 10328c8fff31SAndrew Thompson usb_backend = (struct usb_transfer *) ((uint8_t *)xfer - 10338c8fff31SAndrew Thompson sizeof(struct usb_transfer)); 10348c8fff31SAndrew Thompson usb_backend->transferred = 0; 10358c8fff31SAndrew Thompson usb_backend->flags = 0; 10368c8fff31SAndrew Thompson 10378c8fff31SAndrew Thompson if (xfer->timeout != 0) { 10388c8fff31SAndrew Thompson clock_gettime(CLOCK_MONOTONIC, &cur_ts); 10398c8fff31SAndrew Thompson cur_ts.tv_sec += xfer->timeout / 1000; 10408c8fff31SAndrew Thompson cur_ts.tv_nsec += (xfer->timeout % 1000) * 1000000; 10418c8fff31SAndrew Thompson 10428c8fff31SAndrew Thompson if (cur_ts.tv_nsec > 1000000000) { 10438c8fff31SAndrew Thompson cur_ts.tv_nsec -= 1000000000; 10448c8fff31SAndrew Thompson cur_ts.tv_sec++; 10458c8fff31SAndrew Thompson } 10468c8fff31SAndrew Thompson 10478c8fff31SAndrew Thompson TIMESPEC_TO_TIMEVAL(&usb_backend->timeout, &cur_ts); 10488c8fff31SAndrew Thompson } 10498c8fff31SAndrew Thompson 10508c8fff31SAndrew Thompson /*Add to flying list*/ 10518c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->flying_transfers_lock); 10528c8fff31SAndrew Thompson if (USB_LIST_EMPTY(&ctx->flying_transfers)) { 10538c8fff31SAndrew Thompson LIST_ADD(&usb_backend->list, &ctx->flying_transfers); 10548c8fff31SAndrew Thompson goto out; 10558c8fff31SAndrew Thompson } 10568c8fff31SAndrew Thompson if (timerisset(&usb_backend->timeout) == 0) { 10578c8fff31SAndrew Thompson LIST_ADD_TAIL(&usb_backend->list, &ctx->flying_transfers); 10588c8fff31SAndrew Thompson goto out; 10598c8fff31SAndrew Thompson } 10608c8fff31SAndrew Thompson LIST_FOREACH_ENTRY(usb_node, &ctx->flying_transfers, list) { 10618c8fff31SAndrew Thompson cur_tv = &usb_node->timeout; 10628c8fff31SAndrew Thompson if (timerisset(cur_tv) == 0 || 10638c8fff31SAndrew Thompson (cur_tv->tv_sec > usb_backend->timeout.tv_sec) || 10648c8fff31SAndrew Thompson (cur_tv->tv_sec == usb_backend->timeout.tv_sec && 10658c8fff31SAndrew Thompson cur_tv->tv_usec > usb_backend->timeout.tv_usec)) { 10668c8fff31SAndrew Thompson LIST_ADD_TAIL(&usb_backend->list, &usb_node->list); 10678c8fff31SAndrew Thompson goto out; 10688c8fff31SAndrew Thompson } 10698c8fff31SAndrew Thompson } 10708c8fff31SAndrew Thompson LIST_ADD_TAIL(&usb_backend->list, &ctx->flying_transfers); 10718c8fff31SAndrew Thompson 10728c8fff31SAndrew Thompson out: 10738c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->flying_transfers_lock); 10748c8fff31SAndrew Thompson 10758c8fff31SAndrew Thompson usb20_xfer[0] = libusb20_tr_get_pointer(pdev, 10768c8fff31SAndrew Thompson ((xfer->endpoint / 0x40) | (xfer->endpoint * 4)) % (16 * 4)); 10778c8fff31SAndrew Thompson usb20_xfer[1] = libusb20_tr_get_pointer(pdev, 10788c8fff31SAndrew Thompson (((xfer->endpoint / 0x40) | (xfer->endpoint * 4)) % (16 * 4)) + 1); 10798c8fff31SAndrew Thompson 10808c8fff31SAndrew Thompson if (usb20_xfer[0] == NULL) 10818c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 10828c8fff31SAndrew Thompson 10838c8fff31SAndrew Thompson xfer->os_priv = usb20_xfer; 10848c8fff31SAndrew Thompson 10858c8fff31SAndrew Thompson pthread_mutex_lock(&libusb20_lock); 10868c8fff31SAndrew Thompson 10878c8fff31SAndrew Thompson buffsize = libusb_get_buffsize(pdev, xfer); 10888c8fff31SAndrew Thompson maxframe = libusb_get_maxframe(pdev, xfer); 10898c8fff31SAndrew Thompson 10908c8fff31SAndrew Thompson ret = libusb20_tr_open(usb20_xfer[0], buffsize, 10918c8fff31SAndrew Thompson maxframe, xfer->endpoint); 10928c8fff31SAndrew Thompson if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) 10938c8fff31SAndrew Thompson ret |= libusb20_tr_open(usb20_xfer[1], buffsize, 10948c8fff31SAndrew Thompson maxframe, xfer->endpoint); 10958c8fff31SAndrew Thompson 10968c8fff31SAndrew Thompson if (ret != 0) { 10978c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 10988c8fff31SAndrew Thompson pthread_mutex_lock(&ctx->flying_transfers_lock); 10998c8fff31SAndrew Thompson LIST_DEL(&usb_backend->list); 11008c8fff31SAndrew Thompson pthread_mutex_unlock(&ctx->flying_transfers_lock); 11018c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 11028c8fff31SAndrew Thompson } 11038c8fff31SAndrew Thompson 11048c8fff31SAndrew Thompson libusb20_tr_set_priv_sc0(usb20_xfer[0], xfer); 11058c8fff31SAndrew Thompson libusb20_tr_set_callback(usb20_xfer[0], libusb10_proxy); 11068c8fff31SAndrew Thompson if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { 11078c8fff31SAndrew Thompson libusb20_tr_set_priv_sc0(usb20_xfer[1], xfer); 11088c8fff31SAndrew Thompson libusb20_tr_set_callback(usb20_xfer[1], libusb10_proxy); 11098c8fff31SAndrew Thompson } 11108c8fff31SAndrew Thompson 11118c8fff31SAndrew Thompson libusb20_tr_start(usb20_xfer[0]); 11128c8fff31SAndrew Thompson if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) 11138c8fff31SAndrew Thompson libusb20_tr_start(usb20_xfer[1]); 11148c8fff31SAndrew Thompson 11158c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 11168c8fff31SAndrew Thompson 11178c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave"); 11188c8fff31SAndrew Thompson return (0); 11198c8fff31SAndrew Thompson } 11208c8fff31SAndrew Thompson 11218c8fff31SAndrew Thompson int 11228c8fff31SAndrew Thompson libusb_cancel_transfer(struct libusb_transfer *xfer) 11238c8fff31SAndrew Thompson { 11248c8fff31SAndrew Thompson libusb_context *ctx; 11258c8fff31SAndrew Thompson 11268c8fff31SAndrew Thompson ctx = NULL; 11278c8fff31SAndrew Thompson GET_CONTEXT(ctx); 11288c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 11298c8fff31SAndrew Thompson 11308c8fff31SAndrew Thompson if (xfer == NULL) 11318c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 11328c8fff31SAndrew Thompson 11338c8fff31SAndrew Thompson pthread_mutex_lock(&libusb20_lock); 11348c8fff31SAndrew Thompson libusb20_tr_stop(xfer->os_priv); 11358c8fff31SAndrew Thompson pthread_mutex_unlock(&libusb20_lock); 11368c8fff31SAndrew Thompson 11378c8fff31SAndrew Thompson dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 11388c8fff31SAndrew Thompson return (0); 11398c8fff31SAndrew Thompson } 11408c8fff31SAndrew Thompson 1141