libusb10_io.c revision 203815
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10_io.c 203815 2010-02-13 09:45:50Z wkoszek $ */
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
27203815Swkoszek#include <sys/queue.h>
28203815Swkoszek
29203815Swkoszek#include <errno.h>
30194676Sthompsa#include <poll.h>
31194676Sthompsa#include <pthread.h>
32203815Swkoszek#include <stdio.h>
33203815Swkoszek#include <stdlib.h>
34194676Sthompsa#include <time.h>
35203815Swkoszek#include <unistd.h>
36194676Sthompsa
37194676Sthompsa#include "libusb20.h"
38194676Sthompsa#include "libusb20_desc.h"
39194676Sthompsa#include "libusb20_int.h"
40194676Sthompsa#include "libusb.h"
41194676Sthompsa#include "libusb10.h"
42194676Sthompsa
43195957SalfredUNEXPORTED void
44195957Salfredlibusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd,
45195957Salfred    struct libusb20_device *pdev, int fd, short events)
46195560Sthompsa{
47195560Sthompsa	if (ctx == NULL)
48195957Salfred		return;			/* invalid */
49195560Sthompsa
50195957Salfred	if (pollfd->entry.tqe_prev != NULL)
51195957Salfred		return;			/* already queued */
52195957Salfred
53195957Salfred	if (fd < 0)
54195957Salfred		return;			/* invalid */
55195957Salfred
56195957Salfred	pollfd->pdev = pdev;
57195560Sthompsa	pollfd->pollfd.fd = fd;
58195560Sthompsa	pollfd->pollfd.events = events;
59195560Sthompsa
60195957Salfred	CTX_LOCK(ctx);
61195957Salfred	TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry);
62195957Salfred	CTX_UNLOCK(ctx);
63195560Sthompsa
64195560Sthompsa	if (ctx->fd_added_cb)
65195560Sthompsa		ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
66195560Sthompsa}
67195560Sthompsa
68195560SthompsaUNEXPORTED void
69195957Salfredlibusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd)
70195560Sthompsa{
71195957Salfred	if (ctx == NULL)
72195957Salfred		return;			/* invalid */
73195560Sthompsa
74195957Salfred	if (pollfd->entry.tqe_prev == NULL)
75195957Salfred		return;			/* already dequeued */
76195560Sthompsa
77195957Salfred	CTX_LOCK(ctx);
78195957Salfred	TAILQ_REMOVE(&ctx->pollfds, pollfd, entry);
79195957Salfred	pollfd->entry.tqe_prev = NULL;
80195957Salfred	CTX_UNLOCK(ctx);
81195560Sthompsa
82195560Sthompsa	if (ctx->fd_removed_cb)
83195957Salfred		ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data);
84195560Sthompsa}
85195560Sthompsa
86195957Salfred/* This function must be called locked */
87195560Sthompsa
88195957Salfredstatic int
89195957Salfredlibusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
90195560Sthompsa{
91195957Salfred	struct libusb_device *dev;
92195957Salfred	struct libusb20_device **ppdev;
93195957Salfred	struct libusb_super_pollfd *pfd;
94195957Salfred	struct pollfd *fds;
95195957Salfred	struct libusb_super_transfer *sxfer;
96194676Sthompsa	struct libusb_transfer *uxfer;
97194676Sthompsa	nfds_t nfds;
98194676Sthompsa	int timeout;
99194676Sthompsa	int i;
100195957Salfred	int err;
101194676Sthompsa
102195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
103195957Salfred
104194676Sthompsa	nfds = 0;
105195957Salfred	i = 0;
106195957Salfred	TAILQ_FOREACH(pfd, &ctx->pollfds, entry)
107195957Salfred	    nfds++;
108194676Sthompsa
109195560Sthompsa	fds = alloca(sizeof(*fds) * nfds);
110194676Sthompsa	if (fds == NULL)
111194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
112194676Sthompsa
113195957Salfred	ppdev = alloca(sizeof(*ppdev) * nfds);
114195957Salfred	if (ppdev == NULL)
115195957Salfred		return (LIBUSB_ERROR_NO_MEM);
116195957Salfred
117195957Salfred	TAILQ_FOREACH(pfd, &ctx->pollfds, entry) {
118195957Salfred		fds[i].fd = pfd->pollfd.fd;
119195957Salfred		fds[i].events = pfd->pollfd.events;
120195957Salfred		fds[i].revents = 0;
121195957Salfred		ppdev[i] = pfd->pdev;
122195957Salfred		if (pfd->pdev != NULL)
123195957Salfred			libusb_get_device(pfd->pdev)->refcnt++;
124194676Sthompsa		i++;
125194676Sthompsa	}
126194676Sthompsa
127195957Salfred	if (tv == NULL)
128195957Salfred		timeout = -1;
129195957Salfred	else
130195957Salfred		timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
131194676Sthompsa
132195957Salfred	CTX_UNLOCK(ctx);
133195957Salfred	err = poll(fds, nfds, timeout);
134195957Salfred	CTX_LOCK(ctx);
135194676Sthompsa
136195957Salfred	if ((err == -1) && (errno == EINTR))
137195957Salfred		err = LIBUSB_ERROR_INTERRUPTED;
138195957Salfred	else if (err < 0)
139195957Salfred		err = LIBUSB_ERROR_IO;
140194676Sthompsa
141195957Salfred	if (err < 1) {
142195957Salfred		for (i = 0; i != nfds; i++) {
143195957Salfred			if (ppdev[i] != NULL) {
144195957Salfred				CTX_UNLOCK(ctx);
145195957Salfred				libusb_unref_device(libusb_get_device(ppdev[i]));
146195957Salfred				CTX_LOCK(ctx);
147195957Salfred			}
148194676Sthompsa		}
149195957Salfred		goto do_done;
150194676Sthompsa	}
151195957Salfred	for (i = 0; i != nfds; i++) {
152195957Salfred		if (ppdev[i] != NULL) {
153195957Salfred			dev = libusb_get_device(ppdev[i]);
154194676Sthompsa
155199055Sthompsa			if (fds[i].revents == 0)
156199055Sthompsa				err = 0;	/* nothing to do */
157199055Sthompsa			else
158199055Sthompsa				err = libusb20_dev_process(ppdev[i]);
159199055Sthompsa
160195957Salfred			if (err) {
161195957Salfred				/* cancel all transfers - device is gone */
162195957Salfred				libusb10_cancel_all_transfer(dev);
163199055Sthompsa
164199055Sthompsa				/* remove USB device from polling loop */
165195957Salfred				libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
166195957Salfred			}
167195957Salfred			CTX_UNLOCK(ctx);
168195957Salfred			libusb_unref_device(dev);
169195957Salfred			CTX_LOCK(ctx);
170194676Sthompsa
171195957Salfred		} else {
172195957Salfred			uint8_t dummy;
173194676Sthompsa
174195957Salfred			while (1) {
175195957Salfred				if (read(fds[i].fd, &dummy, 1) != 1)
176195957Salfred					break;
177195957Salfred			}
178194676Sthompsa		}
179195957Salfred	}
180194676Sthompsa
181195957Salfred	err = 0;
182194676Sthompsa
183195957Salfreddo_done:
184194676Sthompsa
185195957Salfred	/* Do all done callbacks */
186194676Sthompsa
187195957Salfred	while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
188195957Salfred		TAILQ_REMOVE(&ctx->tr_done, sxfer, entry);
189195957Salfred		sxfer->entry.tqe_prev = NULL;
190194676Sthompsa
191195957Salfred		ctx->tr_done_ref++;
192195957Salfred
193195957Salfred		CTX_UNLOCK(ctx);
194195957Salfred
195195957Salfred		uxfer = (struct libusb_transfer *)(
196195957Salfred		    ((uint8_t *)sxfer) + sizeof(*sxfer));
197195957Salfred
198195957Salfred		if (uxfer->callback != NULL)
199195957Salfred			(uxfer->callback) (uxfer);
200195957Salfred
201195957Salfred		if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
202195957Salfred			free(uxfer->buffer);
203195957Salfred
204195957Salfred		if (uxfer->flags & LIBUSB_TRANSFER_FREE_TRANSFER)
205195957Salfred			libusb_free_transfer(uxfer);
206195957Salfred
207195957Salfred		CTX_LOCK(ctx);
208195957Salfred
209195957Salfred		ctx->tr_done_ref--;
210195957Salfred		ctx->tr_done_gen++;
211194676Sthompsa	}
212194676Sthompsa
213195957Salfred	/* Wakeup other waiters */
214195957Salfred	pthread_cond_broadcast(&ctx->ctx_cond);
215194676Sthompsa
216195957Salfred	return (err);
217194676Sthompsa}
218194676Sthompsa
219194676Sthompsa/* Polling and timing */
220194676Sthompsa
221194676Sthompsaint
222195957Salfredlibusb_try_lock_events(libusb_context *ctx)
223194676Sthompsa{
224195957Salfred	int err;
225194676Sthompsa
226195957Salfred	ctx = GET_CONTEXT(ctx);
227195957Salfred	if (ctx == NULL)
228194676Sthompsa		return (1);
229194676Sthompsa
230195957Salfred	err = CTX_TRYLOCK(ctx);
231195957Salfred	if (err)
232194676Sthompsa		return (1);
233194676Sthompsa
234195957Salfred	err = (ctx->ctx_handler != NO_THREAD);
235195957Salfred	if (err)
236195957Salfred		CTX_UNLOCK(ctx);
237195957Salfred	else
238195957Salfred		ctx->ctx_handler = pthread_self();
239195957Salfred
240195957Salfred	return (err);
241194676Sthompsa}
242194676Sthompsa
243194676Sthompsavoid
244195957Salfredlibusb_lock_events(libusb_context *ctx)
245194676Sthompsa{
246195957Salfred	ctx = GET_CONTEXT(ctx);
247195957Salfred	CTX_LOCK(ctx);
248195957Salfred	if (ctx->ctx_handler == NO_THREAD)
249195957Salfred		ctx->ctx_handler = pthread_self();
250194676Sthompsa}
251194676Sthompsa
252194676Sthompsavoid
253195957Salfredlibusb_unlock_events(libusb_context *ctx)
254194676Sthompsa{
255195957Salfred	ctx = GET_CONTEXT(ctx);
256195957Salfred	if (ctx->ctx_handler == pthread_self()) {
257195957Salfred		ctx->ctx_handler = NO_THREAD;
258195957Salfred		pthread_cond_broadcast(&ctx->ctx_cond);
259195957Salfred	}
260195957Salfred	CTX_UNLOCK(ctx);
261194676Sthompsa}
262194676Sthompsa
263194676Sthompsaint
264195957Salfredlibusb_event_handling_ok(libusb_context *ctx)
265194676Sthompsa{
266195957Salfred	ctx = GET_CONTEXT(ctx);
267195957Salfred	return (ctx->ctx_handler == pthread_self());
268194676Sthompsa}
269194676Sthompsa
270194676Sthompsaint
271195957Salfredlibusb_event_handler_active(libusb_context *ctx)
272194676Sthompsa{
273195957Salfred	ctx = GET_CONTEXT(ctx);
274195957Salfred	return (ctx->ctx_handler != NO_THREAD);
275194676Sthompsa}
276194676Sthompsa
277194676Sthompsavoid
278195957Salfredlibusb_lock_event_waiters(libusb_context *ctx)
279194676Sthompsa{
280195957Salfred	ctx = GET_CONTEXT(ctx);
281195957Salfred	CTX_LOCK(ctx);
282194676Sthompsa}
283194676Sthompsa
284194676Sthompsavoid
285195957Salfredlibusb_unlock_event_waiters(libusb_context *ctx)
286194676Sthompsa{
287195957Salfred	ctx = GET_CONTEXT(ctx);
288195957Salfred	CTX_UNLOCK(ctx);
289194676Sthompsa}
290194676Sthompsa
291194676Sthompsaint
292195957Salfredlibusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
293194676Sthompsa{
294194676Sthompsa	struct timespec ts;
295195957Salfred	int err;
296194676Sthompsa
297195957Salfred	ctx = GET_CONTEXT(ctx);
298195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
299194676Sthompsa
300194676Sthompsa	if (tv == NULL) {
301195957Salfred		pthread_cond_wait(&ctx->ctx_cond,
302195957Salfred		    &ctx->ctx_lock);
303194676Sthompsa		return (0);
304194676Sthompsa	}
305195957Salfred	err = clock_gettime(CLOCK_REALTIME, &ts);
306195957Salfred	if (err < 0)
307194676Sthompsa		return (LIBUSB_ERROR_OTHER);
308194676Sthompsa
309194676Sthompsa	ts.tv_sec = tv->tv_sec;
310194676Sthompsa	ts.tv_nsec = tv->tv_usec * 1000;
311195957Salfred	if (ts.tv_nsec >= 1000000000) {
312194676Sthompsa		ts.tv_nsec -= 1000000000;
313194676Sthompsa		ts.tv_sec++;
314194676Sthompsa	}
315195957Salfred	err = pthread_cond_timedwait(&ctx->ctx_cond,
316195957Salfred	    &ctx->ctx_lock, &ts);
317194676Sthompsa
318195957Salfred	if (err == ETIMEDOUT)
319194676Sthompsa		return (1);
320194676Sthompsa
321194676Sthompsa	return (0);
322194676Sthompsa}
323194676Sthompsa
324194676Sthompsaint
325195957Salfredlibusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
326194676Sthompsa{
327195957Salfred	int err;
328195957Salfred
329195957Salfred	ctx = GET_CONTEXT(ctx);
330195957Salfred
331195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout enter");
332194676Sthompsa
333195957Salfred	libusb_lock_events(ctx);
334194676Sthompsa
335195957Salfred	err = libusb_handle_events_locked(ctx, tv);
336194676Sthompsa
337195957Salfred	libusb_unlock_events(ctx);
338194676Sthompsa
339195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout leave");
340195957Salfred
341195957Salfred	return (err);
342194676Sthompsa}
343194676Sthompsa
344194676Sthompsaint
345195957Salfredlibusb_handle_events(libusb_context *ctx)
346194676Sthompsa{
347195957Salfred	return (libusb_handle_events_timeout(ctx, NULL));
348194676Sthompsa}
349194676Sthompsa
350194676Sthompsaint
351195957Salfredlibusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
352194676Sthompsa{
353195957Salfred	int err;
354194676Sthompsa
355195957Salfred	ctx = GET_CONTEXT(ctx);
356194676Sthompsa
357195957Salfred	if (libusb_event_handling_ok(ctx)) {
358195957Salfred		err = libusb10_handle_events_sub(ctx, tv);
359195957Salfred	} else {
360195957Salfred		libusb_wait_for_event(ctx, tv);
361195957Salfred		err = 0;
362194676Sthompsa	}
363195957Salfred	return (err);
364194676Sthompsa}
365194676Sthompsa
366194676Sthompsaint
367195957Salfredlibusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
368194676Sthompsa{
369195957Salfred	/* all timeouts are currently being done by the kernel */
370195957Salfred	timerclear(tv);
371195957Salfred	return (0);
372194676Sthompsa}
373194676Sthompsa
374194676Sthompsavoid
375195957Salfredlibusb_set_pollfd_notifiers(libusb_context *ctx,
376194676Sthompsa    libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
377194676Sthompsa    void *user_data)
378194676Sthompsa{
379195957Salfred	ctx = GET_CONTEXT(ctx);
380194676Sthompsa
381194676Sthompsa	ctx->fd_added_cb = added_cb;
382194676Sthompsa	ctx->fd_removed_cb = removed_cb;
383194676Sthompsa	ctx->fd_cb_user_data = user_data;
384194676Sthompsa}
385194676Sthompsa
386194676Sthompsastruct libusb_pollfd **
387195957Salfredlibusb_get_pollfds(libusb_context *ctx)
388194676Sthompsa{
389195957Salfred	struct libusb_super_pollfd *pollfd;
390194676Sthompsa	libusb_pollfd **ret;
391194676Sthompsa	int i;
392194676Sthompsa
393195957Salfred	ctx = GET_CONTEXT(ctx);
394194676Sthompsa
395195957Salfred	CTX_LOCK(ctx);
396195957Salfred
397194676Sthompsa	i = 0;
398195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
399195957Salfred	    i++;
400194676Sthompsa
401195957Salfred	ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
402195957Salfred	if (ret == NULL)
403195957Salfred		goto done;
404194676Sthompsa
405194676Sthompsa	i = 0;
406195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
407195957Salfred	    ret[i++] = &pollfd->pollfd;
408194676Sthompsa	ret[i] = NULL;
409194676Sthompsa
410195957Salfreddone:
411195957Salfred	CTX_UNLOCK(ctx);
412194676Sthompsa	return (ret);
413194676Sthompsa}
414194676Sthompsa
415194676Sthompsa
416194676Sthompsa/* Synchronous device I/O */
417194676Sthompsa
418194676Sthompsaint
419195957Salfredlibusb_control_transfer(libusb_device_handle *devh,
420194676Sthompsa    uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
421195957Salfred    uint8_t *data, uint16_t wLength, unsigned int timeout)
422194676Sthompsa{
423195957Salfred	struct LIBUSB20_CONTROL_SETUP_DECODED req;
424195957Salfred	int err;
425195957Salfred	uint16_t actlen;
426194676Sthompsa
427195957Salfred	if (devh == NULL)
428195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
429194676Sthompsa
430195957Salfred	if ((wLength != 0) && (data == NULL))
431195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
432194676Sthompsa
433195957Salfred	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
434194676Sthompsa
435195957Salfred	req.bmRequestType = bmRequestType;
436195957Salfred	req.bRequest = bRequest;
437195957Salfred	req.wValue = wValue;
438195957Salfred	req.wIndex = wIndex;
439195957Salfred	req.wLength = wLength;
440194676Sthompsa
441195957Salfred	err = libusb20_dev_request_sync(devh, &req, data,
442195957Salfred	    &actlen, timeout, 0);
443194676Sthompsa
444195957Salfred	if (err == LIBUSB20_ERROR_PIPE)
445195957Salfred		return (LIBUSB_ERROR_PIPE);
446195957Salfred	else if (err == LIBUSB20_ERROR_TIMEOUT)
447195957Salfred		return (LIBUSB_ERROR_TIMEOUT);
448195957Salfred	else if (err)
449195957Salfred		return (LIBUSB_ERROR_NO_DEVICE);
450194676Sthompsa
451195957Salfred	return (actlen);
452195957Salfred}
453194676Sthompsa
454195957Salfredstatic void
455195957Salfredlibusb10_do_transfer_cb(struct libusb_transfer *transfer)
456195957Salfred{
457195957Salfred	libusb_context *ctx;
458195957Salfred	int *pdone;
459194676Sthompsa
460195957Salfred	ctx = GET_CONTEXT(NULL);
461194676Sthompsa
462195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
463194676Sthompsa
464195957Salfred	pdone = transfer->user_data;
465195957Salfred	*pdone = 1;
466194676Sthompsa}
467194676Sthompsa
468195957Salfred/*
469195957Salfred * TODO: Replace the following function. Allocating and freeing on a
470195957Salfred * per-transfer basis is slow.  --HPS
471195957Salfred */
472194676Sthompsastatic int
473195957Salfredlibusb10_do_transfer(libusb_device_handle *devh,
474195957Salfred    uint8_t endpoint, uint8_t *data, int length,
475194676Sthompsa    int *transferred, unsigned int timeout, int type)
476194676Sthompsa{
477195957Salfred	libusb_context *ctx;
478194676Sthompsa	struct libusb_transfer *xfer;
479195957Salfred	volatile int complet;
480194676Sthompsa	int ret;
481194676Sthompsa
482195957Salfred	if (devh == NULL)
483195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
484194676Sthompsa
485195957Salfred	if ((length != 0) && (data == NULL))
486195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
487195957Salfred
488194676Sthompsa	xfer = libusb_alloc_transfer(0);
489194676Sthompsa	if (xfer == NULL)
490194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
491194676Sthompsa
492195957Salfred	ctx = libusb_get_device(devh)->ctx;
493194676Sthompsa
494194676Sthompsa	xfer->dev_handle = devh;
495194676Sthompsa	xfer->endpoint = endpoint;
496194676Sthompsa	xfer->type = type;
497194676Sthompsa	xfer->timeout = timeout;
498194676Sthompsa	xfer->buffer = data;
499194676Sthompsa	xfer->length = length;
500195957Salfred	xfer->user_data = (void *)&complet;
501195957Salfred	xfer->callback = libusb10_do_transfer_cb;
502194676Sthompsa	complet = 0;
503194676Sthompsa
504194676Sthompsa	if ((ret = libusb_submit_transfer(xfer)) < 0) {
505194676Sthompsa		libusb_free_transfer(xfer);
506194676Sthompsa		return (ret);
507194676Sthompsa	}
508194676Sthompsa	while (complet == 0) {
509194676Sthompsa		if ((ret = libusb_handle_events(ctx)) < 0) {
510194676Sthompsa			libusb_cancel_transfer(xfer);
511195957Salfred			usleep(1000);	/* nice it */
512194676Sthompsa		}
513194676Sthompsa	}
514194676Sthompsa
515194676Sthompsa	*transferred = xfer->actual_length;
516195957Salfred
517194676Sthompsa	switch (xfer->status) {
518194676Sthompsa	case LIBUSB_TRANSFER_COMPLETED:
519195957Salfred		ret = 0;
520194676Sthompsa		break;
521194676Sthompsa	case LIBUSB_TRANSFER_TIMED_OUT:
522195957Salfred		ret = LIBUSB_ERROR_TIMEOUT;
523195957Salfred		break;
524194676Sthompsa	case LIBUSB_TRANSFER_OVERFLOW:
525195957Salfred		ret = LIBUSB_ERROR_OVERFLOW;
526195957Salfred		break;
527194676Sthompsa	case LIBUSB_TRANSFER_STALL:
528195957Salfred		ret = LIBUSB_ERROR_PIPE;
529195957Salfred		break;
530194676Sthompsa	case LIBUSB_TRANSFER_NO_DEVICE:
531195957Salfred		ret = LIBUSB_ERROR_NO_DEVICE;
532194676Sthompsa		break;
533194676Sthompsa	default:
534194676Sthompsa		ret = LIBUSB_ERROR_OTHER;
535195957Salfred		break;
536194676Sthompsa	}
537194676Sthompsa
538194676Sthompsa	libusb_free_transfer(xfer);
539194676Sthompsa	return (ret);
540194676Sthompsa}
541194676Sthompsa
542194676Sthompsaint
543195957Salfredlibusb_bulk_transfer(libusb_device_handle *devh,
544195957Salfred    uint8_t endpoint, uint8_t *data, int length,
545194676Sthompsa    int *transferred, unsigned int timeout)
546194676Sthompsa{
547194676Sthompsa	libusb_context *ctx;
548194676Sthompsa	int ret;
549195957Salfred
550195957Salfred	ctx = GET_CONTEXT(NULL);
551195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
552194676Sthompsa
553195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
554194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
555194676Sthompsa
556195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
557194676Sthompsa	return (ret);
558194676Sthompsa}
559194676Sthompsa
560194676Sthompsaint
561195957Salfredlibusb_interrupt_transfer(libusb_device_handle *devh,
562195957Salfred    uint8_t endpoint, uint8_t *data, int length,
563194676Sthompsa    int *transferred, unsigned int timeout)
564194676Sthompsa{
565194676Sthompsa	libusb_context *ctx;
566194676Sthompsa	int ret;
567194676Sthompsa
568195957Salfred	ctx = GET_CONTEXT(NULL);
569195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
570194676Sthompsa
571195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
572194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
573194676Sthompsa
574195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
575194676Sthompsa	return (ret);
576194676Sthompsa}
577199055Sthompsa
578199055Sthompsauint8_t *
579199055Sthompsalibusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t index)
580199055Sthompsa{
581199055Sthompsa	uint8_t *ptr;
582199055Sthompsa	uint32_t n;
583199055Sthompsa
584199055Sthompsa	if (transfer->num_iso_packets < 0)
585199055Sthompsa		return (NULL);
586199055Sthompsa
587199055Sthompsa	if (index >= (uint32_t)transfer->num_iso_packets)
588199055Sthompsa		return (NULL);
589199055Sthompsa
590199055Sthompsa	ptr = transfer->buffer;
591199055Sthompsa	if (ptr == NULL)
592199055Sthompsa		return (NULL);
593199055Sthompsa
594199055Sthompsa	for (n = 0; n != index; n++) {
595199055Sthompsa		ptr += transfer->iso_packet_desc[n].length;
596199055Sthompsa	}
597199055Sthompsa	return (ptr);
598199055Sthompsa}
599199055Sthompsa
600199055Sthompsauint8_t *
601199055Sthompsalibusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t index)
602199055Sthompsa{
603199055Sthompsa	uint8_t *ptr;
604199055Sthompsa
605199055Sthompsa	if (transfer->num_iso_packets < 0)
606199055Sthompsa		return (NULL);
607199055Sthompsa
608199055Sthompsa	if (index >= (uint32_t)transfer->num_iso_packets)
609199055Sthompsa		return (NULL);
610199055Sthompsa
611199055Sthompsa	ptr = transfer->buffer;
612199055Sthompsa	if (ptr == NULL)
613199055Sthompsa		return (NULL);
614199055Sthompsa
615199055Sthompsa	ptr += transfer->iso_packet_desc[0].length * index;
616199055Sthompsa
617199055Sthompsa	return (ptr);
618199055Sthompsa}
619199055Sthompsa
620199055Sthompsavoid
621199055Sthompsalibusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length)
622199055Sthompsa{
623199055Sthompsa	int n;
624199055Sthompsa
625199055Sthompsa	if (transfer->num_iso_packets < 0)
626199055Sthompsa		return;
627199055Sthompsa
628199055Sthompsa	for (n = 0; n != transfer->num_iso_packets; n++)
629199055Sthompsa		transfer->iso_packet_desc[n].length = length;
630199055Sthompsa}
631199055Sthompsa
632199055Sthompsauint8_t *
633199055Sthompsalibusb_control_transfer_get_data(struct libusb_transfer *transfer)
634199055Sthompsa{
635199055Sthompsa	if (transfer->buffer == NULL)
636199055Sthompsa		return (NULL);
637199055Sthompsa
638199055Sthompsa	return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
639199055Sthompsa}
640199055Sthompsa
641199055Sthompsastruct libusb_control_setup *
642199055Sthompsalibusb_control_transfer_get_setup(struct libusb_transfer *transfer)
643199055Sthompsa{
644199055Sthompsa	return ((struct libusb_control_setup *)transfer->buffer);
645199055Sthompsa}
646199055Sthompsa
647199055Sthompsavoid
648199055Sthompsalibusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType,
649199055Sthompsa    uint8_t bRequest, uint16_t wValue,
650199055Sthompsa    uint16_t wIndex, uint16_t wLength)
651199055Sthompsa{
652199055Sthompsa	struct libusb_control_setup *req = (struct libusb_control_setup *)buf;
653199055Sthompsa
654199055Sthompsa	/* The alignment is OK for all fields below. */
655199055Sthompsa	req->bmRequestType = bmRequestType;
656199055Sthompsa	req->bRequest = bRequest;
657199055Sthompsa	req->wValue = htole16(wValue);
658199055Sthompsa	req->wIndex = htole16(wIndex);
659199055Sthompsa	req->wLength = htole16(wLength);
660199055Sthompsa}
661199055Sthompsa
662199055Sthompsavoid
663199055Sthompsalibusb_fill_control_transfer(struct libusb_transfer *transfer,
664199055Sthompsa    libusb_device_handle *devh, uint8_t *buf,
665199055Sthompsa    libusb_transfer_cb_fn callback, void *user_data,
666199055Sthompsa    uint32_t timeout)
667199055Sthompsa{
668199055Sthompsa	struct libusb_control_setup *setup = (struct libusb_control_setup *)buf;
669199055Sthompsa
670199055Sthompsa	transfer->dev_handle = devh;
671199055Sthompsa	transfer->endpoint = 0;
672199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
673199055Sthompsa	transfer->timeout = timeout;
674199055Sthompsa	transfer->buffer = buf;
675199055Sthompsa	if (setup != NULL)
676199055Sthompsa		transfer->length = LIBUSB_CONTROL_SETUP_SIZE
677199055Sthompsa			+ le16toh(setup->wLength);
678199055Sthompsa	else
679199055Sthompsa		transfer->length = 0;
680199055Sthompsa	transfer->user_data = user_data;
681199055Sthompsa	transfer->callback = callback;
682199055Sthompsa
683199055Sthompsa}
684199055Sthompsa
685199055Sthompsavoid
686199055Sthompsalibusb_fill_bulk_transfer(struct libusb_transfer *transfer,
687199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
688199055Sthompsa    int length, libusb_transfer_cb_fn callback, void *user_data,
689199055Sthompsa    uint32_t timeout)
690199055Sthompsa{
691199055Sthompsa	transfer->dev_handle = devh;
692199055Sthompsa	transfer->endpoint = endpoint;
693199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
694199055Sthompsa	transfer->timeout = timeout;
695199055Sthompsa	transfer->buffer = buf;
696199055Sthompsa	transfer->length = length;
697199055Sthompsa	transfer->user_data = user_data;
698199055Sthompsa	transfer->callback = callback;
699199055Sthompsa}
700199055Sthompsa
701199055Sthompsavoid
702199055Sthompsalibusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
703199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
704199055Sthompsa    int length, libusb_transfer_cb_fn callback, void *user_data,
705199055Sthompsa    uint32_t timeout)
706199055Sthompsa{
707199055Sthompsa	transfer->dev_handle = devh;
708199055Sthompsa	transfer->endpoint = endpoint;
709199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
710199055Sthompsa	transfer->timeout = timeout;
711199055Sthompsa	transfer->buffer = buf;
712199055Sthompsa	transfer->length = length;
713199055Sthompsa	transfer->user_data = user_data;
714199055Sthompsa	transfer->callback = callback;
715199055Sthompsa}
716199055Sthompsa
717199055Sthompsavoid
718199055Sthompsalibusb_fill_iso_transfer(struct libusb_transfer *transfer,
719199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
720199055Sthompsa    int length, int npacket, libusb_transfer_cb_fn callback,
721199055Sthompsa    void *user_data, uint32_t timeout)
722199055Sthompsa{
723199055Sthompsa	transfer->dev_handle = devh;
724199055Sthompsa	transfer->endpoint = endpoint;
725199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
726199055Sthompsa	transfer->timeout = timeout;
727199055Sthompsa	transfer->buffer = buf;
728199055Sthompsa	transfer->length = length;
729199055Sthompsa	transfer->num_iso_packets = npacket;
730199055Sthompsa	transfer->user_data = user_data;
731199055Sthompsa	transfer->callback = callback;
732199055Sthompsa}
733199055Sthompsa
734