1194676Sthompsa/* $FreeBSD: stable/11/lib/libusb/libusb10_io.c 339189 2018-10-05 07:49:01Z hselasky $ */
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
162338788Shselasky			if (fds[i].revents != 0) {
163199055Sthompsa				err = libusb20_dev_process(ppdev[i]);
164199055Sthompsa
165338788Shselasky				if (err) {
166338788Shselasky					/* set device is gone */
167338788Shselasky					dev->device_is_gone = 1;
168199055Sthompsa
169338788Shselasky					/* remove USB device from polling loop */
170338788Shselasky					libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
171338788Shselasky
172338788Shselasky					/* cancel all pending transfers */
173338788Shselasky					libusb10_cancel_all_transfer_locked(ppdev[i], dev);
174338788Shselasky				}
175195957Salfred			}
176195957Salfred			CTX_UNLOCK(ctx);
177195957Salfred			libusb_unref_device(dev);
178195957Salfred			CTX_LOCK(ctx);
179194676Sthompsa
180195957Salfred		} else {
181195957Salfred			uint8_t dummy;
182194676Sthompsa
183338788Shselasky			while (read(fds[i].fd, &dummy, 1) == 1)
184338788Shselasky				;
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);
313339189Shselasky		/* try to grab polling of actual events, if any */
314339189Shselasky		if (ctx->ctx_handler == NO_THREAD)
315339189Shselasky			ctx->ctx_handler = pthread_self();
316194676Sthompsa		return (0);
317194676Sthompsa	}
318236944Shselasky	err = clock_gettime(CLOCK_MONOTONIC, &ts);
319195957Salfred	if (err < 0)
320194676Sthompsa		return (LIBUSB_ERROR_OTHER);
321194676Sthompsa
322236944Shselasky	/*
323236944Shselasky	 * The "tv" arguments points to a relative time structure and
324236944Shselasky	 * not an absolute time structure.
325236944Shselasky	 */
326236944Shselasky	ts.tv_sec += tv->tv_sec;
327236944Shselasky	ts.tv_nsec += tv->tv_usec * 1000;
328195957Salfred	if (ts.tv_nsec >= 1000000000) {
329194676Sthompsa		ts.tv_nsec -= 1000000000;
330194676Sthompsa		ts.tv_sec++;
331194676Sthompsa	}
332195957Salfred	err = pthread_cond_timedwait(&ctx->ctx_cond,
333195957Salfred	    &ctx->ctx_lock, &ts);
334339189Shselasky	/* try to grab polling of actual events, if any */
335339189Shselasky	if (ctx->ctx_handler == NO_THREAD)
336339189Shselasky		ctx->ctx_handler = pthread_self();
337194676Sthompsa
338195957Salfred	if (err == ETIMEDOUT)
339194676Sthompsa		return (1);
340194676Sthompsa
341194676Sthompsa	return (0);
342194676Sthompsa}
343194676Sthompsa
344194676Sthompsaint
345260315Shselaskylibusb_handle_events_timeout_completed(libusb_context *ctx,
346260315Shselasky    struct timeval *tv, int *completed)
347194676Sthompsa{
348260315Shselasky	int err = 0;
349195957Salfred
350195957Salfred	ctx = GET_CONTEXT(ctx);
351195957Salfred
352260315Shselasky	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter");
353194676Sthompsa
354195957Salfred	libusb_lock_events(ctx);
355194676Sthompsa
356260315Shselasky	while (1) {
357260315Shselasky		if (completed != NULL) {
358260315Shselasky			if (*completed != 0 || err != 0)
359260315Shselasky				break;
360260315Shselasky		}
361260315Shselasky		err = libusb_handle_events_locked(ctx, tv);
362260315Shselasky		if (completed == NULL)
363260315Shselasky			break;
364260315Shselasky	}
365194676Sthompsa
366195957Salfred	libusb_unlock_events(ctx);
367194676Sthompsa
368260315Shselasky	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit");
369195957Salfred
370195957Salfred	return (err);
371194676Sthompsa}
372194676Sthompsa
373194676Sthompsaint
374260315Shselaskylibusb_handle_events_completed(libusb_context *ctx, int *completed)
375260315Shselasky{
376260315Shselasky	return (libusb_handle_events_timeout_completed(ctx, NULL, completed));
377260315Shselasky}
378260315Shselasky
379260315Shselaskyint
380260315Shselaskylibusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
381260315Shselasky{
382260315Shselasky	return (libusb_handle_events_timeout_completed(ctx, tv, NULL));
383260315Shselasky}
384260315Shselasky
385260315Shselaskyint
386195957Salfredlibusb_handle_events(libusb_context *ctx)
387194676Sthompsa{
388260315Shselasky	return (libusb_handle_events_timeout_completed(ctx, NULL, NULL));
389194676Sthompsa}
390194676Sthompsa
391194676Sthompsaint
392195957Salfredlibusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
393194676Sthompsa{
394195957Salfred	int err;
395194676Sthompsa
396195957Salfred	ctx = GET_CONTEXT(ctx);
397194676Sthompsa
398195957Salfred	if (libusb_event_handling_ok(ctx)) {
399195957Salfred		err = libusb10_handle_events_sub(ctx, tv);
400195957Salfred	} else {
401260315Shselasky		err = libusb_wait_for_event(ctx, tv);
402260315Shselasky		if (err != 0)
403260315Shselasky			err = LIBUSB_ERROR_TIMEOUT;
404194676Sthompsa	}
405195957Salfred	return (err);
406194676Sthompsa}
407194676Sthompsa
408194676Sthompsaint
409195957Salfredlibusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
410194676Sthompsa{
411195957Salfred	/* all timeouts are currently being done by the kernel */
412195957Salfred	timerclear(tv);
413195957Salfred	return (0);
414194676Sthompsa}
415194676Sthompsa
416194676Sthompsavoid
417195957Salfredlibusb_set_pollfd_notifiers(libusb_context *ctx,
418194676Sthompsa    libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
419194676Sthompsa    void *user_data)
420194676Sthompsa{
421195957Salfred	ctx = GET_CONTEXT(ctx);
422194676Sthompsa
423194676Sthompsa	ctx->fd_added_cb = added_cb;
424194676Sthompsa	ctx->fd_removed_cb = removed_cb;
425194676Sthompsa	ctx->fd_cb_user_data = user_data;
426194676Sthompsa}
427194676Sthompsa
428250335Semasteconst struct libusb_pollfd **
429195957Salfredlibusb_get_pollfds(libusb_context *ctx)
430194676Sthompsa{
431195957Salfred	struct libusb_super_pollfd *pollfd;
432194676Sthompsa	libusb_pollfd **ret;
433194676Sthompsa	int i;
434194676Sthompsa
435195957Salfred	ctx = GET_CONTEXT(ctx);
436194676Sthompsa
437195957Salfred	CTX_LOCK(ctx);
438195957Salfred
439194676Sthompsa	i = 0;
440195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
441195957Salfred	    i++;
442194676Sthompsa
443195957Salfred	ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
444195957Salfred	if (ret == NULL)
445195957Salfred		goto done;
446194676Sthompsa
447194676Sthompsa	i = 0;
448195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
449195957Salfred	    ret[i++] = &pollfd->pollfd;
450194676Sthompsa	ret[i] = NULL;
451194676Sthompsa
452195957Salfreddone:
453195957Salfred	CTX_UNLOCK(ctx);
454250335Semaste	return ((const struct libusb_pollfd **)ret);
455194676Sthompsa}
456194676Sthompsa
457194676Sthompsa
458194676Sthompsa/* Synchronous device I/O */
459194676Sthompsa
460194676Sthompsaint
461195957Salfredlibusb_control_transfer(libusb_device_handle *devh,
462194676Sthompsa    uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
463195957Salfred    uint8_t *data, uint16_t wLength, unsigned int timeout)
464194676Sthompsa{
465195957Salfred	struct LIBUSB20_CONTROL_SETUP_DECODED req;
466195957Salfred	int err;
467195957Salfred	uint16_t actlen;
468194676Sthompsa
469195957Salfred	if (devh == NULL)
470195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
471194676Sthompsa
472195957Salfred	if ((wLength != 0) && (data == NULL))
473195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
474194676Sthompsa
475195957Salfred	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
476194676Sthompsa
477195957Salfred	req.bmRequestType = bmRequestType;
478195957Salfred	req.bRequest = bRequest;
479195957Salfred	req.wValue = wValue;
480195957Salfred	req.wIndex = wIndex;
481195957Salfred	req.wLength = wLength;
482194676Sthompsa
483195957Salfred	err = libusb20_dev_request_sync(devh, &req, data,
484195957Salfred	    &actlen, timeout, 0);
485194676Sthompsa
486195957Salfred	if (err == LIBUSB20_ERROR_PIPE)
487195957Salfred		return (LIBUSB_ERROR_PIPE);
488195957Salfred	else if (err == LIBUSB20_ERROR_TIMEOUT)
489195957Salfred		return (LIBUSB_ERROR_TIMEOUT);
490195957Salfred	else if (err)
491195957Salfred		return (LIBUSB_ERROR_NO_DEVICE);
492194676Sthompsa
493195957Salfred	return (actlen);
494195957Salfred}
495194676Sthompsa
496338791Shselaskystatic libusb_context *
497338791Shselaskylibusb10_get_context_by_device_handle(libusb_device_handle *devh)
498338791Shselasky{
499338791Shselasky	libusb_context *ctx;
500338791Shselasky
501338791Shselasky	if (devh != NULL)
502338791Shselasky		ctx = libusb_get_device(devh)->ctx;
503338791Shselasky	else
504338791Shselasky		ctx = NULL;
505338791Shselasky
506338791Shselasky	return (GET_CONTEXT(ctx));
507338791Shselasky}
508338791Shselasky
509195957Salfredstatic void
510195957Salfredlibusb10_do_transfer_cb(struct libusb_transfer *transfer)
511195957Salfred{
512195957Salfred	libusb_context *ctx;
513195957Salfred	int *pdone;
514194676Sthompsa
515338791Shselasky	ctx = libusb10_get_context_by_device_handle(transfer->dev_handle);
516194676Sthompsa
517195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
518194676Sthompsa
519195957Salfred	pdone = transfer->user_data;
520195957Salfred	*pdone = 1;
521194676Sthompsa}
522194676Sthompsa
523195957Salfred/*
524195957Salfred * TODO: Replace the following function. Allocating and freeing on a
525195957Salfred * per-transfer basis is slow.  --HPS
526195957Salfred */
527194676Sthompsastatic int
528195957Salfredlibusb10_do_transfer(libusb_device_handle *devh,
529195957Salfred    uint8_t endpoint, uint8_t *data, int length,
530194676Sthompsa    int *transferred, unsigned int timeout, int type)
531194676Sthompsa{
532195957Salfred	libusb_context *ctx;
533194676Sthompsa	struct libusb_transfer *xfer;
534234491Shselasky	int done;
535194676Sthompsa	int ret;
536194676Sthompsa
537195957Salfred	if (devh == NULL)
538195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
539194676Sthompsa
540195957Salfred	if ((length != 0) && (data == NULL))
541195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
542195957Salfred
543194676Sthompsa	xfer = libusb_alloc_transfer(0);
544194676Sthompsa	if (xfer == NULL)
545194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
546194676Sthompsa
547195957Salfred	ctx = libusb_get_device(devh)->ctx;
548194676Sthompsa
549194676Sthompsa	xfer->dev_handle = devh;
550194676Sthompsa	xfer->endpoint = endpoint;
551194676Sthompsa	xfer->type = type;
552194676Sthompsa	xfer->timeout = timeout;
553194676Sthompsa	xfer->buffer = data;
554194676Sthompsa	xfer->length = length;
555234491Shselasky	xfer->user_data = (void *)&done;
556195957Salfred	xfer->callback = libusb10_do_transfer_cb;
557234491Shselasky	done = 0;
558194676Sthompsa
559194676Sthompsa	if ((ret = libusb_submit_transfer(xfer)) < 0) {
560194676Sthompsa		libusb_free_transfer(xfer);
561194676Sthompsa		return (ret);
562194676Sthompsa	}
563234491Shselasky	while (done == 0) {
564194676Sthompsa		if ((ret = libusb_handle_events(ctx)) < 0) {
565194676Sthompsa			libusb_cancel_transfer(xfer);
566195957Salfred			usleep(1000);	/* nice it */
567194676Sthompsa		}
568194676Sthompsa	}
569194676Sthompsa
570194676Sthompsa	*transferred = xfer->actual_length;
571195957Salfred
572194676Sthompsa	switch (xfer->status) {
573194676Sthompsa	case LIBUSB_TRANSFER_COMPLETED:
574195957Salfred		ret = 0;
575194676Sthompsa		break;
576194676Sthompsa	case LIBUSB_TRANSFER_TIMED_OUT:
577195957Salfred		ret = LIBUSB_ERROR_TIMEOUT;
578195957Salfred		break;
579194676Sthompsa	case LIBUSB_TRANSFER_OVERFLOW:
580195957Salfred		ret = LIBUSB_ERROR_OVERFLOW;
581195957Salfred		break;
582194676Sthompsa	case LIBUSB_TRANSFER_STALL:
583195957Salfred		ret = LIBUSB_ERROR_PIPE;
584195957Salfred		break;
585194676Sthompsa	case LIBUSB_TRANSFER_NO_DEVICE:
586195957Salfred		ret = LIBUSB_ERROR_NO_DEVICE;
587194676Sthompsa		break;
588194676Sthompsa	default:
589194676Sthompsa		ret = LIBUSB_ERROR_OTHER;
590195957Salfred		break;
591194676Sthompsa	}
592194676Sthompsa
593194676Sthompsa	libusb_free_transfer(xfer);
594194676Sthompsa	return (ret);
595194676Sthompsa}
596194676Sthompsa
597194676Sthompsaint
598195957Salfredlibusb_bulk_transfer(libusb_device_handle *devh,
599195957Salfred    uint8_t endpoint, uint8_t *data, int length,
600194676Sthompsa    int *transferred, unsigned int timeout)
601194676Sthompsa{
602194676Sthompsa	libusb_context *ctx;
603194676Sthompsa	int ret;
604195957Salfred
605338791Shselasky	ctx = libusb10_get_context_by_device_handle(devh);
606338791Shselasky
607195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
608194676Sthompsa
609195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
610194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
611194676Sthompsa
612195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
613194676Sthompsa	return (ret);
614194676Sthompsa}
615194676Sthompsa
616194676Sthompsaint
617195957Salfredlibusb_interrupt_transfer(libusb_device_handle *devh,
618195957Salfred    uint8_t endpoint, uint8_t *data, int length,
619194676Sthompsa    int *transferred, unsigned int timeout)
620194676Sthompsa{
621194676Sthompsa	libusb_context *ctx;
622194676Sthompsa	int ret;
623194676Sthompsa
624338791Shselasky	ctx = libusb10_get_context_by_device_handle(devh);
625338791Shselasky
626195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
627194676Sthompsa
628195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
629194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
630194676Sthompsa
631195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
632194676Sthompsa	return (ret);
633194676Sthompsa}
634199055Sthompsa
635199055Sthompsauint8_t *
636234491Shselaskylibusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t off)
637199055Sthompsa{
638199055Sthompsa	uint8_t *ptr;
639199055Sthompsa	uint32_t n;
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	for (n = 0; n != off; n++) {
652199055Sthompsa		ptr += transfer->iso_packet_desc[n].length;
653199055Sthompsa	}
654199055Sthompsa	return (ptr);
655199055Sthompsa}
656199055Sthompsa
657199055Sthompsauint8_t *
658234491Shselaskylibusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t off)
659199055Sthompsa{
660199055Sthompsa	uint8_t *ptr;
661199055Sthompsa
662199055Sthompsa	if (transfer->num_iso_packets < 0)
663199055Sthompsa		return (NULL);
664199055Sthompsa
665234491Shselasky	if (off >= (uint32_t)transfer->num_iso_packets)
666199055Sthompsa		return (NULL);
667199055Sthompsa
668199055Sthompsa	ptr = transfer->buffer;
669199055Sthompsa	if (ptr == NULL)
670199055Sthompsa		return (NULL);
671199055Sthompsa
672234491Shselasky	ptr += transfer->iso_packet_desc[0].length * off;
673199055Sthompsa
674199055Sthompsa	return (ptr);
675199055Sthompsa}
676199055Sthompsa
677199055Sthompsavoid
678199055Sthompsalibusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length)
679199055Sthompsa{
680199055Sthompsa	int n;
681199055Sthompsa
682199055Sthompsa	if (transfer->num_iso_packets < 0)
683199055Sthompsa		return;
684199055Sthompsa
685199055Sthompsa	for (n = 0; n != transfer->num_iso_packets; n++)
686199055Sthompsa		transfer->iso_packet_desc[n].length = length;
687199055Sthompsa}
688199055Sthompsa
689199055Sthompsauint8_t *
690199055Sthompsalibusb_control_transfer_get_data(struct libusb_transfer *transfer)
691199055Sthompsa{
692199055Sthompsa	if (transfer->buffer == NULL)
693199055Sthompsa		return (NULL);
694199055Sthompsa
695199055Sthompsa	return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
696199055Sthompsa}
697199055Sthompsa
698199055Sthompsastruct libusb_control_setup *
699199055Sthompsalibusb_control_transfer_get_setup(struct libusb_transfer *transfer)
700199055Sthompsa{
701199055Sthompsa	return ((struct libusb_control_setup *)transfer->buffer);
702199055Sthompsa}
703199055Sthompsa
704199055Sthompsavoid
705199055Sthompsalibusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType,
706199055Sthompsa    uint8_t bRequest, uint16_t wValue,
707199055Sthompsa    uint16_t wIndex, uint16_t wLength)
708199055Sthompsa{
709199055Sthompsa	struct libusb_control_setup *req = (struct libusb_control_setup *)buf;
710199055Sthompsa
711199055Sthompsa	/* The alignment is OK for all fields below. */
712199055Sthompsa	req->bmRequestType = bmRequestType;
713199055Sthompsa	req->bRequest = bRequest;
714199055Sthompsa	req->wValue = htole16(wValue);
715199055Sthompsa	req->wIndex = htole16(wIndex);
716199055Sthompsa	req->wLength = htole16(wLength);
717199055Sthompsa}
718199055Sthompsa
719199055Sthompsavoid
720199055Sthompsalibusb_fill_control_transfer(struct libusb_transfer *transfer,
721199055Sthompsa    libusb_device_handle *devh, uint8_t *buf,
722199055Sthompsa    libusb_transfer_cb_fn callback, void *user_data,
723199055Sthompsa    uint32_t timeout)
724199055Sthompsa{
725199055Sthompsa	struct libusb_control_setup *setup = (struct libusb_control_setup *)buf;
726199055Sthompsa
727199055Sthompsa	transfer->dev_handle = devh;
728199055Sthompsa	transfer->endpoint = 0;
729199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
730199055Sthompsa	transfer->timeout = timeout;
731199055Sthompsa	transfer->buffer = buf;
732199055Sthompsa	if (setup != NULL)
733199055Sthompsa		transfer->length = LIBUSB_CONTROL_SETUP_SIZE
734199055Sthompsa			+ le16toh(setup->wLength);
735199055Sthompsa	else
736199055Sthompsa		transfer->length = 0;
737199055Sthompsa	transfer->user_data = user_data;
738199055Sthompsa	transfer->callback = callback;
739199055Sthompsa
740199055Sthompsa}
741199055Sthompsa
742199055Sthompsavoid
743199055Sthompsalibusb_fill_bulk_transfer(struct libusb_transfer *transfer,
744199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
745199055Sthompsa    int length, libusb_transfer_cb_fn callback, void *user_data,
746199055Sthompsa    uint32_t timeout)
747199055Sthompsa{
748199055Sthompsa	transfer->dev_handle = devh;
749199055Sthompsa	transfer->endpoint = endpoint;
750199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
751199055Sthompsa	transfer->timeout = timeout;
752199055Sthompsa	transfer->buffer = buf;
753199055Sthompsa	transfer->length = length;
754199055Sthompsa	transfer->user_data = user_data;
755199055Sthompsa	transfer->callback = callback;
756199055Sthompsa}
757199055Sthompsa
758199055Sthompsavoid
759199055Sthompsalibusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
760199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
761199055Sthompsa    int length, libusb_transfer_cb_fn callback, void *user_data,
762199055Sthompsa    uint32_t timeout)
763199055Sthompsa{
764199055Sthompsa	transfer->dev_handle = devh;
765199055Sthompsa	transfer->endpoint = endpoint;
766199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
767199055Sthompsa	transfer->timeout = timeout;
768199055Sthompsa	transfer->buffer = buf;
769199055Sthompsa	transfer->length = length;
770199055Sthompsa	transfer->user_data = user_data;
771199055Sthompsa	transfer->callback = callback;
772199055Sthompsa}
773199055Sthompsa
774199055Sthompsavoid
775199055Sthompsalibusb_fill_iso_transfer(struct libusb_transfer *transfer,
776199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
777199055Sthompsa    int length, int npacket, libusb_transfer_cb_fn callback,
778199055Sthompsa    void *user_data, uint32_t timeout)
779199055Sthompsa{
780199055Sthompsa	transfer->dev_handle = devh;
781199055Sthompsa	transfer->endpoint = endpoint;
782199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
783199055Sthompsa	transfer->timeout = timeout;
784199055Sthompsa	transfer->buffer = buf;
785199055Sthompsa	transfer->length = length;
786199055Sthompsa	transfer->num_iso_packets = npacket;
787199055Sthompsa	transfer->user_data = user_data;
788199055Sthompsa	transfer->callback = callback;
789199055Sthompsa}
790199055Sthompsa
791302125Shselaskyint
792302125Shselaskylibusb_alloc_streams(libusb_device_handle *dev, uint32_t num_streams,
793302125Shselasky    unsigned char *endpoints, int num_endpoints)
794302125Shselasky{
795302125Shselasky	if (num_streams > 1)
796302125Shselasky		return (LIBUSB_ERROR_INVALID_PARAM);
797302125Shselasky	return (0);
798302125Shselasky}
799302125Shselasky
800302125Shselaskyint
801302125Shselaskylibusb_free_streams(libusb_device_handle *dev, unsigned char *endpoints, int num_endpoints)
802302125Shselasky{
803302125Shselasky
804302125Shselasky	return (0);
805302125Shselasky}
806302125Shselasky
807302125Shselaskyvoid
808302125Shselaskylibusb_transfer_set_stream_id(struct libusb_transfer *transfer, uint32_t stream_id)
809302125Shselasky{
810302125Shselasky	struct libusb_super_transfer *sxfer;
811302125Shselasky
812302125Shselasky	if (transfer == NULL)
813302125Shselasky		return;
814302125Shselasky
815302125Shselasky	sxfer = (struct libusb_super_transfer *)(
816302125Shselasky	    ((uint8_t *)transfer) - sizeof(*sxfer));
817302125Shselasky
818302125Shselasky	/* set stream ID */
819302125Shselasky	sxfer->stream_id = stream_id;
820302125Shselasky}
821302125Shselasky
822302125Shselaskyuint32_t
823302125Shselaskylibusb_transfer_get_stream_id(struct libusb_transfer *transfer)
824302125Shselasky{
825302125Shselasky	struct libusb_super_transfer *sxfer;
826302125Shselasky
827302125Shselasky	if (transfer == NULL)
828302125Shselasky		return (0);
829302125Shselasky
830302125Shselasky	sxfer = (struct libusb_super_transfer *)(
831302125Shselasky	    ((uint8_t *)transfer) - sizeof(*sxfer));
832302125Shselasky
833302125Shselasky	/* get stream ID */
834302125Shselasky	return (sxfer->stream_id);
835302125Shselasky}
836