1194676Sthompsa/* $FreeBSD$ */ 2194676Sthompsa/*- 3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4194676Sthompsa * 5194676Sthompsa * Redistribution and use in source and binary forms, with or without 6194676Sthompsa * modification, are permitted provided that the following conditions 7194676Sthompsa * are met: 8194676Sthompsa * 1. Redistributions of source code must retain the above copyright 9194676Sthompsa * notice, this list of conditions and the following disclaimer. 10194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 11194676Sthompsa * notice, this list of conditions and the following disclaimer in the 12194676Sthompsa * documentation and/or other materials provided with the distribution. 13194676Sthompsa * 14194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194676Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194676Sthompsa * SUCH DAMAGE. 25194676Sthompsa */ 26194676Sthompsa 27248236Shselasky#ifdef LIBUSB_GLOBAL_INCLUDE_FILE 28248236Shselasky#include LIBUSB_GLOBAL_INCLUDE_FILE 29248236Shselasky#else 30203815Swkoszek#include <errno.h> 31194676Sthompsa#include <poll.h> 32194676Sthompsa#include <pthread.h> 33203815Swkoszek#include <stdio.h> 34203815Swkoszek#include <stdlib.h> 35248236Shselasky#include <string.h> 36194676Sthompsa#include <time.h> 37203815Swkoszek#include <unistd.h> 38248236Shselasky#include <sys/queue.h> 39248236Shselasky#include <sys/endian.h> 40248236Shselasky#endif 41194676Sthompsa 42208020Sthompsa#define libusb_device_handle libusb20_device 43208020Sthompsa 44194676Sthompsa#include "libusb20.h" 45194676Sthompsa#include "libusb20_desc.h" 46194676Sthompsa#include "libusb20_int.h" 47194676Sthompsa#include "libusb.h" 48194676Sthompsa#include "libusb10.h" 49194676Sthompsa 50195957SalfredUNEXPORTED void 51195957Salfredlibusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd, 52195957Salfred struct libusb20_device *pdev, int fd, short events) 53195560Sthompsa{ 54195560Sthompsa if (ctx == NULL) 55195957Salfred return; /* invalid */ 56195560Sthompsa 57195957Salfred if (pollfd->entry.tqe_prev != NULL) 58195957Salfred return; /* already queued */ 59195957Salfred 60195957Salfred if (fd < 0) 61195957Salfred return; /* invalid */ 62195957Salfred 63195957Salfred pollfd->pdev = pdev; 64195560Sthompsa pollfd->pollfd.fd = fd; 65195560Sthompsa pollfd->pollfd.events = events; 66195560Sthompsa 67195957Salfred CTX_LOCK(ctx); 68195957Salfred TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry); 69195957Salfred CTX_UNLOCK(ctx); 70195560Sthompsa 71195560Sthompsa if (ctx->fd_added_cb) 72195560Sthompsa ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data); 73195560Sthompsa} 74195560Sthompsa 75195560SthompsaUNEXPORTED void 76195957Salfredlibusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd) 77195560Sthompsa{ 78195957Salfred if (ctx == NULL) 79195957Salfred return; /* invalid */ 80195560Sthompsa 81195957Salfred if (pollfd->entry.tqe_prev == NULL) 82195957Salfred return; /* already dequeued */ 83195560Sthompsa 84195957Salfred CTX_LOCK(ctx); 85195957Salfred TAILQ_REMOVE(&ctx->pollfds, pollfd, entry); 86195957Salfred pollfd->entry.tqe_prev = NULL; 87195957Salfred CTX_UNLOCK(ctx); 88195560Sthompsa 89195560Sthompsa if (ctx->fd_removed_cb) 90195957Salfred ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data); 91195560Sthompsa} 92195560Sthompsa 93195957Salfred/* This function must be called locked */ 94195560Sthompsa 95195957Salfredstatic int 96195957Salfredlibusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv) 97195560Sthompsa{ 98195957Salfred struct libusb_device *dev; 99195957Salfred struct libusb20_device **ppdev; 100195957Salfred struct libusb_super_pollfd *pfd; 101195957Salfred struct pollfd *fds; 102195957Salfred struct libusb_super_transfer *sxfer; 103194676Sthompsa struct libusb_transfer *uxfer; 104194676Sthompsa nfds_t nfds; 105194676Sthompsa int timeout; 106194676Sthompsa int i; 107195957Salfred int err; 108194676Sthompsa 109195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter"); 110195957Salfred 111194676Sthompsa nfds = 0; 112195957Salfred i = 0; 113195957Salfred TAILQ_FOREACH(pfd, &ctx->pollfds, entry) 114195957Salfred nfds++; 115194676Sthompsa 116195560Sthompsa fds = alloca(sizeof(*fds) * nfds); 117194676Sthompsa if (fds == NULL) 118194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 119194676Sthompsa 120195957Salfred ppdev = alloca(sizeof(*ppdev) * nfds); 121195957Salfred if (ppdev == NULL) 122195957Salfred return (LIBUSB_ERROR_NO_MEM); 123195957Salfred 124195957Salfred TAILQ_FOREACH(pfd, &ctx->pollfds, entry) { 125195957Salfred fds[i].fd = pfd->pollfd.fd; 126195957Salfred fds[i].events = pfd->pollfd.events; 127195957Salfred fds[i].revents = 0; 128195957Salfred ppdev[i] = pfd->pdev; 129195957Salfred if (pfd->pdev != NULL) 130195957Salfred libusb_get_device(pfd->pdev)->refcnt++; 131194676Sthompsa i++; 132194676Sthompsa } 133194676Sthompsa 134195957Salfred if (tv == NULL) 135195957Salfred timeout = -1; 136195957Salfred else 137195957Salfred timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000); 138194676Sthompsa 139195957Salfred CTX_UNLOCK(ctx); 140195957Salfred err = poll(fds, nfds, timeout); 141195957Salfred CTX_LOCK(ctx); 142194676Sthompsa 143195957Salfred if ((err == -1) && (errno == EINTR)) 144195957Salfred err = LIBUSB_ERROR_INTERRUPTED; 145195957Salfred else if (err < 0) 146195957Salfred err = LIBUSB_ERROR_IO; 147194676Sthompsa 148195957Salfred if (err < 1) { 149213849Shselasky for (i = 0; i != (int)nfds; i++) { 150195957Salfred if (ppdev[i] != NULL) { 151195957Salfred CTX_UNLOCK(ctx); 152195957Salfred libusb_unref_device(libusb_get_device(ppdev[i])); 153195957Salfred CTX_LOCK(ctx); 154195957Salfred } 155194676Sthompsa } 156195957Salfred goto do_done; 157194676Sthompsa } 158213849Shselasky for (i = 0; i != (int)nfds; i++) { 159195957Salfred if (ppdev[i] != NULL) { 160195957Salfred dev = libusb_get_device(ppdev[i]); 161194676Sthompsa 162199055Sthompsa if (fds[i].revents == 0) 163199055Sthompsa err = 0; /* nothing to do */ 164199055Sthompsa else 165199055Sthompsa err = libusb20_dev_process(ppdev[i]); 166199055Sthompsa 167195957Salfred if (err) { 168195957Salfred /* cancel all transfers - device is gone */ 169195957Salfred libusb10_cancel_all_transfer(dev); 170199055Sthompsa 171199055Sthompsa /* remove USB device from polling loop */ 172195957Salfred libusb10_remove_pollfd(dev->ctx, &dev->dev_poll); 173195957Salfred } 174195957Salfred CTX_UNLOCK(ctx); 175195957Salfred libusb_unref_device(dev); 176195957Salfred CTX_LOCK(ctx); 177194676Sthompsa 178195957Salfred } else { 179195957Salfred uint8_t dummy; 180194676Sthompsa 181195957Salfred while (1) { 182195957Salfred if (read(fds[i].fd, &dummy, 1) != 1) 183195957Salfred break; 184195957Salfred } 185194676Sthompsa } 186195957Salfred } 187194676Sthompsa 188195957Salfred err = 0; 189194676Sthompsa 190195957Salfreddo_done: 191194676Sthompsa 192195957Salfred /* Do all done callbacks */ 193194676Sthompsa 194195957Salfred while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) { 195215253Shselasky uint8_t flags; 196215253Shselasky 197195957Salfred TAILQ_REMOVE(&ctx->tr_done, sxfer, entry); 198195957Salfred sxfer->entry.tqe_prev = NULL; 199194676Sthompsa 200195957Salfred ctx->tr_done_ref++; 201195957Salfred 202195957Salfred CTX_UNLOCK(ctx); 203195957Salfred 204195957Salfred uxfer = (struct libusb_transfer *)( 205195957Salfred ((uint8_t *)sxfer) + sizeof(*sxfer)); 206195957Salfred 207215253Shselasky /* Allow the callback to free the transfer itself. */ 208215253Shselasky flags = uxfer->flags; 209215253Shselasky 210195957Salfred if (uxfer->callback != NULL) 211195957Salfred (uxfer->callback) (uxfer); 212195957Salfred 213215253Shselasky /* Check if the USB transfer should be automatically freed. */ 214215253Shselasky if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) 215195957Salfred libusb_free_transfer(uxfer); 216195957Salfred 217195957Salfred CTX_LOCK(ctx); 218195957Salfred 219195957Salfred ctx->tr_done_ref--; 220195957Salfred ctx->tr_done_gen++; 221194676Sthompsa } 222194676Sthompsa 223195957Salfred /* Wakeup other waiters */ 224195957Salfred pthread_cond_broadcast(&ctx->ctx_cond); 225194676Sthompsa 226195957Salfred return (err); 227194676Sthompsa} 228194676Sthompsa 229194676Sthompsa/* Polling and timing */ 230194676Sthompsa 231194676Sthompsaint 232195957Salfredlibusb_try_lock_events(libusb_context *ctx) 233194676Sthompsa{ 234195957Salfred int err; 235194676Sthompsa 236195957Salfred ctx = GET_CONTEXT(ctx); 237195957Salfred if (ctx == NULL) 238194676Sthompsa return (1); 239194676Sthompsa 240195957Salfred err = CTX_TRYLOCK(ctx); 241195957Salfred if (err) 242194676Sthompsa return (1); 243194676Sthompsa 244195957Salfred err = (ctx->ctx_handler != NO_THREAD); 245195957Salfred if (err) 246195957Salfred CTX_UNLOCK(ctx); 247195957Salfred else 248195957Salfred ctx->ctx_handler = pthread_self(); 249195957Salfred 250195957Salfred return (err); 251194676Sthompsa} 252194676Sthompsa 253194676Sthompsavoid 254195957Salfredlibusb_lock_events(libusb_context *ctx) 255194676Sthompsa{ 256195957Salfred ctx = GET_CONTEXT(ctx); 257195957Salfred CTX_LOCK(ctx); 258195957Salfred if (ctx->ctx_handler == NO_THREAD) 259195957Salfred ctx->ctx_handler = pthread_self(); 260194676Sthompsa} 261194676Sthompsa 262194676Sthompsavoid 263195957Salfredlibusb_unlock_events(libusb_context *ctx) 264194676Sthompsa{ 265195957Salfred ctx = GET_CONTEXT(ctx); 266195957Salfred if (ctx->ctx_handler == pthread_self()) { 267195957Salfred ctx->ctx_handler = NO_THREAD; 268195957Salfred pthread_cond_broadcast(&ctx->ctx_cond); 269195957Salfred } 270195957Salfred CTX_UNLOCK(ctx); 271194676Sthompsa} 272194676Sthompsa 273194676Sthompsaint 274195957Salfredlibusb_event_handling_ok(libusb_context *ctx) 275194676Sthompsa{ 276195957Salfred ctx = GET_CONTEXT(ctx); 277195957Salfred return (ctx->ctx_handler == pthread_self()); 278194676Sthompsa} 279194676Sthompsa 280194676Sthompsaint 281195957Salfredlibusb_event_handler_active(libusb_context *ctx) 282194676Sthompsa{ 283195957Salfred ctx = GET_CONTEXT(ctx); 284195957Salfred return (ctx->ctx_handler != NO_THREAD); 285194676Sthompsa} 286194676Sthompsa 287194676Sthompsavoid 288195957Salfredlibusb_lock_event_waiters(libusb_context *ctx) 289194676Sthompsa{ 290195957Salfred ctx = GET_CONTEXT(ctx); 291195957Salfred CTX_LOCK(ctx); 292194676Sthompsa} 293194676Sthompsa 294194676Sthompsavoid 295195957Salfredlibusb_unlock_event_waiters(libusb_context *ctx) 296194676Sthompsa{ 297195957Salfred ctx = GET_CONTEXT(ctx); 298195957Salfred CTX_UNLOCK(ctx); 299194676Sthompsa} 300194676Sthompsa 301194676Sthompsaint 302195957Salfredlibusb_wait_for_event(libusb_context *ctx, struct timeval *tv) 303194676Sthompsa{ 304194676Sthompsa struct timespec ts; 305195957Salfred int err; 306194676Sthompsa 307195957Salfred ctx = GET_CONTEXT(ctx); 308195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter"); 309194676Sthompsa 310194676Sthompsa if (tv == NULL) { 311195957Salfred pthread_cond_wait(&ctx->ctx_cond, 312195957Salfred &ctx->ctx_lock); 313194676Sthompsa return (0); 314194676Sthompsa } 315236944Shselasky err = clock_gettime(CLOCK_MONOTONIC, &ts); 316195957Salfred if (err < 0) 317194676Sthompsa return (LIBUSB_ERROR_OTHER); 318194676Sthompsa 319236944Shselasky /* 320236944Shselasky * The "tv" arguments points to a relative time structure and 321236944Shselasky * not an absolute time structure. 322236944Shselasky */ 323236944Shselasky ts.tv_sec += tv->tv_sec; 324236944Shselasky ts.tv_nsec += tv->tv_usec * 1000; 325195957Salfred if (ts.tv_nsec >= 1000000000) { 326194676Sthompsa ts.tv_nsec -= 1000000000; 327194676Sthompsa ts.tv_sec++; 328194676Sthompsa } 329195957Salfred err = pthread_cond_timedwait(&ctx->ctx_cond, 330195957Salfred &ctx->ctx_lock, &ts); 331194676Sthompsa 332195957Salfred if (err == ETIMEDOUT) 333194676Sthompsa return (1); 334194676Sthompsa 335194676Sthompsa return (0); 336194676Sthompsa} 337194676Sthompsa 338194676Sthompsaint 339261482Shselaskylibusb_handle_events_timeout_completed(libusb_context *ctx, 340261482Shselasky struct timeval *tv, int *completed) 341194676Sthompsa{ 342261482Shselasky int err = 0; 343195957Salfred 344195957Salfred ctx = GET_CONTEXT(ctx); 345195957Salfred 346261482Shselasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter"); 347194676Sthompsa 348195957Salfred libusb_lock_events(ctx); 349194676Sthompsa 350261482Shselasky while (1) { 351261482Shselasky if (completed != NULL) { 352261482Shselasky if (*completed != 0 || err != 0) 353261482Shselasky break; 354261482Shselasky } 355261482Shselasky err = libusb_handle_events_locked(ctx, tv); 356261482Shselasky if (completed == NULL) 357261482Shselasky break; 358261482Shselasky } 359194676Sthompsa 360195957Salfred libusb_unlock_events(ctx); 361194676Sthompsa 362261482Shselasky DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit"); 363195957Salfred 364195957Salfred return (err); 365194676Sthompsa} 366194676Sthompsa 367194676Sthompsaint 368261482Shselaskylibusb_handle_events_completed(libusb_context *ctx, int *completed) 369261482Shselasky{ 370261482Shselasky return (libusb_handle_events_timeout_completed(ctx, NULL, completed)); 371261482Shselasky} 372261482Shselasky 373261482Shselaskyint 374261482Shselaskylibusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv) 375261482Shselasky{ 376261482Shselasky return (libusb_handle_events_timeout_completed(ctx, tv, NULL)); 377261482Shselasky} 378261482Shselasky 379261482Shselaskyint 380195957Salfredlibusb_handle_events(libusb_context *ctx) 381194676Sthompsa{ 382261482Shselasky return (libusb_handle_events_timeout_completed(ctx, NULL, NULL)); 383194676Sthompsa} 384194676Sthompsa 385194676Sthompsaint 386195957Salfredlibusb_handle_events_locked(libusb_context *ctx, struct timeval *tv) 387194676Sthompsa{ 388195957Salfred int err; 389194676Sthompsa 390195957Salfred ctx = GET_CONTEXT(ctx); 391194676Sthompsa 392195957Salfred if (libusb_event_handling_ok(ctx)) { 393195957Salfred err = libusb10_handle_events_sub(ctx, tv); 394195957Salfred } else { 395261482Shselasky err = libusb_wait_for_event(ctx, tv); 396261482Shselasky if (err != 0) 397261482Shselasky err = LIBUSB_ERROR_TIMEOUT; 398194676Sthompsa } 399195957Salfred return (err); 400194676Sthompsa} 401194676Sthompsa 402194676Sthompsaint 403195957Salfredlibusb_get_next_timeout(libusb_context *ctx, struct timeval *tv) 404194676Sthompsa{ 405195957Salfred /* all timeouts are currently being done by the kernel */ 406195957Salfred timerclear(tv); 407195957Salfred return (0); 408194676Sthompsa} 409194676Sthompsa 410194676Sthompsavoid 411195957Salfredlibusb_set_pollfd_notifiers(libusb_context *ctx, 412194676Sthompsa libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, 413194676Sthompsa void *user_data) 414194676Sthompsa{ 415195957Salfred ctx = GET_CONTEXT(ctx); 416194676Sthompsa 417194676Sthompsa ctx->fd_added_cb = added_cb; 418194676Sthompsa ctx->fd_removed_cb = removed_cb; 419194676Sthompsa ctx->fd_cb_user_data = user_data; 420194676Sthompsa} 421194676Sthompsa 422250335Semasteconst struct libusb_pollfd ** 423195957Salfredlibusb_get_pollfds(libusb_context *ctx) 424194676Sthompsa{ 425195957Salfred struct libusb_super_pollfd *pollfd; 426194676Sthompsa libusb_pollfd **ret; 427194676Sthompsa int i; 428194676Sthompsa 429195957Salfred ctx = GET_CONTEXT(ctx); 430194676Sthompsa 431195957Salfred CTX_LOCK(ctx); 432195957Salfred 433194676Sthompsa i = 0; 434195957Salfred TAILQ_FOREACH(pollfd, &ctx->pollfds, entry) 435195957Salfred i++; 436194676Sthompsa 437195957Salfred ret = calloc(i + 1, sizeof(struct libusb_pollfd *)); 438195957Salfred if (ret == NULL) 439195957Salfred goto done; 440194676Sthompsa 441194676Sthompsa i = 0; 442195957Salfred TAILQ_FOREACH(pollfd, &ctx->pollfds, entry) 443195957Salfred ret[i++] = &pollfd->pollfd; 444194676Sthompsa ret[i] = NULL; 445194676Sthompsa 446195957Salfreddone: 447195957Salfred CTX_UNLOCK(ctx); 448250335Semaste return ((const struct libusb_pollfd **)ret); 449194676Sthompsa} 450194676Sthompsa 451194676Sthompsa 452194676Sthompsa/* Synchronous device I/O */ 453194676Sthompsa 454194676Sthompsaint 455195957Salfredlibusb_control_transfer(libusb_device_handle *devh, 456194676Sthompsa uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, 457195957Salfred uint8_t *data, uint16_t wLength, unsigned int timeout) 458194676Sthompsa{ 459195957Salfred struct LIBUSB20_CONTROL_SETUP_DECODED req; 460195957Salfred int err; 461195957Salfred uint16_t actlen; 462194676Sthompsa 463195957Salfred if (devh == NULL) 464195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 465194676Sthompsa 466195957Salfred if ((wLength != 0) && (data == NULL)) 467195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 468194676Sthompsa 469195957Salfred LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req); 470194676Sthompsa 471195957Salfred req.bmRequestType = bmRequestType; 472195957Salfred req.bRequest = bRequest; 473195957Salfred req.wValue = wValue; 474195957Salfred req.wIndex = wIndex; 475195957Salfred req.wLength = wLength; 476194676Sthompsa 477195957Salfred err = libusb20_dev_request_sync(devh, &req, data, 478195957Salfred &actlen, timeout, 0); 479194676Sthompsa 480195957Salfred if (err == LIBUSB20_ERROR_PIPE) 481195957Salfred return (LIBUSB_ERROR_PIPE); 482195957Salfred else if (err == LIBUSB20_ERROR_TIMEOUT) 483195957Salfred return (LIBUSB_ERROR_TIMEOUT); 484195957Salfred else if (err) 485195957Salfred return (LIBUSB_ERROR_NO_DEVICE); 486194676Sthompsa 487195957Salfred return (actlen); 488195957Salfred} 489194676Sthompsa 490195957Salfredstatic void 491195957Salfredlibusb10_do_transfer_cb(struct libusb_transfer *transfer) 492195957Salfred{ 493195957Salfred libusb_context *ctx; 494195957Salfred int *pdone; 495194676Sthompsa 496195957Salfred ctx = GET_CONTEXT(NULL); 497194676Sthompsa 498195957Salfred DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done"); 499194676Sthompsa 500195957Salfred pdone = transfer->user_data; 501195957Salfred *pdone = 1; 502194676Sthompsa} 503194676Sthompsa 504195957Salfred/* 505195957Salfred * TODO: Replace the following function. Allocating and freeing on a 506195957Salfred * per-transfer basis is slow. --HPS 507195957Salfred */ 508194676Sthompsastatic int 509195957Salfredlibusb10_do_transfer(libusb_device_handle *devh, 510195957Salfred uint8_t endpoint, uint8_t *data, int length, 511194676Sthompsa int *transferred, unsigned int timeout, int type) 512194676Sthompsa{ 513195957Salfred libusb_context *ctx; 514194676Sthompsa struct libusb_transfer *xfer; 515234491Shselasky int done; 516194676Sthompsa int ret; 517194676Sthompsa 518195957Salfred if (devh == NULL) 519195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 520194676Sthompsa 521195957Salfred if ((length != 0) && (data == NULL)) 522195957Salfred return (LIBUSB_ERROR_INVALID_PARAM); 523195957Salfred 524194676Sthompsa xfer = libusb_alloc_transfer(0); 525194676Sthompsa if (xfer == NULL) 526194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 527194676Sthompsa 528195957Salfred ctx = libusb_get_device(devh)->ctx; 529194676Sthompsa 530194676Sthompsa xfer->dev_handle = devh; 531194676Sthompsa xfer->endpoint = endpoint; 532194676Sthompsa xfer->type = type; 533194676Sthompsa xfer->timeout = timeout; 534194676Sthompsa xfer->buffer = data; 535194676Sthompsa xfer->length = length; 536234491Shselasky xfer->user_data = (void *)&done; 537195957Salfred xfer->callback = libusb10_do_transfer_cb; 538234491Shselasky done = 0; 539194676Sthompsa 540194676Sthompsa if ((ret = libusb_submit_transfer(xfer)) < 0) { 541194676Sthompsa libusb_free_transfer(xfer); 542194676Sthompsa return (ret); 543194676Sthompsa } 544234491Shselasky while (done == 0) { 545194676Sthompsa if ((ret = libusb_handle_events(ctx)) < 0) { 546194676Sthompsa libusb_cancel_transfer(xfer); 547195957Salfred usleep(1000); /* nice it */ 548194676Sthompsa } 549194676Sthompsa } 550194676Sthompsa 551194676Sthompsa *transferred = xfer->actual_length; 552195957Salfred 553194676Sthompsa switch (xfer->status) { 554194676Sthompsa case LIBUSB_TRANSFER_COMPLETED: 555195957Salfred ret = 0; 556194676Sthompsa break; 557194676Sthompsa case LIBUSB_TRANSFER_TIMED_OUT: 558195957Salfred ret = LIBUSB_ERROR_TIMEOUT; 559195957Salfred break; 560194676Sthompsa case LIBUSB_TRANSFER_OVERFLOW: 561195957Salfred ret = LIBUSB_ERROR_OVERFLOW; 562195957Salfred break; 563194676Sthompsa case LIBUSB_TRANSFER_STALL: 564195957Salfred ret = LIBUSB_ERROR_PIPE; 565195957Salfred break; 566194676Sthompsa case LIBUSB_TRANSFER_NO_DEVICE: 567195957Salfred ret = LIBUSB_ERROR_NO_DEVICE; 568194676Sthompsa break; 569194676Sthompsa default: 570194676Sthompsa ret = LIBUSB_ERROR_OTHER; 571195957Salfred break; 572194676Sthompsa } 573194676Sthompsa 574194676Sthompsa libusb_free_transfer(xfer); 575194676Sthompsa return (ret); 576194676Sthompsa} 577194676Sthompsa 578194676Sthompsaint 579195957Salfredlibusb_bulk_transfer(libusb_device_handle *devh, 580195957Salfred uint8_t endpoint, uint8_t *data, int length, 581194676Sthompsa int *transferred, unsigned int timeout) 582194676Sthompsa{ 583194676Sthompsa libusb_context *ctx; 584194676Sthompsa int ret; 585195957Salfred 586195957Salfred ctx = GET_CONTEXT(NULL); 587195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter"); 588194676Sthompsa 589195957Salfred ret = libusb10_do_transfer(devh, endpoint, data, length, transferred, 590194676Sthompsa timeout, LIBUSB_TRANSFER_TYPE_BULK); 591194676Sthompsa 592195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave"); 593194676Sthompsa return (ret); 594194676Sthompsa} 595194676Sthompsa 596194676Sthompsaint 597195957Salfredlibusb_interrupt_transfer(libusb_device_handle *devh, 598195957Salfred uint8_t endpoint, uint8_t *data, int length, 599194676Sthompsa int *transferred, unsigned int timeout) 600194676Sthompsa{ 601194676Sthompsa libusb_context *ctx; 602194676Sthompsa int ret; 603194676Sthompsa 604195957Salfred ctx = GET_CONTEXT(NULL); 605195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter"); 606194676Sthompsa 607195957Salfred ret = libusb10_do_transfer(devh, endpoint, data, length, transferred, 608194676Sthompsa timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT); 609194676Sthompsa 610195560Sthompsa DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave"); 611194676Sthompsa return (ret); 612194676Sthompsa} 613199055Sthompsa 614199055Sthompsauint8_t * 615234491Shselaskylibusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t off) 616199055Sthompsa{ 617199055Sthompsa uint8_t *ptr; 618199055Sthompsa uint32_t n; 619199055Sthompsa 620199055Sthompsa if (transfer->num_iso_packets < 0) 621199055Sthompsa return (NULL); 622199055Sthompsa 623234491Shselasky if (off >= (uint32_t)transfer->num_iso_packets) 624199055Sthompsa return (NULL); 625199055Sthompsa 626199055Sthompsa ptr = transfer->buffer; 627199055Sthompsa if (ptr == NULL) 628199055Sthompsa return (NULL); 629199055Sthompsa 630234491Shselasky for (n = 0; n != off; n++) { 631199055Sthompsa ptr += transfer->iso_packet_desc[n].length; 632199055Sthompsa } 633199055Sthompsa return (ptr); 634199055Sthompsa} 635199055Sthompsa 636199055Sthompsauint8_t * 637234491Shselaskylibusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t off) 638199055Sthompsa{ 639199055Sthompsa uint8_t *ptr; 640199055Sthompsa 641199055Sthompsa if (transfer->num_iso_packets < 0) 642199055Sthompsa return (NULL); 643199055Sthompsa 644234491Shselasky if (off >= (uint32_t)transfer->num_iso_packets) 645199055Sthompsa return (NULL); 646199055Sthompsa 647199055Sthompsa ptr = transfer->buffer; 648199055Sthompsa if (ptr == NULL) 649199055Sthompsa return (NULL); 650199055Sthompsa 651234491Shselasky ptr += transfer->iso_packet_desc[0].length * off; 652199055Sthompsa 653199055Sthompsa return (ptr); 654199055Sthompsa} 655199055Sthompsa 656199055Sthompsavoid 657199055Sthompsalibusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length) 658199055Sthompsa{ 659199055Sthompsa int n; 660199055Sthompsa 661199055Sthompsa if (transfer->num_iso_packets < 0) 662199055Sthompsa return; 663199055Sthompsa 664199055Sthompsa for (n = 0; n != transfer->num_iso_packets; n++) 665199055Sthompsa transfer->iso_packet_desc[n].length = length; 666199055Sthompsa} 667199055Sthompsa 668199055Sthompsauint8_t * 669199055Sthompsalibusb_control_transfer_get_data(struct libusb_transfer *transfer) 670199055Sthompsa{ 671199055Sthompsa if (transfer->buffer == NULL) 672199055Sthompsa return (NULL); 673199055Sthompsa 674199055Sthompsa return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE); 675199055Sthompsa} 676199055Sthompsa 677199055Sthompsastruct libusb_control_setup * 678199055Sthompsalibusb_control_transfer_get_setup(struct libusb_transfer *transfer) 679199055Sthompsa{ 680199055Sthompsa return ((struct libusb_control_setup *)transfer->buffer); 681199055Sthompsa} 682199055Sthompsa 683199055Sthompsavoid 684199055Sthompsalibusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType, 685199055Sthompsa uint8_t bRequest, uint16_t wValue, 686199055Sthompsa uint16_t wIndex, uint16_t wLength) 687199055Sthompsa{ 688199055Sthompsa struct libusb_control_setup *req = (struct libusb_control_setup *)buf; 689199055Sthompsa 690199055Sthompsa /* The alignment is OK for all fields below. */ 691199055Sthompsa req->bmRequestType = bmRequestType; 692199055Sthompsa req->bRequest = bRequest; 693199055Sthompsa req->wValue = htole16(wValue); 694199055Sthompsa req->wIndex = htole16(wIndex); 695199055Sthompsa req->wLength = htole16(wLength); 696199055Sthompsa} 697199055Sthompsa 698199055Sthompsavoid 699199055Sthompsalibusb_fill_control_transfer(struct libusb_transfer *transfer, 700199055Sthompsa libusb_device_handle *devh, uint8_t *buf, 701199055Sthompsa libusb_transfer_cb_fn callback, void *user_data, 702199055Sthompsa uint32_t timeout) 703199055Sthompsa{ 704199055Sthompsa struct libusb_control_setup *setup = (struct libusb_control_setup *)buf; 705199055Sthompsa 706199055Sthompsa transfer->dev_handle = devh; 707199055Sthompsa transfer->endpoint = 0; 708199055Sthompsa transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; 709199055Sthompsa transfer->timeout = timeout; 710199055Sthompsa transfer->buffer = buf; 711199055Sthompsa if (setup != NULL) 712199055Sthompsa transfer->length = LIBUSB_CONTROL_SETUP_SIZE 713199055Sthompsa + le16toh(setup->wLength); 714199055Sthompsa else 715199055Sthompsa transfer->length = 0; 716199055Sthompsa transfer->user_data = user_data; 717199055Sthompsa transfer->callback = callback; 718199055Sthompsa 719199055Sthompsa} 720199055Sthompsa 721199055Sthompsavoid 722199055Sthompsalibusb_fill_bulk_transfer(struct libusb_transfer *transfer, 723199055Sthompsa libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, 724199055Sthompsa int length, libusb_transfer_cb_fn callback, void *user_data, 725199055Sthompsa uint32_t timeout) 726199055Sthompsa{ 727199055Sthompsa transfer->dev_handle = devh; 728199055Sthompsa transfer->endpoint = endpoint; 729199055Sthompsa transfer->type = LIBUSB_TRANSFER_TYPE_BULK; 730199055Sthompsa transfer->timeout = timeout; 731199055Sthompsa transfer->buffer = buf; 732199055Sthompsa transfer->length = length; 733199055Sthompsa transfer->user_data = user_data; 734199055Sthompsa transfer->callback = callback; 735199055Sthompsa} 736199055Sthompsa 737199055Sthompsavoid 738199055Sthompsalibusb_fill_interrupt_transfer(struct libusb_transfer *transfer, 739199055Sthompsa libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, 740199055Sthompsa int length, libusb_transfer_cb_fn callback, void *user_data, 741199055Sthompsa uint32_t timeout) 742199055Sthompsa{ 743199055Sthompsa transfer->dev_handle = devh; 744199055Sthompsa transfer->endpoint = endpoint; 745199055Sthompsa transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; 746199055Sthompsa transfer->timeout = timeout; 747199055Sthompsa transfer->buffer = buf; 748199055Sthompsa transfer->length = length; 749199055Sthompsa transfer->user_data = user_data; 750199055Sthompsa transfer->callback = callback; 751199055Sthompsa} 752199055Sthompsa 753199055Sthompsavoid 754199055Sthompsalibusb_fill_iso_transfer(struct libusb_transfer *transfer, 755199055Sthompsa libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf, 756199055Sthompsa int length, int npacket, libusb_transfer_cb_fn callback, 757199055Sthompsa void *user_data, uint32_t timeout) 758199055Sthompsa{ 759199055Sthompsa transfer->dev_handle = devh; 760199055Sthompsa transfer->endpoint = endpoint; 761199055Sthompsa transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; 762199055Sthompsa transfer->timeout = timeout; 763199055Sthompsa transfer->buffer = buf; 764199055Sthompsa transfer->length = length; 765199055Sthompsa transfer->num_iso_packets = npacket; 766199055Sthompsa transfer->user_data = user_data; 767199055Sthompsa transfer->callback = callback; 768199055Sthompsa} 769199055Sthompsa 770