libusb10.c revision 215253
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 215253 2010-11-13 19:25:11Z 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_maxframe(struct libusb20_device *, libusb_transfer *); 55195957Salfredstatic int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); 56195957Salfredstatic int libusb10_convert_error(uint8_t status); 57195957Salfredstatic void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); 58195957Salfredstatic void libusb10_isoc_proxy(struct libusb20_transfer *); 59195957Salfredstatic void libusb10_bulk_intr_proxy(struct libusb20_transfer *); 60195957Salfredstatic void libusb10_ctrl_proxy(struct libusb20_transfer *); 61195957Salfredstatic void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t); 62195957Salfred 63194676Sthompsa/* Library initialisation / deinitialisation */ 64194676Sthompsa 65194676Sthompsavoid 66195957Salfredlibusb_set_debug(libusb_context *ctx, int level) 67194676Sthompsa{ 68195957Salfred ctx = GET_CONTEXT(ctx); 69194676Sthompsa if (ctx) 70194676Sthompsa ctx->debug = level; 71194676Sthompsa} 72194676Sthompsa 73213853Shselaskystatic void 74213853Shselaskylibusb_set_nonblocking(int f) 75213853Shselasky{ 76213853Shselasky int flags; 77213853Shselasky 78213853Shselasky /* 79213853Shselasky * We ignore any failures in this function, hence the 80213853Shselasky * non-blocking flag is not critical to the operation of 81213853Shselasky * libUSB. We use F_GETFL and F_SETFL to be compatible with 82213853Shselasky * Linux. 83213853Shselasky */ 84213853Shselasky 85213853Shselasky flags = fcntl(f, F_GETFL, NULL); 86213853Shselasky if (flags == -1) 87213853Shselasky return; 88213853Shselasky flags |= O_NONBLOCK; 89213853Shselasky fcntl(f, F_SETFL, flags); 90213853Shselasky} 91213853Shselasky 92194676Sthompsaint 93195957Salfredlibusb_init(libusb_context **context) 94194676Sthompsa{ 95194676Sthompsa struct libusb_context *ctx; 96195957Salfred char *debug; 97194676Sthompsa int ret; 98194676Sthompsa 99194676Sthompsa ctx = malloc(sizeof(*ctx)); 100194676Sthompsa if (!ctx) 101194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 102194676Sthompsa 103194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 104194676Sthompsa 105194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 106194676Sthompsa if (debug != NULL) { 107194676Sthompsa ctx->debug = atoi(debug); 108194676Sthompsa if (ctx->debug != 0) 109194676Sthompsa ctx->debug_fixed = 1; 110194676Sthompsa } 111195957Salfred TAILQ_INIT(&ctx->pollfds); 112195957Salfred TAILQ_INIT(&ctx->tr_done); 113194676Sthompsa 114195957Salfred pthread_mutex_init(&ctx->ctx_lock, NULL); 115195957Salfred pthread_cond_init(&ctx->ctx_cond, NULL); 116194676Sthompsa 117195957Salfred ctx->ctx_handler = NO_THREAD; 118194676Sthompsa 119194676Sthompsa ret = pipe(ctx->ctrl_pipe); 120194676Sthompsa if (ret < 0) { 121195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 122195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 123194676Sthompsa free(ctx); 124194676Sthompsa return (LIBUSB_ERROR_OTHER); 125194676Sthompsa } 126195957Salfred /* set non-blocking mode on the control pipe to avoid deadlock */ 127213853Shselasky libusb_set_nonblocking(ctx->ctrl_pipe[0]); 128213853Shselasky libusb_set_nonblocking(ctx->ctrl_pipe[1]); 129194676Sthompsa 130195957Salfred libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 131194676Sthompsa 132194676Sthompsa pthread_mutex_lock(&default_context_lock); 133194676Sthompsa if (usbi_default_context == NULL) { 134194676Sthompsa usbi_default_context = ctx; 135194676Sthompsa } 136194676Sthompsa pthread_mutex_unlock(&default_context_lock); 137194676Sthompsa 138194676Sthompsa if (context) 139194676Sthompsa *context = ctx; 140194676Sthompsa 141195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 142195957Salfred 143194676Sthompsa return (0); 144194676Sthompsa} 145194676Sthompsa 146194676Sthompsavoid 147195957Salfredlibusb_exit(libusb_context *ctx) 148194676Sthompsa{ 149195957Salfred ctx = GET_CONTEXT(ctx); 150194676Sthompsa 151195957Salfred if (ctx == NULL) 152195957Salfred return; 153195957Salfred 154195957Salfred /* XXX cleanup devices */ 155195957Salfred 156195957Salfred libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 157194676Sthompsa close(ctx->ctrl_pipe[0]); 158194676Sthompsa close(ctx->ctrl_pipe[1]); 159195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 160195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 161194676Sthompsa 162194676Sthompsa pthread_mutex_lock(&default_context_lock); 163194676Sthompsa if (ctx == usbi_default_context) { 164194676Sthompsa usbi_default_context = NULL; 165194676Sthompsa } 166194676Sthompsa pthread_mutex_unlock(&default_context_lock); 167194676Sthompsa 168194676Sthompsa free(ctx); 169194676Sthompsa} 170194676Sthompsa 171194676Sthompsa/* Device handling and initialisation. */ 172194676Sthompsa 173194676Sthompsassize_t 174195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list) 175194676Sthompsa{ 176195957Salfred struct libusb20_backend *usb_backend; 177194676Sthompsa struct libusb20_device *pdev; 178194676Sthompsa struct libusb_device *dev; 179194676Sthompsa int i; 180194676Sthompsa 181195957Salfred ctx = GET_CONTEXT(ctx); 182194676Sthompsa 183195957Salfred if (ctx == NULL) 184195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 185195957Salfred 186195957Salfred if (list == NULL) 187195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 188195957Salfred 189194676Sthompsa usb_backend = libusb20_be_alloc_default(); 190194676Sthompsa if (usb_backend == NULL) 191195957Salfred return (LIBUSB_ERROR_NO_MEM); 192194676Sthompsa 193195957Salfred /* figure out how many USB devices are present */ 194194676Sthompsa pdev = NULL; 195194676Sthompsa i = 0; 196194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 197194676Sthompsa i++; 198194676Sthompsa 199195957Salfred /* allocate device pointer list */ 200194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 201194676Sthompsa if (*list == NULL) { 202194676Sthompsa libusb20_be_free(usb_backend); 203194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 204194676Sthompsa } 205195957Salfred /* create libusb v1.0 compliant devices */ 206194676Sthompsa i = 0; 207194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 208194676Sthompsa 209194676Sthompsa dev = malloc(sizeof(*dev)); 210194676Sthompsa if (dev == NULL) { 211195560Sthompsa while (i != 0) { 212195560Sthompsa libusb_unref_device((*list)[i - 1]); 213195560Sthompsa i--; 214195560Sthompsa } 215194676Sthompsa free(*list); 216195957Salfred *list = NULL; 217194676Sthompsa libusb20_be_free(usb_backend); 218194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 219194676Sthompsa } 220199055Sthompsa 221199055Sthompsa /* get device into libUSB v1.0 list */ 222199055Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 223199055Sthompsa 224194676Sthompsa memset(dev, 0, sizeof(*dev)); 225194676Sthompsa 226195957Salfred /* init transfer queues */ 227195957Salfred TAILQ_INIT(&dev->tr_head); 228195957Salfred 229195957Salfred /* set context we belong to */ 230194676Sthompsa dev->ctx = ctx; 231194676Sthompsa 232194676Sthompsa /* link together the two structures */ 233194676Sthompsa dev->os_priv = pdev; 234195957Salfred pdev->privLuData = dev; 235194676Sthompsa 236194676Sthompsa (*list)[i] = libusb_ref_device(dev); 237194676Sthompsa i++; 238194676Sthompsa } 239194676Sthompsa (*list)[i] = NULL; 240194676Sthompsa 241194676Sthompsa libusb20_be_free(usb_backend); 242194676Sthompsa return (i); 243194676Sthompsa} 244194676Sthompsa 245194676Sthompsavoid 246194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 247194676Sthompsa{ 248194676Sthompsa int i; 249194676Sthompsa 250194676Sthompsa if (list == NULL) 251195957Salfred return; /* be NULL safe */ 252194676Sthompsa 253194676Sthompsa if (unref_devices) { 254194676Sthompsa for (i = 0; list[i] != NULL; i++) 255194676Sthompsa libusb_unref_device(list[i]); 256194676Sthompsa } 257194676Sthompsa free(list); 258194676Sthompsa} 259194676Sthompsa 260194676Sthompsauint8_t 261195957Salfredlibusb_get_bus_number(libusb_device *dev) 262194676Sthompsa{ 263194676Sthompsa if (dev == NULL) 264195957Salfred return (0); /* should not happen */ 265195957Salfred return (libusb20_dev_get_bus_number(dev->os_priv)); 266194676Sthompsa} 267194676Sthompsa 268194676Sthompsauint8_t 269195957Salfredlibusb_get_device_address(libusb_device *dev) 270194676Sthompsa{ 271194676Sthompsa if (dev == NULL) 272195957Salfred return (0); /* should not happen */ 273195957Salfred return (libusb20_dev_get_address(dev->os_priv)); 274194676Sthompsa} 275194676Sthompsa 276194676Sthompsaint 277195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 278194676Sthompsa{ 279194676Sthompsa struct libusb_config_descriptor *pdconf; 280194676Sthompsa struct libusb_interface *pinf; 281194676Sthompsa struct libusb_interface_descriptor *pdinf; 282194676Sthompsa struct libusb_endpoint_descriptor *pdend; 283195957Salfred int i; 284195957Salfred int j; 285195957Salfred int k; 286195957Salfred int ret; 287194676Sthompsa 288194676Sthompsa if (dev == NULL) 289194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 290194676Sthompsa 291195957Salfred ret = libusb_get_active_config_descriptor(dev, &pdconf); 292195957Salfred if (ret < 0) 293195957Salfred return (ret); 294195957Salfred 295194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 296195957Salfred for (i = 0; i < pdconf->bNumInterfaces; i++) { 297194676Sthompsa pinf = &pdconf->interface[i]; 298195957Salfred for (j = 0; j < pinf->num_altsetting; j++) { 299194676Sthompsa pdinf = &pinf->altsetting[j]; 300195957Salfred for (k = 0; k < pdinf->bNumEndpoints; k++) { 301194676Sthompsa pdend = &pdinf->endpoint[k]; 302194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 303194676Sthompsa ret = pdend->wMaxPacketSize; 304194676Sthompsa goto out; 305194676Sthompsa } 306194676Sthompsa } 307194676Sthompsa } 308194676Sthompsa } 309194676Sthompsa 310194676Sthompsaout: 311194676Sthompsa libusb_free_config_descriptor(pdconf); 312194676Sthompsa return (ret); 313194676Sthompsa} 314194676Sthompsa 315194676Sthompsalibusb_device * 316195957Salfredlibusb_ref_device(libusb_device *dev) 317194676Sthompsa{ 318194676Sthompsa if (dev == NULL) 319195957Salfred return (NULL); /* be NULL safe */ 320194676Sthompsa 321195957Salfred CTX_LOCK(dev->ctx); 322194676Sthompsa dev->refcnt++; 323195957Salfred CTX_UNLOCK(dev->ctx); 324194676Sthompsa 325194676Sthompsa return (dev); 326194676Sthompsa} 327194676Sthompsa 328194676Sthompsavoid 329195957Salfredlibusb_unref_device(libusb_device *dev) 330194676Sthompsa{ 331194676Sthompsa if (dev == NULL) 332195957Salfred return; /* be NULL safe */ 333194676Sthompsa 334195957Salfred CTX_LOCK(dev->ctx); 335194676Sthompsa dev->refcnt--; 336195957Salfred CTX_UNLOCK(dev->ctx); 337194676Sthompsa 338194676Sthompsa if (dev->refcnt == 0) { 339194676Sthompsa libusb20_dev_free(dev->os_priv); 340194676Sthompsa free(dev); 341194676Sthompsa } 342194676Sthompsa} 343194676Sthompsa 344194676Sthompsaint 345195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh) 346194676Sthompsa{ 347194676Sthompsa libusb_context *ctx = dev->ctx; 348194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 349195957Salfred uint8_t dummy; 350194676Sthompsa int err; 351194676Sthompsa 352194676Sthompsa if (devh == NULL) 353194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 354194676Sthompsa 355195957Salfred /* set default device handle value */ 356195957Salfred *devh = NULL; 357194676Sthompsa 358195957Salfred dev = libusb_ref_device(dev); 359195957Salfred if (dev == NULL) 360195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 361195957Salfred 362194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 363194676Sthompsa if (err) { 364195957Salfred libusb_unref_device(dev); 365194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 366194676Sthompsa } 367195957Salfred libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 368194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 369194676Sthompsa 370195957Salfred /* make sure our event loop detects the new device */ 371195957Salfred dummy = 0; 372194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 373213853Shselasky if (err < (int)sizeof(dummy)) { 374195957Salfred /* ignore error, if any */ 375195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 376194676Sthompsa } 377195957Salfred *devh = pdev; 378194676Sthompsa 379194676Sthompsa return (0); 380194676Sthompsa} 381194676Sthompsa 382194676Sthompsalibusb_device_handle * 383195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 384194676Sthompsa uint16_t product_id) 385194676Sthompsa{ 386194676Sthompsa struct libusb_device **devs; 387194676Sthompsa struct libusb20_device *pdev; 388194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 389195957Salfred int i; 390195957Salfred int j; 391194676Sthompsa 392195957Salfred ctx = GET_CONTEXT(ctx); 393195957Salfred if (ctx == NULL) 394195957Salfred return (NULL); /* be NULL safe */ 395195957Salfred 396195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 397194676Sthompsa 398194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 399194676Sthompsa return (NULL); 400194676Sthompsa 401194676Sthompsa for (j = 0; j < i; j++) { 402195957Salfred pdev = devs[j]->os_priv; 403194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 404195957Salfred /* 405195957Salfred * NOTE: The USB library will automatically swap the 406195957Salfred * fields in the device descriptor to be of host 407195957Salfred * endian type! 408195957Salfred */ 409194676Sthompsa if (pdesc->idVendor == vendor_id && 410195560Sthompsa pdesc->idProduct == product_id) { 411195957Salfred if (libusb_open(devs[j], &pdev) < 0) 412195957Salfred pdev = NULL; 413195957Salfred break; 414195560Sthompsa } 415194676Sthompsa } 416200424Sscf if (j == i) 417200424Sscf pdev = NULL; 418194676Sthompsa 419194676Sthompsa libusb_free_device_list(devs, 1); 420195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 421195957Salfred return (pdev); 422194676Sthompsa} 423194676Sthompsa 424194676Sthompsavoid 425195957Salfredlibusb_close(struct libusb20_device *pdev) 426194676Sthompsa{ 427194676Sthompsa libusb_context *ctx; 428195957Salfred struct libusb_device *dev; 429195957Salfred uint8_t dummy; 430194676Sthompsa int err; 431194676Sthompsa 432195957Salfred if (pdev == NULL) 433195957Salfred return; /* be NULL safe */ 434194676Sthompsa 435195957Salfred dev = libusb_get_device(pdev); 436195957Salfred ctx = dev->ctx; 437194676Sthompsa 438195957Salfred libusb10_remove_pollfd(ctx, &dev->dev_poll); 439194676Sthompsa 440195957Salfred libusb20_dev_close(pdev); 441199055Sthompsa 442199055Sthompsa /* unref will free the "pdev" when the refcount reaches zero */ 443195957Salfred libusb_unref_device(dev); 444194676Sthompsa 445195957Salfred /* make sure our event loop detects the closed device */ 446195957Salfred dummy = 0; 447194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 448213853Shselasky if (err < (int)sizeof(dummy)) { 449195957Salfred /* ignore error, if any */ 450195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 451194676Sthompsa } 452194676Sthompsa} 453194676Sthompsa 454194676Sthompsalibusb_device * 455195957Salfredlibusb_get_device(struct libusb20_device *pdev) 456194676Sthompsa{ 457195957Salfred if (pdev == NULL) 458194676Sthompsa return (NULL); 459195957Salfred return ((libusb_device *)pdev->privLuData); 460194676Sthompsa} 461194676Sthompsa 462194676Sthompsaint 463195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config) 464194676Sthompsa{ 465195957Salfred struct libusb20_config *pconf; 466194676Sthompsa 467195957Salfred if (pdev == NULL || config == NULL) 468194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 469194676Sthompsa 470195957Salfred pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 471195957Salfred if (pconf == NULL) 472195957Salfred return (LIBUSB_ERROR_NO_MEM); 473194676Sthompsa 474195957Salfred *config = pconf->desc.bConfigurationValue; 475195957Salfred 476195957Salfred free(pconf); 477195957Salfred 478194676Sthompsa return (0); 479194676Sthompsa} 480194676Sthompsa 481194676Sthompsaint 482195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration) 483194676Sthompsa{ 484195957Salfred struct libusb20_config *pconf; 485195957Salfred struct libusb_device *dev; 486195957Salfred int err; 487195957Salfred uint8_t i; 488194676Sthompsa 489195957Salfred dev = libusb_get_device(pdev); 490195957Salfred if (dev == NULL) 491194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 492194676Sthompsa 493195957Salfred if (configuration < 1) { 494195957Salfred /* unconfigure */ 495195957Salfred i = 255; 496195957Salfred } else { 497195957Salfred for (i = 0; i != 255; i++) { 498195957Salfred uint8_t found; 499194676Sthompsa 500195957Salfred pconf = libusb20_dev_alloc_config(pdev, i); 501195957Salfred if (pconf == NULL) 502195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 503195957Salfred found = (pconf->desc.bConfigurationValue 504195957Salfred == configuration); 505195957Salfred free(pconf); 506195957Salfred 507195957Salfred if (found) 508195957Salfred goto set_config; 509195957Salfred } 510195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 511195957Salfred } 512195957Salfred 513195957Salfredset_config: 514195957Salfred 515195957Salfred libusb10_cancel_all_transfer(dev); 516195957Salfred 517195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 518195957Salfred 519195957Salfred err = libusb20_dev_set_config_index(pdev, i); 520195957Salfred 521195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 522195957Salfred POLLOUT | POLLRDNORM | POLLWRNORM); 523195957Salfred 524195957Salfred return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 525194676Sthompsa} 526194676Sthompsa 527194676Sthompsaint 528195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number) 529194676Sthompsa{ 530195957Salfred libusb_device *dev; 531195957Salfred int err = 0; 532194676Sthompsa 533195957Salfred dev = libusb_get_device(pdev); 534194676Sthompsa if (dev == NULL) 535194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 536194676Sthompsa 537195957Salfred if (interface_number < 0 || interface_number > 31) 538194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 539194676Sthompsa 540195957Salfred CTX_LOCK(dev->ctx); 541194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 542195957Salfred err = LIBUSB_ERROR_BUSY; 543194676Sthompsa 544195957Salfred if (!err) 545194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 546195957Salfred CTX_UNLOCK(dev->ctx); 547195957Salfred return (err); 548194676Sthompsa} 549194676Sthompsa 550194676Sthompsaint 551195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number) 552194676Sthompsa{ 553195957Salfred libusb_device *dev; 554195957Salfred int err = 0; 555194676Sthompsa 556195957Salfred dev = libusb_get_device(pdev); 557194676Sthompsa if (dev == NULL) 558194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 559194676Sthompsa 560195957Salfred if (interface_number < 0 || interface_number > 31) 561194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 562194676Sthompsa 563195957Salfred CTX_LOCK(dev->ctx); 564194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 565195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 566194676Sthompsa 567195957Salfred if (!err) 568194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 569195957Salfred CTX_UNLOCK(dev->ctx); 570195957Salfred return (err); 571194676Sthompsa} 572194676Sthompsa 573194676Sthompsaint 574195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev, 575194676Sthompsa int interface_number, int alternate_setting) 576194676Sthompsa{ 577195957Salfred libusb_device *dev; 578195957Salfred int err = 0; 579194676Sthompsa 580195957Salfred dev = libusb_get_device(pdev); 581194676Sthompsa if (dev == NULL) 582194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 583194676Sthompsa 584195957Salfred if (interface_number < 0 || interface_number > 31) 585194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 586194676Sthompsa 587195957Salfred CTX_LOCK(dev->ctx); 588195957Salfred if (!(dev->claimed_interfaces & (1 << interface_number))) 589195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 590195957Salfred CTX_UNLOCK(dev->ctx); 591194676Sthompsa 592195957Salfred if (err) 593195957Salfred return (err); 594195957Salfred 595195957Salfred libusb10_cancel_all_transfer(dev); 596195957Salfred 597195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 598195957Salfred 599195957Salfred err = libusb20_dev_set_alt_index(pdev, 600195957Salfred interface_number, alternate_setting); 601195957Salfred 602195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 603195957Salfred pdev, libusb20_dev_get_fd(pdev), 604195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 605195957Salfred 606195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 607194676Sthompsa} 608194676Sthompsa 609195957Salfredstatic struct libusb20_transfer * 610195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev, 611195957Salfred uint8_t endpoint, uint8_t index) 612195957Salfred{ 613195957Salfred index &= 1; /* double buffering */ 614195957Salfred 615195957Salfred index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 616195957Salfred 617195957Salfred if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 618195957Salfred /* this is an IN endpoint */ 619195957Salfred index |= 2; 620195957Salfred } 621195957Salfred return (libusb20_tr_get_pointer(pdev, index)); 622195957Salfred} 623195957Salfred 624194676Sthompsaint 625195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 626194676Sthompsa{ 627194676Sthompsa struct libusb20_transfer *xfer; 628195957Salfred struct libusb_device *dev; 629195957Salfred int err; 630194676Sthompsa 631195957Salfred xfer = libusb10_get_transfer(pdev, endpoint, 0); 632195560Sthompsa if (xfer == NULL) 633195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 634194676Sthompsa 635195957Salfred dev = libusb_get_device(pdev); 636213853Shselasky if (dev == NULL) 637213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 638195957Salfred 639195957Salfred CTX_LOCK(dev->ctx); 640195957Salfred err = libusb20_tr_open(xfer, 0, 0, endpoint); 641195957Salfred CTX_UNLOCK(dev->ctx); 642195957Salfred 643195957Salfred if (err != 0 && err != LIBUSB20_ERROR_BUSY) 644194676Sthompsa return (LIBUSB_ERROR_OTHER); 645194676Sthompsa 646194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 647195957Salfred 648195957Salfred /* check if we opened the transfer */ 649195957Salfred if (err == 0) { 650195957Salfred CTX_LOCK(dev->ctx); 651194676Sthompsa libusb20_tr_close(xfer); 652195957Salfred CTX_UNLOCK(dev->ctx); 653195957Salfred } 654195957Salfred return (0); /* success */ 655194676Sthompsa} 656194676Sthompsa 657194676Sthompsaint 658195957Salfredlibusb_reset_device(struct libusb20_device *pdev) 659194676Sthompsa{ 660195957Salfred libusb_device *dev; 661195957Salfred int err; 662194676Sthompsa 663195957Salfred dev = libusb_get_device(pdev); 664194676Sthompsa if (dev == NULL) 665213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 666194676Sthompsa 667195957Salfred libusb10_cancel_all_transfer(dev); 668195957Salfred 669195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 670195957Salfred 671195957Salfred err = libusb20_dev_reset(pdev); 672195957Salfred 673195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 674195957Salfred pdev, libusb20_dev_get_fd(pdev), 675195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 676195957Salfred 677195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 678194676Sthompsa} 679194676Sthompsa 680194676Sthompsaint 681213848Shselaskylibusb_check_connected(struct libusb20_device *pdev) 682213848Shselasky{ 683213848Shselasky libusb_device *dev; 684213848Shselasky int err; 685213848Shselasky 686213848Shselasky dev = libusb_get_device(pdev); 687213848Shselasky if (dev == NULL) 688213848Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 689213848Shselasky 690213848Shselasky err = libusb20_dev_check_connected(pdev); 691213848Shselasky 692213848Shselasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 693213848Shselasky} 694213848Shselasky 695213848Shselaskyint 696195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 697194676Sthompsa{ 698195957Salfred if (pdev == NULL) 699194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 700194676Sthompsa 701195957Salfred return (libusb20_dev_kernel_driver_active( 702195957Salfred pdev, interface)); 703194676Sthompsa} 704194676Sthompsa 705194676Sthompsaint 706213853Shselaskylibusb_get_driver_np(struct libusb20_device *pdev, int interface, 707213853Shselasky char *name, int namelen) 708213853Shselasky{ 709213853Shselasky return (libusb_get_driver(pdev, interface, name, namelen)); 710213853Shselasky} 711213853Shselasky 712213853Shselaskyint 713213853Shselaskylibusb_get_driver(struct libusb20_device *pdev, int interface, 714213853Shselasky char *name, int namelen) 715213853Shselasky{ 716213853Shselasky char *ptr; 717213853Shselasky int err; 718213853Shselasky 719213853Shselasky if (pdev == NULL) 720213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 721213853Shselasky if (namelen < 1) 722213853Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 723213853Shselasky 724213853Shselasky err = libusb20_dev_get_iface_desc( 725213853Shselasky pdev, interface, name, namelen); 726213853Shselasky 727213853Shselasky if (err != 0) 728213853Shselasky return (LIBUSB_ERROR_OTHER); 729213853Shselasky 730213853Shselasky /* we only want the driver name */ 731213853Shselasky ptr = strstr(name, ":"); 732213853Shselasky if (ptr != NULL) 733213853Shselasky *ptr = 0; 734213853Shselasky 735213853Shselasky return (0); 736213853Shselasky} 737213853Shselasky 738213853Shselaskyint 739213853Shselaskylibusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface) 740213853Shselasky{ 741213853Shselasky return (libusb_detach_kernel_driver(pdev, interface)); 742213853Shselasky} 743213853Shselasky 744213853Shselaskyint 745195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 746194676Sthompsa{ 747195957Salfred int err; 748194676Sthompsa 749195957Salfred if (pdev == NULL) 750194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 751194676Sthompsa 752195957Salfred err = libusb20_dev_detach_kernel_driver( 753195957Salfred pdev, interface); 754194676Sthompsa 755213853Shselasky return (err ? LIBUSB_ERROR_OTHER : 0); 756194676Sthompsa} 757194676Sthompsa 758194676Sthompsaint 759195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 760194676Sthompsa{ 761195957Salfred if (pdev == NULL) 762194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 763195957Salfred /* stub - currently not supported by libusb20 */ 764194676Sthompsa return (0); 765194676Sthompsa} 766194676Sthompsa 767194676Sthompsa/* Asynchronous device I/O */ 768194676Sthompsa 769194676Sthompsastruct libusb_transfer * 770194676Sthompsalibusb_alloc_transfer(int iso_packets) 771194676Sthompsa{ 772195957Salfred struct libusb_transfer *uxfer; 773195957Salfred struct libusb_super_transfer *sxfer; 774194676Sthompsa int len; 775194676Sthompsa 776194676Sthompsa len = sizeof(struct libusb_transfer) + 777195957Salfred sizeof(struct libusb_super_transfer) + 778194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 779194676Sthompsa 780195957Salfred sxfer = malloc(len); 781195957Salfred if (sxfer == NULL) 782194676Sthompsa return (NULL); 783194676Sthompsa 784195957Salfred memset(sxfer, 0, len); 785194676Sthompsa 786195957Salfred uxfer = (struct libusb_transfer *)( 787195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 788194676Sthompsa 789195957Salfred /* set default value */ 790195957Salfred uxfer->num_iso_packets = iso_packets; 791195957Salfred 792195957Salfred return (uxfer); 793194676Sthompsa} 794194676Sthompsa 795194676Sthompsavoid 796195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 797194676Sthompsa{ 798195957Salfred struct libusb_super_transfer *sxfer; 799194676Sthompsa 800195957Salfred if (uxfer == NULL) 801195957Salfred return; /* be NULL safe */ 802194676Sthompsa 803215253Shselasky /* check if we should free the transfer buffer */ 804215253Shselasky if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER) 805215253Shselasky free(uxfer->buffer); 806215253Shselasky 807195957Salfred sxfer = (struct libusb_super_transfer *)( 808195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 809194676Sthompsa 810195957Salfred free(sxfer); 811194676Sthompsa} 812194676Sthompsa 813195560Sthompsastatic int 814195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 815195560Sthompsa{ 816195560Sthompsa int ret; 817195560Sthompsa int usb_speed; 818195560Sthompsa 819195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 820195560Sthompsa 821195560Sthompsa switch (xfer->type) { 822195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 823195560Sthompsa switch (usb_speed) { 824195560Sthompsa case LIBUSB20_SPEED_LOW: 825195560Sthompsa case LIBUSB20_SPEED_FULL: 826195560Sthompsa ret = 60 * 1; 827195957Salfred break; 828195957Salfred default: 829195560Sthompsa ret = 60 * 8; 830195957Salfred break; 831195560Sthompsa } 832195957Salfred break; 833195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 834195560Sthompsa ret = 2; 835195957Salfred break; 836195560Sthompsa default: 837195560Sthompsa ret = 1; 838195957Salfred break; 839195560Sthompsa } 840195957Salfred return (ret); 841195560Sthompsa} 842195560Sthompsa 843195560Sthompsastatic int 844195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 845195560Sthompsa{ 846195560Sthompsa int ret; 847195560Sthompsa int usb_speed; 848195560Sthompsa 849195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 850195560Sthompsa 851195560Sthompsa switch (xfer->type) { 852195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 853195957Salfred ret = 0; /* kernel will auto-select */ 854195957Salfred break; 855195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 856195957Salfred ret = 1024; 857195957Salfred break; 858195957Salfred default: 859195560Sthompsa switch (usb_speed) { 860195957Salfred case LIBUSB20_SPEED_LOW: 861195957Salfred ret = 256; 862195957Salfred break; 863195957Salfred case LIBUSB20_SPEED_FULL: 864195957Salfred ret = 4096; 865195957Salfred break; 866195957Salfred default: 867195957Salfred ret = 16384; 868195957Salfred break; 869195560Sthompsa } 870195957Salfred break; 871195560Sthompsa } 872195957Salfred return (ret); 873195560Sthompsa} 874195560Sthompsa 875195957Salfredstatic int 876195957Salfredlibusb10_convert_error(uint8_t status) 877195957Salfred{ 878195957Salfred ; /* indent fix */ 879195957Salfred 880195957Salfred switch (status) { 881195957Salfred case LIBUSB20_TRANSFER_START: 882195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 883195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 884195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 885195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 886195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 887195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 888195957Salfred case LIBUSB20_TRANSFER_STALL: 889195957Salfred return (LIBUSB_TRANSFER_STALL); 890195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 891195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 892195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 893195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 894195957Salfred default: 895195957Salfred return (LIBUSB_TRANSFER_ERROR); 896195957Salfred } 897195957Salfred} 898195957Salfred 899195957Salfred/* This function must be called locked */ 900195957Salfred 901194676Sthompsastatic void 902195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 903195957Salfred struct libusb_super_transfer *sxfer, int status) 904194676Sthompsa{ 905195957Salfred struct libusb_transfer *uxfer; 906195957Salfred struct libusb_device *dev; 907195957Salfred 908195957Salfred uxfer = (struct libusb_transfer *)( 909195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 910195957Salfred 911195957Salfred if (pxfer != NULL) 912195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 913195957Salfred 914199575Sthompsa /* set transfer status */ 915195957Salfred uxfer->status = status; 916195957Salfred 917199575Sthompsa /* update super transfer state */ 918199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 919199575Sthompsa 920195957Salfred dev = libusb_get_device(uxfer->dev_handle); 921195957Salfred 922195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 923195957Salfred} 924195957Salfred 925195957Salfred/* This function must be called locked */ 926195957Salfred 927195957Salfredstatic void 928195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 929195957Salfred{ 930195957Salfred struct libusb_super_transfer *sxfer; 931195957Salfred struct libusb_transfer *uxfer; 932195957Salfred uint32_t actlen; 933195957Salfred uint16_t iso_packets; 934195957Salfred uint16_t i; 935194676Sthompsa uint8_t status; 936195957Salfred uint8_t flags; 937194676Sthompsa 938195957Salfred status = libusb20_tr_get_status(pxfer); 939195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 940195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 941195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 942194676Sthompsa 943195957Salfred if (sxfer == NULL) 944195957Salfred return; /* cancelled - nothing to do */ 945195957Salfred 946195957Salfred uxfer = (struct libusb_transfer *)( 947195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 948195957Salfred 949195957Salfred if (iso_packets > uxfer->num_iso_packets) 950195957Salfred iso_packets = uxfer->num_iso_packets; 951195957Salfred 952195957Salfred if (iso_packets == 0) 953195957Salfred return; /* nothing to do */ 954195957Salfred 955195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 956195957Salfred uxfer->num_iso_packets = iso_packets; 957195957Salfred 958195957Salfred flags = uxfer->flags; 959195957Salfred 960194676Sthompsa switch (status) { 961194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 962195560Sthompsa 963195957Salfred /* update actual length */ 964195957Salfred uxfer->actual_length = actlen; 965195957Salfred for (i = 0; i != iso_packets; i++) { 966195957Salfred uxfer->iso_packet_desc[i].actual_length = 967195957Salfred libusb20_tr_get_length(pxfer, i); 968195957Salfred } 969195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 970195957Salfred break; 971195560Sthompsa 972194676Sthompsa case LIBUSB20_TRANSFER_START: 973195957Salfred 974195957Salfred /* setup length(s) */ 975195957Salfred actlen = 0; 976195957Salfred for (i = 0; i != iso_packets; i++) { 977195957Salfred libusb20_tr_setup_isoc(pxfer, 978195957Salfred &uxfer->buffer[actlen], 979195957Salfred uxfer->iso_packet_desc[i].length, i); 980195957Salfred actlen += uxfer->iso_packet_desc[i].length; 981194676Sthompsa } 982195957Salfred 983195957Salfred /* no remainder */ 984195957Salfred sxfer->rem_len = 0; 985195957Salfred 986195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 987195957Salfred libusb20_tr_submit(pxfer); 988195957Salfred 989195957Salfred /* fork another USB transfer, if any */ 990195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 991195957Salfred break; 992195957Salfred 993194676Sthompsa default: 994195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 995195957Salfred break; 996194676Sthompsa } 997195957Salfred} 998194676Sthompsa 999195957Salfred/* This function must be called locked */ 1000195957Salfred 1001195957Salfredstatic void 1002195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 1003195957Salfred{ 1004195957Salfred struct libusb_super_transfer *sxfer; 1005195957Salfred struct libusb_transfer *uxfer; 1006195957Salfred uint32_t max_bulk; 1007195957Salfred uint32_t actlen; 1008195957Salfred uint8_t status; 1009195957Salfred uint8_t flags; 1010195957Salfred 1011195957Salfred status = libusb20_tr_get_status(pxfer); 1012195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1013195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1014195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1015195957Salfred 1016195957Salfred if (sxfer == NULL) 1017195957Salfred return; /* cancelled - nothing to do */ 1018195957Salfred 1019195957Salfred uxfer = (struct libusb_transfer *)( 1020195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1021195957Salfred 1022195957Salfred flags = uxfer->flags; 1023195957Salfred 1024194676Sthompsa switch (status) { 1025194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 1026195957Salfred 1027195957Salfred uxfer->actual_length += actlen; 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; 1037195957Salfred } 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 */ 1044195957Salfred 1045195957Salfred case LIBUSB20_TRANSFER_START: 1046195957Salfred if (max_bulk > sxfer->rem_len) { 1047195957Salfred max_bulk = sxfer->rem_len; 1048195957Salfred } 1049195957Salfred /* setup new BULK or INTERRUPT transaction */ 1050195957Salfred libusb20_tr_setup_bulk(pxfer, 1051195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 1052195957Salfred 1053195957Salfred /* update counters */ 1054195957Salfred sxfer->last_len = max_bulk; 1055195957Salfred sxfer->curr_data += max_bulk; 1056195957Salfred sxfer->rem_len -= max_bulk; 1057195957Salfred 1058195957Salfred libusb20_tr_submit(pxfer); 1059195957Salfred 1060195957Salfred /* check if we can fork another USB transfer */ 1061195957Salfred if (sxfer->rem_len == 0) 1062195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1063195957Salfred break; 1064195957Salfred 1065195957Salfred default: 1066195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1067195957Salfred break; 1068194676Sthompsa } 1069194676Sthompsa} 1070194676Sthompsa 1071195957Salfred/* This function must be called locked */ 1072195957Salfred 1073195957Salfredstatic void 1074195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1075194676Sthompsa{ 1076195957Salfred struct libusb_super_transfer *sxfer; 1077195957Salfred struct libusb_transfer *uxfer; 1078195957Salfred uint32_t max_bulk; 1079195957Salfred uint32_t actlen; 1080195957Salfred uint8_t status; 1081195957Salfred uint8_t flags; 1082194676Sthompsa 1083195957Salfred status = libusb20_tr_get_status(pxfer); 1084195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1085195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1086195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1087194676Sthompsa 1088195957Salfred if (sxfer == NULL) 1089195957Salfred return; /* cancelled - nothing to do */ 1090194676Sthompsa 1091195957Salfred uxfer = (struct libusb_transfer *)( 1092195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1093194676Sthompsa 1094195957Salfred flags = uxfer->flags; 1095194676Sthompsa 1096195957Salfred switch (status) { 1097195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1098194676Sthompsa 1099195957Salfred uxfer->actual_length += actlen; 1100195957Salfred 1101195957Salfred /* subtract length of SETUP packet, if any */ 1102195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1103195957Salfred 1104195957Salfred /* check for short packet */ 1105195957Salfred if (sxfer->last_len != actlen) { 1106195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1107195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1108195957Salfred } else { 1109195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1110195957Salfred } 1111195957Salfred break; 1112194676Sthompsa } 1113195957Salfred /* check for end of data */ 1114195957Salfred if (sxfer->rem_len == 0) { 1115195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1116195957Salfred break; 1117195957Salfred } 1118195957Salfred /* FALLTHROUGH */ 1119194676Sthompsa 1120195957Salfred case LIBUSB20_TRANSFER_START: 1121195957Salfred if (max_bulk > sxfer->rem_len) { 1122195957Salfred max_bulk = sxfer->rem_len; 1123195957Salfred } 1124195957Salfred /* setup new CONTROL transaction */ 1125195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1126195957Salfred /* next fragment - don't send SETUP packet */ 1127195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1128195957Salfred } else { 1129195957Salfred /* first fragment - send SETUP packet */ 1130195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1131195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1132195957Salfred } 1133195957Salfred 1134195957Salfred if (max_bulk != 0) { 1135195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1136195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1137195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1138195957Salfred } else { 1139195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1140195957Salfred } 1141195957Salfred 1142195957Salfred /* update counters */ 1143195957Salfred sxfer->last_len = max_bulk; 1144195957Salfred sxfer->curr_data += max_bulk; 1145195957Salfred sxfer->rem_len -= max_bulk; 1146195957Salfred 1147195957Salfred libusb20_tr_submit(pxfer); 1148195957Salfred 1149195957Salfred /* check if we can fork another USB transfer */ 1150195957Salfred if (sxfer->rem_len == 0) 1151195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1152195957Salfred break; 1153195957Salfred 1154195957Salfred default: 1155195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1156195957Salfred break; 1157194676Sthompsa } 1158195957Salfred} 1159195957Salfred 1160195957Salfred/* The following function must be called locked */ 1161195957Salfred 1162195957Salfredstatic void 1163195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1164195957Salfred{ 1165195957Salfred struct libusb20_transfer *pxfer0; 1166195957Salfred struct libusb20_transfer *pxfer1; 1167195957Salfred struct libusb_super_transfer *sxfer; 1168195957Salfred struct libusb_transfer *uxfer; 1169195957Salfred struct libusb_device *dev; 1170195957Salfred int err; 1171195957Salfred int buffsize; 1172195957Salfred int maxframe; 1173195957Salfred int temp; 1174195957Salfred uint8_t dummy; 1175195957Salfred 1176195957Salfred dev = libusb_get_device(pdev); 1177195957Salfred 1178195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1179195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1180195957Salfred 1181195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1182195957Salfred return; /* shouldn't happen */ 1183195957Salfred 1184195957Salfred temp = 0; 1185195957Salfred if (libusb20_tr_pending(pxfer0)) 1186195957Salfred temp |= 1; 1187195957Salfred if (libusb20_tr_pending(pxfer1)) 1188195957Salfred temp |= 2; 1189195957Salfred 1190195957Salfred switch (temp) { 1191195957Salfred case 3: 1192195957Salfred /* wait till one of the transfers complete */ 1193195957Salfred return; 1194195957Salfred case 2: 1195195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1196199575Sthompsa if (sxfer == NULL) 1197199575Sthompsa return; /* cancelling */ 1198195957Salfred if (sxfer->rem_len) 1199195957Salfred return; /* cannot queue another one */ 1200195957Salfred /* swap transfers */ 1201195957Salfred pxfer1 = pxfer0; 1202195957Salfred break; 1203195957Salfred case 1: 1204195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1205199575Sthompsa if (sxfer == NULL) 1206199575Sthompsa return; /* cancelling */ 1207195957Salfred if (sxfer->rem_len) 1208195957Salfred return; /* cannot queue another one */ 1209195957Salfred /* swap transfers */ 1210195957Salfred pxfer0 = pxfer1; 1211195957Salfred break; 1212195957Salfred default: 1213195957Salfred break; 1214194676Sthompsa } 1215195957Salfred 1216195957Salfred /* find next transfer on same endpoint */ 1217195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1218195957Salfred 1219195957Salfred uxfer = (struct libusb_transfer *)( 1220195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1221195957Salfred 1222195957Salfred if (uxfer->endpoint == endpoint) { 1223195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1224195957Salfred sxfer->entry.tqe_prev = NULL; 1225195957Salfred goto found; 1226194676Sthompsa } 1227195957Salfred } 1228195957Salfred return; /* success */ 1229194676Sthompsa 1230195957Salfredfound: 1231194676Sthompsa 1232195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1233195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1234194676Sthompsa 1235195957Salfred /* reset super transfer state */ 1236195957Salfred sxfer->rem_len = uxfer->length; 1237195957Salfred sxfer->curr_data = uxfer->buffer; 1238195957Salfred uxfer->actual_length = 0; 1239194676Sthompsa 1240195957Salfred switch (uxfer->type) { 1241195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1242195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1243195957Salfred break; 1244195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1245195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1246195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1247195957Salfred break; 1248195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1249195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1250195957Salfred if (sxfer->rem_len < 8) 1251195957Salfred goto failure; 1252194676Sthompsa 1253195957Salfred /* remove SETUP packet from data */ 1254195957Salfred sxfer->rem_len -= 8; 1255195957Salfred sxfer->curr_data += 8; 1256195957Salfred break; 1257195957Salfred default: 1258195957Salfred goto failure; 1259195560Sthompsa } 1260195957Salfred 1261195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1262195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1263195957Salfred 1264195957Salfred /* make sure the transfer is opened */ 1265195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1266195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1267195957Salfred goto failure; 1268194676Sthompsa } 1269195957Salfred libusb20_tr_start(pxfer0); 1270195957Salfred return; 1271194676Sthompsa 1272195957Salfredfailure: 1273195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1274194676Sthompsa 1275195957Salfred /* make sure our event loop spins the done handler */ 1276195957Salfred dummy = 0; 1277195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1278195957Salfred} 1279194676Sthompsa 1280195957Salfred/* The following function must be called unlocked */ 1281194676Sthompsa 1282195957Salfredint 1283195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1284195957Salfred{ 1285195957Salfred struct libusb20_transfer *pxfer0; 1286195957Salfred struct libusb20_transfer *pxfer1; 1287195957Salfred struct libusb_super_transfer *sxfer; 1288195957Salfred struct libusb_device *dev; 1289199055Sthompsa uint32_t endpoint; 1290195957Salfred int err; 1291195957Salfred 1292195957Salfred if (uxfer == NULL) 1293195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1294195957Salfred 1295195957Salfred if (uxfer->dev_handle == NULL) 1296195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1297195957Salfred 1298195957Salfred endpoint = uxfer->endpoint; 1299195957Salfred 1300195957Salfred if (endpoint > 255) 1301195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1302195957Salfred 1303195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1304195957Salfred 1305195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1306195957Salfred 1307195957Salfred sxfer = (struct libusb_super_transfer *)( 1308195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1309195957Salfred 1310195957Salfred CTX_LOCK(dev->ctx); 1311195957Salfred 1312195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1313195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1314195957Salfred 1315195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1316195957Salfred err = LIBUSB_ERROR_OTHER; 1317195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1318199575Sthompsa (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1319195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1320195957Salfred err = LIBUSB_ERROR_BUSY; 1321195957Salfred } else { 1322199575Sthompsa 1323199575Sthompsa /* set pending state */ 1324199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 1325199575Sthompsa 1326199575Sthompsa /* insert transfer into transfer head list */ 1327195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1328195957Salfred 1329199575Sthompsa /* start work transfers */ 1330195957Salfred libusb10_submit_transfer_sub( 1331195957Salfred uxfer->dev_handle, endpoint); 1332195957Salfred 1333195957Salfred err = 0; /* success */ 1334195957Salfred } 1335195957Salfred 1336195957Salfred CTX_UNLOCK(dev->ctx); 1337195957Salfred 1338195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1339195957Salfred 1340195957Salfred return (err); 1341194676Sthompsa} 1342194676Sthompsa 1343195957Salfred/* Asynchronous transfer cancel */ 1344195957Salfred 1345194676Sthompsaint 1346195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1347194676Sthompsa{ 1348195957Salfred struct libusb20_transfer *pxfer0; 1349195957Salfred struct libusb20_transfer *pxfer1; 1350195957Salfred struct libusb_super_transfer *sxfer; 1351195957Salfred struct libusb_device *dev; 1352199055Sthompsa uint32_t endpoint; 1353199575Sthompsa int retval; 1354194676Sthompsa 1355195957Salfred if (uxfer == NULL) 1356195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1357194676Sthompsa 1358199575Sthompsa /* check if not initialised */ 1359195957Salfred if (uxfer->dev_handle == NULL) 1360199575Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 1361194676Sthompsa 1362195957Salfred endpoint = uxfer->endpoint; 1363194676Sthompsa 1364195957Salfred if (endpoint > 255) 1365195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1366195957Salfred 1367195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1368195957Salfred 1369195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1370195957Salfred 1371195957Salfred sxfer = (struct libusb_super_transfer *)( 1372195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1373195957Salfred 1374199575Sthompsa retval = 0; 1375199575Sthompsa 1376195957Salfred CTX_LOCK(dev->ctx); 1377195957Salfred 1378195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1379195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1380195957Salfred 1381199575Sthompsa if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 1382199575Sthompsa /* only update the transfer status */ 1383199575Sthompsa uxfer->status = LIBUSB_TRANSFER_CANCELLED; 1384199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1385199575Sthompsa } else if (sxfer->entry.tqe_prev != NULL) { 1386195957Salfred /* we are lucky - transfer is on a queue */ 1387195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1388195957Salfred sxfer->entry.tqe_prev = NULL; 1389199575Sthompsa libusb10_complete_transfer(NULL, 1390199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1391195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1392195957Salfred /* not started */ 1393199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1394195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1395199575Sthompsa libusb10_complete_transfer(pxfer0, 1396199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1397195957Salfred libusb20_tr_stop(pxfer0); 1398195957Salfred /* make sure the queue doesn't stall */ 1399195957Salfred libusb10_submit_transfer_sub( 1400195957Salfred uxfer->dev_handle, endpoint); 1401195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1402199575Sthompsa libusb10_complete_transfer(pxfer1, 1403199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1404195957Salfred libusb20_tr_stop(pxfer1); 1405195957Salfred /* make sure the queue doesn't stall */ 1406195957Salfred libusb10_submit_transfer_sub( 1407195957Salfred uxfer->dev_handle, endpoint); 1408195957Salfred } else { 1409195957Salfred /* not started */ 1410199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1411195957Salfred } 1412195957Salfred 1413195957Salfred CTX_UNLOCK(dev->ctx); 1414195957Salfred 1415195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1416195957Salfred 1417199575Sthompsa return (retval); 1418194676Sthompsa} 1419194676Sthompsa 1420195957SalfredUNEXPORTED void 1421195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1422195957Salfred{ 1423195957Salfred /* TODO */ 1424195957Salfred} 1425199055Sthompsa 1426199055Sthompsauint16_t 1427199055Sthompsalibusb_cpu_to_le16(uint16_t x) 1428199055Sthompsa{ 1429199055Sthompsa return (htole16(x)); 1430199055Sthompsa} 1431199055Sthompsa 1432199055Sthompsauint16_t 1433199055Sthompsalibusb_le16_to_cpu(uint16_t x) 1434199055Sthompsa{ 1435199055Sthompsa return (le16toh(x)); 1436199055Sthompsa} 1437199055Sthompsa 1438213853Shselaskyconst char * 1439213853Shselaskylibusb_strerror(int code) 1440213853Shselasky{ 1441213853Shselasky /* TODO */ 1442213853Shselasky return ("Unknown error"); 1443213853Shselasky} 1444