libusb10.c revision 195957
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 195957 2009-07-30 00:11:41Z alfred $ */ 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> 38194676Sthompsa 39194676Sthompsa#include "libusb20.h" 40194676Sthompsa#include "libusb20_desc.h" 41194676Sthompsa#include "libusb20_int.h" 42194676Sthompsa#include "libusb.h" 43194676Sthompsa#include "libusb10.h" 44194676Sthompsa 45194676Sthompsastatic pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 46194676Sthompsastruct libusb_context *usbi_default_context = NULL; 47194676Sthompsa 48195957Salfred/* Prototypes */ 49195957Salfred 50195957Salfredstatic struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 51195957Salfredstatic int libusb10_get_maxframe(struct libusb20_device *, libusb_transfer *); 52195957Salfredstatic int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 53195957Salfredstatic int libusb10_convert_error(uint8_t status); 54195957Salfredstatic void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 55195957Salfredstatic void libusb10_isoc_proxy(struct libusb20_transfer *); 56195957Salfredstatic void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 57195957Salfredstatic void libusb10_ctrl_proxy(struct libusb20_transfer *); 58195957Salfredstatic void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 59195957Salfred 60194676Sthompsa/* Library initialisation / deinitialisation */ 61194676Sthompsa 62194676Sthompsavoid 63195957Salfredlibusb_set_debug(libusb_context *ctx, int level) 64194676Sthompsa{ 65195957Salfred ctx = GET_CONTEXT(ctx); 66194676Sthompsa if (ctx) 67194676Sthompsa ctx->debug = level; 68194676Sthompsa} 69194676Sthompsa 70194676Sthompsaint 71195957Salfredlibusb_init(libusb_context **context) 72194676Sthompsa{ 73194676Sthompsa struct libusb_context *ctx; 74195957Salfred char *debug; 75194676Sthompsa int ret; 76194676Sthompsa 77194676Sthompsa ctx = malloc(sizeof(*ctx)); 78194676Sthompsa if (!ctx) 79194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 80194676Sthompsa 81194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 82194676Sthompsa 83194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 84194676Sthompsa if (debug != NULL) { 85194676Sthompsa ctx->debug = atoi(debug); 86194676Sthompsa if (ctx->debug != 0) 87194676Sthompsa ctx->debug_fixed = 1; 88194676Sthompsa } 89195957Salfred TAILQ_INIT(&ctx->pollfds); 90195957Salfred TAILQ_INIT(&ctx->tr_done); 91194676Sthompsa 92195957Salfred pthread_mutex_init(&ctx->ctx_lock, NULL); 93195957Salfred pthread_cond_init(&ctx->ctx_cond, NULL); 94194676Sthompsa 95195957Salfred ctx->ctx_handler = NO_THREAD; 96194676Sthompsa 97194676Sthompsa ret = pipe(ctx->ctrl_pipe); 98194676Sthompsa if (ret < 0) { 99195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 100195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 101194676Sthompsa free(ctx); 102194676Sthompsa return (LIBUSB_ERROR_OTHER); 103194676Sthompsa } 104195957Salfred /* set non-blocking mode on the control pipe to avoid deadlock */ 105195957Salfred ret = 1; 106195957Salfred ioctl(ctx->ctrl_pipe[0], FIONBIO, &ret); 107195957Salfred ret = 1; 108195957Salfred ioctl(ctx->ctrl_pipe[1], FIONBIO, &ret); 109194676Sthompsa 110195957Salfred libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 111194676Sthompsa 112194676Sthompsa pthread_mutex_lock(&default_context_lock); 113194676Sthompsa if (usbi_default_context == NULL) { 114194676Sthompsa usbi_default_context = ctx; 115194676Sthompsa } 116194676Sthompsa pthread_mutex_unlock(&default_context_lock); 117194676Sthompsa 118194676Sthompsa if (context) 119194676Sthompsa *context = ctx; 120194676Sthompsa 121195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 122195957Salfred 123194676Sthompsa return (0); 124194676Sthompsa} 125194676Sthompsa 126194676Sthompsavoid 127195957Salfredlibusb_exit(libusb_context *ctx) 128194676Sthompsa{ 129195957Salfred ctx = GET_CONTEXT(ctx); 130194676Sthompsa 131195957Salfred if (ctx == NULL) 132195957Salfred return; 133195957Salfred 134195957Salfred /* XXX cleanup devices */ 135195957Salfred 136195957Salfred libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 137194676Sthompsa close(ctx->ctrl_pipe[0]); 138194676Sthompsa close(ctx->ctrl_pipe[1]); 139195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 140195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 141194676Sthompsa 142194676Sthompsa pthread_mutex_lock(&default_context_lock); 143194676Sthompsa if (ctx == usbi_default_context) { 144194676Sthompsa usbi_default_context = NULL; 145194676Sthompsa } 146194676Sthompsa pthread_mutex_unlock(&default_context_lock); 147194676Sthompsa 148194676Sthompsa free(ctx); 149194676Sthompsa} 150194676Sthompsa 151194676Sthompsa/* Device handling and initialisation. */ 152194676Sthompsa 153194676Sthompsassize_t 154195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list) 155194676Sthompsa{ 156195957Salfred struct libusb20_backend *usb_backend; 157194676Sthompsa struct libusb20_device *pdev; 158194676Sthompsa struct libusb_device *dev; 159194676Sthompsa int i; 160194676Sthompsa 161195957Salfred ctx = GET_CONTEXT(ctx); 162194676Sthompsa 163195957Salfred if (ctx == NULL) 164195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 165195957Salfred 166195957Salfred if (list == NULL) 167195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 168195957Salfred 169194676Sthompsa usb_backend = libusb20_be_alloc_default(); 170194676Sthompsa if (usb_backend == NULL) 171195957Salfred return (LIBUSB_ERROR_NO_MEM); 172194676Sthompsa 173195957Salfred /* figure out how many USB devices are present */ 174194676Sthompsa pdev = NULL; 175194676Sthompsa i = 0; 176194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 177194676Sthompsa i++; 178194676Sthompsa 179195957Salfred /* allocate device pointer list */ 180194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 181194676Sthompsa if (*list == NULL) { 182194676Sthompsa libusb20_be_free(usb_backend); 183194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 184194676Sthompsa } 185195957Salfred /* create libusb v1.0 compliant devices */ 186194676Sthompsa i = 0; 187194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 188194676Sthompsa /* get device into libUSB v1.0 list */ 189194676Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 190194676Sthompsa 191194676Sthompsa dev = malloc(sizeof(*dev)); 192194676Sthompsa if (dev == NULL) { 193195560Sthompsa while (i != 0) { 194195560Sthompsa libusb_unref_device((*list)[i - 1]); 195195560Sthompsa i--; 196195560Sthompsa } 197194676Sthompsa free(*list); 198195957Salfred *list = NULL; 199194676Sthompsa libusb20_be_free(usb_backend); 200194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 201194676Sthompsa } 202194676Sthompsa memset(dev, 0, sizeof(*dev)); 203194676Sthompsa 204195957Salfred /* init transfer queues */ 205195957Salfred TAILQ_INIT(&dev->tr_head); 206195957Salfred 207195957Salfred /* set context we belong to */ 208194676Sthompsa dev->ctx = ctx; 209194676Sthompsa 210194676Sthompsa /* link together the two structures */ 211194676Sthompsa dev->os_priv = pdev; 212195957Salfred pdev->privLuData = dev; 213194676Sthompsa 214194676Sthompsa (*list)[i] = libusb_ref_device(dev); 215194676Sthompsa i++; 216194676Sthompsa } 217194676Sthompsa (*list)[i] = NULL; 218194676Sthompsa 219194676Sthompsa libusb20_be_free(usb_backend); 220194676Sthompsa return (i); 221194676Sthompsa} 222194676Sthompsa 223194676Sthompsavoid 224194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 225194676Sthompsa{ 226194676Sthompsa int i; 227194676Sthompsa 228194676Sthompsa if (list == NULL) 229195957Salfred return; /* be NULL safe */ 230194676Sthompsa 231194676Sthompsa if (unref_devices) { 232194676Sthompsa for (i = 0; list[i] != NULL; i++) 233194676Sthompsa libusb_unref_device(list[i]); 234194676Sthompsa } 235194676Sthompsa free(list); 236194676Sthompsa} 237194676Sthompsa 238194676Sthompsauint8_t 239195957Salfredlibusb_get_bus_number(libusb_device *dev) 240194676Sthompsa{ 241194676Sthompsa if (dev == NULL) 242195957Salfred return (0); /* should not happen */ 243195957Salfred return (libusb20_dev_get_bus_number(dev->os_priv)); 244194676Sthompsa} 245194676Sthompsa 246194676Sthompsauint8_t 247195957Salfredlibusb_get_device_address(libusb_device *dev) 248194676Sthompsa{ 249194676Sthompsa if (dev == NULL) 250195957Salfred return (0); /* should not happen */ 251195957Salfred return (libusb20_dev_get_address(dev->os_priv)); 252194676Sthompsa} 253194676Sthompsa 254194676Sthompsaint 255195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 256194676Sthompsa{ 257194676Sthompsa struct libusb_config_descriptor *pdconf; 258194676Sthompsa struct libusb_interface *pinf; 259194676Sthompsa struct libusb_interface_descriptor *pdinf; 260194676Sthompsa struct libusb_endpoint_descriptor *pdend; 261195957Salfred int i; 262195957Salfred int j; 263195957Salfred int k; 264195957Salfred int ret; 265194676Sthompsa 266194676Sthompsa if (dev == NULL) 267194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 268194676Sthompsa 269195957Salfred ret = libusb_get_active_config_descriptor(dev, &pdconf); 270195957Salfred if (ret < 0) 271195957Salfred return (ret); 272195957Salfred 273194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 274195957Salfred for (i = 0; i < pdconf->bNumInterfaces; i++) { 275194676Sthompsa pinf = &pdconf->interface[i]; 276195957Salfred for (j = 0; j < pinf->num_altsetting; j++) { 277194676Sthompsa pdinf = &pinf->altsetting[j]; 278195957Salfred for (k = 0; k < pdinf->bNumEndpoints; k++) { 279194676Sthompsa pdend = &pdinf->endpoint[k]; 280194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 281194676Sthompsa ret = pdend->wMaxPacketSize; 282194676Sthompsa goto out; 283194676Sthompsa } 284194676Sthompsa } 285194676Sthompsa } 286194676Sthompsa } 287194676Sthompsa 288194676Sthompsaout: 289194676Sthompsa libusb_free_config_descriptor(pdconf); 290194676Sthompsa return (ret); 291194676Sthompsa} 292194676Sthompsa 293194676Sthompsalibusb_device * 294195957Salfredlibusb_ref_device(libusb_device *dev) 295194676Sthompsa{ 296194676Sthompsa if (dev == NULL) 297195957Salfred return (NULL); /* be NULL safe */ 298194676Sthompsa 299195957Salfred CTX_LOCK(dev->ctx); 300194676Sthompsa dev->refcnt++; 301195957Salfred CTX_UNLOCK(dev->ctx); 302194676Sthompsa 303194676Sthompsa return (dev); 304194676Sthompsa} 305194676Sthompsa 306194676Sthompsavoid 307195957Salfredlibusb_unref_device(libusb_device *dev) 308194676Sthompsa{ 309194676Sthompsa if (dev == NULL) 310195957Salfred return; /* be NULL safe */ 311194676Sthompsa 312195957Salfred CTX_LOCK(dev->ctx); 313194676Sthompsa dev->refcnt--; 314195957Salfred CTX_UNLOCK(dev->ctx); 315194676Sthompsa 316194676Sthompsa if (dev->refcnt == 0) { 317194676Sthompsa libusb20_dev_free(dev->os_priv); 318194676Sthompsa free(dev); 319194676Sthompsa } 320194676Sthompsa} 321194676Sthompsa 322194676Sthompsaint 323195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh) 324194676Sthompsa{ 325194676Sthompsa libusb_context *ctx = dev->ctx; 326194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 327195957Salfred uint8_t dummy; 328194676Sthompsa int err; 329194676Sthompsa 330194676Sthompsa if (devh == NULL) 331194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 332194676Sthompsa 333195957Salfred /* set default device handle value */ 334195957Salfred *devh = NULL; 335194676Sthompsa 336195957Salfred dev = libusb_ref_device(dev); 337195957Salfred if (dev == NULL) 338195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 339195957Salfred 340194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 341194676Sthompsa if (err) { 342195957Salfred libusb_unref_device(dev); 343194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 344194676Sthompsa } 345195957Salfred libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 346194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 347194676Sthompsa 348195957Salfred /* make sure our event loop detects the new device */ 349195957Salfred dummy = 0; 350194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 351195957Salfred if (err < sizeof(dummy)) { 352195957Salfred /* ignore error, if any */ 353195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 354194676Sthompsa } 355195957Salfred *devh = pdev; 356194676Sthompsa 357194676Sthompsa return (0); 358194676Sthompsa} 359194676Sthompsa 360194676Sthompsalibusb_device_handle * 361195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 362194676Sthompsa uint16_t product_id) 363194676Sthompsa{ 364194676Sthompsa struct libusb_device **devs; 365194676Sthompsa struct libusb20_device *pdev; 366194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 367195957Salfred int i; 368195957Salfred int j; 369194676Sthompsa 370195957Salfred ctx = GET_CONTEXT(ctx); 371195957Salfred if (ctx == NULL) 372195957Salfred return (NULL); /* be NULL safe */ 373195957Salfred 374195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 375194676Sthompsa 376194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 377194676Sthompsa return (NULL); 378194676Sthompsa 379195957Salfred pdev = NULL; 380195957Salfred 381194676Sthompsa for (j = 0; j < i; j++) { 382195957Salfred pdev = devs[j]->os_priv; 383194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 384195957Salfred /* 385195957Salfred * NOTE: The USB library will automatically swap the 386195957Salfred * fields in the device descriptor to be of host 387195957Salfred * endian type! 388195957Salfred */ 389194676Sthompsa if (pdesc->idVendor == vendor_id && 390195560Sthompsa pdesc->idProduct == product_id) { 391195957Salfred if (libusb_open(devs[j], &pdev) < 0) 392195957Salfred pdev = NULL; 393195957Salfred break; 394195560Sthompsa } 395194676Sthompsa } 396194676Sthompsa 397194676Sthompsa libusb_free_device_list(devs, 1); 398195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 399195957Salfred return (pdev); 400194676Sthompsa} 401194676Sthompsa 402194676Sthompsavoid 403195957Salfredlibusb_close(struct libusb20_device *pdev) 404194676Sthompsa{ 405194676Sthompsa libusb_context *ctx; 406195957Salfred struct libusb_device *dev; 407195957Salfred uint8_t dummy; 408194676Sthompsa int err; 409194676Sthompsa 410195957Salfred if (pdev == NULL) 411195957Salfred return; /* be NULL safe */ 412194676Sthompsa 413195957Salfred dev = libusb_get_device(pdev); 414195957Salfred ctx = dev->ctx; 415194676Sthompsa 416195957Salfred libusb10_remove_pollfd(ctx, &dev->dev_poll); 417194676Sthompsa 418195957Salfred libusb20_dev_close(pdev); 419195957Salfred libusb_unref_device(dev); 420194676Sthompsa 421195957Salfred /* make sure our event loop detects the closed device */ 422195957Salfred dummy = 0; 423194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 424195957Salfred if (err < sizeof(dummy)) { 425195957Salfred /* ignore error, if any */ 426195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 427194676Sthompsa } 428194676Sthompsa} 429194676Sthompsa 430194676Sthompsalibusb_device * 431195957Salfredlibusb_get_device(struct libusb20_device *pdev) 432194676Sthompsa{ 433195957Salfred if (pdev == NULL) 434194676Sthompsa return (NULL); 435195957Salfred return ((libusb_device *)pdev->privLuData); 436194676Sthompsa} 437194676Sthompsa 438194676Sthompsaint 439195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config) 440194676Sthompsa{ 441195957Salfred struct libusb20_config *pconf; 442194676Sthompsa 443195957Salfred if (pdev == NULL || config == NULL) 444194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 445194676Sthompsa 446195957Salfred pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 447195957Salfred if (pconf == NULL) 448195957Salfred return (LIBUSB_ERROR_NO_MEM); 449194676Sthompsa 450195957Salfred *config = pconf->desc.bConfigurationValue; 451195957Salfred 452195957Salfred free(pconf); 453195957Salfred 454194676Sthompsa return (0); 455194676Sthompsa} 456194676Sthompsa 457194676Sthompsaint 458195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration) 459194676Sthompsa{ 460195957Salfred struct libusb20_config *pconf; 461195957Salfred struct libusb_device *dev; 462195957Salfred int err; 463195957Salfred uint8_t i; 464194676Sthompsa 465195957Salfred dev = libusb_get_device(pdev); 466194676Sthompsa 467195957Salfred if (dev == NULL) 468194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 469194676Sthompsa 470195957Salfred if (configuration < 1) { 471195957Salfred /* unconfigure */ 472195957Salfred i = 255; 473195957Salfred } else { 474195957Salfred for (i = 0; i != 255; i++) { 475195957Salfred uint8_t found; 476194676Sthompsa 477195957Salfred pconf = libusb20_dev_alloc_config(pdev, i); 478195957Salfred if (pconf == NULL) 479195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 480195957Salfred found = (pconf->desc.bConfigurationValue 481195957Salfred == configuration); 482195957Salfred free(pconf); 483195957Salfred 484195957Salfred if (found) 485195957Salfred goto set_config; 486195957Salfred } 487195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 488195957Salfred } 489195957Salfred 490195957Salfredset_config: 491195957Salfred 492195957Salfred libusb10_cancel_all_transfer(dev); 493195957Salfred 494195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 495195957Salfred 496195957Salfred err = libusb20_dev_set_config_index(pdev, i); 497195957Salfred 498195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 499195957Salfred POLLOUT | POLLRDNORM | POLLWRNORM); 500195957Salfred 501195957Salfred return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 502194676Sthompsa} 503194676Sthompsa 504194676Sthompsaint 505195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number) 506194676Sthompsa{ 507195957Salfred libusb_device *dev; 508195957Salfred int err = 0; 509194676Sthompsa 510195957Salfred dev = libusb_get_device(pdev); 511194676Sthompsa if (dev == NULL) 512194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 513194676Sthompsa 514195957Salfred if (interface_number < 0 || interface_number > 31) 515194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 516194676Sthompsa 517195957Salfred CTX_LOCK(dev->ctx); 518194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 519195957Salfred err = LIBUSB_ERROR_BUSY; 520194676Sthompsa 521195957Salfred if (!err) 522194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 523195957Salfred CTX_UNLOCK(dev->ctx); 524195957Salfred return (err); 525194676Sthompsa} 526194676Sthompsa 527194676Sthompsaint 528195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number) 529194676Sthompsa{ 530195957Salfred libusb_device *dev; 531195957Salfred int err = 0; 532194676Sthompsa 533195957Salfred dev = libusb_get_device(pdev); 534194676Sthompsa if (dev == NULL) 535194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 536194676Sthompsa 537195957Salfred if (interface_number < 0 || interface_number > 31) 538194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 539194676Sthompsa 540195957Salfred CTX_LOCK(dev->ctx); 541194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 542195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 543194676Sthompsa 544195957Salfred if (!err) 545194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 546195957Salfred CTX_UNLOCK(dev->ctx); 547195957Salfred return (err); 548194676Sthompsa} 549194676Sthompsa 550194676Sthompsaint 551195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev, 552194676Sthompsa int interface_number, int alternate_setting) 553194676Sthompsa{ 554195957Salfred libusb_device *dev; 555195957Salfred int err = 0; 556194676Sthompsa 557195957Salfred dev = libusb_get_device(pdev); 558194676Sthompsa if (dev == NULL) 559194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 560194676Sthompsa 561195957Salfred if (interface_number < 0 || interface_number > 31) 562194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 563194676Sthompsa 564195957Salfred CTX_LOCK(dev->ctx); 565195957Salfred if (!(dev->claimed_interfaces & (1 << interface_number))) 566195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 567195957Salfred CTX_UNLOCK(dev->ctx); 568194676Sthompsa 569195957Salfred if (err) 570195957Salfred return (err); 571195957Salfred 572195957Salfred libusb10_cancel_all_transfer(dev); 573195957Salfred 574195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 575195957Salfred 576195957Salfred err = libusb20_dev_set_alt_index(pdev, 577195957Salfred interface_number, alternate_setting); 578195957Salfred 579195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 580195957Salfred pdev, libusb20_dev_get_fd(pdev), 581195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 582195957Salfred 583195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 584194676Sthompsa} 585194676Sthompsa 586195957Salfredstatic struct libusb20_transfer * 587195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev, 588195957Salfred uint8_t endpoint, uint8_t index) 589195957Salfred{ 590195957Salfred index &= 1; /* double buffering */ 591195957Salfred 592195957Salfred index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 593195957Salfred 594195957Salfred if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 595195957Salfred /* this is an IN endpoint */ 596195957Salfred index |= 2; 597195957Salfred } 598195957Salfred return (libusb20_tr_get_pointer(pdev, index)); 599195957Salfred} 600195957Salfred 601194676Sthompsaint 602195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 603194676Sthompsa{ 604194676Sthompsa struct libusb20_transfer *xfer; 605195957Salfred struct libusb_device *dev; 606195957Salfred int err; 607194676Sthompsa 608195957Salfred xfer = libusb10_get_transfer(pdev, endpoint, 0); 609195560Sthompsa if (xfer == NULL) 610195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 611194676Sthompsa 612195957Salfred dev = libusb_get_device(pdev); 613195957Salfred 614195957Salfred CTX_LOCK(dev->ctx); 615195957Salfred err = libusb20_tr_open(xfer, 0, 0, endpoint); 616195957Salfred CTX_UNLOCK(dev->ctx); 617195957Salfred 618195957Salfred if (err != 0 && err != LIBUSB20_ERROR_BUSY) 619194676Sthompsa return (LIBUSB_ERROR_OTHER); 620194676Sthompsa 621194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 622195957Salfred 623195957Salfred /* check if we opened the transfer */ 624195957Salfred if (err == 0) { 625195957Salfred CTX_LOCK(dev->ctx); 626194676Sthompsa libusb20_tr_close(xfer); 627195957Salfred CTX_UNLOCK(dev->ctx); 628195957Salfred } 629195957Salfred return (0); /* success */ 630194676Sthompsa} 631194676Sthompsa 632194676Sthompsaint 633195957Salfredlibusb_reset_device(struct libusb20_device *pdev) 634194676Sthompsa{ 635195957Salfred libusb_device *dev; 636195957Salfred int err; 637194676Sthompsa 638195957Salfred dev = libusb_get_device(pdev); 639194676Sthompsa if (dev == NULL) 640194676Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 641194676Sthompsa 642195957Salfred libusb10_cancel_all_transfer(dev); 643195957Salfred 644195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 645195957Salfred 646195957Salfred err = libusb20_dev_reset(pdev); 647195957Salfred 648195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 649195957Salfred pdev, libusb20_dev_get_fd(pdev), 650195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 651195957Salfred 652195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 653194676Sthompsa} 654194676Sthompsa 655194676Sthompsaint 656195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 657194676Sthompsa{ 658195957Salfred if (pdev == NULL) 659194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 660194676Sthompsa 661195957Salfred return (libusb20_dev_kernel_driver_active( 662195957Salfred pdev, interface)); 663194676Sthompsa} 664194676Sthompsa 665194676Sthompsaint 666195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 667194676Sthompsa{ 668195957Salfred int err; 669194676Sthompsa 670195957Salfred if (pdev == NULL) 671194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 672194676Sthompsa 673195957Salfred err = libusb20_dev_detach_kernel_driver( 674195957Salfred pdev, interface); 675194676Sthompsa 676195957Salfred return (err ? LIBUSB20_ERROR_OTHER : 0); 677194676Sthompsa} 678194676Sthompsa 679194676Sthompsaint 680195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 681194676Sthompsa{ 682195957Salfred if (pdev == NULL) 683194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 684195957Salfred /* stub - currently not supported by libusb20 */ 685194676Sthompsa return (0); 686194676Sthompsa} 687194676Sthompsa 688194676Sthompsa/* Asynchronous device I/O */ 689194676Sthompsa 690194676Sthompsastruct libusb_transfer * 691194676Sthompsalibusb_alloc_transfer(int iso_packets) 692194676Sthompsa{ 693195957Salfred struct libusb_transfer *uxfer; 694195957Salfred struct libusb_super_transfer *sxfer; 695194676Sthompsa int len; 696194676Sthompsa 697194676Sthompsa len = sizeof(struct libusb_transfer) + 698195957Salfred sizeof(struct libusb_super_transfer) + 699194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 700194676Sthompsa 701195957Salfred sxfer = malloc(len); 702195957Salfred if (sxfer == NULL) 703194676Sthompsa return (NULL); 704194676Sthompsa 705195957Salfred memset(sxfer, 0, len); 706194676Sthompsa 707195957Salfred uxfer = (struct libusb_transfer *)( 708195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 709194676Sthompsa 710195957Salfred /* set default value */ 711195957Salfred uxfer->num_iso_packets = iso_packets; 712195957Salfred 713195957Salfred return (uxfer); 714194676Sthompsa} 715194676Sthompsa 716194676Sthompsavoid 717195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 718194676Sthompsa{ 719195957Salfred struct libusb_super_transfer *sxfer; 720194676Sthompsa 721195957Salfred if (uxfer == NULL) 722195957Salfred return; /* be NULL safe */ 723194676Sthompsa 724195957Salfred sxfer = (struct libusb_super_transfer *)( 725195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 726194676Sthompsa 727195957Salfred free(sxfer); 728194676Sthompsa} 729194676Sthompsa 730195560Sthompsastatic int 731195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 732195560Sthompsa{ 733195560Sthompsa int ret; 734195560Sthompsa int usb_speed; 735195560Sthompsa 736195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 737195560Sthompsa 738195560Sthompsa switch (xfer->type) { 739195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 740195560Sthompsa switch (usb_speed) { 741195560Sthompsa case LIBUSB20_SPEED_LOW: 742195560Sthompsa case LIBUSB20_SPEED_FULL: 743195560Sthompsa ret = 60 * 1; 744195957Salfred break; 745195957Salfred default: 746195560Sthompsa ret = 60 * 8; 747195957Salfred break; 748195560Sthompsa } 749195957Salfred break; 750195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 751195560Sthompsa ret = 2; 752195957Salfred break; 753195560Sthompsa default: 754195560Sthompsa ret = 1; 755195957Salfred break; 756195560Sthompsa } 757195957Salfred return (ret); 758195560Sthompsa} 759195560Sthompsa 760195560Sthompsastatic int 761195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 762195560Sthompsa{ 763195560Sthompsa int ret; 764195560Sthompsa int usb_speed; 765195560Sthompsa 766195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 767195560Sthompsa 768195560Sthompsa switch (xfer->type) { 769195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 770195957Salfred ret = 0; /* kernel will auto-select */ 771195957Salfred break; 772195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 773195957Salfred ret = 1024; 774195957Salfred break; 775195957Salfred default: 776195560Sthompsa switch (usb_speed) { 777195957Salfred case LIBUSB20_SPEED_LOW: 778195957Salfred ret = 256; 779195957Salfred break; 780195957Salfred case LIBUSB20_SPEED_FULL: 781195957Salfred ret = 4096; 782195957Salfred break; 783195957Salfred default: 784195957Salfred ret = 16384; 785195957Salfred break; 786195560Sthompsa } 787195957Salfred break; 788195560Sthompsa } 789195957Salfred return (ret); 790195560Sthompsa} 791195560Sthompsa 792195957Salfredstatic int 793195957Salfredlibusb10_convert_error(uint8_t status) 794195957Salfred{ 795195957Salfred ; /* indent fix */ 796195957Salfred 797195957Salfred switch (status) { 798195957Salfred case LIBUSB20_TRANSFER_START: 799195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 800195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 801195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 802195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 803195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 804195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 805195957Salfred case LIBUSB20_TRANSFER_STALL: 806195957Salfred return (LIBUSB_TRANSFER_STALL); 807195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 808195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 809195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 810195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 811195957Salfred default: 812195957Salfred return (LIBUSB_TRANSFER_ERROR); 813195957Salfred } 814195957Salfred} 815195957Salfred 816195957Salfred/* This function must be called locked */ 817195957Salfred 818194676Sthompsastatic void 819195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 820195957Salfred struct libusb_super_transfer *sxfer, int status) 821194676Sthompsa{ 822195957Salfred struct libusb_transfer *uxfer; 823195957Salfred struct libusb_device *dev; 824195957Salfred 825195957Salfred uxfer = (struct libusb_transfer *)( 826195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 827195957Salfred 828195957Salfred if (pxfer != NULL) 829195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 830195957Salfred 831195957Salfred uxfer->status = status; 832195957Salfred 833195957Salfred dev = libusb_get_device(uxfer->dev_handle); 834195957Salfred 835195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 836195957Salfred} 837195957Salfred 838195957Salfred/* This function must be called locked */ 839195957Salfred 840195957Salfredstatic void 841195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 842195957Salfred{ 843195957Salfred struct libusb_super_transfer *sxfer; 844195957Salfred struct libusb_transfer *uxfer; 845195957Salfred uint32_t actlen; 846195957Salfred uint16_t iso_packets; 847195957Salfred uint16_t i; 848194676Sthompsa uint8_t status; 849195957Salfred uint8_t flags; 850194676Sthompsa 851195957Salfred status = libusb20_tr_get_status(pxfer); 852195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 853195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 854195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 855194676Sthompsa 856195957Salfred if (sxfer == NULL) 857195957Salfred return; /* cancelled - nothing to do */ 858195957Salfred 859195957Salfred uxfer = (struct libusb_transfer *)( 860195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 861195957Salfred 862195957Salfred if (iso_packets > uxfer->num_iso_packets) 863195957Salfred iso_packets = uxfer->num_iso_packets; 864195957Salfred 865195957Salfred if (iso_packets == 0) 866195957Salfred return; /* nothing to do */ 867195957Salfred 868195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 869195957Salfred uxfer->num_iso_packets = iso_packets; 870195957Salfred 871195957Salfred flags = uxfer->flags; 872195957Salfred 873194676Sthompsa switch (status) { 874194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 875195560Sthompsa 876195957Salfred /* update actual length */ 877195957Salfred uxfer->actual_length = actlen; 878195957Salfred for (i = 0; i != iso_packets; i++) { 879195957Salfred uxfer->iso_packet_desc[i].actual_length = 880195957Salfred libusb20_tr_get_length(pxfer, i); 881195957Salfred } 882195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 883195957Salfred break; 884195560Sthompsa 885194676Sthompsa case LIBUSB20_TRANSFER_START: 886195957Salfred 887195957Salfred /* setup length(s) */ 888195957Salfred actlen = 0; 889195957Salfred for (i = 0; i != iso_packets; i++) { 890195957Salfred libusb20_tr_setup_isoc(pxfer, 891195957Salfred &uxfer->buffer[actlen], 892195957Salfred uxfer->iso_packet_desc[i].length, i); 893195957Salfred actlen += uxfer->iso_packet_desc[i].length; 894194676Sthompsa } 895195957Salfred 896195957Salfred /* no remainder */ 897195957Salfred sxfer->rem_len = 0; 898195957Salfred 899195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 900195957Salfred libusb20_tr_submit(pxfer); 901195957Salfred 902195957Salfred /* fork another USB transfer, if any */ 903195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 904195957Salfred break; 905195957Salfred 906194676Sthompsa default: 907195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 908195957Salfred break; 909194676Sthompsa } 910195957Salfred} 911194676Sthompsa 912195957Salfred/* This function must be called locked */ 913195957Salfred 914195957Salfredstatic void 915195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 916195957Salfred{ 917195957Salfred struct libusb_super_transfer *sxfer; 918195957Salfred struct libusb_transfer *uxfer; 919195957Salfred uint32_t max_bulk; 920195957Salfred uint32_t actlen; 921195957Salfred uint8_t status; 922195957Salfred uint8_t flags; 923195957Salfred 924195957Salfred status = libusb20_tr_get_status(pxfer); 925195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 926195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 927195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 928195957Salfred 929195957Salfred if (sxfer == NULL) 930195957Salfred return; /* cancelled - nothing to do */ 931195957Salfred 932195957Salfred uxfer = (struct libusb_transfer *)( 933195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 934195957Salfred 935195957Salfred flags = uxfer->flags; 936195957Salfred 937194676Sthompsa switch (status) { 938194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 939195957Salfred 940195957Salfred uxfer->actual_length += actlen; 941195957Salfred 942195957Salfred /* check for short packet */ 943195957Salfred if (sxfer->last_len != actlen) { 944195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 945195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 946195957Salfred } else { 947195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 948195957Salfred } 949195957Salfred break; 950195957Salfred } 951195957Salfred /* check for end of data */ 952195957Salfred if (sxfer->rem_len == 0) { 953195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 954195957Salfred break; 955195957Salfred } 956195957Salfred /* FALLTHROUGH */ 957195957Salfred 958195957Salfred case LIBUSB20_TRANSFER_START: 959195957Salfred if (max_bulk > sxfer->rem_len) { 960195957Salfred max_bulk = sxfer->rem_len; 961195957Salfred } 962195957Salfred /* setup new BULK or INTERRUPT transaction */ 963195957Salfred libusb20_tr_setup_bulk(pxfer, 964195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 965195957Salfred 966195957Salfred /* update counters */ 967195957Salfred sxfer->last_len = max_bulk; 968195957Salfred sxfer->curr_data += max_bulk; 969195957Salfred sxfer->rem_len -= max_bulk; 970195957Salfred 971195957Salfred libusb20_tr_submit(pxfer); 972195957Salfred 973195957Salfred /* check if we can fork another USB transfer */ 974195957Salfred if (sxfer->rem_len == 0) 975195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 976195957Salfred break; 977195957Salfred 978195957Salfred default: 979195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 980195957Salfred break; 981194676Sthompsa } 982194676Sthompsa} 983194676Sthompsa 984195957Salfred/* This function must be called locked */ 985195957Salfred 986195957Salfredstatic void 987195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 988194676Sthompsa{ 989195957Salfred struct libusb_super_transfer *sxfer; 990195957Salfred struct libusb_transfer *uxfer; 991195957Salfred uint32_t max_bulk; 992195957Salfred uint32_t actlen; 993195957Salfred uint8_t status; 994195957Salfred uint8_t flags; 995194676Sthompsa 996195957Salfred status = libusb20_tr_get_status(pxfer); 997195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 998195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 999195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1000194676Sthompsa 1001195957Salfred if (sxfer == NULL) 1002195957Salfred return; /* cancelled - nothing to do */ 1003194676Sthompsa 1004195957Salfred uxfer = (struct libusb_transfer *)( 1005195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1006194676Sthompsa 1007195957Salfred flags = uxfer->flags; 1008194676Sthompsa 1009195957Salfred switch (status) { 1010195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1011194676Sthompsa 1012195957Salfred uxfer->actual_length += actlen; 1013195957Salfred 1014195957Salfred /* subtract length of SETUP packet, if any */ 1015195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1016195957Salfred 1017195957Salfred /* check for short packet */ 1018195957Salfred if (sxfer->last_len != actlen) { 1019195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1020195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1021195957Salfred } else { 1022195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1023195957Salfred } 1024195957Salfred break; 1025194676Sthompsa } 1026195957Salfred /* check for end of data */ 1027195957Salfred if (sxfer->rem_len == 0) { 1028195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1029195957Salfred break; 1030195957Salfred } 1031195957Salfred /* FALLTHROUGH */ 1032194676Sthompsa 1033195957Salfred case LIBUSB20_TRANSFER_START: 1034195957Salfred if (max_bulk > sxfer->rem_len) { 1035195957Salfred max_bulk = sxfer->rem_len; 1036195957Salfred } 1037195957Salfred /* setup new CONTROL transaction */ 1038195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1039195957Salfred /* next fragment - don't send SETUP packet */ 1040195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1041195957Salfred } else { 1042195957Salfred /* first fragment - send SETUP packet */ 1043195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1044195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1045195957Salfred } 1046195957Salfred 1047195957Salfred if (max_bulk != 0) { 1048195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1049195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1050195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1051195957Salfred } else { 1052195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1053195957Salfred } 1054195957Salfred 1055195957Salfred /* update counters */ 1056195957Salfred sxfer->last_len = max_bulk; 1057195957Salfred sxfer->curr_data += max_bulk; 1058195957Salfred sxfer->rem_len -= max_bulk; 1059195957Salfred 1060195957Salfred libusb20_tr_submit(pxfer); 1061195957Salfred 1062195957Salfred /* check if we can fork another USB transfer */ 1063195957Salfred if (sxfer->rem_len == 0) 1064195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1065195957Salfred break; 1066195957Salfred 1067195957Salfred default: 1068195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1069195957Salfred break; 1070194676Sthompsa } 1071195957Salfred} 1072195957Salfred 1073195957Salfred/* The following function must be called locked */ 1074195957Salfred 1075195957Salfredstatic void 1076195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1077195957Salfred{ 1078195957Salfred struct libusb20_transfer *pxfer0; 1079195957Salfred struct libusb20_transfer *pxfer1; 1080195957Salfred struct libusb_super_transfer *sxfer; 1081195957Salfred struct libusb_transfer *uxfer; 1082195957Salfred struct libusb_device *dev; 1083195957Salfred int err; 1084195957Salfred int buffsize; 1085195957Salfred int maxframe; 1086195957Salfred int temp; 1087195957Salfred uint8_t dummy; 1088195957Salfred 1089195957Salfred dev = libusb_get_device(pdev); 1090195957Salfred 1091195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1092195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1093195957Salfred 1094195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1095195957Salfred return; /* shouldn't happen */ 1096195957Salfred 1097195957Salfred temp = 0; 1098195957Salfred if (libusb20_tr_pending(pxfer0)) 1099195957Salfred temp |= 1; 1100195957Salfred if (libusb20_tr_pending(pxfer1)) 1101195957Salfred temp |= 2; 1102195957Salfred 1103195957Salfred switch (temp) { 1104195957Salfred case 3: 1105195957Salfred /* wait till one of the transfers complete */ 1106195957Salfred return; 1107195957Salfred case 2: 1108195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1109195957Salfred if (sxfer->rem_len) 1110195957Salfred return; /* cannot queue another one */ 1111195957Salfred /* swap transfers */ 1112195957Salfred pxfer1 = pxfer0; 1113195957Salfred break; 1114195957Salfred case 1: 1115195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1116195957Salfred if (sxfer->rem_len) 1117195957Salfred return; /* cannot queue another one */ 1118195957Salfred /* swap transfers */ 1119195957Salfred pxfer0 = pxfer1; 1120195957Salfred break; 1121195957Salfred default: 1122195957Salfred break; 1123194676Sthompsa } 1124195957Salfred 1125195957Salfred /* find next transfer on same endpoint */ 1126195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1127195957Salfred 1128195957Salfred uxfer = (struct libusb_transfer *)( 1129195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1130195957Salfred 1131195957Salfred if (uxfer->endpoint == endpoint) { 1132195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1133195957Salfred sxfer->entry.tqe_prev = NULL; 1134195957Salfred goto found; 1135194676Sthompsa } 1136195957Salfred } 1137195957Salfred return; /* success */ 1138194676Sthompsa 1139195957Salfredfound: 1140194676Sthompsa 1141195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1142195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1143194676Sthompsa 1144195957Salfred /* reset super transfer state */ 1145195957Salfred sxfer->rem_len = uxfer->length; 1146195957Salfred sxfer->curr_data = uxfer->buffer; 1147195957Salfred uxfer->actual_length = 0; 1148194676Sthompsa 1149195957Salfred switch (uxfer->type) { 1150195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1151195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1152195957Salfred break; 1153195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1154195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1155195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1156195957Salfred break; 1157195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1158195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1159195957Salfred if (sxfer->rem_len < 8) 1160195957Salfred goto failure; 1161194676Sthompsa 1162195957Salfred /* remove SETUP packet from data */ 1163195957Salfred sxfer->rem_len -= 8; 1164195957Salfred sxfer->curr_data += 8; 1165195957Salfred break; 1166195957Salfred default: 1167195957Salfred goto failure; 1168195560Sthompsa } 1169195957Salfred 1170195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1171195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1172195957Salfred 1173195957Salfred /* make sure the transfer is opened */ 1174195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1175195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1176195957Salfred goto failure; 1177194676Sthompsa } 1178195957Salfred libusb20_tr_start(pxfer0); 1179195957Salfred return; 1180194676Sthompsa 1181195957Salfredfailure: 1182195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1183194676Sthompsa 1184195957Salfred /* make sure our event loop spins the done handler */ 1185195957Salfred dummy = 0; 1186195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1187195957Salfred} 1188194676Sthompsa 1189195957Salfred/* The following function must be called unlocked */ 1190194676Sthompsa 1191195957Salfredint 1192195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1193195957Salfred{ 1194195957Salfred struct libusb20_transfer *pxfer0; 1195195957Salfred struct libusb20_transfer *pxfer1; 1196195957Salfred struct libusb_super_transfer *sxfer; 1197195957Salfred struct libusb_device *dev; 1198195957Salfred unsigned int endpoint; 1199195957Salfred int err; 1200195957Salfred 1201195957Salfred if (uxfer == NULL) 1202195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1203195957Salfred 1204195957Salfred if (uxfer->dev_handle == NULL) 1205195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1206195957Salfred 1207195957Salfred endpoint = uxfer->endpoint; 1208195957Salfred 1209195957Salfred if (endpoint > 255) 1210195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1211195957Salfred 1212195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1213195957Salfred 1214195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1215195957Salfred 1216195957Salfred sxfer = (struct libusb_super_transfer *)( 1217195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1218195957Salfred 1219195957Salfred CTX_LOCK(dev->ctx); 1220195957Salfred 1221195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1222195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1223195957Salfred 1224195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1225195957Salfred err = LIBUSB_ERROR_OTHER; 1226195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1227195957Salfred (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1228195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1229195957Salfred err = LIBUSB_ERROR_BUSY; 1230195957Salfred } else { 1231195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1232195957Salfred 1233195957Salfred libusb10_submit_transfer_sub( 1234195957Salfred uxfer->dev_handle, endpoint); 1235195957Salfred 1236195957Salfred err = 0; /* success */ 1237195957Salfred } 1238195957Salfred 1239195957Salfred CTX_UNLOCK(dev->ctx); 1240195957Salfred 1241195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1242195957Salfred 1243195957Salfred return (err); 1244194676Sthompsa} 1245194676Sthompsa 1246195957Salfred/* Asynchronous transfer cancel */ 1247195957Salfred 1248194676Sthompsaint 1249195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1250194676Sthompsa{ 1251195957Salfred struct libusb20_transfer *pxfer0; 1252195957Salfred struct libusb20_transfer *pxfer1; 1253195957Salfred struct libusb_super_transfer *sxfer; 1254195957Salfred struct libusb_device *dev; 1255195957Salfred unsigned int endpoint; 1256194676Sthompsa 1257195957Salfred if (uxfer == NULL) 1258195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1259194676Sthompsa 1260195957Salfred if (uxfer->dev_handle == NULL) 1261195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1262194676Sthompsa 1263195957Salfred endpoint = uxfer->endpoint; 1264194676Sthompsa 1265195957Salfred if (endpoint > 255) 1266195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1267195957Salfred 1268195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1269195957Salfred 1270195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1271195957Salfred 1272195957Salfred sxfer = (struct libusb_super_transfer *)( 1273195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1274195957Salfred 1275195957Salfred CTX_LOCK(dev->ctx); 1276195957Salfred 1277195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1278195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1279195957Salfred 1280195957Salfred if (sxfer->entry.tqe_prev != NULL) { 1281195957Salfred /* we are lucky - transfer is on a queue */ 1282195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1283195957Salfred sxfer->entry.tqe_prev = NULL; 1284195957Salfred libusb10_complete_transfer(NULL, sxfer, LIBUSB_TRANSFER_CANCELLED); 1285195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1286195957Salfred /* not started */ 1287195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1288195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_CANCELLED); 1289195957Salfred libusb20_tr_stop(pxfer0); 1290195957Salfred /* make sure the queue doesn't stall */ 1291195957Salfred libusb10_submit_transfer_sub( 1292195957Salfred uxfer->dev_handle, endpoint); 1293195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1294195957Salfred libusb10_complete_transfer(pxfer1, sxfer, LIBUSB_TRANSFER_CANCELLED); 1295195957Salfred libusb20_tr_stop(pxfer1); 1296195957Salfred /* make sure the queue doesn't stall */ 1297195957Salfred libusb10_submit_transfer_sub( 1298195957Salfred uxfer->dev_handle, endpoint); 1299195957Salfred } else { 1300195957Salfred /* not started */ 1301195957Salfred } 1302195957Salfred 1303195957Salfred CTX_UNLOCK(dev->ctx); 1304195957Salfred 1305195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1306195957Salfred 1307194676Sthompsa return (0); 1308194676Sthompsa} 1309194676Sthompsa 1310195957SalfredUNEXPORTED void 1311195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1312195957Salfred{ 1313195957Salfred /* TODO */ 1314195957Salfred} 1315