libusb10.c revision 203815
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 203815 2010-02-13 09:45:50Z wkoszek $ */ 2194676Sthompsa/*- 3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4195957Salfred * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 5194676Sthompsa * 6194676Sthompsa * Redistribution and use in source and binary forms, with or without 7194676Sthompsa * modification, are permitted provided that the following conditions 8194676Sthompsa * are met: 9194676Sthompsa * 1. Redistributions of source code must retain the above copyright 10194676Sthompsa * notice, this list of conditions and the following disclaimer. 11194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 12194676Sthompsa * notice, this list of conditions and the following disclaimer in the 13194676Sthompsa * documentation and/or other materials provided with the distribution. 14194676Sthompsa * 15194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18194676Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25194676Sthompsa * SUCH DAMAGE. 26194676Sthompsa */ 27194676Sthompsa 28203815Swkoszek#include <sys/fcntl.h> 29203815Swkoszek#include <sys/ioctl.h> 30203815Swkoszek#include <sys/queue.h> 31203815Swkoszek 32203774Swkoszek#include <assert.h> 33203815Swkoszek#include <errno.h> 34203815Swkoszek#include <poll.h> 35203815Swkoszek#include <pthread.h> 36203815Swkoszek#include <stdio.h> 37194676Sthompsa#include <stdlib.h> 38194676Sthompsa#include <unistd.h> 39194676Sthompsa 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; 76203774Swkoszek int flag; 77194676Sthompsa int ret; 78194676Sthompsa 79194676Sthompsa ctx = malloc(sizeof(*ctx)); 80194676Sthompsa if (!ctx) 81194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 82194676Sthompsa 83194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 84194676Sthompsa 85194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 86194676Sthompsa if (debug != NULL) { 87194676Sthompsa ctx->debug = atoi(debug); 88194676Sthompsa if (ctx->debug != 0) 89194676Sthompsa ctx->debug_fixed = 1; 90194676Sthompsa } 91195957Salfred TAILQ_INIT(&ctx->pollfds); 92195957Salfred TAILQ_INIT(&ctx->tr_done); 93194676Sthompsa 94195957Salfred pthread_mutex_init(&ctx->ctx_lock, NULL); 95195957Salfred pthread_cond_init(&ctx->ctx_cond, NULL); 96194676Sthompsa 97195957Salfred ctx->ctx_handler = NO_THREAD; 98194676Sthompsa 99194676Sthompsa ret = pipe(ctx->ctrl_pipe); 100194676Sthompsa if (ret < 0) { 101195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 102195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 103194676Sthompsa free(ctx); 104194676Sthompsa return (LIBUSB_ERROR_OTHER); 105194676Sthompsa } 106195957Salfred /* set non-blocking mode on the control pipe to avoid deadlock */ 107203774Swkoszek flag = 1; 108203774Swkoszek ret = fcntl(ctx->ctrl_pipe[0], O_NONBLOCK, &flag); 109203774Swkoszek assert(ret != -1 && "Couldn't set O_NONBLOCK for ctx->ctrl_pipe[0]"); 110203774Swkoszek flag = 1; 111203774Swkoszek ret = fcntl(ctx->ctrl_pipe[1], O_NONBLOCK, &flag); 112203774Swkoszek assert(ret != -1 && "Couldn't set O_NONBLOCK for ctx->ctrl_pipe[1]"); 113194676Sthompsa 114195957Salfred libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 115194676Sthompsa 116194676Sthompsa pthread_mutex_lock(&default_context_lock); 117194676Sthompsa if (usbi_default_context == NULL) { 118194676Sthompsa usbi_default_context = ctx; 119194676Sthompsa } 120194676Sthompsa pthread_mutex_unlock(&default_context_lock); 121194676Sthompsa 122194676Sthompsa if (context) 123194676Sthompsa *context = ctx; 124194676Sthompsa 125195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 126195957Salfred 127194676Sthompsa return (0); 128194676Sthompsa} 129194676Sthompsa 130194676Sthompsavoid 131195957Salfredlibusb_exit(libusb_context *ctx) 132194676Sthompsa{ 133195957Salfred ctx = GET_CONTEXT(ctx); 134194676Sthompsa 135195957Salfred if (ctx == NULL) 136195957Salfred return; 137195957Salfred 138195957Salfred /* XXX cleanup devices */ 139195957Salfred 140195957Salfred libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 141194676Sthompsa close(ctx->ctrl_pipe[0]); 142194676Sthompsa close(ctx->ctrl_pipe[1]); 143195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 144195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 145194676Sthompsa 146194676Sthompsa pthread_mutex_lock(&default_context_lock); 147194676Sthompsa if (ctx == usbi_default_context) { 148194676Sthompsa usbi_default_context = NULL; 149194676Sthompsa } 150194676Sthompsa pthread_mutex_unlock(&default_context_lock); 151194676Sthompsa 152194676Sthompsa free(ctx); 153194676Sthompsa} 154194676Sthompsa 155194676Sthompsa/* Device handling and initialisation. */ 156194676Sthompsa 157194676Sthompsassize_t 158195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list) 159194676Sthompsa{ 160195957Salfred struct libusb20_backend *usb_backend; 161194676Sthompsa struct libusb20_device *pdev; 162194676Sthompsa struct libusb_device *dev; 163194676Sthompsa int i; 164194676Sthompsa 165195957Salfred ctx = GET_CONTEXT(ctx); 166194676Sthompsa 167195957Salfred if (ctx == NULL) 168195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 169195957Salfred 170195957Salfred if (list == NULL) 171195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 172195957Salfred 173194676Sthompsa usb_backend = libusb20_be_alloc_default(); 174194676Sthompsa if (usb_backend == NULL) 175195957Salfred return (LIBUSB_ERROR_NO_MEM); 176194676Sthompsa 177195957Salfred /* figure out how many USB devices are present */ 178194676Sthompsa pdev = NULL; 179194676Sthompsa i = 0; 180194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 181194676Sthompsa i++; 182194676Sthompsa 183195957Salfred /* allocate device pointer list */ 184194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 185194676Sthompsa if (*list == NULL) { 186194676Sthompsa libusb20_be_free(usb_backend); 187194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 188194676Sthompsa } 189195957Salfred /* create libusb v1.0 compliant devices */ 190194676Sthompsa i = 0; 191194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 192194676Sthompsa 193194676Sthompsa dev = malloc(sizeof(*dev)); 194194676Sthompsa if (dev == NULL) { 195195560Sthompsa while (i != 0) { 196195560Sthompsa libusb_unref_device((*list)[i - 1]); 197195560Sthompsa i--; 198195560Sthompsa } 199194676Sthompsa free(*list); 200195957Salfred *list = NULL; 201194676Sthompsa libusb20_be_free(usb_backend); 202194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 203194676Sthompsa } 204199055Sthompsa 205199055Sthompsa /* get device into libUSB v1.0 list */ 206199055Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 207199055Sthompsa 208194676Sthompsa memset(dev, 0, sizeof(*dev)); 209194676Sthompsa 210195957Salfred /* init transfer queues */ 211195957Salfred TAILQ_INIT(&dev->tr_head); 212195957Salfred 213195957Salfred /* set context we belong to */ 214194676Sthompsa dev->ctx = ctx; 215194676Sthompsa 216194676Sthompsa /* link together the two structures */ 217194676Sthompsa dev->os_priv = pdev; 218195957Salfred pdev->privLuData = dev; 219194676Sthompsa 220194676Sthompsa (*list)[i] = libusb_ref_device(dev); 221194676Sthompsa i++; 222194676Sthompsa } 223194676Sthompsa (*list)[i] = NULL; 224194676Sthompsa 225194676Sthompsa libusb20_be_free(usb_backend); 226194676Sthompsa return (i); 227194676Sthompsa} 228194676Sthompsa 229194676Sthompsavoid 230194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 231194676Sthompsa{ 232194676Sthompsa int i; 233194676Sthompsa 234194676Sthompsa if (list == NULL) 235195957Salfred return; /* be NULL safe */ 236194676Sthompsa 237194676Sthompsa if (unref_devices) { 238194676Sthompsa for (i = 0; list[i] != NULL; i++) 239194676Sthompsa libusb_unref_device(list[i]); 240194676Sthompsa } 241194676Sthompsa free(list); 242194676Sthompsa} 243194676Sthompsa 244194676Sthompsauint8_t 245195957Salfredlibusb_get_bus_number(libusb_device *dev) 246194676Sthompsa{ 247194676Sthompsa if (dev == NULL) 248195957Salfred return (0); /* should not happen */ 249195957Salfred return (libusb20_dev_get_bus_number(dev->os_priv)); 250194676Sthompsa} 251194676Sthompsa 252194676Sthompsauint8_t 253195957Salfredlibusb_get_device_address(libusb_device *dev) 254194676Sthompsa{ 255194676Sthompsa if (dev == NULL) 256195957Salfred return (0); /* should not happen */ 257195957Salfred return (libusb20_dev_get_address(dev->os_priv)); 258194676Sthompsa} 259194676Sthompsa 260194676Sthompsaint 261195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 262194676Sthompsa{ 263194676Sthompsa struct libusb_config_descriptor *pdconf; 264194676Sthompsa struct libusb_interface *pinf; 265194676Sthompsa struct libusb_interface_descriptor *pdinf; 266194676Sthompsa struct libusb_endpoint_descriptor *pdend; 267195957Salfred int i; 268195957Salfred int j; 269195957Salfred int k; 270195957Salfred int ret; 271194676Sthompsa 272194676Sthompsa if (dev == NULL) 273194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 274194676Sthompsa 275195957Salfred ret = libusb_get_active_config_descriptor(dev, &pdconf); 276195957Salfred if (ret < 0) 277195957Salfred return (ret); 278195957Salfred 279194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 280195957Salfred for (i = 0; i < pdconf->bNumInterfaces; i++) { 281194676Sthompsa pinf = &pdconf->interface[i]; 282195957Salfred for (j = 0; j < pinf->num_altsetting; j++) { 283194676Sthompsa pdinf = &pinf->altsetting[j]; 284195957Salfred for (k = 0; k < pdinf->bNumEndpoints; k++) { 285194676Sthompsa pdend = &pdinf->endpoint[k]; 286194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 287194676Sthompsa ret = pdend->wMaxPacketSize; 288194676Sthompsa goto out; 289194676Sthompsa } 290194676Sthompsa } 291194676Sthompsa } 292194676Sthompsa } 293194676Sthompsa 294194676Sthompsaout: 295194676Sthompsa libusb_free_config_descriptor(pdconf); 296194676Sthompsa return (ret); 297194676Sthompsa} 298194676Sthompsa 299194676Sthompsalibusb_device * 300195957Salfredlibusb_ref_device(libusb_device *dev) 301194676Sthompsa{ 302194676Sthompsa if (dev == NULL) 303195957Salfred return (NULL); /* be NULL safe */ 304194676Sthompsa 305195957Salfred CTX_LOCK(dev->ctx); 306194676Sthompsa dev->refcnt++; 307195957Salfred CTX_UNLOCK(dev->ctx); 308194676Sthompsa 309194676Sthompsa return (dev); 310194676Sthompsa} 311194676Sthompsa 312194676Sthompsavoid 313195957Salfredlibusb_unref_device(libusb_device *dev) 314194676Sthompsa{ 315194676Sthompsa if (dev == NULL) 316195957Salfred return; /* be NULL safe */ 317194676Sthompsa 318195957Salfred CTX_LOCK(dev->ctx); 319194676Sthompsa dev->refcnt--; 320195957Salfred CTX_UNLOCK(dev->ctx); 321194676Sthompsa 322194676Sthompsa if (dev->refcnt == 0) { 323194676Sthompsa libusb20_dev_free(dev->os_priv); 324194676Sthompsa free(dev); 325194676Sthompsa } 326194676Sthompsa} 327194676Sthompsa 328194676Sthompsaint 329195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh) 330194676Sthompsa{ 331194676Sthompsa libusb_context *ctx = dev->ctx; 332194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 333195957Salfred uint8_t dummy; 334194676Sthompsa int err; 335194676Sthompsa 336194676Sthompsa if (devh == NULL) 337194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 338194676Sthompsa 339195957Salfred /* set default device handle value */ 340195957Salfred *devh = NULL; 341194676Sthompsa 342195957Salfred dev = libusb_ref_device(dev); 343195957Salfred if (dev == NULL) 344195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 345195957Salfred 346194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 347194676Sthompsa if (err) { 348195957Salfred libusb_unref_device(dev); 349194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 350194676Sthompsa } 351195957Salfred libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 352194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 353194676Sthompsa 354195957Salfred /* make sure our event loop detects the new device */ 355195957Salfred dummy = 0; 356194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 357195957Salfred if (err < sizeof(dummy)) { 358195957Salfred /* ignore error, if any */ 359195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 360194676Sthompsa } 361195957Salfred *devh = pdev; 362194676Sthompsa 363194676Sthompsa return (0); 364194676Sthompsa} 365194676Sthompsa 366194676Sthompsalibusb_device_handle * 367195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 368194676Sthompsa uint16_t product_id) 369194676Sthompsa{ 370194676Sthompsa struct libusb_device **devs; 371194676Sthompsa struct libusb20_device *pdev; 372194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 373195957Salfred int i; 374195957Salfred int j; 375194676Sthompsa 376195957Salfred ctx = GET_CONTEXT(ctx); 377195957Salfred if (ctx == NULL) 378195957Salfred return (NULL); /* be NULL safe */ 379195957Salfred 380195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 381194676Sthompsa 382194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 383194676Sthompsa return (NULL); 384194676Sthompsa 385194676Sthompsa for (j = 0; j < i; j++) { 386195957Salfred pdev = devs[j]->os_priv; 387194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 388195957Salfred /* 389195957Salfred * NOTE: The USB library will automatically swap the 390195957Salfred * fields in the device descriptor to be of host 391195957Salfred * endian type! 392195957Salfred */ 393194676Sthompsa if (pdesc->idVendor == vendor_id && 394195560Sthompsa pdesc->idProduct == product_id) { 395195957Salfred if (libusb_open(devs[j], &pdev) < 0) 396195957Salfred pdev = NULL; 397195957Salfred break; 398195560Sthompsa } 399194676Sthompsa } 400200424Sscf if (j == i) 401200424Sscf pdev = NULL; 402194676Sthompsa 403194676Sthompsa libusb_free_device_list(devs, 1); 404195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 405195957Salfred return (pdev); 406194676Sthompsa} 407194676Sthompsa 408194676Sthompsavoid 409195957Salfredlibusb_close(struct libusb20_device *pdev) 410194676Sthompsa{ 411194676Sthompsa libusb_context *ctx; 412195957Salfred struct libusb_device *dev; 413195957Salfred uint8_t dummy; 414194676Sthompsa int err; 415194676Sthompsa 416195957Salfred if (pdev == NULL) 417195957Salfred return; /* be NULL safe */ 418194676Sthompsa 419195957Salfred dev = libusb_get_device(pdev); 420195957Salfred ctx = dev->ctx; 421194676Sthompsa 422195957Salfred libusb10_remove_pollfd(ctx, &dev->dev_poll); 423194676Sthompsa 424195957Salfred libusb20_dev_close(pdev); 425199055Sthompsa 426199055Sthompsa /* unref will free the "pdev" when the refcount reaches zero */ 427195957Salfred libusb_unref_device(dev); 428194676Sthompsa 429195957Salfred /* make sure our event loop detects the closed device */ 430195957Salfred dummy = 0; 431194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 432195957Salfred if (err < sizeof(dummy)) { 433195957Salfred /* ignore error, if any */ 434195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 435194676Sthompsa } 436194676Sthompsa} 437194676Sthompsa 438194676Sthompsalibusb_device * 439195957Salfredlibusb_get_device(struct libusb20_device *pdev) 440194676Sthompsa{ 441195957Salfred if (pdev == NULL) 442194676Sthompsa return (NULL); 443195957Salfred return ((libusb_device *)pdev->privLuData); 444194676Sthompsa} 445194676Sthompsa 446194676Sthompsaint 447195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config) 448194676Sthompsa{ 449195957Salfred struct libusb20_config *pconf; 450194676Sthompsa 451195957Salfred if (pdev == NULL || config == NULL) 452194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 453194676Sthompsa 454195957Salfred pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 455195957Salfred if (pconf == NULL) 456195957Salfred return (LIBUSB_ERROR_NO_MEM); 457194676Sthompsa 458195957Salfred *config = pconf->desc.bConfigurationValue; 459195957Salfred 460195957Salfred free(pconf); 461195957Salfred 462194676Sthompsa return (0); 463194676Sthompsa} 464194676Sthompsa 465194676Sthompsaint 466195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration) 467194676Sthompsa{ 468195957Salfred struct libusb20_config *pconf; 469195957Salfred struct libusb_device *dev; 470195957Salfred int err; 471195957Salfred uint8_t i; 472194676Sthompsa 473195957Salfred dev = libusb_get_device(pdev); 474194676Sthompsa 475195957Salfred if (dev == NULL) 476194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 477194676Sthompsa 478195957Salfred if (configuration < 1) { 479195957Salfred /* unconfigure */ 480195957Salfred i = 255; 481195957Salfred } else { 482195957Salfred for (i = 0; i != 255; i++) { 483195957Salfred uint8_t found; 484194676Sthompsa 485195957Salfred pconf = libusb20_dev_alloc_config(pdev, i); 486195957Salfred if (pconf == NULL) 487195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 488195957Salfred found = (pconf->desc.bConfigurationValue 489195957Salfred == configuration); 490195957Salfred free(pconf); 491195957Salfred 492195957Salfred if (found) 493195957Salfred goto set_config; 494195957Salfred } 495195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 496195957Salfred } 497195957Salfred 498195957Salfredset_config: 499195957Salfred 500195957Salfred libusb10_cancel_all_transfer(dev); 501195957Salfred 502195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 503195957Salfred 504195957Salfred err = libusb20_dev_set_config_index(pdev, i); 505195957Salfred 506195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 507195957Salfred POLLOUT | POLLRDNORM | POLLWRNORM); 508195957Salfred 509195957Salfred return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 510194676Sthompsa} 511194676Sthompsa 512194676Sthompsaint 513195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number) 514194676Sthompsa{ 515195957Salfred libusb_device *dev; 516195957Salfred int err = 0; 517194676Sthompsa 518195957Salfred dev = libusb_get_device(pdev); 519194676Sthompsa if (dev == NULL) 520194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 521194676Sthompsa 522195957Salfred if (interface_number < 0 || interface_number > 31) 523194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 524194676Sthompsa 525195957Salfred CTX_LOCK(dev->ctx); 526194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 527195957Salfred err = LIBUSB_ERROR_BUSY; 528194676Sthompsa 529195957Salfred if (!err) 530194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 531195957Salfred CTX_UNLOCK(dev->ctx); 532195957Salfred return (err); 533194676Sthompsa} 534194676Sthompsa 535194676Sthompsaint 536195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number) 537194676Sthompsa{ 538195957Salfred libusb_device *dev; 539195957Salfred int err = 0; 540194676Sthompsa 541195957Salfred dev = libusb_get_device(pdev); 542194676Sthompsa if (dev == NULL) 543194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 544194676Sthompsa 545195957Salfred if (interface_number < 0 || interface_number > 31) 546194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 547194676Sthompsa 548195957Salfred CTX_LOCK(dev->ctx); 549194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 550195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 551194676Sthompsa 552195957Salfred if (!err) 553194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 554195957Salfred CTX_UNLOCK(dev->ctx); 555195957Salfred return (err); 556194676Sthompsa} 557194676Sthompsa 558194676Sthompsaint 559195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev, 560194676Sthompsa int interface_number, int alternate_setting) 561194676Sthompsa{ 562195957Salfred libusb_device *dev; 563195957Salfred int err = 0; 564194676Sthompsa 565195957Salfred dev = libusb_get_device(pdev); 566194676Sthompsa if (dev == NULL) 567194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 568194676Sthompsa 569195957Salfred if (interface_number < 0 || interface_number > 31) 570194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 571194676Sthompsa 572195957Salfred CTX_LOCK(dev->ctx); 573195957Salfred if (!(dev->claimed_interfaces & (1 << interface_number))) 574195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 575195957Salfred CTX_UNLOCK(dev->ctx); 576194676Sthompsa 577195957Salfred if (err) 578195957Salfred return (err); 579195957Salfred 580195957Salfred libusb10_cancel_all_transfer(dev); 581195957Salfred 582195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 583195957Salfred 584195957Salfred err = libusb20_dev_set_alt_index(pdev, 585195957Salfred interface_number, alternate_setting); 586195957Salfred 587195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 588195957Salfred pdev, libusb20_dev_get_fd(pdev), 589195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 590195957Salfred 591195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 592194676Sthompsa} 593194676Sthompsa 594195957Salfredstatic struct libusb20_transfer * 595195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev, 596195957Salfred uint8_t endpoint, uint8_t index) 597195957Salfred{ 598195957Salfred index &= 1; /* double buffering */ 599195957Salfred 600195957Salfred index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 601195957Salfred 602195957Salfred if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 603195957Salfred /* this is an IN endpoint */ 604195957Salfred index |= 2; 605195957Salfred } 606195957Salfred return (libusb20_tr_get_pointer(pdev, index)); 607195957Salfred} 608195957Salfred 609194676Sthompsaint 610195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 611194676Sthompsa{ 612194676Sthompsa struct libusb20_transfer *xfer; 613195957Salfred struct libusb_device *dev; 614195957Salfred int err; 615194676Sthompsa 616195957Salfred xfer = libusb10_get_transfer(pdev, endpoint, 0); 617195560Sthompsa if (xfer == NULL) 618195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 619194676Sthompsa 620195957Salfred dev = libusb_get_device(pdev); 621195957Salfred 622195957Salfred CTX_LOCK(dev->ctx); 623195957Salfred err = libusb20_tr_open(xfer, 0, 0, endpoint); 624195957Salfred CTX_UNLOCK(dev->ctx); 625195957Salfred 626195957Salfred if (err != 0 && err != LIBUSB20_ERROR_BUSY) 627194676Sthompsa return (LIBUSB_ERROR_OTHER); 628194676Sthompsa 629194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 630195957Salfred 631195957Salfred /* check if we opened the transfer */ 632195957Salfred if (err == 0) { 633195957Salfred CTX_LOCK(dev->ctx); 634194676Sthompsa libusb20_tr_close(xfer); 635195957Salfred CTX_UNLOCK(dev->ctx); 636195957Salfred } 637195957Salfred return (0); /* success */ 638194676Sthompsa} 639194676Sthompsa 640194676Sthompsaint 641195957Salfredlibusb_reset_device(struct libusb20_device *pdev) 642194676Sthompsa{ 643195957Salfred libusb_device *dev; 644195957Salfred int err; 645194676Sthompsa 646195957Salfred dev = libusb_get_device(pdev); 647194676Sthompsa if (dev == NULL) 648194676Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 649194676Sthompsa 650195957Salfred libusb10_cancel_all_transfer(dev); 651195957Salfred 652195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 653195957Salfred 654195957Salfred err = libusb20_dev_reset(pdev); 655195957Salfred 656195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 657195957Salfred pdev, libusb20_dev_get_fd(pdev), 658195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 659195957Salfred 660195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 661194676Sthompsa} 662194676Sthompsa 663194676Sthompsaint 664195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 665194676Sthompsa{ 666195957Salfred if (pdev == NULL) 667194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 668194676Sthompsa 669195957Salfred return (libusb20_dev_kernel_driver_active( 670195957Salfred pdev, interface)); 671194676Sthompsa} 672194676Sthompsa 673194676Sthompsaint 674195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 675194676Sthompsa{ 676195957Salfred int err; 677194676Sthompsa 678195957Salfred if (pdev == NULL) 679194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 680194676Sthompsa 681195957Salfred err = libusb20_dev_detach_kernel_driver( 682195957Salfred pdev, interface); 683194676Sthompsa 684195957Salfred return (err ? LIBUSB20_ERROR_OTHER : 0); 685194676Sthompsa} 686194676Sthompsa 687194676Sthompsaint 688195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 689194676Sthompsa{ 690195957Salfred if (pdev == NULL) 691194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 692195957Salfred /* stub - currently not supported by libusb20 */ 693194676Sthompsa return (0); 694194676Sthompsa} 695194676Sthompsa 696194676Sthompsa/* Asynchronous device I/O */ 697194676Sthompsa 698194676Sthompsastruct libusb_transfer * 699194676Sthompsalibusb_alloc_transfer(int iso_packets) 700194676Sthompsa{ 701195957Salfred struct libusb_transfer *uxfer; 702195957Salfred struct libusb_super_transfer *sxfer; 703194676Sthompsa int len; 704194676Sthompsa 705194676Sthompsa len = sizeof(struct libusb_transfer) + 706195957Salfred sizeof(struct libusb_super_transfer) + 707194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 708194676Sthompsa 709195957Salfred sxfer = malloc(len); 710195957Salfred if (sxfer == NULL) 711194676Sthompsa return (NULL); 712194676Sthompsa 713195957Salfred memset(sxfer, 0, len); 714194676Sthompsa 715195957Salfred uxfer = (struct libusb_transfer *)( 716195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 717194676Sthompsa 718195957Salfred /* set default value */ 719195957Salfred uxfer->num_iso_packets = iso_packets; 720195957Salfred 721195957Salfred return (uxfer); 722194676Sthompsa} 723194676Sthompsa 724194676Sthompsavoid 725195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 726194676Sthompsa{ 727195957Salfred struct libusb_super_transfer *sxfer; 728194676Sthompsa 729195957Salfred if (uxfer == NULL) 730195957Salfred return; /* be NULL safe */ 731194676Sthompsa 732195957Salfred sxfer = (struct libusb_super_transfer *)( 733195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 734194676Sthompsa 735195957Salfred free(sxfer); 736194676Sthompsa} 737194676Sthompsa 738195560Sthompsastatic int 739195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 740195560Sthompsa{ 741195560Sthompsa int ret; 742195560Sthompsa int usb_speed; 743195560Sthompsa 744195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 745195560Sthompsa 746195560Sthompsa switch (xfer->type) { 747195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 748195560Sthompsa switch (usb_speed) { 749195560Sthompsa case LIBUSB20_SPEED_LOW: 750195560Sthompsa case LIBUSB20_SPEED_FULL: 751195560Sthompsa ret = 60 * 1; 752195957Salfred break; 753195957Salfred default: 754195560Sthompsa ret = 60 * 8; 755195957Salfred break; 756195560Sthompsa } 757195957Salfred break; 758195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 759195560Sthompsa ret = 2; 760195957Salfred break; 761195560Sthompsa default: 762195560Sthompsa ret = 1; 763195957Salfred break; 764195560Sthompsa } 765195957Salfred return (ret); 766195560Sthompsa} 767195560Sthompsa 768195560Sthompsastatic int 769195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 770195560Sthompsa{ 771195560Sthompsa int ret; 772195560Sthompsa int usb_speed; 773195560Sthompsa 774195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 775195560Sthompsa 776195560Sthompsa switch (xfer->type) { 777195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 778195957Salfred ret = 0; /* kernel will auto-select */ 779195957Salfred break; 780195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 781195957Salfred ret = 1024; 782195957Salfred break; 783195957Salfred default: 784195560Sthompsa switch (usb_speed) { 785195957Salfred case LIBUSB20_SPEED_LOW: 786195957Salfred ret = 256; 787195957Salfred break; 788195957Salfred case LIBUSB20_SPEED_FULL: 789195957Salfred ret = 4096; 790195957Salfred break; 791195957Salfred default: 792195957Salfred ret = 16384; 793195957Salfred break; 794195560Sthompsa } 795195957Salfred break; 796195560Sthompsa } 797195957Salfred return (ret); 798195560Sthompsa} 799195560Sthompsa 800195957Salfredstatic int 801195957Salfredlibusb10_convert_error(uint8_t status) 802195957Salfred{ 803195957Salfred ; /* indent fix */ 804195957Salfred 805195957Salfred switch (status) { 806195957Salfred case LIBUSB20_TRANSFER_START: 807195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 808195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 809195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 810195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 811195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 812195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 813195957Salfred case LIBUSB20_TRANSFER_STALL: 814195957Salfred return (LIBUSB_TRANSFER_STALL); 815195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 816195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 817195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 818195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 819195957Salfred default: 820195957Salfred return (LIBUSB_TRANSFER_ERROR); 821195957Salfred } 822195957Salfred} 823195957Salfred 824195957Salfred/* This function must be called locked */ 825195957Salfred 826194676Sthompsastatic void 827195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 828195957Salfred struct libusb_super_transfer *sxfer, int status) 829194676Sthompsa{ 830195957Salfred struct libusb_transfer *uxfer; 831195957Salfred struct libusb_device *dev; 832195957Salfred 833195957Salfred uxfer = (struct libusb_transfer *)( 834195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 835195957Salfred 836195957Salfred if (pxfer != NULL) 837195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 838195957Salfred 839199575Sthompsa /* set transfer status */ 840195957Salfred uxfer->status = status; 841195957Salfred 842199575Sthompsa /* update super transfer state */ 843199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 844199575Sthompsa 845195957Salfred dev = libusb_get_device(uxfer->dev_handle); 846195957Salfred 847195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 848195957Salfred} 849195957Salfred 850195957Salfred/* This function must be called locked */ 851195957Salfred 852195957Salfredstatic void 853195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 854195957Salfred{ 855195957Salfred struct libusb_super_transfer *sxfer; 856195957Salfred struct libusb_transfer *uxfer; 857195957Salfred uint32_t actlen; 858195957Salfred uint16_t iso_packets; 859195957Salfred uint16_t i; 860194676Sthompsa uint8_t status; 861195957Salfred uint8_t flags; 862194676Sthompsa 863195957Salfred status = libusb20_tr_get_status(pxfer); 864195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 865195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 866195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 867194676Sthompsa 868195957Salfred if (sxfer == NULL) 869195957Salfred return; /* cancelled - nothing to do */ 870195957Salfred 871195957Salfred uxfer = (struct libusb_transfer *)( 872195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 873195957Salfred 874195957Salfred if (iso_packets > uxfer->num_iso_packets) 875195957Salfred iso_packets = uxfer->num_iso_packets; 876195957Salfred 877195957Salfred if (iso_packets == 0) 878195957Salfred return; /* nothing to do */ 879195957Salfred 880195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 881195957Salfred uxfer->num_iso_packets = iso_packets; 882195957Salfred 883195957Salfred flags = uxfer->flags; 884195957Salfred 885194676Sthompsa switch (status) { 886194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 887195560Sthompsa 888195957Salfred /* update actual length */ 889195957Salfred uxfer->actual_length = actlen; 890195957Salfred for (i = 0; i != iso_packets; i++) { 891195957Salfred uxfer->iso_packet_desc[i].actual_length = 892195957Salfred libusb20_tr_get_length(pxfer, i); 893195957Salfred } 894195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 895195957Salfred break; 896195560Sthompsa 897194676Sthompsa case LIBUSB20_TRANSFER_START: 898195957Salfred 899195957Salfred /* setup length(s) */ 900195957Salfred actlen = 0; 901195957Salfred for (i = 0; i != iso_packets; i++) { 902195957Salfred libusb20_tr_setup_isoc(pxfer, 903195957Salfred &uxfer->buffer[actlen], 904195957Salfred uxfer->iso_packet_desc[i].length, i); 905195957Salfred actlen += uxfer->iso_packet_desc[i].length; 906194676Sthompsa } 907195957Salfred 908195957Salfred /* no remainder */ 909195957Salfred sxfer->rem_len = 0; 910195957Salfred 911195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 912195957Salfred libusb20_tr_submit(pxfer); 913195957Salfred 914195957Salfred /* fork another USB transfer, if any */ 915195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 916195957Salfred break; 917195957Salfred 918194676Sthompsa default: 919195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 920195957Salfred break; 921194676Sthompsa } 922195957Salfred} 923194676Sthompsa 924195957Salfred/* This function must be called locked */ 925195957Salfred 926195957Salfredstatic void 927195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 928195957Salfred{ 929195957Salfred struct libusb_super_transfer *sxfer; 930195957Salfred struct libusb_transfer *uxfer; 931195957Salfred uint32_t max_bulk; 932195957Salfred uint32_t actlen; 933195957Salfred uint8_t status; 934195957Salfred uint8_t flags; 935195957Salfred 936195957Salfred status = libusb20_tr_get_status(pxfer); 937195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 938195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 939195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 940195957Salfred 941195957Salfred if (sxfer == NULL) 942195957Salfred return; /* cancelled - nothing to do */ 943195957Salfred 944195957Salfred uxfer = (struct libusb_transfer *)( 945195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 946195957Salfred 947195957Salfred flags = uxfer->flags; 948195957Salfred 949194676Sthompsa switch (status) { 950194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 951195957Salfred 952195957Salfred uxfer->actual_length += actlen; 953195957Salfred 954195957Salfred /* check for short packet */ 955195957Salfred if (sxfer->last_len != actlen) { 956195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 957195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 958195957Salfred } else { 959195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 960195957Salfred } 961195957Salfred break; 962195957Salfred } 963195957Salfred /* check for end of data */ 964195957Salfred if (sxfer->rem_len == 0) { 965195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 966195957Salfred break; 967195957Salfred } 968195957Salfred /* FALLTHROUGH */ 969195957Salfred 970195957Salfred case LIBUSB20_TRANSFER_START: 971195957Salfred if (max_bulk > sxfer->rem_len) { 972195957Salfred max_bulk = sxfer->rem_len; 973195957Salfred } 974195957Salfred /* setup new BULK or INTERRUPT transaction */ 975195957Salfred libusb20_tr_setup_bulk(pxfer, 976195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 977195957Salfred 978195957Salfred /* update counters */ 979195957Salfred sxfer->last_len = max_bulk; 980195957Salfred sxfer->curr_data += max_bulk; 981195957Salfred sxfer->rem_len -= max_bulk; 982195957Salfred 983195957Salfred libusb20_tr_submit(pxfer); 984195957Salfred 985195957Salfred /* check if we can fork another USB transfer */ 986195957Salfred if (sxfer->rem_len == 0) 987195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 988195957Salfred break; 989195957Salfred 990195957Salfred default: 991195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 992195957Salfred break; 993194676Sthompsa } 994194676Sthompsa} 995194676Sthompsa 996195957Salfred/* This function must be called locked */ 997195957Salfred 998195957Salfredstatic void 999195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1000194676Sthompsa{ 1001195957Salfred struct libusb_super_transfer *sxfer; 1002195957Salfred struct libusb_transfer *uxfer; 1003195957Salfred uint32_t max_bulk; 1004195957Salfred uint32_t actlen; 1005195957Salfred uint8_t status; 1006195957Salfred uint8_t flags; 1007194676Sthompsa 1008195957Salfred status = libusb20_tr_get_status(pxfer); 1009195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1010195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1011195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1012194676Sthompsa 1013195957Salfred if (sxfer == NULL) 1014195957Salfred return; /* cancelled - nothing to do */ 1015194676Sthompsa 1016195957Salfred uxfer = (struct libusb_transfer *)( 1017195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1018194676Sthompsa 1019195957Salfred flags = uxfer->flags; 1020194676Sthompsa 1021195957Salfred switch (status) { 1022195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1023194676Sthompsa 1024195957Salfred uxfer->actual_length += actlen; 1025195957Salfred 1026195957Salfred /* subtract length of SETUP packet, if any */ 1027195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1028195957Salfred 1029195957Salfred /* check for short packet */ 1030195957Salfred if (sxfer->last_len != actlen) { 1031195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1032195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1033195957Salfred } else { 1034195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1035195957Salfred } 1036195957Salfred break; 1037194676Sthompsa } 1038195957Salfred /* check for end of data */ 1039195957Salfred if (sxfer->rem_len == 0) { 1040195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1041195957Salfred break; 1042195957Salfred } 1043195957Salfred /* FALLTHROUGH */ 1044194676Sthompsa 1045195957Salfred case LIBUSB20_TRANSFER_START: 1046195957Salfred if (max_bulk > sxfer->rem_len) { 1047195957Salfred max_bulk = sxfer->rem_len; 1048195957Salfred } 1049195957Salfred /* setup new CONTROL transaction */ 1050195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1051195957Salfred /* next fragment - don't send SETUP packet */ 1052195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1053195957Salfred } else { 1054195957Salfred /* first fragment - send SETUP packet */ 1055195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1056195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1057195957Salfred } 1058195957Salfred 1059195957Salfred if (max_bulk != 0) { 1060195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1061195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1062195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1063195957Salfred } else { 1064195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1065195957Salfred } 1066195957Salfred 1067195957Salfred /* update counters */ 1068195957Salfred sxfer->last_len = max_bulk; 1069195957Salfred sxfer->curr_data += max_bulk; 1070195957Salfred sxfer->rem_len -= max_bulk; 1071195957Salfred 1072195957Salfred libusb20_tr_submit(pxfer); 1073195957Salfred 1074195957Salfred /* check if we can fork another USB transfer */ 1075195957Salfred if (sxfer->rem_len == 0) 1076195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1077195957Salfred break; 1078195957Salfred 1079195957Salfred default: 1080195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1081195957Salfred break; 1082194676Sthompsa } 1083195957Salfred} 1084195957Salfred 1085195957Salfred/* The following function must be called locked */ 1086195957Salfred 1087195957Salfredstatic void 1088195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1089195957Salfred{ 1090195957Salfred struct libusb20_transfer *pxfer0; 1091195957Salfred struct libusb20_transfer *pxfer1; 1092195957Salfred struct libusb_super_transfer *sxfer; 1093195957Salfred struct libusb_transfer *uxfer; 1094195957Salfred struct libusb_device *dev; 1095195957Salfred int err; 1096195957Salfred int buffsize; 1097195957Salfred int maxframe; 1098195957Salfred int temp; 1099195957Salfred uint8_t dummy; 1100195957Salfred 1101195957Salfred dev = libusb_get_device(pdev); 1102195957Salfred 1103195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1104195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1105195957Salfred 1106195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1107195957Salfred return; /* shouldn't happen */ 1108195957Salfred 1109195957Salfred temp = 0; 1110195957Salfred if (libusb20_tr_pending(pxfer0)) 1111195957Salfred temp |= 1; 1112195957Salfred if (libusb20_tr_pending(pxfer1)) 1113195957Salfred temp |= 2; 1114195957Salfred 1115195957Salfred switch (temp) { 1116195957Salfred case 3: 1117195957Salfred /* wait till one of the transfers complete */ 1118195957Salfred return; 1119195957Salfred case 2: 1120195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1121199575Sthompsa if (sxfer == NULL) 1122199575Sthompsa return; /* cancelling */ 1123195957Salfred if (sxfer->rem_len) 1124195957Salfred return; /* cannot queue another one */ 1125195957Salfred /* swap transfers */ 1126195957Salfred pxfer1 = pxfer0; 1127195957Salfred break; 1128195957Salfred case 1: 1129195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1130199575Sthompsa if (sxfer == NULL) 1131199575Sthompsa return; /* cancelling */ 1132195957Salfred if (sxfer->rem_len) 1133195957Salfred return; /* cannot queue another one */ 1134195957Salfred /* swap transfers */ 1135195957Salfred pxfer0 = pxfer1; 1136195957Salfred break; 1137195957Salfred default: 1138195957Salfred break; 1139194676Sthompsa } 1140195957Salfred 1141195957Salfred /* find next transfer on same endpoint */ 1142195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1143195957Salfred 1144195957Salfred uxfer = (struct libusb_transfer *)( 1145195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1146195957Salfred 1147195957Salfred if (uxfer->endpoint == endpoint) { 1148195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1149195957Salfred sxfer->entry.tqe_prev = NULL; 1150195957Salfred goto found; 1151194676Sthompsa } 1152195957Salfred } 1153195957Salfred return; /* success */ 1154194676Sthompsa 1155195957Salfredfound: 1156194676Sthompsa 1157195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1158195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1159194676Sthompsa 1160195957Salfred /* reset super transfer state */ 1161195957Salfred sxfer->rem_len = uxfer->length; 1162195957Salfred sxfer->curr_data = uxfer->buffer; 1163195957Salfred uxfer->actual_length = 0; 1164194676Sthompsa 1165195957Salfred switch (uxfer->type) { 1166195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1167195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1168195957Salfred break; 1169195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1170195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1171195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1172195957Salfred break; 1173195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1174195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1175195957Salfred if (sxfer->rem_len < 8) 1176195957Salfred goto failure; 1177194676Sthompsa 1178195957Salfred /* remove SETUP packet from data */ 1179195957Salfred sxfer->rem_len -= 8; 1180195957Salfred sxfer->curr_data += 8; 1181195957Salfred break; 1182195957Salfred default: 1183195957Salfred goto failure; 1184195560Sthompsa } 1185195957Salfred 1186195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1187195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1188195957Salfred 1189195957Salfred /* make sure the transfer is opened */ 1190195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1191195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1192195957Salfred goto failure; 1193194676Sthompsa } 1194195957Salfred libusb20_tr_start(pxfer0); 1195195957Salfred return; 1196194676Sthompsa 1197195957Salfredfailure: 1198195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1199194676Sthompsa 1200195957Salfred /* make sure our event loop spins the done handler */ 1201195957Salfred dummy = 0; 1202195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1203195957Salfred} 1204194676Sthompsa 1205195957Salfred/* The following function must be called unlocked */ 1206194676Sthompsa 1207195957Salfredint 1208195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1209195957Salfred{ 1210195957Salfred struct libusb20_transfer *pxfer0; 1211195957Salfred struct libusb20_transfer *pxfer1; 1212195957Salfred struct libusb_super_transfer *sxfer; 1213195957Salfred struct libusb_device *dev; 1214199055Sthompsa uint32_t endpoint; 1215195957Salfred int err; 1216195957Salfred 1217195957Salfred if (uxfer == NULL) 1218195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1219195957Salfred 1220195957Salfred if (uxfer->dev_handle == NULL) 1221195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1222195957Salfred 1223195957Salfred endpoint = uxfer->endpoint; 1224195957Salfred 1225195957Salfred if (endpoint > 255) 1226195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1227195957Salfred 1228195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1229195957Salfred 1230195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1231195957Salfred 1232195957Salfred sxfer = (struct libusb_super_transfer *)( 1233195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1234195957Salfred 1235195957Salfred CTX_LOCK(dev->ctx); 1236195957Salfred 1237195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1238195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1239195957Salfred 1240195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1241195957Salfred err = LIBUSB_ERROR_OTHER; 1242195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1243199575Sthompsa (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1244195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1245195957Salfred err = LIBUSB_ERROR_BUSY; 1246195957Salfred } else { 1247199575Sthompsa 1248199575Sthompsa /* set pending state */ 1249199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 1250199575Sthompsa 1251199575Sthompsa /* insert transfer into transfer head list */ 1252195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1253195957Salfred 1254199575Sthompsa /* start work transfers */ 1255195957Salfred libusb10_submit_transfer_sub( 1256195957Salfred uxfer->dev_handle, endpoint); 1257195957Salfred 1258195957Salfred err = 0; /* success */ 1259195957Salfred } 1260195957Salfred 1261195957Salfred CTX_UNLOCK(dev->ctx); 1262195957Salfred 1263195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1264195957Salfred 1265195957Salfred return (err); 1266194676Sthompsa} 1267194676Sthompsa 1268195957Salfred/* Asynchronous transfer cancel */ 1269195957Salfred 1270194676Sthompsaint 1271195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1272194676Sthompsa{ 1273195957Salfred struct libusb20_transfer *pxfer0; 1274195957Salfred struct libusb20_transfer *pxfer1; 1275195957Salfred struct libusb_super_transfer *sxfer; 1276195957Salfred struct libusb_device *dev; 1277199055Sthompsa uint32_t endpoint; 1278199575Sthompsa int retval; 1279194676Sthompsa 1280195957Salfred if (uxfer == NULL) 1281195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1282194676Sthompsa 1283199575Sthompsa /* check if not initialised */ 1284195957Salfred if (uxfer->dev_handle == NULL) 1285199575Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 1286194676Sthompsa 1287195957Salfred endpoint = uxfer->endpoint; 1288194676Sthompsa 1289195957Salfred if (endpoint > 255) 1290195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1291195957Salfred 1292195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1293195957Salfred 1294195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1295195957Salfred 1296195957Salfred sxfer = (struct libusb_super_transfer *)( 1297195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1298195957Salfred 1299199575Sthompsa retval = 0; 1300199575Sthompsa 1301195957Salfred CTX_LOCK(dev->ctx); 1302195957Salfred 1303195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1304195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1305195957Salfred 1306199575Sthompsa if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 1307199575Sthompsa /* only update the transfer status */ 1308199575Sthompsa uxfer->status = LIBUSB_TRANSFER_CANCELLED; 1309199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1310199575Sthompsa } else if (sxfer->entry.tqe_prev != NULL) { 1311195957Salfred /* we are lucky - transfer is on a queue */ 1312195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1313195957Salfred sxfer->entry.tqe_prev = NULL; 1314199575Sthompsa libusb10_complete_transfer(NULL, 1315199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1316195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1317195957Salfred /* not started */ 1318199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1319195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1320199575Sthompsa libusb10_complete_transfer(pxfer0, 1321199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1322195957Salfred libusb20_tr_stop(pxfer0); 1323195957Salfred /* make sure the queue doesn't stall */ 1324195957Salfred libusb10_submit_transfer_sub( 1325195957Salfred uxfer->dev_handle, endpoint); 1326195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1327199575Sthompsa libusb10_complete_transfer(pxfer1, 1328199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1329195957Salfred libusb20_tr_stop(pxfer1); 1330195957Salfred /* make sure the queue doesn't stall */ 1331195957Salfred libusb10_submit_transfer_sub( 1332195957Salfred uxfer->dev_handle, endpoint); 1333195957Salfred } else { 1334195957Salfred /* not started */ 1335199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1336195957Salfred } 1337195957Salfred 1338195957Salfred CTX_UNLOCK(dev->ctx); 1339195957Salfred 1340195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1341195957Salfred 1342199575Sthompsa return (retval); 1343194676Sthompsa} 1344194676Sthompsa 1345195957SalfredUNEXPORTED void 1346195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1347195957Salfred{ 1348195957Salfred /* TODO */ 1349195957Salfred} 1350199055Sthompsa 1351199055Sthompsauint16_t 1352199055Sthompsalibusb_cpu_to_le16(uint16_t x) 1353199055Sthompsa{ 1354199055Sthompsa return (htole16(x)); 1355199055Sthompsa} 1356199055Sthompsa 1357199055Sthompsauint16_t 1358199055Sthompsalibusb_le16_to_cpu(uint16_t x) 1359199055Sthompsa{ 1360199055Sthompsa return (le16toh(x)); 1361199055Sthompsa} 1362199055Sthompsa 1363