libusb10.c revision 223642
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 223642 2011-06-28 14:07:28Z hselasky $ */ 2194676Sthompsa/*- 3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4195957Salfred * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 5194676Sthompsa * 6194676Sthompsa * Redistribution and use in source and binary forms, with or without 7194676Sthompsa * modification, are permitted provided that the following conditions 8194676Sthompsa * are met: 9194676Sthompsa * 1. Redistributions of source code must retain the above copyright 10194676Sthompsa * notice, this list of conditions and the following disclaimer. 11194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 12194676Sthompsa * notice, this list of conditions and the following disclaimer in the 13194676Sthompsa * documentation and/or other materials provided with the distribution. 14194676Sthompsa * 15194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18194676Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25194676Sthompsa * SUCH DAMAGE. 26194676Sthompsa */ 27194676Sthompsa 28203815Swkoszek#include <sys/fcntl.h> 29203815Swkoszek#include <sys/ioctl.h> 30203815Swkoszek#include <sys/queue.h> 31203815Swkoszek 32203774Swkoszek#include <assert.h> 33203815Swkoszek#include <errno.h> 34203815Swkoszek#include <poll.h> 35203815Swkoszek#include <pthread.h> 36203815Swkoszek#include <stdio.h> 37194676Sthompsa#include <stdlib.h> 38194676Sthompsa#include <unistd.h> 39194676Sthompsa 40208020Sthompsa#define libusb_device_handle libusb20_device 41208020Sthompsa 42194676Sthompsa#include "libusb20.h" 43194676Sthompsa#include "libusb20_desc.h" 44194676Sthompsa#include "libusb20_int.h" 45194676Sthompsa#include "libusb.h" 46194676Sthompsa#include "libusb10.h" 47194676Sthompsa 48194676Sthompsastatic pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; 49194676Sthompsastruct libusb_context *usbi_default_context = NULL; 50194676Sthompsa 51195957Salfred/* Prototypes */ 52195957Salfred 53195957Salfredstatic struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); 54195957Salfredstatic int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 55195957Salfredstatic int libusb10_convert_error(uint8_t status); 56195957Salfredstatic void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 57195957Salfredstatic void libusb10_isoc_proxy(struct libusb20_transfer *); 58195957Salfredstatic void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 59195957Salfredstatic void libusb10_ctrl_proxy(struct libusb20_transfer *); 60195957Salfredstatic void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 61195957Salfred 62194676Sthompsa/* Library initialisation / deinitialisation */ 63194676Sthompsa 64194676Sthompsavoid 65195957Salfredlibusb_set_debug(libusb_context *ctx, int level) 66194676Sthompsa{ 67195957Salfred ctx = GET_CONTEXT(ctx); 68194676Sthompsa if (ctx) 69194676Sthompsa ctx->debug = level; 70194676Sthompsa} 71194676Sthompsa 72213853Shselaskystatic void 73213853Shselaskylibusb_set_nonblocking(int f) 74213853Shselasky{ 75213853Shselasky int flags; 76213853Shselasky 77213853Shselasky /* 78213853Shselasky * We ignore any failures in this function, hence the 79213853Shselasky * non-blocking flag is not critical to the operation of 80213853Shselasky * libUSB. We use F_GETFL and F_SETFL to be compatible with 81213853Shselasky * Linux. 82213853Shselasky */ 83213853Shselasky 84213853Shselasky flags = fcntl(f, F_GETFL, NULL); 85213853Shselasky if (flags == -1) 86213853Shselasky return; 87213853Shselasky flags |= O_NONBLOCK; 88213853Shselasky fcntl(f, F_SETFL, flags); 89213853Shselasky} 90213853Shselasky 91194676Sthompsaint 92195957Salfredlibusb_init(libusb_context **context) 93194676Sthompsa{ 94194676Sthompsa struct libusb_context *ctx; 95195957Salfred char *debug; 96194676Sthompsa int ret; 97194676Sthompsa 98194676Sthompsa ctx = malloc(sizeof(*ctx)); 99194676Sthompsa if (!ctx) 100194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 101194676Sthompsa 102194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 103194676Sthompsa 104194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 105194676Sthompsa if (debug != NULL) { 106194676Sthompsa ctx->debug = atoi(debug); 107194676Sthompsa if (ctx->debug != 0) 108194676Sthompsa ctx->debug_fixed = 1; 109194676Sthompsa } 110195957Salfred TAILQ_INIT(&ctx->pollfds); 111195957Salfred TAILQ_INIT(&ctx->tr_done); 112194676Sthompsa 113195957Salfred pthread_mutex_init(&ctx->ctx_lock, NULL); 114195957Salfred pthread_cond_init(&ctx->ctx_cond, NULL); 115194676Sthompsa 116195957Salfred ctx->ctx_handler = NO_THREAD; 117194676Sthompsa 118194676Sthompsa ret = pipe(ctx->ctrl_pipe); 119194676Sthompsa if (ret < 0) { 120195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 121195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 122194676Sthompsa free(ctx); 123194676Sthompsa return (LIBUSB_ERROR_OTHER); 124194676Sthompsa } 125195957Salfred /* set non-blocking mode on the control pipe to avoid deadlock */ 126213853Shselasky libusb_set_nonblocking(ctx->ctrl_pipe[0]); 127213853Shselasky libusb_set_nonblocking(ctx->ctrl_pipe[1]); 128194676Sthompsa 129195957Salfred libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 130194676Sthompsa 131194676Sthompsa pthread_mutex_lock(&default_context_lock); 132194676Sthompsa if (usbi_default_context == NULL) { 133194676Sthompsa usbi_default_context = ctx; 134194676Sthompsa } 135194676Sthompsa pthread_mutex_unlock(&default_context_lock); 136194676Sthompsa 137194676Sthompsa if (context) 138194676Sthompsa *context = ctx; 139194676Sthompsa 140195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 141195957Salfred 142194676Sthompsa return (0); 143194676Sthompsa} 144194676Sthompsa 145194676Sthompsavoid 146195957Salfredlibusb_exit(libusb_context *ctx) 147194676Sthompsa{ 148195957Salfred ctx = GET_CONTEXT(ctx); 149194676Sthompsa 150195957Salfred if (ctx == NULL) 151195957Salfred return; 152195957Salfred 153195957Salfred /* XXX cleanup devices */ 154195957Salfred 155195957Salfred libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 156194676Sthompsa close(ctx->ctrl_pipe[0]); 157194676Sthompsa close(ctx->ctrl_pipe[1]); 158195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 159195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 160194676Sthompsa 161194676Sthompsa pthread_mutex_lock(&default_context_lock); 162194676Sthompsa if (ctx == usbi_default_context) { 163194676Sthompsa usbi_default_context = NULL; 164194676Sthompsa } 165194676Sthompsa pthread_mutex_unlock(&default_context_lock); 166194676Sthompsa 167194676Sthompsa free(ctx); 168194676Sthompsa} 169194676Sthompsa 170194676Sthompsa/* Device handling and initialisation. */ 171194676Sthompsa 172194676Sthompsassize_t 173195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list) 174194676Sthompsa{ 175195957Salfred struct libusb20_backend *usb_backend; 176194676Sthompsa struct libusb20_device *pdev; 177194676Sthompsa struct libusb_device *dev; 178194676Sthompsa int i; 179194676Sthompsa 180195957Salfred ctx = GET_CONTEXT(ctx); 181194676Sthompsa 182195957Salfred if (ctx == NULL) 183195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 184195957Salfred 185195957Salfred if (list == NULL) 186195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 187195957Salfred 188194676Sthompsa usb_backend = libusb20_be_alloc_default(); 189194676Sthompsa if (usb_backend == NULL) 190195957Salfred return (LIBUSB_ERROR_NO_MEM); 191194676Sthompsa 192195957Salfred /* figure out how many USB devices are present */ 193194676Sthompsa pdev = NULL; 194194676Sthompsa i = 0; 195194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 196194676Sthompsa i++; 197194676Sthompsa 198195957Salfred /* allocate device pointer list */ 199194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 200194676Sthompsa if (*list == NULL) { 201194676Sthompsa libusb20_be_free(usb_backend); 202194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 203194676Sthompsa } 204195957Salfred /* create libusb v1.0 compliant devices */ 205194676Sthompsa i = 0; 206194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 207194676Sthompsa 208194676Sthompsa dev = malloc(sizeof(*dev)); 209194676Sthompsa if (dev == NULL) { 210195560Sthompsa while (i != 0) { 211195560Sthompsa libusb_unref_device((*list)[i - 1]); 212195560Sthompsa i--; 213195560Sthompsa } 214194676Sthompsa free(*list); 215195957Salfred *list = NULL; 216194676Sthompsa libusb20_be_free(usb_backend); 217194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 218194676Sthompsa } 219199055Sthompsa 220199055Sthompsa /* get device into libUSB v1.0 list */ 221199055Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 222199055Sthompsa 223194676Sthompsa memset(dev, 0, sizeof(*dev)); 224194676Sthompsa 225195957Salfred /* init transfer queues */ 226195957Salfred TAILQ_INIT(&dev->tr_head); 227195957Salfred 228195957Salfred /* set context we belong to */ 229194676Sthompsa dev->ctx = ctx; 230194676Sthompsa 231194676Sthompsa /* link together the two structures */ 232194676Sthompsa dev->os_priv = pdev; 233195957Salfred pdev->privLuData = dev; 234194676Sthompsa 235194676Sthompsa (*list)[i] = libusb_ref_device(dev); 236194676Sthompsa i++; 237194676Sthompsa } 238194676Sthompsa (*list)[i] = NULL; 239194676Sthompsa 240194676Sthompsa libusb20_be_free(usb_backend); 241194676Sthompsa return (i); 242194676Sthompsa} 243194676Sthompsa 244194676Sthompsavoid 245194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 246194676Sthompsa{ 247194676Sthompsa int i; 248194676Sthompsa 249194676Sthompsa if (list == NULL) 250195957Salfred return; /* be NULL safe */ 251194676Sthompsa 252194676Sthompsa if (unref_devices) { 253194676Sthompsa for (i = 0; list[i] != NULL; i++) 254194676Sthompsa libusb_unref_device(list[i]); 255194676Sthompsa } 256194676Sthompsa free(list); 257194676Sthompsa} 258194676Sthompsa 259194676Sthompsauint8_t 260195957Salfredlibusb_get_bus_number(libusb_device *dev) 261194676Sthompsa{ 262194676Sthompsa if (dev == NULL) 263195957Salfred return (0); /* should not happen */ 264195957Salfred return (libusb20_dev_get_bus_number(dev->os_priv)); 265194676Sthompsa} 266194676Sthompsa 267194676Sthompsauint8_t 268195957Salfredlibusb_get_device_address(libusb_device *dev) 269194676Sthompsa{ 270194676Sthompsa if (dev == NULL) 271195957Salfred return (0); /* should not happen */ 272195957Salfred return (libusb20_dev_get_address(dev->os_priv)); 273194676Sthompsa} 274194676Sthompsa 275194676Sthompsaint 276195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 277194676Sthompsa{ 278194676Sthompsa struct libusb_config_descriptor *pdconf; 279194676Sthompsa struct libusb_interface *pinf; 280194676Sthompsa struct libusb_interface_descriptor *pdinf; 281194676Sthompsa struct libusb_endpoint_descriptor *pdend; 282195957Salfred int i; 283195957Salfred int j; 284195957Salfred int k; 285195957Salfred int ret; 286194676Sthompsa 287194676Sthompsa if (dev == NULL) 288194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 289194676Sthompsa 290195957Salfred ret = libusb_get_active_config_descriptor(dev, &pdconf); 291195957Salfred if (ret < 0) 292195957Salfred return (ret); 293195957Salfred 294194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 295195957Salfred for (i = 0; i < pdconf->bNumInterfaces; i++) { 296194676Sthompsa pinf = &pdconf->interface[i]; 297195957Salfred for (j = 0; j < pinf->num_altsetting; j++) { 298194676Sthompsa pdinf = &pinf->altsetting[j]; 299195957Salfred for (k = 0; k < pdinf->bNumEndpoints; k++) { 300194676Sthompsa pdend = &pdinf->endpoint[k]; 301194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 302194676Sthompsa ret = pdend->wMaxPacketSize; 303194676Sthompsa goto out; 304194676Sthompsa } 305194676Sthompsa } 306194676Sthompsa } 307194676Sthompsa } 308194676Sthompsa 309194676Sthompsaout: 310194676Sthompsa libusb_free_config_descriptor(pdconf); 311194676Sthompsa return (ret); 312194676Sthompsa} 313194676Sthompsa 314194676Sthompsalibusb_device * 315195957Salfredlibusb_ref_device(libusb_device *dev) 316194676Sthompsa{ 317194676Sthompsa if (dev == NULL) 318195957Salfred return (NULL); /* be NULL safe */ 319194676Sthompsa 320195957Salfred CTX_LOCK(dev->ctx); 321194676Sthompsa dev->refcnt++; 322195957Salfred CTX_UNLOCK(dev->ctx); 323194676Sthompsa 324194676Sthompsa return (dev); 325194676Sthompsa} 326194676Sthompsa 327194676Sthompsavoid 328195957Salfredlibusb_unref_device(libusb_device *dev) 329194676Sthompsa{ 330194676Sthompsa if (dev == NULL) 331195957Salfred return; /* be NULL safe */ 332194676Sthompsa 333195957Salfred CTX_LOCK(dev->ctx); 334194676Sthompsa dev->refcnt--; 335195957Salfred CTX_UNLOCK(dev->ctx); 336194676Sthompsa 337194676Sthompsa if (dev->refcnt == 0) { 338194676Sthompsa libusb20_dev_free(dev->os_priv); 339194676Sthompsa free(dev); 340194676Sthompsa } 341194676Sthompsa} 342194676Sthompsa 343194676Sthompsaint 344195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh) 345194676Sthompsa{ 346194676Sthompsa libusb_context *ctx = dev->ctx; 347194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 348195957Salfred uint8_t dummy; 349194676Sthompsa int err; 350194676Sthompsa 351194676Sthompsa if (devh == NULL) 352194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 353194676Sthompsa 354195957Salfred /* set default device handle value */ 355195957Salfred *devh = NULL; 356194676Sthompsa 357195957Salfred dev = libusb_ref_device(dev); 358195957Salfred if (dev == NULL) 359195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 360195957Salfred 361194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 362194676Sthompsa if (err) { 363195957Salfred libusb_unref_device(dev); 364194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 365194676Sthompsa } 366195957Salfred libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 367194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 368194676Sthompsa 369195957Salfred /* make sure our event loop detects the new device */ 370195957Salfred dummy = 0; 371194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 372213853Shselasky if (err < (int)sizeof(dummy)) { 373195957Salfred /* ignore error, if any */ 374195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 375194676Sthompsa } 376195957Salfred *devh = pdev; 377194676Sthompsa 378194676Sthompsa return (0); 379194676Sthompsa} 380194676Sthompsa 381194676Sthompsalibusb_device_handle * 382195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 383194676Sthompsa uint16_t product_id) 384194676Sthompsa{ 385194676Sthompsa struct libusb_device **devs; 386194676Sthompsa struct libusb20_device *pdev; 387194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 388195957Salfred int i; 389195957Salfred int j; 390194676Sthompsa 391195957Salfred ctx = GET_CONTEXT(ctx); 392195957Salfred if (ctx == NULL) 393195957Salfred return (NULL); /* be NULL safe */ 394195957Salfred 395195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 396194676Sthompsa 397194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 398194676Sthompsa return (NULL); 399194676Sthompsa 400194676Sthompsa for (j = 0; j < i; j++) { 401195957Salfred pdev = devs[j]->os_priv; 402194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 403195957Salfred /* 404195957Salfred * NOTE: The USB library will automatically swap the 405195957Salfred * fields in the device descriptor to be of host 406195957Salfred * endian type! 407195957Salfred */ 408194676Sthompsa if (pdesc->idVendor == vendor_id && 409195560Sthompsa pdesc->idProduct == product_id) { 410195957Salfred if (libusb_open(devs[j], &pdev) < 0) 411195957Salfred pdev = NULL; 412195957Salfred break; 413195560Sthompsa } 414194676Sthompsa } 415200424Sscf if (j == i) 416200424Sscf pdev = NULL; 417194676Sthompsa 418194676Sthompsa libusb_free_device_list(devs, 1); 419195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 420195957Salfred return (pdev); 421194676Sthompsa} 422194676Sthompsa 423194676Sthompsavoid 424195957Salfredlibusb_close(struct libusb20_device *pdev) 425194676Sthompsa{ 426194676Sthompsa libusb_context *ctx; 427195957Salfred struct libusb_device *dev; 428195957Salfred uint8_t dummy; 429194676Sthompsa int err; 430194676Sthompsa 431195957Salfred if (pdev == NULL) 432195957Salfred return; /* be NULL safe */ 433194676Sthompsa 434195957Salfred dev = libusb_get_device(pdev); 435195957Salfred ctx = dev->ctx; 436194676Sthompsa 437195957Salfred libusb10_remove_pollfd(ctx, &dev->dev_poll); 438194676Sthompsa 439195957Salfred libusb20_dev_close(pdev); 440199055Sthompsa 441199055Sthompsa /* unref will free the "pdev" when the refcount reaches zero */ 442195957Salfred libusb_unref_device(dev); 443194676Sthompsa 444195957Salfred /* make sure our event loop detects the closed device */ 445195957Salfred dummy = 0; 446194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 447213853Shselasky if (err < (int)sizeof(dummy)) { 448195957Salfred /* ignore error, if any */ 449195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 450194676Sthompsa } 451194676Sthompsa} 452194676Sthompsa 453194676Sthompsalibusb_device * 454195957Salfredlibusb_get_device(struct libusb20_device *pdev) 455194676Sthompsa{ 456195957Salfred if (pdev == NULL) 457194676Sthompsa return (NULL); 458195957Salfred return ((libusb_device *)pdev->privLuData); 459194676Sthompsa} 460194676Sthompsa 461194676Sthompsaint 462195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config) 463194676Sthompsa{ 464195957Salfred struct libusb20_config *pconf; 465194676Sthompsa 466195957Salfred if (pdev == NULL || config == NULL) 467194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 468194676Sthompsa 469195957Salfred pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 470195957Salfred if (pconf == NULL) 471195957Salfred return (LIBUSB_ERROR_NO_MEM); 472194676Sthompsa 473195957Salfred *config = pconf->desc.bConfigurationValue; 474195957Salfred 475195957Salfred free(pconf); 476195957Salfred 477194676Sthompsa return (0); 478194676Sthompsa} 479194676Sthompsa 480194676Sthompsaint 481195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration) 482194676Sthompsa{ 483195957Salfred struct libusb20_config *pconf; 484195957Salfred struct libusb_device *dev; 485195957Salfred int err; 486195957Salfred uint8_t i; 487194676Sthompsa 488195957Salfred dev = libusb_get_device(pdev); 489195957Salfred if (dev == NULL) 490194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 491194676Sthompsa 492195957Salfred if (configuration < 1) { 493195957Salfred /* unconfigure */ 494195957Salfred i = 255; 495195957Salfred } else { 496195957Salfred for (i = 0; i != 255; i++) { 497195957Salfred uint8_t found; 498194676Sthompsa 499195957Salfred pconf = libusb20_dev_alloc_config(pdev, i); 500195957Salfred if (pconf == NULL) 501195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 502195957Salfred found = (pconf->desc.bConfigurationValue 503195957Salfred == configuration); 504195957Salfred free(pconf); 505195957Salfred 506195957Salfred if (found) 507195957Salfred goto set_config; 508195957Salfred } 509195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 510195957Salfred } 511195957Salfred 512195957Salfredset_config: 513195957Salfred 514195957Salfred libusb10_cancel_all_transfer(dev); 515195957Salfred 516195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 517195957Salfred 518195957Salfred err = libusb20_dev_set_config_index(pdev, i); 519195957Salfred 520195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 521195957Salfred POLLOUT | POLLRDNORM | POLLWRNORM); 522195957Salfred 523195957Salfred return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 524194676Sthompsa} 525194676Sthompsa 526194676Sthompsaint 527195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number) 528194676Sthompsa{ 529195957Salfred libusb_device *dev; 530195957Salfred int err = 0; 531194676Sthompsa 532195957Salfred dev = libusb_get_device(pdev); 533194676Sthompsa if (dev == NULL) 534194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 535194676Sthompsa 536195957Salfred if (interface_number < 0 || interface_number > 31) 537194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 538194676Sthompsa 539195957Salfred CTX_LOCK(dev->ctx); 540194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 541195957Salfred err = LIBUSB_ERROR_BUSY; 542194676Sthompsa 543195957Salfred if (!err) 544194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 545195957Salfred CTX_UNLOCK(dev->ctx); 546195957Salfred return (err); 547194676Sthompsa} 548194676Sthompsa 549194676Sthompsaint 550195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number) 551194676Sthompsa{ 552195957Salfred libusb_device *dev; 553195957Salfred int err = 0; 554194676Sthompsa 555195957Salfred dev = libusb_get_device(pdev); 556194676Sthompsa if (dev == NULL) 557194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 558194676Sthompsa 559195957Salfred if (interface_number < 0 || interface_number > 31) 560194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 561194676Sthompsa 562195957Salfred CTX_LOCK(dev->ctx); 563194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 564195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 565194676Sthompsa 566195957Salfred if (!err) 567194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 568195957Salfred CTX_UNLOCK(dev->ctx); 569195957Salfred return (err); 570194676Sthompsa} 571194676Sthompsa 572194676Sthompsaint 573195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev, 574194676Sthompsa int interface_number, int alternate_setting) 575194676Sthompsa{ 576195957Salfred libusb_device *dev; 577195957Salfred int err = 0; 578194676Sthompsa 579195957Salfred dev = libusb_get_device(pdev); 580194676Sthompsa if (dev == NULL) 581194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 582194676Sthompsa 583195957Salfred if (interface_number < 0 || interface_number > 31) 584194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 585194676Sthompsa 586195957Salfred CTX_LOCK(dev->ctx); 587195957Salfred if (!(dev->claimed_interfaces & (1 << interface_number))) 588195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 589195957Salfred CTX_UNLOCK(dev->ctx); 590194676Sthompsa 591195957Salfred if (err) 592195957Salfred return (err); 593195957Salfred 594195957Salfred libusb10_cancel_all_transfer(dev); 595195957Salfred 596195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 597195957Salfred 598195957Salfred err = libusb20_dev_set_alt_index(pdev, 599195957Salfred interface_number, alternate_setting); 600195957Salfred 601195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 602195957Salfred pdev, libusb20_dev_get_fd(pdev), 603195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 604195957Salfred 605195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 606194676Sthompsa} 607194676Sthompsa 608195957Salfredstatic struct libusb20_transfer * 609195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev, 610195957Salfred uint8_t endpoint, uint8_t index) 611195957Salfred{ 612195957Salfred index &= 1; /* double buffering */ 613195957Salfred 614195957Salfred index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 615195957Salfred 616195957Salfred if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 617195957Salfred /* this is an IN endpoint */ 618195957Salfred index |= 2; 619195957Salfred } 620195957Salfred return (libusb20_tr_get_pointer(pdev, index)); 621195957Salfred} 622195957Salfred 623194676Sthompsaint 624195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 625194676Sthompsa{ 626194676Sthompsa struct libusb20_transfer *xfer; 627195957Salfred struct libusb_device *dev; 628195957Salfred int err; 629194676Sthompsa 630195957Salfred xfer = libusb10_get_transfer(pdev, endpoint, 0); 631195560Sthompsa if (xfer == NULL) 632195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 633194676Sthompsa 634195957Salfred dev = libusb_get_device(pdev); 635213853Shselasky if (dev == NULL) 636213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 637195957Salfred 638195957Salfred CTX_LOCK(dev->ctx); 639223642Shselasky err = libusb20_tr_open(xfer, 0, 1, endpoint); 640195957Salfred CTX_UNLOCK(dev->ctx); 641195957Salfred 642195957Salfred if (err != 0 && err != LIBUSB20_ERROR_BUSY) 643194676Sthompsa return (LIBUSB_ERROR_OTHER); 644194676Sthompsa 645194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 646195957Salfred 647195957Salfred /* check if we opened the transfer */ 648195957Salfred if (err == 0) { 649195957Salfred CTX_LOCK(dev->ctx); 650194676Sthompsa libusb20_tr_close(xfer); 651195957Salfred CTX_UNLOCK(dev->ctx); 652195957Salfred } 653195957Salfred return (0); /* success */ 654194676Sthompsa} 655194676Sthompsa 656194676Sthompsaint 657195957Salfredlibusb_reset_device(struct libusb20_device *pdev) 658194676Sthompsa{ 659195957Salfred libusb_device *dev; 660195957Salfred int err; 661194676Sthompsa 662195957Salfred dev = libusb_get_device(pdev); 663194676Sthompsa if (dev == NULL) 664213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 665194676Sthompsa 666195957Salfred libusb10_cancel_all_transfer(dev); 667195957Salfred 668195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 669195957Salfred 670195957Salfred err = libusb20_dev_reset(pdev); 671195957Salfred 672195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 673195957Salfred pdev, libusb20_dev_get_fd(pdev), 674195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 675195957Salfred 676195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 677194676Sthompsa} 678194676Sthompsa 679194676Sthompsaint 680213848Shselaskylibusb_check_connected(struct libusb20_device *pdev) 681213848Shselasky{ 682213848Shselasky libusb_device *dev; 683213848Shselasky int err; 684213848Shselasky 685213848Shselasky dev = libusb_get_device(pdev); 686213848Shselasky if (dev == NULL) 687213848Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 688213848Shselasky 689213848Shselasky err = libusb20_dev_check_connected(pdev); 690213848Shselasky 691213848Shselasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 692213848Shselasky} 693213848Shselasky 694213848Shselaskyint 695195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 696194676Sthompsa{ 697195957Salfred if (pdev == NULL) 698194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 699194676Sthompsa 700195957Salfred return (libusb20_dev_kernel_driver_active( 701195957Salfred pdev, interface)); 702194676Sthompsa} 703194676Sthompsa 704194676Sthompsaint 705213853Shselaskylibusb_get_driver_np(struct libusb20_device *pdev, int interface, 706213853Shselasky char *name, int namelen) 707213853Shselasky{ 708213853Shselasky return (libusb_get_driver(pdev, interface, name, namelen)); 709213853Shselasky} 710213853Shselasky 711213853Shselaskyint 712213853Shselaskylibusb_get_driver(struct libusb20_device *pdev, int interface, 713213853Shselasky char *name, int namelen) 714213853Shselasky{ 715213853Shselasky char *ptr; 716213853Shselasky int err; 717213853Shselasky 718213853Shselasky if (pdev == NULL) 719213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 720213853Shselasky if (namelen < 1) 721213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 722213853Shselasky 723213853Shselasky err = libusb20_dev_get_iface_desc( 724213853Shselasky pdev, interface, name, namelen); 725213853Shselasky 726213853Shselasky if (err != 0) 727213853Shselasky return (LIBUSB_ERROR_OTHER); 728213853Shselasky 729213853Shselasky /* we only want the driver name */ 730213853Shselasky ptr = strstr(name, ":"); 731213853Shselasky if (ptr != NULL) 732213853Shselasky *ptr = 0; 733213853Shselasky 734213853Shselasky return (0); 735213853Shselasky} 736213853Shselasky 737213853Shselaskyint 738213853Shselaskylibusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface) 739213853Shselasky{ 740213853Shselasky return (libusb_detach_kernel_driver(pdev, interface)); 741213853Shselasky} 742213853Shselasky 743213853Shselaskyint 744195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 745194676Sthompsa{ 746195957Salfred int err; 747194676Sthompsa 748195957Salfred if (pdev == NULL) 749194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 750194676Sthompsa 751195957Salfred err = libusb20_dev_detach_kernel_driver( 752195957Salfred pdev, interface); 753194676Sthompsa 754213853Shselasky return (err ? LIBUSB_ERROR_OTHER : 0); 755194676Sthompsa} 756194676Sthompsa 757194676Sthompsaint 758195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 759194676Sthompsa{ 760195957Salfred if (pdev == NULL) 761194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 762195957Salfred /* stub - currently not supported by libusb20 */ 763194676Sthompsa return (0); 764194676Sthompsa} 765194676Sthompsa 766194676Sthompsa/* Asynchronous device I/O */ 767194676Sthompsa 768194676Sthompsastruct libusb_transfer * 769194676Sthompsalibusb_alloc_transfer(int iso_packets) 770194676Sthompsa{ 771195957Salfred struct libusb_transfer *uxfer; 772195957Salfred struct libusb_super_transfer *sxfer; 773194676Sthompsa int len; 774194676Sthompsa 775194676Sthompsa len = sizeof(struct libusb_transfer) + 776195957Salfred sizeof(struct libusb_super_transfer) + 777194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 778194676Sthompsa 779195957Salfred sxfer = malloc(len); 780195957Salfred if (sxfer == NULL) 781194676Sthompsa return (NULL); 782194676Sthompsa 783195957Salfred memset(sxfer, 0, len); 784194676Sthompsa 785195957Salfred uxfer = (struct libusb_transfer *)( 786195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 787194676Sthompsa 788195957Salfred /* set default value */ 789195957Salfred uxfer->num_iso_packets = iso_packets; 790195957Salfred 791195957Salfred return (uxfer); 792194676Sthompsa} 793194676Sthompsa 794194676Sthompsavoid 795195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 796194676Sthompsa{ 797195957Salfred struct libusb_super_transfer *sxfer; 798194676Sthompsa 799195957Salfred if (uxfer == NULL) 800195957Salfred return; /* be NULL safe */ 801194676Sthompsa 802215253Shselasky /* check if we should free the transfer buffer */ 803215253Shselasky if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) 804215253Shselasky free(uxfer->buffer); 805215253Shselasky 806195957Salfred sxfer = (struct libusb_super_transfer *)( 807195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 808194676Sthompsa 809195957Salfred free(sxfer); 810194676Sthompsa} 811194676Sthompsa 812219100Shselaskystatic uint32_t 813195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 814195560Sthompsa{ 815219100Shselasky uint32_t ret; 816195560Sthompsa 817195560Sthompsa switch (xfer->type) { 818195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 819219100Shselasky ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */ 820195957Salfred break; 821195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 822195560Sthompsa ret = 2; 823195957Salfred break; 824195560Sthompsa default: 825195560Sthompsa ret = 1; 826195957Salfred break; 827195560Sthompsa } 828195957Salfred return (ret); 829195560Sthompsa} 830195560Sthompsa 831195560Sthompsastatic int 832195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 833195560Sthompsa{ 834195560Sthompsa int ret; 835195560Sthompsa int usb_speed; 836195560Sthompsa 837195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 838195560Sthompsa 839195560Sthompsa switch (xfer->type) { 840195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 841195957Salfred ret = 0; /* kernel will auto-select */ 842195957Salfred break; 843195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 844195957Salfred ret = 1024; 845195957Salfred break; 846195957Salfred default: 847195560Sthompsa switch (usb_speed) { 848195957Salfred case LIBUSB20_SPEED_LOW: 849195957Salfred ret = 256; 850195957Salfred break; 851195957Salfred case LIBUSB20_SPEED_FULL: 852195957Salfred ret = 4096; 853195957Salfred break; 854195957Salfred default: 855195957Salfred ret = 16384; 856195957Salfred break; 857195560Sthompsa } 858195957Salfred break; 859195560Sthompsa } 860195957Salfred return (ret); 861195560Sthompsa} 862195560Sthompsa 863195957Salfredstatic int 864195957Salfredlibusb10_convert_error(uint8_t status) 865195957Salfred{ 866195957Salfred ; /* indent fix */ 867195957Salfred 868195957Salfred switch (status) { 869195957Salfred case LIBUSB20_TRANSFER_START: 870195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 871195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 872195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 873195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 874195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 875195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 876195957Salfred case LIBUSB20_TRANSFER_STALL: 877195957Salfred return (LIBUSB_TRANSFER_STALL); 878195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 879195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 880195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 881195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 882195957Salfred default: 883195957Salfred return (LIBUSB_TRANSFER_ERROR); 884195957Salfred } 885195957Salfred} 886195957Salfred 887195957Salfred/* This function must be called locked */ 888195957Salfred 889194676Sthompsastatic void 890195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 891195957Salfred struct libusb_super_transfer *sxfer, int status) 892194676Sthompsa{ 893195957Salfred struct libusb_transfer *uxfer; 894195957Salfred struct libusb_device *dev; 895195957Salfred 896195957Salfred uxfer = (struct libusb_transfer *)( 897195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 898195957Salfred 899195957Salfred if (pxfer != NULL) 900195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 901195957Salfred 902199575Sthompsa /* set transfer status */ 903195957Salfred uxfer->status = status; 904195957Salfred 905199575Sthompsa /* update super transfer state */ 906199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 907199575Sthompsa 908195957Salfred dev = libusb_get_device(uxfer->dev_handle); 909195957Salfred 910195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 911195957Salfred} 912195957Salfred 913195957Salfred/* This function must be called locked */ 914195957Salfred 915195957Salfredstatic void 916195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 917195957Salfred{ 918195957Salfred struct libusb_super_transfer *sxfer; 919195957Salfred struct libusb_transfer *uxfer; 920195957Salfred uint32_t actlen; 921195957Salfred uint16_t iso_packets; 922195957Salfred uint16_t i; 923194676Sthompsa uint8_t status; 924195957Salfred uint8_t flags; 925194676Sthompsa 926195957Salfred status = libusb20_tr_get_status(pxfer); 927195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 928195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 929195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 930194676Sthompsa 931195957Salfred if (sxfer == NULL) 932195957Salfred return; /* cancelled - nothing to do */ 933195957Salfred 934195957Salfred uxfer = (struct libusb_transfer *)( 935195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 936195957Salfred 937195957Salfred if (iso_packets > uxfer->num_iso_packets) 938195957Salfred iso_packets = uxfer->num_iso_packets; 939195957Salfred 940195957Salfred if (iso_packets == 0) 941195957Salfred return; /* nothing to do */ 942195957Salfred 943195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 944195957Salfred uxfer->num_iso_packets = iso_packets; 945195957Salfred 946195957Salfred flags = uxfer->flags; 947195957Salfred 948194676Sthompsa switch (status) { 949194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 950195560Sthompsa 951195957Salfred /* update actual length */ 952195957Salfred uxfer->actual_length = actlen; 953195957Salfred for (i = 0; i != iso_packets; i++) { 954195957Salfred uxfer->iso_packet_desc[i].actual_length = 955195957Salfred libusb20_tr_get_length(pxfer, i); 956195957Salfred } 957195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 958195957Salfred break; 959195560Sthompsa 960194676Sthompsa case LIBUSB20_TRANSFER_START: 961195957Salfred 962195957Salfred /* setup length(s) */ 963195957Salfred actlen = 0; 964195957Salfred for (i = 0; i != iso_packets; i++) { 965195957Salfred libusb20_tr_setup_isoc(pxfer, 966195957Salfred &uxfer->buffer[actlen], 967195957Salfred uxfer->iso_packet_desc[i].length, i); 968195957Salfred actlen += uxfer->iso_packet_desc[i].length; 969194676Sthompsa } 970195957Salfred 971195957Salfred /* no remainder */ 972195957Salfred sxfer->rem_len = 0; 973195957Salfred 974195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 975195957Salfred libusb20_tr_submit(pxfer); 976195957Salfred 977195957Salfred /* fork another USB transfer, if any */ 978195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 979195957Salfred break; 980195957Salfred 981194676Sthompsa default: 982195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 983195957Salfred break; 984194676Sthompsa } 985195957Salfred} 986194676Sthompsa 987195957Salfred/* This function must be called locked */ 988195957Salfred 989195957Salfredstatic void 990195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 991195957Salfred{ 992195957Salfred struct libusb_super_transfer *sxfer; 993195957Salfred struct libusb_transfer *uxfer; 994195957Salfred uint32_t max_bulk; 995195957Salfred uint32_t actlen; 996195957Salfred uint8_t status; 997195957Salfred uint8_t flags; 998195957Salfred 999195957Salfred status = libusb20_tr_get_status(pxfer); 1000195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1001195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1002195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1003195957Salfred 1004195957Salfred if (sxfer == NULL) 1005195957Salfred return; /* cancelled - nothing to do */ 1006195957Salfred 1007195957Salfred uxfer = (struct libusb_transfer *)( 1008195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1009195957Salfred 1010195957Salfred flags = uxfer->flags; 1011195957Salfred 1012194676Sthompsa switch (status) { 1013194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 1014195957Salfred 1015195957Salfred uxfer->actual_length += actlen; 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; 1025195957Salfred } 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 */ 1032195957Salfred 1033195957Salfred case LIBUSB20_TRANSFER_START: 1034195957Salfred if (max_bulk > sxfer->rem_len) { 1035195957Salfred max_bulk = sxfer->rem_len; 1036195957Salfred } 1037195957Salfred /* setup new BULK or INTERRUPT transaction */ 1038195957Salfred libusb20_tr_setup_bulk(pxfer, 1039195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 1040195957Salfred 1041195957Salfred /* update counters */ 1042195957Salfred sxfer->last_len = max_bulk; 1043195957Salfred sxfer->curr_data += max_bulk; 1044195957Salfred sxfer->rem_len -= max_bulk; 1045195957Salfred 1046195957Salfred libusb20_tr_submit(pxfer); 1047195957Salfred 1048195957Salfred /* check if we can fork another USB transfer */ 1049195957Salfred if (sxfer->rem_len == 0) 1050195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1051195957Salfred break; 1052195957Salfred 1053195957Salfred default: 1054195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1055195957Salfred break; 1056194676Sthompsa } 1057194676Sthompsa} 1058194676Sthompsa 1059195957Salfred/* This function must be called locked */ 1060195957Salfred 1061195957Salfredstatic void 1062195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1063194676Sthompsa{ 1064195957Salfred struct libusb_super_transfer *sxfer; 1065195957Salfred struct libusb_transfer *uxfer; 1066195957Salfred uint32_t max_bulk; 1067195957Salfred uint32_t actlen; 1068195957Salfred uint8_t status; 1069195957Salfred uint8_t flags; 1070194676Sthompsa 1071195957Salfred status = libusb20_tr_get_status(pxfer); 1072195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1073195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1074195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1075194676Sthompsa 1076195957Salfred if (sxfer == NULL) 1077195957Salfred return; /* cancelled - nothing to do */ 1078194676Sthompsa 1079195957Salfred uxfer = (struct libusb_transfer *)( 1080195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1081194676Sthompsa 1082195957Salfred flags = uxfer->flags; 1083194676Sthompsa 1084195957Salfred switch (status) { 1085195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1086194676Sthompsa 1087195957Salfred uxfer->actual_length += actlen; 1088195957Salfred 1089195957Salfred /* subtract length of SETUP packet, if any */ 1090195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1091195957Salfred 1092195957Salfred /* check for short packet */ 1093195957Salfred if (sxfer->last_len != actlen) { 1094195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1095195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1096195957Salfred } else { 1097195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1098195957Salfred } 1099195957Salfred break; 1100194676Sthompsa } 1101195957Salfred /* check for end of data */ 1102195957Salfred if (sxfer->rem_len == 0) { 1103195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1104195957Salfred break; 1105195957Salfred } 1106195957Salfred /* FALLTHROUGH */ 1107194676Sthompsa 1108195957Salfred case LIBUSB20_TRANSFER_START: 1109195957Salfred if (max_bulk > sxfer->rem_len) { 1110195957Salfred max_bulk = sxfer->rem_len; 1111195957Salfred } 1112195957Salfred /* setup new CONTROL transaction */ 1113195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1114195957Salfred /* next fragment - don't send SETUP packet */ 1115195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1116195957Salfred } else { 1117195957Salfred /* first fragment - send SETUP packet */ 1118195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1119195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1120195957Salfred } 1121195957Salfred 1122195957Salfred if (max_bulk != 0) { 1123195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1124195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1125195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1126195957Salfred } else { 1127195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1128195957Salfred } 1129195957Salfred 1130195957Salfred /* update counters */ 1131195957Salfred sxfer->last_len = max_bulk; 1132195957Salfred sxfer->curr_data += max_bulk; 1133195957Salfred sxfer->rem_len -= max_bulk; 1134195957Salfred 1135195957Salfred libusb20_tr_submit(pxfer); 1136195957Salfred 1137195957Salfred /* check if we can fork another USB transfer */ 1138195957Salfred if (sxfer->rem_len == 0) 1139195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1140195957Salfred break; 1141195957Salfred 1142195957Salfred default: 1143195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1144195957Salfred break; 1145194676Sthompsa } 1146195957Salfred} 1147195957Salfred 1148195957Salfred/* The following function must be called locked */ 1149195957Salfred 1150195957Salfredstatic void 1151195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1152195957Salfred{ 1153195957Salfred struct libusb20_transfer *pxfer0; 1154195957Salfred struct libusb20_transfer *pxfer1; 1155195957Salfred struct libusb_super_transfer *sxfer; 1156195957Salfred struct libusb_transfer *uxfer; 1157195957Salfred struct libusb_device *dev; 1158195957Salfred int err; 1159195957Salfred int buffsize; 1160195957Salfred int maxframe; 1161195957Salfred int temp; 1162195957Salfred uint8_t dummy; 1163195957Salfred 1164195957Salfred dev = libusb_get_device(pdev); 1165195957Salfred 1166195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1167195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1168195957Salfred 1169195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1170195957Salfred return; /* shouldn't happen */ 1171195957Salfred 1172195957Salfred temp = 0; 1173195957Salfred if (libusb20_tr_pending(pxfer0)) 1174195957Salfred temp |= 1; 1175195957Salfred if (libusb20_tr_pending(pxfer1)) 1176195957Salfred temp |= 2; 1177195957Salfred 1178195957Salfred switch (temp) { 1179195957Salfred case 3: 1180195957Salfred /* wait till one of the transfers complete */ 1181195957Salfred return; 1182195957Salfred case 2: 1183195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1184199575Sthompsa if (sxfer == NULL) 1185199575Sthompsa return; /* cancelling */ 1186195957Salfred if (sxfer->rem_len) 1187195957Salfred return; /* cannot queue another one */ 1188195957Salfred /* swap transfers */ 1189195957Salfred pxfer1 = pxfer0; 1190195957Salfred break; 1191195957Salfred case 1: 1192195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1193199575Sthompsa if (sxfer == NULL) 1194199575Sthompsa return; /* cancelling */ 1195195957Salfred if (sxfer->rem_len) 1196195957Salfred return; /* cannot queue another one */ 1197195957Salfred /* swap transfers */ 1198195957Salfred pxfer0 = pxfer1; 1199195957Salfred break; 1200195957Salfred default: 1201195957Salfred break; 1202194676Sthompsa } 1203195957Salfred 1204195957Salfred /* find next transfer on same endpoint */ 1205195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1206195957Salfred 1207195957Salfred uxfer = (struct libusb_transfer *)( 1208195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1209195957Salfred 1210195957Salfred if (uxfer->endpoint == endpoint) { 1211195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1212195957Salfred sxfer->entry.tqe_prev = NULL; 1213195957Salfred goto found; 1214194676Sthompsa } 1215195957Salfred } 1216195957Salfred return; /* success */ 1217194676Sthompsa 1218195957Salfredfound: 1219194676Sthompsa 1220195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1221195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1222194676Sthompsa 1223195957Salfred /* reset super transfer state */ 1224195957Salfred sxfer->rem_len = uxfer->length; 1225195957Salfred sxfer->curr_data = uxfer->buffer; 1226195957Salfred uxfer->actual_length = 0; 1227194676Sthompsa 1228195957Salfred switch (uxfer->type) { 1229195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1230195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1231195957Salfred break; 1232195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1233195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1234195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1235195957Salfred break; 1236195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1237195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1238195957Salfred if (sxfer->rem_len < 8) 1239195957Salfred goto failure; 1240194676Sthompsa 1241195957Salfred /* remove SETUP packet from data */ 1242195957Salfred sxfer->rem_len -= 8; 1243195957Salfred sxfer->curr_data += 8; 1244195957Salfred break; 1245195957Salfred default: 1246195957Salfred goto failure; 1247195560Sthompsa } 1248195957Salfred 1249195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1250195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1251195957Salfred 1252195957Salfred /* make sure the transfer is opened */ 1253195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1254195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1255195957Salfred goto failure; 1256194676Sthompsa } 1257195957Salfred libusb20_tr_start(pxfer0); 1258195957Salfred return; 1259194676Sthompsa 1260195957Salfredfailure: 1261195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1262194676Sthompsa 1263195957Salfred /* make sure our event loop spins the done handler */ 1264195957Salfred dummy = 0; 1265195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1266195957Salfred} 1267194676Sthompsa 1268195957Salfred/* The following function must be called unlocked */ 1269194676Sthompsa 1270195957Salfredint 1271195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1272195957Salfred{ 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; 1278195957Salfred int err; 1279195957Salfred 1280195957Salfred if (uxfer == NULL) 1281195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1282195957Salfred 1283195957Salfred if (uxfer->dev_handle == NULL) 1284195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1285195957Salfred 1286195957Salfred endpoint = uxfer->endpoint; 1287195957Salfred 1288195957Salfred if (endpoint > 255) 1289195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1290195957Salfred 1291195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1292195957Salfred 1293195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1294195957Salfred 1295195957Salfred sxfer = (struct libusb_super_transfer *)( 1296195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1297195957Salfred 1298195957Salfred CTX_LOCK(dev->ctx); 1299195957Salfred 1300195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1301195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1302195957Salfred 1303195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1304195957Salfred err = LIBUSB_ERROR_OTHER; 1305195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1306199575Sthompsa (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1307195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1308195957Salfred err = LIBUSB_ERROR_BUSY; 1309195957Salfred } else { 1310199575Sthompsa 1311199575Sthompsa /* set pending state */ 1312199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 1313199575Sthompsa 1314199575Sthompsa /* insert transfer into transfer head list */ 1315195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1316195957Salfred 1317199575Sthompsa /* start work transfers */ 1318195957Salfred libusb10_submit_transfer_sub( 1319195957Salfred uxfer->dev_handle, endpoint); 1320195957Salfred 1321195957Salfred err = 0; /* success */ 1322195957Salfred } 1323195957Salfred 1324195957Salfred CTX_UNLOCK(dev->ctx); 1325195957Salfred 1326195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1327195957Salfred 1328195957Salfred return (err); 1329194676Sthompsa} 1330194676Sthompsa 1331195957Salfred/* Asynchronous transfer cancel */ 1332195957Salfred 1333194676Sthompsaint 1334195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1335194676Sthompsa{ 1336195957Salfred struct libusb20_transfer *pxfer0; 1337195957Salfred struct libusb20_transfer *pxfer1; 1338195957Salfred struct libusb_super_transfer *sxfer; 1339195957Salfred struct libusb_device *dev; 1340199055Sthompsa uint32_t endpoint; 1341199575Sthompsa int retval; 1342194676Sthompsa 1343195957Salfred if (uxfer == NULL) 1344195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1345194676Sthompsa 1346199575Sthompsa /* check if not initialised */ 1347195957Salfred if (uxfer->dev_handle == NULL) 1348199575Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 1349194676Sthompsa 1350195957Salfred endpoint = uxfer->endpoint; 1351194676Sthompsa 1352195957Salfred if (endpoint > 255) 1353195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1354195957Salfred 1355195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1356195957Salfred 1357195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1358195957Salfred 1359195957Salfred sxfer = (struct libusb_super_transfer *)( 1360195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1361195957Salfred 1362199575Sthompsa retval = 0; 1363199575Sthompsa 1364195957Salfred CTX_LOCK(dev->ctx); 1365195957Salfred 1366195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1367195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1368195957Salfred 1369199575Sthompsa if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 1370199575Sthompsa /* only update the transfer status */ 1371199575Sthompsa uxfer->status = LIBUSB_TRANSFER_CANCELLED; 1372199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1373199575Sthompsa } else if (sxfer->entry.tqe_prev != NULL) { 1374195957Salfred /* we are lucky - transfer is on a queue */ 1375195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1376195957Salfred sxfer->entry.tqe_prev = NULL; 1377199575Sthompsa libusb10_complete_transfer(NULL, 1378199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1379195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1380195957Salfred /* not started */ 1381199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1382195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1383199575Sthompsa libusb10_complete_transfer(pxfer0, 1384199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1385195957Salfred libusb20_tr_stop(pxfer0); 1386195957Salfred /* make sure the queue doesn't stall */ 1387195957Salfred libusb10_submit_transfer_sub( 1388195957Salfred uxfer->dev_handle, endpoint); 1389195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1390199575Sthompsa libusb10_complete_transfer(pxfer1, 1391199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1392195957Salfred libusb20_tr_stop(pxfer1); 1393195957Salfred /* make sure the queue doesn't stall */ 1394195957Salfred libusb10_submit_transfer_sub( 1395195957Salfred uxfer->dev_handle, endpoint); 1396195957Salfred } else { 1397195957Salfred /* not started */ 1398199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1399195957Salfred } 1400195957Salfred 1401195957Salfred CTX_UNLOCK(dev->ctx); 1402195957Salfred 1403195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1404195957Salfred 1405199575Sthompsa return (retval); 1406194676Sthompsa} 1407194676Sthompsa 1408195957SalfredUNEXPORTED void 1409195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1410195957Salfred{ 1411195957Salfred /* TODO */ 1412195957Salfred} 1413199055Sthompsa 1414199055Sthompsauint16_t 1415199055Sthompsalibusb_cpu_to_le16(uint16_t x) 1416199055Sthompsa{ 1417199055Sthompsa return (htole16(x)); 1418199055Sthompsa} 1419199055Sthompsa 1420199055Sthompsauint16_t 1421199055Sthompsalibusb_le16_to_cpu(uint16_t x) 1422199055Sthompsa{ 1423199055Sthompsa return (le16toh(x)); 1424199055Sthompsa} 1425199055Sthompsa 1426213853Shselaskyconst char * 1427213853Shselaskylibusb_strerror(int code) 1428213853Shselasky{ 1429213853Shselasky /* TODO */ 1430213853Shselasky return ("Unknown error"); 1431213853Shselasky} 1432