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