libusb10_io.c revision 195957
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10_io.c 195957 2009-07-30 00:11:41Z alfred $ */
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
27194676Sthompsa#include <stdlib.h>
28194676Sthompsa#include <unistd.h>
29194676Sthompsa#include <stdio.h>
30194676Sthompsa#include <poll.h>
31194676Sthompsa#include <pthread.h>
32194676Sthompsa#include <time.h>
33194676Sthompsa#include <errno.h>
34195957Salfred#include <sys/queue.h>
35194676Sthompsa
36194676Sthompsa#include "libusb20.h"
37194676Sthompsa#include "libusb20_desc.h"
38194676Sthompsa#include "libusb20_int.h"
39194676Sthompsa#include "libusb.h"
40194676Sthompsa#include "libusb10.h"
41194676Sthompsa
42195957SalfredUNEXPORTED void
43195957Salfredlibusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd,
44195957Salfred    struct libusb20_device *pdev, int fd, short events)
45195560Sthompsa{
46195560Sthompsa	if (ctx == NULL)
47195957Salfred		return;			/* invalid */
48195560Sthompsa
49195957Salfred	if (pollfd->entry.tqe_prev != NULL)
50195957Salfred		return;			/* already queued */
51195957Salfred
52195957Salfred	if (fd < 0)
53195957Salfred		return;			/* invalid */
54195957Salfred
55195957Salfred	pollfd->pdev = pdev;
56195560Sthompsa	pollfd->pollfd.fd = fd;
57195560Sthompsa	pollfd->pollfd.events = events;
58195560Sthompsa
59195957Salfred	CTX_LOCK(ctx);
60195957Salfred	TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry);
61195957Salfred	CTX_UNLOCK(ctx);
62195560Sthompsa
63195560Sthompsa	if (ctx->fd_added_cb)
64195560Sthompsa		ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
65195560Sthompsa}
66195560Sthompsa
67195560SthompsaUNEXPORTED void
68195957Salfredlibusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd)
69195560Sthompsa{
70195957Salfred	if (ctx == NULL)
71195957Salfred		return;			/* invalid */
72195560Sthompsa
73195957Salfred	if (pollfd->entry.tqe_prev == NULL)
74195957Salfred		return;			/* already dequeued */
75195560Sthompsa
76195957Salfred	CTX_LOCK(ctx);
77195957Salfred	TAILQ_REMOVE(&ctx->pollfds, pollfd, entry);
78195957Salfred	pollfd->entry.tqe_prev = NULL;
79195957Salfred	CTX_UNLOCK(ctx);
80195560Sthompsa
81195560Sthompsa	if (ctx->fd_removed_cb)
82195957Salfred		ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data);
83195560Sthompsa}
84195560Sthompsa
85195957Salfred/* This function must be called locked */
86195560Sthompsa
87195957Salfredstatic int
88195957Salfredlibusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
89195560Sthompsa{
90195957Salfred	struct libusb_device *dev;
91195957Salfred	struct libusb20_device **ppdev;
92195957Salfred	struct libusb_super_pollfd *pfd;
93195957Salfred	struct pollfd *fds;
94195957Salfred	struct libusb_super_transfer *sxfer;
95194676Sthompsa	struct libusb_transfer *uxfer;
96194676Sthompsa	nfds_t nfds;
97194676Sthompsa	int timeout;
98194676Sthompsa	int i;
99195957Salfred	int err;
100194676Sthompsa
101195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
102195957Salfred
103194676Sthompsa	nfds = 0;
104195957Salfred	i = 0;
105195957Salfred	TAILQ_FOREACH(pfd, &ctx->pollfds, entry)
106195957Salfred	    nfds++;
107194676Sthompsa
108195560Sthompsa	fds = alloca(sizeof(*fds) * nfds);
109194676Sthompsa	if (fds == NULL)
110194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
111194676Sthompsa
112195957Salfred	ppdev = alloca(sizeof(*ppdev) * nfds);
113195957Salfred	if (ppdev == NULL)
114195957Salfred		return (LIBUSB_ERROR_NO_MEM);
115195957Salfred
116195957Salfred	TAILQ_FOREACH(pfd, &ctx->pollfds, entry) {
117195957Salfred		fds[i].fd = pfd->pollfd.fd;
118195957Salfred		fds[i].events = pfd->pollfd.events;
119195957Salfred		fds[i].revents = 0;
120195957Salfred		ppdev[i] = pfd->pdev;
121195957Salfred		if (pfd->pdev != NULL)
122195957Salfred			libusb_get_device(pfd->pdev)->refcnt++;
123194676Sthompsa		i++;
124194676Sthompsa	}
125194676Sthompsa
126195957Salfred	if (tv == NULL)
127195957Salfred		timeout = -1;
128195957Salfred	else
129195957Salfred		timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
130194676Sthompsa
131195957Salfred	CTX_UNLOCK(ctx);
132195957Salfred	err = poll(fds, nfds, timeout);
133195957Salfred	CTX_LOCK(ctx);
134194676Sthompsa
135195957Salfred	if ((err == -1) && (errno == EINTR))
136195957Salfred		err = LIBUSB_ERROR_INTERRUPTED;
137195957Salfred	else if (err < 0)
138195957Salfred		err = LIBUSB_ERROR_IO;
139194676Sthompsa
140195957Salfred	if (err < 1) {
141195957Salfred		for (i = 0; i != nfds; i++) {
142195957Salfred			if (ppdev[i] != NULL) {
143195957Salfred				CTX_UNLOCK(ctx);
144195957Salfred				libusb_unref_device(libusb_get_device(ppdev[i]));
145195957Salfred				CTX_LOCK(ctx);
146195957Salfred			}
147194676Sthompsa		}
148195957Salfred		goto do_done;
149194676Sthompsa	}
150195957Salfred	for (i = 0; i != nfds; i++) {
151195957Salfred		if (fds[i].revents == 0)
152195957Salfred			continue;
153195957Salfred		if (ppdev[i] != NULL) {
154195957Salfred			dev = libusb_get_device(ppdev[i]);
155194676Sthompsa
156195957Salfred			err = libusb20_dev_process(ppdev[i]);
157195957Salfred			if (err) {
158195957Salfred				/* cancel all transfers - device is gone */
159195957Salfred				libusb10_cancel_all_transfer(dev);
160195957Salfred				/*
161195957Salfred				 * make sure we don't go into an infinite
162195957Salfred				 * loop
163195957Salfred				 */
164195957Salfred				libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
165195957Salfred			}
166195957Salfred			CTX_UNLOCK(ctx);
167195957Salfred			libusb_unref_device(dev);
168195957Salfred			CTX_LOCK(ctx);
169194676Sthompsa
170195957Salfred		} else {
171195957Salfred			uint8_t dummy;
172194676Sthompsa
173195957Salfred			while (1) {
174195957Salfred				if (read(fds[i].fd, &dummy, 1) != 1)
175195957Salfred					break;
176195957Salfred			}
177194676Sthompsa		}
178195957Salfred	}
179194676Sthompsa
180195957Salfred	err = 0;
181194676Sthompsa
182195957Salfreddo_done:
183194676Sthompsa
184195957Salfred	/* Do all done callbacks */
185194676Sthompsa
186195957Salfred	while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
187195957Salfred		TAILQ_REMOVE(&ctx->tr_done, sxfer, entry);
188195957Salfred		sxfer->entry.tqe_prev = NULL;
189194676Sthompsa
190195957Salfred		ctx->tr_done_ref++;
191195957Salfred
192195957Salfred		CTX_UNLOCK(ctx);
193195957Salfred
194195957Salfred		uxfer = (struct libusb_transfer *)(
195195957Salfred		    ((uint8_t *)sxfer) + sizeof(*sxfer));
196195957Salfred
197195957Salfred		if (uxfer->callback != NULL)
198195957Salfred			(uxfer->callback) (uxfer);
199195957Salfred
200195957Salfred		if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
201195957Salfred			free(uxfer->buffer);
202195957Salfred
203195957Salfred		if (uxfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER)
204195957Salfred			libusb_free_transfer(uxfer);
205195957Salfred
206195957Salfred		CTX_LOCK(ctx);
207195957Salfred
208195957Salfred		ctx->tr_done_ref--;
209195957Salfred		ctx->tr_done_gen++;
210194676Sthompsa	}
211194676Sthompsa
212195957Salfred	/* Wakeup other waiters */
213195957Salfred	pthread_cond_broadcast(&ctx->ctx_cond);
214194676Sthompsa
215195957Salfred	return (err);
216194676Sthompsa}
217194676Sthompsa
218194676Sthompsa/* Polling and timing */
219194676Sthompsa
220194676Sthompsaint
221195957Salfredlibusb_try_lock_events(libusb_context *ctx)
222194676Sthompsa{
223195957Salfred	int err;
224194676Sthompsa
225195957Salfred	ctx = GET_CONTEXT(ctx);
226195957Salfred	if (ctx == NULL)
227194676Sthompsa		return (1);
228194676Sthompsa
229195957Salfred	err = CTX_TRYLOCK(ctx);
230195957Salfred	if (err)
231194676Sthompsa		return (1);
232194676Sthompsa
233195957Salfred	err = (ctx->ctx_handler != NO_THREAD);
234195957Salfred	if (err)
235195957Salfred		CTX_UNLOCK(ctx);
236195957Salfred	else
237195957Salfred		ctx->ctx_handler = pthread_self();
238195957Salfred
239195957Salfred	return (err);
240194676Sthompsa}
241194676Sthompsa
242194676Sthompsavoid
243195957Salfredlibusb_lock_events(libusb_context *ctx)
244194676Sthompsa{
245195957Salfred	ctx = GET_CONTEXT(ctx);
246195957Salfred	CTX_LOCK(ctx);
247195957Salfred	if (ctx->ctx_handler == NO_THREAD)
248195957Salfred		ctx->ctx_handler = pthread_self();
249194676Sthompsa}
250194676Sthompsa
251194676Sthompsavoid
252195957Salfredlibusb_unlock_events(libusb_context *ctx)
253194676Sthompsa{
254195957Salfred	ctx = GET_CONTEXT(ctx);
255195957Salfred	if (ctx->ctx_handler == pthread_self()) {
256195957Salfred		ctx->ctx_handler = NO_THREAD;
257195957Salfred		pthread_cond_broadcast(&ctx->ctx_cond);
258195957Salfred	}
259195957Salfred	CTX_UNLOCK(ctx);
260194676Sthompsa}
261194676Sthompsa
262194676Sthompsaint
263195957Salfredlibusb_event_handling_ok(libusb_context *ctx)
264194676Sthompsa{
265195957Salfred	ctx = GET_CONTEXT(ctx);
266195957Salfred	return (ctx->ctx_handler == pthread_self());
267194676Sthompsa}
268194676Sthompsa
269194676Sthompsaint
270195957Salfredlibusb_event_handler_active(libusb_context *ctx)
271194676Sthompsa{
272195957Salfred	ctx = GET_CONTEXT(ctx);
273195957Salfred	return (ctx->ctx_handler != NO_THREAD);
274194676Sthompsa}
275194676Sthompsa
276194676Sthompsavoid
277195957Salfredlibusb_lock_event_waiters(libusb_context *ctx)
278194676Sthompsa{
279195957Salfred	ctx = GET_CONTEXT(ctx);
280195957Salfred	CTX_LOCK(ctx);
281194676Sthompsa}
282194676Sthompsa
283194676Sthompsavoid
284195957Salfredlibusb_unlock_event_waiters(libusb_context *ctx)
285194676Sthompsa{
286195957Salfred	ctx = GET_CONTEXT(ctx);
287195957Salfred	CTX_UNLOCK(ctx);
288194676Sthompsa}
289194676Sthompsa
290194676Sthompsaint
291195957Salfredlibusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
292194676Sthompsa{
293194676Sthompsa	struct timespec ts;
294195957Salfred	int err;
295194676Sthompsa
296195957Salfred	ctx = GET_CONTEXT(ctx);
297195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
298194676Sthompsa
299194676Sthompsa	if (tv == NULL) {
300195957Salfred		pthread_cond_wait(&ctx->ctx_cond,
301195957Salfred		    &ctx->ctx_lock);
302194676Sthompsa		return (0);
303194676Sthompsa	}
304195957Salfred	err = clock_gettime(CLOCK_REALTIME, &ts);
305195957Salfred	if (err < 0)
306194676Sthompsa		return (LIBUSB_ERROR_OTHER);
307194676Sthompsa
308194676Sthompsa	ts.tv_sec = tv->tv_sec;
309194676Sthompsa	ts.tv_nsec = tv->tv_usec * 1000;
310195957Salfred	if (ts.tv_nsec >= 1000000000) {
311194676Sthompsa		ts.tv_nsec -= 1000000000;
312194676Sthompsa		ts.tv_sec++;
313194676Sthompsa	}
314195957Salfred	err = pthread_cond_timedwait(&ctx->ctx_cond,
315195957Salfred	    &ctx->ctx_lock, &ts);
316194676Sthompsa
317195957Salfred	if (err == ETIMEDOUT)
318194676Sthompsa		return (1);
319194676Sthompsa
320194676Sthompsa	return (0);
321194676Sthompsa}
322194676Sthompsa
323194676Sthompsaint
324195957Salfredlibusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
325194676Sthompsa{
326195957Salfred	int err;
327195957Salfred
328195957Salfred	ctx = GET_CONTEXT(ctx);
329195957Salfred
330195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout enter");
331194676Sthompsa
332195957Salfred	libusb_lock_events(ctx);
333194676Sthompsa
334195957Salfred	err = libusb_handle_events_locked(ctx, tv);
335194676Sthompsa
336195957Salfred	libusb_unlock_events(ctx);
337194676Sthompsa
338195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout leave");
339195957Salfred
340195957Salfred	return (err);
341194676Sthompsa}
342194676Sthompsa
343194676Sthompsaint
344195957Salfredlibusb_handle_events(libusb_context *ctx)
345194676Sthompsa{
346195957Salfred	return (libusb_handle_events_timeout(ctx, NULL));
347194676Sthompsa}
348194676Sthompsa
349194676Sthompsaint
350195957Salfredlibusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
351194676Sthompsa{
352195957Salfred	int err;
353194676Sthompsa
354195957Salfred	ctx = GET_CONTEXT(ctx);
355194676Sthompsa
356195957Salfred	if (libusb_event_handling_ok(ctx)) {
357195957Salfred		err = libusb10_handle_events_sub(ctx, tv);
358195957Salfred	} else {
359195957Salfred		libusb_wait_for_event(ctx, tv);
360195957Salfred		err = 0;
361194676Sthompsa	}
362195957Salfred	return (err);
363194676Sthompsa}
364194676Sthompsa
365194676Sthompsaint
366195957Salfredlibusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
367194676Sthompsa{
368195957Salfred	/* all timeouts are currently being done by the kernel */
369195957Salfred	timerclear(tv);
370195957Salfred	return (0);
371194676Sthompsa}
372194676Sthompsa
373194676Sthompsavoid
374195957Salfredlibusb_set_pollfd_notifiers(libusb_context *ctx,
375194676Sthompsa    libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
376194676Sthompsa    void *user_data)
377194676Sthompsa{
378195957Salfred	ctx = GET_CONTEXT(ctx);
379194676Sthompsa
380194676Sthompsa	ctx->fd_added_cb = added_cb;
381194676Sthompsa	ctx->fd_removed_cb = removed_cb;
382194676Sthompsa	ctx->fd_cb_user_data = user_data;
383194676Sthompsa}
384194676Sthompsa
385194676Sthompsastruct libusb_pollfd **
386195957Salfredlibusb_get_pollfds(libusb_context *ctx)
387194676Sthompsa{
388195957Salfred	struct libusb_super_pollfd *pollfd;
389194676Sthompsa	libusb_pollfd **ret;
390194676Sthompsa	int i;
391194676Sthompsa
392195957Salfred	ctx = GET_CONTEXT(ctx);
393194676Sthompsa
394195957Salfred	CTX_LOCK(ctx);
395195957Salfred
396194676Sthompsa	i = 0;
397195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
398195957Salfred	    i++;
399194676Sthompsa
400195957Salfred	ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
401195957Salfred	if (ret == NULL)
402195957Salfred		goto done;
403194676Sthompsa
404194676Sthompsa	i = 0;
405195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
406195957Salfred	    ret[i++] = &pollfd->pollfd;
407194676Sthompsa	ret[i] = NULL;
408194676Sthompsa
409195957Salfreddone:
410195957Salfred	CTX_UNLOCK(ctx);
411194676Sthompsa	return (ret);
412194676Sthompsa}
413194676Sthompsa
414194676Sthompsa
415194676Sthompsa/* Synchronous device I/O */
416194676Sthompsa
417194676Sthompsaint
418195957Salfredlibusb_control_transfer(libusb_device_handle *devh,
419194676Sthompsa    uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
420195957Salfred    uint8_t *data, uint16_t wLength, unsigned int timeout)
421194676Sthompsa{
422195957Salfred	struct LIBUSB20_CONTROL_SETUP_DECODED req;
423195957Salfred	int err;
424195957Salfred	uint16_t actlen;
425194676Sthompsa
426195957Salfred	if (devh == NULL)
427195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
428194676Sthompsa
429195957Salfred	if ((wLength != 0) && (data == NULL))
430195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
431194676Sthompsa
432195957Salfred	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
433194676Sthompsa
434195957Salfred	req.bmRequestType = bmRequestType;
435195957Salfred	req.bRequest = bRequest;
436195957Salfred	req.wValue = wValue;
437195957Salfred	req.wIndex = wIndex;
438195957Salfred	req.wLength = wLength;
439194676Sthompsa
440195957Salfred	err = libusb20_dev_request_sync(devh, &req, data,
441195957Salfred	    &actlen, timeout, 0);
442194676Sthompsa
443195957Salfred	if (err == LIBUSB20_ERROR_PIPE)
444195957Salfred		return (LIBUSB_ERROR_PIPE);
445195957Salfred	else if (err == LIBUSB20_ERROR_TIMEOUT)
446195957Salfred		return (LIBUSB_ERROR_TIMEOUT);
447195957Salfred	else if (err)
448195957Salfred		return (LIBUSB_ERROR_NO_DEVICE);
449194676Sthompsa
450195957Salfred	return (actlen);
451195957Salfred}
452194676Sthompsa
453195957Salfredstatic void
454195957Salfredlibusb10_do_transfer_cb(struct libusb_transfer *transfer)
455195957Salfred{
456195957Salfred	libusb_context *ctx;
457195957Salfred	int *pdone;
458194676Sthompsa
459195957Salfred	ctx = GET_CONTEXT(NULL);
460194676Sthompsa
461195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
462194676Sthompsa
463195957Salfred	pdone = transfer->user_data;
464195957Salfred	*pdone = 1;
465194676Sthompsa}
466194676Sthompsa
467195957Salfred/*
468195957Salfred * TODO: Replace the following function. Allocating and freeing on a
469195957Salfred * per-transfer basis is slow.  --HPS
470195957Salfred */
471194676Sthompsastatic int
472195957Salfredlibusb10_do_transfer(libusb_device_handle *devh,
473195957Salfred    uint8_t endpoint, uint8_t *data, int length,
474194676Sthompsa    int *transferred, unsigned int timeout, int type)
475194676Sthompsa{
476195957Salfred	libusb_context *ctx;
477194676Sthompsa	struct libusb_transfer *xfer;
478195957Salfred	volatile int complet;
479194676Sthompsa	int ret;
480194676Sthompsa
481195957Salfred	if (devh == NULL)
482195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
483194676Sthompsa
484195957Salfred	if ((length != 0) && (data == NULL))
485195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
486195957Salfred
487194676Sthompsa	xfer = libusb_alloc_transfer(0);
488194676Sthompsa	if (xfer == NULL)
489194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
490194676Sthompsa
491195957Salfred	ctx = libusb_get_device(devh)->ctx;
492194676Sthompsa
493194676Sthompsa	xfer->dev_handle = devh;
494194676Sthompsa	xfer->endpoint = endpoint;
495194676Sthompsa	xfer->type = type;
496194676Sthompsa	xfer->timeout = timeout;
497194676Sthompsa	xfer->buffer = data;
498194676Sthompsa	xfer->length = length;
499195957Salfred	xfer->user_data = (void *)&complet;
500195957Salfred	xfer->callback = libusb10_do_transfer_cb;
501194676Sthompsa	complet = 0;
502194676Sthompsa
503194676Sthompsa	if ((ret = libusb_submit_transfer(xfer)) < 0) {
504194676Sthompsa		libusb_free_transfer(xfer);
505194676Sthompsa		return (ret);
506194676Sthompsa	}
507194676Sthompsa	while (complet == 0) {
508194676Sthompsa		if ((ret = libusb_handle_events(ctx)) < 0) {
509194676Sthompsa			libusb_cancel_transfer(xfer);
510195957Salfred			usleep(1000);	/* nice it */
511194676Sthompsa		}
512194676Sthompsa	}
513194676Sthompsa
514194676Sthompsa	*transferred = xfer->actual_length;
515195957Salfred
516194676Sthompsa	switch (xfer->status) {
517194676Sthompsa	case LIBUSB_TRANSFER_COMPLETED:
518195957Salfred		ret = 0;
519194676Sthompsa		break;
520194676Sthompsa	case LIBUSB_TRANSFER_TIMED_OUT:
521195957Salfred		ret = LIBUSB_ERROR_TIMEOUT;
522195957Salfred		break;
523194676Sthompsa	case LIBUSB_TRANSFER_OVERFLOW:
524195957Salfred		ret = LIBUSB_ERROR_OVERFLOW;
525195957Salfred		break;
526194676Sthompsa	case LIBUSB_TRANSFER_STALL:
527195957Salfred		ret = LIBUSB_ERROR_PIPE;
528195957Salfred		break;
529194676Sthompsa	case LIBUSB_TRANSFER_NO_DEVICE:
530195957Salfred		ret = LIBUSB_ERROR_NO_DEVICE;
531194676Sthompsa		break;
532194676Sthompsa	default:
533194676Sthompsa		ret = LIBUSB_ERROR_OTHER;
534195957Salfred		break;
535194676Sthompsa	}
536194676Sthompsa
537194676Sthompsa	libusb_free_transfer(xfer);
538194676Sthompsa	return (ret);
539194676Sthompsa}
540194676Sthompsa
541194676Sthompsaint
542195957Salfredlibusb_bulk_transfer(libusb_device_handle *devh,
543195957Salfred    uint8_t endpoint, uint8_t *data, int length,
544194676Sthompsa    int *transferred, unsigned int timeout)
545194676Sthompsa{
546194676Sthompsa	libusb_context *ctx;
547194676Sthompsa	int ret;
548195957Salfred
549195957Salfred	ctx = GET_CONTEXT(NULL);
550195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
551194676Sthompsa
552195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
553194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
554194676Sthompsa
555195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
556194676Sthompsa	return (ret);
557194676Sthompsa}
558194676Sthompsa
559194676Sthompsaint
560195957Salfredlibusb_interrupt_transfer(libusb_device_handle *devh,
561195957Salfred    uint8_t endpoint, uint8_t *data, int length,
562194676Sthompsa    int *transferred, unsigned int timeout)
563194676Sthompsa{
564194676Sthompsa	libusb_context *ctx;
565194676Sthompsa	int ret;
566194676Sthompsa
567195957Salfred	ctx = GET_CONTEXT(NULL);
568195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
569194676Sthompsa
570195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
571194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
572194676Sthompsa
573195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
574194676Sthompsa	return (ret);
575194676Sthompsa}
576