xref: /dflybsd-src/lib/libusb/libusb10_io.c (revision 9b0c1abe99cfd7e619068968896b466f0d1d6f69)
1*9b0c1abeSSascha Wildner /* $FreeBSD: head/lib/libusb/libusb10_io.c 260315 2014-01-05 10:41:43Z hselasky $ */
21d96047eSMarkus Pfeiffer /*-
31d96047eSMarkus Pfeiffer  * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
41d96047eSMarkus Pfeiffer  *
51d96047eSMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
61d96047eSMarkus Pfeiffer  * modification, are permitted provided that the following conditions
71d96047eSMarkus Pfeiffer  * are met:
81d96047eSMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
91d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
101d96047eSMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
111d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
121d96047eSMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
131d96047eSMarkus Pfeiffer  *
141d96047eSMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151d96047eSMarkus Pfeiffer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161d96047eSMarkus Pfeiffer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171d96047eSMarkus Pfeiffer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181d96047eSMarkus Pfeiffer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191d96047eSMarkus Pfeiffer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201d96047eSMarkus Pfeiffer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211d96047eSMarkus Pfeiffer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221d96047eSMarkus Pfeiffer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231d96047eSMarkus Pfeiffer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241d96047eSMarkus Pfeiffer  * SUCH DAMAGE.
251d96047eSMarkus Pfeiffer  */
261d96047eSMarkus Pfeiffer 
27*9b0c1abeSSascha Wildner #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
28*9b0c1abeSSascha Wildner #include LIBUSB_GLOBAL_INCLUDE_FILE
29*9b0c1abeSSascha Wildner #else
301d96047eSMarkus Pfeiffer #include <errno.h>
311d96047eSMarkus Pfeiffer #include <poll.h>
321d96047eSMarkus Pfeiffer #include <pthread.h>
331d96047eSMarkus Pfeiffer #include <stdio.h>
341d96047eSMarkus Pfeiffer #include <stdlib.h>
35*9b0c1abeSSascha Wildner #include <string.h>
361d96047eSMarkus Pfeiffer #include <time.h>
371d96047eSMarkus Pfeiffer #include <unistd.h>
38*9b0c1abeSSascha Wildner #include <sys/queue.h>
39*9b0c1abeSSascha Wildner #include <sys/endian.h>
40*9b0c1abeSSascha Wildner #endif
411d96047eSMarkus Pfeiffer 
421d96047eSMarkus Pfeiffer #define	libusb_device_handle libusb20_device
431d96047eSMarkus Pfeiffer 
441d96047eSMarkus Pfeiffer #include "libusb20.h"
451d96047eSMarkus Pfeiffer #include "libusb20_desc.h"
461d96047eSMarkus Pfeiffer #include "libusb20_int.h"
471d96047eSMarkus Pfeiffer #include "libusb.h"
481d96047eSMarkus Pfeiffer #include "libusb10.h"
491d96047eSMarkus Pfeiffer 
501d96047eSMarkus Pfeiffer UNEXPORTED void
libusb10_add_pollfd(libusb_context * ctx,struct libusb_super_pollfd * pollfd,struct libusb20_device * pdev,int fd,short events)511d96047eSMarkus Pfeiffer libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd,
521d96047eSMarkus Pfeiffer     struct libusb20_device *pdev, int fd, short events)
531d96047eSMarkus Pfeiffer {
541d96047eSMarkus Pfeiffer 	if (ctx == NULL)
551d96047eSMarkus Pfeiffer 		return;			/* invalid */
561d96047eSMarkus Pfeiffer 
571d96047eSMarkus Pfeiffer 	if (pollfd->entry.tqe_prev != NULL)
581d96047eSMarkus Pfeiffer 		return;			/* already queued */
591d96047eSMarkus Pfeiffer 
601d96047eSMarkus Pfeiffer 	if (fd < 0)
611d96047eSMarkus Pfeiffer 		return;			/* invalid */
621d96047eSMarkus Pfeiffer 
631d96047eSMarkus Pfeiffer 	pollfd->pdev = pdev;
641d96047eSMarkus Pfeiffer 	pollfd->pollfd.fd = fd;
651d96047eSMarkus Pfeiffer 	pollfd->pollfd.events = events;
661d96047eSMarkus Pfeiffer 
671d96047eSMarkus Pfeiffer 	CTX_LOCK(ctx);
681d96047eSMarkus Pfeiffer 	TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry);
691d96047eSMarkus Pfeiffer 	CTX_UNLOCK(ctx);
701d96047eSMarkus Pfeiffer 
711d96047eSMarkus Pfeiffer 	if (ctx->fd_added_cb)
721d96047eSMarkus Pfeiffer 		ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
731d96047eSMarkus Pfeiffer }
741d96047eSMarkus Pfeiffer 
751d96047eSMarkus Pfeiffer UNEXPORTED void
libusb10_remove_pollfd(libusb_context * ctx,struct libusb_super_pollfd * pollfd)761d96047eSMarkus Pfeiffer libusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd)
771d96047eSMarkus Pfeiffer {
781d96047eSMarkus Pfeiffer 	if (ctx == NULL)
791d96047eSMarkus Pfeiffer 		return;			/* invalid */
801d96047eSMarkus Pfeiffer 
811d96047eSMarkus Pfeiffer 	if (pollfd->entry.tqe_prev == NULL)
821d96047eSMarkus Pfeiffer 		return;			/* already dequeued */
831d96047eSMarkus Pfeiffer 
841d96047eSMarkus Pfeiffer 	CTX_LOCK(ctx);
851d96047eSMarkus Pfeiffer 	TAILQ_REMOVE(&ctx->pollfds, pollfd, entry);
861d96047eSMarkus Pfeiffer 	pollfd->entry.tqe_prev = NULL;
871d96047eSMarkus Pfeiffer 	CTX_UNLOCK(ctx);
881d96047eSMarkus Pfeiffer 
891d96047eSMarkus Pfeiffer 	if (ctx->fd_removed_cb)
901d96047eSMarkus Pfeiffer 		ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data);
911d96047eSMarkus Pfeiffer }
921d96047eSMarkus Pfeiffer 
931d96047eSMarkus Pfeiffer /* This function must be called locked */
941d96047eSMarkus Pfeiffer 
951d96047eSMarkus Pfeiffer static int
libusb10_handle_events_sub(struct libusb_context * ctx,struct timeval * tv)961d96047eSMarkus Pfeiffer libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
971d96047eSMarkus Pfeiffer {
981d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
991d96047eSMarkus Pfeiffer 	struct libusb20_device **ppdev;
1001d96047eSMarkus Pfeiffer 	struct libusb_super_pollfd *pfd;
1011d96047eSMarkus Pfeiffer 	struct pollfd *fds;
1021d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
1031d96047eSMarkus Pfeiffer 	struct libusb_transfer *uxfer;
1041d96047eSMarkus Pfeiffer 	nfds_t nfds;
1051d96047eSMarkus Pfeiffer 	int timeout;
1061d96047eSMarkus Pfeiffer 	int i;
1071d96047eSMarkus Pfeiffer 	int err;
1081d96047eSMarkus Pfeiffer 
1091d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
1101d96047eSMarkus Pfeiffer 
1111d96047eSMarkus Pfeiffer 	nfds = 0;
1121d96047eSMarkus Pfeiffer 	i = 0;
1131d96047eSMarkus Pfeiffer 	TAILQ_FOREACH(pfd, &ctx->pollfds, entry)
1141d96047eSMarkus Pfeiffer 	    nfds++;
1151d96047eSMarkus Pfeiffer 
1161d96047eSMarkus Pfeiffer 	fds = alloca(sizeof(*fds) * nfds);
1171d96047eSMarkus Pfeiffer 	if (fds == NULL)
1181d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_MEM);
1191d96047eSMarkus Pfeiffer 
1201d96047eSMarkus Pfeiffer 	ppdev = alloca(sizeof(*ppdev) * nfds);
1211d96047eSMarkus Pfeiffer 	if (ppdev == NULL)
1221d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_MEM);
1231d96047eSMarkus Pfeiffer 
1241d96047eSMarkus Pfeiffer 	TAILQ_FOREACH(pfd, &ctx->pollfds, entry) {
1251d96047eSMarkus Pfeiffer 		fds[i].fd = pfd->pollfd.fd;
1261d96047eSMarkus Pfeiffer 		fds[i].events = pfd->pollfd.events;
1271d96047eSMarkus Pfeiffer 		fds[i].revents = 0;
1281d96047eSMarkus Pfeiffer 		ppdev[i] = pfd->pdev;
1291d96047eSMarkus Pfeiffer 		if (pfd->pdev != NULL)
1301d96047eSMarkus Pfeiffer 			libusb_get_device(pfd->pdev)->refcnt++;
1311d96047eSMarkus Pfeiffer 		i++;
1321d96047eSMarkus Pfeiffer 	}
1331d96047eSMarkus Pfeiffer 
1341d96047eSMarkus Pfeiffer 	if (tv == NULL)
1351d96047eSMarkus Pfeiffer 		timeout = -1;
1361d96047eSMarkus Pfeiffer 	else
1371d96047eSMarkus Pfeiffer 		timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
1381d96047eSMarkus Pfeiffer 
1391d96047eSMarkus Pfeiffer 	CTX_UNLOCK(ctx);
1401d96047eSMarkus Pfeiffer 	err = poll(fds, nfds, timeout);
1411d96047eSMarkus Pfeiffer 	CTX_LOCK(ctx);
1421d96047eSMarkus Pfeiffer 
1431d96047eSMarkus Pfeiffer 	if ((err == -1) && (errno == EINTR))
1441d96047eSMarkus Pfeiffer 		err = LIBUSB_ERROR_INTERRUPTED;
1451d96047eSMarkus Pfeiffer 	else if (err < 0)
1461d96047eSMarkus Pfeiffer 		err = LIBUSB_ERROR_IO;
1471d96047eSMarkus Pfeiffer 
1481d96047eSMarkus Pfeiffer 	if (err < 1) {
1491d96047eSMarkus Pfeiffer 		for (i = 0; i != (int)nfds; i++) {
1501d96047eSMarkus Pfeiffer 			if (ppdev[i] != NULL) {
1511d96047eSMarkus Pfeiffer 				CTX_UNLOCK(ctx);
1521d96047eSMarkus Pfeiffer 				libusb_unref_device(libusb_get_device(ppdev[i]));
1531d96047eSMarkus Pfeiffer 				CTX_LOCK(ctx);
1541d96047eSMarkus Pfeiffer 			}
1551d96047eSMarkus Pfeiffer 		}
1561d96047eSMarkus Pfeiffer 		goto do_done;
1571d96047eSMarkus Pfeiffer 	}
1581d96047eSMarkus Pfeiffer 	for (i = 0; i != (int)nfds; i++) {
1591d96047eSMarkus Pfeiffer 		if (ppdev[i] != NULL) {
1601d96047eSMarkus Pfeiffer 			dev = libusb_get_device(ppdev[i]);
1611d96047eSMarkus Pfeiffer 
1621d96047eSMarkus Pfeiffer 			if (fds[i].revents == 0)
1631d96047eSMarkus Pfeiffer 				err = 0;	/* nothing to do */
1641d96047eSMarkus Pfeiffer 			else
1651d96047eSMarkus Pfeiffer 				err = libusb20_dev_process(ppdev[i]);
1661d96047eSMarkus Pfeiffer 
1671d96047eSMarkus Pfeiffer 			if (err) {
1681d96047eSMarkus Pfeiffer 				/* cancel all transfers - device is gone */
1691d96047eSMarkus Pfeiffer 				libusb10_cancel_all_transfer(dev);
1701d96047eSMarkus Pfeiffer 
1711d96047eSMarkus Pfeiffer 				/* remove USB device from polling loop */
1721d96047eSMarkus Pfeiffer 				libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
1731d96047eSMarkus Pfeiffer 			}
1741d96047eSMarkus Pfeiffer 			CTX_UNLOCK(ctx);
1751d96047eSMarkus Pfeiffer 			libusb_unref_device(dev);
1761d96047eSMarkus Pfeiffer 			CTX_LOCK(ctx);
1771d96047eSMarkus Pfeiffer 
1781d96047eSMarkus Pfeiffer 		} else {
1791d96047eSMarkus Pfeiffer 			uint8_t dummy;
1801d96047eSMarkus Pfeiffer 
1811d96047eSMarkus Pfeiffer 			while (1) {
1821d96047eSMarkus Pfeiffer 				if (read(fds[i].fd, &dummy, 1) != 1)
1831d96047eSMarkus Pfeiffer 					break;
1841d96047eSMarkus Pfeiffer 			}
1851d96047eSMarkus Pfeiffer 		}
1861d96047eSMarkus Pfeiffer 	}
1871d96047eSMarkus Pfeiffer 
1881d96047eSMarkus Pfeiffer 	err = 0;
1891d96047eSMarkus Pfeiffer 
1901d96047eSMarkus Pfeiffer do_done:
1911d96047eSMarkus Pfeiffer 
1921d96047eSMarkus Pfeiffer 	/* Do all done callbacks */
1931d96047eSMarkus Pfeiffer 
1941d96047eSMarkus Pfeiffer 	while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
1951d96047eSMarkus Pfeiffer 		uint8_t flags;
1961d96047eSMarkus Pfeiffer 
1971d96047eSMarkus Pfeiffer 		TAILQ_REMOVE(&ctx->tr_done, sxfer, entry);
1981d96047eSMarkus Pfeiffer 		sxfer->entry.tqe_prev = NULL;
1991d96047eSMarkus Pfeiffer 
2001d96047eSMarkus Pfeiffer 		ctx->tr_done_ref++;
2011d96047eSMarkus Pfeiffer 
2021d96047eSMarkus Pfeiffer 		CTX_UNLOCK(ctx);
2031d96047eSMarkus Pfeiffer 
2041d96047eSMarkus Pfeiffer 		uxfer = (struct libusb_transfer *)(
2051d96047eSMarkus Pfeiffer 		    ((uint8_t *)sxfer) + sizeof(*sxfer));
2061d96047eSMarkus Pfeiffer 
2071d96047eSMarkus Pfeiffer 		/* Allow the callback to free the transfer itself. */
2081d96047eSMarkus Pfeiffer 		flags = uxfer->flags;
2091d96047eSMarkus Pfeiffer 
2101d96047eSMarkus Pfeiffer 		if (uxfer->callback != NULL)
2111d96047eSMarkus Pfeiffer 			(uxfer->callback) (uxfer);
2121d96047eSMarkus Pfeiffer 
2131d96047eSMarkus Pfeiffer 		/* Check if the USB transfer should be automatically freed. */
2141d96047eSMarkus Pfeiffer 		if (flags & LIBUSB_TRANSFER_FREE_TRANSFER)
2151d96047eSMarkus Pfeiffer 			libusb_free_transfer(uxfer);
2161d96047eSMarkus Pfeiffer 
2171d96047eSMarkus Pfeiffer 		CTX_LOCK(ctx);
2181d96047eSMarkus Pfeiffer 
2191d96047eSMarkus Pfeiffer 		ctx->tr_done_ref--;
2201d96047eSMarkus Pfeiffer 		ctx->tr_done_gen++;
2211d96047eSMarkus Pfeiffer 	}
2221d96047eSMarkus Pfeiffer 
2231d96047eSMarkus Pfeiffer 	/* Wakeup other waiters */
2241d96047eSMarkus Pfeiffer 	pthread_cond_broadcast(&ctx->ctx_cond);
2251d96047eSMarkus Pfeiffer 
2261d96047eSMarkus Pfeiffer 	return (err);
2271d96047eSMarkus Pfeiffer }
2281d96047eSMarkus Pfeiffer 
2291d96047eSMarkus Pfeiffer /* Polling and timing */
2301d96047eSMarkus Pfeiffer 
2311d96047eSMarkus Pfeiffer int
libusb_try_lock_events(libusb_context * ctx)2321d96047eSMarkus Pfeiffer libusb_try_lock_events(libusb_context *ctx)
2331d96047eSMarkus Pfeiffer {
2341d96047eSMarkus Pfeiffer 	int err;
2351d96047eSMarkus Pfeiffer 
2361d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2371d96047eSMarkus Pfeiffer 	if (ctx == NULL)
2381d96047eSMarkus Pfeiffer 		return (1);
2391d96047eSMarkus Pfeiffer 
2401d96047eSMarkus Pfeiffer 	err = CTX_TRYLOCK(ctx);
2411d96047eSMarkus Pfeiffer 	if (err)
2421d96047eSMarkus Pfeiffer 		return (1);
2431d96047eSMarkus Pfeiffer 
2441d96047eSMarkus Pfeiffer 	err = (ctx->ctx_handler != NO_THREAD);
2451d96047eSMarkus Pfeiffer 	if (err)
2461d96047eSMarkus Pfeiffer 		CTX_UNLOCK(ctx);
2471d96047eSMarkus Pfeiffer 	else
2481d96047eSMarkus Pfeiffer 		ctx->ctx_handler = pthread_self();
2491d96047eSMarkus Pfeiffer 
2501d96047eSMarkus Pfeiffer 	return (err);
2511d96047eSMarkus Pfeiffer }
2521d96047eSMarkus Pfeiffer 
2531d96047eSMarkus Pfeiffer void
libusb_lock_events(libusb_context * ctx)2541d96047eSMarkus Pfeiffer libusb_lock_events(libusb_context *ctx)
2551d96047eSMarkus Pfeiffer {
2561d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2571d96047eSMarkus Pfeiffer 	CTX_LOCK(ctx);
2581d96047eSMarkus Pfeiffer 	if (ctx->ctx_handler == NO_THREAD)
2591d96047eSMarkus Pfeiffer 		ctx->ctx_handler = pthread_self();
2601d96047eSMarkus Pfeiffer }
2611d96047eSMarkus Pfeiffer 
2621d96047eSMarkus Pfeiffer void
libusb_unlock_events(libusb_context * ctx)2631d96047eSMarkus Pfeiffer libusb_unlock_events(libusb_context *ctx)
2641d96047eSMarkus Pfeiffer {
2651d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2661d96047eSMarkus Pfeiffer 	if (ctx->ctx_handler == pthread_self()) {
2671d96047eSMarkus Pfeiffer 		ctx->ctx_handler = NO_THREAD;
2681d96047eSMarkus Pfeiffer 		pthread_cond_broadcast(&ctx->ctx_cond);
2691d96047eSMarkus Pfeiffer 	}
2701d96047eSMarkus Pfeiffer 	CTX_UNLOCK(ctx);
2711d96047eSMarkus Pfeiffer }
2721d96047eSMarkus Pfeiffer 
2731d96047eSMarkus Pfeiffer int
libusb_event_handling_ok(libusb_context * ctx)2741d96047eSMarkus Pfeiffer libusb_event_handling_ok(libusb_context *ctx)
2751d96047eSMarkus Pfeiffer {
2761d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2771d96047eSMarkus Pfeiffer 	return (ctx->ctx_handler == pthread_self());
2781d96047eSMarkus Pfeiffer }
2791d96047eSMarkus Pfeiffer 
2801d96047eSMarkus Pfeiffer int
libusb_event_handler_active(libusb_context * ctx)2811d96047eSMarkus Pfeiffer libusb_event_handler_active(libusb_context *ctx)
2821d96047eSMarkus Pfeiffer {
2831d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2841d96047eSMarkus Pfeiffer 	return (ctx->ctx_handler != NO_THREAD);
2851d96047eSMarkus Pfeiffer }
2861d96047eSMarkus Pfeiffer 
2871d96047eSMarkus Pfeiffer void
libusb_lock_event_waiters(libusb_context * ctx)2881d96047eSMarkus Pfeiffer libusb_lock_event_waiters(libusb_context *ctx)
2891d96047eSMarkus Pfeiffer {
2901d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2911d96047eSMarkus Pfeiffer 	CTX_LOCK(ctx);
2921d96047eSMarkus Pfeiffer }
2931d96047eSMarkus Pfeiffer 
2941d96047eSMarkus Pfeiffer void
libusb_unlock_event_waiters(libusb_context * ctx)2951d96047eSMarkus Pfeiffer libusb_unlock_event_waiters(libusb_context *ctx)
2961d96047eSMarkus Pfeiffer {
2971d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2981d96047eSMarkus Pfeiffer 	CTX_UNLOCK(ctx);
2991d96047eSMarkus Pfeiffer }
3001d96047eSMarkus Pfeiffer 
3011d96047eSMarkus Pfeiffer int
libusb_wait_for_event(libusb_context * ctx,struct timeval * tv)3021d96047eSMarkus Pfeiffer libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
3031d96047eSMarkus Pfeiffer {
3041d96047eSMarkus Pfeiffer 	struct timespec ts;
3051d96047eSMarkus Pfeiffer 	int err;
3061d96047eSMarkus Pfeiffer 
3071d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
3081d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
3091d96047eSMarkus Pfeiffer 
3101d96047eSMarkus Pfeiffer 	if (tv == NULL) {
3111d96047eSMarkus Pfeiffer 		pthread_cond_wait(&ctx->ctx_cond,
3121d96047eSMarkus Pfeiffer 		    &ctx->ctx_lock);
3131d96047eSMarkus Pfeiffer 		return (0);
3141d96047eSMarkus Pfeiffer 	}
315aa3e5c14SSascha Wildner 	err = clock_gettime(CLOCK_MONOTONIC, &ts);
3161d96047eSMarkus Pfeiffer 	if (err < 0)
3171d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_OTHER);
3181d96047eSMarkus Pfeiffer 
319aa3e5c14SSascha Wildner 	/*
320aa3e5c14SSascha Wildner 	 * The "tv" arguments points to a relative time structure and
321aa3e5c14SSascha Wildner 	 * not an absolute time structure.
322aa3e5c14SSascha Wildner 	 */
323aa3e5c14SSascha Wildner 	ts.tv_sec += tv->tv_sec;
324aa3e5c14SSascha Wildner 	ts.tv_nsec += tv->tv_usec * 1000;
3251d96047eSMarkus Pfeiffer 	if (ts.tv_nsec >= 1000000000) {
3261d96047eSMarkus Pfeiffer 		ts.tv_nsec -= 1000000000;
3271d96047eSMarkus Pfeiffer 		ts.tv_sec++;
3281d96047eSMarkus Pfeiffer 	}
3291d96047eSMarkus Pfeiffer 	err = pthread_cond_timedwait(&ctx->ctx_cond,
3301d96047eSMarkus Pfeiffer 	    &ctx->ctx_lock, &ts);
3311d96047eSMarkus Pfeiffer 
3321d96047eSMarkus Pfeiffer 	if (err == ETIMEDOUT)
3331d96047eSMarkus Pfeiffer 		return (1);
3341d96047eSMarkus Pfeiffer 
3351d96047eSMarkus Pfeiffer 	return (0);
3361d96047eSMarkus Pfeiffer }
3371d96047eSMarkus Pfeiffer 
3381d96047eSMarkus Pfeiffer int
libusb_handle_events_timeout_completed(libusb_context * ctx,struct timeval * tv,int * completed)339*9b0c1abeSSascha Wildner libusb_handle_events_timeout_completed(libusb_context *ctx,
340*9b0c1abeSSascha Wildner     struct timeval *tv, int *completed)
3411d96047eSMarkus Pfeiffer {
342*9b0c1abeSSascha Wildner 	int err = 0;
3431d96047eSMarkus Pfeiffer 
3441d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
3451d96047eSMarkus Pfeiffer 
346*9b0c1abeSSascha Wildner 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter");
3471d96047eSMarkus Pfeiffer 
3481d96047eSMarkus Pfeiffer 	libusb_lock_events(ctx);
3491d96047eSMarkus Pfeiffer 
350*9b0c1abeSSascha Wildner 	while (1) {
351*9b0c1abeSSascha Wildner 		if (completed != NULL) {
352*9b0c1abeSSascha Wildner 			if (*completed != 0 || err != 0)
353*9b0c1abeSSascha Wildner 				break;
354*9b0c1abeSSascha Wildner 		}
3551d96047eSMarkus Pfeiffer 		err = libusb_handle_events_locked(ctx, tv);
356*9b0c1abeSSascha Wildner 		if (completed == NULL)
357*9b0c1abeSSascha Wildner 			break;
358*9b0c1abeSSascha Wildner 	}
3591d96047eSMarkus Pfeiffer 
3601d96047eSMarkus Pfeiffer 	libusb_unlock_events(ctx);
3611d96047eSMarkus Pfeiffer 
362*9b0c1abeSSascha Wildner 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit");
3631d96047eSMarkus Pfeiffer 
3641d96047eSMarkus Pfeiffer 	return (err);
3651d96047eSMarkus Pfeiffer }
3661d96047eSMarkus Pfeiffer 
3671d96047eSMarkus Pfeiffer int
libusb_handle_events_completed(libusb_context * ctx,int * completed)368*9b0c1abeSSascha Wildner libusb_handle_events_completed(libusb_context *ctx, int *completed)
369*9b0c1abeSSascha Wildner {
370*9b0c1abeSSascha Wildner 	return (libusb_handle_events_timeout_completed(ctx, NULL, completed));
371*9b0c1abeSSascha Wildner }
372*9b0c1abeSSascha Wildner 
373*9b0c1abeSSascha Wildner int
libusb_handle_events_timeout(libusb_context * ctx,struct timeval * tv)374*9b0c1abeSSascha Wildner libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
375*9b0c1abeSSascha Wildner {
376*9b0c1abeSSascha Wildner 	return (libusb_handle_events_timeout_completed(ctx, tv, NULL));
377*9b0c1abeSSascha Wildner }
378*9b0c1abeSSascha Wildner 
379*9b0c1abeSSascha Wildner int
libusb_handle_events(libusb_context * ctx)3801d96047eSMarkus Pfeiffer libusb_handle_events(libusb_context *ctx)
3811d96047eSMarkus Pfeiffer {
382*9b0c1abeSSascha Wildner 	return (libusb_handle_events_timeout_completed(ctx, NULL, NULL));
3831d96047eSMarkus Pfeiffer }
3841d96047eSMarkus Pfeiffer 
3851d96047eSMarkus Pfeiffer int
libusb_handle_events_locked(libusb_context * ctx,struct timeval * tv)3861d96047eSMarkus Pfeiffer libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
3871d96047eSMarkus Pfeiffer {
3881d96047eSMarkus Pfeiffer 	int err;
3891d96047eSMarkus Pfeiffer 
3901d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
3911d96047eSMarkus Pfeiffer 
3921d96047eSMarkus Pfeiffer 	if (libusb_event_handling_ok(ctx)) {
3931d96047eSMarkus Pfeiffer 		err = libusb10_handle_events_sub(ctx, tv);
3941d96047eSMarkus Pfeiffer 	} else {
395*9b0c1abeSSascha Wildner 		err = libusb_wait_for_event(ctx, tv);
396*9b0c1abeSSascha Wildner 		if (err != 0)
397*9b0c1abeSSascha Wildner 			err = LIBUSB_ERROR_TIMEOUT;
3981d96047eSMarkus Pfeiffer 	}
3991d96047eSMarkus Pfeiffer 	return (err);
4001d96047eSMarkus Pfeiffer }
4011d96047eSMarkus Pfeiffer 
4021d96047eSMarkus Pfeiffer int
libusb_get_next_timeout(libusb_context * ctx,struct timeval * tv)4031d96047eSMarkus Pfeiffer libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
4041d96047eSMarkus Pfeiffer {
4051d96047eSMarkus Pfeiffer 	/* all timeouts are currently being done by the kernel */
4061d96047eSMarkus Pfeiffer 	timerclear(tv);
4071d96047eSMarkus Pfeiffer 	return (0);
4081d96047eSMarkus Pfeiffer }
4091d96047eSMarkus Pfeiffer 
4101d96047eSMarkus Pfeiffer void
libusb_set_pollfd_notifiers(libusb_context * ctx,libusb_pollfd_added_cb added_cb,libusb_pollfd_removed_cb removed_cb,void * user_data)4111d96047eSMarkus Pfeiffer libusb_set_pollfd_notifiers(libusb_context *ctx,
4121d96047eSMarkus Pfeiffer     libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
4131d96047eSMarkus Pfeiffer     void *user_data)
4141d96047eSMarkus Pfeiffer {
4151d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
4161d96047eSMarkus Pfeiffer 
4171d96047eSMarkus Pfeiffer 	ctx->fd_added_cb = added_cb;
4181d96047eSMarkus Pfeiffer 	ctx->fd_removed_cb = removed_cb;
4191d96047eSMarkus Pfeiffer 	ctx->fd_cb_user_data = user_data;
4201d96047eSMarkus Pfeiffer }
4211d96047eSMarkus Pfeiffer 
422*9b0c1abeSSascha Wildner const struct libusb_pollfd **
libusb_get_pollfds(libusb_context * ctx)4231d96047eSMarkus Pfeiffer libusb_get_pollfds(libusb_context *ctx)
4241d96047eSMarkus Pfeiffer {
4251d96047eSMarkus Pfeiffer 	struct libusb_super_pollfd *pollfd;
4261d96047eSMarkus Pfeiffer 	libusb_pollfd **ret;
4271d96047eSMarkus Pfeiffer 	int i;
4281d96047eSMarkus Pfeiffer 
4291d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
4301d96047eSMarkus Pfeiffer 
4311d96047eSMarkus Pfeiffer 	CTX_LOCK(ctx);
4321d96047eSMarkus Pfeiffer 
4331d96047eSMarkus Pfeiffer 	i = 0;
4341d96047eSMarkus Pfeiffer 	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
4351d96047eSMarkus Pfeiffer 	    i++;
4361d96047eSMarkus Pfeiffer 
4371d96047eSMarkus Pfeiffer 	ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
4381d96047eSMarkus Pfeiffer 	if (ret == NULL)
4391d96047eSMarkus Pfeiffer 		goto done;
4401d96047eSMarkus Pfeiffer 
4411d96047eSMarkus Pfeiffer 	i = 0;
4421d96047eSMarkus Pfeiffer 	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
4431d96047eSMarkus Pfeiffer 	    ret[i++] = &pollfd->pollfd;
4441d96047eSMarkus Pfeiffer 	ret[i] = NULL;
4451d96047eSMarkus Pfeiffer 
4461d96047eSMarkus Pfeiffer done:
4471d96047eSMarkus Pfeiffer 	CTX_UNLOCK(ctx);
448*9b0c1abeSSascha Wildner 	return ((const struct libusb_pollfd **)ret);
4491d96047eSMarkus Pfeiffer }
4501d96047eSMarkus Pfeiffer 
4511d96047eSMarkus Pfeiffer 
4521d96047eSMarkus Pfeiffer /* Synchronous device I/O */
4531d96047eSMarkus Pfeiffer 
4541d96047eSMarkus Pfeiffer int
libusb_control_transfer(libusb_device_handle * devh,uint8_t bmRequestType,uint8_t bRequest,uint16_t wValue,uint16_t wIndex,uint8_t * data,uint16_t wLength,unsigned int timeout)4551d96047eSMarkus Pfeiffer libusb_control_transfer(libusb_device_handle *devh,
4561d96047eSMarkus Pfeiffer     uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
4571d96047eSMarkus Pfeiffer     uint8_t *data, uint16_t wLength, unsigned int timeout)
4581d96047eSMarkus Pfeiffer {
4591d96047eSMarkus Pfeiffer 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
4601d96047eSMarkus Pfeiffer 	int err;
4611d96047eSMarkus Pfeiffer 	uint16_t actlen;
4621d96047eSMarkus Pfeiffer 
4631d96047eSMarkus Pfeiffer 	if (devh == NULL)
4641d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
4651d96047eSMarkus Pfeiffer 
4661d96047eSMarkus Pfeiffer 	if ((wLength != 0) && (data == NULL))
4671d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
4681d96047eSMarkus Pfeiffer 
4691d96047eSMarkus Pfeiffer 	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
4701d96047eSMarkus Pfeiffer 
4711d96047eSMarkus Pfeiffer 	req.bmRequestType = bmRequestType;
4721d96047eSMarkus Pfeiffer 	req.bRequest = bRequest;
4731d96047eSMarkus Pfeiffer 	req.wValue = wValue;
4741d96047eSMarkus Pfeiffer 	req.wIndex = wIndex;
4751d96047eSMarkus Pfeiffer 	req.wLength = wLength;
4761d96047eSMarkus Pfeiffer 
4771d96047eSMarkus Pfeiffer 	err = libusb20_dev_request_sync(devh, &req, data,
4781d96047eSMarkus Pfeiffer 	    &actlen, timeout, 0);
4791d96047eSMarkus Pfeiffer 
4801d96047eSMarkus Pfeiffer 	if (err == LIBUSB20_ERROR_PIPE)
4811d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_PIPE);
4821d96047eSMarkus Pfeiffer 	else if (err == LIBUSB20_ERROR_TIMEOUT)
4831d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_TIMEOUT);
4841d96047eSMarkus Pfeiffer 	else if (err)
4851d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_DEVICE);
4861d96047eSMarkus Pfeiffer 
4871d96047eSMarkus Pfeiffer 	return (actlen);
4881d96047eSMarkus Pfeiffer }
4891d96047eSMarkus Pfeiffer 
4901d96047eSMarkus Pfeiffer static void
libusb10_do_transfer_cb(struct libusb_transfer * transfer)4911d96047eSMarkus Pfeiffer libusb10_do_transfer_cb(struct libusb_transfer *transfer)
4921d96047eSMarkus Pfeiffer {
4931d96047eSMarkus Pfeiffer 	libusb_context *ctx;
4941d96047eSMarkus Pfeiffer 	int *pdone;
4951d96047eSMarkus Pfeiffer 
4961d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(NULL);
4971d96047eSMarkus Pfeiffer 
4981d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
4991d96047eSMarkus Pfeiffer 
5001d96047eSMarkus Pfeiffer 	pdone = transfer->user_data;
5011d96047eSMarkus Pfeiffer 	*pdone = 1;
5021d96047eSMarkus Pfeiffer }
5031d96047eSMarkus Pfeiffer 
5041d96047eSMarkus Pfeiffer /*
5051d96047eSMarkus Pfeiffer  * TODO: Replace the following function. Allocating and freeing on a
5061d96047eSMarkus Pfeiffer  * per-transfer basis is slow.  --HPS
5071d96047eSMarkus Pfeiffer  */
5081d96047eSMarkus Pfeiffer static int
libusb10_do_transfer(libusb_device_handle * devh,uint8_t endpoint,uint8_t * data,int length,int * transferred,unsigned int timeout,int type)5091d96047eSMarkus Pfeiffer libusb10_do_transfer(libusb_device_handle *devh,
5101d96047eSMarkus Pfeiffer     uint8_t endpoint, uint8_t *data, int length,
5111d96047eSMarkus Pfeiffer     int *transferred, unsigned int timeout, int type)
5121d96047eSMarkus Pfeiffer {
5131d96047eSMarkus Pfeiffer 	libusb_context *ctx;
5141d96047eSMarkus Pfeiffer 	struct libusb_transfer *xfer;
515aa3e5c14SSascha Wildner 	int done;
5161d96047eSMarkus Pfeiffer 	int ret;
5171d96047eSMarkus Pfeiffer 
5181d96047eSMarkus Pfeiffer 	if (devh == NULL)
5191d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
5201d96047eSMarkus Pfeiffer 
5211d96047eSMarkus Pfeiffer 	if ((length != 0) && (data == NULL))
5221d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
5231d96047eSMarkus Pfeiffer 
5241d96047eSMarkus Pfeiffer 	xfer = libusb_alloc_transfer(0);
5251d96047eSMarkus Pfeiffer 	if (xfer == NULL)
5261d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_MEM);
5271d96047eSMarkus Pfeiffer 
5281d96047eSMarkus Pfeiffer 	ctx = libusb_get_device(devh)->ctx;
5291d96047eSMarkus Pfeiffer 
5301d96047eSMarkus Pfeiffer 	xfer->dev_handle = devh;
5311d96047eSMarkus Pfeiffer 	xfer->endpoint = endpoint;
5321d96047eSMarkus Pfeiffer 	xfer->type = type;
5331d96047eSMarkus Pfeiffer 	xfer->timeout = timeout;
5341d96047eSMarkus Pfeiffer 	xfer->buffer = data;
5351d96047eSMarkus Pfeiffer 	xfer->length = length;
536aa3e5c14SSascha Wildner 	xfer->user_data = (void *)&done;
5371d96047eSMarkus Pfeiffer 	xfer->callback = libusb10_do_transfer_cb;
538aa3e5c14SSascha Wildner 	done = 0;
5391d96047eSMarkus Pfeiffer 
5401d96047eSMarkus Pfeiffer 	if ((ret = libusb_submit_transfer(xfer)) < 0) {
5411d96047eSMarkus Pfeiffer 		libusb_free_transfer(xfer);
5421d96047eSMarkus Pfeiffer 		return (ret);
5431d96047eSMarkus Pfeiffer 	}
544aa3e5c14SSascha Wildner 	while (done == 0) {
5451d96047eSMarkus Pfeiffer 		if ((ret = libusb_handle_events(ctx)) < 0) {
5461d96047eSMarkus Pfeiffer 			libusb_cancel_transfer(xfer);
5471d96047eSMarkus Pfeiffer 			usleep(1000);	/* nice it */
5481d96047eSMarkus Pfeiffer 		}
5491d96047eSMarkus Pfeiffer 	}
5501d96047eSMarkus Pfeiffer 
5511d96047eSMarkus Pfeiffer 	*transferred = xfer->actual_length;
5521d96047eSMarkus Pfeiffer 
5531d96047eSMarkus Pfeiffer 	switch (xfer->status) {
5541d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_COMPLETED:
5551d96047eSMarkus Pfeiffer 		ret = 0;
5561d96047eSMarkus Pfeiffer 		break;
5571d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TIMED_OUT:
5581d96047eSMarkus Pfeiffer 		ret = LIBUSB_ERROR_TIMEOUT;
5591d96047eSMarkus Pfeiffer 		break;
5601d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_OVERFLOW:
5611d96047eSMarkus Pfeiffer 		ret = LIBUSB_ERROR_OVERFLOW;
5621d96047eSMarkus Pfeiffer 		break;
5631d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_STALL:
5641d96047eSMarkus Pfeiffer 		ret = LIBUSB_ERROR_PIPE;
5651d96047eSMarkus Pfeiffer 		break;
5661d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_NO_DEVICE:
5671d96047eSMarkus Pfeiffer 		ret = LIBUSB_ERROR_NO_DEVICE;
5681d96047eSMarkus Pfeiffer 		break;
5691d96047eSMarkus Pfeiffer 	default:
5701d96047eSMarkus Pfeiffer 		ret = LIBUSB_ERROR_OTHER;
5711d96047eSMarkus Pfeiffer 		break;
5721d96047eSMarkus Pfeiffer 	}
5731d96047eSMarkus Pfeiffer 
5741d96047eSMarkus Pfeiffer 	libusb_free_transfer(xfer);
5751d96047eSMarkus Pfeiffer 	return (ret);
5761d96047eSMarkus Pfeiffer }
5771d96047eSMarkus Pfeiffer 
5781d96047eSMarkus Pfeiffer int
libusb_bulk_transfer(libusb_device_handle * devh,uint8_t endpoint,uint8_t * data,int length,int * transferred,unsigned int timeout)5791d96047eSMarkus Pfeiffer libusb_bulk_transfer(libusb_device_handle *devh,
5801d96047eSMarkus Pfeiffer     uint8_t endpoint, uint8_t *data, int length,
5811d96047eSMarkus Pfeiffer     int *transferred, unsigned int timeout)
5821d96047eSMarkus Pfeiffer {
5831d96047eSMarkus Pfeiffer 	libusb_context *ctx;
5841d96047eSMarkus Pfeiffer 	int ret;
5851d96047eSMarkus Pfeiffer 
5861d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(NULL);
5871d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
5881d96047eSMarkus Pfeiffer 
5891d96047eSMarkus Pfeiffer 	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
5901d96047eSMarkus Pfeiffer 	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
5911d96047eSMarkus Pfeiffer 
5921d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
5931d96047eSMarkus Pfeiffer 	return (ret);
5941d96047eSMarkus Pfeiffer }
5951d96047eSMarkus Pfeiffer 
5961d96047eSMarkus Pfeiffer int
libusb_interrupt_transfer(libusb_device_handle * devh,uint8_t endpoint,uint8_t * data,int length,int * transferred,unsigned int timeout)5971d96047eSMarkus Pfeiffer libusb_interrupt_transfer(libusb_device_handle *devh,
5981d96047eSMarkus Pfeiffer     uint8_t endpoint, uint8_t *data, int length,
5991d96047eSMarkus Pfeiffer     int *transferred, unsigned int timeout)
6001d96047eSMarkus Pfeiffer {
6011d96047eSMarkus Pfeiffer 	libusb_context *ctx;
6021d96047eSMarkus Pfeiffer 	int ret;
6031d96047eSMarkus Pfeiffer 
6041d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(NULL);
6051d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
6061d96047eSMarkus Pfeiffer 
6071d96047eSMarkus Pfeiffer 	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
6081d96047eSMarkus Pfeiffer 	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
6091d96047eSMarkus Pfeiffer 
6101d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
6111d96047eSMarkus Pfeiffer 	return (ret);
6121d96047eSMarkus Pfeiffer }
6131d96047eSMarkus Pfeiffer 
6141d96047eSMarkus Pfeiffer uint8_t *
libusb_get_iso_packet_buffer(struct libusb_transfer * transfer,uint32_t off)615aa3e5c14SSascha Wildner libusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t off)
6161d96047eSMarkus Pfeiffer {
6171d96047eSMarkus Pfeiffer 	uint8_t *ptr;
6181d96047eSMarkus Pfeiffer 	uint32_t n;
6191d96047eSMarkus Pfeiffer 
6201d96047eSMarkus Pfeiffer 	if (transfer->num_iso_packets < 0)
6211d96047eSMarkus Pfeiffer 		return (NULL);
6221d96047eSMarkus Pfeiffer 
623aa3e5c14SSascha Wildner 	if (off >= (uint32_t)transfer->num_iso_packets)
6241d96047eSMarkus Pfeiffer 		return (NULL);
6251d96047eSMarkus Pfeiffer 
6261d96047eSMarkus Pfeiffer 	ptr = transfer->buffer;
6271d96047eSMarkus Pfeiffer 	if (ptr == NULL)
6281d96047eSMarkus Pfeiffer 		return (NULL);
6291d96047eSMarkus Pfeiffer 
630aa3e5c14SSascha Wildner 	for (n = 0; n != off; n++) {
6311d96047eSMarkus Pfeiffer 		ptr += transfer->iso_packet_desc[n].length;
6321d96047eSMarkus Pfeiffer 	}
6331d96047eSMarkus Pfeiffer 	return (ptr);
6341d96047eSMarkus Pfeiffer }
6351d96047eSMarkus Pfeiffer 
6361d96047eSMarkus Pfeiffer uint8_t *
libusb_get_iso_packet_buffer_simple(struct libusb_transfer * transfer,uint32_t off)637aa3e5c14SSascha Wildner libusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t off)
6381d96047eSMarkus Pfeiffer {
6391d96047eSMarkus Pfeiffer 	uint8_t *ptr;
6401d96047eSMarkus Pfeiffer 
6411d96047eSMarkus Pfeiffer 	if (transfer->num_iso_packets < 0)
6421d96047eSMarkus Pfeiffer 		return (NULL);
6431d96047eSMarkus Pfeiffer 
644aa3e5c14SSascha Wildner 	if (off >= (uint32_t)transfer->num_iso_packets)
6451d96047eSMarkus Pfeiffer 		return (NULL);
6461d96047eSMarkus Pfeiffer 
6471d96047eSMarkus Pfeiffer 	ptr = transfer->buffer;
6481d96047eSMarkus Pfeiffer 	if (ptr == NULL)
6491d96047eSMarkus Pfeiffer 		return (NULL);
6501d96047eSMarkus Pfeiffer 
651aa3e5c14SSascha Wildner 	ptr += transfer->iso_packet_desc[0].length * off;
6521d96047eSMarkus Pfeiffer 
6531d96047eSMarkus Pfeiffer 	return (ptr);
6541d96047eSMarkus Pfeiffer }
6551d96047eSMarkus Pfeiffer 
6561d96047eSMarkus Pfeiffer void
libusb_set_iso_packet_lengths(struct libusb_transfer * transfer,uint32_t length)6571d96047eSMarkus Pfeiffer libusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length)
6581d96047eSMarkus Pfeiffer {
6591d96047eSMarkus Pfeiffer 	int n;
6601d96047eSMarkus Pfeiffer 
6611d96047eSMarkus Pfeiffer 	if (transfer->num_iso_packets < 0)
6621d96047eSMarkus Pfeiffer 		return;
6631d96047eSMarkus Pfeiffer 
6641d96047eSMarkus Pfeiffer 	for (n = 0; n != transfer->num_iso_packets; n++)
6651d96047eSMarkus Pfeiffer 		transfer->iso_packet_desc[n].length = length;
6661d96047eSMarkus Pfeiffer }
6671d96047eSMarkus Pfeiffer 
6681d96047eSMarkus Pfeiffer uint8_t *
libusb_control_transfer_get_data(struct libusb_transfer * transfer)6691d96047eSMarkus Pfeiffer libusb_control_transfer_get_data(struct libusb_transfer *transfer)
6701d96047eSMarkus Pfeiffer {
6711d96047eSMarkus Pfeiffer 	if (transfer->buffer == NULL)
6721d96047eSMarkus Pfeiffer 		return (NULL);
6731d96047eSMarkus Pfeiffer 
6741d96047eSMarkus Pfeiffer 	return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
6751d96047eSMarkus Pfeiffer }
6761d96047eSMarkus Pfeiffer 
6771d96047eSMarkus Pfeiffer struct libusb_control_setup *
libusb_control_transfer_get_setup(struct libusb_transfer * transfer)6781d96047eSMarkus Pfeiffer libusb_control_transfer_get_setup(struct libusb_transfer *transfer)
6791d96047eSMarkus Pfeiffer {
6801d96047eSMarkus Pfeiffer 	return ((struct libusb_control_setup *)transfer->buffer);
6811d96047eSMarkus Pfeiffer }
6821d96047eSMarkus Pfeiffer 
6831d96047eSMarkus Pfeiffer void
libusb_fill_control_setup(uint8_t * buf,uint8_t bmRequestType,uint8_t bRequest,uint16_t wValue,uint16_t wIndex,uint16_t wLength)6841d96047eSMarkus Pfeiffer libusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType,
6851d96047eSMarkus Pfeiffer     uint8_t bRequest, uint16_t wValue,
6861d96047eSMarkus Pfeiffer     uint16_t wIndex, uint16_t wLength)
6871d96047eSMarkus Pfeiffer {
6881d96047eSMarkus Pfeiffer 	struct libusb_control_setup *req = (struct libusb_control_setup *)buf;
6891d96047eSMarkus Pfeiffer 
6901d96047eSMarkus Pfeiffer 	/* The alignment is OK for all fields below. */
6911d96047eSMarkus Pfeiffer 	req->bmRequestType = bmRequestType;
6921d96047eSMarkus Pfeiffer 	req->bRequest = bRequest;
6931d96047eSMarkus Pfeiffer 	req->wValue = htole16(wValue);
6941d96047eSMarkus Pfeiffer 	req->wIndex = htole16(wIndex);
6951d96047eSMarkus Pfeiffer 	req->wLength = htole16(wLength);
6961d96047eSMarkus Pfeiffer }
6971d96047eSMarkus Pfeiffer 
6981d96047eSMarkus Pfeiffer void
libusb_fill_control_transfer(struct libusb_transfer * transfer,libusb_device_handle * devh,uint8_t * buf,libusb_transfer_cb_fn callback,void * user_data,uint32_t timeout)6991d96047eSMarkus Pfeiffer libusb_fill_control_transfer(struct libusb_transfer *transfer,
7001d96047eSMarkus Pfeiffer     libusb_device_handle *devh, uint8_t *buf,
7011d96047eSMarkus Pfeiffer     libusb_transfer_cb_fn callback, void *user_data,
7021d96047eSMarkus Pfeiffer     uint32_t timeout)
7031d96047eSMarkus Pfeiffer {
7041d96047eSMarkus Pfeiffer 	struct libusb_control_setup *setup = (struct libusb_control_setup *)buf;
7051d96047eSMarkus Pfeiffer 
7061d96047eSMarkus Pfeiffer 	transfer->dev_handle = devh;
7071d96047eSMarkus Pfeiffer 	transfer->endpoint = 0;
7081d96047eSMarkus Pfeiffer 	transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
7091d96047eSMarkus Pfeiffer 	transfer->timeout = timeout;
7101d96047eSMarkus Pfeiffer 	transfer->buffer = buf;
7111d96047eSMarkus Pfeiffer 	if (setup != NULL)
7121d96047eSMarkus Pfeiffer 		transfer->length = LIBUSB_CONTROL_SETUP_SIZE
7131d96047eSMarkus Pfeiffer 			+ le16toh(setup->wLength);
7141d96047eSMarkus Pfeiffer 	else
7151d96047eSMarkus Pfeiffer 		transfer->length = 0;
7161d96047eSMarkus Pfeiffer 	transfer->user_data = user_data;
7171d96047eSMarkus Pfeiffer 	transfer->callback = callback;
7181d96047eSMarkus Pfeiffer 
7191d96047eSMarkus Pfeiffer }
7201d96047eSMarkus Pfeiffer 
7211d96047eSMarkus Pfeiffer void
libusb_fill_bulk_transfer(struct libusb_transfer * transfer,libusb_device_handle * devh,uint8_t endpoint,uint8_t * buf,int length,libusb_transfer_cb_fn callback,void * user_data,uint32_t timeout)7221d96047eSMarkus Pfeiffer libusb_fill_bulk_transfer(struct libusb_transfer *transfer,
7231d96047eSMarkus Pfeiffer     libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
7241d96047eSMarkus Pfeiffer     int length, libusb_transfer_cb_fn callback, void *user_data,
7251d96047eSMarkus Pfeiffer     uint32_t timeout)
7261d96047eSMarkus Pfeiffer {
7271d96047eSMarkus Pfeiffer 	transfer->dev_handle = devh;
7281d96047eSMarkus Pfeiffer 	transfer->endpoint = endpoint;
7291d96047eSMarkus Pfeiffer 	transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
7301d96047eSMarkus Pfeiffer 	transfer->timeout = timeout;
7311d96047eSMarkus Pfeiffer 	transfer->buffer = buf;
7321d96047eSMarkus Pfeiffer 	transfer->length = length;
7331d96047eSMarkus Pfeiffer 	transfer->user_data = user_data;
7341d96047eSMarkus Pfeiffer 	transfer->callback = callback;
7351d96047eSMarkus Pfeiffer }
7361d96047eSMarkus Pfeiffer 
7371d96047eSMarkus Pfeiffer void
libusb_fill_interrupt_transfer(struct libusb_transfer * transfer,libusb_device_handle * devh,uint8_t endpoint,uint8_t * buf,int length,libusb_transfer_cb_fn callback,void * user_data,uint32_t timeout)7381d96047eSMarkus Pfeiffer libusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
7391d96047eSMarkus Pfeiffer     libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
7401d96047eSMarkus Pfeiffer     int length, libusb_transfer_cb_fn callback, void *user_data,
7411d96047eSMarkus Pfeiffer     uint32_t timeout)
7421d96047eSMarkus Pfeiffer {
7431d96047eSMarkus Pfeiffer 	transfer->dev_handle = devh;
7441d96047eSMarkus Pfeiffer 	transfer->endpoint = endpoint;
7451d96047eSMarkus Pfeiffer 	transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
7461d96047eSMarkus Pfeiffer 	transfer->timeout = timeout;
7471d96047eSMarkus Pfeiffer 	transfer->buffer = buf;
7481d96047eSMarkus Pfeiffer 	transfer->length = length;
7491d96047eSMarkus Pfeiffer 	transfer->user_data = user_data;
7501d96047eSMarkus Pfeiffer 	transfer->callback = callback;
7511d96047eSMarkus Pfeiffer }
7521d96047eSMarkus Pfeiffer 
7531d96047eSMarkus Pfeiffer void
libusb_fill_iso_transfer(struct libusb_transfer * transfer,libusb_device_handle * devh,uint8_t endpoint,uint8_t * buf,int length,int npacket,libusb_transfer_cb_fn callback,void * user_data,uint32_t timeout)7541d96047eSMarkus Pfeiffer libusb_fill_iso_transfer(struct libusb_transfer *transfer,
7551d96047eSMarkus Pfeiffer     libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
7561d96047eSMarkus Pfeiffer     int length, int npacket, libusb_transfer_cb_fn callback,
7571d96047eSMarkus Pfeiffer     void *user_data, uint32_t timeout)
7581d96047eSMarkus Pfeiffer {
7591d96047eSMarkus Pfeiffer 	transfer->dev_handle = devh;
7601d96047eSMarkus Pfeiffer 	transfer->endpoint = endpoint;
7611d96047eSMarkus Pfeiffer 	transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
7621d96047eSMarkus Pfeiffer 	transfer->timeout = timeout;
7631d96047eSMarkus Pfeiffer 	transfer->buffer = buf;
7641d96047eSMarkus Pfeiffer 	transfer->length = length;
7651d96047eSMarkus Pfeiffer 	transfer->num_iso_packets = npacket;
7661d96047eSMarkus Pfeiffer 	transfer->user_data = user_data;
7671d96047eSMarkus Pfeiffer 	transfer->callback = callback;
7681d96047eSMarkus Pfeiffer }
7691d96047eSMarkus Pfeiffer 
770