libusb10.c revision 213848
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 213848 2010-10-14 20:04:36Z 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 73194676Sthompsaint 74195957Salfredlibusb_init(libusb_context **context) 75194676Sthompsa{ 76194676Sthompsa struct libusb_context *ctx; 77195957Salfred char *debug; 78203774Swkoszek int flag; 79194676Sthompsa int ret; 80194676Sthompsa 81194676Sthompsa ctx = malloc(sizeof(*ctx)); 82194676Sthompsa if (!ctx) 83194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 84194676Sthompsa 85194676Sthompsa memset(ctx, 0, sizeof(*ctx)); 86194676Sthompsa 87194676Sthompsa debug = getenv("LIBUSB_DEBUG"); 88194676Sthompsa if (debug != NULL) { 89194676Sthompsa ctx->debug = atoi(debug); 90194676Sthompsa if (ctx->debug != 0) 91194676Sthompsa ctx->debug_fixed = 1; 92194676Sthompsa } 93195957Salfred TAILQ_INIT(&ctx->pollfds); 94195957Salfred TAILQ_INIT(&ctx->tr_done); 95194676Sthompsa 96195957Salfred pthread_mutex_init(&ctx->ctx_lock, NULL); 97195957Salfred pthread_cond_init(&ctx->ctx_cond, NULL); 98194676Sthompsa 99195957Salfred ctx->ctx_handler = NO_THREAD; 100194676Sthompsa 101194676Sthompsa ret = pipe(ctx->ctrl_pipe); 102194676Sthompsa if (ret < 0) { 103195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 104195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 105194676Sthompsa free(ctx); 106194676Sthompsa return (LIBUSB_ERROR_OTHER); 107194676Sthompsa } 108195957Salfred /* set non-blocking mode on the control pipe to avoid deadlock */ 109203774Swkoszek flag = 1; 110203774Swkoszek ret = fcntl(ctx->ctrl_pipe[0], O_NONBLOCK, &flag); 111203774Swkoszek assert(ret != -1 && "Couldn't set O_NONBLOCK for ctx->ctrl_pipe[0]"); 112203774Swkoszek flag = 1; 113203774Swkoszek ret = fcntl(ctx->ctrl_pipe[1], O_NONBLOCK, &flag); 114203774Swkoszek assert(ret != -1 && "Couldn't set O_NONBLOCK for ctx->ctrl_pipe[1]"); 115194676Sthompsa 116195957Salfred libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN); 117194676Sthompsa 118194676Sthompsa pthread_mutex_lock(&default_context_lock); 119194676Sthompsa if (usbi_default_context == NULL) { 120194676Sthompsa usbi_default_context = ctx; 121194676Sthompsa } 122194676Sthompsa pthread_mutex_unlock(&default_context_lock); 123194676Sthompsa 124194676Sthompsa if (context) 125194676Sthompsa *context = ctx; 126194676Sthompsa 127195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete"); 128195957Salfred 129194676Sthompsa return (0); 130194676Sthompsa} 131194676Sthompsa 132194676Sthompsavoid 133195957Salfredlibusb_exit(libusb_context *ctx) 134194676Sthompsa{ 135195957Salfred ctx = GET_CONTEXT(ctx); 136194676Sthompsa 137195957Salfred if (ctx == NULL) 138195957Salfred return; 139195957Salfred 140195957Salfred /* XXX cleanup devices */ 141195957Salfred 142195957Salfred libusb10_remove_pollfd(ctx, &ctx->ctx_poll); 143194676Sthompsa close(ctx->ctrl_pipe[0]); 144194676Sthompsa close(ctx->ctrl_pipe[1]); 145195957Salfred pthread_mutex_destroy(&ctx->ctx_lock); 146195957Salfred pthread_cond_destroy(&ctx->ctx_cond); 147194676Sthompsa 148194676Sthompsa pthread_mutex_lock(&default_context_lock); 149194676Sthompsa if (ctx == usbi_default_context) { 150194676Sthompsa usbi_default_context = NULL; 151194676Sthompsa } 152194676Sthompsa pthread_mutex_unlock(&default_context_lock); 153194676Sthompsa 154194676Sthompsa free(ctx); 155194676Sthompsa} 156194676Sthompsa 157194676Sthompsa/* Device handling and initialisation. */ 158194676Sthompsa 159194676Sthompsassize_t 160195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list) 161194676Sthompsa{ 162195957Salfred struct libusb20_backend *usb_backend; 163194676Sthompsa struct libusb20_device *pdev; 164194676Sthompsa struct libusb_device *dev; 165194676Sthompsa int i; 166194676Sthompsa 167195957Salfred ctx = GET_CONTEXT(ctx); 168194676Sthompsa 169195957Salfred if (ctx == NULL) 170195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 171195957Salfred 172195957Salfred if (list == NULL) 173195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 174195957Salfred 175194676Sthompsa usb_backend = libusb20_be_alloc_default(); 176194676Sthompsa if (usb_backend == NULL) 177195957Salfred return (LIBUSB_ERROR_NO_MEM); 178194676Sthompsa 179195957Salfred /* figure out how many USB devices are present */ 180194676Sthompsa pdev = NULL; 181194676Sthompsa i = 0; 182194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, pdev))) 183194676Sthompsa i++; 184194676Sthompsa 185195957Salfred /* allocate device pointer list */ 186194676Sthompsa *list = malloc((i + 1) * sizeof(void *)); 187194676Sthompsa if (*list == NULL) { 188194676Sthompsa libusb20_be_free(usb_backend); 189194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 190194676Sthompsa } 191195957Salfred /* create libusb v1.0 compliant devices */ 192194676Sthompsa i = 0; 193194676Sthompsa while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) { 194194676Sthompsa 195194676Sthompsa dev = malloc(sizeof(*dev)); 196194676Sthompsa if (dev == NULL) { 197195560Sthompsa while (i != 0) { 198195560Sthompsa libusb_unref_device((*list)[i - 1]); 199195560Sthompsa i--; 200195560Sthompsa } 201194676Sthompsa free(*list); 202195957Salfred *list = NULL; 203194676Sthompsa libusb20_be_free(usb_backend); 204194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 205194676Sthompsa } 206199055Sthompsa 207199055Sthompsa /* get device into libUSB v1.0 list */ 208199055Sthompsa libusb20_be_dequeue_device(usb_backend, pdev); 209199055Sthompsa 210194676Sthompsa memset(dev, 0, sizeof(*dev)); 211194676Sthompsa 212195957Salfred /* init transfer queues */ 213195957Salfred TAILQ_INIT(&dev->tr_head); 214195957Salfred 215195957Salfred /* set context we belong to */ 216194676Sthompsa dev->ctx = ctx; 217194676Sthompsa 218194676Sthompsa /* link together the two structures */ 219194676Sthompsa dev->os_priv = pdev; 220195957Salfred pdev->privLuData = dev; 221194676Sthompsa 222194676Sthompsa (*list)[i] = libusb_ref_device(dev); 223194676Sthompsa i++; 224194676Sthompsa } 225194676Sthompsa (*list)[i] = NULL; 226194676Sthompsa 227194676Sthompsa libusb20_be_free(usb_backend); 228194676Sthompsa return (i); 229194676Sthompsa} 230194676Sthompsa 231194676Sthompsavoid 232194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices) 233194676Sthompsa{ 234194676Sthompsa int i; 235194676Sthompsa 236194676Sthompsa if (list == NULL) 237195957Salfred return; /* be NULL safe */ 238194676Sthompsa 239194676Sthompsa if (unref_devices) { 240194676Sthompsa for (i = 0; list[i] != NULL; i++) 241194676Sthompsa libusb_unref_device(list[i]); 242194676Sthompsa } 243194676Sthompsa free(list); 244194676Sthompsa} 245194676Sthompsa 246194676Sthompsauint8_t 247195957Salfredlibusb_get_bus_number(libusb_device *dev) 248194676Sthompsa{ 249194676Sthompsa if (dev == NULL) 250195957Salfred return (0); /* should not happen */ 251195957Salfred return (libusb20_dev_get_bus_number(dev->os_priv)); 252194676Sthompsa} 253194676Sthompsa 254194676Sthompsauint8_t 255195957Salfredlibusb_get_device_address(libusb_device *dev) 256194676Sthompsa{ 257194676Sthompsa if (dev == NULL) 258195957Salfred return (0); /* should not happen */ 259195957Salfred return (libusb20_dev_get_address(dev->os_priv)); 260194676Sthompsa} 261194676Sthompsa 262194676Sthompsaint 263195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint) 264194676Sthompsa{ 265194676Sthompsa struct libusb_config_descriptor *pdconf; 266194676Sthompsa struct libusb_interface *pinf; 267194676Sthompsa struct libusb_interface_descriptor *pdinf; 268194676Sthompsa struct libusb_endpoint_descriptor *pdend; 269195957Salfred int i; 270195957Salfred int j; 271195957Salfred int k; 272195957Salfred int ret; 273194676Sthompsa 274194676Sthompsa if (dev == NULL) 275194676Sthompsa return (LIBUSB_ERROR_NO_DEVICE); 276194676Sthompsa 277195957Salfred ret = libusb_get_active_config_descriptor(dev, &pdconf); 278195957Salfred if (ret < 0) 279195957Salfred return (ret); 280195957Salfred 281194676Sthompsa ret = LIBUSB_ERROR_NOT_FOUND; 282195957Salfred for (i = 0; i < pdconf->bNumInterfaces; i++) { 283194676Sthompsa pinf = &pdconf->interface[i]; 284195957Salfred for (j = 0; j < pinf->num_altsetting; j++) { 285194676Sthompsa pdinf = &pinf->altsetting[j]; 286195957Salfred for (k = 0; k < pdinf->bNumEndpoints; k++) { 287194676Sthompsa pdend = &pdinf->endpoint[k]; 288194676Sthompsa if (pdend->bEndpointAddress == endpoint) { 289194676Sthompsa ret = pdend->wMaxPacketSize; 290194676Sthompsa goto out; 291194676Sthompsa } 292194676Sthompsa } 293194676Sthompsa } 294194676Sthompsa } 295194676Sthompsa 296194676Sthompsaout: 297194676Sthompsa libusb_free_config_descriptor(pdconf); 298194676Sthompsa return (ret); 299194676Sthompsa} 300194676Sthompsa 301194676Sthompsalibusb_device * 302195957Salfredlibusb_ref_device(libusb_device *dev) 303194676Sthompsa{ 304194676Sthompsa if (dev == NULL) 305195957Salfred return (NULL); /* be NULL safe */ 306194676Sthompsa 307195957Salfred CTX_LOCK(dev->ctx); 308194676Sthompsa dev->refcnt++; 309195957Salfred CTX_UNLOCK(dev->ctx); 310194676Sthompsa 311194676Sthompsa return (dev); 312194676Sthompsa} 313194676Sthompsa 314194676Sthompsavoid 315195957Salfredlibusb_unref_device(libusb_device *dev) 316194676Sthompsa{ 317194676Sthompsa if (dev == NULL) 318195957Salfred return; /* be NULL safe */ 319194676Sthompsa 320195957Salfred CTX_LOCK(dev->ctx); 321194676Sthompsa dev->refcnt--; 322195957Salfred CTX_UNLOCK(dev->ctx); 323194676Sthompsa 324194676Sthompsa if (dev->refcnt == 0) { 325194676Sthompsa libusb20_dev_free(dev->os_priv); 326194676Sthompsa free(dev); 327194676Sthompsa } 328194676Sthompsa} 329194676Sthompsa 330194676Sthompsaint 331195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh) 332194676Sthompsa{ 333194676Sthompsa libusb_context *ctx = dev->ctx; 334194676Sthompsa struct libusb20_device *pdev = dev->os_priv; 335195957Salfred uint8_t dummy; 336194676Sthompsa int err; 337194676Sthompsa 338194676Sthompsa if (devh == NULL) 339194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 340194676Sthompsa 341195957Salfred /* set default device handle value */ 342195957Salfred *devh = NULL; 343194676Sthompsa 344195957Salfred dev = libusb_ref_device(dev); 345195957Salfred if (dev == NULL) 346195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 347195957Salfred 348194676Sthompsa err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ ); 349194676Sthompsa if (err) { 350195957Salfred libusb_unref_device(dev); 351194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 352194676Sthompsa } 353195957Salfred libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 354194676Sthompsa POLLOUT | POLLRDNORM | POLLWRNORM); 355194676Sthompsa 356195957Salfred /* make sure our event loop detects the new device */ 357195957Salfred dummy = 0; 358194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 359195957Salfred if (err < sizeof(dummy)) { 360195957Salfred /* ignore error, if any */ 361195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!"); 362194676Sthompsa } 363195957Salfred *devh = pdev; 364194676Sthompsa 365194676Sthompsa return (0); 366194676Sthompsa} 367194676Sthompsa 368194676Sthompsalibusb_device_handle * 369195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, 370194676Sthompsa uint16_t product_id) 371194676Sthompsa{ 372194676Sthompsa struct libusb_device **devs; 373194676Sthompsa struct libusb20_device *pdev; 374194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 375195957Salfred int i; 376195957Salfred int j; 377194676Sthompsa 378195957Salfred ctx = GET_CONTEXT(ctx); 379195957Salfred if (ctx == NULL) 380195957Salfred return (NULL); /* be NULL safe */ 381195957Salfred 382195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter"); 383194676Sthompsa 384194676Sthompsa if ((i = libusb_get_device_list(ctx, &devs)) < 0) 385194676Sthompsa return (NULL); 386194676Sthompsa 387194676Sthompsa for (j = 0; j < i; j++) { 388195957Salfred pdev = devs[j]->os_priv; 389194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 390195957Salfred /* 391195957Salfred * NOTE: The USB library will automatically swap the 392195957Salfred * fields in the device descriptor to be of host 393195957Salfred * endian type! 394195957Salfred */ 395194676Sthompsa if (pdesc->idVendor == vendor_id && 396195560Sthompsa pdesc->idProduct == product_id) { 397195957Salfred if (libusb_open(devs[j], &pdev) < 0) 398195957Salfred pdev = NULL; 399195957Salfred break; 400195560Sthompsa } 401194676Sthompsa } 402200424Sscf if (j == i) 403200424Sscf pdev = NULL; 404194676Sthompsa 405194676Sthompsa libusb_free_device_list(devs, 1); 406195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave"); 407195957Salfred return (pdev); 408194676Sthompsa} 409194676Sthompsa 410194676Sthompsavoid 411195957Salfredlibusb_close(struct libusb20_device *pdev) 412194676Sthompsa{ 413194676Sthompsa libusb_context *ctx; 414195957Salfred struct libusb_device *dev; 415195957Salfred uint8_t dummy; 416194676Sthompsa int err; 417194676Sthompsa 418195957Salfred if (pdev == NULL) 419195957Salfred return; /* be NULL safe */ 420194676Sthompsa 421195957Salfred dev = libusb_get_device(pdev); 422195957Salfred ctx = dev->ctx; 423194676Sthompsa 424195957Salfred libusb10_remove_pollfd(ctx, &dev->dev_poll); 425194676Sthompsa 426195957Salfred libusb20_dev_close(pdev); 427199055Sthompsa 428199055Sthompsa /* unref will free the "pdev" when the refcount reaches zero */ 429195957Salfred libusb_unref_device(dev); 430194676Sthompsa 431195957Salfred /* make sure our event loop detects the closed device */ 432195957Salfred dummy = 0; 433194676Sthompsa err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 434195957Salfred if (err < sizeof(dummy)) { 435195957Salfred /* ignore error, if any */ 436195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!"); 437194676Sthompsa } 438194676Sthompsa} 439194676Sthompsa 440194676Sthompsalibusb_device * 441195957Salfredlibusb_get_device(struct libusb20_device *pdev) 442194676Sthompsa{ 443195957Salfred if (pdev == NULL) 444194676Sthompsa return (NULL); 445195957Salfred return ((libusb_device *)pdev->privLuData); 446194676Sthompsa} 447194676Sthompsa 448194676Sthompsaint 449195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config) 450194676Sthompsa{ 451195957Salfred struct libusb20_config *pconf; 452194676Sthompsa 453195957Salfred if (pdev == NULL || config == NULL) 454194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 455194676Sthompsa 456195957Salfred pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev)); 457195957Salfred if (pconf == NULL) 458195957Salfred return (LIBUSB_ERROR_NO_MEM); 459194676Sthompsa 460195957Salfred *config = pconf->desc.bConfigurationValue; 461195957Salfred 462195957Salfred free(pconf); 463195957Salfred 464194676Sthompsa return (0); 465194676Sthompsa} 466194676Sthompsa 467194676Sthompsaint 468195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration) 469194676Sthompsa{ 470195957Salfred struct libusb20_config *pconf; 471195957Salfred struct libusb_device *dev; 472195957Salfred int err; 473195957Salfred uint8_t i; 474194676Sthompsa 475195957Salfred dev = libusb_get_device(pdev); 476194676Sthompsa 477195957Salfred if (dev == NULL) 478194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 479194676Sthompsa 480195957Salfred if (configuration < 1) { 481195957Salfred /* unconfigure */ 482195957Salfred i = 255; 483195957Salfred } else { 484195957Salfred for (i = 0; i != 255; i++) { 485195957Salfred uint8_t found; 486194676Sthompsa 487195957Salfred pconf = libusb20_dev_alloc_config(pdev, i); 488195957Salfred if (pconf == NULL) 489195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 490195957Salfred found = (pconf->desc.bConfigurationValue 491195957Salfred == configuration); 492195957Salfred free(pconf); 493195957Salfred 494195957Salfred if (found) 495195957Salfred goto set_config; 496195957Salfred } 497195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 498195957Salfred } 499195957Salfred 500195957Salfredset_config: 501195957Salfred 502195957Salfred libusb10_cancel_all_transfer(dev); 503195957Salfred 504195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 505195957Salfred 506195957Salfred err = libusb20_dev_set_config_index(pdev, i); 507195957Salfred 508195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN | 509195957Salfred POLLOUT | POLLRDNORM | POLLWRNORM); 510195957Salfred 511195957Salfred return (err ? LIBUSB_ERROR_INVALID_PARAM : 0); 512194676Sthompsa} 513194676Sthompsa 514194676Sthompsaint 515195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number) 516194676Sthompsa{ 517195957Salfred libusb_device *dev; 518195957Salfred int err = 0; 519194676Sthompsa 520195957Salfred dev = libusb_get_device(pdev); 521194676Sthompsa if (dev == NULL) 522194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 523194676Sthompsa 524195957Salfred if (interface_number < 0 || interface_number > 31) 525194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 526194676Sthompsa 527195957Salfred CTX_LOCK(dev->ctx); 528194676Sthompsa if (dev->claimed_interfaces & (1 << interface_number)) 529195957Salfred err = LIBUSB_ERROR_BUSY; 530194676Sthompsa 531195957Salfred if (!err) 532194676Sthompsa dev->claimed_interfaces |= (1 << interface_number); 533195957Salfred CTX_UNLOCK(dev->ctx); 534195957Salfred return (err); 535194676Sthompsa} 536194676Sthompsa 537194676Sthompsaint 538195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number) 539194676Sthompsa{ 540195957Salfred libusb_device *dev; 541195957Salfred int err = 0; 542194676Sthompsa 543195957Salfred dev = libusb_get_device(pdev); 544194676Sthompsa if (dev == NULL) 545194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 546194676Sthompsa 547195957Salfred if (interface_number < 0 || interface_number > 31) 548194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 549194676Sthompsa 550195957Salfred CTX_LOCK(dev->ctx); 551194676Sthompsa if (!(dev->claimed_interfaces & (1 << interface_number))) 552195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 553194676Sthompsa 554195957Salfred if (!err) 555194676Sthompsa dev->claimed_interfaces &= ~(1 << interface_number); 556195957Salfred CTX_UNLOCK(dev->ctx); 557195957Salfred return (err); 558194676Sthompsa} 559194676Sthompsa 560194676Sthompsaint 561195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev, 562194676Sthompsa int interface_number, int alternate_setting) 563194676Sthompsa{ 564195957Salfred libusb_device *dev; 565195957Salfred int err = 0; 566194676Sthompsa 567195957Salfred dev = libusb_get_device(pdev); 568194676Sthompsa if (dev == NULL) 569194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 570194676Sthompsa 571195957Salfred if (interface_number < 0 || interface_number > 31) 572194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 573194676Sthompsa 574195957Salfred CTX_LOCK(dev->ctx); 575195957Salfred if (!(dev->claimed_interfaces & (1 << interface_number))) 576195957Salfred err = LIBUSB_ERROR_NOT_FOUND; 577195957Salfred CTX_UNLOCK(dev->ctx); 578194676Sthompsa 579195957Salfred if (err) 580195957Salfred return (err); 581195957Salfred 582195957Salfred libusb10_cancel_all_transfer(dev); 583195957Salfred 584195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 585195957Salfred 586195957Salfred err = libusb20_dev_set_alt_index(pdev, 587195957Salfred interface_number, alternate_setting); 588195957Salfred 589195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 590195957Salfred pdev, libusb20_dev_get_fd(pdev), 591195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 592195957Salfred 593195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 594194676Sthompsa} 595194676Sthompsa 596195957Salfredstatic struct libusb20_transfer * 597195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev, 598195957Salfred uint8_t endpoint, uint8_t index) 599195957Salfred{ 600195957Salfred index &= 1; /* double buffering */ 601195957Salfred 602195957Salfred index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4; 603195957Salfred 604195957Salfred if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) { 605195957Salfred /* this is an IN endpoint */ 606195957Salfred index |= 2; 607195957Salfred } 608195957Salfred return (libusb20_tr_get_pointer(pdev, index)); 609195957Salfred} 610195957Salfred 611194676Sthompsaint 612195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) 613194676Sthompsa{ 614194676Sthompsa struct libusb20_transfer *xfer; 615195957Salfred struct libusb_device *dev; 616195957Salfred int err; 617194676Sthompsa 618195957Salfred xfer = libusb10_get_transfer(pdev, endpoint, 0); 619195560Sthompsa if (xfer == NULL) 620195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 621194676Sthompsa 622195957Salfred dev = libusb_get_device(pdev); 623195957Salfred 624195957Salfred CTX_LOCK(dev->ctx); 625195957Salfred err = libusb20_tr_open(xfer, 0, 0, endpoint); 626195957Salfred CTX_UNLOCK(dev->ctx); 627195957Salfred 628195957Salfred if (err != 0 && err != LIBUSB20_ERROR_BUSY) 629194676Sthompsa return (LIBUSB_ERROR_OTHER); 630194676Sthompsa 631194676Sthompsa libusb20_tr_clear_stall_sync(xfer); 632195957Salfred 633195957Salfred /* check if we opened the transfer */ 634195957Salfred if (err == 0) { 635195957Salfred CTX_LOCK(dev->ctx); 636194676Sthompsa libusb20_tr_close(xfer); 637195957Salfred CTX_UNLOCK(dev->ctx); 638195957Salfred } 639195957Salfred return (0); /* success */ 640194676Sthompsa} 641194676Sthompsa 642194676Sthompsaint 643195957Salfredlibusb_reset_device(struct libusb20_device *pdev) 644194676Sthompsa{ 645195957Salfred libusb_device *dev; 646195957Salfred int err; 647194676Sthompsa 648195957Salfred dev = libusb_get_device(pdev); 649194676Sthompsa if (dev == NULL) 650194676Sthompsa return (LIBUSB20_ERROR_INVALID_PARAM); 651194676Sthompsa 652195957Salfred libusb10_cancel_all_transfer(dev); 653195957Salfred 654195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 655195957Salfred 656195957Salfred err = libusb20_dev_reset(pdev); 657195957Salfred 658195957Salfred libusb10_add_pollfd(dev->ctx, &dev->dev_poll, 659195957Salfred pdev, libusb20_dev_get_fd(pdev), 660195957Salfred POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); 661195957Salfred 662195957Salfred return (err ? LIBUSB_ERROR_OTHER : 0); 663194676Sthompsa} 664194676Sthompsa 665194676Sthompsaint 666213848Shselaskylibusb_check_connected(struct libusb20_device *pdev) 667213848Shselasky{ 668213848Shselasky libusb_device *dev; 669213848Shselasky int err; 670213848Shselasky 671213848Shselasky dev = libusb_get_device(pdev); 672213848Shselasky if (dev == NULL) 673213848Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 674213848Shselasky 675213848Shselasky err = libusb20_dev_check_connected(pdev); 676213848Shselasky 677213848Shselasky return (err ? LIBUSB_ERROR_NO_DEVICE : 0); 678213848Shselasky} 679213848Shselasky 680213848Shselaskyint 681195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 682194676Sthompsa{ 683195957Salfred if (pdev == NULL) 684194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 685194676Sthompsa 686195957Salfred return (libusb20_dev_kernel_driver_active( 687195957Salfred pdev, interface)); 688194676Sthompsa} 689194676Sthompsa 690194676Sthompsaint 691195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 692194676Sthompsa{ 693195957Salfred int err; 694194676Sthompsa 695195957Salfred if (pdev == NULL) 696194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 697194676Sthompsa 698195957Salfred err = libusb20_dev_detach_kernel_driver( 699195957Salfred pdev, interface); 700194676Sthompsa 701195957Salfred return (err ? LIBUSB20_ERROR_OTHER : 0); 702194676Sthompsa} 703194676Sthompsa 704194676Sthompsaint 705195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 706194676Sthompsa{ 707195957Salfred if (pdev == NULL) 708194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 709195957Salfred /* stub - currently not supported by libusb20 */ 710194676Sthompsa return (0); 711194676Sthompsa} 712194676Sthompsa 713194676Sthompsa/* Asynchronous device I/O */ 714194676Sthompsa 715194676Sthompsastruct libusb_transfer * 716194676Sthompsalibusb_alloc_transfer(int iso_packets) 717194676Sthompsa{ 718195957Salfred struct libusb_transfer *uxfer; 719195957Salfred struct libusb_super_transfer *sxfer; 720194676Sthompsa int len; 721194676Sthompsa 722194676Sthompsa len = sizeof(struct libusb_transfer) + 723195957Salfred sizeof(struct libusb_super_transfer) + 724194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 725194676Sthompsa 726195957Salfred sxfer = malloc(len); 727195957Salfred if (sxfer == NULL) 728194676Sthompsa return (NULL); 729194676Sthompsa 730195957Salfred memset(sxfer, 0, len); 731194676Sthompsa 732195957Salfred uxfer = (struct libusb_transfer *)( 733195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 734194676Sthompsa 735195957Salfred /* set default value */ 736195957Salfred uxfer->num_iso_packets = iso_packets; 737195957Salfred 738195957Salfred return (uxfer); 739194676Sthompsa} 740194676Sthompsa 741194676Sthompsavoid 742195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 743194676Sthompsa{ 744195957Salfred struct libusb_super_transfer *sxfer; 745194676Sthompsa 746195957Salfred if (uxfer == NULL) 747195957Salfred return; /* be NULL safe */ 748194676Sthompsa 749195957Salfred sxfer = (struct libusb_super_transfer *)( 750195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 751194676Sthompsa 752195957Salfred free(sxfer); 753194676Sthompsa} 754194676Sthompsa 755195560Sthompsastatic int 756195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 757195560Sthompsa{ 758195560Sthompsa int ret; 759195560Sthompsa int usb_speed; 760195560Sthompsa 761195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 762195560Sthompsa 763195560Sthompsa switch (xfer->type) { 764195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 765195560Sthompsa switch (usb_speed) { 766195560Sthompsa case LIBUSB20_SPEED_LOW: 767195560Sthompsa case LIBUSB20_SPEED_FULL: 768195560Sthompsa ret = 60 * 1; 769195957Salfred break; 770195957Salfred default: 771195560Sthompsa ret = 60 * 8; 772195957Salfred break; 773195560Sthompsa } 774195957Salfred break; 775195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 776195560Sthompsa ret = 2; 777195957Salfred break; 778195560Sthompsa default: 779195560Sthompsa ret = 1; 780195957Salfred break; 781195560Sthompsa } 782195957Salfred return (ret); 783195560Sthompsa} 784195560Sthompsa 785195560Sthompsastatic int 786195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 787195560Sthompsa{ 788195560Sthompsa int ret; 789195560Sthompsa int usb_speed; 790195560Sthompsa 791195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 792195560Sthompsa 793195560Sthompsa switch (xfer->type) { 794195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 795195957Salfred ret = 0; /* kernel will auto-select */ 796195957Salfred break; 797195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 798195957Salfred ret = 1024; 799195957Salfred break; 800195957Salfred default: 801195560Sthompsa switch (usb_speed) { 802195957Salfred case LIBUSB20_SPEED_LOW: 803195957Salfred ret = 256; 804195957Salfred break; 805195957Salfred case LIBUSB20_SPEED_FULL: 806195957Salfred ret = 4096; 807195957Salfred break; 808195957Salfred default: 809195957Salfred ret = 16384; 810195957Salfred break; 811195560Sthompsa } 812195957Salfred break; 813195560Sthompsa } 814195957Salfred return (ret); 815195560Sthompsa} 816195560Sthompsa 817195957Salfredstatic int 818195957Salfredlibusb10_convert_error(uint8_t status) 819195957Salfred{ 820195957Salfred ; /* indent fix */ 821195957Salfred 822195957Salfred switch (status) { 823195957Salfred case LIBUSB20_TRANSFER_START: 824195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 825195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 826195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 827195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 828195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 829195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 830195957Salfred case LIBUSB20_TRANSFER_STALL: 831195957Salfred return (LIBUSB_TRANSFER_STALL); 832195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 833195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 834195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 835195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 836195957Salfred default: 837195957Salfred return (LIBUSB_TRANSFER_ERROR); 838195957Salfred } 839195957Salfred} 840195957Salfred 841195957Salfred/* This function must be called locked */ 842195957Salfred 843194676Sthompsastatic void 844195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 845195957Salfred struct libusb_super_transfer *sxfer, int status) 846194676Sthompsa{ 847195957Salfred struct libusb_transfer *uxfer; 848195957Salfred struct libusb_device *dev; 849195957Salfred 850195957Salfred uxfer = (struct libusb_transfer *)( 851195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 852195957Salfred 853195957Salfred if (pxfer != NULL) 854195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 855195957Salfred 856199575Sthompsa /* set transfer status */ 857195957Salfred uxfer->status = status; 858195957Salfred 859199575Sthompsa /* update super transfer state */ 860199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 861199575Sthompsa 862195957Salfred dev = libusb_get_device(uxfer->dev_handle); 863195957Salfred 864195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 865195957Salfred} 866195957Salfred 867195957Salfred/* This function must be called locked */ 868195957Salfred 869195957Salfredstatic void 870195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 871195957Salfred{ 872195957Salfred struct libusb_super_transfer *sxfer; 873195957Salfred struct libusb_transfer *uxfer; 874195957Salfred uint32_t actlen; 875195957Salfred uint16_t iso_packets; 876195957Salfred uint16_t i; 877194676Sthompsa uint8_t status; 878195957Salfred uint8_t flags; 879194676Sthompsa 880195957Salfred status = libusb20_tr_get_status(pxfer); 881195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 882195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 883195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 884194676Sthompsa 885195957Salfred if (sxfer == NULL) 886195957Salfred return; /* cancelled - nothing to do */ 887195957Salfred 888195957Salfred uxfer = (struct libusb_transfer *)( 889195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 890195957Salfred 891195957Salfred if (iso_packets > uxfer->num_iso_packets) 892195957Salfred iso_packets = uxfer->num_iso_packets; 893195957Salfred 894195957Salfred if (iso_packets == 0) 895195957Salfred return; /* nothing to do */ 896195957Salfred 897195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 898195957Salfred uxfer->num_iso_packets = iso_packets; 899195957Salfred 900195957Salfred flags = uxfer->flags; 901195957Salfred 902194676Sthompsa switch (status) { 903194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 904195560Sthompsa 905195957Salfred /* update actual length */ 906195957Salfred uxfer->actual_length = actlen; 907195957Salfred for (i = 0; i != iso_packets; i++) { 908195957Salfred uxfer->iso_packet_desc[i].actual_length = 909195957Salfred libusb20_tr_get_length(pxfer, i); 910195957Salfred } 911195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 912195957Salfred break; 913195560Sthompsa 914194676Sthompsa case LIBUSB20_TRANSFER_START: 915195957Salfred 916195957Salfred /* setup length(s) */ 917195957Salfred actlen = 0; 918195957Salfred for (i = 0; i != iso_packets; i++) { 919195957Salfred libusb20_tr_setup_isoc(pxfer, 920195957Salfred &uxfer->buffer[actlen], 921195957Salfred uxfer->iso_packet_desc[i].length, i); 922195957Salfred actlen += uxfer->iso_packet_desc[i].length; 923194676Sthompsa } 924195957Salfred 925195957Salfred /* no remainder */ 926195957Salfred sxfer->rem_len = 0; 927195957Salfred 928195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 929195957Salfred libusb20_tr_submit(pxfer); 930195957Salfred 931195957Salfred /* fork another USB transfer, if any */ 932195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 933195957Salfred break; 934195957Salfred 935194676Sthompsa default: 936195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 937195957Salfred break; 938194676Sthompsa } 939195957Salfred} 940194676Sthompsa 941195957Salfred/* This function must be called locked */ 942195957Salfred 943195957Salfredstatic void 944195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 945195957Salfred{ 946195957Salfred struct libusb_super_transfer *sxfer; 947195957Salfred struct libusb_transfer *uxfer; 948195957Salfred uint32_t max_bulk; 949195957Salfred uint32_t actlen; 950195957Salfred uint8_t status; 951195957Salfred uint8_t flags; 952195957Salfred 953195957Salfred status = libusb20_tr_get_status(pxfer); 954195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 955195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 956195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 957195957Salfred 958195957Salfred if (sxfer == NULL) 959195957Salfred return; /* cancelled - nothing to do */ 960195957Salfred 961195957Salfred uxfer = (struct libusb_transfer *)( 962195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 963195957Salfred 964195957Salfred flags = uxfer->flags; 965195957Salfred 966194676Sthompsa switch (status) { 967194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 968195957Salfred 969195957Salfred uxfer->actual_length += actlen; 970195957Salfred 971195957Salfred /* check for short packet */ 972195957Salfred if (sxfer->last_len != actlen) { 973195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 974195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 975195957Salfred } else { 976195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 977195957Salfred } 978195957Salfred break; 979195957Salfred } 980195957Salfred /* check for end of data */ 981195957Salfred if (sxfer->rem_len == 0) { 982195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 983195957Salfred break; 984195957Salfred } 985195957Salfred /* FALLTHROUGH */ 986195957Salfred 987195957Salfred case LIBUSB20_TRANSFER_START: 988195957Salfred if (max_bulk > sxfer->rem_len) { 989195957Salfred max_bulk = sxfer->rem_len; 990195957Salfred } 991195957Salfred /* setup new BULK or INTERRUPT transaction */ 992195957Salfred libusb20_tr_setup_bulk(pxfer, 993195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 994195957Salfred 995195957Salfred /* update counters */ 996195957Salfred sxfer->last_len = max_bulk; 997195957Salfred sxfer->curr_data += max_bulk; 998195957Salfred sxfer->rem_len -= max_bulk; 999195957Salfred 1000195957Salfred libusb20_tr_submit(pxfer); 1001195957Salfred 1002195957Salfred /* check if we can fork another USB transfer */ 1003195957Salfred if (sxfer->rem_len == 0) 1004195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1005195957Salfred break; 1006195957Salfred 1007195957Salfred default: 1008195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1009195957Salfred break; 1010194676Sthompsa } 1011194676Sthompsa} 1012194676Sthompsa 1013195957Salfred/* This function must be called locked */ 1014195957Salfred 1015195957Salfredstatic void 1016195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1017194676Sthompsa{ 1018195957Salfred struct libusb_super_transfer *sxfer; 1019195957Salfred struct libusb_transfer *uxfer; 1020195957Salfred uint32_t max_bulk; 1021195957Salfred uint32_t actlen; 1022195957Salfred uint8_t status; 1023195957Salfred uint8_t flags; 1024194676Sthompsa 1025195957Salfred status = libusb20_tr_get_status(pxfer); 1026195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1027195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1028195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1029194676Sthompsa 1030195957Salfred if (sxfer == NULL) 1031195957Salfred return; /* cancelled - nothing to do */ 1032194676Sthompsa 1033195957Salfred uxfer = (struct libusb_transfer *)( 1034195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1035194676Sthompsa 1036195957Salfred flags = uxfer->flags; 1037194676Sthompsa 1038195957Salfred switch (status) { 1039195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1040194676Sthompsa 1041195957Salfred uxfer->actual_length += actlen; 1042195957Salfred 1043195957Salfred /* subtract length of SETUP packet, if any */ 1044195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1045195957Salfred 1046195957Salfred /* check for short packet */ 1047195957Salfred if (sxfer->last_len != actlen) { 1048195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1049195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1050195957Salfred } else { 1051195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1052195957Salfred } 1053195957Salfred break; 1054194676Sthompsa } 1055195957Salfred /* check for end of data */ 1056195957Salfred if (sxfer->rem_len == 0) { 1057195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1058195957Salfred break; 1059195957Salfred } 1060195957Salfred /* FALLTHROUGH */ 1061194676Sthompsa 1062195957Salfred case LIBUSB20_TRANSFER_START: 1063195957Salfred if (max_bulk > sxfer->rem_len) { 1064195957Salfred max_bulk = sxfer->rem_len; 1065195957Salfred } 1066195957Salfred /* setup new CONTROL transaction */ 1067195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1068195957Salfred /* next fragment - don't send SETUP packet */ 1069195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1070195957Salfred } else { 1071195957Salfred /* first fragment - send SETUP packet */ 1072195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1073195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1074195957Salfred } 1075195957Salfred 1076195957Salfred if (max_bulk != 0) { 1077195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1078195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1079195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1080195957Salfred } else { 1081195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1082195957Salfred } 1083195957Salfred 1084195957Salfred /* update counters */ 1085195957Salfred sxfer->last_len = max_bulk; 1086195957Salfred sxfer->curr_data += max_bulk; 1087195957Salfred sxfer->rem_len -= max_bulk; 1088195957Salfred 1089195957Salfred libusb20_tr_submit(pxfer); 1090195957Salfred 1091195957Salfred /* check if we can fork another USB transfer */ 1092195957Salfred if (sxfer->rem_len == 0) 1093195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1094195957Salfred break; 1095195957Salfred 1096195957Salfred default: 1097195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1098195957Salfred break; 1099194676Sthompsa } 1100195957Salfred} 1101195957Salfred 1102195957Salfred/* The following function must be called locked */ 1103195957Salfred 1104195957Salfredstatic void 1105195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1106195957Salfred{ 1107195957Salfred struct libusb20_transfer *pxfer0; 1108195957Salfred struct libusb20_transfer *pxfer1; 1109195957Salfred struct libusb_super_transfer *sxfer; 1110195957Salfred struct libusb_transfer *uxfer; 1111195957Salfred struct libusb_device *dev; 1112195957Salfred int err; 1113195957Salfred int buffsize; 1114195957Salfred int maxframe; 1115195957Salfred int temp; 1116195957Salfred uint8_t dummy; 1117195957Salfred 1118195957Salfred dev = libusb_get_device(pdev); 1119195957Salfred 1120195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1121195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1122195957Salfred 1123195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1124195957Salfred return; /* shouldn't happen */ 1125195957Salfred 1126195957Salfred temp = 0; 1127195957Salfred if (libusb20_tr_pending(pxfer0)) 1128195957Salfred temp |= 1; 1129195957Salfred if (libusb20_tr_pending(pxfer1)) 1130195957Salfred temp |= 2; 1131195957Salfred 1132195957Salfred switch (temp) { 1133195957Salfred case 3: 1134195957Salfred /* wait till one of the transfers complete */ 1135195957Salfred return; 1136195957Salfred case 2: 1137195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1138199575Sthompsa if (sxfer == NULL) 1139199575Sthompsa return; /* cancelling */ 1140195957Salfred if (sxfer->rem_len) 1141195957Salfred return; /* cannot queue another one */ 1142195957Salfred /* swap transfers */ 1143195957Salfred pxfer1 = pxfer0; 1144195957Salfred break; 1145195957Salfred case 1: 1146195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1147199575Sthompsa if (sxfer == NULL) 1148199575Sthompsa return; /* cancelling */ 1149195957Salfred if (sxfer->rem_len) 1150195957Salfred return; /* cannot queue another one */ 1151195957Salfred /* swap transfers */ 1152195957Salfred pxfer0 = pxfer1; 1153195957Salfred break; 1154195957Salfred default: 1155195957Salfred break; 1156194676Sthompsa } 1157195957Salfred 1158195957Salfred /* find next transfer on same endpoint */ 1159195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1160195957Salfred 1161195957Salfred uxfer = (struct libusb_transfer *)( 1162195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1163195957Salfred 1164195957Salfred if (uxfer->endpoint == endpoint) { 1165195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1166195957Salfred sxfer->entry.tqe_prev = NULL; 1167195957Salfred goto found; 1168194676Sthompsa } 1169195957Salfred } 1170195957Salfred return; /* success */ 1171194676Sthompsa 1172195957Salfredfound: 1173194676Sthompsa 1174195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1175195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1176194676Sthompsa 1177195957Salfred /* reset super transfer state */ 1178195957Salfred sxfer->rem_len = uxfer->length; 1179195957Salfred sxfer->curr_data = uxfer->buffer; 1180195957Salfred uxfer->actual_length = 0; 1181194676Sthompsa 1182195957Salfred switch (uxfer->type) { 1183195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1184195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1185195957Salfred break; 1186195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1187195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1188195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1189195957Salfred break; 1190195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1191195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1192195957Salfred if (sxfer->rem_len < 8) 1193195957Salfred goto failure; 1194194676Sthompsa 1195195957Salfred /* remove SETUP packet from data */ 1196195957Salfred sxfer->rem_len -= 8; 1197195957Salfred sxfer->curr_data += 8; 1198195957Salfred break; 1199195957Salfred default: 1200195957Salfred goto failure; 1201195560Sthompsa } 1202195957Salfred 1203195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1204195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1205195957Salfred 1206195957Salfred /* make sure the transfer is opened */ 1207195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1208195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1209195957Salfred goto failure; 1210194676Sthompsa } 1211195957Salfred libusb20_tr_start(pxfer0); 1212195957Salfred return; 1213194676Sthompsa 1214195957Salfredfailure: 1215195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1216194676Sthompsa 1217195957Salfred /* make sure our event loop spins the done handler */ 1218195957Salfred dummy = 0; 1219195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1220195957Salfred} 1221194676Sthompsa 1222195957Salfred/* The following function must be called unlocked */ 1223194676Sthompsa 1224195957Salfredint 1225195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1226195957Salfred{ 1227195957Salfred struct libusb20_transfer *pxfer0; 1228195957Salfred struct libusb20_transfer *pxfer1; 1229195957Salfred struct libusb_super_transfer *sxfer; 1230195957Salfred struct libusb_device *dev; 1231199055Sthompsa uint32_t endpoint; 1232195957Salfred int err; 1233195957Salfred 1234195957Salfred if (uxfer == NULL) 1235195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1236195957Salfred 1237195957Salfred if (uxfer->dev_handle == NULL) 1238195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1239195957Salfred 1240195957Salfred endpoint = uxfer->endpoint; 1241195957Salfred 1242195957Salfred if (endpoint > 255) 1243195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1244195957Salfred 1245195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1246195957Salfred 1247195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1248195957Salfred 1249195957Salfred sxfer = (struct libusb_super_transfer *)( 1250195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1251195957Salfred 1252195957Salfred CTX_LOCK(dev->ctx); 1253195957Salfred 1254195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1255195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1256195957Salfred 1257195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1258195957Salfred err = LIBUSB_ERROR_OTHER; 1259195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1260199575Sthompsa (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1261195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1262195957Salfred err = LIBUSB_ERROR_BUSY; 1263195957Salfred } else { 1264199575Sthompsa 1265199575Sthompsa /* set pending state */ 1266199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 1267199575Sthompsa 1268199575Sthompsa /* insert transfer into transfer head list */ 1269195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1270195957Salfred 1271199575Sthompsa /* start work transfers */ 1272195957Salfred libusb10_submit_transfer_sub( 1273195957Salfred uxfer->dev_handle, endpoint); 1274195957Salfred 1275195957Salfred err = 0; /* success */ 1276195957Salfred } 1277195957Salfred 1278195957Salfred CTX_UNLOCK(dev->ctx); 1279195957Salfred 1280195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1281195957Salfred 1282195957Salfred return (err); 1283194676Sthompsa} 1284194676Sthompsa 1285195957Salfred/* Asynchronous transfer cancel */ 1286195957Salfred 1287194676Sthompsaint 1288195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1289194676Sthompsa{ 1290195957Salfred struct libusb20_transfer *pxfer0; 1291195957Salfred struct libusb20_transfer *pxfer1; 1292195957Salfred struct libusb_super_transfer *sxfer; 1293195957Salfred struct libusb_device *dev; 1294199055Sthompsa uint32_t endpoint; 1295199575Sthompsa int retval; 1296194676Sthompsa 1297195957Salfred if (uxfer == NULL) 1298195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1299194676Sthompsa 1300199575Sthompsa /* check if not initialised */ 1301195957Salfred if (uxfer->dev_handle == NULL) 1302199575Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 1303194676Sthompsa 1304195957Salfred endpoint = uxfer->endpoint; 1305194676Sthompsa 1306195957Salfred if (endpoint > 255) 1307195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1308195957Salfred 1309195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1310195957Salfred 1311195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1312195957Salfred 1313195957Salfred sxfer = (struct libusb_super_transfer *)( 1314195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1315195957Salfred 1316199575Sthompsa retval = 0; 1317199575Sthompsa 1318195957Salfred CTX_LOCK(dev->ctx); 1319195957Salfred 1320195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1321195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1322195957Salfred 1323199575Sthompsa if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 1324199575Sthompsa /* only update the transfer status */ 1325199575Sthompsa uxfer->status = LIBUSB_TRANSFER_CANCELLED; 1326199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1327199575Sthompsa } else if (sxfer->entry.tqe_prev != NULL) { 1328195957Salfred /* we are lucky - transfer is on a queue */ 1329195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1330195957Salfred sxfer->entry.tqe_prev = NULL; 1331199575Sthompsa libusb10_complete_transfer(NULL, 1332199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1333195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1334195957Salfred /* not started */ 1335199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1336195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1337199575Sthompsa libusb10_complete_transfer(pxfer0, 1338199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1339195957Salfred libusb20_tr_stop(pxfer0); 1340195957Salfred /* make sure the queue doesn't stall */ 1341195957Salfred libusb10_submit_transfer_sub( 1342195957Salfred uxfer->dev_handle, endpoint); 1343195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1344199575Sthompsa libusb10_complete_transfer(pxfer1, 1345199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1346195957Salfred libusb20_tr_stop(pxfer1); 1347195957Salfred /* make sure the queue doesn't stall */ 1348195957Salfred libusb10_submit_transfer_sub( 1349195957Salfred uxfer->dev_handle, endpoint); 1350195957Salfred } else { 1351195957Salfred /* not started */ 1352199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1353195957Salfred } 1354195957Salfred 1355195957Salfred CTX_UNLOCK(dev->ctx); 1356195957Salfred 1357195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1358195957Salfred 1359199575Sthompsa return (retval); 1360194676Sthompsa} 1361194676Sthompsa 1362195957SalfredUNEXPORTED void 1363195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1364195957Salfred{ 1365195957Salfred /* TODO */ 1366195957Salfred} 1367199055Sthompsa 1368199055Sthompsauint16_t 1369199055Sthompsalibusb_cpu_to_le16(uint16_t x) 1370199055Sthompsa{ 1371199055Sthompsa return (htole16(x)); 1372199055Sthompsa} 1373199055Sthompsa 1374199055Sthompsauint16_t 1375199055Sthompsalibusb_le16_to_cpu(uint16_t x) 1376199055Sthompsa{ 1377199055Sthompsa return (le16toh(x)); 1378199055Sthompsa} 1379199055Sthompsa 1380