libusb10_io.c revision 234491
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10_io.c 234491 2012-04-20 14:29:45Z 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
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
37208020Sthompsa#define	libusb_device_handle libusb20_device
38208020Sthompsa
39194676Sthompsa#include "libusb20.h"
40194676Sthompsa#include "libusb20_desc.h"
41194676Sthompsa#include "libusb20_int.h"
42194676Sthompsa#include "libusb.h"
43194676Sthompsa#include "libusb10.h"
44194676Sthompsa
45195957SalfredUNEXPORTED void
46195957Salfredlibusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd,
47195957Salfred    struct libusb20_device *pdev, int fd, short events)
48195560Sthompsa{
49195560Sthompsa	if (ctx == NULL)
50195957Salfred		return;			/* invalid */
51195560Sthompsa
52195957Salfred	if (pollfd->entry.tqe_prev != NULL)
53195957Salfred		return;			/* already queued */
54195957Salfred
55195957Salfred	if (fd < 0)
56195957Salfred		return;			/* invalid */
57195957Salfred
58195957Salfred	pollfd->pdev = pdev;
59195560Sthompsa	pollfd->pollfd.fd = fd;
60195560Sthompsa	pollfd->pollfd.events = events;
61195560Sthompsa
62195957Salfred	CTX_LOCK(ctx);
63195957Salfred	TAILQ_INSERT_TAIL(&ctx->pollfds, pollfd, entry);
64195957Salfred	CTX_UNLOCK(ctx);
65195560Sthompsa
66195560Sthompsa	if (ctx->fd_added_cb)
67195560Sthompsa		ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data);
68195560Sthompsa}
69195560Sthompsa
70195560SthompsaUNEXPORTED void
71195957Salfredlibusb10_remove_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd)
72195560Sthompsa{
73195957Salfred	if (ctx == NULL)
74195957Salfred		return;			/* invalid */
75195560Sthompsa
76195957Salfred	if (pollfd->entry.tqe_prev == NULL)
77195957Salfred		return;			/* already dequeued */
78195560Sthompsa
79195957Salfred	CTX_LOCK(ctx);
80195957Salfred	TAILQ_REMOVE(&ctx->pollfds, pollfd, entry);
81195957Salfred	pollfd->entry.tqe_prev = NULL;
82195957Salfred	CTX_UNLOCK(ctx);
83195560Sthompsa
84195560Sthompsa	if (ctx->fd_removed_cb)
85195957Salfred		ctx->fd_removed_cb(pollfd->pollfd.fd, ctx->fd_cb_user_data);
86195560Sthompsa}
87195560Sthompsa
88195957Salfred/* This function must be called locked */
89195560Sthompsa
90195957Salfredstatic int
91195957Salfredlibusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
92195560Sthompsa{
93195957Salfred	struct libusb_device *dev;
94195957Salfred	struct libusb20_device **ppdev;
95195957Salfred	struct libusb_super_pollfd *pfd;
96195957Salfred	struct pollfd *fds;
97195957Salfred	struct libusb_super_transfer *sxfer;
98194676Sthompsa	struct libusb_transfer *uxfer;
99194676Sthompsa	nfds_t nfds;
100194676Sthompsa	int timeout;
101194676Sthompsa	int i;
102195957Salfred	int err;
103194676Sthompsa
104195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
105195957Salfred
106194676Sthompsa	nfds = 0;
107195957Salfred	i = 0;
108195957Salfred	TAILQ_FOREACH(pfd, &ctx->pollfds, entry)
109195957Salfred	    nfds++;
110194676Sthompsa
111195560Sthompsa	fds = alloca(sizeof(*fds) * nfds);
112194676Sthompsa	if (fds == NULL)
113194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
114194676Sthompsa
115195957Salfred	ppdev = alloca(sizeof(*ppdev) * nfds);
116195957Salfred	if (ppdev == NULL)
117195957Salfred		return (LIBUSB_ERROR_NO_MEM);
118195957Salfred
119195957Salfred	TAILQ_FOREACH(pfd, &ctx->pollfds, entry) {
120195957Salfred		fds[i].fd = pfd->pollfd.fd;
121195957Salfred		fds[i].events = pfd->pollfd.events;
122195957Salfred		fds[i].revents = 0;
123195957Salfred		ppdev[i] = pfd->pdev;
124195957Salfred		if (pfd->pdev != NULL)
125195957Salfred			libusb_get_device(pfd->pdev)->refcnt++;
126194676Sthompsa		i++;
127194676Sthompsa	}
128194676Sthompsa
129195957Salfred	if (tv == NULL)
130195957Salfred		timeout = -1;
131195957Salfred	else
132195957Salfred		timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
133194676Sthompsa
134195957Salfred	CTX_UNLOCK(ctx);
135195957Salfred	err = poll(fds, nfds, timeout);
136195957Salfred	CTX_LOCK(ctx);
137194676Sthompsa
138195957Salfred	if ((err == -1) && (errno == EINTR))
139195957Salfred		err = LIBUSB_ERROR_INTERRUPTED;
140195957Salfred	else if (err < 0)
141195957Salfred		err = LIBUSB_ERROR_IO;
142194676Sthompsa
143195957Salfred	if (err < 1) {
144213849Shselasky		for (i = 0; i != (int)nfds; i++) {
145195957Salfred			if (ppdev[i] != NULL) {
146195957Salfred				CTX_UNLOCK(ctx);
147195957Salfred				libusb_unref_device(libusb_get_device(ppdev[i]));
148195957Salfred				CTX_LOCK(ctx);
149195957Salfred			}
150194676Sthompsa		}
151195957Salfred		goto do_done;
152194676Sthompsa	}
153213849Shselasky	for (i = 0; i != (int)nfds; i++) {
154195957Salfred		if (ppdev[i] != NULL) {
155195957Salfred			dev = libusb_get_device(ppdev[i]);
156194676Sthompsa
157199055Sthompsa			if (fds[i].revents == 0)
158199055Sthompsa				err = 0;	/* nothing to do */
159199055Sthompsa			else
160199055Sthompsa				err = libusb20_dev_process(ppdev[i]);
161199055Sthompsa
162195957Salfred			if (err) {
163195957Salfred				/* cancel all transfers - device is gone */
164195957Salfred				libusb10_cancel_all_transfer(dev);
165199055Sthompsa
166199055Sthompsa				/* remove USB device from polling loop */
167195957Salfred				libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
168195957Salfred			}
169195957Salfred			CTX_UNLOCK(ctx);
170195957Salfred			libusb_unref_device(dev);
171195957Salfred			CTX_LOCK(ctx);
172194676Sthompsa
173195957Salfred		} else {
174195957Salfred			uint8_t dummy;
175194676Sthompsa
176195957Salfred			while (1) {
177195957Salfred				if (read(fds[i].fd, &dummy, 1) != 1)
178195957Salfred					break;
179195957Salfred			}
180194676Sthompsa		}
181195957Salfred	}
182194676Sthompsa
183195957Salfred	err = 0;
184194676Sthompsa
185195957Salfreddo_done:
186194676Sthompsa
187195957Salfred	/* Do all done callbacks */
188194676Sthompsa
189195957Salfred	while ((sxfer = TAILQ_FIRST(&ctx->tr_done))) {
190215253Shselasky		uint8_t flags;
191215253Shselasky
192195957Salfred		TAILQ_REMOVE(&ctx->tr_done, sxfer, entry);
193195957Salfred		sxfer->entry.tqe_prev = NULL;
194194676Sthompsa
195195957Salfred		ctx->tr_done_ref++;
196195957Salfred
197195957Salfred		CTX_UNLOCK(ctx);
198195957Salfred
199195957Salfred		uxfer = (struct libusb_transfer *)(
200195957Salfred		    ((uint8_t *)sxfer) + sizeof(*sxfer));
201195957Salfred
202215253Shselasky		/* Allow the callback to free the transfer itself. */
203215253Shselasky		flags = uxfer->flags;
204215253Shselasky
205195957Salfred		if (uxfer->callback != NULL)
206195957Salfred			(uxfer->callback) (uxfer);
207195957Salfred
208215253Shselasky		/* Check if the USB transfer should be automatically freed. */
209215253Shselasky		if (flags & LIBUSB_TRANSFER_FREE_TRANSFER)
210195957Salfred			libusb_free_transfer(uxfer);
211195957Salfred
212195957Salfred		CTX_LOCK(ctx);
213195957Salfred
214195957Salfred		ctx->tr_done_ref--;
215195957Salfred		ctx->tr_done_gen++;
216194676Sthompsa	}
217194676Sthompsa
218195957Salfred	/* Wakeup other waiters */
219195957Salfred	pthread_cond_broadcast(&ctx->ctx_cond);
220194676Sthompsa
221195957Salfred	return (err);
222194676Sthompsa}
223194676Sthompsa
224194676Sthompsa/* Polling and timing */
225194676Sthompsa
226194676Sthompsaint
227195957Salfredlibusb_try_lock_events(libusb_context *ctx)
228194676Sthompsa{
229195957Salfred	int err;
230194676Sthompsa
231195957Salfred	ctx = GET_CONTEXT(ctx);
232195957Salfred	if (ctx == NULL)
233194676Sthompsa		return (1);
234194676Sthompsa
235195957Salfred	err = CTX_TRYLOCK(ctx);
236195957Salfred	if (err)
237194676Sthompsa		return (1);
238194676Sthompsa
239195957Salfred	err = (ctx->ctx_handler != NO_THREAD);
240195957Salfred	if (err)
241195957Salfred		CTX_UNLOCK(ctx);
242195957Salfred	else
243195957Salfred		ctx->ctx_handler = pthread_self();
244195957Salfred
245195957Salfred	return (err);
246194676Sthompsa}
247194676Sthompsa
248194676Sthompsavoid
249195957Salfredlibusb_lock_events(libusb_context *ctx)
250194676Sthompsa{
251195957Salfred	ctx = GET_CONTEXT(ctx);
252195957Salfred	CTX_LOCK(ctx);
253195957Salfred	if (ctx->ctx_handler == NO_THREAD)
254195957Salfred		ctx->ctx_handler = pthread_self();
255194676Sthompsa}
256194676Sthompsa
257194676Sthompsavoid
258195957Salfredlibusb_unlock_events(libusb_context *ctx)
259194676Sthompsa{
260195957Salfred	ctx = GET_CONTEXT(ctx);
261195957Salfred	if (ctx->ctx_handler == pthread_self()) {
262195957Salfred		ctx->ctx_handler = NO_THREAD;
263195957Salfred		pthread_cond_broadcast(&ctx->ctx_cond);
264195957Salfred	}
265195957Salfred	CTX_UNLOCK(ctx);
266194676Sthompsa}
267194676Sthompsa
268194676Sthompsaint
269195957Salfredlibusb_event_handling_ok(libusb_context *ctx)
270194676Sthompsa{
271195957Salfred	ctx = GET_CONTEXT(ctx);
272195957Salfred	return (ctx->ctx_handler == pthread_self());
273194676Sthompsa}
274194676Sthompsa
275194676Sthompsaint
276195957Salfredlibusb_event_handler_active(libusb_context *ctx)
277194676Sthompsa{
278195957Salfred	ctx = GET_CONTEXT(ctx);
279195957Salfred	return (ctx->ctx_handler != NO_THREAD);
280194676Sthompsa}
281194676Sthompsa
282194676Sthompsavoid
283195957Salfredlibusb_lock_event_waiters(libusb_context *ctx)
284194676Sthompsa{
285195957Salfred	ctx = GET_CONTEXT(ctx);
286195957Salfred	CTX_LOCK(ctx);
287194676Sthompsa}
288194676Sthompsa
289194676Sthompsavoid
290195957Salfredlibusb_unlock_event_waiters(libusb_context *ctx)
291194676Sthompsa{
292195957Salfred	ctx = GET_CONTEXT(ctx);
293195957Salfred	CTX_UNLOCK(ctx);
294194676Sthompsa}
295194676Sthompsa
296194676Sthompsaint
297195957Salfredlibusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
298194676Sthompsa{
299194676Sthompsa	struct timespec ts;
300195957Salfred	int err;
301194676Sthompsa
302195957Salfred	ctx = GET_CONTEXT(ctx);
303195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
304194676Sthompsa
305194676Sthompsa	if (tv == NULL) {
306195957Salfred		pthread_cond_wait(&ctx->ctx_cond,
307195957Salfred		    &ctx->ctx_lock);
308194676Sthompsa		return (0);
309194676Sthompsa	}
310195957Salfred	err = clock_gettime(CLOCK_REALTIME, &ts);
311195957Salfred	if (err < 0)
312194676Sthompsa		return (LIBUSB_ERROR_OTHER);
313194676Sthompsa
314194676Sthompsa	ts.tv_sec = tv->tv_sec;
315194676Sthompsa	ts.tv_nsec = tv->tv_usec * 1000;
316195957Salfred	if (ts.tv_nsec >= 1000000000) {
317194676Sthompsa		ts.tv_nsec -= 1000000000;
318194676Sthompsa		ts.tv_sec++;
319194676Sthompsa	}
320195957Salfred	err = pthread_cond_timedwait(&ctx->ctx_cond,
321195957Salfred	    &ctx->ctx_lock, &ts);
322194676Sthompsa
323195957Salfred	if (err == ETIMEDOUT)
324194676Sthompsa		return (1);
325194676Sthompsa
326194676Sthompsa	return (0);
327194676Sthompsa}
328194676Sthompsa
329194676Sthompsaint
330195957Salfredlibusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
331194676Sthompsa{
332195957Salfred	int err;
333195957Salfred
334195957Salfred	ctx = GET_CONTEXT(ctx);
335195957Salfred
336195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout enter");
337194676Sthompsa
338195957Salfred	libusb_lock_events(ctx);
339194676Sthompsa
340195957Salfred	err = libusb_handle_events_locked(ctx, tv);
341194676Sthompsa
342195957Salfred	libusb_unlock_events(ctx);
343194676Sthompsa
344195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout leave");
345195957Salfred
346195957Salfred	return (err);
347194676Sthompsa}
348194676Sthompsa
349194676Sthompsaint
350195957Salfredlibusb_handle_events(libusb_context *ctx)
351194676Sthompsa{
352195957Salfred	return (libusb_handle_events_timeout(ctx, NULL));
353194676Sthompsa}
354194676Sthompsa
355194676Sthompsaint
356195957Salfredlibusb_handle_events_locked(libusb_context *ctx, struct timeval *tv)
357194676Sthompsa{
358195957Salfred	int err;
359194676Sthompsa
360195957Salfred	ctx = GET_CONTEXT(ctx);
361194676Sthompsa
362195957Salfred	if (libusb_event_handling_ok(ctx)) {
363195957Salfred		err = libusb10_handle_events_sub(ctx, tv);
364195957Salfred	} else {
365195957Salfred		libusb_wait_for_event(ctx, tv);
366195957Salfred		err = 0;
367194676Sthompsa	}
368195957Salfred	return (err);
369194676Sthompsa}
370194676Sthompsa
371194676Sthompsaint
372195957Salfredlibusb_get_next_timeout(libusb_context *ctx, struct timeval *tv)
373194676Sthompsa{
374195957Salfred	/* all timeouts are currently being done by the kernel */
375195957Salfred	timerclear(tv);
376195957Salfred	return (0);
377194676Sthompsa}
378194676Sthompsa
379194676Sthompsavoid
380195957Salfredlibusb_set_pollfd_notifiers(libusb_context *ctx,
381194676Sthompsa    libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
382194676Sthompsa    void *user_data)
383194676Sthompsa{
384195957Salfred	ctx = GET_CONTEXT(ctx);
385194676Sthompsa
386194676Sthompsa	ctx->fd_added_cb = added_cb;
387194676Sthompsa	ctx->fd_removed_cb = removed_cb;
388194676Sthompsa	ctx->fd_cb_user_data = user_data;
389194676Sthompsa}
390194676Sthompsa
391194676Sthompsastruct libusb_pollfd **
392195957Salfredlibusb_get_pollfds(libusb_context *ctx)
393194676Sthompsa{
394195957Salfred	struct libusb_super_pollfd *pollfd;
395194676Sthompsa	libusb_pollfd **ret;
396194676Sthompsa	int i;
397194676Sthompsa
398195957Salfred	ctx = GET_CONTEXT(ctx);
399194676Sthompsa
400195957Salfred	CTX_LOCK(ctx);
401195957Salfred
402194676Sthompsa	i = 0;
403195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
404195957Salfred	    i++;
405194676Sthompsa
406195957Salfred	ret = calloc(i + 1, sizeof(struct libusb_pollfd *));
407195957Salfred	if (ret == NULL)
408195957Salfred		goto done;
409194676Sthompsa
410194676Sthompsa	i = 0;
411195957Salfred	TAILQ_FOREACH(pollfd, &ctx->pollfds, entry)
412195957Salfred	    ret[i++] = &pollfd->pollfd;
413194676Sthompsa	ret[i] = NULL;
414194676Sthompsa
415195957Salfreddone:
416195957Salfred	CTX_UNLOCK(ctx);
417194676Sthompsa	return (ret);
418194676Sthompsa}
419194676Sthompsa
420194676Sthompsa
421194676Sthompsa/* Synchronous device I/O */
422194676Sthompsa
423194676Sthompsaint
424195957Salfredlibusb_control_transfer(libusb_device_handle *devh,
425194676Sthompsa    uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
426195957Salfred    uint8_t *data, uint16_t wLength, unsigned int timeout)
427194676Sthompsa{
428195957Salfred	struct LIBUSB20_CONTROL_SETUP_DECODED req;
429195957Salfred	int err;
430195957Salfred	uint16_t actlen;
431194676Sthompsa
432195957Salfred	if (devh == NULL)
433195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
434194676Sthompsa
435195957Salfred	if ((wLength != 0) && (data == NULL))
436195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
437194676Sthompsa
438195957Salfred	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
439194676Sthompsa
440195957Salfred	req.bmRequestType = bmRequestType;
441195957Salfred	req.bRequest = bRequest;
442195957Salfred	req.wValue = wValue;
443195957Salfred	req.wIndex = wIndex;
444195957Salfred	req.wLength = wLength;
445194676Sthompsa
446195957Salfred	err = libusb20_dev_request_sync(devh, &req, data,
447195957Salfred	    &actlen, timeout, 0);
448194676Sthompsa
449195957Salfred	if (err == LIBUSB20_ERROR_PIPE)
450195957Salfred		return (LIBUSB_ERROR_PIPE);
451195957Salfred	else if (err == LIBUSB20_ERROR_TIMEOUT)
452195957Salfred		return (LIBUSB_ERROR_TIMEOUT);
453195957Salfred	else if (err)
454195957Salfred		return (LIBUSB_ERROR_NO_DEVICE);
455194676Sthompsa
456195957Salfred	return (actlen);
457195957Salfred}
458194676Sthompsa
459195957Salfredstatic void
460195957Salfredlibusb10_do_transfer_cb(struct libusb_transfer *transfer)
461195957Salfred{
462195957Salfred	libusb_context *ctx;
463195957Salfred	int *pdone;
464194676Sthompsa
465195957Salfred	ctx = GET_CONTEXT(NULL);
466194676Sthompsa
467195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
468194676Sthompsa
469195957Salfred	pdone = transfer->user_data;
470195957Salfred	*pdone = 1;
471194676Sthompsa}
472194676Sthompsa
473195957Salfred/*
474195957Salfred * TODO: Replace the following function. Allocating and freeing on a
475195957Salfred * per-transfer basis is slow.  --HPS
476195957Salfred */
477194676Sthompsastatic int
478195957Salfredlibusb10_do_transfer(libusb_device_handle *devh,
479195957Salfred    uint8_t endpoint, uint8_t *data, int length,
480194676Sthompsa    int *transferred, unsigned int timeout, int type)
481194676Sthompsa{
482195957Salfred	libusb_context *ctx;
483194676Sthompsa	struct libusb_transfer *xfer;
484234491Shselasky	int done;
485194676Sthompsa	int ret;
486194676Sthompsa
487195957Salfred	if (devh == NULL)
488195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
489194676Sthompsa
490195957Salfred	if ((length != 0) && (data == NULL))
491195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
492195957Salfred
493194676Sthompsa	xfer = libusb_alloc_transfer(0);
494194676Sthompsa	if (xfer == NULL)
495194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
496194676Sthompsa
497195957Salfred	ctx = libusb_get_device(devh)->ctx;
498194676Sthompsa
499194676Sthompsa	xfer->dev_handle = devh;
500194676Sthompsa	xfer->endpoint = endpoint;
501194676Sthompsa	xfer->type = type;
502194676Sthompsa	xfer->timeout = timeout;
503194676Sthompsa	xfer->buffer = data;
504194676Sthompsa	xfer->length = length;
505234491Shselasky	xfer->user_data = (void *)&done;
506195957Salfred	xfer->callback = libusb10_do_transfer_cb;
507234491Shselasky	done = 0;
508194676Sthompsa
509194676Sthompsa	if ((ret = libusb_submit_transfer(xfer)) < 0) {
510194676Sthompsa		libusb_free_transfer(xfer);
511194676Sthompsa		return (ret);
512194676Sthompsa	}
513234491Shselasky	while (done == 0) {
514194676Sthompsa		if ((ret = libusb_handle_events(ctx)) < 0) {
515194676Sthompsa			libusb_cancel_transfer(xfer);
516195957Salfred			usleep(1000);	/* nice it */
517194676Sthompsa		}
518194676Sthompsa	}
519194676Sthompsa
520194676Sthompsa	*transferred = xfer->actual_length;
521195957Salfred
522194676Sthompsa	switch (xfer->status) {
523194676Sthompsa	case LIBUSB_TRANSFER_COMPLETED:
524195957Salfred		ret = 0;
525194676Sthompsa		break;
526194676Sthompsa	case LIBUSB_TRANSFER_TIMED_OUT:
527195957Salfred		ret = LIBUSB_ERROR_TIMEOUT;
528195957Salfred		break;
529194676Sthompsa	case LIBUSB_TRANSFER_OVERFLOW:
530195957Salfred		ret = LIBUSB_ERROR_OVERFLOW;
531195957Salfred		break;
532194676Sthompsa	case LIBUSB_TRANSFER_STALL:
533195957Salfred		ret = LIBUSB_ERROR_PIPE;
534195957Salfred		break;
535194676Sthompsa	case LIBUSB_TRANSFER_NO_DEVICE:
536195957Salfred		ret = LIBUSB_ERROR_NO_DEVICE;
537194676Sthompsa		break;
538194676Sthompsa	default:
539194676Sthompsa		ret = LIBUSB_ERROR_OTHER;
540195957Salfred		break;
541194676Sthompsa	}
542194676Sthompsa
543194676Sthompsa	libusb_free_transfer(xfer);
544194676Sthompsa	return (ret);
545194676Sthompsa}
546194676Sthompsa
547194676Sthompsaint
548195957Salfredlibusb_bulk_transfer(libusb_device_handle *devh,
549195957Salfred    uint8_t endpoint, uint8_t *data, int length,
550194676Sthompsa    int *transferred, unsigned int timeout)
551194676Sthompsa{
552194676Sthompsa	libusb_context *ctx;
553194676Sthompsa	int ret;
554195957Salfred
555195957Salfred	ctx = GET_CONTEXT(NULL);
556195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
557194676Sthompsa
558195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
559194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
560194676Sthompsa
561195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
562194676Sthompsa	return (ret);
563194676Sthompsa}
564194676Sthompsa
565194676Sthompsaint
566195957Salfredlibusb_interrupt_transfer(libusb_device_handle *devh,
567195957Salfred    uint8_t endpoint, uint8_t *data, int length,
568194676Sthompsa    int *transferred, unsigned int timeout)
569194676Sthompsa{
570194676Sthompsa	libusb_context *ctx;
571194676Sthompsa	int ret;
572194676Sthompsa
573195957Salfred	ctx = GET_CONTEXT(NULL);
574195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
575194676Sthompsa
576195957Salfred	ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
577194676Sthompsa	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
578194676Sthompsa
579195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
580194676Sthompsa	return (ret);
581194676Sthompsa}
582199055Sthompsa
583199055Sthompsauint8_t *
584234491Shselaskylibusb_get_iso_packet_buffer(struct libusb_transfer *transfer, uint32_t off)
585199055Sthompsa{
586199055Sthompsa	uint8_t *ptr;
587199055Sthompsa	uint32_t n;
588199055Sthompsa
589199055Sthompsa	if (transfer->num_iso_packets < 0)
590199055Sthompsa		return (NULL);
591199055Sthompsa
592234491Shselasky	if (off >= (uint32_t)transfer->num_iso_packets)
593199055Sthompsa		return (NULL);
594199055Sthompsa
595199055Sthompsa	ptr = transfer->buffer;
596199055Sthompsa	if (ptr == NULL)
597199055Sthompsa		return (NULL);
598199055Sthompsa
599234491Shselasky	for (n = 0; n != off; n++) {
600199055Sthompsa		ptr += transfer->iso_packet_desc[n].length;
601199055Sthompsa	}
602199055Sthompsa	return (ptr);
603199055Sthompsa}
604199055Sthompsa
605199055Sthompsauint8_t *
606234491Shselaskylibusb_get_iso_packet_buffer_simple(struct libusb_transfer *transfer, uint32_t off)
607199055Sthompsa{
608199055Sthompsa	uint8_t *ptr;
609199055Sthompsa
610199055Sthompsa	if (transfer->num_iso_packets < 0)
611199055Sthompsa		return (NULL);
612199055Sthompsa
613234491Shselasky	if (off >= (uint32_t)transfer->num_iso_packets)
614199055Sthompsa		return (NULL);
615199055Sthompsa
616199055Sthompsa	ptr = transfer->buffer;
617199055Sthompsa	if (ptr == NULL)
618199055Sthompsa		return (NULL);
619199055Sthompsa
620234491Shselasky	ptr += transfer->iso_packet_desc[0].length * off;
621199055Sthompsa
622199055Sthompsa	return (ptr);
623199055Sthompsa}
624199055Sthompsa
625199055Sthompsavoid
626199055Sthompsalibusb_set_iso_packet_lengths(struct libusb_transfer *transfer, uint32_t length)
627199055Sthompsa{
628199055Sthompsa	int n;
629199055Sthompsa
630199055Sthompsa	if (transfer->num_iso_packets < 0)
631199055Sthompsa		return;
632199055Sthompsa
633199055Sthompsa	for (n = 0; n != transfer->num_iso_packets; n++)
634199055Sthompsa		transfer->iso_packet_desc[n].length = length;
635199055Sthompsa}
636199055Sthompsa
637199055Sthompsauint8_t *
638199055Sthompsalibusb_control_transfer_get_data(struct libusb_transfer *transfer)
639199055Sthompsa{
640199055Sthompsa	if (transfer->buffer == NULL)
641199055Sthompsa		return (NULL);
642199055Sthompsa
643199055Sthompsa	return (transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE);
644199055Sthompsa}
645199055Sthompsa
646199055Sthompsastruct libusb_control_setup *
647199055Sthompsalibusb_control_transfer_get_setup(struct libusb_transfer *transfer)
648199055Sthompsa{
649199055Sthompsa	return ((struct libusb_control_setup *)transfer->buffer);
650199055Sthompsa}
651199055Sthompsa
652199055Sthompsavoid
653199055Sthompsalibusb_fill_control_setup(uint8_t *buf, uint8_t bmRequestType,
654199055Sthompsa    uint8_t bRequest, uint16_t wValue,
655199055Sthompsa    uint16_t wIndex, uint16_t wLength)
656199055Sthompsa{
657199055Sthompsa	struct libusb_control_setup *req = (struct libusb_control_setup *)buf;
658199055Sthompsa
659199055Sthompsa	/* The alignment is OK for all fields below. */
660199055Sthompsa	req->bmRequestType = bmRequestType;
661199055Sthompsa	req->bRequest = bRequest;
662199055Sthompsa	req->wValue = htole16(wValue);
663199055Sthompsa	req->wIndex = htole16(wIndex);
664199055Sthompsa	req->wLength = htole16(wLength);
665199055Sthompsa}
666199055Sthompsa
667199055Sthompsavoid
668199055Sthompsalibusb_fill_control_transfer(struct libusb_transfer *transfer,
669199055Sthompsa    libusb_device_handle *devh, uint8_t *buf,
670199055Sthompsa    libusb_transfer_cb_fn callback, void *user_data,
671199055Sthompsa    uint32_t timeout)
672199055Sthompsa{
673199055Sthompsa	struct libusb_control_setup *setup = (struct libusb_control_setup *)buf;
674199055Sthompsa
675199055Sthompsa	transfer->dev_handle = devh;
676199055Sthompsa	transfer->endpoint = 0;
677199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
678199055Sthompsa	transfer->timeout = timeout;
679199055Sthompsa	transfer->buffer = buf;
680199055Sthompsa	if (setup != NULL)
681199055Sthompsa		transfer->length = LIBUSB_CONTROL_SETUP_SIZE
682199055Sthompsa			+ le16toh(setup->wLength);
683199055Sthompsa	else
684199055Sthompsa		transfer->length = 0;
685199055Sthompsa	transfer->user_data = user_data;
686199055Sthompsa	transfer->callback = callback;
687199055Sthompsa
688199055Sthompsa}
689199055Sthompsa
690199055Sthompsavoid
691199055Sthompsalibusb_fill_bulk_transfer(struct libusb_transfer *transfer,
692199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
693199055Sthompsa    int length, libusb_transfer_cb_fn callback, void *user_data,
694199055Sthompsa    uint32_t timeout)
695199055Sthompsa{
696199055Sthompsa	transfer->dev_handle = devh;
697199055Sthompsa	transfer->endpoint = endpoint;
698199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
699199055Sthompsa	transfer->timeout = timeout;
700199055Sthompsa	transfer->buffer = buf;
701199055Sthompsa	transfer->length = length;
702199055Sthompsa	transfer->user_data = user_data;
703199055Sthompsa	transfer->callback = callback;
704199055Sthompsa}
705199055Sthompsa
706199055Sthompsavoid
707199055Sthompsalibusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
708199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
709199055Sthompsa    int length, libusb_transfer_cb_fn callback, void *user_data,
710199055Sthompsa    uint32_t timeout)
711199055Sthompsa{
712199055Sthompsa	transfer->dev_handle = devh;
713199055Sthompsa	transfer->endpoint = endpoint;
714199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
715199055Sthompsa	transfer->timeout = timeout;
716199055Sthompsa	transfer->buffer = buf;
717199055Sthompsa	transfer->length = length;
718199055Sthompsa	transfer->user_data = user_data;
719199055Sthompsa	transfer->callback = callback;
720199055Sthompsa}
721199055Sthompsa
722199055Sthompsavoid
723199055Sthompsalibusb_fill_iso_transfer(struct libusb_transfer *transfer,
724199055Sthompsa    libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
725199055Sthompsa    int length, int npacket, libusb_transfer_cb_fn callback,
726199055Sthompsa    void *user_data, uint32_t timeout)
727199055Sthompsa{
728199055Sthompsa	transfer->dev_handle = devh;
729199055Sthompsa	transfer->endpoint = endpoint;
730199055Sthompsa	transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS;
731199055Sthompsa	transfer->timeout = timeout;
732199055Sthompsa	transfer->buffer = buf;
733199055Sthompsa	transfer->length = length;
734199055Sthompsa	transfer->num_iso_packets = npacket;
735199055Sthompsa	transfer->user_data = user_data;
736199055Sthompsa	transfer->callback = callback;
737199055Sthompsa}
738199055Sthompsa
739