libusb10.c revision 199575
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 199575 2009-11-20 08:57:25Z thompsa $ */ 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 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> 35195957Salfred#include <sys/ioctl.h> 36195957Salfred#include <sys/filio.h> 37195957Salfred#include <sys/queue.h> 38199055Sthompsa#include <sys/endian.h> 39194676Sthompsa 40194676Sthompsa#include "libusb20.h" 41194676Sthompsa#include "libusb20_desc.h" 42194676Sthompsa#include "libusb20_int.h" 43194676Sthompsa#include "libusb.h" 44194676Sthompsa#include "libusb10.h" 45194676Sthompsa 46194676Sthompsastatic pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 47194676Sthompsastruct libusb_context *usbi_default_context = NULL; 48194676Sthompsa 49195957Salfred/* Prototypes */ 50195957Salfred 51195957Salfredstatic struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 52195957Salfredstatic int libusb10_get_maxframe(struct libusb20_device *, libusb_transfer *); 53195957Salfredstatic int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 54195957Salfredstatic int libusb10_convert_error(uint8_t status); 55195957Salfredstatic void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 56195957Salfredstatic void libusb10_isoc_proxy(struct libusb20_transfer *); 57195957Salfredstatic void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 58195957Salfredstatic void libusb10_ctrl_proxy(struct libusb20_transfer *); 59195957Salfredstatic void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 60195957Salfred 61194676Sthompsa/* Library initialisation / deinitialisation */ 62194676Sthompsa 63194676Sthompsavoid 64195957Salfredlibusb_set_debug(libusb_context *ctx, int level) 65194676Sthompsa{ 66195957Salfred ctx = GET_CONTEXT(ctx); 67194676Sthompsa if (ctx) 68194676Sthompsa ctx->debug = level; 69194676Sthompsa} 70194676Sthompsa 71194676Sthompsaint 72195957Salfredlibusb_init(libusb_context **context) 73194676Sthompsa{ 74194676Sthompsa struct libusb_context *ctx; 75195957Salfred char *debug; 76194676Sthompsa int ret; 77194676Sthompsa 78194676Sthompsa ctx = malloc(sizeof(*ctx)); 79194676Sthompsa if (!ctx) 80194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 81194676Sthompsa 82194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 83194676Sthompsa 84194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 85194676Sthompsa if (debug != NULL) { 86194676Sthompsa ctx->debug = atoi(debug); 87194676Sthompsa if (ctx->debug != 0) 88194676Sthompsa ctx->debug_fixed = 1; 89194676Sthompsa } 90195957Salfred TAILQ_INIT(&ctx->pollfds); 91195957Salfred TAILQ_INIT(&ctx->tr_done); 92194676Sthompsa 93195957Salfred pthread_mutex_init(&ctx->ctx_lock, NULL); 94195957Salfred pthread_cond_init(&ctx->ctx_cond, NULL); 95194676Sthompsa 96195957Salfred ctx->ctx_handler = NO_THREAD; 97194676Sthompsa 98194676Sthompsa ret = pipe(ctx->ctrl_pipe); 99194676Sthompsa if (ret < 0) { 100195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 101195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 102194676Sthompsa free(ctx); 103194676Sthompsa return (LIBUSB_ERROR_OTHER); 104194676Sthompsa } 105195957Salfred /* set non-blocking mode on the control pipe to avoid deadlock */ 106195957Salfred ret = 1; 107195957Salfred ioctl(ctx->ctrl_pipe[0], FIONBIO, &ret); 108195957Salfred ret = 1; 109195957Salfred ioctl(ctx->ctrl_pipe[1], FIONBIO, &ret); 110194676Sthompsa 111195957Salfred libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 112194676Sthompsa 113194676Sthompsa pthread_mutex_lock(&default_context_lock); 114194676Sthompsa if (usbi_default_context == NULL) { 115194676Sthompsa usbi_default_context = ctx; 116194676Sthompsa } 117194676Sthompsa pthread_mutex_unlock(&default_context_lock); 118194676Sthompsa 119194676Sthompsa if (context) 120194676Sthompsa *context = ctx; 121194676Sthompsa 122195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 123195957Salfred 124194676Sthompsa return (0); 125194676Sthompsa} 126194676Sthompsa 127194676Sthompsavoid 128195957Salfredlibusb_exit(libusb_context *ctx) 129194676Sthompsa{ 130195957Salfred ctx = GET_CONTEXT(ctx); 131194676Sthompsa 132195957Salfred if (ctx == NULL) 133195957Salfred return; 134195957Salfred 135195957Salfred /* XXX cleanup devices */ 136195957Salfred 137195957Salfred libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 138194676Sthompsa close(ctx->ctrl_pipe[0]); 139194676Sthompsa close(ctx->ctrl_pipe[1]); 140195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 141195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 142194676Sthompsa 143194676Sthompsa pthread_mutex_lock(&default_context_lock); 144194676Sthompsa if (ctx == usbi_default_context) { 145194676Sthompsa usbi_default_context = NULL; 146194676Sthompsa } 147194676Sthompsa pthread_mutex_unlock(&default_context_lock); 148194676Sthompsa 149194676Sthompsa free(ctx); 150194676Sthompsa} 151194676Sthompsa 152194676Sthompsa/* Device handling and initialisation. */ 153194676Sthompsa 154194676Sthompsassize_t 155195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list) 156194676Sthompsa{ 157195957Salfred struct libusb20_backend *usb_backend; 158194676Sthompsa struct libusb20_device *pdev; 159194676Sthompsa struct libusb_device *dev; 160194676Sthompsa int i; 161194676Sthompsa 162195957Salfred ctx = GET_CONTEXT(ctx); 163194676Sthompsa 164195957Salfred if (ctx == NULL) 165195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 166195957Salfred 167195957Salfred if (list == NULL) 168195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 169195957Salfred 170194676Sthompsa usb_backend = libusb20_be_alloc_default(); 171194676Sthompsa if (usb_backend == NULL) 172195957Salfred return (LIBUSB_ERROR_NO_MEM); 173194676Sthompsa 174195957Salfred /* figure out how many USB devices are present */ 175194676Sthompsa pdev = NULL; 176194676Sthompsa i = 0; 177194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 178194676Sthompsa i++; 179194676Sthompsa 180195957Salfred /* allocate device pointer list */ 181194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 182194676Sthompsa if (*list == NULL) { 183194676Sthompsa libusb20_be_free(usb_backend); 184194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 185194676Sthompsa } 186195957Salfred /* create libusb v1.0 compliant devices */ 187194676Sthompsa i = 0; 188194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 189194676Sthompsa 190194676Sthompsa dev = malloc(sizeof(*dev)); 191194676Sthompsa if (dev == NULL) { 192195560Sthompsa while (i != 0) { 193195560Sthompsa libusb_unref_device((*list)[i - 1]); 194195560Sthompsa i--; 195195560Sthompsa } 196194676Sthompsa free(*list); 197195957Salfred *list = NULL; 198194676Sthompsa libusb20_be_free(usb_backend); 199194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 200194676Sthompsa } 201199055Sthompsa 202199055Sthompsa /* get device into libUSB v1.0 list */ 203199055Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 204199055Sthompsa 205194676Sthompsa memset(dev, 0, sizeof(*dev)); 206194676Sthompsa 207195957Salfred /* init transfer queues */ 208195957Salfred TAILQ_INIT(&dev->tr_head); 209195957Salfred 210195957Salfred /* set context we belong to */ 211194676Sthompsa dev->ctx = ctx; 212194676Sthompsa 213194676Sthompsa /* link together the two structures */ 214194676Sthompsa dev->os_priv = pdev; 215195957Salfred pdev->privLuData = dev; 216194676Sthompsa 217194676Sthompsa (*list)[i] = libusb_ref_device(dev); 218194676Sthompsa i++; 219194676Sthompsa } 220194676Sthompsa (*list)[i] = NULL; 221194676Sthompsa 222194676Sthompsa libusb20_be_free(usb_backend); 223194676Sthompsa return (i); 224194676Sthompsa} 225194676Sthompsa 226194676Sthompsavoid 227194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 228194676Sthompsa{ 229194676Sthompsa int i; 230194676Sthompsa 231194676Sthompsa if (list == NULL) 232195957Salfred return; /* be NULL safe */ 233194676Sthompsa 234194676Sthompsa if (unref_devices) { 235194676Sthompsa for (i = 0; list[i] != NULL; i++) 236194676Sthompsa libusb_unref_device(list[i]); 237194676Sthompsa } 238194676Sthompsa free(list); 239194676Sthompsa} 240194676Sthompsa 241194676Sthompsauint8_t 242195957Salfredlibusb_get_bus_number(libusb_device *dev) 243194676Sthompsa{ 244194676Sthompsa if (dev == NULL) 245195957Salfred return (0); /* should not happen */ 246195957Salfred return (libusb20_dev_get_bus_number(dev->os_priv)); 247194676Sthompsa} 248194676Sthompsa 249194676Sthompsauint8_t 250195957Salfredlibusb_get_device_address(libusb_device *dev) 251194676Sthompsa{ 252194676Sthompsa if (dev == NULL) 253195957Salfred return (0); /* should not happen */ 254195957Salfred return (libusb20_dev_get_address(dev->os_priv)); 255194676Sthompsa} 256194676Sthompsa 257194676Sthompsaint 258195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 259194676Sthompsa{ 260194676Sthompsa struct libusb_config_descriptor *pdconf; 261194676Sthompsa struct libusb_interface *pinf; 262194676Sthompsa struct libusb_interface_descriptor *pdinf; 263194676Sthompsa struct libusb_endpoint_descriptor *pdend; 264195957Salfred int i; 265195957Salfred int j; 266195957Salfred int k; 267195957Salfred int ret; 268194676Sthompsa 269194676Sthompsa if (dev == NULL) 270194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 271194676Sthompsa 272195957Salfred ret = libusb_get_active_config_descriptor(dev, &pdconf); 273195957Salfred if (ret < 0) 274195957Salfred return (ret); 275195957Salfred 276194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 277195957Salfred for (i = 0; i < pdconf->bNumInterfaces; i++) { 278194676Sthompsa pinf = &pdconf->interface[i]; 279195957Salfred for (j = 0; j < pinf->num_altsetting; j++) { 280194676Sthompsa pdinf = &pinf->altsetting[j]; 281195957Salfred for (k = 0; k < pdinf->bNumEndpoints; k++) { 282194676Sthompsa pdend = &pdinf->endpoint[k]; 283194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 284194676Sthompsa ret = pdend->wMaxPacketSize; 285194676Sthompsa goto out; 286194676Sthompsa } 287194676Sthompsa } 288194676Sthompsa } 289194676Sthompsa } 290194676Sthompsa 291194676Sthompsaout: 292194676Sthompsa libusb_free_config_descriptor(pdconf); 293194676Sthompsa return (ret); 294194676Sthompsa} 295194676Sthompsa 296194676Sthompsalibusb_device * 297195957Salfredlibusb_ref_device(libusb_device *dev) 298194676Sthompsa{ 299194676Sthompsa if (dev == NULL) 300195957Salfred return (NULL); /* be NULL safe */ 301194676Sthompsa 302195957Salfred CTX_LOCK(dev->ctx); 303194676Sthompsa dev->refcnt++; 304195957Salfred CTX_UNLOCK(dev->ctx); 305194676Sthompsa 306194676Sthompsa return (dev); 307194676Sthompsa} 308194676Sthompsa 309194676Sthompsavoid 310195957Salfredlibusb_unref_device(libusb_device *dev) 311194676Sthompsa{ 312194676Sthompsa if (dev == NULL) 313195957Salfred return; /* be NULL safe */ 314194676Sthompsa 315195957Salfred CTX_LOCK(dev->ctx); 316194676Sthompsa dev->refcnt--; 317195957Salfred CTX_UNLOCK(dev->ctx); 318194676Sthompsa 319194676Sthompsa if (dev->refcnt == 0) { 320194676Sthompsa libusb20_dev_free(dev->os_priv); 321194676Sthompsa free(dev); 322194676Sthompsa } 323194676Sthompsa} 324194676Sthompsa 325194676Sthompsaint 326195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh) 327194676Sthompsa{ 328194676Sthompsa libusb_context *ctx = dev->ctx; 329194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 330195957Salfred uint8_t dummy; 331194676Sthompsa int err; 332194676Sthompsa 333194676Sthompsa if (devh == NULL) 334194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 335194676Sthompsa 336195957Salfred /* set default device handle value */ 337195957Salfred *devh = NULL; 338194676Sthompsa 339195957Salfred dev = libusb_ref_device(dev); 340195957Salfred if (dev == NULL) 341195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 342195957Salfred 343194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 344194676Sthompsa if (err) { 345195957Salfred libusb_unref_device(dev); 346194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 347194676Sthompsa } 348195957Salfred libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 349194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 350194676Sthompsa 351195957Salfred /* make sure our event loop detects the new device */ 352195957Salfred dummy = 0; 353194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 354195957Salfred if (err < sizeof(dummy)) { 355195957Salfred /* ignore error, if any */ 356195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 357194676Sthompsa } 358195957Salfred *devh = pdev; 359194676Sthompsa 360194676Sthompsa return (0); 361194676Sthompsa} 362194676Sthompsa 363194676Sthompsalibusb_device_handle * 364195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 365194676Sthompsa uint16_t product_id) 366194676Sthompsa{ 367194676Sthompsa struct libusb_device **devs; 368194676Sthompsa struct libusb20_device *pdev; 369194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 370195957Salfred int i; 371195957Salfred int j; 372194676Sthompsa 373195957Salfred ctx = GET_CONTEXT(ctx); 374195957Salfred if (ctx == NULL) 375195957Salfred return (NULL); /* be NULL safe */ 376195957Salfred 377195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 378194676Sthompsa 379194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 380194676Sthompsa return (NULL); 381194676Sthompsa 382195957Salfred pdev = NULL; 383195957Salfred 384194676Sthompsa for (j = 0; j < i; j++) { 385195957Salfred pdev = devs[j]->os_priv; 386194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 387195957Salfred /* 388195957Salfred * NOTE: The USB library will automatically swap the 389195957Salfred * fields in the device descriptor to be of host 390195957Salfred * endian type! 391195957Salfred */ 392194676Sthompsa if (pdesc->idVendor == vendor_id && 393195560Sthompsa pdesc->idProduct == product_id) { 394195957Salfred if (libusb_open(devs[j], &pdev) < 0) 395195957Salfred pdev = NULL; 396195957Salfred break; 397195560Sthompsa } 398194676Sthompsa } 399194676Sthompsa 400194676Sthompsa libusb_free_device_list(devs, 1); 401195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 402195957Salfred return (pdev); 403194676Sthompsa} 404194676Sthompsa 405194676Sthompsavoid 406195957Salfredlibusb_close(struct libusb20_device *pdev) 407194676Sthompsa{ 408194676Sthompsa libusb_context *ctx; 409195957Salfred struct libusb_device *dev; 410195957Salfred uint8_t dummy; 411194676Sthompsa int err; 412194676Sthompsa 413195957Salfred if (pdev == NULL) 414195957Salfred return; /* be NULL safe */ 415194676Sthompsa 416195957Salfred dev = libusb_get_device(pdev); 417195957Salfred ctx = dev->ctx; 418194676Sthompsa 419195957Salfred libusb10_remove_pollfd(ctx, &dev->dev_poll); 420194676Sthompsa 421195957Salfred libusb20_dev_close(pdev); 422199055Sthompsa 423199055Sthompsa /* unref will free the "pdev" when the refcount reaches zero */ 424195957Salfred libusb_unref_device(dev); 425194676Sthompsa 426195957Salfred /* make sure our event loop detects the closed device */ 427195957Salfred dummy = 0; 428194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 429195957Salfred if (err < sizeof(dummy)) { 430195957Salfred /* ignore error, if any */ 431195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 432194676Sthompsa } 433194676Sthompsa} 434194676Sthompsa 435194676Sthompsalibusb_device * 436195957Salfredlibusb_get_device(struct libusb20_device *pdev) 437194676Sthompsa{ 438195957Salfred if (pdev == NULL) 439194676Sthompsa return (NULL); 440195957Salfred return ((libusb_device *)pdev->privLuData); 441194676Sthompsa} 442194676Sthompsa 443194676Sthompsaint 444195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config) 445194676Sthompsa{ 446195957Salfred struct libusb20_config *pconf; 447194676Sthompsa 448195957Salfred if (pdev == NULL || config == NULL) 449194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 450194676Sthompsa 451195957Salfred pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 452195957Salfred if (pconf == NULL) 453195957Salfred return (LIBUSB_ERROR_NO_MEM); 454194676Sthompsa 455195957Salfred *config = pconf->desc.bConfigurationValue; 456195957Salfred 457195957Salfred free(pconf); 458195957Salfred 459194676Sthompsa return (0); 460194676Sthompsa} 461194676Sthompsa 462194676Sthompsaint 463195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration) 464194676Sthompsa{ 465195957Salfred struct libusb20_config *pconf; 466195957Salfred struct libusb_device *dev; 467195957Salfred int err; 468195957Salfred uint8_t i; 469194676Sthompsa 470195957Salfred dev = libusb_get_device(pdev); 471194676Sthompsa 472195957Salfred if (dev == NULL) 473194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 474194676Sthompsa 475195957Salfred if (configuration < 1) { 476195957Salfred /* unconfigure */ 477195957Salfred i = 255; 478195957Salfred } else { 479195957Salfred for (i = 0; i != 255; i++) { 480195957Salfred uint8_t found; 481194676Sthompsa 482195957Salfred pconf = libusb20_dev_alloc_config(pdev, i); 483195957Salfred if (pconf == NULL) 484195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 485195957Salfred found = (pconf->desc.bConfigurationValue 486195957Salfred == configuration); 487195957Salfred free(pconf); 488195957Salfred 489195957Salfred if (found) 490195957Salfred goto set_config; 491195957Salfred } 492195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 493195957Salfred } 494195957Salfred 495195957Salfredset_config: 496195957Salfred 497195957Salfred libusb10_cancel_all_transfer(dev); 498195957Salfred 499195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 500195957Salfred 501195957Salfred err = libusb20_dev_set_config_index(pdev, i); 502195957Salfred 503195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 504195957Salfred POLLOUT | POLLRDNORM | POLLWRNORM); 505195957Salfred 506195957Salfred return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 507194676Sthompsa} 508194676Sthompsa 509194676Sthompsaint 510195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number) 511194676Sthompsa{ 512195957Salfred libusb_device *dev; 513195957Salfred int err = 0; 514194676Sthompsa 515195957Salfred dev = libusb_get_device(pdev); 516194676Sthompsa if (dev == NULL) 517194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 518194676Sthompsa 519195957Salfred if (interface_number < 0 || interface_number > 31) 520194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 521194676Sthompsa 522195957Salfred CTX_LOCK(dev->ctx); 523194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 524195957Salfred err = LIBUSB_ERROR_BUSY; 525194676Sthompsa 526195957Salfred if (!err) 527194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 528195957Salfred CTX_UNLOCK(dev->ctx); 529195957Salfred return (err); 530194676Sthompsa} 531194676Sthompsa 532194676Sthompsaint 533195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number) 534194676Sthompsa{ 535195957Salfred libusb_device *dev; 536195957Salfred int err = 0; 537194676Sthompsa 538195957Salfred dev = libusb_get_device(pdev); 539194676Sthompsa if (dev == NULL) 540194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 541194676Sthompsa 542195957Salfred if (interface_number < 0 || interface_number > 31) 543194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 544194676Sthompsa 545195957Salfred CTX_LOCK(dev->ctx); 546194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 547195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 548194676Sthompsa 549195957Salfred if (!err) 550194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 551195957Salfred CTX_UNLOCK(dev->ctx); 552195957Salfred return (err); 553194676Sthompsa} 554194676Sthompsa 555194676Sthompsaint 556195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev, 557194676Sthompsa int interface_number, int alternate_setting) 558194676Sthompsa{ 559195957Salfred libusb_device *dev; 560195957Salfred int err = 0; 561194676Sthompsa 562195957Salfred dev = libusb_get_device(pdev); 563194676Sthompsa if (dev == NULL) 564194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 565194676Sthompsa 566195957Salfred if (interface_number < 0 || interface_number > 31) 567194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 568194676Sthompsa 569195957Salfred CTX_LOCK(dev->ctx); 570195957Salfred if (!(dev->claimed_interfaces & (1 << interface_number))) 571195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 572195957Salfred CTX_UNLOCK(dev->ctx); 573194676Sthompsa 574195957Salfred if (err) 575195957Salfred return (err); 576195957Salfred 577195957Salfred libusb10_cancel_all_transfer(dev); 578195957Salfred 579195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 580195957Salfred 581195957Salfred err = libusb20_dev_set_alt_index(pdev, 582195957Salfred interface_number, alternate_setting); 583195957Salfred 584195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 585195957Salfred pdev, libusb20_dev_get_fd(pdev), 586195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 587195957Salfred 588195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 589194676Sthompsa} 590194676Sthompsa 591195957Salfredstatic struct libusb20_transfer * 592195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev, 593195957Salfred uint8_t endpoint, uint8_t index) 594195957Salfred{ 595195957Salfred index &= 1; /* double buffering */ 596195957Salfred 597195957Salfred index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 598195957Salfred 599195957Salfred if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 600195957Salfred /* this is an IN endpoint */ 601195957Salfred index |= 2; 602195957Salfred } 603195957Salfred return (libusb20_tr_get_pointer(pdev, index)); 604195957Salfred} 605195957Salfred 606194676Sthompsaint 607195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 608194676Sthompsa{ 609194676Sthompsa struct libusb20_transfer *xfer; 610195957Salfred struct libusb_device *dev; 611195957Salfred int err; 612194676Sthompsa 613195957Salfred xfer = libusb10_get_transfer(pdev, endpoint, 0); 614195560Sthompsa if (xfer == NULL) 615195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 616194676Sthompsa 617195957Salfred dev = libusb_get_device(pdev); 618195957Salfred 619195957Salfred CTX_LOCK(dev->ctx); 620195957Salfred err = libusb20_tr_open(xfer, 0, 0, endpoint); 621195957Salfred CTX_UNLOCK(dev->ctx); 622195957Salfred 623195957Salfred if (err != 0 && err != LIBUSB20_ERROR_BUSY) 624194676Sthompsa return (LIBUSB_ERROR_OTHER); 625194676Sthompsa 626194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 627195957Salfred 628195957Salfred /* check if we opened the transfer */ 629195957Salfred if (err == 0) { 630195957Salfred CTX_LOCK(dev->ctx); 631194676Sthompsa libusb20_tr_close(xfer); 632195957Salfred CTX_UNLOCK(dev->ctx); 633195957Salfred } 634195957Salfred return (0); /* success */ 635194676Sthompsa} 636194676Sthompsa 637194676Sthompsaint 638195957Salfredlibusb_reset_device(struct libusb20_device *pdev) 639194676Sthompsa{ 640195957Salfred libusb_device *dev; 641195957Salfred int err; 642194676Sthompsa 643195957Salfred dev = libusb_get_device(pdev); 644194676Sthompsa if (dev == NULL) 645194676Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 646194676Sthompsa 647195957Salfred libusb10_cancel_all_transfer(dev); 648195957Salfred 649195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 650195957Salfred 651195957Salfred err = libusb20_dev_reset(pdev); 652195957Salfred 653195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 654195957Salfred pdev, libusb20_dev_get_fd(pdev), 655195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 656195957Salfred 657195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 658194676Sthompsa} 659194676Sthompsa 660194676Sthompsaint 661195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 662194676Sthompsa{ 663195957Salfred if (pdev == NULL) 664194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 665194676Sthompsa 666195957Salfred return (libusb20_dev_kernel_driver_active( 667195957Salfred pdev, interface)); 668194676Sthompsa} 669194676Sthompsa 670194676Sthompsaint 671195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 672194676Sthompsa{ 673195957Salfred int err; 674194676Sthompsa 675195957Salfred if (pdev == NULL) 676194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 677194676Sthompsa 678195957Salfred err = libusb20_dev_detach_kernel_driver( 679195957Salfred pdev, interface); 680194676Sthompsa 681195957Salfred return (err ? LIBUSB20_ERROR_OTHER : 0); 682194676Sthompsa} 683194676Sthompsa 684194676Sthompsaint 685195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 686194676Sthompsa{ 687195957Salfred if (pdev == NULL) 688194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 689195957Salfred /* stub - currently not supported by libusb20 */ 690194676Sthompsa return (0); 691194676Sthompsa} 692194676Sthompsa 693194676Sthompsa/* Asynchronous device I/O */ 694194676Sthompsa 695194676Sthompsastruct libusb_transfer * 696194676Sthompsalibusb_alloc_transfer(int iso_packets) 697194676Sthompsa{ 698195957Salfred struct libusb_transfer *uxfer; 699195957Salfred struct libusb_super_transfer *sxfer; 700194676Sthompsa int len; 701194676Sthompsa 702194676Sthompsa len = sizeof(struct libusb_transfer) + 703195957Salfred sizeof(struct libusb_super_transfer) + 704194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 705194676Sthompsa 706195957Salfred sxfer = malloc(len); 707195957Salfred if (sxfer == NULL) 708194676Sthompsa return (NULL); 709194676Sthompsa 710195957Salfred memset(sxfer, 0, len); 711194676Sthompsa 712195957Salfred uxfer = (struct libusb_transfer *)( 713195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 714194676Sthompsa 715195957Salfred /* set default value */ 716195957Salfred uxfer->num_iso_packets = iso_packets; 717195957Salfred 718195957Salfred return (uxfer); 719194676Sthompsa} 720194676Sthompsa 721194676Sthompsavoid 722195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 723194676Sthompsa{ 724195957Salfred struct libusb_super_transfer *sxfer; 725194676Sthompsa 726195957Salfred if (uxfer == NULL) 727195957Salfred return; /* be NULL safe */ 728194676Sthompsa 729195957Salfred sxfer = (struct libusb_super_transfer *)( 730195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 731194676Sthompsa 732195957Salfred free(sxfer); 733194676Sthompsa} 734194676Sthompsa 735195560Sthompsastatic int 736195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 737195560Sthompsa{ 738195560Sthompsa int ret; 739195560Sthompsa int usb_speed; 740195560Sthompsa 741195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 742195560Sthompsa 743195560Sthompsa switch (xfer->type) { 744195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 745195560Sthompsa switch (usb_speed) { 746195560Sthompsa case LIBUSB20_SPEED_LOW: 747195560Sthompsa case LIBUSB20_SPEED_FULL: 748195560Sthompsa ret = 60 * 1; 749195957Salfred break; 750195957Salfred default: 751195560Sthompsa ret = 60 * 8; 752195957Salfred break; 753195560Sthompsa } 754195957Salfred break; 755195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 756195560Sthompsa ret = 2; 757195957Salfred break; 758195560Sthompsa default: 759195560Sthompsa ret = 1; 760195957Salfred break; 761195560Sthompsa } 762195957Salfred return (ret); 763195560Sthompsa} 764195560Sthompsa 765195560Sthompsastatic int 766195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 767195560Sthompsa{ 768195560Sthompsa int ret; 769195560Sthompsa int usb_speed; 770195560Sthompsa 771195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 772195560Sthompsa 773195560Sthompsa switch (xfer->type) { 774195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 775195957Salfred ret = 0; /* kernel will auto-select */ 776195957Salfred break; 777195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 778195957Salfred ret = 1024; 779195957Salfred break; 780195957Salfred default: 781195560Sthompsa switch (usb_speed) { 782195957Salfred case LIBUSB20_SPEED_LOW: 783195957Salfred ret = 256; 784195957Salfred break; 785195957Salfred case LIBUSB20_SPEED_FULL: 786195957Salfred ret = 4096; 787195957Salfred break; 788195957Salfred default: 789195957Salfred ret = 16384; 790195957Salfred break; 791195560Sthompsa } 792195957Salfred break; 793195560Sthompsa } 794195957Salfred return (ret); 795195560Sthompsa} 796195560Sthompsa 797195957Salfredstatic int 798195957Salfredlibusb10_convert_error(uint8_t status) 799195957Salfred{ 800195957Salfred ; /* indent fix */ 801195957Salfred 802195957Salfred switch (status) { 803195957Salfred case LIBUSB20_TRANSFER_START: 804195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 805195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 806195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 807195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 808195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 809195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 810195957Salfred case LIBUSB20_TRANSFER_STALL: 811195957Salfred return (LIBUSB_TRANSFER_STALL); 812195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 813195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 814195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 815195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 816195957Salfred default: 817195957Salfred return (LIBUSB_TRANSFER_ERROR); 818195957Salfred } 819195957Salfred} 820195957Salfred 821195957Salfred/* This function must be called locked */ 822195957Salfred 823194676Sthompsastatic void 824195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 825195957Salfred struct libusb_super_transfer *sxfer, int status) 826194676Sthompsa{ 827195957Salfred struct libusb_transfer *uxfer; 828195957Salfred struct libusb_device *dev; 829195957Salfred 830195957Salfred uxfer = (struct libusb_transfer *)( 831195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 832195957Salfred 833195957Salfred if (pxfer != NULL) 834195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 835195957Salfred 836199575Sthompsa /* set transfer status */ 837195957Salfred uxfer->status = status; 838195957Salfred 839199575Sthompsa /* update super transfer state */ 840199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 841199575Sthompsa 842195957Salfred dev = libusb_get_device(uxfer->dev_handle); 843195957Salfred 844195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 845195957Salfred} 846195957Salfred 847195957Salfred/* This function must be called locked */ 848195957Salfred 849195957Salfredstatic void 850195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 851195957Salfred{ 852195957Salfred struct libusb_super_transfer *sxfer; 853195957Salfred struct libusb_transfer *uxfer; 854195957Salfred uint32_t actlen; 855195957Salfred uint16_t iso_packets; 856195957Salfred uint16_t i; 857194676Sthompsa uint8_t status; 858195957Salfred uint8_t flags; 859194676Sthompsa 860195957Salfred status = libusb20_tr_get_status(pxfer); 861195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 862195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 863195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 864194676Sthompsa 865195957Salfred if (sxfer == NULL) 866195957Salfred return; /* cancelled - nothing to do */ 867195957Salfred 868195957Salfred uxfer = (struct libusb_transfer *)( 869195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 870195957Salfred 871195957Salfred if (iso_packets > uxfer->num_iso_packets) 872195957Salfred iso_packets = uxfer->num_iso_packets; 873195957Salfred 874195957Salfred if (iso_packets == 0) 875195957Salfred return; /* nothing to do */ 876195957Salfred 877195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 878195957Salfred uxfer->num_iso_packets = iso_packets; 879195957Salfred 880195957Salfred flags = uxfer->flags; 881195957Salfred 882194676Sthompsa switch (status) { 883194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 884195560Sthompsa 885195957Salfred /* update actual length */ 886195957Salfred uxfer->actual_length = actlen; 887195957Salfred for (i = 0; i != iso_packets; i++) { 888195957Salfred uxfer->iso_packet_desc[i].actual_length = 889195957Salfred libusb20_tr_get_length(pxfer, i); 890195957Salfred } 891195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 892195957Salfred break; 893195560Sthompsa 894194676Sthompsa case LIBUSB20_TRANSFER_START: 895195957Salfred 896195957Salfred /* setup length(s) */ 897195957Salfred actlen = 0; 898195957Salfred for (i = 0; i != iso_packets; i++) { 899195957Salfred libusb20_tr_setup_isoc(pxfer, 900195957Salfred &uxfer->buffer[actlen], 901195957Salfred uxfer->iso_packet_desc[i].length, i); 902195957Salfred actlen += uxfer->iso_packet_desc[i].length; 903194676Sthompsa } 904195957Salfred 905195957Salfred /* no remainder */ 906195957Salfred sxfer->rem_len = 0; 907195957Salfred 908195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 909195957Salfred libusb20_tr_submit(pxfer); 910195957Salfred 911195957Salfred /* fork another USB transfer, if any */ 912195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 913195957Salfred break; 914195957Salfred 915194676Sthompsa default: 916195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 917195957Salfred break; 918194676Sthompsa } 919195957Salfred} 920194676Sthompsa 921195957Salfred/* This function must be called locked */ 922195957Salfred 923195957Salfredstatic void 924195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 925195957Salfred{ 926195957Salfred struct libusb_super_transfer *sxfer; 927195957Salfred struct libusb_transfer *uxfer; 928195957Salfred uint32_t max_bulk; 929195957Salfred uint32_t actlen; 930195957Salfred uint8_t status; 931195957Salfred uint8_t flags; 932195957Salfred 933195957Salfred status = libusb20_tr_get_status(pxfer); 934195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 935195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 936195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 937195957Salfred 938195957Salfred if (sxfer == NULL) 939195957Salfred return; /* cancelled - nothing to do */ 940195957Salfred 941195957Salfred uxfer = (struct libusb_transfer *)( 942195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 943195957Salfred 944195957Salfred flags = uxfer->flags; 945195957Salfred 946194676Sthompsa switch (status) { 947194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 948195957Salfred 949195957Salfred uxfer->actual_length += actlen; 950195957Salfred 951195957Salfred /* check for short packet */ 952195957Salfred if (sxfer->last_len != actlen) { 953195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 954195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 955195957Salfred } else { 956195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 957195957Salfred } 958195957Salfred break; 959195957Salfred } 960195957Salfred /* check for end of data */ 961195957Salfred if (sxfer->rem_len == 0) { 962195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 963195957Salfred break; 964195957Salfred } 965195957Salfred /* FALLTHROUGH */ 966195957Salfred 967195957Salfred case LIBUSB20_TRANSFER_START: 968195957Salfred if (max_bulk > sxfer->rem_len) { 969195957Salfred max_bulk = sxfer->rem_len; 970195957Salfred } 971195957Salfred /* setup new BULK or INTERRUPT transaction */ 972195957Salfred libusb20_tr_setup_bulk(pxfer, 973195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 974195957Salfred 975195957Salfred /* update counters */ 976195957Salfred sxfer->last_len = max_bulk; 977195957Salfred sxfer->curr_data += max_bulk; 978195957Salfred sxfer->rem_len -= max_bulk; 979195957Salfred 980195957Salfred libusb20_tr_submit(pxfer); 981195957Salfred 982195957Salfred /* check if we can fork another USB transfer */ 983195957Salfred if (sxfer->rem_len == 0) 984195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 985195957Salfred break; 986195957Salfred 987195957Salfred default: 988195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 989195957Salfred break; 990194676Sthompsa } 991194676Sthompsa} 992194676Sthompsa 993195957Salfred/* This function must be called locked */ 994195957Salfred 995195957Salfredstatic void 996195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 997194676Sthompsa{ 998195957Salfred struct libusb_super_transfer *sxfer; 999195957Salfred struct libusb_transfer *uxfer; 1000195957Salfred uint32_t max_bulk; 1001195957Salfred uint32_t actlen; 1002195957Salfred uint8_t status; 1003195957Salfred uint8_t flags; 1004194676Sthompsa 1005195957Salfred status = libusb20_tr_get_status(pxfer); 1006195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1007195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1008195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1009194676Sthompsa 1010195957Salfred if (sxfer == NULL) 1011195957Salfred return; /* cancelled - nothing to do */ 1012194676Sthompsa 1013195957Salfred uxfer = (struct libusb_transfer *)( 1014195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1015194676Sthompsa 1016195957Salfred flags = uxfer->flags; 1017194676Sthompsa 1018195957Salfred switch (status) { 1019195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1020194676Sthompsa 1021195957Salfred uxfer->actual_length += actlen; 1022195957Salfred 1023195957Salfred /* subtract length of SETUP packet, if any */ 1024195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1025195957Salfred 1026195957Salfred /* check for short packet */ 1027195957Salfred if (sxfer->last_len != actlen) { 1028195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1029195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1030195957Salfred } else { 1031195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1032195957Salfred } 1033195957Salfred break; 1034194676Sthompsa } 1035195957Salfred /* check for end of data */ 1036195957Salfred if (sxfer->rem_len == 0) { 1037195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1038195957Salfred break; 1039195957Salfred } 1040195957Salfred /* FALLTHROUGH */ 1041194676Sthompsa 1042195957Salfred case LIBUSB20_TRANSFER_START: 1043195957Salfred if (max_bulk > sxfer->rem_len) { 1044195957Salfred max_bulk = sxfer->rem_len; 1045195957Salfred } 1046195957Salfred /* setup new CONTROL transaction */ 1047195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1048195957Salfred /* next fragment - don't send SETUP packet */ 1049195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1050195957Salfred } else { 1051195957Salfred /* first fragment - send SETUP packet */ 1052195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1053195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1054195957Salfred } 1055195957Salfred 1056195957Salfred if (max_bulk != 0) { 1057195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1058195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1059195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1060195957Salfred } else { 1061195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1062195957Salfred } 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 } 1080195957Salfred} 1081195957Salfred 1082195957Salfred/* The following function must be called locked */ 1083195957Salfred 1084195957Salfredstatic void 1085195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1086195957Salfred{ 1087195957Salfred struct libusb20_transfer *pxfer0; 1088195957Salfred struct libusb20_transfer *pxfer1; 1089195957Salfred struct libusb_super_transfer *sxfer; 1090195957Salfred struct libusb_transfer *uxfer; 1091195957Salfred struct libusb_device *dev; 1092195957Salfred int err; 1093195957Salfred int buffsize; 1094195957Salfred int maxframe; 1095195957Salfred int temp; 1096195957Salfred uint8_t dummy; 1097195957Salfred 1098195957Salfred dev = libusb_get_device(pdev); 1099195957Salfred 1100195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1101195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1102195957Salfred 1103195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1104195957Salfred return; /* shouldn't happen */ 1105195957Salfred 1106195957Salfred temp = 0; 1107195957Salfred if (libusb20_tr_pending(pxfer0)) 1108195957Salfred temp |= 1; 1109195957Salfred if (libusb20_tr_pending(pxfer1)) 1110195957Salfred temp |= 2; 1111195957Salfred 1112195957Salfred switch (temp) { 1113195957Salfred case 3: 1114195957Salfred /* wait till one of the transfers complete */ 1115195957Salfred return; 1116195957Salfred case 2: 1117195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1118199575Sthompsa if (sxfer == NULL) 1119199575Sthompsa return; /* cancelling */ 1120195957Salfred if (sxfer->rem_len) 1121195957Salfred return; /* cannot queue another one */ 1122195957Salfred /* swap transfers */ 1123195957Salfred pxfer1 = pxfer0; 1124195957Salfred break; 1125195957Salfred case 1: 1126195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1127199575Sthompsa if (sxfer == NULL) 1128199575Sthompsa return; /* cancelling */ 1129195957Salfred if (sxfer->rem_len) 1130195957Salfred return; /* cannot queue another one */ 1131195957Salfred /* swap transfers */ 1132195957Salfred pxfer0 = pxfer1; 1133195957Salfred break; 1134195957Salfred default: 1135195957Salfred break; 1136194676Sthompsa } 1137195957Salfred 1138195957Salfred /* find next transfer on same endpoint */ 1139195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1140195957Salfred 1141195957Salfred uxfer = (struct libusb_transfer *)( 1142195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1143195957Salfred 1144195957Salfred if (uxfer->endpoint == endpoint) { 1145195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1146195957Salfred sxfer->entry.tqe_prev = NULL; 1147195957Salfred goto found; 1148194676Sthompsa } 1149195957Salfred } 1150195957Salfred return; /* success */ 1151194676Sthompsa 1152195957Salfredfound: 1153194676Sthompsa 1154195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1155195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1156194676Sthompsa 1157195957Salfred /* reset super transfer state */ 1158195957Salfred sxfer->rem_len = uxfer->length; 1159195957Salfred sxfer->curr_data = uxfer->buffer; 1160195957Salfred uxfer->actual_length = 0; 1161194676Sthompsa 1162195957Salfred switch (uxfer->type) { 1163195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1164195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1165195957Salfred break; 1166195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1167195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1168195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1169195957Salfred break; 1170195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1171195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1172195957Salfred if (sxfer->rem_len < 8) 1173195957Salfred goto failure; 1174194676Sthompsa 1175195957Salfred /* remove SETUP packet from data */ 1176195957Salfred sxfer->rem_len -= 8; 1177195957Salfred sxfer->curr_data += 8; 1178195957Salfred break; 1179195957Salfred default: 1180195957Salfred goto failure; 1181195560Sthompsa } 1182195957Salfred 1183195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1184195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1185195957Salfred 1186195957Salfred /* make sure the transfer is opened */ 1187195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1188195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1189195957Salfred goto failure; 1190194676Sthompsa } 1191195957Salfred libusb20_tr_start(pxfer0); 1192195957Salfred return; 1193194676Sthompsa 1194195957Salfredfailure: 1195195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1196194676Sthompsa 1197195957Salfred /* make sure our event loop spins the done handler */ 1198195957Salfred dummy = 0; 1199195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1200195957Salfred} 1201194676Sthompsa 1202195957Salfred/* The following function must be called unlocked */ 1203194676Sthompsa 1204195957Salfredint 1205195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1206195957Salfred{ 1207195957Salfred struct libusb20_transfer *pxfer0; 1208195957Salfred struct libusb20_transfer *pxfer1; 1209195957Salfred struct libusb_super_transfer *sxfer; 1210195957Salfred struct libusb_device *dev; 1211199055Sthompsa uint32_t endpoint; 1212195957Salfred int err; 1213195957Salfred 1214195957Salfred if (uxfer == NULL) 1215195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1216195957Salfred 1217195957Salfred if (uxfer->dev_handle == NULL) 1218195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1219195957Salfred 1220195957Salfred endpoint = uxfer->endpoint; 1221195957Salfred 1222195957Salfred if (endpoint > 255) 1223195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1224195957Salfred 1225195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1226195957Salfred 1227195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1228195957Salfred 1229195957Salfred sxfer = (struct libusb_super_transfer *)( 1230195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1231195957Salfred 1232195957Salfred CTX_LOCK(dev->ctx); 1233195957Salfred 1234195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1235195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1236195957Salfred 1237195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1238195957Salfred err = LIBUSB_ERROR_OTHER; 1239195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1240199575Sthompsa (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1241195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1242195957Salfred err = LIBUSB_ERROR_BUSY; 1243195957Salfred } else { 1244199575Sthompsa 1245199575Sthompsa /* set pending state */ 1246199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 1247199575Sthompsa 1248199575Sthompsa /* insert transfer into transfer head list */ 1249195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1250195957Salfred 1251199575Sthompsa /* start work transfers */ 1252195957Salfred libusb10_submit_transfer_sub( 1253195957Salfred uxfer->dev_handle, endpoint); 1254195957Salfred 1255195957Salfred err = 0; /* success */ 1256195957Salfred } 1257195957Salfred 1258195957Salfred CTX_UNLOCK(dev->ctx); 1259195957Salfred 1260195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1261195957Salfred 1262195957Salfred return (err); 1263194676Sthompsa} 1264194676Sthompsa 1265195957Salfred/* Asynchronous transfer cancel */ 1266195957Salfred 1267194676Sthompsaint 1268195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1269194676Sthompsa{ 1270195957Salfred struct libusb20_transfer *pxfer0; 1271195957Salfred struct libusb20_transfer *pxfer1; 1272195957Salfred struct libusb_super_transfer *sxfer; 1273195957Salfred struct libusb_device *dev; 1274199055Sthompsa uint32_t endpoint; 1275199575Sthompsa int retval; 1276194676Sthompsa 1277195957Salfred if (uxfer == NULL) 1278195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1279194676Sthompsa 1280199575Sthompsa /* check if not initialised */ 1281195957Salfred if (uxfer->dev_handle == NULL) 1282199575Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 1283194676Sthompsa 1284195957Salfred endpoint = uxfer->endpoint; 1285194676Sthompsa 1286195957Salfred if (endpoint > 255) 1287195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1288195957Salfred 1289195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1290195957Salfred 1291195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1292195957Salfred 1293195957Salfred sxfer = (struct libusb_super_transfer *)( 1294195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1295195957Salfred 1296199575Sthompsa retval = 0; 1297199575Sthompsa 1298195957Salfred CTX_LOCK(dev->ctx); 1299195957Salfred 1300195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1301195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1302195957Salfred 1303199575Sthompsa if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 1304199575Sthompsa /* only update the transfer status */ 1305199575Sthompsa uxfer->status = LIBUSB_TRANSFER_CANCELLED; 1306199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1307199575Sthompsa } else if (sxfer->entry.tqe_prev != NULL) { 1308195957Salfred /* we are lucky - transfer is on a queue */ 1309195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1310195957Salfred sxfer->entry.tqe_prev = NULL; 1311199575Sthompsa libusb10_complete_transfer(NULL, 1312199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1313195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1314195957Salfred /* not started */ 1315199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1316195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1317199575Sthompsa libusb10_complete_transfer(pxfer0, 1318199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1319195957Salfred libusb20_tr_stop(pxfer0); 1320195957Salfred /* make sure the queue doesn't stall */ 1321195957Salfred libusb10_submit_transfer_sub( 1322195957Salfred uxfer->dev_handle, endpoint); 1323195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1324199575Sthompsa libusb10_complete_transfer(pxfer1, 1325199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1326195957Salfred libusb20_tr_stop(pxfer1); 1327195957Salfred /* make sure the queue doesn't stall */ 1328195957Salfred libusb10_submit_transfer_sub( 1329195957Salfred uxfer->dev_handle, endpoint); 1330195957Salfred } else { 1331195957Salfred /* not started */ 1332199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1333195957Salfred } 1334195957Salfred 1335195957Salfred CTX_UNLOCK(dev->ctx); 1336195957Salfred 1337195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1338195957Salfred 1339199575Sthompsa return (retval); 1340194676Sthompsa} 1341194676Sthompsa 1342195957SalfredUNEXPORTED void 1343195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1344195957Salfred{ 1345195957Salfred /* TODO */ 1346195957Salfred} 1347199055Sthompsa 1348199055Sthompsauint16_t 1349199055Sthompsalibusb_cpu_to_le16(uint16_t x) 1350199055Sthompsa{ 1351199055Sthompsa return (htole16(x)); 1352199055Sthompsa} 1353199055Sthompsa 1354199055Sthompsauint16_t 1355199055Sthompsalibusb_le16_to_cpu(uint16_t x) 1356199055Sthompsa{ 1357199055Sthompsa return (le16toh(x)); 1358199055Sthompsa} 1359199055Sthompsa 1360