libusb10.c revision 208020
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 208020 2010-05-13 00:25:30Z thompsa $ */ 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 666195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface) 667194676Sthompsa{ 668195957Salfred if (pdev == NULL) 669194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 670194676Sthompsa 671195957Salfred return (libusb20_dev_kernel_driver_active( 672195957Salfred pdev, interface)); 673194676Sthompsa} 674194676Sthompsa 675194676Sthompsaint 676195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface) 677194676Sthompsa{ 678195957Salfred int err; 679194676Sthompsa 680195957Salfred if (pdev == NULL) 681194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 682194676Sthompsa 683195957Salfred err = libusb20_dev_detach_kernel_driver( 684195957Salfred pdev, interface); 685194676Sthompsa 686195957Salfred return (err ? LIBUSB20_ERROR_OTHER : 0); 687194676Sthompsa} 688194676Sthompsa 689194676Sthompsaint 690195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface) 691194676Sthompsa{ 692195957Salfred if (pdev == NULL) 693194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 694195957Salfred /* stub - currently not supported by libusb20 */ 695194676Sthompsa return (0); 696194676Sthompsa} 697194676Sthompsa 698194676Sthompsa/* Asynchronous device I/O */ 699194676Sthompsa 700194676Sthompsastruct libusb_transfer * 701194676Sthompsalibusb_alloc_transfer(int iso_packets) 702194676Sthompsa{ 703195957Salfred struct libusb_transfer *uxfer; 704195957Salfred struct libusb_super_transfer *sxfer; 705194676Sthompsa int len; 706194676Sthompsa 707194676Sthompsa len = sizeof(struct libusb_transfer) + 708195957Salfred sizeof(struct libusb_super_transfer) + 709194676Sthompsa (iso_packets * sizeof(libusb_iso_packet_descriptor)); 710194676Sthompsa 711195957Salfred sxfer = malloc(len); 712195957Salfred if (sxfer == NULL) 713194676Sthompsa return (NULL); 714194676Sthompsa 715195957Salfred memset(sxfer, 0, len); 716194676Sthompsa 717195957Salfred uxfer = (struct libusb_transfer *)( 718195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 719194676Sthompsa 720195957Salfred /* set default value */ 721195957Salfred uxfer->num_iso_packets = iso_packets; 722195957Salfred 723195957Salfred return (uxfer); 724194676Sthompsa} 725194676Sthompsa 726194676Sthompsavoid 727195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer) 728194676Sthompsa{ 729195957Salfred struct libusb_super_transfer *sxfer; 730194676Sthompsa 731195957Salfred if (uxfer == NULL) 732195957Salfred return; /* be NULL safe */ 733194676Sthompsa 734195957Salfred sxfer = (struct libusb_super_transfer *)( 735195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 736194676Sthompsa 737195957Salfred free(sxfer); 738194676Sthompsa} 739194676Sthompsa 740195560Sthompsastatic int 741195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) 742195560Sthompsa{ 743195560Sthompsa int ret; 744195560Sthompsa int usb_speed; 745195560Sthompsa 746195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 747195560Sthompsa 748195560Sthompsa switch (xfer->type) { 749195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 750195560Sthompsa switch (usb_speed) { 751195560Sthompsa case LIBUSB20_SPEED_LOW: 752195560Sthompsa case LIBUSB20_SPEED_FULL: 753195560Sthompsa ret = 60 * 1; 754195957Salfred break; 755195957Salfred default: 756195560Sthompsa ret = 60 * 8; 757195957Salfred break; 758195560Sthompsa } 759195957Salfred break; 760195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 761195560Sthompsa ret = 2; 762195957Salfred break; 763195560Sthompsa default: 764195560Sthompsa ret = 1; 765195957Salfred break; 766195560Sthompsa } 767195957Salfred return (ret); 768195560Sthompsa} 769195560Sthompsa 770195560Sthompsastatic int 771195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer) 772195560Sthompsa{ 773195560Sthompsa int ret; 774195560Sthompsa int usb_speed; 775195560Sthompsa 776195560Sthompsa usb_speed = libusb20_dev_get_speed(pdev); 777195560Sthompsa 778195560Sthompsa switch (xfer->type) { 779195560Sthompsa case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 780195957Salfred ret = 0; /* kernel will auto-select */ 781195957Salfred break; 782195560Sthompsa case LIBUSB_TRANSFER_TYPE_CONTROL: 783195957Salfred ret = 1024; 784195957Salfred break; 785195957Salfred default: 786195560Sthompsa switch (usb_speed) { 787195957Salfred case LIBUSB20_SPEED_LOW: 788195957Salfred ret = 256; 789195957Salfred break; 790195957Salfred case LIBUSB20_SPEED_FULL: 791195957Salfred ret = 4096; 792195957Salfred break; 793195957Salfred default: 794195957Salfred ret = 16384; 795195957Salfred break; 796195560Sthompsa } 797195957Salfred break; 798195560Sthompsa } 799195957Salfred return (ret); 800195560Sthompsa} 801195560Sthompsa 802195957Salfredstatic int 803195957Salfredlibusb10_convert_error(uint8_t status) 804195957Salfred{ 805195957Salfred ; /* indent fix */ 806195957Salfred 807195957Salfred switch (status) { 808195957Salfred case LIBUSB20_TRANSFER_START: 809195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 810195957Salfred return (LIBUSB_TRANSFER_COMPLETED); 811195957Salfred case LIBUSB20_TRANSFER_OVERFLOW: 812195957Salfred return (LIBUSB_TRANSFER_OVERFLOW); 813195957Salfred case LIBUSB20_TRANSFER_NO_DEVICE: 814195957Salfred return (LIBUSB_TRANSFER_NO_DEVICE); 815195957Salfred case LIBUSB20_TRANSFER_STALL: 816195957Salfred return (LIBUSB_TRANSFER_STALL); 817195957Salfred case LIBUSB20_TRANSFER_CANCELLED: 818195957Salfred return (LIBUSB_TRANSFER_CANCELLED); 819195957Salfred case LIBUSB20_TRANSFER_TIMED_OUT: 820195957Salfred return (LIBUSB_TRANSFER_TIMED_OUT); 821195957Salfred default: 822195957Salfred return (LIBUSB_TRANSFER_ERROR); 823195957Salfred } 824195957Salfred} 825195957Salfred 826195957Salfred/* This function must be called locked */ 827195957Salfred 828194676Sthompsastatic void 829195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer, 830195957Salfred struct libusb_super_transfer *sxfer, int status) 831194676Sthompsa{ 832195957Salfred struct libusb_transfer *uxfer; 833195957Salfred struct libusb_device *dev; 834195957Salfred 835195957Salfred uxfer = (struct libusb_transfer *)( 836195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 837195957Salfred 838195957Salfred if (pxfer != NULL) 839195957Salfred libusb20_tr_set_priv_sc1(pxfer, NULL); 840195957Salfred 841199575Sthompsa /* set transfer status */ 842195957Salfred uxfer->status = status; 843195957Salfred 844199575Sthompsa /* update super transfer state */ 845199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; 846199575Sthompsa 847195957Salfred dev = libusb_get_device(uxfer->dev_handle); 848195957Salfred 849195957Salfred TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); 850195957Salfred} 851195957Salfred 852195957Salfred/* This function must be called locked */ 853195957Salfred 854195957Salfredstatic void 855195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer) 856195957Salfred{ 857195957Salfred struct libusb_super_transfer *sxfer; 858195957Salfred struct libusb_transfer *uxfer; 859195957Salfred uint32_t actlen; 860195957Salfred uint16_t iso_packets; 861195957Salfred uint16_t i; 862194676Sthompsa uint8_t status; 863195957Salfred uint8_t flags; 864194676Sthompsa 865195957Salfred status = libusb20_tr_get_status(pxfer); 866195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 867195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 868195957Salfred iso_packets = libusb20_tr_get_max_frames(pxfer); 869194676Sthompsa 870195957Salfred if (sxfer == NULL) 871195957Salfred return; /* cancelled - nothing to do */ 872195957Salfred 873195957Salfred uxfer = (struct libusb_transfer *)( 874195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 875195957Salfred 876195957Salfred if (iso_packets > uxfer->num_iso_packets) 877195957Salfred iso_packets = uxfer->num_iso_packets; 878195957Salfred 879195957Salfred if (iso_packets == 0) 880195957Salfred return; /* nothing to do */ 881195957Salfred 882195957Salfred /* make sure that the number of ISOCHRONOUS packets is valid */ 883195957Salfred uxfer->num_iso_packets = iso_packets; 884195957Salfred 885195957Salfred flags = uxfer->flags; 886195957Salfred 887194676Sthompsa switch (status) { 888194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 889195560Sthompsa 890195957Salfred /* update actual length */ 891195957Salfred uxfer->actual_length = actlen; 892195957Salfred for (i = 0; i != iso_packets; i++) { 893195957Salfred uxfer->iso_packet_desc[i].actual_length = 894195957Salfred libusb20_tr_get_length(pxfer, i); 895195957Salfred } 896195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 897195957Salfred break; 898195560Sthompsa 899194676Sthompsa case LIBUSB20_TRANSFER_START: 900195957Salfred 901195957Salfred /* setup length(s) */ 902195957Salfred actlen = 0; 903195957Salfred for (i = 0; i != iso_packets; i++) { 904195957Salfred libusb20_tr_setup_isoc(pxfer, 905195957Salfred &uxfer->buffer[actlen], 906195957Salfred uxfer->iso_packet_desc[i].length, i); 907195957Salfred actlen += uxfer->iso_packet_desc[i].length; 908194676Sthompsa } 909195957Salfred 910195957Salfred /* no remainder */ 911195957Salfred sxfer->rem_len = 0; 912195957Salfred 913195957Salfred libusb20_tr_set_total_frames(pxfer, iso_packets); 914195957Salfred libusb20_tr_submit(pxfer); 915195957Salfred 916195957Salfred /* fork another USB transfer, if any */ 917195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 918195957Salfred break; 919195957Salfred 920194676Sthompsa default: 921195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 922195957Salfred break; 923194676Sthompsa } 924195957Salfred} 925194676Sthompsa 926195957Salfred/* This function must be called locked */ 927195957Salfred 928195957Salfredstatic void 929195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer) 930195957Salfred{ 931195957Salfred struct libusb_super_transfer *sxfer; 932195957Salfred struct libusb_transfer *uxfer; 933195957Salfred uint32_t max_bulk; 934195957Salfred uint32_t actlen; 935195957Salfred uint8_t status; 936195957Salfred uint8_t flags; 937195957Salfred 938195957Salfred status = libusb20_tr_get_status(pxfer); 939195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 940195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 941195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 942195957Salfred 943195957Salfred if (sxfer == NULL) 944195957Salfred return; /* cancelled - nothing to do */ 945195957Salfred 946195957Salfred uxfer = (struct libusb_transfer *)( 947195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 948195957Salfred 949195957Salfred flags = uxfer->flags; 950195957Salfred 951194676Sthompsa switch (status) { 952194676Sthompsa case LIBUSB20_TRANSFER_COMPLETED: 953195957Salfred 954195957Salfred uxfer->actual_length += actlen; 955195957Salfred 956195957Salfred /* check for short packet */ 957195957Salfred if (sxfer->last_len != actlen) { 958195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 959195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 960195957Salfred } else { 961195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 962195957Salfred } 963195957Salfred break; 964195957Salfred } 965195957Salfred /* check for end of data */ 966195957Salfred if (sxfer->rem_len == 0) { 967195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 968195957Salfred break; 969195957Salfred } 970195957Salfred /* FALLTHROUGH */ 971195957Salfred 972195957Salfred case LIBUSB20_TRANSFER_START: 973195957Salfred if (max_bulk > sxfer->rem_len) { 974195957Salfred max_bulk = sxfer->rem_len; 975195957Salfred } 976195957Salfred /* setup new BULK or INTERRUPT transaction */ 977195957Salfred libusb20_tr_setup_bulk(pxfer, 978195957Salfred sxfer->curr_data, max_bulk, uxfer->timeout); 979195957Salfred 980195957Salfred /* update counters */ 981195957Salfred sxfer->last_len = max_bulk; 982195957Salfred sxfer->curr_data += max_bulk; 983195957Salfred sxfer->rem_len -= max_bulk; 984195957Salfred 985195957Salfred libusb20_tr_submit(pxfer); 986195957Salfred 987195957Salfred /* check if we can fork another USB transfer */ 988195957Salfred if (sxfer->rem_len == 0) 989195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 990195957Salfred break; 991195957Salfred 992195957Salfred default: 993195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 994195957Salfred break; 995194676Sthompsa } 996194676Sthompsa} 997194676Sthompsa 998195957Salfred/* This function must be called locked */ 999195957Salfred 1000195957Salfredstatic void 1001195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer) 1002194676Sthompsa{ 1003195957Salfred struct libusb_super_transfer *sxfer; 1004195957Salfred struct libusb_transfer *uxfer; 1005195957Salfred uint32_t max_bulk; 1006195957Salfred uint32_t actlen; 1007195957Salfred uint8_t status; 1008195957Salfred uint8_t flags; 1009194676Sthompsa 1010195957Salfred status = libusb20_tr_get_status(pxfer); 1011195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer); 1012195957Salfred max_bulk = libusb20_tr_get_max_total_length(pxfer); 1013195957Salfred actlen = libusb20_tr_get_actual_length(pxfer); 1014194676Sthompsa 1015195957Salfred if (sxfer == NULL) 1016195957Salfred return; /* cancelled - nothing to do */ 1017194676Sthompsa 1018195957Salfred uxfer = (struct libusb_transfer *)( 1019195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1020194676Sthompsa 1021195957Salfred flags = uxfer->flags; 1022194676Sthompsa 1023195957Salfred switch (status) { 1024195957Salfred case LIBUSB20_TRANSFER_COMPLETED: 1025194676Sthompsa 1026195957Salfred uxfer->actual_length += actlen; 1027195957Salfred 1028195957Salfred /* subtract length of SETUP packet, if any */ 1029195957Salfred actlen -= libusb20_tr_get_length(pxfer, 0); 1030195957Salfred 1031195957Salfred /* check for short packet */ 1032195957Salfred if (sxfer->last_len != actlen) { 1033195957Salfred if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { 1034195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR); 1035195957Salfred } else { 1036195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1037195957Salfred } 1038195957Salfred break; 1039194676Sthompsa } 1040195957Salfred /* check for end of data */ 1041195957Salfred if (sxfer->rem_len == 0) { 1042195957Salfred libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED); 1043195957Salfred break; 1044195957Salfred } 1045195957Salfred /* FALLTHROUGH */ 1046194676Sthompsa 1047195957Salfred case LIBUSB20_TRANSFER_START: 1048195957Salfred if (max_bulk > sxfer->rem_len) { 1049195957Salfred max_bulk = sxfer->rem_len; 1050195957Salfred } 1051195957Salfred /* setup new CONTROL transaction */ 1052195957Salfred if (status == LIBUSB20_TRANSFER_COMPLETED) { 1053195957Salfred /* next fragment - don't send SETUP packet */ 1054195957Salfred libusb20_tr_set_length(pxfer, 0, 0); 1055195957Salfred } else { 1056195957Salfred /* first fragment - send SETUP packet */ 1057195957Salfred libusb20_tr_set_length(pxfer, 8, 0); 1058195957Salfred libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0); 1059195957Salfred } 1060195957Salfred 1061195957Salfred if (max_bulk != 0) { 1062195957Salfred libusb20_tr_set_length(pxfer, max_bulk, 1); 1063195957Salfred libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1); 1064195957Salfred libusb20_tr_set_total_frames(pxfer, 2); 1065195957Salfred } else { 1066195957Salfred libusb20_tr_set_total_frames(pxfer, 1); 1067195957Salfred } 1068195957Salfred 1069195957Salfred /* update counters */ 1070195957Salfred sxfer->last_len = max_bulk; 1071195957Salfred sxfer->curr_data += max_bulk; 1072195957Salfred sxfer->rem_len -= max_bulk; 1073195957Salfred 1074195957Salfred libusb20_tr_submit(pxfer); 1075195957Salfred 1076195957Salfred /* check if we can fork another USB transfer */ 1077195957Salfred if (sxfer->rem_len == 0) 1078195957Salfred libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint); 1079195957Salfred break; 1080195957Salfred 1081195957Salfred default: 1082195957Salfred libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status)); 1083195957Salfred break; 1084194676Sthompsa } 1085195957Salfred} 1086195957Salfred 1087195957Salfred/* The following function must be called locked */ 1088195957Salfred 1089195957Salfredstatic void 1090195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) 1091195957Salfred{ 1092195957Salfred struct libusb20_transfer *pxfer0; 1093195957Salfred struct libusb20_transfer *pxfer1; 1094195957Salfred struct libusb_super_transfer *sxfer; 1095195957Salfred struct libusb_transfer *uxfer; 1096195957Salfred struct libusb_device *dev; 1097195957Salfred int err; 1098195957Salfred int buffsize; 1099195957Salfred int maxframe; 1100195957Salfred int temp; 1101195957Salfred uint8_t dummy; 1102195957Salfred 1103195957Salfred dev = libusb_get_device(pdev); 1104195957Salfred 1105195957Salfred pxfer0 = libusb10_get_transfer(pdev, endpoint, 0); 1106195957Salfred pxfer1 = libusb10_get_transfer(pdev, endpoint, 1); 1107195957Salfred 1108195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) 1109195957Salfred return; /* shouldn't happen */ 1110195957Salfred 1111195957Salfred temp = 0; 1112195957Salfred if (libusb20_tr_pending(pxfer0)) 1113195957Salfred temp |= 1; 1114195957Salfred if (libusb20_tr_pending(pxfer1)) 1115195957Salfred temp |= 2; 1116195957Salfred 1117195957Salfred switch (temp) { 1118195957Salfred case 3: 1119195957Salfred /* wait till one of the transfers complete */ 1120195957Salfred return; 1121195957Salfred case 2: 1122195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer1); 1123199575Sthompsa if (sxfer == NULL) 1124199575Sthompsa return; /* cancelling */ 1125195957Salfred if (sxfer->rem_len) 1126195957Salfred return; /* cannot queue another one */ 1127195957Salfred /* swap transfers */ 1128195957Salfred pxfer1 = pxfer0; 1129195957Salfred break; 1130195957Salfred case 1: 1131195957Salfred sxfer = libusb20_tr_get_priv_sc1(pxfer0); 1132199575Sthompsa if (sxfer == NULL) 1133199575Sthompsa return; /* cancelling */ 1134195957Salfred if (sxfer->rem_len) 1135195957Salfred return; /* cannot queue another one */ 1136195957Salfred /* swap transfers */ 1137195957Salfred pxfer0 = pxfer1; 1138195957Salfred break; 1139195957Salfred default: 1140195957Salfred break; 1141194676Sthompsa } 1142195957Salfred 1143195957Salfred /* find next transfer on same endpoint */ 1144195957Salfred TAILQ_FOREACH(sxfer, &dev->tr_head, entry) { 1145195957Salfred 1146195957Salfred uxfer = (struct libusb_transfer *)( 1147195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 1148195957Salfred 1149195957Salfred if (uxfer->endpoint == endpoint) { 1150195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1151195957Salfred sxfer->entry.tqe_prev = NULL; 1152195957Salfred goto found; 1153194676Sthompsa } 1154195957Salfred } 1155195957Salfred return; /* success */ 1156194676Sthompsa 1157195957Salfredfound: 1158194676Sthompsa 1159195957Salfred libusb20_tr_set_priv_sc0(pxfer0, pdev); 1160195957Salfred libusb20_tr_set_priv_sc1(pxfer0, sxfer); 1161194676Sthompsa 1162195957Salfred /* reset super transfer state */ 1163195957Salfred sxfer->rem_len = uxfer->length; 1164195957Salfred sxfer->curr_data = uxfer->buffer; 1165195957Salfred uxfer->actual_length = 0; 1166194676Sthompsa 1167195957Salfred switch (uxfer->type) { 1168195957Salfred case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: 1169195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy); 1170195957Salfred break; 1171195957Salfred case LIBUSB_TRANSFER_TYPE_BULK: 1172195957Salfred case LIBUSB_TRANSFER_TYPE_INTERRUPT: 1173195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy); 1174195957Salfred break; 1175195957Salfred case LIBUSB_TRANSFER_TYPE_CONTROL: 1176195957Salfred libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy); 1177195957Salfred if (sxfer->rem_len < 8) 1178195957Salfred goto failure; 1179194676Sthompsa 1180195957Salfred /* remove SETUP packet from data */ 1181195957Salfred sxfer->rem_len -= 8; 1182195957Salfred sxfer->curr_data += 8; 1183195957Salfred break; 1184195957Salfred default: 1185195957Salfred goto failure; 1186195560Sthompsa } 1187195957Salfred 1188195957Salfred buffsize = libusb10_get_buffsize(pdev, uxfer); 1189195957Salfred maxframe = libusb10_get_maxframe(pdev, uxfer); 1190195957Salfred 1191195957Salfred /* make sure the transfer is opened */ 1192195957Salfred err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint); 1193195957Salfred if (err && (err != LIBUSB20_ERROR_BUSY)) { 1194195957Salfred goto failure; 1195194676Sthompsa } 1196195957Salfred libusb20_tr_start(pxfer0); 1197195957Salfred return; 1198194676Sthompsa 1199195957Salfredfailure: 1200195957Salfred libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR); 1201194676Sthompsa 1202195957Salfred /* make sure our event loop spins the done handler */ 1203195957Salfred dummy = 0; 1204195957Salfred write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); 1205195957Salfred} 1206194676Sthompsa 1207195957Salfred/* The following function must be called unlocked */ 1208194676Sthompsa 1209195957Salfredint 1210195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer) 1211195957Salfred{ 1212195957Salfred struct libusb20_transfer *pxfer0; 1213195957Salfred struct libusb20_transfer *pxfer1; 1214195957Salfred struct libusb_super_transfer *sxfer; 1215195957Salfred struct libusb_device *dev; 1216199055Sthompsa uint32_t endpoint; 1217195957Salfred int err; 1218195957Salfred 1219195957Salfred if (uxfer == NULL) 1220195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1221195957Salfred 1222195957Salfred if (uxfer->dev_handle == NULL) 1223195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1224195957Salfred 1225195957Salfred endpoint = uxfer->endpoint; 1226195957Salfred 1227195957Salfred if (endpoint > 255) 1228195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1229195957Salfred 1230195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1231195957Salfred 1232195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter"); 1233195957Salfred 1234195957Salfred sxfer = (struct libusb_super_transfer *)( 1235195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1236195957Salfred 1237195957Salfred CTX_LOCK(dev->ctx); 1238195957Salfred 1239195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1240195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1241195957Salfred 1242195957Salfred if (pxfer0 == NULL || pxfer1 == NULL) { 1243195957Salfred err = LIBUSB_ERROR_OTHER; 1244195957Salfred } else if ((sxfer->entry.tqe_prev != NULL) || 1245199575Sthompsa (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || 1246195957Salfred (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { 1247195957Salfred err = LIBUSB_ERROR_BUSY; 1248195957Salfred } else { 1249199575Sthompsa 1250199575Sthompsa /* set pending state */ 1251199575Sthompsa sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; 1252199575Sthompsa 1253199575Sthompsa /* insert transfer into transfer head list */ 1254195957Salfred TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); 1255195957Salfred 1256199575Sthompsa /* start work transfers */ 1257195957Salfred libusb10_submit_transfer_sub( 1258195957Salfred uxfer->dev_handle, endpoint); 1259195957Salfred 1260195957Salfred err = 0; /* success */ 1261195957Salfred } 1262195957Salfred 1263195957Salfred CTX_UNLOCK(dev->ctx); 1264195957Salfred 1265195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err); 1266195957Salfred 1267195957Salfred return (err); 1268194676Sthompsa} 1269194676Sthompsa 1270195957Salfred/* Asynchronous transfer cancel */ 1271195957Salfred 1272194676Sthompsaint 1273195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer) 1274194676Sthompsa{ 1275195957Salfred struct libusb20_transfer *pxfer0; 1276195957Salfred struct libusb20_transfer *pxfer1; 1277195957Salfred struct libusb_super_transfer *sxfer; 1278195957Salfred struct libusb_device *dev; 1279199055Sthompsa uint32_t endpoint; 1280199575Sthompsa int retval; 1281194676Sthompsa 1282195957Salfred if (uxfer == NULL) 1283195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1284194676Sthompsa 1285199575Sthompsa /* check if not initialised */ 1286195957Salfred if (uxfer->dev_handle == NULL) 1287199575Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 1288194676Sthompsa 1289195957Salfred endpoint = uxfer->endpoint; 1290194676Sthompsa 1291195957Salfred if (endpoint > 255) 1292195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 1293195957Salfred 1294195957Salfred dev = libusb_get_device(uxfer->dev_handle); 1295195957Salfred 1296195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter"); 1297195957Salfred 1298195957Salfred sxfer = (struct libusb_super_transfer *)( 1299195957Salfred (uint8_t *)uxfer - sizeof(*sxfer)); 1300195957Salfred 1301199575Sthompsa retval = 0; 1302199575Sthompsa 1303195957Salfred CTX_LOCK(dev->ctx); 1304195957Salfred 1305195957Salfred pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); 1306195957Salfred pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); 1307195957Salfred 1308199575Sthompsa if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { 1309199575Sthompsa /* only update the transfer status */ 1310199575Sthompsa uxfer->status = LIBUSB_TRANSFER_CANCELLED; 1311199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1312199575Sthompsa } else if (sxfer->entry.tqe_prev != NULL) { 1313195957Salfred /* we are lucky - transfer is on a queue */ 1314195957Salfred TAILQ_REMOVE(&dev->tr_head, sxfer, entry); 1315195957Salfred sxfer->entry.tqe_prev = NULL; 1316199575Sthompsa libusb10_complete_transfer(NULL, 1317199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1318195957Salfred } else if (pxfer0 == NULL || pxfer1 == NULL) { 1319195957Salfred /* not started */ 1320199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1321195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { 1322199575Sthompsa libusb10_complete_transfer(pxfer0, 1323199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1324195957Salfred libusb20_tr_stop(pxfer0); 1325195957Salfred /* make sure the queue doesn't stall */ 1326195957Salfred libusb10_submit_transfer_sub( 1327195957Salfred uxfer->dev_handle, endpoint); 1328195957Salfred } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { 1329199575Sthompsa libusb10_complete_transfer(pxfer1, 1330199575Sthompsa sxfer, LIBUSB_TRANSFER_CANCELLED); 1331195957Salfred libusb20_tr_stop(pxfer1); 1332195957Salfred /* make sure the queue doesn't stall */ 1333195957Salfred libusb10_submit_transfer_sub( 1334195957Salfred uxfer->dev_handle, endpoint); 1335195957Salfred } else { 1336195957Salfred /* not started */ 1337199575Sthompsa retval = LIBUSB_ERROR_NOT_FOUND; 1338195957Salfred } 1339195957Salfred 1340195957Salfred CTX_UNLOCK(dev->ctx); 1341195957Salfred 1342195957Salfred DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); 1343195957Salfred 1344199575Sthompsa return (retval); 1345194676Sthompsa} 1346194676Sthompsa 1347195957SalfredUNEXPORTED void 1348195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev) 1349195957Salfred{ 1350195957Salfred /* TODO */ 1351195957Salfred} 1352199055Sthompsa 1353199055Sthompsauint16_t 1354199055Sthompsalibusb_cpu_to_le16(uint16_t x) 1355199055Sthompsa{ 1356199055Sthompsa return (htole16(x)); 1357199055Sthompsa} 1358199055Sthompsa 1359199055Sthompsauint16_t 1360199055Sthompsalibusb_le16_to_cpu(uint16_t x) 1361199055Sthompsa{ 1362199055Sthompsa return (le16toh(x)); 1363199055Sthompsa} 1364199055Sthompsa 1365