libusb10.c revision 195560
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 195560 2009-07-10 14:15:53Z thompsa $ */ 2194676Sthompsa/*- 3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4194676Sthompsa * 5194676Sthompsa * Redistribution and use in source and binary forms, with or without 6194676Sthompsa * modification, are permitted provided that the following conditions 7194676Sthompsa * are met: 8194676Sthompsa * 1. Redistributions of source code must retain the above copyright 9194676Sthompsa * notice, this list of conditions and the following disclaimer. 10194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 11194676Sthompsa * notice, this list of conditions and the following disclaimer in the 12194676Sthompsa * documentation and/or other materials provided with the distribution. 13194676Sthompsa * 14194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194676Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194676Sthompsa * SUCH DAMAGE. 25194676Sthompsa */ 26194676Sthompsa 27194676Sthompsa#include <sys/queue.h> 28194676Sthompsa#include <stdlib.h> 29194676Sthompsa#include <unistd.h> 30194676Sthompsa#include <stdio.h> 31194676Sthompsa#include <poll.h> 32194676Sthompsa#include <pthread.h> 33194676Sthompsa#include <time.h> 34194676Sthompsa#include <errno.h> 35194676Sthompsa 36194676Sthompsa#include "libusb20.h" 37194676Sthompsa#include "libusb20_desc.h" 38194676Sthompsa#include "libusb20_int.h" 39194676Sthompsa#include "libusb.h" 40194676Sthompsa#include "libusb10.h" 41194676Sthompsa 42194676Sthompsastatic pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 43194676Sthompsastruct libusb_context *usbi_default_context = NULL; 44194676Sthompsapthread_mutex_t libusb20_lock = PTHREAD_MUTEX_INITIALIZER; 45194676Sthompsa 46194676Sthompsa/* Library initialisation / deinitialisation */ 47194676Sthompsa 48194676Sthompsavoid 49194676Sthompsalibusb_set_debug(libusb_context * ctx, int level) 50194676Sthompsa{ 51194676Sthompsa GET_CONTEXT(ctx); 52194676Sthompsa if (ctx) 53194676Sthompsa ctx->debug = level; 54194676Sthompsa} 55194676Sthompsa 56194676Sthompsaint 57194676Sthompsalibusb_init(libusb_context ** context) 58194676Sthompsa{ 59194676Sthompsa struct libusb_context *ctx; 60194676Sthompsa char * debug; 61194676Sthompsa int ret; 62194676Sthompsa 63194676Sthompsa ctx = malloc(sizeof(*ctx)); 64194676Sthompsa if (!ctx) 65194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 66194676Sthompsa 67194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 68194676Sthompsa 69194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 70194676Sthompsa if (debug != NULL) { 71194676Sthompsa ctx->debug = atoi(debug); 72194676Sthompsa if (ctx->debug != 0) 73194676Sthompsa ctx->debug_fixed = 1; 74194676Sthompsa } 75194676Sthompsa 76194676Sthompsa pthread_mutex_init(&ctx->usb_devs_lock, NULL); 77194676Sthompsa pthread_mutex_init(&ctx->open_devs_lock, NULL); 78195560Sthompsa TAILQ_INIT(&ctx->usb_devs); 79195560Sthompsa TAILQ_INIT(&ctx->open_devs); 80194676Sthompsa 81194676Sthompsa pthread_mutex_init(&ctx->flying_transfers_lock, NULL); 82194676Sthompsa pthread_mutex_init(&ctx->pollfds_lock, NULL); 83194676Sthompsa pthread_mutex_init(&ctx->pollfd_modify_lock, NULL); 84194676Sthompsa pthread_mutex_init(&ctx->events_lock, NULL); 85194676Sthompsa pthread_mutex_init(&ctx->event_waiters_lock, NULL); 86194676Sthompsa pthread_cond_init(&ctx->event_waiters_cond, NULL); 87194676Sthompsa 88195560Sthompsa TAILQ_INIT(&ctx->flying_transfers); 89195560Sthompsa TAILQ_INIT(&ctx->pollfds); 90194676Sthompsa 91194676Sthompsa ret = pipe(ctx->ctrl_pipe); 92194676Sthompsa if (ret < 0) { 93194676Sthompsa usb_remove_pollfd(ctx, ctx->ctrl_pipe[0]); 94194676Sthompsa close(ctx->ctrl_pipe[0]); 95194676Sthompsa close(ctx->ctrl_pipe[1]); 96194676Sthompsa free(ctx); 97194676Sthompsa return (LIBUSB_ERROR_OTHER); 98194676Sthompsa } 99194676Sthompsa 100194676Sthompsa ret = usb_add_pollfd(ctx, ctx->ctrl_pipe[0], POLLIN); 101194676Sthompsa if (ret < 0) { 102194676Sthompsa usb_remove_pollfd(ctx, ctx->ctrl_pipe[0]); 103194676Sthompsa close(ctx->ctrl_pipe[0]); 104194676Sthompsa close(ctx->ctrl_pipe[1]); 105194676Sthompsa free(ctx); 106194676Sthompsa return ret; 107194676Sthompsa } 108194676Sthompsa 109194676Sthompsa pthread_mutex_lock(&default_context_lock); 110194676Sthompsa if (usbi_default_context == NULL) { 111194676Sthompsa usbi_default_context = ctx; 112194676Sthompsa } 113194676Sthompsa pthread_mutex_unlock(&default_context_lock); 114194676Sthompsa 115194676Sthompsa if (context) 116194676Sthompsa *context = ctx; 117194676Sthompsa 118194676Sthompsa return (0); 119194676Sthompsa} 120194676Sthompsa 121194676Sthompsavoid 122194676Sthompsalibusb_exit(libusb_context * ctx) 123194676Sthompsa{ 124194676Sthompsa GET_CONTEXT(ctx); 125194676Sthompsa 126195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_exit enter"); 127194676Sthompsa usb_remove_pollfd(ctx, ctx->ctrl_pipe[0]); 128194676Sthompsa close(ctx->ctrl_pipe[0]); 129194676Sthompsa close(ctx->ctrl_pipe[1]); 130194676Sthompsa 131194676Sthompsa pthread_mutex_lock(&default_context_lock); 132194676Sthompsa if (ctx == usbi_default_context) { 133194676Sthompsa usbi_default_context = NULL; 134194676Sthompsa } 135194676Sthompsa pthread_mutex_unlock(&default_context_lock); 136194676Sthompsa 137194676Sthompsa free(ctx); 138195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_exit leave"); 139194676Sthompsa} 140194676Sthompsa 141194676Sthompsa/* Device handling and initialisation. */ 142194676Sthompsa 143194676Sthompsassize_t 144194676Sthompsalibusb_get_device_list(libusb_context * ctx, libusb_device *** list) 145194676Sthompsa{ 146194676Sthompsa struct libusb20_device *pdev; 147194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 148194676Sthompsa struct libusb_device *dev; 149194676Sthompsa struct libusb20_backend *usb_backend; 150194676Sthompsa int i; 151194676Sthompsa 152194676Sthompsa GET_CONTEXT(ctx); 153195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_list enter"); 154194676Sthompsa 155194676Sthompsa usb_backend = libusb20_be_alloc_default(); 156194676Sthompsa if (usb_backend == NULL) 157194676Sthompsa return (-1); 158194676Sthompsa 159194676Sthompsa pdev = NULL; 160194676Sthompsa i = 0; 161194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 162194676Sthompsa i++; 163194676Sthompsa 164194676Sthompsa if (list == NULL) { 165194676Sthompsa libusb20_be_free(usb_backend); 166194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 167194676Sthompsa } 168194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 169194676Sthompsa if (*list == NULL) { 170194676Sthompsa libusb20_be_free(usb_backend); 171194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 172194676Sthompsa } 173194676Sthompsa i = 0; 174194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 175194676Sthompsa /* get device into libUSB v1.0 list */ 176194676Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 177194676Sthompsa 178194676Sthompsa ddesc = libusb20_dev_get_device_desc(pdev); 179194676Sthompsa dev = malloc(sizeof(*dev)); 180194676Sthompsa if (dev == NULL) { 181195560Sthompsa while (i != 0) { 182195560Sthompsa libusb_unref_device((*list)[i - 1]); 183195560Sthompsa i--; 184195560Sthompsa } 185194676Sthompsa free(*list); 186194676Sthompsa libusb20_be_free(usb_backend); 187194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 188194676Sthompsa } 189194676Sthompsa memset(dev, 0, sizeof(*dev)); 190194676Sthompsa 191194676Sthompsa pthread_mutex_init(&dev->lock, NULL); 192194676Sthompsa dev->ctx = ctx; 193194676Sthompsa dev->bus_number = pdev->bus_number; 194194676Sthompsa dev->device_address = pdev->device_address; 195194676Sthompsa dev->num_configurations = ddesc->bNumConfigurations; 196194676Sthompsa 197194676Sthompsa /* link together the two structures */ 198194676Sthompsa dev->os_priv = pdev; 199194676Sthompsa 200194676Sthompsa pthread_mutex_lock(&ctx->usb_devs_lock); 201195560Sthompsa TAILQ_INSERT_HEAD(&ctx->usb_devs, dev, list); 202194676Sthompsa pthread_mutex_unlock(&ctx->usb_devs_lock); 203194676Sthompsa 204194676Sthompsa (*list)[i] = libusb_ref_device(dev); 205194676Sthompsa i++; 206194676Sthompsa } 207194676Sthompsa (*list)[i] = NULL; 208194676Sthompsa 209194676Sthompsa libusb20_be_free(usb_backend); 210195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_list leave"); 211194676Sthompsa return (i); 212194676Sthompsa} 213194676Sthompsa 214194676Sthompsa/* 215194676Sthompsa * In this function we cant free all the device contained into list because 216194676Sthompsa * open_with_pid_vid use some node of list after the free_device_list. 217194676Sthompsa */ 218194676Sthompsavoid 219194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 220194676Sthompsa{ 221194676Sthompsa int i; 222194676Sthompsa libusb_context *ctx; 223194676Sthompsa 224194676Sthompsa ctx = NULL; 225194676Sthompsa GET_CONTEXT(ctx); 226195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_device_list enter"); 227194676Sthompsa 228194676Sthompsa if (list == NULL) 229194676Sthompsa return ; 230194676Sthompsa 231194676Sthompsa if (unref_devices) { 232194676Sthompsa for (i = 0; list[i] != NULL; i++) 233194676Sthompsa libusb_unref_device(list[i]); 234194676Sthompsa } 235194676Sthompsa free(list); 236195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_device_list leave"); 237194676Sthompsa} 238194676Sthompsa 239194676Sthompsauint8_t 240194676Sthompsalibusb_get_bus_number(libusb_device * dev) 241194676Sthompsa{ 242194676Sthompsa libusb_context *ctx; 243194676Sthompsa 244194676Sthompsa ctx = NULL; 245194676Sthompsa GET_CONTEXT(ctx); 246195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_bus_number enter"); 247194676Sthompsa 248194676Sthompsa if (dev == NULL) 249194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 250195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_bus_number leave"); 251194676Sthompsa return (dev->bus_number); 252194676Sthompsa} 253194676Sthompsa 254194676Sthompsauint8_t 255194676Sthompsalibusb_get_device_address(libusb_device * dev) 256194676Sthompsa{ 257194676Sthompsa libusb_context *ctx; 258194676Sthompsa 259194676Sthompsa ctx = NULL; 260194676Sthompsa GET_CONTEXT(ctx); 261195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_address enter"); 262194676Sthompsa 263194676Sthompsa if (dev == NULL) 264194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 265195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_address leave"); 266194676Sthompsa return (dev->device_address); 267194676Sthompsa} 268194676Sthompsa 269194676Sthompsaint 270194676Sthompsalibusb_get_max_packet_size(libusb_device *dev, unsigned char endpoint) 271194676Sthompsa{ 272194676Sthompsa struct libusb_config_descriptor *pdconf; 273194676Sthompsa struct libusb_interface *pinf; 274194676Sthompsa struct libusb_interface_descriptor *pdinf; 275194676Sthompsa struct libusb_endpoint_descriptor *pdend; 276194676Sthompsa libusb_context *ctx; 277194676Sthompsa int i, j, k, ret; 278194676Sthompsa 279194676Sthompsa ctx = NULL; 280194676Sthompsa GET_CONTEXT(ctx); 281195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_max_packet_size enter"); 282194676Sthompsa 283194676Sthompsa if (dev == NULL) 284194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 285194676Sthompsa 286194676Sthompsa if (libusb_get_active_config_descriptor(dev, &pdconf) < 0) 287194676Sthompsa return (LIBUSB_ERROR_OTHER); 288194676Sthompsa 289194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 290194676Sthompsa for (i = 0 ; i < pdconf->bNumInterfaces ; i++) { 291194676Sthompsa pinf = &pdconf->interface[i]; 292194676Sthompsa for (j = 0 ; j < pinf->num_altsetting ; j++) { 293194676Sthompsa pdinf = &pinf->altsetting[j]; 294194676Sthompsa for (k = 0 ; k < pdinf->bNumEndpoints ; k++) { 295194676Sthompsa pdend = &pdinf->endpoint[k]; 296194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 297194676Sthompsa ret = pdend->wMaxPacketSize; 298194676Sthompsa goto out; 299194676Sthompsa } 300194676Sthompsa } 301194676Sthompsa } 302194676Sthompsa } 303194676Sthompsa 304194676Sthompsaout: 305194676Sthompsa libusb_free_config_descriptor(pdconf); 306195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_max_packet_size leave"); 307194676Sthompsa return (ret); 308194676Sthompsa} 309194676Sthompsa 310194676Sthompsalibusb_device * 311194676Sthompsalibusb_ref_device(libusb_device * dev) 312194676Sthompsa{ 313194676Sthompsa libusb_context *ctx; 314194676Sthompsa 315194676Sthompsa ctx = NULL; 316194676Sthompsa GET_CONTEXT(ctx); 317195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_ref_device enter"); 318194676Sthompsa 319194676Sthompsa if (dev == NULL) 320194676Sthompsa return (NULL); 321194676Sthompsa 322194676Sthompsa pthread_mutex_lock(&dev->lock); 323194676Sthompsa dev->refcnt++; 324194676Sthompsa pthread_mutex_unlock(&dev->lock); 325194676Sthompsa 326195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_ref_device leave"); 327194676Sthompsa return (dev); 328194676Sthompsa} 329194676Sthompsa 330194676Sthompsavoid 331194676Sthompsalibusb_unref_device(libusb_device * dev) 332194676Sthompsa{ 333194676Sthompsa libusb_context *ctx; 334194676Sthompsa 335194676Sthompsa ctx = NULL; 336194676Sthompsa GET_CONTEXT(ctx); 337195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unref_device enter"); 338194676Sthompsa 339194676Sthompsa if (dev == NULL) 340194676Sthompsa return; 341194676Sthompsa 342194676Sthompsa pthread_mutex_lock(&dev->lock); 343194676Sthompsa dev->refcnt--; 344194676Sthompsa pthread_mutex_unlock(&dev->lock); 345194676Sthompsa 346194676Sthompsa if (dev->refcnt == 0) { 347194676Sthompsa pthread_mutex_lock(&dev->ctx->usb_devs_lock); 348195560Sthompsa TAILQ_REMOVE(&ctx->usb_devs, dev, list); 349194676Sthompsa pthread_mutex_unlock(&dev->ctx->usb_devs_lock); 350194676Sthompsa 351194676Sthompsa libusb20_dev_free(dev->os_priv); 352194676Sthompsa free(dev); 353194676Sthompsa } 354195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unref_device leave"); 355194676Sthompsa} 356194676Sthompsa 357194676Sthompsaint 358194676Sthompsalibusb_open(libusb_device * dev, libusb_device_handle **devh) 359194676Sthompsa{ 360194676Sthompsa libusb_context *ctx = dev->ctx; 361194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 362194676Sthompsa libusb_device_handle *hdl; 363194676Sthompsa unsigned char dummy; 364194676Sthompsa int err; 365194676Sthompsa 366194676Sthompsa GET_CONTEXT(ctx); 367195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open enter"); 368194676Sthompsa 369194676Sthompsa dummy = 1; 370194676Sthompsa if (devh == NULL) 371194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 372194676Sthompsa 373194676Sthompsa hdl = malloc(sizeof(*hdl)); 374194676Sthompsa if (hdl == NULL) 375194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 376194676Sthompsa 377194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 378194676Sthompsa if (err) { 379194676Sthompsa free(hdl); 380194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 381194676Sthompsa } 382194676Sthompsa memset(hdl, 0, sizeof(*hdl)); 383194676Sthompsa pthread_mutex_init(&hdl->lock, NULL); 384194676Sthompsa 385195560Sthompsa TAILQ_INIT(&hdl->ep_list); 386194676Sthompsa hdl->dev = libusb_ref_device(dev); 387194676Sthompsa hdl->claimed_interfaces = 0; 388194676Sthompsa hdl->os_priv = dev->os_priv; 389194676Sthompsa err = usb_add_pollfd(ctx, libusb20_dev_get_fd(pdev), POLLIN | 390194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 391194676Sthompsa if (err < 0) { 392194676Sthompsa libusb_unref_device(dev); 393194676Sthompsa free(hdl); 394194676Sthompsa return (err); 395194676Sthompsa } 396194676Sthompsa 397194676Sthompsa pthread_mutex_lock(&ctx->open_devs_lock); 398195560Sthompsa TAILQ_INSERT_HEAD(&ctx->open_devs, hdl, list); 399194676Sthompsa pthread_mutex_unlock(&ctx->open_devs_lock); 400194676Sthompsa 401194676Sthompsa *devh = hdl; 402194676Sthompsa 403194676Sthompsa pthread_mutex_lock(&ctx->pollfd_modify_lock); 404194676Sthompsa ctx->pollfd_modify++; 405194676Sthompsa pthread_mutex_unlock(&ctx->pollfd_modify_lock); 406194676Sthompsa 407194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 408194676Sthompsa if (err <= 0) { 409194676Sthompsa pthread_mutex_lock(&ctx->pollfd_modify_lock); 410194676Sthompsa ctx->pollfd_modify--; 411194676Sthompsa pthread_mutex_unlock(&ctx->pollfd_modify_lock); 412194676Sthompsa return 0; 413194676Sthompsa } 414194676Sthompsa 415194676Sthompsa libusb_lock_events(ctx); 416194676Sthompsa read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); 417194676Sthompsa pthread_mutex_lock(&ctx->pollfd_modify_lock); 418194676Sthompsa ctx->pollfd_modify--; 419194676Sthompsa pthread_mutex_unlock(&ctx->pollfd_modify_lock); 420194676Sthompsa libusb_unlock_events(ctx); 421194676Sthompsa 422195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open leave"); 423194676Sthompsa return (0); 424194676Sthompsa} 425194676Sthompsa 426194676Sthompsalibusb_device_handle * 427194676Sthompsalibusb_open_device_with_vid_pid(libusb_context * ctx, uint16_t vendor_id, 428194676Sthompsa uint16_t product_id) 429194676Sthompsa{ 430194676Sthompsa struct libusb_device **devs; 431194676Sthompsa struct libusb_device_handle *devh; 432194676Sthompsa struct libusb20_device *pdev; 433194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 434194676Sthompsa int i, j; 435194676Sthompsa 436194676Sthompsa GET_CONTEXT(ctx); 437195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 438194676Sthompsa 439194676Sthompsa devh = NULL; 440194676Sthompsa 441194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 442194676Sthompsa return (NULL); 443194676Sthompsa 444194676Sthompsa for (j = 0; j < i; j++) { 445194676Sthompsa pdev = (struct libusb20_device *)devs[j]->os_priv; 446194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 447194676Sthompsa if (pdesc->idVendor == vendor_id && 448195560Sthompsa pdesc->idProduct == product_id) { 449194676Sthompsa if (libusb_open(devs[j], &devh) < 0) 450194676Sthompsa devh = NULL; 451195560Sthompsa break ; 452195560Sthompsa } 453194676Sthompsa } 454194676Sthompsa 455194676Sthompsa libusb_free_device_list(devs, 1); 456195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 457194676Sthompsa return (devh); 458194676Sthompsa} 459194676Sthompsa 460194676Sthompsavoid 461194676Sthompsalibusb_close(libusb_device_handle * devh) 462194676Sthompsa{ 463194676Sthompsa libusb_context *ctx; 464194676Sthompsa struct libusb20_device *pdev; 465195560Sthompsa struct usb_ep_tr *eptr; 466194676Sthompsa unsigned char dummy = 1; 467194676Sthompsa int err; 468194676Sthompsa 469194676Sthompsa if (devh == NULL) 470194676Sthompsa return ; 471194676Sthompsa 472194676Sthompsa ctx = devh->dev->ctx; 473194676Sthompsa pdev = devh->os_priv; 474194676Sthompsa 475194676Sthompsa GET_CONTEXT(ctx); 476195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close enter"); 477194676Sthompsa 478194676Sthompsa pthread_mutex_lock(&ctx->pollfd_modify_lock); 479194676Sthompsa ctx->pollfd_modify++; 480194676Sthompsa pthread_mutex_unlock(&ctx->pollfd_modify_lock); 481194676Sthompsa 482194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 483194676Sthompsa 484194676Sthompsa if (err <= 0) { 485194676Sthompsa pthread_mutex_lock(&ctx->open_devs_lock); 486195560Sthompsa TAILQ_REMOVE(&ctx->open_devs, devh, list); 487194676Sthompsa pthread_mutex_unlock(&ctx->open_devs_lock); 488194676Sthompsa 489194676Sthompsa usb_remove_pollfd(ctx, libusb20_dev_get_fd(pdev)); 490195560Sthompsa libusb20_dev_close(pdev); 491194676Sthompsa libusb_unref_device(devh->dev); 492195560Sthompsa TAILQ_FOREACH(eptr, &devh->ep_list, list) { 493195560Sthompsa TAILQ_REMOVE(&devh->ep_list, eptr, list); 494195560Sthompsa libusb20_tr_close(((struct libusb20_transfer **) 495195560Sthompsa eptr->os_priv)[0]); 496195560Sthompsa if (eptr->flags) 497195560Sthompsa libusb20_tr_close(((struct libusb20_transfer **) 498195560Sthompsa eptr->os_priv)[1]); 499195560Sthompsa free((struct libusb20_transfer **)eptr->os_priv); 500195560Sthompsa } 501194676Sthompsa free(devh); 502194676Sthompsa 503194676Sthompsa pthread_mutex_lock(&ctx->pollfd_modify_lock); 504194676Sthompsa ctx->pollfd_modify--; 505194676Sthompsa pthread_mutex_unlock(&ctx->pollfd_modify_lock); 506194676Sthompsa return ; 507194676Sthompsa } 508194676Sthompsa libusb_lock_events(ctx); 509194676Sthompsa 510194676Sthompsa read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); 511194676Sthompsa pthread_mutex_lock(&ctx->open_devs_lock); 512195560Sthompsa TAILQ_REMOVE(&ctx->open_devs, devh, list); 513194676Sthompsa pthread_mutex_unlock(&ctx->open_devs_lock); 514194676Sthompsa 515194676Sthompsa usb_remove_pollfd(ctx, libusb20_dev_get_fd(pdev)); 516195560Sthompsa libusb20_dev_close(pdev); 517194676Sthompsa libusb_unref_device(devh->dev); 518195560Sthompsa TAILQ_FOREACH(eptr, &devh->ep_list, list) { 519195560Sthompsa TAILQ_REMOVE(&devh->ep_list, eptr, list); 520195560Sthompsa libusb20_tr_close(((struct libusb20_transfer **) 521195560Sthompsa eptr->os_priv)[0]); 522195560Sthompsa if (eptr->flags) 523195560Sthompsa libusb20_tr_close(((struct libusb20_transfer **) 524195560Sthompsa eptr->os_priv)[1]); 525195560Sthompsa free((struct libusb20_transfer **)eptr->os_priv); 526195560Sthompsa } 527194676Sthompsa free(devh); 528194676Sthompsa 529194676Sthompsa pthread_mutex_lock(&ctx->pollfd_modify_lock); 530194676Sthompsa ctx->pollfd_modify--; 531194676Sthompsa pthread_mutex_unlock(&ctx->pollfd_modify_lock); 532194676Sthompsa 533194676Sthompsa libusb_unlock_events(ctx); 534195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close leave"); 535194676Sthompsa} 536194676Sthompsa 537194676Sthompsalibusb_device * 538194676Sthompsalibusb_get_device(libusb_device_handle * devh) 539194676Sthompsa{ 540194676Sthompsa libusb_context *ctx; 541194676Sthompsa 542194676Sthompsa ctx = NULL; 543194676Sthompsa GET_CONTEXT(ctx); 544195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device enter"); 545194676Sthompsa 546194676Sthompsa if (devh == NULL) 547194676Sthompsa return (NULL); 548194676Sthompsa 549195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device leave"); 550194676Sthompsa return (devh->dev); 551194676Sthompsa} 552194676Sthompsa 553194676Sthompsaint 554194676Sthompsalibusb_get_configuration(libusb_device_handle * devh, int *config) 555194676Sthompsa{ 556194676Sthompsa libusb_context *ctx; 557194676Sthompsa 558194676Sthompsa ctx = NULL; 559194676Sthompsa GET_CONTEXT(ctx); 560195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_configuration enter"); 561194676Sthompsa 562194676Sthompsa if (devh == NULL || config == NULL) 563194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 564194676Sthompsa 565194676Sthompsa *config = libusb20_dev_get_config_index((struct libusb20_device *) 566194676Sthompsa devh->dev->os_priv); 567194676Sthompsa 568195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_configuration leave"); 569194676Sthompsa return (0); 570194676Sthompsa} 571194676Sthompsa 572194676Sthompsaint 573194676Sthompsalibusb_set_configuration(libusb_device_handle * devh, int configuration) 574194676Sthompsa{ 575194676Sthompsa struct libusb20_device *pdev; 576194676Sthompsa libusb_context *ctx; 577194676Sthompsa 578194676Sthompsa ctx = NULL; 579194676Sthompsa GET_CONTEXT(ctx); 580195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_configuration enter"); 581194676Sthompsa 582194676Sthompsa if (devh == NULL) 583194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 584194676Sthompsa 585194676Sthompsa pdev = (struct libusb20_device *)devh->dev->os_priv; 586194676Sthompsa 587195560Sthompsa libusb20_dev_set_config_index(pdev, configuration); 588195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_configuration leave"); 589194676Sthompsa return (0); 590194676Sthompsa} 591194676Sthompsa 592194676Sthompsaint 593194676Sthompsalibusb_claim_interface(libusb_device_handle * dev, int interface_number) 594194676Sthompsa{ 595194676Sthompsa libusb_context *ctx; 596194676Sthompsa int ret = 0; 597194676Sthompsa 598194676Sthompsa ctx = NULL; 599194676Sthompsa GET_CONTEXT(ctx); 600195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_claim_interface enter"); 601194676Sthompsa 602194676Sthompsa if (dev == NULL) 603194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 604194676Sthompsa 605194676Sthompsa if (interface_number >= sizeof(dev->claimed_interfaces) * 8) 606194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 607194676Sthompsa 608194676Sthompsa pthread_mutex_lock(&(dev->lock)); 609194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 610194676Sthompsa ret = LIBUSB_ERROR_BUSY; 611194676Sthompsa 612194676Sthompsa if (!ret) 613194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 614194676Sthompsa pthread_mutex_unlock(&(dev->lock)); 615194676Sthompsa 616195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_claim_interface leave"); 617194676Sthompsa return (ret); 618194676Sthompsa} 619194676Sthompsa 620194676Sthompsaint 621194676Sthompsalibusb_release_interface(libusb_device_handle * dev, int interface_number) 622194676Sthompsa{ 623194676Sthompsa libusb_context *ctx; 624194676Sthompsa int ret; 625194676Sthompsa 626194676Sthompsa ctx = NULL; 627194676Sthompsa GET_CONTEXT(ctx); 628195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_release_interface enter"); 629194676Sthompsa 630194676Sthompsa ret = 0; 631194676Sthompsa if (dev == NULL) 632194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 633194676Sthompsa 634194676Sthompsa if (interface_number >= sizeof(dev->claimed_interfaces) * 8) 635194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 636194676Sthompsa 637194676Sthompsa pthread_mutex_lock(&(dev->lock)); 638194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 639194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 640194676Sthompsa 641194676Sthompsa if (!ret) 642194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 643194676Sthompsa pthread_mutex_unlock(&(dev->lock)); 644194676Sthompsa 645195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_release_interface leave"); 646194676Sthompsa return (ret); 647194676Sthompsa} 648194676Sthompsa 649194676Sthompsaint 650194676Sthompsalibusb_set_interface_alt_setting(libusb_device_handle * dev, 651194676Sthompsa int interface_number, int alternate_setting) 652194676Sthompsa{ 653194676Sthompsa libusb_context *ctx; 654194676Sthompsa 655194676Sthompsa ctx = NULL; 656194676Sthompsa GET_CONTEXT(ctx); 657195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_interface_alt_setting enter"); 658194676Sthompsa 659194676Sthompsa if (dev == NULL) 660194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 661194676Sthompsa 662194676Sthompsa if (interface_number >= sizeof(dev->claimed_interfaces) *8) 663194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 664194676Sthompsa 665194676Sthompsa pthread_mutex_lock(&dev->lock); 666194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) { 667194676Sthompsa pthread_mutex_unlock(&dev->lock); 668194676Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 669194676Sthompsa } 670194676Sthompsa pthread_mutex_unlock(&dev->lock); 671194676Sthompsa 672194676Sthompsa if (libusb20_dev_set_alt_index(dev->os_priv, interface_number, 673194676Sthompsa alternate_setting) != 0) 674194676Sthompsa return (LIBUSB_ERROR_OTHER); 675194676Sthompsa 676195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_interface_alt_setting leave"); 677194676Sthompsa return (0); 678194676Sthompsa} 679194676Sthompsa 680194676Sthompsaint 681194676Sthompsalibusb_clear_halt(libusb_device_handle * devh, unsigned char endpoint) 682194676Sthompsa{ 683194676Sthompsa struct libusb20_transfer *xfer; 684195560Sthompsa struct libusb20_device *pdev; 685194676Sthompsa libusb_context *ctx; 686194676Sthompsa int ret; 687194676Sthompsa 688194676Sthompsa ctx = NULL; 689194676Sthompsa GET_CONTEXT(ctx); 690195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_clear_halt enter"); 691195560Sthompsa 692195560Sthompsa pdev = devh->os_priv; 693195560Sthompsa xfer = libusb20_tr_get_pointer(pdev, 694195560Sthompsa ((endpoint / 0x40) | (endpoint * 4)) % (16 * 4)); 695195560Sthompsa if (xfer == NULL) 696195560Sthompsa return (LIBUSB_ERROR_NO_MEM); 697194676Sthompsa 698194676Sthompsa pthread_mutex_lock(&libusb20_lock); 699194676Sthompsa ret = libusb20_tr_open(xfer, 0, 0, endpoint); 700194676Sthompsa if (ret != 0 && ret != LIBUSB20_ERROR_BUSY) { 701194676Sthompsa pthread_mutex_unlock(&libusb20_lock); 702194676Sthompsa return (LIBUSB_ERROR_OTHER); 703194676Sthompsa } 704194676Sthompsa 705194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 706194676Sthompsa if (ret == 0) /* check if we have open the device */ 707194676Sthompsa libusb20_tr_close(xfer); 708194676Sthompsa pthread_mutex_unlock(&libusb20_lock); 709194676Sthompsa 710195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_clear_halt leave"); 711194676Sthompsa return (0); 712194676Sthompsa} 713194676Sthompsa 714194676Sthompsaint 715194676Sthompsalibusb_reset_device(libusb_device_handle * dev) 716194676Sthompsa{ 717194676Sthompsa libusb_context *ctx; 718194676Sthompsa 719194676Sthompsa ctx = NULL; 720194676Sthompsa GET_CONTEXT(ctx); 721195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_reset_device enter"); 722194676Sthompsa 723194676Sthompsa if (dev == NULL) 724194676Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 725194676Sthompsa 726194676Sthompsa libusb20_dev_reset(dev->os_priv); 727195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_reset_device leave"); 728194676Sthompsa return (0); 729194676Sthompsa} 730194676Sthompsa 731194676Sthompsaint 732194676Sthompsalibusb_kernel_driver_active(libusb_device_handle * devh, int interface) 733194676Sthompsa{ 734194676Sthompsa libusb_context *ctx; 735194676Sthompsa 736194676Sthompsa ctx = NULL; 737194676Sthompsa GET_CONTEXT(ctx); 738195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_kernel_driver_active enter"); 739194676Sthompsa 740194676Sthompsa if (devh == NULL) 741194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 742194676Sthompsa 743195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_kernel_driver_active leave"); 744194676Sthompsa return (libusb20_dev_kernel_driver_active(devh->os_priv, interface)); 745194676Sthompsa} 746194676Sthompsa 747194676Sthompsaint 748194676Sthompsalibusb_detach_kernel_driver(libusb_device_handle * devh, int interface) 749194676Sthompsa{ 750194676Sthompsa struct libusb20_device *pdev; 751194676Sthompsa libusb_context *ctx; 752194676Sthompsa 753194676Sthompsa ctx = NULL; 754194676Sthompsa GET_CONTEXT(ctx); 755195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_detach_kernel_driver enter"); 756194676Sthompsa 757194676Sthompsa if (devh == NULL) 758194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 759194676Sthompsa 760194676Sthompsa pdev = (struct libusb20_device *)devh->dev->os_priv; 761194676Sthompsa if (libusb20_dev_detach_kernel_driver(pdev, interface) == LIBUSB20_ERROR_OTHER) 762194676Sthompsa return (LIBUSB_ERROR_OTHER); 763194676Sthompsa 764195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_detach_kernel_driver leave"); 765194676Sthompsa return (0); 766194676Sthompsa} 767194676Sthompsa 768194676Sthompsa/* 769194676Sthompsa * stub function. 770194676Sthompsa * libusb20 doesn't support this feature. 771194676Sthompsa */ 772194676Sthompsaint 773194676Sthompsalibusb_attach_kernel_driver(libusb_device_handle * devh, int interface) 774194676Sthompsa{ 775194676Sthompsa libusb_context *ctx; 776194676Sthompsa 777194676Sthompsa ctx = NULL; 778194676Sthompsa GET_CONTEXT(ctx); 779195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_attach_kernel_driver enter"); 780194676Sthompsa 781194676Sthompsa if (devh == NULL) 782194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 783194676Sthompsa 784195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_attach_kernel_driver leave"); 785194676Sthompsa return (0); 786194676Sthompsa} 787194676Sthompsa 788194676Sthompsa/* Asynchronous device I/O */ 789194676Sthompsa 790194676Sthompsastruct libusb_transfer * 791194676Sthompsalibusb_alloc_transfer(int iso_packets) 792194676Sthompsa{ 793194676Sthompsa struct libusb_transfer *xfer; 794194676Sthompsa struct usb_transfer *bxfer; 795194676Sthompsa libusb_context *ctx; 796194676Sthompsa int len; 797194676Sthompsa 798194676Sthompsa ctx = NULL; 799194676Sthompsa GET_CONTEXT(ctx); 800195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_alloc_transfer enter"); 801194676Sthompsa 802194676Sthompsa len = sizeof(struct libusb_transfer) + 803194676Sthompsa sizeof(struct usb_transfer) + 804194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 805194676Sthompsa 806194676Sthompsa bxfer = malloc(len); 807194676Sthompsa if (bxfer == NULL) 808194676Sthompsa return (NULL); 809194676Sthompsa 810194676Sthompsa memset(bxfer, 0, len); 811194676Sthompsa bxfer->num_iso_packets = iso_packets; 812194676Sthompsa 813194676Sthompsa xfer = (struct libusb_transfer *) ((uint8_t *)bxfer + 814194676Sthompsa sizeof(struct usb_transfer)); 815194676Sthompsa 816195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_alloc_transfer leave"); 817194676Sthompsa return (xfer); 818194676Sthompsa} 819194676Sthompsa 820194676Sthompsavoid 821194676Sthompsalibusb_free_transfer(struct libusb_transfer *xfer) 822194676Sthompsa{ 823194676Sthompsa struct usb_transfer *bxfer; 824194676Sthompsa libusb_context *ctx; 825194676Sthompsa 826194676Sthompsa ctx = NULL; 827194676Sthompsa GET_CONTEXT(ctx); 828195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_transfer enter"); 829194676Sthompsa 830194676Sthompsa if (xfer == NULL) 831194676Sthompsa return ; 832194676Sthompsa 833194676Sthompsa bxfer = (struct usb_transfer *) ((uint8_t *)xfer - 834194676Sthompsa sizeof(struct usb_transfer)); 835194676Sthompsa 836194676Sthompsa free(bxfer); 837195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_transfer leave"); 838194676Sthompsa return; 839194676Sthompsa} 840194676Sthompsa 841195560Sthompsastatic int 842195560Sthompsalibusb_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 843195560Sthompsa{ 844195560Sthompsa int ret; 845195560Sthompsa int usb_speed; 846195560Sthompsa 847195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 848195560Sthompsa 849195560Sthompsa switch (xfer->type) { 850195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 851195560Sthompsa switch (usb_speed) { 852195560Sthompsa case LIBUSB20_SPEED_LOW: 853195560Sthompsa case LIBUSB20_SPEED_FULL: 854195560Sthompsa ret = 60 * 1; 855195560Sthompsa break ; 856195560Sthompsa default : 857195560Sthompsa ret = 60 * 8; 858195560Sthompsa break ; 859195560Sthompsa } 860195560Sthompsa break ; 861195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 862195560Sthompsa ret = 2; 863195560Sthompsa break ; 864195560Sthompsa default: 865195560Sthompsa ret = 1; 866195560Sthompsa break ; 867195560Sthompsa } 868195560Sthompsa 869195560Sthompsa return ret; 870195560Sthompsa} 871195560Sthompsa 872195560Sthompsastatic int 873195560Sthompsalibusb_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 874195560Sthompsa{ 875195560Sthompsa int ret; 876195560Sthompsa int usb_speed; 877195560Sthompsa 878195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 879195560Sthompsa 880195560Sthompsa switch (xfer->type) { 881195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 882195560Sthompsa ret = 0; 883195560Sthompsa break ; 884195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 885195560Sthompsa switch (usb_speed) { 886195560Sthompsa case LIBUSB20_SPEED_LOW: 887195560Sthompsa ret = 8; 888195560Sthompsa break ; 889195560Sthompsa case LIBUSB20_SPEED_FULL: 890195560Sthompsa ret = 64; 891195560Sthompsa break ; 892195560Sthompsa default: 893195560Sthompsa ret = 64; 894195560Sthompsa break ; 895195560Sthompsa } 896195560Sthompsa ret += 8; 897195560Sthompsa break ; 898195560Sthompsa default : 899195560Sthompsa switch (usb_speed) { 900195560Sthompsa case LIBUSB20_SPEED_LOW: 901195560Sthompsa ret = 256; 902195560Sthompsa break ; 903195560Sthompsa case LIBUSB20_SPEED_FULL: 904195560Sthompsa ret = 4096; 905195560Sthompsa break ; 906195560Sthompsa default: 907195560Sthompsa ret = 16384; 908195560Sthompsa break ; 909195560Sthompsa } 910195560Sthompsa break ; 911195560Sthompsa } 912195560Sthompsa 913195560Sthompsa return ret; 914195560Sthompsa} 915195560Sthompsa 916194676Sthompsastatic void 917194676Sthompsalibusb10_proxy(struct libusb20_transfer *xfer) 918194676Sthompsa{ 919194676Sthompsa struct usb_transfer *usb_backend; 920194676Sthompsa struct libusb20_device *pdev; 921194676Sthompsa libusb_transfer *usb_xfer; 922194676Sthompsa libusb_context *ctx; 923195560Sthompsa uint32_t pos; 924195560Sthompsa uint32_t max; 925195560Sthompsa uint32_t size; 926194676Sthompsa uint8_t status; 927194676Sthompsa uint32_t iso_packets; 928194676Sthompsa int i; 929194676Sthompsa 930194676Sthompsa status = libusb20_tr_get_status(xfer); 931194676Sthompsa usb_xfer = libusb20_tr_get_priv_sc0(xfer); 932194676Sthompsa usb_backend = (struct usb_transfer *) ((uint8_t *)usb_xfer - 933194676Sthompsa sizeof(struct usb_transfer)); 934194676Sthompsa pdev = usb_xfer->dev_handle->dev->os_priv; 935194676Sthompsa ctx = usb_xfer->dev_handle->dev->ctx; 936194676Sthompsa GET_CONTEXT(ctx); 937194676Sthompsa 938194676Sthompsa switch (status) { 939194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 940195560Sthompsa usb_backend->transferred += libusb20_tr_get_actual_length(xfer); 941195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 TRANSFER %i bytes", 942195560Sthompsa usb_backend->transferred); 943195560Sthompsa if (usb_backend->transferred != usb_xfer->length) 944195560Sthompsa goto tr_start; 945195560Sthompsa 946195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 TRANSFER COMPLETE"); 947195560Sthompsa usb_handle_transfer_completion(usb_backend, LIBUSB_TRANSFER_COMPLETED); 948195560Sthompsa 949194676Sthompsa break ; 950194676Sthompsa case LIBUSB20_TRANSFER_START: 951195560Sthompsatr_start: 952195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 START"); 953195560Sthompsa max = libusb_get_buffsize(pdev, usb_xfer); 954195560Sthompsa pos = usb_backend->transferred; 955195560Sthompsa size = (usb_xfer->length - pos); 956195560Sthompsa size = (size > max) ? max : size; 957194676Sthompsa usb_xfer->actual_length = 0; 958194676Sthompsa switch (usb_xfer->type) { 959194676Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 960195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE CTR"); 961194676Sthompsa libusb20_tr_setup_control(xfer, usb_xfer->buffer, 962195560Sthompsa (void *)(((uint8_t *) &usb_xfer->buffer[pos]) + 963194676Sthompsa sizeof(libusb_control_setup)), 964194676Sthompsa usb_xfer->timeout); 965194676Sthompsa break ; 966194676Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 967195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE ISO"); 968194676Sthompsa iso_packets = libusb20_tr_get_max_frames(xfer); 969194676Sthompsa if (usb_xfer->num_iso_packets > iso_packets) 970194676Sthompsa usb_xfer->num_iso_packets = iso_packets; 971194676Sthompsa for (i = 0 ; i < usb_xfer->num_iso_packets ; i++) { 972194676Sthompsa libusb20_tr_setup_isoc(xfer, 973195560Sthompsa &usb_xfer->buffer[pos], size, i); 974194676Sthompsa } 975194676Sthompsa libusb20_tr_set_total_frames(xfer, i); 976194676Sthompsa break ; 977194676Sthompsa case LIBUSB_TRANSFER_TYPE_BULK: 978195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE BULK"); 979195560Sthompsa libusb20_tr_setup_bulk(xfer, &usb_xfer->buffer[pos], 980195560Sthompsa size, usb_xfer->timeout); 981194676Sthompsa break ; 982194676Sthompsa case LIBUSB_TRANSFER_TYPE_INTERRUPT: 983195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TYPE INTR"); 984195560Sthompsa libusb20_tr_setup_intr(xfer, &usb_xfer->buffer[pos], 985195560Sthompsa size, usb_xfer->timeout); 986194676Sthompsa break ; 987194676Sthompsa } 988194676Sthompsa libusb20_tr_submit(xfer); 989195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20 SUBMITED"); 990194676Sthompsa break ; 991194676Sthompsa default: 992195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "TRANSFER DEFAULT 0x%x\n", 993195560Sthompsa status); 994195560Sthompsa usb_backend->transferred = 0; 995195560Sthompsa usb_handle_transfer_completion(usb_backend, LIBUSB_TRANSFER_CANCELLED); 996194676Sthompsa break ; 997194676Sthompsa } 998194676Sthompsa 999194676Sthompsa switch (status) { 1000194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 1001195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS COMPLETED"); 1002194676Sthompsa usb_xfer->status = LIBUSB_TRANSFER_COMPLETED; 1003194676Sthompsa break ; 1004194676Sthompsa case LIBUSB20_TRANSFER_OVERFLOW: 1005195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR OVERFLOW"); 1006194676Sthompsa usb_xfer->status = LIBUSB_TRANSFER_OVERFLOW; 1007194676Sthompsa break ; 1008194676Sthompsa case LIBUSB20_TRANSFER_NO_DEVICE: 1009195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR NO DEVICE"); 1010194676Sthompsa usb_xfer->status = LIBUSB_TRANSFER_NO_DEVICE; 1011194676Sthompsa break ; 1012194676Sthompsa case LIBUSB20_TRANSFER_STALL: 1013195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR STALL"); 1014194676Sthompsa usb_xfer->status = LIBUSB_TRANSFER_STALL; 1015194676Sthompsa break ; 1016194676Sthompsa case LIBUSB20_TRANSFER_CANCELLED: 1017195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR CANCELLED"); 1018194676Sthompsa usb_xfer->status = LIBUSB_TRANSFER_CANCELLED; 1019194676Sthompsa break ; 1020194676Sthompsa case LIBUSB20_TRANSFER_TIMED_OUT: 1021195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "STATUS TR TIMEOUT"); 1022194676Sthompsa usb_xfer->status = LIBUSB_TRANSFER_TIMED_OUT; 1023194676Sthompsa break ; 1024194676Sthompsa case LIBUSB20_TRANSFER_ERROR: 1025195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "ERROR"); 1026194676Sthompsa usb_xfer->status = LIBUSB_TRANSFER_ERROR; 1027194676Sthompsa break ; 1028194676Sthompsa } 1029194676Sthompsa} 1030194676Sthompsa 1031194676Sthompsaint 1032194676Sthompsalibusb_submit_transfer(struct libusb_transfer *xfer) 1033194676Sthompsa{ 1034194676Sthompsa struct libusb20_transfer **usb20_xfer; 1035194676Sthompsa struct usb_transfer *usb_backend; 1036194676Sthompsa struct usb_transfer *usb_node; 1037194676Sthompsa struct libusb20_device *pdev; 1038195560Sthompsa struct usb_ep_tr *eptr; 1039194676Sthompsa struct timespec cur_ts; 1040194676Sthompsa struct timeval *cur_tv; 1041195560Sthompsa libusb_device_handle *devh; 1042195560Sthompsa libusb_context *ctx; 1043194676Sthompsa int maxframe; 1044194676Sthompsa int buffsize; 1045194676Sthompsa int ep_idx; 1046194676Sthompsa int ret; 1047194676Sthompsa 1048194676Sthompsa if (xfer == NULL) 1049194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 1050194676Sthompsa 1051194676Sthompsa usb20_xfer = malloc(2 * sizeof(struct libusb20_transfer *)); 1052194676Sthompsa if (usb20_xfer == NULL) 1053194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 1054194676Sthompsa 1055194676Sthompsa ctx = xfer->dev_handle->dev->ctx; 1056194676Sthompsa pdev = xfer->dev_handle->os_priv; 1057195560Sthompsa devh = xfer->dev_handle; 1058194676Sthompsa 1059195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1060194676Sthompsa 1061194676Sthompsa usb_backend = (struct usb_transfer *) ((uint8_t *)xfer - 1062194676Sthompsa sizeof(struct usb_transfer)); 1063194676Sthompsa usb_backend->transferred = 0; 1064194676Sthompsa usb_backend->flags = 0; 1065194676Sthompsa 1066194676Sthompsa if (xfer->timeout != 0) { 1067194676Sthompsa clock_gettime(CLOCK_MONOTONIC, &cur_ts); 1068194676Sthompsa cur_ts.tv_sec += xfer->timeout / 1000; 1069194676Sthompsa cur_ts.tv_nsec += (xfer->timeout % 1000) * 1000000; 1070194676Sthompsa 1071194676Sthompsa if (cur_ts.tv_nsec > 1000000000) { 1072194676Sthompsa cur_ts.tv_nsec -= 1000000000; 1073194676Sthompsa cur_ts.tv_sec++; 1074194676Sthompsa } 1075194676Sthompsa 1076194676Sthompsa TIMESPEC_TO_TIMEVAL(&usb_backend->timeout, &cur_ts); 1077195560Sthompsa } 1078194676Sthompsa 1079194676Sthompsa /*Add to flying list*/ 1080194676Sthompsa pthread_mutex_lock(&ctx->flying_transfers_lock); 1081195560Sthompsa if (TAILQ_EMPTY(&ctx->flying_transfers)) { 1082195560Sthompsa TAILQ_INSERT_HEAD(&ctx->flying_transfers, usb_backend, list); 1083194676Sthompsa goto out; 1084194676Sthompsa } 1085194676Sthompsa if (timerisset(&usb_backend->timeout) == 0) { 1086195560Sthompsa TAILQ_INSERT_HEAD(&ctx->flying_transfers, usb_backend, list); 1087194676Sthompsa goto out; 1088194676Sthompsa } 1089195560Sthompsa TAILQ_FOREACH(usb_node, &ctx->flying_transfers, list) { 1090194676Sthompsa cur_tv = &usb_node->timeout; 1091194676Sthompsa if (timerisset(cur_tv) == 0 || 1092194676Sthompsa (cur_tv->tv_sec > usb_backend->timeout.tv_sec) || 1093194676Sthompsa (cur_tv->tv_sec == usb_backend->timeout.tv_sec && 1094194676Sthompsa cur_tv->tv_usec > usb_backend->timeout.tv_usec)) { 1095195560Sthompsa TAILQ_INSERT_TAIL(&ctx->flying_transfers, usb_backend, list); 1096194676Sthompsa goto out; 1097194676Sthompsa } 1098194676Sthompsa } 1099195560Sthompsa TAILQ_INSERT_TAIL(&ctx->flying_transfers, usb_backend, list); 1100194676Sthompsa 1101194676Sthompsaout: 1102194676Sthompsa pthread_mutex_unlock(&ctx->flying_transfers_lock); 1103194676Sthompsa 1104195560Sthompsa ep_idx = (xfer->endpoint / 0x40) | (xfer->endpoint * 4) % (16 * 4); 1105195560Sthompsa usb20_xfer[0] = libusb20_tr_get_pointer(pdev, ep_idx); 1106195560Sthompsa usb20_xfer[1] = libusb20_tr_get_pointer(pdev, ep_idx + 1); 1107194676Sthompsa 1108194676Sthompsa if (usb20_xfer[0] == NULL) 1109194676Sthompsa return (LIBUSB_ERROR_OTHER); 1110194676Sthompsa 1111194676Sthompsa xfer->os_priv = usb20_xfer; 1112194676Sthompsa 1113194676Sthompsa pthread_mutex_lock(&libusb20_lock); 1114194676Sthompsa 1115194676Sthompsa buffsize = libusb_get_buffsize(pdev, xfer); 1116194676Sthompsa maxframe = libusb_get_maxframe(pdev, xfer); 1117194676Sthompsa 1118195560Sthompsa ret = 0; 1119195560Sthompsa TAILQ_FOREACH(eptr, &devh->ep_list, list) { 1120195560Sthompsa if (xfer->endpoint == eptr->addr) 1121195560Sthompsa ret++; 1122195560Sthompsa } 1123195560Sthompsa if (ret == 0) { 1124195560Sthompsa eptr = malloc(sizeof(struct usb_ep_tr)); 1125195560Sthompsa eptr->addr = xfer->endpoint; 1126195560Sthompsa eptr->idx = ep_idx; 1127195560Sthompsa eptr->os_priv = usb20_xfer; 1128195560Sthompsa eptr->flags = (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)?1:0; 1129195560Sthompsa TAILQ_INSERT_HEAD(&devh->ep_list, eptr, list); 1130195560Sthompsa ret = libusb20_tr_open(usb20_xfer[0], buffsize, 1131195560Sthompsa maxframe, xfer->endpoint); 1132195560Sthompsa if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) 1133195560Sthompsa ret |= libusb20_tr_open(usb20_xfer[1], buffsize, 1134195560Sthompsa maxframe, xfer->endpoint); 1135194676Sthompsa 1136195560Sthompsa if (ret != 0) { 1137195560Sthompsa pthread_mutex_unlock(&libusb20_lock); 1138195560Sthompsa pthread_mutex_lock(&ctx->flying_transfers_lock); 1139195560Sthompsa TAILQ_REMOVE(&ctx->flying_transfers, usb_backend, list); 1140195560Sthompsa pthread_mutex_unlock(&ctx->flying_transfers_lock); 1141195560Sthompsa return (LIBUSB_ERROR_OTHER); 1142195560Sthompsa } 1143194676Sthompsa } 1144194676Sthompsa 1145194676Sthompsa libusb20_tr_set_priv_sc0(usb20_xfer[0], xfer); 1146194676Sthompsa libusb20_tr_set_callback(usb20_xfer[0], libusb10_proxy); 1147194676Sthompsa if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { 1148194676Sthompsa libusb20_tr_set_priv_sc0(usb20_xfer[1], xfer); 1149194676Sthompsa libusb20_tr_set_callback(usb20_xfer[1], libusb10_proxy); 1150194676Sthompsa } 1151194676Sthompsa 1152195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20_TR_START"); 1153194676Sthompsa libusb20_tr_start(usb20_xfer[0]); 1154194676Sthompsa if (xfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) 1155194676Sthompsa libusb20_tr_start(usb20_xfer[1]); 1156194676Sthompsa 1157194676Sthompsa pthread_mutex_unlock(&libusb20_lock); 1158194676Sthompsa 1159195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave"); 1160194676Sthompsa return (0); 1161194676Sthompsa} 1162194676Sthompsa 1163194676Sthompsaint 1164194676Sthompsalibusb_cancel_transfer(struct libusb_transfer *xfer) 1165194676Sthompsa{ 1166194676Sthompsa libusb_context *ctx; 1167194676Sthompsa 1168194676Sthompsa ctx = NULL; 1169194676Sthompsa GET_CONTEXT(ctx); 1170195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1171194676Sthompsa 1172194676Sthompsa if (xfer == NULL) 1173194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 1174194676Sthompsa 1175194676Sthompsa pthread_mutex_lock(&libusb20_lock); 1176194676Sthompsa libusb20_tr_stop(xfer->os_priv); 1177194676Sthompsa pthread_mutex_unlock(&libusb20_lock); 1178194676Sthompsa 1179195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1180194676Sthompsa return (0); 1181194676Sthompsa} 1182194676Sthompsa 1183