xref: /freebsd-src/lib/libusb/libusb10_io.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
18c8fff31SAndrew Thompson /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni  *
48c8fff31SAndrew Thompson  * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
58c8fff31SAndrew Thompson  *
68c8fff31SAndrew Thompson  * Redistribution and use in source and binary forms, with or without
78c8fff31SAndrew Thompson  * modification, are permitted provided that the following conditions
88c8fff31SAndrew Thompson  * are met:
98c8fff31SAndrew Thompson  * 1. Redistributions of source code must retain the above copyright
108c8fff31SAndrew Thompson  *    notice, this list of conditions and the following disclaimer.
118c8fff31SAndrew Thompson  * 2. Redistributions in binary form must reproduce the above copyright
128c8fff31SAndrew Thompson  *    notice, this list of conditions and the following disclaimer in the
138c8fff31SAndrew Thompson  *    documentation and/or other materials provided with the distribution.
148c8fff31SAndrew Thompson  *
158c8fff31SAndrew Thompson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
168c8fff31SAndrew Thompson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
178c8fff31SAndrew Thompson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
188c8fff31SAndrew Thompson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
198c8fff31SAndrew Thompson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
208c8fff31SAndrew Thompson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
218c8fff31SAndrew Thompson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
228c8fff31SAndrew Thompson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
238c8fff31SAndrew Thompson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
248c8fff31SAndrew Thompson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
258c8fff31SAndrew Thompson  * SUCH DAMAGE.
268c8fff31SAndrew Thompson  */
278c8fff31SAndrew Thompson 
2866194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
2966194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE
3066194130SHans Petter Selasky #else
31f3cba95cSWojciech A. Koszek #include <errno.h>
328c8fff31SAndrew Thompson #include <poll.h>
338c8fff31SAndrew Thompson #include <pthread.h>
34f3cba95cSWojciech A. Koszek #include <stdio.h>
35f3cba95cSWojciech A. Koszek #include <stdlib.h>
3666194130SHans Petter Selasky #include <string.h>
378c8fff31SAndrew Thompson #include <time.h>
38f3cba95cSWojciech A. Koszek #include <unistd.h>
3966194130SHans Petter Selasky #include <sys/queue.h>
4066194130SHans Petter Selasky #include <sys/endian.h>
4166194130SHans Petter Selasky #endif
428c8fff31SAndrew Thompson 
439c087c5aSAndrew Thompson #define	libusb_device_handle libusb20_device
449c087c5aSAndrew Thompson 
458c8fff31SAndrew Thompson #include "libusb20.h"
468c8fff31SAndrew Thompson #include "libusb20_desc.h"
478c8fff31SAndrew Thompson #include "libusb20_int.h"
488c8fff31SAndrew Thompson #include "libusb.h"
498c8fff31SAndrew Thompson #include "libusb10.h"
508c8fff31SAndrew Thompson 
51390065b1SAlfred Perlstein UNEXPORTED void
libusb10_add_pollfd(libusb_context * ctx,struct libusb_super_pollfd * pollfd,struct libusb20_device * pdev,int fd,short events)52390065b1SAlfred Perlstein libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd,
53390065b1SAlfred Perlstein     struct libusb20_device *pdev, int fd, short events)
54c500e4ddSAndrew Thompson {
55c500e4ddSAndrew Thompson 	if (ctx == NULL)
56390065b1SAlfred Perlstein 		return;			/* invalid */
57c500e4ddSAndrew Thompson 
58390065b1SAlfred Perlstein 	if (pollfd->entry.tqe_prev != NULL)
59390065b1SAlfred Perlstein 		return;			/* already queued */
60c500e4ddSAndrew Thompson 
61390065b1SAlfred Perlstein 	if (fd < 0)
62390065b1SAlfred Perlstein 		return;			/* invalid */
63390065b1SAlfred Perlstein 
64390065b1SAlfred Perlstein 	pollfd->pdev = pdev;
65c500e4ddSAndrew Thompson 	pollfd->pollfd.fd = fd;
66c500e4ddSAndrew Thompson 	pollfd->pollfd.events = events;
67c500e4ddSAndrew Thompson 
68390065b1SAlfred Perlstein 	CTX_LOCK(ctx);
69390065b1SAlfred Perlstein 	TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry);
70390065b1SAlfred Perlstein 	CTX_UNLOCK(ctx);
71c500e4ddSAndrew Thompson 
72c500e4ddSAndrew Thompson 	if (ctx->fd_added_cb)
73c500e4ddSAndrew Thompson 		ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
74c500e4ddSAndrew Thompson }
75c500e4ddSAndrew Thompson 
76c500e4ddSAndrew Thompson UNEXPORTED void
libusb10_remove_pollfd(libusb_context * ctx,struct libusb_super_pollfd * pollfd)77390065b1SAlfred Perlstein libusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd)
78c500e4ddSAndrew Thompson {
79390065b1SAlfred Perlstein 	if (ctx == NULL)
80390065b1SAlfred Perlstein 		return;			/* invalid */
81c500e4ddSAndrew Thompson 
82390065b1SAlfred Perlstein 	if (pollfd->entry.tqe_prev == NULL)
83390065b1SAlfred Perlstein 		return;			/* already dequeued */
84c500e4ddSAndrew Thompson 
85390065b1SAlfred Perlstein 	CTX_LOCK(ctx);
86390065b1SAlfred Perlstein 	TAILQ_REMOVE(&ctx->pollfds, pollfd, entry);
87390065b1SAlfred Perlstein 	pollfd->entry.tqe_prev = NULL;
88390065b1SAlfred Perlstein 	CTX_UNLOCK(ctx);
89c500e4ddSAndrew Thompson 
90c500e4ddSAndrew Thompson 	if (ctx->fd_removed_cb)
91390065b1SAlfred Perlstein 		ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data);
92c500e4ddSAndrew Thompson }
93c500e4ddSAndrew Thompson 
94390065b1SAlfred Perlstein /* This function must be called locked */
95390065b1SAlfred Perlstein 
96390065b1SAlfred Perlstein static int
libusb10_handle_events_sub(struct libusb_context * ctx,struct timeval * tv)97390065b1SAlfred Perlstein libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
98c500e4ddSAndrew Thompson {
99390065b1SAlfred Perlstein 	struct libusb_device *dev;
100390065b1SAlfred Perlstein 	struct libusb20_device **ppdev;
101390065b1SAlfred Perlstein 	struct libusb_super_pollfd *pfd;
1028c8fff31SAndrew Thompson 	struct pollfd *fds;
103390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
104390065b1SAlfred Perlstein 	struct libusb_transfer *uxfer;
1058c8fff31SAndrew Thompson 	nfds_t nfds;
1068c8fff31SAndrew Thompson 	int timeout;
1078c8fff31SAndrew Thompson 	int i;
108390065b1SAlfred Perlstein 	int err;
1098c8fff31SAndrew Thompson 
110390065b1SAlfred Perlstein 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
1118c8fff31SAndrew Thompson 
1128c8fff31SAndrew Thompson 	nfds = 0;
113390065b1SAlfred Perlstein 	i = 0;
114390065b1SAlfred Perlstein 	TAILQ_FOREACH(pfd, &ctx->pollfds, entry)
1158c8fff31SAndrew Thompson 	    nfds++;
1168c8fff31SAndrew Thompson 
117c500e4ddSAndrew Thompson 	fds = alloca(sizeof(*fds) * nfds);
1188c8fff31SAndrew Thompson 	if (fds == NULL)
1198c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_NO_MEM);
1208c8fff31SAndrew Thompson 
121390065b1SAlfred Perlstein 	ppdev = alloca(sizeof(*ppdev) * nfds);
122390065b1SAlfred Perlstein 	if (ppdev == NULL)
123390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_NO_MEM);
124390065b1SAlfred Perlstein 
125390065b1SAlfred Perlstein 	TAILQ_FOREACH(pfd, &ctx->pollfds, entry) {
126390065b1SAlfred Perlstein 		fds[i].fd = pfd->pollfd.fd;
127390065b1SAlfred Perlstein 		fds[i].events = pfd->pollfd.events;
1288c8fff31SAndrew Thompson 		fds[i].revents = 0;
129390065b1SAlfred Perlstein 		ppdev[i] = pfd->pdev;
130390065b1SAlfred Perlstein 		if (pfd->pdev != NULL)
131390065b1SAlfred Perlstein 			libusb_get_device(pfd->pdev)->refcnt++;
132390065b1SAlfred Perlstein 		i++;
1338c8fff31SAndrew Thompson 	}
1348c8fff31SAndrew Thompson 
135390065b1SAlfred Perlstein 	if (tv == NULL)
136390065b1SAlfred Perlstein 		timeout = -1;
137390065b1SAlfred Perlstein 	else
138390065b1SAlfred Perlstein 		timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
1398c8fff31SAndrew Thompson 
140390065b1SAlfred Perlstein 	CTX_UNLOCK(ctx);
141390065b1SAlfred Perlstein 	err = poll(fds, nfds, timeout);
142390065b1SAlfred Perlstein 	CTX_LOCK(ctx);
1438c8fff31SAndrew Thompson 
144390065b1SAlfred Perlstein 	if ((err == -1) && (errno == EINTR))
145390065b1SAlfred Perlstein 		err = LIBUSB_ERROR_INTERRUPTED;
146390065b1SAlfred Perlstein 	else if (err < 0)
147390065b1SAlfred Perlstein 		err = LIBUSB_ERROR_IO;
1488c8fff31SAndrew Thompson 
149390065b1SAlfred Perlstein 	if (err < 1) {
150a1221549SHans Petter Selasky 		for (i = 0; i != (int)nfds; i++) {
151390065b1SAlfred Perlstein 			if (ppdev[i] != NULL) {
152390065b1SAlfred Perlstein 				CTX_UNLOCK(ctx);
153390065b1SAlfred Perlstein 				libusb_unref_device(libusb_get_device(ppdev[i]));
154390065b1SAlfred Perlstein 				CTX_LOCK(ctx);
1558c8fff31SAndrew Thompson 			}
1568c8fff31SAndrew Thompson 		}
157390065b1SAlfred Perlstein 		goto do_done;
158390065b1SAlfred Perlstein 	}
159a1221549SHans Petter Selasky 	for (i = 0; i != (int)nfds; i++) {
160390065b1SAlfred Perlstein 		if (ppdev[i] != NULL) {
161390065b1SAlfred Perlstein 			dev = libusb_get_device(ppdev[i]);
1628c8fff31SAndrew Thompson 
163540c7229SHans Petter Selasky 			if (fds[i].revents != 0) {
164390065b1SAlfred Perlstein 				err = libusb20_dev_process(ppdev[i]);
165ccef4ddfSAndrew Thompson 
166390065b1SAlfred Perlstein 				if (err) {
1676847ea50SHans Petter Selasky 					/*
1686847ea50SHans Petter Selasky 					 * When the device is opened
1696847ea50SHans Petter Selasky 					 * set the "device_is_gone"
1706847ea50SHans Petter Selasky 					 * flag. This prevents the
1716847ea50SHans Petter Selasky 					 * client from submitting new
1726847ea50SHans Petter Selasky 					 * USB transfers to a detached
1736847ea50SHans Petter Selasky 					 * device.
1746847ea50SHans Petter Selasky 					 */
1756847ea50SHans Petter Selasky 					if (ppdev[i]->is_opened)
176540c7229SHans Petter Selasky 						dev->device_is_gone = 1;
177ccef4ddfSAndrew Thompson 
178ccef4ddfSAndrew Thompson 					/* remove USB device from polling loop */
179390065b1SAlfred Perlstein 					libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
180540c7229SHans Petter Selasky 
181540c7229SHans Petter Selasky 					/* cancel all pending transfers */
182540c7229SHans Petter Selasky 					libusb10_cancel_all_transfer_locked(ppdev[i], dev);
183540c7229SHans Petter Selasky 				}
184390065b1SAlfred Perlstein 			}
185390065b1SAlfred Perlstein 			CTX_UNLOCK(ctx);
186390065b1SAlfred Perlstein 			libusb_unref_device(dev);
187390065b1SAlfred Perlstein 			CTX_LOCK(ctx);
188390065b1SAlfred Perlstein 
189390065b1SAlfred Perlstein 		} else {
190390065b1SAlfred Perlstein 			uint8_t dummy;
191390065b1SAlfred Perlstein 
192540c7229SHans Petter Selasky 			while (read(fds[i].fd, &dummy, 1) == 1)
193540c7229SHans Petter Selasky 				;
194390065b1SAlfred Perlstein 		}
1958c8fff31SAndrew Thompson 	}
1968c8fff31SAndrew Thompson 
197390065b1SAlfred Perlstein 	err = 0;
1988c8fff31SAndrew Thompson 
199390065b1SAlfred Perlstein do_done:
2008c8fff31SAndrew Thompson 
201390065b1SAlfred Perlstein 	/* Do all done callbacks */
2028c8fff31SAndrew Thompson 
203390065b1SAlfred Perlstein 	while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
20431f7072cSHans Petter Selasky 		uint8_t flags;
20531f7072cSHans Petter Selasky 
206390065b1SAlfred Perlstein 		TAILQ_REMOVE(&ctx->tr_done, sxfer, entry);
207390065b1SAlfred Perlstein 		sxfer->entry.tqe_prev = NULL;
208390065b1SAlfred Perlstein 
209390065b1SAlfred Perlstein 		ctx->tr_done_ref++;
210390065b1SAlfred Perlstein 
211390065b1SAlfred Perlstein 		CTX_UNLOCK(ctx);
212390065b1SAlfred Perlstein 
213390065b1SAlfred Perlstein 		uxfer = (struct libusb_transfer *)(
214390065b1SAlfred Perlstein 		    ((uint8_t *)sxfer) + sizeof(*sxfer));
215390065b1SAlfred Perlstein 
21631f7072cSHans Petter Selasky 		/* Allow the callback to free the transfer itself. */
21731f7072cSHans Petter Selasky 		flags = uxfer->flags;
21831f7072cSHans Petter Selasky 
219390065b1SAlfred Perlstein 		if (uxfer->callback != NULL)
220390065b1SAlfred Perlstein 			(uxfer->callback) (uxfer);
221390065b1SAlfred Perlstein 
22231f7072cSHans Petter Selasky 		/* Check if the USB transfer should be automatically freed. */
22331f7072cSHans Petter Selasky 		if (flags & LIBUSB_TRANSFER_FREE_TRANSFER)
224390065b1SAlfred Perlstein 			libusb_free_transfer(uxfer);
225390065b1SAlfred Perlstein 
226390065b1SAlfred Perlstein 		CTX_LOCK(ctx);
227390065b1SAlfred Perlstein 
228390065b1SAlfred Perlstein 		ctx->tr_done_ref--;
229390065b1SAlfred Perlstein 		ctx->tr_done_gen++;
2308c8fff31SAndrew Thompson 	}
2318c8fff31SAndrew Thompson 
232390065b1SAlfred Perlstein 	/* Wakeup other waiters */
233390065b1SAlfred Perlstein 	pthread_cond_broadcast(&ctx->ctx_cond);
2348c8fff31SAndrew Thompson 
235390065b1SAlfred Perlstein 	return (err);
2368c8fff31SAndrew Thompson }
2378c8fff31SAndrew Thompson 
2388c8fff31SAndrew Thompson /* Polling and timing */
2398c8fff31SAndrew Thompson 
2408c8fff31SAndrew Thompson int
libusb_try_lock_events(libusb_context * ctx)2418c8fff31SAndrew Thompson libusb_try_lock_events(libusb_context *ctx)
2428c8fff31SAndrew Thompson {
243390065b1SAlfred Perlstein 	int err;
2448c8fff31SAndrew Thompson 
245390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
246390065b1SAlfred Perlstein 	if (ctx == NULL)
2478c8fff31SAndrew Thompson 		return (1);
2488c8fff31SAndrew Thompson 
249390065b1SAlfred Perlstein 	err = CTX_TRYLOCK(ctx);
250390065b1SAlfred Perlstein 	if (err)
2518c8fff31SAndrew Thompson 		return (1);
2528c8fff31SAndrew Thompson 
253390065b1SAlfred Perlstein 	err = (ctx->ctx_handler != NO_THREAD);
254390065b1SAlfred Perlstein 	if (err)
255390065b1SAlfred Perlstein 		CTX_UNLOCK(ctx);
256390065b1SAlfred Perlstein 	else
257390065b1SAlfred Perlstein 		ctx->ctx_handler = pthread_self();
2588c8fff31SAndrew Thompson 
259390065b1SAlfred Perlstein 	return (err);
2608c8fff31SAndrew Thompson }
2618c8fff31SAndrew Thompson 
2628c8fff31SAndrew Thompson void
libusb_lock_events(libusb_context * ctx)2638c8fff31SAndrew Thompson libusb_lock_events(libusb_context *ctx)
2648c8fff31SAndrew Thompson {
265390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
266390065b1SAlfred Perlstein 	CTX_LOCK(ctx);
267390065b1SAlfred Perlstein 	if (ctx->ctx_handler == NO_THREAD)
268390065b1SAlfred Perlstein 		ctx->ctx_handler = pthread_self();
2698c8fff31SAndrew Thompson }
2708c8fff31SAndrew Thompson 
2718c8fff31SAndrew Thompson void
libusb_unlock_events(libusb_context * ctx)2728c8fff31SAndrew Thompson libusb_unlock_events(libusb_context *ctx)
2738c8fff31SAndrew Thompson {
274390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
275390065b1SAlfred Perlstein 	if (ctx->ctx_handler == pthread_self()) {
276390065b1SAlfred Perlstein 		ctx->ctx_handler = NO_THREAD;
277390065b1SAlfred Perlstein 		pthread_cond_broadcast(&ctx->ctx_cond);
278390065b1SAlfred Perlstein 	}
279390065b1SAlfred Perlstein 	CTX_UNLOCK(ctx);
2808c8fff31SAndrew Thompson }
2818c8fff31SAndrew Thompson 
2828c8fff31SAndrew Thompson int
libusb_event_handling_ok(libusb_context * ctx)2838c8fff31SAndrew Thompson libusb_event_handling_ok(libusb_context *ctx)
2848c8fff31SAndrew Thompson {
285390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
286390065b1SAlfred Perlstein 	return (ctx->ctx_handler == pthread_self());
2878c8fff31SAndrew Thompson }
2888c8fff31SAndrew Thompson 
2898c8fff31SAndrew Thompson int
libusb_event_handler_active(libusb_context * ctx)2908c8fff31SAndrew Thompson libusb_event_handler_active(libusb_context *ctx)
2918c8fff31SAndrew Thompson {
292390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
293390065b1SAlfred Perlstein 	return (ctx->ctx_handler != NO_THREAD);
2948c8fff31SAndrew Thompson }
2958c8fff31SAndrew Thompson 
2968c8fff31SAndrew Thompson void
libusb_lock_event_waiters(libusb_context * ctx)2978c8fff31SAndrew Thompson libusb_lock_event_waiters(libusb_context *ctx)
2988c8fff31SAndrew Thompson {
299390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
300390065b1SAlfred Perlstein 	CTX_LOCK(ctx);
3018c8fff31SAndrew Thompson }
3028c8fff31SAndrew Thompson 
3038c8fff31SAndrew Thompson void
libusb_unlock_event_waiters(libusb_context * ctx)3048c8fff31SAndrew Thompson libusb_unlock_event_waiters(libusb_context *ctx)
3058c8fff31SAndrew Thompson {
306390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
307390065b1SAlfred Perlstein 	CTX_UNLOCK(ctx);
3088c8fff31SAndrew Thompson }
3098c8fff31SAndrew Thompson 
3108c8fff31SAndrew Thompson int
libusb_wait_for_event(libusb_context * ctx,struct timeval * tv)3118c8fff31SAndrew Thompson libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
3128c8fff31SAndrew Thompson {
3138c8fff31SAndrew Thompson 	struct timespec ts;
314390065b1SAlfred Perlstein 	int err;
3158c8fff31SAndrew Thompson 
316390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
317c500e4ddSAndrew Thompson 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
3188c8fff31SAndrew Thompson 
3198c8fff31SAndrew Thompson 	if (tv == NULL) {
320390065b1SAlfred Perlstein 		pthread_cond_wait(&ctx->ctx_cond,
321390065b1SAlfred Perlstein 		    &ctx->ctx_lock);
32226829924SHans Petter Selasky 		/* try to grab polling of actual events, if any */
32326829924SHans Petter Selasky 		if (ctx->ctx_handler == NO_THREAD)
32426829924SHans Petter Selasky 			ctx->ctx_handler = pthread_self();
3258c8fff31SAndrew Thompson 		return (0);
3268c8fff31SAndrew Thompson 	}
327f7287225SHans Petter Selasky 	err = clock_gettime(CLOCK_MONOTONIC, &ts);
328390065b1SAlfred Perlstein 	if (err < 0)
3298c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_OTHER);
3308c8fff31SAndrew Thompson 
331f7287225SHans Petter Selasky 	/*
332f7287225SHans Petter Selasky 	 * The "tv" arguments points to a relative time structure and
333f7287225SHans Petter Selasky 	 * not an absolute time structure.
334f7287225SHans Petter Selasky 	 */
335f7287225SHans Petter Selasky 	ts.tv_sec += tv->tv_sec;
336f7287225SHans Petter Selasky 	ts.tv_nsec += tv->tv_usec * 1000;
337390065b1SAlfred Perlstein 	if (ts.tv_nsec >= 1000000000) {
3388c8fff31SAndrew Thompson 		ts.tv_nsec -= 1000000000;
3398c8fff31SAndrew Thompson 		ts.tv_sec++;
3408c8fff31SAndrew Thompson 	}
341390065b1SAlfred Perlstein 	err = pthread_cond_timedwait(&ctx->ctx_cond,
342390065b1SAlfred Perlstein 	    &ctx->ctx_lock, &ts);
34326829924SHans Petter Selasky 	/* try to grab polling of actual events, if any */
34426829924SHans Petter Selasky 	if (ctx->ctx_handler == NO_THREAD)
34526829924SHans Petter Selasky 		ctx->ctx_handler = pthread_self();
3468c8fff31SAndrew Thompson 
347390065b1SAlfred Perlstein 	if (err == ETIMEDOUT)
3488c8fff31SAndrew Thompson 		return (1);
3498c8fff31SAndrew Thompson 
3508c8fff31SAndrew Thompson 	return (0);
3518c8fff31SAndrew Thompson }
3528c8fff31SAndrew Thompson 
3538c8fff31SAndrew Thompson int
libusb_handle_events_timeout_completed(libusb_context * ctx,struct timeval * tv,int * completed)35403205428SHans Petter Selasky libusb_handle_events_timeout_completed(libusb_context *ctx,
35503205428SHans Petter Selasky     struct timeval *tv, int *completed)
3568c8fff31SAndrew Thompson {
35703205428SHans Petter Selasky 	int err = 0;
3588c8fff31SAndrew Thompson 
359390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
360390065b1SAlfred Perlstein 
36103205428SHans Petter Selasky 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter");
3628c8fff31SAndrew Thompson 
363390065b1SAlfred Perlstein 	libusb_lock_events(ctx);
364390065b1SAlfred Perlstein 
36503205428SHans Petter Selasky 	while (1) {
36603205428SHans Petter Selasky 		if (completed != NULL) {
36703205428SHans Petter Selasky 			if (*completed != 0 || err != 0)
36803205428SHans Petter Selasky 				break;
36903205428SHans Petter Selasky 		}
370390065b1SAlfred Perlstein 		err = libusb_handle_events_locked(ctx, tv);
37103205428SHans Petter Selasky 		if (completed == NULL)
37203205428SHans Petter Selasky 			break;
37303205428SHans Petter Selasky 	}
374390065b1SAlfred Perlstein 
3758c8fff31SAndrew Thompson 	libusb_unlock_events(ctx);
3768c8fff31SAndrew Thompson 
37703205428SHans Petter Selasky 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit");
378390065b1SAlfred Perlstein 
379390065b1SAlfred Perlstein 	return (err);
3808c8fff31SAndrew Thompson }
3818c8fff31SAndrew Thompson 
3828c8fff31SAndrew Thompson int
libusb_handle_events_completed(libusb_context * ctx,int * completed)38303205428SHans Petter Selasky libusb_handle_events_completed(libusb_context *ctx, int *completed)
38403205428SHans Petter Selasky {
38503205428SHans Petter Selasky 	return (libusb_handle_events_timeout_completed(ctx, NULL, completed));
38603205428SHans Petter Selasky }
38703205428SHans Petter Selasky 
38803205428SHans Petter Selasky int
libusb_handle_events_timeout(libusb_context * ctx,struct timeval * tv)38903205428SHans Petter Selasky libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
39003205428SHans Petter Selasky {
39103205428SHans Petter Selasky 	return (libusb_handle_events_timeout_completed(ctx, tv, NULL));
39203205428SHans Petter Selasky }
39303205428SHans Petter Selasky 
39403205428SHans Petter Selasky int
libusb_handle_events(libusb_context * ctx)3958c8fff31SAndrew Thompson libusb_handle_events(libusb_context *ctx)
3968c8fff31SAndrew Thompson {
39703205428SHans Petter Selasky 	return (libusb_handle_events_timeout_completed(ctx, NULL, NULL));
3988c8fff31SAndrew Thompson }
3998c8fff31SAndrew Thompson 
4008c8fff31SAndrew Thompson int
libusb_handle_events_locked(libusb_context * ctx,struct timeval * tv)4018c8fff31SAndrew Thompson libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
4028c8fff31SAndrew Thompson {
403390065b1SAlfred Perlstein 	int err;
4048c8fff31SAndrew Thompson 
405390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
4068c8fff31SAndrew Thompson 
407390065b1SAlfred Perlstein 	if (libusb_event_handling_ok(ctx)) {
408390065b1SAlfred Perlstein 		err = libusb10_handle_events_sub(ctx, tv);
409390065b1SAlfred Perlstein 	} else {
41003205428SHans Petter Selasky 		err = libusb_wait_for_event(ctx, tv);
41103205428SHans Petter Selasky 		if (err != 0)
41203205428SHans Petter Selasky 			err = LIBUSB_ERROR_TIMEOUT;
4138c8fff31SAndrew Thompson 	}
414390065b1SAlfred Perlstein 	return (err);
4158c8fff31SAndrew Thompson }
4168c8fff31SAndrew Thompson 
4178c8fff31SAndrew Thompson int
libusb_get_next_timeout(libusb_context * ctx,struct timeval * tv)4188c8fff31SAndrew Thompson libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
4198c8fff31SAndrew Thompson {
420390065b1SAlfred Perlstein 	/* all timeouts are currently being done by the kernel */
4218c8fff31SAndrew Thompson 	timerclear(tv);
422390065b1SAlfred Perlstein 	return (0);
4238c8fff31SAndrew Thompson }
4248c8fff31SAndrew Thompson 
4258c8fff31SAndrew Thompson void
libusb_set_pollfd_notifiers(libusb_context * ctx,libusb_pollfd_added_cb added_cb,libusb_pollfd_removed_cb removed_cb,void * user_data)4268c8fff31SAndrew Thompson libusb_set_pollfd_notifiers(libusb_context *ctx,
4278c8fff31SAndrew Thompson     libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
4288c8fff31SAndrew Thompson     void *user_data)
4298c8fff31SAndrew Thompson {
430390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
4318c8fff31SAndrew Thompson 
4328c8fff31SAndrew Thompson 	ctx->fd_added_cb = added_cb;
4338c8fff31SAndrew Thompson 	ctx->fd_removed_cb = removed_cb;
4348c8fff31SAndrew Thompson 	ctx->fd_cb_user_data = user_data;
4358c8fff31SAndrew Thompson }
4368c8fff31SAndrew Thompson 
43722a962c9SEd Maste const struct libusb_pollfd **
libusb_get_pollfds(libusb_context * ctx)4388c8fff31SAndrew Thompson libusb_get_pollfds(libusb_context *ctx)
4398c8fff31SAndrew Thompson {
440390065b1SAlfred Perlstein 	struct libusb_super_pollfd *pollfd;
4418c8fff31SAndrew Thompson 	libusb_pollfd **ret;
4428c8fff31SAndrew Thompson 	int i;
4438c8fff31SAndrew Thompson 
444390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
445390065b1SAlfred Perlstein 
446390065b1SAlfred Perlstein 	CTX_LOCK(ctx);
4478c8fff31SAndrew Thompson 
4488c8fff31SAndrew Thompson 	i = 0;
449390065b1SAlfred Perlstein 	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
4508c8fff31SAndrew Thompson 	    i++;
4518c8fff31SAndrew Thompson 
4528c8fff31SAndrew Thompson 	ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
453390065b1SAlfred Perlstein 	if (ret == NULL)
454390065b1SAlfred Perlstein 		goto done;
4558c8fff31SAndrew Thompson 
4568c8fff31SAndrew Thompson 	i = 0;
457390065b1SAlfred Perlstein 	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
458390065b1SAlfred Perlstein 	    ret[i++] = &pollfd->pollfd;
4598c8fff31SAndrew Thompson 	ret[i] = NULL;
4608c8fff31SAndrew Thompson 
461390065b1SAlfred Perlstein done:
462390065b1SAlfred Perlstein 	CTX_UNLOCK(ctx);
46322a962c9SEd Maste 	return ((const struct libusb_pollfd **)ret);
4648c8fff31SAndrew Thompson }
4658c8fff31SAndrew Thompson 
4668c8fff31SAndrew Thompson 
4678c8fff31SAndrew Thompson /* Synchronous device I/O */
4688c8fff31SAndrew Thompson 
4698c8fff31SAndrew Thompson 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)4708c8fff31SAndrew Thompson libusb_control_transfer(libusb_device_handle *devh,
4718c8fff31SAndrew Thompson     uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
472390065b1SAlfred Perlstein     uint8_t *data, uint16_t wLength, unsigned int timeout)
4738c8fff31SAndrew Thompson {
474390065b1SAlfred Perlstein 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
475390065b1SAlfred Perlstein 	int err;
476390065b1SAlfred Perlstein 	uint16_t actlen;
477390065b1SAlfred Perlstein 
478390065b1SAlfred Perlstein 	if (devh == NULL)
479390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
480390065b1SAlfred Perlstein 
481390065b1SAlfred Perlstein 	if ((wLength != 0) && (data == NULL))
482390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
483390065b1SAlfred Perlstein 
484390065b1SAlfred Perlstein 	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
485390065b1SAlfred Perlstein 
486390065b1SAlfred Perlstein 	req.bmRequestType = bmRequestType;
487390065b1SAlfred Perlstein 	req.bRequest = bRequest;
488390065b1SAlfred Perlstein 	req.wValue = wValue;
489390065b1SAlfred Perlstein 	req.wIndex = wIndex;
490390065b1SAlfred Perlstein 	req.wLength = wLength;
491390065b1SAlfred Perlstein 
492390065b1SAlfred Perlstein 	err = libusb20_dev_request_sync(devh, &req, data,
493390065b1SAlfred Perlstein 	    &actlen, timeout, 0);
494390065b1SAlfred Perlstein 
495390065b1SAlfred Perlstein 	if (err == LIBUSB20_ERROR_PIPE)
496390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_PIPE);
497390065b1SAlfred Perlstein 	else if (err == LIBUSB20_ERROR_TIMEOUT)
498390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_TIMEOUT);
499390065b1SAlfred Perlstein 	else if (err)
500390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_NO_DEVICE);
501390065b1SAlfred Perlstein 
502390065b1SAlfred Perlstein 	return (actlen);
503390065b1SAlfred Perlstein }
504390065b1SAlfred Perlstein 
5055b21ba5cSHans Petter Selasky static libusb_context *
libusb10_get_context_by_device_handle(libusb_device_handle * devh)5065b21ba5cSHans Petter Selasky libusb10_get_context_by_device_handle(libusb_device_handle *devh)
5075b21ba5cSHans Petter Selasky {
5085b21ba5cSHans Petter Selasky 	libusb_context *ctx;
5095b21ba5cSHans Petter Selasky 
5105b21ba5cSHans Petter Selasky 	if (devh != NULL)
5115b21ba5cSHans Petter Selasky 		ctx = libusb_get_device(devh)->ctx;
5125b21ba5cSHans Petter Selasky 	else
5135b21ba5cSHans Petter Selasky 		ctx = NULL;
5145b21ba5cSHans Petter Selasky 
5155b21ba5cSHans Petter Selasky 	return (GET_CONTEXT(ctx));
5165b21ba5cSHans Petter Selasky }
5175b21ba5cSHans Petter Selasky 
518390065b1SAlfred Perlstein static void
libusb10_do_transfer_cb(struct libusb_transfer * transfer)519390065b1SAlfred Perlstein libusb10_do_transfer_cb(struct libusb_transfer *transfer)
520390065b1SAlfred Perlstein {
5218c8fff31SAndrew Thompson 	libusb_context *ctx;
522390065b1SAlfred Perlstein 	int *pdone;
5238c8fff31SAndrew Thompson 
5245b21ba5cSHans Petter Selasky 	ctx = libusb10_get_context_by_device_handle(transfer->dev_handle);
5258c8fff31SAndrew Thompson 
526390065b1SAlfred Perlstein 	DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
5278c8fff31SAndrew Thompson 
528390065b1SAlfred Perlstein 	pdone = transfer->user_data;
529390065b1SAlfred Perlstein 	*pdone = 1;
5308c8fff31SAndrew Thompson }
5318c8fff31SAndrew Thompson 
532390065b1SAlfred Perlstein /*
533390065b1SAlfred Perlstein  * TODO: Replace the following function. Allocating and freeing on a
534390065b1SAlfred Perlstein  * per-transfer basis is slow.  --HPS
535390065b1SAlfred Perlstein  */
5368c8fff31SAndrew Thompson static int
libusb10_do_transfer(libusb_device_handle * devh,uint8_t endpoint,uint8_t * data,int length,int * transferred,unsigned int timeout,int type)537390065b1SAlfred Perlstein libusb10_do_transfer(libusb_device_handle *devh,
538390065b1SAlfred Perlstein     uint8_t endpoint, uint8_t *data, int length,
5398c8fff31SAndrew Thompson     int *transferred, unsigned int timeout, int type)
5408c8fff31SAndrew Thompson {
5418c8fff31SAndrew Thompson 	libusb_context *ctx;
542390065b1SAlfred Perlstein 	struct libusb_transfer *xfer;
543d81535d1SHans Petter Selasky 	int done;
5448c8fff31SAndrew Thompson 	int ret;
5458c8fff31SAndrew Thompson 
546390065b1SAlfred Perlstein 	if (devh == NULL)
547390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
548390065b1SAlfred Perlstein 
549390065b1SAlfred Perlstein 	if ((length != 0) && (data == NULL))
550390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
5518c8fff31SAndrew Thompson 
5528c8fff31SAndrew Thompson 	xfer = libusb_alloc_transfer(0);
5538c8fff31SAndrew Thompson 	if (xfer == NULL)
5548c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_NO_MEM);
5558c8fff31SAndrew Thompson 
556390065b1SAlfred Perlstein 	ctx = libusb_get_device(devh)->ctx;
5578c8fff31SAndrew Thompson 
5588c8fff31SAndrew Thompson 	xfer->dev_handle = devh;
5598c8fff31SAndrew Thompson 	xfer->endpoint = endpoint;
5608c8fff31SAndrew Thompson 	xfer->type = type;
5618c8fff31SAndrew Thompson 	xfer->timeout = timeout;
5628c8fff31SAndrew Thompson 	xfer->buffer = data;
5638c8fff31SAndrew Thompson 	xfer->length = length;
564d81535d1SHans Petter Selasky 	xfer->user_data = (void *)&done;
565390065b1SAlfred Perlstein 	xfer->callback = libusb10_do_transfer_cb;
566d81535d1SHans Petter Selasky 	done = 0;
5678c8fff31SAndrew Thompson 
5688c8fff31SAndrew Thompson 	if ((ret = libusb_submit_transfer(xfer)) < 0) {
5698c8fff31SAndrew Thompson 		libusb_free_transfer(xfer);
5708c8fff31SAndrew Thompson 		return (ret);
5718c8fff31SAndrew Thompson 	}
572d81535d1SHans Petter Selasky 	while (done == 0) {
5738c8fff31SAndrew Thompson 		if ((ret = libusb_handle_events(ctx)) < 0) {
5748c8fff31SAndrew Thompson 			libusb_cancel_transfer(xfer);
575390065b1SAlfred Perlstein 			usleep(1000);	/* nice it */
5768c8fff31SAndrew Thompson 		}
5778c8fff31SAndrew Thompson 	}
5788c8fff31SAndrew Thompson 
5798c8fff31SAndrew Thompson 	*transferred = xfer->actual_length;
580390065b1SAlfred Perlstein 
5818c8fff31SAndrew Thompson 	switch (xfer->status) {
5828c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_COMPLETED:
583390065b1SAlfred Perlstein 		ret = 0;
5848c8fff31SAndrew Thompson 		break;
5858c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_TIMED_OUT:
586390065b1SAlfred Perlstein 		ret = LIBUSB_ERROR_TIMEOUT;
587390065b1SAlfred Perlstein 		break;
5888c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_OVERFLOW:
589390065b1SAlfred Perlstein 		ret = LIBUSB_ERROR_OVERFLOW;
590390065b1SAlfred Perlstein 		break;
5918c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_STALL:
592390065b1SAlfred Perlstein 		ret = LIBUSB_ERROR_PIPE;
593390065b1SAlfred Perlstein 		break;
5948c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_NO_DEVICE:
595390065b1SAlfred Perlstein 		ret = LIBUSB_ERROR_NO_DEVICE;
5968c8fff31SAndrew Thompson 		break;
5978c8fff31SAndrew Thompson 	default:
5988c8fff31SAndrew Thompson 		ret = LIBUSB_ERROR_OTHER;
599390065b1SAlfred Perlstein 		break;
6008c8fff31SAndrew Thompson 	}
6018c8fff31SAndrew Thompson 
6028c8fff31SAndrew Thompson 	libusb_free_transfer(xfer);
6038c8fff31SAndrew Thompson 	return (ret);
6048c8fff31SAndrew Thompson }
6058c8fff31SAndrew Thompson 
6068c8fff31SAndrew Thompson int
libusb_bulk_transfer(libusb_device_handle * devh,uint8_t endpoint,uint8_t * data,int length,int * transferred,unsigned int timeout)607390065b1SAlfred Perlstein libusb_bulk_transfer(libusb_device_handle *devh,
608390065b1SAlfred Perlstein     uint8_t endpoint, uint8_t *data, int length,
6098c8fff31SAndrew Thompson     int *transferred, unsigned int timeout)
6108c8fff31SAndrew Thompson {
6118c8fff31SAndrew Thompson 	libusb_context *ctx;
6128c8fff31SAndrew Thompson 	int ret;
6138c8fff31SAndrew Thompson 
6145b21ba5cSHans Petter Selasky 	ctx = libusb10_get_context_by_device_handle(devh);
6155b21ba5cSHans Petter Selasky 
616c500e4ddSAndrew Thompson 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
6178c8fff31SAndrew Thompson 
618390065b1SAlfred Perlstein 	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
6198c8fff31SAndrew Thompson 	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
6208c8fff31SAndrew Thompson 
621c500e4ddSAndrew Thompson 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
6228c8fff31SAndrew Thompson 	return (ret);
6238c8fff31SAndrew Thompson }
6248c8fff31SAndrew Thompson 
6258c8fff31SAndrew Thompson int
libusb_interrupt_transfer(libusb_device_handle * devh,uint8_t endpoint,uint8_t * data,int length,int * transferred,unsigned int timeout)626390065b1SAlfred Perlstein libusb_interrupt_transfer(libusb_device_handle *devh,
627390065b1SAlfred Perlstein     uint8_t endpoint, uint8_t *data, int length,
6288c8fff31SAndrew Thompson     int *transferred, unsigned int timeout)
6298c8fff31SAndrew Thompson {
6308c8fff31SAndrew Thompson 	libusb_context *ctx;
6318c8fff31SAndrew Thompson 	int ret;
6328c8fff31SAndrew Thompson 
6335b21ba5cSHans Petter Selasky 	ctx = libusb10_get_context_by_device_handle(devh);
6345b21ba5cSHans Petter Selasky 
635c500e4ddSAndrew Thompson 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
6368c8fff31SAndrew Thompson 
637390065b1SAlfred Perlstein 	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
6388c8fff31SAndrew Thompson 	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
6398c8fff31SAndrew Thompson 
640c500e4ddSAndrew Thompson 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
6418c8fff31SAndrew Thompson 	return (ret);
6428c8fff31SAndrew Thompson }
643ccef4ddfSAndrew Thompson 
644ccef4ddfSAndrew Thompson uint8_t *
libusb_get_iso_packet_buffer(struct libusb_transfer * transfer,uint32_t off)645d81535d1SHans Petter Selasky libusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t off)
646ccef4ddfSAndrew Thompson {
647ccef4ddfSAndrew Thompson 	uint8_t *ptr;
648ccef4ddfSAndrew Thompson 	uint32_t n;
649ccef4ddfSAndrew Thompson 
650ccef4ddfSAndrew Thompson 	if (transfer->num_iso_packets < 0)
651ccef4ddfSAndrew Thompson 		return (NULL);
652ccef4ddfSAndrew Thompson 
653d81535d1SHans Petter Selasky 	if (off >= (uint32_t)transfer->num_iso_packets)
654ccef4ddfSAndrew Thompson 		return (NULL);
655ccef4ddfSAndrew Thompson 
656ccef4ddfSAndrew Thompson 	ptr = transfer->buffer;
657ccef4ddfSAndrew Thompson 	if (ptr == NULL)
658ccef4ddfSAndrew Thompson 		return (NULL);
659ccef4ddfSAndrew Thompson 
660d81535d1SHans Petter Selasky 	for (n = 0; n != off; n++) {
661ccef4ddfSAndrew Thompson 		ptr += transfer->iso_packet_desc[n].length;
662ccef4ddfSAndrew Thompson 	}
663ccef4ddfSAndrew Thompson 	return (ptr);
664ccef4ddfSAndrew Thompson }
665ccef4ddfSAndrew Thompson 
666ccef4ddfSAndrew Thompson uint8_t *
libusb_get_iso_packet_buffer_simple(struct libusb_transfer * transfer,uint32_t off)667d81535d1SHans Petter Selasky libusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t off)
668ccef4ddfSAndrew Thompson {
669ccef4ddfSAndrew Thompson 	uint8_t *ptr;
670ccef4ddfSAndrew Thompson 
671ccef4ddfSAndrew Thompson 	if (transfer->num_iso_packets < 0)
672ccef4ddfSAndrew Thompson 		return (NULL);
673ccef4ddfSAndrew Thompson 
674d81535d1SHans Petter Selasky 	if (off >= (uint32_t)transfer->num_iso_packets)
675ccef4ddfSAndrew Thompson 		return (NULL);
676ccef4ddfSAndrew Thompson 
677ccef4ddfSAndrew Thompson 	ptr = transfer->buffer;
678ccef4ddfSAndrew Thompson 	if (ptr == NULL)
679ccef4ddfSAndrew Thompson 		return (NULL);
680ccef4ddfSAndrew Thompson 
681d81535d1SHans Petter Selasky 	ptr += transfer->iso_packet_desc[0].length * off;
682ccef4ddfSAndrew Thompson 
683ccef4ddfSAndrew Thompson 	return (ptr);
684ccef4ddfSAndrew Thompson }
685ccef4ddfSAndrew Thompson 
686ccef4ddfSAndrew Thompson void
libusb_set_iso_packet_lengths(struct libusb_transfer * transfer,uint32_t length)687ccef4ddfSAndrew Thompson libusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length)
688ccef4ddfSAndrew Thompson {
689ccef4ddfSAndrew Thompson 	int n;
690ccef4ddfSAndrew Thompson 
691ccef4ddfSAndrew Thompson 	if (transfer->num_iso_packets < 0)
692ccef4ddfSAndrew Thompson 		return;
693ccef4ddfSAndrew Thompson 
694ccef4ddfSAndrew Thompson 	for (n = 0; n != transfer->num_iso_packets; n++)
695ccef4ddfSAndrew Thompson 		transfer->iso_packet_desc[n].length = length;
696ccef4ddfSAndrew Thompson }
697ccef4ddfSAndrew Thompson 
698ccef4ddfSAndrew Thompson uint8_t *
libusb_control_transfer_get_data(struct libusb_transfer * transfer)699ccef4ddfSAndrew Thompson libusb_control_transfer_get_data(struct libusb_transfer *transfer)
700ccef4ddfSAndrew Thompson {
701ccef4ddfSAndrew Thompson 	if (transfer->buffer == NULL)
702ccef4ddfSAndrew Thompson 		return (NULL);
703ccef4ddfSAndrew Thompson 
704ccef4ddfSAndrew Thompson 	return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
705ccef4ddfSAndrew Thompson }
706ccef4ddfSAndrew Thompson 
707ccef4ddfSAndrew Thompson struct libusb_control_setup *
libusb_control_transfer_get_setup(struct libusb_transfer * transfer)708ccef4ddfSAndrew Thompson libusb_control_transfer_get_setup(struct libusb_transfer *transfer)
709ccef4ddfSAndrew Thompson {
710ccef4ddfSAndrew Thompson 	return ((struct libusb_control_setup *)transfer->buffer);
711ccef4ddfSAndrew Thompson }
712ccef4ddfSAndrew Thompson 
713ccef4ddfSAndrew Thompson void
libusb_fill_control_setup(uint8_t * buf,uint8_t bmRequestType,uint8_t bRequest,uint16_t wValue,uint16_t wIndex,uint16_t wLength)714ccef4ddfSAndrew Thompson libusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType,
715ccef4ddfSAndrew Thompson     uint8_t bRequest, uint16_t wValue,
716ccef4ddfSAndrew Thompson     uint16_t wIndex, uint16_t wLength)
717ccef4ddfSAndrew Thompson {
718ccef4ddfSAndrew Thompson 	struct libusb_control_setup *req = (struct libusb_control_setup *)buf;
719ccef4ddfSAndrew Thompson 
720ccef4ddfSAndrew Thompson 	/* The alignment is OK for all fields below. */
721ccef4ddfSAndrew Thompson 	req->bmRequestType = bmRequestType;
722ccef4ddfSAndrew Thompson 	req->bRequest = bRequest;
723ccef4ddfSAndrew Thompson 	req->wValue = htole16(wValue);
724ccef4ddfSAndrew Thompson 	req->wIndex = htole16(wIndex);
725ccef4ddfSAndrew Thompson 	req->wLength = htole16(wLength);
726ccef4ddfSAndrew Thompson }
727ccef4ddfSAndrew Thompson 
728ccef4ddfSAndrew Thompson 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)729ccef4ddfSAndrew Thompson libusb_fill_control_transfer(struct libusb_transfer *transfer,
730ccef4ddfSAndrew Thompson     libusb_device_handle *devh, uint8_t *buf,
731ccef4ddfSAndrew Thompson     libusb_transfer_cb_fn callback, void *user_data,
732ccef4ddfSAndrew Thompson     uint32_t timeout)
733ccef4ddfSAndrew Thompson {
734ccef4ddfSAndrew Thompson 	struct libusb_control_setup *setup = (struct libusb_control_setup *)buf;
735ccef4ddfSAndrew Thompson 
736ccef4ddfSAndrew Thompson 	transfer->dev_handle = devh;
737ccef4ddfSAndrew Thompson 	transfer->endpoint = 0;
738ccef4ddfSAndrew Thompson 	transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
739ccef4ddfSAndrew Thompson 	transfer->timeout = timeout;
740ccef4ddfSAndrew Thompson 	transfer->buffer = buf;
741ccef4ddfSAndrew Thompson 	if (setup != NULL)
742ccef4ddfSAndrew Thompson 		transfer->length = LIBUSB_CONTROL_SETUP_SIZE
743ccef4ddfSAndrew Thompson 			+ le16toh(setup->wLength);
744ccef4ddfSAndrew Thompson 	else
745ccef4ddfSAndrew Thompson 		transfer->length = 0;
746ccef4ddfSAndrew Thompson 	transfer->user_data = user_data;
747ccef4ddfSAndrew Thompson 	transfer->callback = callback;
748ccef4ddfSAndrew Thompson 
749ccef4ddfSAndrew Thompson }
750ccef4ddfSAndrew Thompson 
751ccef4ddfSAndrew Thompson 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)752ccef4ddfSAndrew Thompson libusb_fill_bulk_transfer(struct libusb_transfer *transfer,
753ccef4ddfSAndrew Thompson     libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
754ccef4ddfSAndrew Thompson     int length, libusb_transfer_cb_fn callback, void *user_data,
755ccef4ddfSAndrew Thompson     uint32_t timeout)
756ccef4ddfSAndrew Thompson {
757ccef4ddfSAndrew Thompson 	transfer->dev_handle = devh;
758ccef4ddfSAndrew Thompson 	transfer->endpoint = endpoint;
759ccef4ddfSAndrew Thompson 	transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
760ccef4ddfSAndrew Thompson 	transfer->timeout = timeout;
761ccef4ddfSAndrew Thompson 	transfer->buffer = buf;
762ccef4ddfSAndrew Thompson 	transfer->length = length;
763ccef4ddfSAndrew Thompson 	transfer->user_data = user_data;
764ccef4ddfSAndrew Thompson 	transfer->callback = callback;
765ccef4ddfSAndrew Thompson }
766ccef4ddfSAndrew Thompson 
767ccef4ddfSAndrew Thompson 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)768ccef4ddfSAndrew Thompson libusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
769ccef4ddfSAndrew Thompson     libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
770ccef4ddfSAndrew Thompson     int length, libusb_transfer_cb_fn callback, void *user_data,
771ccef4ddfSAndrew Thompson     uint32_t timeout)
772ccef4ddfSAndrew Thompson {
773ccef4ddfSAndrew Thompson 	transfer->dev_handle = devh;
774ccef4ddfSAndrew Thompson 	transfer->endpoint = endpoint;
775ccef4ddfSAndrew Thompson 	transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
776ccef4ddfSAndrew Thompson 	transfer->timeout = timeout;
777ccef4ddfSAndrew Thompson 	transfer->buffer = buf;
778ccef4ddfSAndrew Thompson 	transfer->length = length;
779ccef4ddfSAndrew Thompson 	transfer->user_data = user_data;
780ccef4ddfSAndrew Thompson 	transfer->callback = callback;
781ccef4ddfSAndrew Thompson }
782ccef4ddfSAndrew Thompson 
783ccef4ddfSAndrew Thompson 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)784ccef4ddfSAndrew Thompson libusb_fill_iso_transfer(struct libusb_transfer *transfer,
785ccef4ddfSAndrew Thompson     libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
786ccef4ddfSAndrew Thompson     int length, int npacket, libusb_transfer_cb_fn callback,
787ccef4ddfSAndrew Thompson     void *user_data, uint32_t timeout)
788ccef4ddfSAndrew Thompson {
789ccef4ddfSAndrew Thompson 	transfer->dev_handle = devh;
790ccef4ddfSAndrew Thompson 	transfer->endpoint = endpoint;
791ccef4ddfSAndrew Thompson 	transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
792ccef4ddfSAndrew Thompson 	transfer->timeout = timeout;
793ccef4ddfSAndrew Thompson 	transfer->buffer = buf;
794ccef4ddfSAndrew Thompson 	transfer->length = length;
795ccef4ddfSAndrew Thompson 	transfer->num_iso_packets = npacket;
796ccef4ddfSAndrew Thompson 	transfer->user_data = user_data;
797ccef4ddfSAndrew Thompson 	transfer->callback = callback;
798ccef4ddfSAndrew Thompson }
799ccef4ddfSAndrew Thompson 
800a0c93fa3SHans Petter Selasky int
libusb_alloc_streams(libusb_device_handle * dev,uint32_t num_streams,unsigned char * endpoints,int num_endpoints)801a0c93fa3SHans Petter Selasky libusb_alloc_streams(libusb_device_handle *dev, uint32_t num_streams,
802a0c93fa3SHans Petter Selasky     unsigned char *endpoints, int num_endpoints)
803a0c93fa3SHans Petter Selasky {
804a0c93fa3SHans Petter Selasky 	if (num_streams > 1)
805a0c93fa3SHans Petter Selasky 		return (LIBUSB_ERROR_INVALID_PARAM);
806a0c93fa3SHans Petter Selasky 	return (0);
807a0c93fa3SHans Petter Selasky }
808a0c93fa3SHans Petter Selasky 
809a0c93fa3SHans Petter Selasky int
libusb_free_streams(libusb_device_handle * dev,unsigned char * endpoints,int num_endpoints)810a0c93fa3SHans Petter Selasky libusb_free_streams(libusb_device_handle *dev, unsigned char *endpoints, int num_endpoints)
811a0c93fa3SHans Petter Selasky {
812a0c93fa3SHans Petter Selasky 
813a0c93fa3SHans Petter Selasky 	return (0);
814a0c93fa3SHans Petter Selasky }
815a0c93fa3SHans Petter Selasky 
816a0c93fa3SHans Petter Selasky void
libusb_transfer_set_stream_id(struct libusb_transfer * transfer,uint32_t stream_id)817a0c93fa3SHans Petter Selasky libusb_transfer_set_stream_id(struct libusb_transfer *transfer, uint32_t stream_id)
818a0c93fa3SHans Petter Selasky {
819a0c93fa3SHans Petter Selasky 	struct libusb_super_transfer *sxfer;
820a0c93fa3SHans Petter Selasky 
821a0c93fa3SHans Petter Selasky 	if (transfer == NULL)
822a0c93fa3SHans Petter Selasky 		return;
823a0c93fa3SHans Petter Selasky 
824a0c93fa3SHans Petter Selasky 	sxfer = (struct libusb_super_transfer *)(
825a0c93fa3SHans Petter Selasky 	    ((uint8_t *)transfer) - sizeof(*sxfer));
826a0c93fa3SHans Petter Selasky 
827a0c93fa3SHans Petter Selasky 	/* set stream ID */
828a0c93fa3SHans Petter Selasky 	sxfer->stream_id = stream_id;
829a0c93fa3SHans Petter Selasky }
830a0c93fa3SHans Petter Selasky 
831a0c93fa3SHans Petter Selasky uint32_t
libusb_transfer_get_stream_id(struct libusb_transfer * transfer)832a0c93fa3SHans Petter Selasky libusb_transfer_get_stream_id(struct libusb_transfer *transfer)
833a0c93fa3SHans Petter Selasky {
834a0c93fa3SHans Petter Selasky 	struct libusb_super_transfer *sxfer;
835a0c93fa3SHans Petter Selasky 
836a0c93fa3SHans Petter Selasky 	if (transfer == NULL)
837a0c93fa3SHans Petter Selasky 		return (0);
838a0c93fa3SHans Petter Selasky 
839a0c93fa3SHans Petter Selasky 	sxfer = (struct libusb_super_transfer *)(
840a0c93fa3SHans Petter Selasky 	    ((uint8_t *)transfer) - sizeof(*sxfer));
841a0c93fa3SHans Petter Selasky 
842a0c93fa3SHans Petter Selasky 	/* get stream ID */
843a0c93fa3SHans Petter Selasky 	return (sxfer->stream_id);
844a0c93fa3SHans Petter Selasky }
845