libusb10.c revision 225035
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 225035 2011-08-20 14:04:16Z hselasky $ */ 2194676Sthompsa/*- 3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4195957Salfred * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 5194676Sthompsa * 6194676Sthompsa * Redistribution and use in source and binary forms, with or without 7194676Sthompsa * modification, are permitted provided that the following conditions 8194676Sthompsa * are met: 9194676Sthompsa * 1. Redistributions of source code must retain the above copyright 10194676Sthompsa * notice, this list of conditions and the following disclaimer. 11194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 12194676Sthompsa * notice, this list of conditions and the following disclaimer in the 13194676Sthompsa * documentation and/or other materials provided with the distribution. 14194676Sthompsa * 15194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18194676Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25194676Sthompsa * SUCH DAMAGE. 26194676Sthompsa */ 27194676Sthompsa 28203815Swkoszek#include <sys/fcntl.h> 29203815Swkoszek#include <sys/ioctl.h> 30203815Swkoszek#include <sys/queue.h> 31203815Swkoszek 32203774Swkoszek#include <assert.h> 33203815Swkoszek#include <errno.h> 34203815Swkoszek#include <poll.h> 35203815Swkoszek#include <pthread.h> 36203815Swkoszek#include <stdio.h> 37194676Sthompsa#include <stdlib.h> 38194676Sthompsa#include <unistd.h> 39194676Sthompsa 40208020Sthompsa#define libusb_device_handle libusb20_device 41208020Sthompsa 42194676Sthompsa#include "libusb20.h" 43194676Sthompsa#include "libusb20_desc.h" 44194676Sthompsa#include "libusb20_int.h" 45194676Sthompsa#include "libusb.h" 46194676Sthompsa#include "libusb10.h" 47194676Sthompsa 48194676Sthompsastatic pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 49194676Sthompsastruct libusb_context *usbi_default_context = NULL; 50194676Sthompsa 51195957Salfred/* Prototypes */ 52195957Salfred 53195957Salfredstatic struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 54195957Salfredstatic int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 55195957Salfredstatic int libusb10_convert_error(uint8_t status); 56195957Salfredstatic void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 57195957Salfredstatic void libusb10_isoc_proxy(struct libusb20_transfer *); 58195957Salfredstatic void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 59195957Salfredstatic void libusb10_ctrl_proxy(struct libusb20_transfer *); 60195957Salfredstatic void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 61195957Salfred 62194676Sthompsa/* Library initialisation / deinitialisation */ 63194676Sthompsa 64194676Sthompsavoid 65195957Salfredlibusb_set_debug(libusb_context *ctx, int level) 66194676Sthompsa{ 67195957Salfred ctx = GET_CONTEXT(ctx); 68194676Sthompsa if (ctx) 69194676Sthompsa ctx->debug = level; 70194676Sthompsa} 71194676Sthompsa 72213853Shselaskystatic void 73213853Shselaskylibusb_set_nonblocking(int f) 74213853Shselasky{ 75213853Shselasky int flags; 76213853Shselasky 77213853Shselasky /* 78213853Shselasky * We ignore any failures in this function, hence the 79213853Shselasky * non-blocking flag is not critical to the operation of 80213853Shselasky * libUSB. We use F_GETFL and F_SETFL to be compatible with 81213853Shselasky * Linux. 82213853Shselasky */ 83213853Shselasky 84213853Shselasky flags = fcntl(f, F_GETFL, NULL); 85213853Shselasky if (flags == -1) 86213853Shselasky return; 87213853Shselasky flags |= O_NONBLOCK; 88213853Shselasky fcntl(f, F_SETFL, flags); 89213853Shselasky} 90213853Shselasky 91194676Sthompsaint 92195957Salfredlibusb_init(libusb_context **context) 93194676Sthompsa{ 94194676Sthompsa struct libusb_context *ctx; 95195957Salfred char *debug; 96194676Sthompsa int ret; 97194676Sthompsa 98194676Sthompsa ctx = malloc(sizeof(*ctx)); 99194676Sthompsa if (!ctx) 100194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 101194676Sthompsa 102194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 103194676Sthompsa 104194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 105194676Sthompsa if (debug != NULL) { 106194676Sthompsa ctx->debug = atoi(debug); 107194676Sthompsa if (ctx->debug != 0) 108194676Sthompsa ctx->debug_fixed = 1; 109194676Sthompsa } 110195957Salfred TAILQ_INIT(&ctx->pollfds); 111195957Salfred TAILQ_INIT(&ctx->tr_done); 112194676Sthompsa 113195957Salfred pthread_mutex_init(&ctx->ctx_lock, NULL); 114195957Salfred pthread_cond_init(&ctx->ctx_cond, NULL); 115194676Sthompsa 116195957Salfred ctx->ctx_handler = NO_THREAD; 117194676Sthompsa 118194676Sthompsa ret = pipe(ctx->ctrl_pipe); 119194676Sthompsa if (ret < 0) { 120195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 121195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 122194676Sthompsa free(ctx); 123194676Sthompsa return (LIBUSB_ERROR_OTHER); 124194676Sthompsa } 125195957Salfred /* set non-blocking mode on the control pipe to avoid deadlock */ 126213853Shselasky libusb_set_nonblocking(ctx->ctrl_pipe[0]); 127213853Shselasky libusb_set_nonblocking(ctx->ctrl_pipe[1]); 128194676Sthompsa 129195957Salfred libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 130194676Sthompsa 131194676Sthompsa pthread_mutex_lock(&default_context_lock); 132194676Sthompsa if (usbi_default_context == NULL) { 133194676Sthompsa usbi_default_context = ctx; 134194676Sthompsa } 135194676Sthompsa pthread_mutex_unlock(&default_context_lock); 136194676Sthompsa 137194676Sthompsa if (context) 138194676Sthompsa *context = ctx; 139194676Sthompsa 140195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 141195957Salfred 142194676Sthompsa return (0); 143194676Sthompsa} 144194676Sthompsa 145194676Sthompsavoid 146195957Salfredlibusb_exit(libusb_context *ctx) 147194676Sthompsa{ 148195957Salfred ctx = GET_CONTEXT(ctx); 149194676Sthompsa 150195957Salfred if (ctx == NULL) 151195957Salfred return; 152195957Salfred 153195957Salfred /* XXX cleanup devices */ 154195957Salfred 155195957Salfred libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 156194676Sthompsa close(ctx->ctrl_pipe[0]); 157194676Sthompsa close(ctx->ctrl_pipe[1]); 158195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 159195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 160194676Sthompsa 161194676Sthompsa pthread_mutex_lock(&default_context_lock); 162194676Sthompsa if (ctx == usbi_default_context) { 163194676Sthompsa usbi_default_context = NULL; 164194676Sthompsa } 165194676Sthompsa pthread_mutex_unlock(&default_context_lock); 166194676Sthompsa 167194676Sthompsa free(ctx); 168194676Sthompsa} 169194676Sthompsa 170194676Sthompsa/* Device handling and initialisation. */ 171194676Sthompsa 172194676Sthompsassize_t 173195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list) 174194676Sthompsa{ 175195957Salfred struct libusb20_backend *usb_backend; 176194676Sthompsa struct libusb20_device *pdev; 177194676Sthompsa struct libusb_device *dev; 178194676Sthompsa int i; 179194676Sthompsa 180195957Salfred ctx = GET_CONTEXT(ctx); 181194676Sthompsa 182195957Salfred if (ctx == NULL) 183195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 184195957Salfred 185195957Salfred if (list == NULL) 186195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 187195957Salfred 188194676Sthompsa usb_backend = libusb20_be_alloc_default(); 189194676Sthompsa if (usb_backend == NULL) 190195957Salfred return (LIBUSB_ERROR_NO_MEM); 191194676Sthompsa 192195957Salfred /* figure out how many USB devices are present */ 193194676Sthompsa pdev = NULL; 194194676Sthompsa i = 0; 195194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 196194676Sthompsa i++; 197194676Sthompsa 198195957Salfred /* allocate device pointer list */ 199194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 200194676Sthompsa if (*list == NULL) { 201194676Sthompsa libusb20_be_free(usb_backend); 202194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 203194676Sthompsa } 204195957Salfred /* create libusb v1.0 compliant devices */ 205194676Sthompsa i = 0; 206194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 207194676Sthompsa 208194676Sthompsa dev = malloc(sizeof(*dev)); 209194676Sthompsa if (dev == NULL) { 210195560Sthompsa while (i != 0) { 211195560Sthompsa libusb_unref_device((*list)[i - 1]); 212195560Sthompsa i--; 213195560Sthompsa } 214194676Sthompsa free(*list); 215195957Salfred *list = NULL; 216194676Sthompsa libusb20_be_free(usb_backend); 217194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 218194676Sthompsa } 219199055Sthompsa 220199055Sthompsa /* get device into libUSB v1.0 list */ 221199055Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 222199055Sthompsa 223194676Sthompsa memset(dev, 0, sizeof(*dev)); 224194676Sthompsa 225195957Salfred /* init transfer queues */ 226195957Salfred TAILQ_INIT(&dev->tr_head); 227195957Salfred 228195957Salfred /* set context we belong to */ 229194676Sthompsa dev->ctx = ctx; 230194676Sthompsa 231194676Sthompsa /* link together the two structures */ 232194676Sthompsa dev->os_priv = pdev; 233195957Salfred pdev->privLuData = dev; 234194676Sthompsa 235194676Sthompsa (*list)[i] = libusb_ref_device(dev); 236194676Sthompsa i++; 237194676Sthompsa } 238194676Sthompsa (*list)[i] = NULL; 239194676Sthompsa 240194676Sthompsa libusb20_be_free(usb_backend); 241194676Sthompsa return (i); 242194676Sthompsa} 243194676Sthompsa 244194676Sthompsavoid 245194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 246194676Sthompsa{ 247194676Sthompsa int i; 248194676Sthompsa 249194676Sthompsa if (list == NULL) 250195957Salfred return; /* be NULL safe */ 251194676Sthompsa 252194676Sthompsa if (unref_devices) { 253194676Sthompsa for (i = 0; list[i] != NULL; i++) 254194676Sthompsa libusb_unref_device(list[i]); 255194676Sthompsa } 256194676Sthompsa free(list); 257194676Sthompsa} 258194676Sthompsa 259194676Sthompsauint8_t 260195957Salfredlibusb_get_bus_number(libusb_device *dev) 261194676Sthompsa{ 262194676Sthompsa if (dev == NULL) 263195957Salfred return (0); /* should not happen */ 264195957Salfred return (libusb20_dev_get_bus_number(dev->os_priv)); 265194676Sthompsa} 266194676Sthompsa 267194676Sthompsauint8_t 268195957Salfredlibusb_get_device_address(libusb_device *dev) 269194676Sthompsa{ 270194676Sthompsa if (dev == NULL) 271195957Salfred return (0); /* should not happen */ 272195957Salfred return (libusb20_dev_get_address(dev->os_priv)); 273194676Sthompsa} 274194676Sthompsa 275224903Shselaskyenum libusb_speed 276224903Shselaskylibusb_get_device_speed(libusb_device *dev) 277224903Shselasky{ 278224903Shselasky if (dev == NULL) 279225035Shselasky return (LIBUSB_SPEED_UNKNOWN); /* should not happen */ 280224903Shselasky 281224903Shselasky switch (libusb20_dev_get_speed(dev->os_priv)) { 282224903Shselasky case LIBUSB20_SPEED_LOW: 283224903Shselasky return (LIBUSB_SPEED_LOW); 284224903Shselasky case LIBUSB20_SPEED_FULL: 285224903Shselasky return (LIBUSB_SPEED_FULL); 286224903Shselasky case LIBUSB20_SPEED_HIGH: 287224903Shselasky return (LIBUSB_SPEED_HIGH); 288224903Shselasky case LIBUSB20_SPEED_SUPER: 289224903Shselasky return (LIBUSB_SPEED_SUPER); 290224903Shselasky default: 291224903Shselasky break; 292224903Shselasky } 293224903Shselasky return (LIBUSB_SPEED_UNKNOWN); 294224903Shselasky} 295224903Shselasky 296194676Sthompsaint 297195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 298194676Sthompsa{ 299194676Sthompsa struct libusb_config_descriptor *pdconf; 300194676Sthompsa struct libusb_interface *pinf; 301194676Sthompsa struct libusb_interface_descriptor *pdinf; 302194676Sthompsa struct libusb_endpoint_descriptor *pdend; 303195957Salfred int i; 304195957Salfred int j; 305195957Salfred int k; 306195957Salfred int ret; 307194676Sthompsa 308194676Sthompsa if (dev == NULL) 309194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 310194676Sthompsa 311195957Salfred ret = libusb_get_active_config_descriptor(dev, &pdconf); 312195957Salfred if (ret < 0) 313195957Salfred return (ret); 314195957Salfred 315194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 316195957Salfred for (i = 0; i < pdconf->bNumInterfaces; i++) { 317194676Sthompsa pinf = &pdconf->interface[i]; 318195957Salfred for (j = 0; j < pinf->num_altsetting; j++) { 319194676Sthompsa pdinf = &pinf->altsetting[j]; 320195957Salfred for (k = 0; k < pdinf->bNumEndpoints; k++) { 321194676Sthompsa pdend = &pdinf->endpoint[k]; 322194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 323194676Sthompsa ret = pdend->wMaxPacketSize; 324194676Sthompsa goto out; 325194676Sthompsa } 326194676Sthompsa } 327194676Sthompsa } 328194676Sthompsa } 329194676Sthompsa 330194676Sthompsaout: 331194676Sthompsa libusb_free_config_descriptor(pdconf); 332194676Sthompsa return (ret); 333194676Sthompsa} 334194676Sthompsa 335194676Sthompsalibusb_device * 336195957Salfredlibusb_ref_device(libusb_device *dev) 337194676Sthompsa{ 338194676Sthompsa if (dev == NULL) 339195957Salfred return (NULL); /* be NULL safe */ 340194676Sthompsa 341195957Salfred CTX_LOCK(dev->ctx); 342194676Sthompsa dev->refcnt++; 343195957Salfred CTX_UNLOCK(dev->ctx); 344194676Sthompsa 345194676Sthompsa return (dev); 346194676Sthompsa} 347194676Sthompsa 348194676Sthompsavoid 349195957Salfredlibusb_unref_device(libusb_device *dev) 350194676Sthompsa{ 351194676Sthompsa if (dev == NULL) 352195957Salfred return; /* be NULL safe */ 353194676Sthompsa 354195957Salfred CTX_LOCK(dev->ctx); 355194676Sthompsa dev->refcnt--; 356195957Salfred CTX_UNLOCK(dev->ctx); 357194676Sthompsa 358194676Sthompsa if (dev->refcnt == 0) { 359194676Sthompsa libusb20_dev_free(dev->os_priv); 360194676Sthompsa free(dev); 361194676Sthompsa } 362194676Sthompsa} 363194676Sthompsa 364194676Sthompsaint 365195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh) 366194676Sthompsa{ 367194676Sthompsa libusb_context *ctx = dev->ctx; 368194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 369195957Salfred uint8_t dummy; 370194676Sthompsa int err; 371194676Sthompsa 372194676Sthompsa if (devh == NULL) 373194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 374194676Sthompsa 375195957Salfred /* set default device handle value */ 376195957Salfred *devh = NULL; 377194676Sthompsa 378195957Salfred dev = libusb_ref_device(dev); 379195957Salfred if (dev == NULL) 380195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 381195957Salfred 382194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 383194676Sthompsa if (err) { 384195957Salfred libusb_unref_device(dev); 385194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 386194676Sthompsa } 387195957Salfred libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 388194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 389194676Sthompsa 390195957Salfred /* make sure our event loop detects the new device */ 391195957Salfred dummy = 0; 392194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 393213853Shselasky if (err < (int)sizeof(dummy)) { 394195957Salfred /* ignore error, if any */ 395195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 396194676Sthompsa } 397195957Salfred *devh = pdev; 398194676Sthompsa 399194676Sthompsa return (0); 400194676Sthompsa} 401194676Sthompsa 402194676Sthompsalibusb_device_handle * 403195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 404194676Sthompsa uint16_t product_id) 405194676Sthompsa{ 406194676Sthompsa struct libusb_device **devs; 407194676Sthompsa struct libusb20_device *pdev; 408194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 409195957Salfred int i; 410195957Salfred int j; 411194676Sthompsa 412195957Salfred ctx = GET_CONTEXT(ctx); 413195957Salfred if (ctx == NULL) 414195957Salfred return (NULL); /* be NULL safe */ 415195957Salfred 416195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 417194676Sthompsa 418194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 419194676Sthompsa return (NULL); 420194676Sthompsa 421194676Sthompsa for (j = 0; j < i; j++) { 422195957Salfred pdev = devs[j]->os_priv; 423194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 424195957Salfred /* 425195957Salfred * NOTE: The USB library will automatically swap the 426195957Salfred * fields in the device descriptor to be of host 427195957Salfred * endian type! 428195957Salfred */ 429194676Sthompsa if (pdesc->idVendor == vendor_id && 430195560Sthompsa pdesc->idProduct == product_id) { 431195957Salfred if (libusb_open(devs[j], &pdev) < 0) 432195957Salfred pdev = NULL; 433195957Salfred break; 434195560Sthompsa } 435194676Sthompsa } 436200424Sscf if (j == i) 437200424Sscf pdev = NULL; 438194676Sthompsa 439194676Sthompsa libusb_free_device_list(devs, 1); 440195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 441195957Salfred return (pdev); 442194676Sthompsa} 443194676Sthompsa 444194676Sthompsavoid 445195957Salfredlibusb_close(struct libusb20_device *pdev) 446194676Sthompsa{ 447194676Sthompsa libusb_context *ctx; 448195957Salfred struct libusb_device *dev; 449195957Salfred uint8_t dummy; 450194676Sthompsa int err; 451194676Sthompsa 452195957Salfred if (pdev == NULL) 453195957Salfred return; /* be NULL safe */ 454194676Sthompsa 455195957Salfred dev = libusb_get_device(pdev); 456195957Salfred ctx = dev->ctx; 457194676Sthompsa 458195957Salfred libusb10_remove_pollfd(ctx, &dev->dev_poll); 459194676Sthompsa 460195957Salfred libusb20_dev_close(pdev); 461199055Sthompsa 462199055Sthompsa /* unref will free the "pdev" when the refcount reaches zero */ 463195957Salfred libusb_unref_device(dev); 464194676Sthompsa 465195957Salfred /* make sure our event loop detects the closed device */ 466195957Salfred dummy = 0; 467194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 468213853Shselasky if (err < (int)sizeof(dummy)) { 469195957Salfred /* ignore error, if any */ 470195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 471194676Sthompsa } 472194676Sthompsa} 473194676Sthompsa 474194676Sthompsalibusb_device * 475195957Salfredlibusb_get_device(struct libusb20_device *pdev) 476194676Sthompsa{ 477195957Salfred if (pdev == NULL) 478194676Sthompsa return (NULL); 479195957Salfred return ((libusb_device *)pdev->privLuData); 480194676Sthompsa} 481194676Sthompsa 482194676Sthompsaint 483195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config) 484194676Sthompsa{ 485195957Salfred struct libusb20_config *pconf; 486194676Sthompsa 487195957Salfred if (pdev == NULL || config == NULL) 488194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 489194676Sthompsa 490195957Salfred pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 491195957Salfred if (pconf == NULL) 492195957Salfred return (LIBUSB_ERROR_NO_MEM); 493194676Sthompsa 494195957Salfred *config = pconf->desc.bConfigurationValue; 495195957Salfred 496195957Salfred free(pconf); 497195957Salfred 498194676Sthompsa return (0); 499194676Sthompsa} 500194676Sthompsa 501194676Sthompsaint 502195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration) 503194676Sthompsa{ 504195957Salfred struct libusb20_config *pconf; 505195957Salfred struct libusb_device *dev; 506195957Salfred int err; 507195957Salfred uint8_t i; 508194676Sthompsa 509195957Salfred dev = libusb_get_device(pdev); 510195957Salfred if (dev == NULL) 511194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 512194676Sthompsa 513195957Salfred if (configuration < 1) { 514195957Salfred /* unconfigure */ 515195957Salfred i = 255; 516195957Salfred } else { 517195957Salfred for (i = 0; i != 255; i++) { 518195957Salfred uint8_t found; 519194676Sthompsa 520195957Salfred pconf = libusb20_dev_alloc_config(pdev, i); 521195957Salfred if (pconf == NULL) 522195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 523195957Salfred found = (pconf->desc.bConfigurationValue 524195957Salfred == configuration); 525195957Salfred free(pconf); 526195957Salfred 527195957Salfred if (found) 528195957Salfred goto set_config; 529195957Salfred } 530195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 531195957Salfred } 532195957Salfred 533195957Salfredset_config: 534195957Salfred 535195957Salfred libusb10_cancel_all_transfer(dev); 536195957Salfred 537195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 538195957Salfred 539195957Salfred err = libusb20_dev_set_config_index(pdev, i); 540195957Salfred 541195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 542195957Salfred POLLOUT | POLLRDNORM | POLLWRNORM); 543195957Salfred 544195957Salfred return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 545194676Sthompsa} 546194676Sthompsa 547194676Sthompsaint 548195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number) 549194676Sthompsa{ 550195957Salfred libusb_device *dev; 551195957Salfred int err = 0; 552194676Sthompsa 553195957Salfred dev = libusb_get_device(pdev); 554194676Sthompsa if (dev == NULL) 555194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 556194676Sthompsa 557195957Salfred if (interface_number < 0 || interface_number > 31) 558194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 559194676Sthompsa 560195957Salfred CTX_LOCK(dev->ctx); 561194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 562195957Salfred err = LIBUSB_ERROR_BUSY; 563194676Sthompsa 564195957Salfred if (!err) 565194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 566195957Salfred CTX_UNLOCK(dev->ctx); 567195957Salfred return (err); 568194676Sthompsa} 569194676Sthompsa 570194676Sthompsaint 571195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number) 572194676Sthompsa{ 573195957Salfred libusb_device *dev; 574195957Salfred int err = 0; 575194676Sthompsa 576195957Salfred dev = libusb_get_device(pdev); 577194676Sthompsa if (dev == NULL) 578194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 579194676Sthompsa 580195957Salfred if (interface_number < 0 || interface_number > 31) 581194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 582194676Sthompsa 583195957Salfred CTX_LOCK(dev->ctx); 584194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 585195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 586194676Sthompsa 587195957Salfred if (!err) 588194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 589195957Salfred CTX_UNLOCK(dev->ctx); 590195957Salfred return (err); 591194676Sthompsa} 592194676Sthompsa 593194676Sthompsaint 594195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev, 595194676Sthompsa int interface_number, int alternate_setting) 596194676Sthompsa{ 597195957Salfred libusb_device *dev; 598195957Salfred int err = 0; 599194676Sthompsa 600195957Salfred dev = libusb_get_device(pdev); 601194676Sthompsa if (dev == NULL) 602194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 603194676Sthompsa 604195957Salfred if (interface_number < 0 || interface_number > 31) 605194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 606194676Sthompsa 607195957Salfred CTX_LOCK(dev->ctx); 608195957Salfred if (!(dev->claimed_interfaces & (1 << interface_number))) 609195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 610195957Salfred CTX_UNLOCK(dev->ctx); 611194676Sthompsa 612195957Salfred if (err) 613195957Salfred return (err); 614195957Salfred 615195957Salfred libusb10_cancel_all_transfer(dev); 616195957Salfred 617195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 618195957Salfred 619195957Salfred err = libusb20_dev_set_alt_index(pdev, 620195957Salfred interface_number, alternate_setting); 621195957Salfred 622195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 623195957Salfred pdev, libusb20_dev_get_fd(pdev), 624195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 625195957Salfred 626195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 627194676Sthompsa} 628194676Sthompsa 629195957Salfredstatic struct libusb20_transfer * 630195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev, 631195957Salfred uint8_t endpoint, uint8_t index) 632195957Salfred{ 633195957Salfred index &= 1; /* double buffering */ 634195957Salfred 635195957Salfred index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 636195957Salfred 637195957Salfred if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 638195957Salfred /* this is an IN endpoint */ 639195957Salfred index |= 2; 640195957Salfred } 641195957Salfred return (libusb20_tr_get_pointer(pdev, index)); 642195957Salfred} 643195957Salfred 644194676Sthompsaint 645195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 646194676Sthompsa{ 647194676Sthompsa struct libusb20_transfer *xfer; 648195957Salfred struct libusb_device *dev; 649195957Salfred int err; 650194676Sthompsa 651195957Salfred xfer = libusb10_get_transfer(pdev, endpoint, 0); 652195560Sthompsa if (xfer == NULL) 653195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 654194676Sthompsa 655195957Salfred dev = libusb_get_device(pdev); 656213853Shselasky if (dev == NULL) 657213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 658195957Salfred 659195957Salfred CTX_LOCK(dev->ctx); 660223642Shselasky err = libusb20_tr_open(xfer, 0, 1, endpoint); 661195957Salfred CTX_UNLOCK(dev->ctx); 662195957Salfred 663195957Salfred if (err != 0 && err != LIBUSB20_ERROR_BUSY) 664194676Sthompsa return (LIBUSB_ERROR_OTHER); 665194676Sthompsa 666194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 667195957Salfred 668195957Salfred /* check if we opened the transfer */ 669195957Salfred if (err == 0) { 670195957Salfred CTX_LOCK(dev->ctx); 671194676Sthompsa libusb20_tr_close(xfer); 672195957Salfred CTX_UNLOCK(dev->ctx); 673195957Salfred } 674195957Salfred return (0); /* success */ 675194676Sthompsa} 676194676Sthompsa 677194676Sthompsaint 678195957Salfredlibusb_reset_device(struct libusb20_device *pdev) 679194676Sthompsa{ 680195957Salfred libusb_device *dev; 681195957Salfred int err; 682194676Sthompsa 683195957Salfred dev = libusb_get_device(pdev); 684194676Sthompsa if (dev == NULL) 685213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 686194676Sthompsa 687195957Salfred libusb10_cancel_all_transfer(dev); 688195957Salfred 689195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 690195957Salfred 691195957Salfred err = libusb20_dev_reset(pdev); 692195957Salfred 693195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 694195957Salfred pdev, libusb20_dev_get_fd(pdev), 695195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 696195957Salfred 697195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 698194676Sthompsa} 699194676Sthompsa 700194676Sthompsaint 701213848Shselaskylibusb_check_connected(struct libusb20_device *pdev) 702213848Shselasky{ 703213848Shselasky libusb_device *dev; 704213848Shselasky int err; 705213848Shselasky 706213848Shselasky dev = libusb_get_device(pdev); 707213848Shselasky if (dev == NULL) 708213848Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 709213848Shselasky 710213848Shselasky err = libusb20_dev_check_connected(pdev); 711213848Shselasky 712213848Shselasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 713213848Shselasky} 714213848Shselasky 715213848Shselaskyint 716195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 717194676Sthompsa{ 718195957Salfred if (pdev == NULL) 719194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 720194676Sthompsa 721195957Salfred return (libusb20_dev_kernel_driver_active( 722195957Salfred pdev, interface)); 723194676Sthompsa} 724194676Sthompsa 725194676Sthompsaint 726213853Shselaskylibusb_get_driver_np(struct libusb20_device *pdev, int interface, 727213853Shselasky char *name, int namelen) 728213853Shselasky{ 729213853Shselasky return (libusb_get_driver(pdev, interface, name, namelen)); 730213853Shselasky} 731213853Shselasky 732213853Shselaskyint 733213853Shselaskylibusb_get_driver(struct libusb20_device *pdev, int interface, 734213853Shselasky char *name, int namelen) 735213853Shselasky{ 736213853Shselasky char *ptr; 737213853Shselasky int err; 738213853Shselasky 739213853Shselasky if (pdev == NULL) 740213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 741213853Shselasky if (namelen < 1) 742213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 743224085Shselasky if (namelen > 255) 744224085Shselasky namelen = 255; 745213853Shselasky 746213853Shselasky err = libusb20_dev_get_iface_desc( 747213853Shselasky pdev, interface, name, namelen); 748213853Shselasky 749213853Shselasky if (err != 0) 750213853Shselasky return (LIBUSB_ERROR_OTHER); 751213853Shselasky 752213853Shselasky /* we only want the driver name */ 753213853Shselasky ptr = strstr(name, ":"); 754213853Shselasky if (ptr != NULL) 755213853Shselasky *ptr = 0; 756213853Shselasky 757213853Shselasky return (0); 758213853Shselasky} 759213853Shselasky 760213853Shselaskyint 761213853Shselaskylibusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface) 762213853Shselasky{ 763213853Shselasky return (libusb_detach_kernel_driver(pdev, interface)); 764213853Shselasky} 765213853Shselasky 766213853Shselaskyint 767195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 768194676Sthompsa{ 769195957Salfred int err; 770194676Sthompsa 771195957Salfred if (pdev == NULL) 772194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 773194676Sthompsa 774195957Salfred err = libusb20_dev_detach_kernel_driver( 775195957Salfred pdev, interface); 776194676Sthompsa 777213853Shselasky return (err ? LIBUSB_ERROR_OTHER : 0); 778194676Sthompsa} 779194676Sthompsa 780194676Sthompsaint 781195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 782194676Sthompsa{ 783195957Salfred if (pdev == NULL) 784194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 785195957Salfred /* stub - currently not supported by libusb20 */ 786194676Sthompsa return (0); 787194676Sthompsa} 788194676Sthompsa 789194676Sthompsa/* Asynchronous device I/O */ 790194676Sthompsa 791194676Sthompsastruct libusb_transfer * 792194676Sthompsalibusb_alloc_transfer(int iso_packets) 793194676Sthompsa{ 794195957Salfred struct libusb_transfer *uxfer; 795195957Salfred struct libusb_super_transfer *sxfer; 796194676Sthompsa int len; 797194676Sthompsa 798194676Sthompsa len = sizeof(struct libusb_transfer) + 799195957Salfred sizeof(struct libusb_super_transfer) + 800194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 801194676Sthompsa 802195957Salfred sxfer = malloc(len); 803195957Salfred if (sxfer == NULL) 804194676Sthompsa return (NULL); 805194676Sthompsa 806195957Salfred memset(sxfer, 0, len); 807194676Sthompsa 808195957Salfred uxfer = (struct libusb_transfer *)( 809195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 810194676Sthompsa 811195957Salfred /* set default value */ 812195957Salfred uxfer->num_iso_packets = iso_packets; 813195957Salfred 814195957Salfred return (uxfer); 815194676Sthompsa} 816194676Sthompsa 817194676Sthompsavoid 818195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 819194676Sthompsa{ 820195957Salfred struct libusb_super_transfer *sxfer; 821194676Sthompsa 822195957Salfred if (uxfer == NULL) 823195957Salfred return; /* be NULL safe */ 824194676Sthompsa 825215253Shselasky /* check if we should free the transfer buffer */ 826215253Shselasky if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) 827215253Shselasky free(uxfer->buffer); 828215253Shselasky 829195957Salfred sxfer = (struct libusb_super_transfer *)( 830195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 831194676Sthompsa 832195957Salfred free(sxfer); 833194676Sthompsa} 834194676Sthompsa 835219100Shselaskystatic uint32_t 836195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 837195560Sthompsa{ 838219100Shselasky uint32_t ret; 839195560Sthompsa 840195560Sthompsa switch (xfer->type) { 841195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 842219100Shselasky ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */ 843195957Salfred break; 844195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 845195560Sthompsa ret = 2; 846195957Salfred break; 847195560Sthompsa default: 848195560Sthompsa ret = 1; 849195957Salfred break; 850195560Sthompsa } 851195957Salfred return (ret); 852195560Sthompsa} 853195560Sthompsa 854195560Sthompsastatic int 855195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 856195560Sthompsa{ 857195560Sthompsa int ret; 858195560Sthompsa int usb_speed; 859195560Sthompsa 860195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 861195560Sthompsa 862195560Sthompsa switch (xfer->type) { 863195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 864195957Salfred ret = 0; /* kernel will auto-select */ 865195957Salfred break; 866195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 867195957Salfred ret = 1024; 868195957Salfred break; 869195957Salfred default: 870195560Sthompsa switch (usb_speed) { 871195957Salfred case LIBUSB20_SPEED_LOW: 872195957Salfred ret = 256; 873195957Salfred break; 874195957Salfred case LIBUSB20_SPEED_FULL: 875195957Salfred ret = 4096; 876195957Salfred break; 877195957Salfred default: 878195957Salfred ret = 16384; 879195957Salfred break; 880195560Sthompsa } 881195957Salfred break; 882195560Sthompsa } 883195957Salfred return (ret); 884195560Sthompsa} 885195560Sthompsa 886195957Salfredstatic int 887195957Salfredlibusb10_convert_error(uint8_t status) 888195957Salfred{ 889195957Salfred ; /* indent fix */ 890195957Salfred 891195957Salfred switch (status) { 892195957Salfred case LIBUSB20_TRANSFER_START: 893195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 894195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 895195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 896195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 897195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 898195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 899195957Salfred case LIBUSB20_TRANSFER_STALL: 900195957Salfred return (LIBUSB_TRANSFER_STALL); 901195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 902195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 903195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 904195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 905195957Salfred default: 906195957Salfred return (LIBUSB_TRANSFER_ERROR); 907195957Salfred } 908195957Salfred} 909195957Salfred 910195957Salfred/* This function must be called locked */ 911195957Salfred 912194676Sthompsastatic void 913195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 914195957Salfred struct libusb_super_transfer *sxfer, int status) 915194676Sthompsa{ 916195957Salfred struct libusb_transfer *uxfer; 917195957Salfred struct libusb_device *dev; 918195957Salfred 919195957Salfred uxfer = (struct libusb_transfer *)( 920195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 921195957Salfred 922195957Salfred if (pxfer != NULL) 923195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 924195957Salfred 925199575Sthompsa /* set transfer status */ 926195957Salfred uxfer->status = status; 927195957Salfred 928199575Sthompsa /* update super transfer state */ 929199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 930199575Sthompsa 931195957Salfred dev = libusb_get_device(uxfer->dev_handle); 932195957Salfred 933195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 934195957Salfred} 935195957Salfred 936195957Salfred/* This function must be called locked */ 937195957Salfred 938195957Salfredstatic void 939195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 940195957Salfred{ 941195957Salfred struct libusb_super_transfer *sxfer; 942195957Salfred struct libusb_transfer *uxfer; 943195957Salfred uint32_t actlen; 944195957Salfred uint16_t iso_packets; 945195957Salfred uint16_t i; 946194676Sthompsa uint8_t status; 947195957Salfred uint8_t flags; 948194676Sthompsa 949195957Salfred status = libusb20_tr_get_status(pxfer); 950195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 951195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 952195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 953194676Sthompsa 954195957Salfred if (sxfer == NULL) 955195957Salfred return; /* cancelled - nothing to do */ 956195957Salfred 957195957Salfred uxfer = (struct libusb_transfer *)( 958195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 959195957Salfred 960195957Salfred if (iso_packets > uxfer->num_iso_packets) 961195957Salfred iso_packets = uxfer->num_iso_packets; 962195957Salfred 963195957Salfred if (iso_packets == 0) 964195957Salfred return; /* nothing to do */ 965195957Salfred 966195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 967195957Salfred uxfer->num_iso_packets = iso_packets; 968195957Salfred 969195957Salfred flags = uxfer->flags; 970195957Salfred 971194676Sthompsa switch (status) { 972194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 973195560Sthompsa 974195957Salfred /* update actual length */ 975195957Salfred uxfer->actual_length = actlen; 976195957Salfred for (i = 0; i != iso_packets; i++) { 977195957Salfred uxfer->iso_packet_desc[i].actual_length = 978195957Salfred libusb20_tr_get_length(pxfer, i); 979195957Salfred } 980195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 981195957Salfred break; 982195560Sthompsa 983194676Sthompsa case LIBUSB20_TRANSFER_START: 984195957Salfred 985195957Salfred /* setup length(s) */ 986195957Salfred actlen = 0; 987195957Salfred for (i = 0; i != iso_packets; i++) { 988195957Salfred libusb20_tr_setup_isoc(pxfer, 989195957Salfred &uxfer->buffer[actlen], 990195957Salfred uxfer->iso_packet_desc[i].length, i); 991195957Salfred actlen += uxfer->iso_packet_desc[i].length; 992194676Sthompsa } 993195957Salfred 994195957Salfred /* no remainder */ 995195957Salfred sxfer->rem_len = 0; 996195957Salfred 997195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 998195957Salfred libusb20_tr_submit(pxfer); 999195957Salfred 1000195957Salfred /* fork another USB transfer, if any */ 1001195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1002195957Salfred break; 1003195957Salfred 1004194676Sthompsa default: 1005195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1006195957Salfred break; 1007194676Sthompsa } 1008195957Salfred} 1009194676Sthompsa 1010195957Salfred/* This function must be called locked */ 1011195957Salfred 1012195957Salfredstatic void 1013195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 1014195957Salfred{ 1015195957Salfred struct libusb_super_transfer *sxfer; 1016195957Salfred struct libusb_transfer *uxfer; 1017195957Salfred uint32_t max_bulk; 1018195957Salfred uint32_t actlen; 1019195957Salfred uint8_t status; 1020195957Salfred uint8_t flags; 1021195957Salfred 1022195957Salfred status = libusb20_tr_get_status(pxfer); 1023195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1024195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1025195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1026195957Salfred 1027195957Salfred if (sxfer == NULL) 1028195957Salfred return; /* cancelled - nothing to do */ 1029195957Salfred 1030195957Salfred uxfer = (struct libusb_transfer *)( 1031195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1032195957Salfred 1033195957Salfred flags = uxfer->flags; 1034195957Salfred 1035194676Sthompsa switch (status) { 1036194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 1037195957Salfred 1038195957Salfred uxfer->actual_length += actlen; 1039195957Salfred 1040195957Salfred /* check for short packet */ 1041195957Salfred if (sxfer->last_len != actlen) { 1042195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1043195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1044195957Salfred } else { 1045195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1046195957Salfred } 1047195957Salfred break; 1048195957Salfred } 1049195957Salfred /* check for end of data */ 1050195957Salfred if (sxfer->rem_len == 0) { 1051195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1052195957Salfred break; 1053195957Salfred } 1054195957Salfred /* FALLTHROUGH */ 1055195957Salfred 1056195957Salfred case LIBUSB20_TRANSFER_START: 1057195957Salfred if (max_bulk > sxfer->rem_len) { 1058195957Salfred max_bulk = sxfer->rem_len; 1059195957Salfred } 1060195957Salfred /* setup new BULK or INTERRUPT transaction */ 1061195957Salfred libusb20_tr_setup_bulk(pxfer, 1062195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 1063195957Salfred 1064195957Salfred /* update counters */ 1065195957Salfred sxfer->last_len = max_bulk; 1066195957Salfred sxfer->curr_data += max_bulk; 1067195957Salfred sxfer->rem_len -= max_bulk; 1068195957Salfred 1069195957Salfred libusb20_tr_submit(pxfer); 1070195957Salfred 1071195957Salfred /* check if we can fork another USB transfer */ 1072195957Salfred if (sxfer->rem_len == 0) 1073195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1074195957Salfred break; 1075195957Salfred 1076195957Salfred default: 1077195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1078195957Salfred break; 1079194676Sthompsa } 1080194676Sthompsa} 1081194676Sthompsa 1082195957Salfred/* This function must be called locked */ 1083195957Salfred 1084195957Salfredstatic void 1085195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1086194676Sthompsa{ 1087195957Salfred struct libusb_super_transfer *sxfer; 1088195957Salfred struct libusb_transfer *uxfer; 1089195957Salfred uint32_t max_bulk; 1090195957Salfred uint32_t actlen; 1091195957Salfred uint8_t status; 1092195957Salfred uint8_t flags; 1093194676Sthompsa 1094195957Salfred status = libusb20_tr_get_status(pxfer); 1095195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1096195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1097195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1098194676Sthompsa 1099195957Salfred if (sxfer == NULL) 1100195957Salfred return; /* cancelled - nothing to do */ 1101194676Sthompsa 1102195957Salfred uxfer = (struct libusb_transfer *)( 1103195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1104194676Sthompsa 1105195957Salfred flags = uxfer->flags; 1106194676Sthompsa 1107195957Salfred switch (status) { 1108195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1109194676Sthompsa 1110195957Salfred uxfer->actual_length += actlen; 1111195957Salfred 1112195957Salfred /* subtract length of SETUP packet, if any */ 1113195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1114195957Salfred 1115195957Salfred /* check for short packet */ 1116195957Salfred if (sxfer->last_len != actlen) { 1117195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1118195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1119195957Salfred } else { 1120195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1121195957Salfred } 1122195957Salfred break; 1123194676Sthompsa } 1124195957Salfred /* check for end of data */ 1125195957Salfred if (sxfer->rem_len == 0) { 1126195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1127195957Salfred break; 1128195957Salfred } 1129195957Salfred /* FALLTHROUGH */ 1130194676Sthompsa 1131195957Salfred case LIBUSB20_TRANSFER_START: 1132195957Salfred if (max_bulk > sxfer->rem_len) { 1133195957Salfred max_bulk = sxfer->rem_len; 1134195957Salfred } 1135195957Salfred /* setup new CONTROL transaction */ 1136195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1137195957Salfred /* next fragment - don't send SETUP packet */ 1138195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1139195957Salfred } else { 1140195957Salfred /* first fragment - send SETUP packet */ 1141195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1142195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1143195957Salfred } 1144195957Salfred 1145195957Salfred if (max_bulk != 0) { 1146195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1147195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1148195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1149195957Salfred } else { 1150195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1151195957Salfred } 1152195957Salfred 1153195957Salfred /* update counters */ 1154195957Salfred sxfer->last_len = max_bulk; 1155195957Salfred sxfer->curr_data += max_bulk; 1156195957Salfred sxfer->rem_len -= max_bulk; 1157195957Salfred 1158195957Salfred libusb20_tr_submit(pxfer); 1159195957Salfred 1160195957Salfred /* check if we can fork another USB transfer */ 1161195957Salfred if (sxfer->rem_len == 0) 1162195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1163195957Salfred break; 1164195957Salfred 1165195957Salfred default: 1166195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1167195957Salfred break; 1168194676Sthompsa } 1169195957Salfred} 1170195957Salfred 1171195957Salfred/* The following function must be called locked */ 1172195957Salfred 1173195957Salfredstatic void 1174195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1175195957Salfred{ 1176195957Salfred struct libusb20_transfer *pxfer0; 1177195957Salfred struct libusb20_transfer *pxfer1; 1178195957Salfred struct libusb_super_transfer *sxfer; 1179195957Salfred struct libusb_transfer *uxfer; 1180195957Salfred struct libusb_device *dev; 1181195957Salfred int err; 1182195957Salfred int buffsize; 1183195957Salfred int maxframe; 1184195957Salfred int temp; 1185195957Salfred uint8_t dummy; 1186195957Salfred 1187195957Salfred dev = libusb_get_device(pdev); 1188195957Salfred 1189195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1190195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1191195957Salfred 1192195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1193195957Salfred return; /* shouldn't happen */ 1194195957Salfred 1195195957Salfred temp = 0; 1196195957Salfred if (libusb20_tr_pending(pxfer0)) 1197195957Salfred temp |= 1; 1198195957Salfred if (libusb20_tr_pending(pxfer1)) 1199195957Salfred temp |= 2; 1200195957Salfred 1201195957Salfred switch (temp) { 1202195957Salfred case 3: 1203195957Salfred /* wait till one of the transfers complete */ 1204195957Salfred return; 1205195957Salfred case 2: 1206195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1207199575Sthompsa if (sxfer == NULL) 1208199575Sthompsa return; /* cancelling */ 1209195957Salfred if (sxfer->rem_len) 1210195957Salfred return; /* cannot queue another one */ 1211195957Salfred /* swap transfers */ 1212195957Salfred pxfer1 = pxfer0; 1213195957Salfred break; 1214195957Salfred case 1: 1215195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1216199575Sthompsa if (sxfer == NULL) 1217199575Sthompsa return; /* cancelling */ 1218195957Salfred if (sxfer->rem_len) 1219195957Salfred return; /* cannot queue another one */ 1220195957Salfred /* swap transfers */ 1221195957Salfred pxfer0 = pxfer1; 1222195957Salfred break; 1223195957Salfred default: 1224195957Salfred break; 1225194676Sthompsa } 1226195957Salfred 1227195957Salfred /* find next transfer on same endpoint */ 1228195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1229195957Salfred 1230195957Salfred uxfer = (struct libusb_transfer *)( 1231195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1232195957Salfred 1233195957Salfred if (uxfer->endpoint == endpoint) { 1234195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1235195957Salfred sxfer->entry.tqe_prev = NULL; 1236195957Salfred goto found; 1237194676Sthompsa } 1238195957Salfred } 1239195957Salfred return; /* success */ 1240194676Sthompsa 1241195957Salfredfound: 1242194676Sthompsa 1243195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1244195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1245194676Sthompsa 1246195957Salfred /* reset super transfer state */ 1247195957Salfred sxfer->rem_len = uxfer->length; 1248195957Salfred sxfer->curr_data = uxfer->buffer; 1249195957Salfred uxfer->actual_length = 0; 1250194676Sthompsa 1251195957Salfred switch (uxfer->type) { 1252195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1253195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1254195957Salfred break; 1255195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1256195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1257195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1258195957Salfred break; 1259195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1260195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1261195957Salfred if (sxfer->rem_len < 8) 1262195957Salfred goto failure; 1263194676Sthompsa 1264195957Salfred /* remove SETUP packet from data */ 1265195957Salfred sxfer->rem_len -= 8; 1266195957Salfred sxfer->curr_data += 8; 1267195957Salfred break; 1268195957Salfred default: 1269195957Salfred goto failure; 1270195560Sthompsa } 1271195957Salfred 1272195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1273195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1274195957Salfred 1275195957Salfred /* make sure the transfer is opened */ 1276195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1277195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1278195957Salfred goto failure; 1279194676Sthompsa } 1280195957Salfred libusb20_tr_start(pxfer0); 1281195957Salfred return; 1282194676Sthompsa 1283195957Salfredfailure: 1284195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1285194676Sthompsa 1286195957Salfred /* make sure our event loop spins the done handler */ 1287195957Salfred dummy = 0; 1288195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1289195957Salfred} 1290194676Sthompsa 1291195957Salfred/* The following function must be called unlocked */ 1292194676Sthompsa 1293195957Salfredint 1294195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1295195957Salfred{ 1296195957Salfred struct libusb20_transfer *pxfer0; 1297195957Salfred struct libusb20_transfer *pxfer1; 1298195957Salfred struct libusb_super_transfer *sxfer; 1299195957Salfred struct libusb_device *dev; 1300199055Sthompsa uint32_t endpoint; 1301195957Salfred int err; 1302195957Salfred 1303195957Salfred if (uxfer == NULL) 1304195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1305195957Salfred 1306195957Salfred if (uxfer->dev_handle == NULL) 1307195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1308195957Salfred 1309195957Salfred endpoint = uxfer->endpoint; 1310195957Salfred 1311195957Salfred if (endpoint > 255) 1312195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1313195957Salfred 1314195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1315195957Salfred 1316195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1317195957Salfred 1318195957Salfred sxfer = (struct libusb_super_transfer *)( 1319195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1320195957Salfred 1321195957Salfred CTX_LOCK(dev->ctx); 1322195957Salfred 1323195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1324195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1325195957Salfred 1326195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1327195957Salfred err = LIBUSB_ERROR_OTHER; 1328195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1329199575Sthompsa (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1330195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1331195957Salfred err = LIBUSB_ERROR_BUSY; 1332195957Salfred } else { 1333199575Sthompsa 1334199575Sthompsa /* set pending state */ 1335199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 1336199575Sthompsa 1337199575Sthompsa /* insert transfer into transfer head list */ 1338195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1339195957Salfred 1340199575Sthompsa /* start work transfers */ 1341195957Salfred libusb10_submit_transfer_sub( 1342195957Salfred uxfer->dev_handle, endpoint); 1343195957Salfred 1344195957Salfred err = 0; /* success */ 1345195957Salfred } 1346195957Salfred 1347195957Salfred CTX_UNLOCK(dev->ctx); 1348195957Salfred 1349195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1350195957Salfred 1351195957Salfred return (err); 1352194676Sthompsa} 1353194676Sthompsa 1354195957Salfred/* Asynchronous transfer cancel */ 1355195957Salfred 1356194676Sthompsaint 1357195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1358194676Sthompsa{ 1359195957Salfred struct libusb20_transfer *pxfer0; 1360195957Salfred struct libusb20_transfer *pxfer1; 1361195957Salfred struct libusb_super_transfer *sxfer; 1362195957Salfred struct libusb_device *dev; 1363199055Sthompsa uint32_t endpoint; 1364199575Sthompsa int retval; 1365194676Sthompsa 1366195957Salfred if (uxfer == NULL) 1367195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1368194676Sthompsa 1369199575Sthompsa /* check if not initialised */ 1370195957Salfred if (uxfer->dev_handle == NULL) 1371199575Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 1372194676Sthompsa 1373195957Salfred endpoint = uxfer->endpoint; 1374194676Sthompsa 1375195957Salfred if (endpoint > 255) 1376195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1377195957Salfred 1378195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1379195957Salfred 1380195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1381195957Salfred 1382195957Salfred sxfer = (struct libusb_super_transfer *)( 1383195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1384195957Salfred 1385199575Sthompsa retval = 0; 1386199575Sthompsa 1387195957Salfred CTX_LOCK(dev->ctx); 1388195957Salfred 1389195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1390195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1391195957Salfred 1392199575Sthompsa if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 1393199575Sthompsa /* only update the transfer status */ 1394199575Sthompsa uxfer->status = LIBUSB_TRANSFER_CANCELLED; 1395199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1396199575Sthompsa } else if (sxfer->entry.tqe_prev != NULL) { 1397195957Salfred /* we are lucky - transfer is on a queue */ 1398195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1399195957Salfred sxfer->entry.tqe_prev = NULL; 1400199575Sthompsa libusb10_complete_transfer(NULL, 1401199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1402195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1403195957Salfred /* not started */ 1404199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1405195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1406199575Sthompsa libusb10_complete_transfer(pxfer0, 1407199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1408195957Salfred libusb20_tr_stop(pxfer0); 1409195957Salfred /* make sure the queue doesn't stall */ 1410195957Salfred libusb10_submit_transfer_sub( 1411195957Salfred uxfer->dev_handle, endpoint); 1412195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1413199575Sthompsa libusb10_complete_transfer(pxfer1, 1414199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1415195957Salfred libusb20_tr_stop(pxfer1); 1416195957Salfred /* make sure the queue doesn't stall */ 1417195957Salfred libusb10_submit_transfer_sub( 1418195957Salfred uxfer->dev_handle, endpoint); 1419195957Salfred } else { 1420195957Salfred /* not started */ 1421199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1422195957Salfred } 1423195957Salfred 1424195957Salfred CTX_UNLOCK(dev->ctx); 1425195957Salfred 1426195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1427195957Salfred 1428199575Sthompsa return (retval); 1429194676Sthompsa} 1430194676Sthompsa 1431195957SalfredUNEXPORTED void 1432195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1433195957Salfred{ 1434195957Salfred /* TODO */ 1435195957Salfred} 1436199055Sthompsa 1437199055Sthompsauint16_t 1438199055Sthompsalibusb_cpu_to_le16(uint16_t x) 1439199055Sthompsa{ 1440199055Sthompsa return (htole16(x)); 1441199055Sthompsa} 1442199055Sthompsa 1443199055Sthompsauint16_t 1444199055Sthompsalibusb_le16_to_cpu(uint16_t x) 1445199055Sthompsa{ 1446199055Sthompsa return (le16toh(x)); 1447199055Sthompsa} 1448199055Sthompsa 1449213853Shselaskyconst char * 1450213853Shselaskylibusb_strerror(int code) 1451213853Shselasky{ 1452213853Shselasky /* TODO */ 1453213853Shselasky return ("Unknown error"); 1454213853Shselasky} 1455