libusb10_io.c revision 194676
1/* $FreeBSD: head/lib/libusb/libusb10_io.c 194676 2009-06-23 01:04:58Z thompsa $ */
2/*-
3 * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/queue.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <stdio.h>
31#include <poll.h>
32#include <pthread.h>
33#include <time.h>
34#include <errno.h>
35
36#include "libusb20.h"
37#include "libusb20_desc.h"
38#include "libusb20_int.h"
39#include "libusb.h"
40#include "libusb10.h"
41
42static int
43get_next_timeout(libusb_context *ctx, struct timeval *tv, struct timeval *out)
44{
45	struct timeval timeout;
46	int ret;
47
48	ret = libusb_get_next_timeout(ctx, &timeout);
49
50	if (ret) {
51		if (timerisset(&timeout) == 0)
52			return 1;
53		if (timercmp(&timeout, tv, <) != 0)
54			*out = timeout;
55		else
56			*out = *tv;
57	} else {
58		*out = *tv;
59	}
60
61	return (0);
62}
63
64static int
65handle_timeouts(struct libusb_context *ctx)
66{
67	struct timespec sys_ts;
68	struct timeval sys_tv;
69	struct timeval *cur_tv;
70	struct usb_transfer *xfer;
71	struct libusb_transfer *uxfer;
72	int ret;
73
74	GET_CONTEXT(ctx);
75	ret = 0;
76
77	pthread_mutex_lock(&ctx->flying_transfers_lock);
78	if (USB_LIST_EMPTY(&ctx->flying_transfers))
79		goto out;
80
81	ret = clock_gettime(CLOCK_MONOTONIC, &sys_ts);
82	TIMESPEC_TO_TIMEVAL(&sys_tv, &sys_ts);
83
84	LIST_FOREACH_ENTRY(xfer, &ctx->flying_transfers, list) {
85		cur_tv = &xfer->timeout;
86
87		if (timerisset(cur_tv) == 0)
88			goto out;
89
90		if (xfer->flags & USB_TIMED_OUT)
91			continue;
92
93		if ((cur_tv->tv_sec > sys_tv.tv_sec) || (cur_tv->tv_sec == sys_tv.tv_sec &&
94		    cur_tv->tv_usec > sys_tv.tv_usec))
95			goto out;
96
97		xfer->flags |= USB_TIMED_OUT;
98		uxfer = (libusb_transfer *) ((uint8_t *)xfer +
99		    sizeof(struct usb_transfer));
100		ret = libusb_cancel_transfer(uxfer);
101	}
102out:
103	pthread_mutex_unlock(&ctx->flying_transfers_lock);
104	return (ret);
105}
106
107static int
108handle_events(struct libusb_context *ctx, struct timeval *tv)
109{
110	struct libusb_pollfd *tmppollfd;
111	struct libusb_device_handle *devh;
112	struct usb_pollfd *ipollfd;
113	struct usb_transfer *cur;
114	struct usb_transfer *cancel;
115	struct libusb_transfer *xfer;
116	struct pollfd *fds;
117	struct pollfd *tfds;
118	nfds_t nfds;
119	int tmpfd;
120	int tmp;
121	int ret;
122	int timeout;
123	int i;
124
125	GET_CONTEXT(ctx);
126	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "handle_events enter");
127
128	nfds = 0;
129	i = -1;
130
131	pthread_mutex_lock(&ctx->pollfds_lock);
132	LIST_FOREACH_ENTRY(ipollfd, &ctx->pollfds, list)
133		nfds++;
134
135	fds = malloc(sizeof(*fds) * nfds);
136	if (fds == NULL)
137		return (LIBUSB_ERROR_NO_MEM);
138
139	LIST_FOREACH_ENTRY(ipollfd, &ctx->pollfds, list) {
140		tmppollfd = &ipollfd->pollfd;
141		tmpfd = tmppollfd->fd;
142		i++;
143		fds[i].fd = tmpfd;
144		fds[i].events = tmppollfd->events;
145		fds[i].revents = 0;
146	}
147
148	pthread_mutex_unlock(&ctx->pollfds_lock);
149
150	timeout = (tv->tv_sec * 1000) + (tv->tv_usec / 1000);
151	if (tv->tv_usec % 1000)
152		timeout++;
153
154	ret = poll(fds, nfds, timeout);
155	if (ret == 0) {
156		free(fds);
157		return (handle_timeouts(ctx));
158	} else if (ret == -1 && errno == EINTR) {
159		free(fds);
160		return (LIBUSB_ERROR_INTERRUPTED);
161	} else if (ret < 0) {
162		free(fds);
163		return (LIBUSB_ERROR_IO);
164	}
165
166	if (fds[0].revents) {
167		if (ret == 1){
168			ret = 0;
169			goto handled;
170		} else {
171			fds[0].revents = 0;
172			ret--;
173		}
174	}
175
176	pthread_mutex_lock(&ctx->open_devs_lock);
177	for (i = 0 ; i < nfds && ret > 0 ; i++) {
178
179		tfds = &fds[i];
180		if (!tfds->revents)
181			continue;
182
183		ret--;
184		LIST_FOREACH_ENTRY(devh, &ctx->open_devs, list) {
185			if (libusb20_dev_get_fd(devh->os_priv) == tfds->fd)
186				break ;
187		}
188
189		if (tfds->revents & POLLERR) {
190			usb_remove_pollfd(ctx, libusb20_dev_get_fd(devh->os_priv));
191			usb_handle_disconnect(devh);
192			continue ;
193		}
194
195
196		pthread_mutex_lock(&libusb20_lock);
197		dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "LIBUSB20_PROCESS");
198		ret = libusb20_dev_process(devh->os_priv);
199		pthread_mutex_unlock(&libusb20_lock);
200
201
202		if (ret == 0 || ret == LIBUSB20_ERROR_NO_DEVICE)
203		       	continue;
204		else if (ret < 0)
205			goto out;
206	}
207
208	ret = 0;
209out:
210	pthread_mutex_unlock(&ctx->open_devs_lock);
211
212handled:
213	free(fds);
214	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "handle_events leave");
215	return ret;
216}
217
218/* Polling and timing */
219
220int
221libusb_try_lock_events(libusb_context * ctx)
222{
223	int ret;
224
225	GET_CONTEXT(ctx);
226	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_try_lock_events enter");
227
228	pthread_mutex_lock(&ctx->pollfd_modify_lock);
229	ret = ctx->pollfd_modify;
230	pthread_mutex_unlock(&ctx->pollfd_modify_lock);
231
232	if (ret != 0)
233		return (1);
234
235	ret = pthread_mutex_trylock(&ctx->events_lock);
236
237	if (ret != 0)
238		return (1);
239
240	ctx->event_handler_active = 1;
241
242	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_try_lock_events leave");
243	return (0);
244}
245
246void
247libusb_lock_events(libusb_context * ctx)
248{
249	GET_CONTEXT(ctx);
250	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_events enter");
251
252	pthread_mutex_lock(&ctx->events_lock);
253	ctx->event_handler_active = 1;
254
255	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_events leave");
256}
257
258void
259libusb_unlock_events(libusb_context * ctx)
260{
261	GET_CONTEXT(ctx);
262	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_events enter");
263
264	ctx->event_handler_active = 0;
265	pthread_mutex_unlock(&ctx->events_lock);
266
267	pthread_mutex_lock(&ctx->event_waiters_lock);
268	pthread_cond_broadcast(&ctx->event_waiters_cond);
269	pthread_mutex_unlock(&ctx->event_waiters_lock);
270
271	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_events leave");
272}
273
274int
275libusb_event_handling_ok(libusb_context * ctx)
276{
277	int ret;
278
279	GET_CONTEXT(ctx);
280	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handling_ok enter");
281
282	pthread_mutex_lock(&ctx->pollfd_modify_lock);
283	ret = ctx->pollfd_modify;
284	pthread_mutex_unlock(&ctx->pollfd_modify_lock);
285
286	if (ret != 0)
287		return (0);
288
289	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handling_ok leave");
290	return (1);
291}
292
293int
294libusb_event_handler_active(libusb_context * ctx)
295{
296	int ret;
297
298	GET_CONTEXT(ctx);
299	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handler_active enter");
300
301	pthread_mutex_lock(&ctx->pollfd_modify_lock);
302	ret = ctx->pollfd_modify;
303	pthread_mutex_unlock(&ctx->pollfd_modify_lock);
304
305	if (ret != 0)
306		return (1);
307
308	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_event_handler_active leave");
309	return (ctx->event_handler_active);
310}
311
312void
313libusb_lock_event_waiters(libusb_context * ctx)
314{
315	GET_CONTEXT(ctx);
316	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_event_waiters enter");
317
318	pthread_mutex_lock(&ctx->event_waiters_lock);
319
320	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_lock_event_waiters leave");
321}
322
323void
324libusb_unlock_event_waiters(libusb_context * ctx)
325{
326	GET_CONTEXT(ctx);
327	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_event_waiters enter");
328
329	pthread_mutex_unlock(&ctx->event_waiters_lock);
330
331	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_unlock_event_waiters leave");
332}
333
334int
335libusb_wait_for_event(libusb_context * ctx, struct timeval *tv)
336{
337	int ret;
338	struct timespec ts;
339
340	GET_CONTEXT(ctx);
341	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
342
343	if (tv == NULL) {
344		pthread_cond_wait(&ctx->event_waiters_cond,
345		    &ctx->event_waiters_lock);
346		return (0);
347	}
348
349	ret = clock_gettime(CLOCK_REALTIME, &ts);
350	if (ret < 0)
351		return (LIBUSB_ERROR_OTHER);
352
353	ts.tv_sec = tv->tv_sec;
354	ts.tv_nsec = tv->tv_usec * 1000;
355	if (ts.tv_nsec > 1000000000) {
356		ts.tv_nsec -= 1000000000;
357		ts.tv_sec++;
358	}
359
360	ret = pthread_cond_timedwait(&ctx->event_waiters_cond,
361	    &ctx->event_waiters_lock, &ts);
362
363	if (ret == ETIMEDOUT)
364		return (1);
365
366	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event leave");
367	return (0);
368}
369
370int
371libusb_handle_events_timeout(libusb_context * ctx, struct timeval *tv)
372{
373	struct timeval timeout;
374	struct timeval poll_timeout;
375	int ret;
376
377	GET_CONTEXT(ctx);
378	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout enter");
379
380	ret = get_next_timeout(ctx, tv, &poll_timeout);
381	if (ret != 0) {
382		return handle_timeouts(ctx);
383	}
384retry:
385	if (libusb_try_lock_events(ctx) == 0) {
386		ret = handle_events(ctx, &poll_timeout);
387		libusb_unlock_events(ctx);
388		return ret;
389	}
390
391	libusb_lock_event_waiters(ctx);
392	if (libusb_event_handler_active(ctx) == 0) {
393		libusb_unlock_event_waiters(ctx);
394		goto retry;
395	}
396
397	ret = libusb_wait_for_event(ctx, &poll_timeout);
398	libusb_unlock_event_waiters(ctx);
399
400	if (ret < 0)
401		return ret;
402	else if (ret == 1)
403		return (handle_timeouts(ctx));
404
405	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout leave");
406	return (0);
407}
408
409int
410libusb_handle_events(libusb_context * ctx)
411{
412	struct timeval tv;
413	int ret;
414
415	GET_CONTEXT(ctx);
416	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events enter");
417
418	tv.tv_sec = 2;
419	tv.tv_usec = 0;
420	ret = libusb_handle_events_timeout(ctx, &tv);
421
422	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events leave");
423	return (ret);
424}
425
426int
427libusb_handle_events_locked(libusb_context * ctx, struct timeval *tv)
428{
429	int ret;
430	struct timeval poll_tv;
431
432	GET_CONTEXT(ctx);
433	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_locked enter");
434
435	ret = get_next_timeout(ctx, tv, &poll_tv);
436	if (ret != 0) {
437		return handle_timeouts(ctx);
438	}
439
440	ret = handle_events(ctx, &poll_tv);
441
442	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_locked leave");
443	return (ret);
444}
445
446int
447libusb_get_next_timeout(libusb_context * ctx, struct timeval *tv)
448{
449	struct usb_transfer *xfer;
450	struct timeval *next_tv;
451	struct timeval cur_tv;
452	struct timespec cur_ts;
453	int found;
454	int ret;
455
456	GET_CONTEXT(ctx);
457	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_next_timeout enter");
458
459	found = 0;
460	pthread_mutex_lock(&ctx->flying_transfers_lock);
461	if (USB_LIST_EMPTY(&ctx->flying_transfers)) {
462		pthread_mutex_unlock(&ctx->flying_transfers_lock);
463		return (0);
464	}
465
466	LIST_FOREACH_ENTRY(xfer, &ctx->flying_transfers, list) {
467		if (!(xfer->flags & USB_TIMED_OUT)) {
468			found = 1;
469			break ;
470		}
471	}
472	pthread_mutex_unlock(&ctx->flying_transfers_lock);
473
474	if (found == 0) {
475		return 0;
476	}
477
478	next_tv = &xfer->timeout;
479	if (timerisset(next_tv) == 0)
480		return (0);
481
482	ret = clock_gettime(CLOCK_MONOTONIC, &cur_ts);
483       	if (ret < 0)
484		return (LIBUSB_ERROR_OTHER);
485	TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);
486
487	if (timercmp(&cur_tv, next_tv, >=) != 0)
488		timerclear(tv);
489	else
490		timersub(next_tv, &cur_tv, tv);
491
492	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_next_timeout leave");
493	return (1);
494}
495
496void
497libusb_set_pollfd_notifiers(libusb_context * ctx,
498    libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
499    void *user_data)
500{
501	GET_CONTEXT(ctx);
502	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_pollfd_notifiers enter");
503
504	ctx->fd_added_cb = added_cb;
505	ctx->fd_removed_cb = removed_cb;
506	ctx->fd_cb_user_data = user_data;
507
508	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_set_pollfd_notifiers leave");
509}
510
511struct libusb_pollfd **
512libusb_get_pollfds(libusb_context * ctx)
513{
514	struct usb_pollfd *pollfd;
515	libusb_pollfd **ret;
516	int i;
517
518	GET_CONTEXT(ctx);
519	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_pollfds enter");
520
521	i = 0;
522	pthread_mutex_lock(&ctx->pollfds_lock);
523	LIST_FOREACH_ENTRY(pollfd, &ctx->pollfds, list)
524		i++;
525
526	ret = calloc(i + 1 , sizeof(struct libusb_pollfd *));
527	if (ret == NULL) {
528		pthread_mutex_unlock(&ctx->pollfds_lock);
529		return (ret);
530	}
531
532	i = 0;
533	LIST_FOREACH_ENTRY(pollfd, &ctx->pollfds, list)
534		ret[i++] = (struct libusb_pollfd *) pollfd;
535	ret[i] = NULL;
536
537	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_pollfds leave");
538	return (ret);
539}
540
541
542/* Synchronous device I/O */
543
544static void ctrl_tr_cb(struct libusb_transfer *transfer)
545{
546	libusb_context *ctx;
547	int *complet;
548
549	ctx = NULL;
550	GET_CONTEXT(ctx);
551	dprintf(ctx, LIBUSB_DEBUG_TRANSFER, "CALLBACK ENTER");
552
553	complet = transfer->user_data;
554	*complet = 1;
555}
556
557int
558libusb_control_transfer(libusb_device_handle * devh,
559    uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
560    unsigned char *data, uint16_t wLength, unsigned int timeout)
561{
562	struct libusb_transfer *xfer;
563	struct libusb_control_setup *ctr;
564	libusb_context *ctx;
565	unsigned char *buff;
566	int complet;
567	int ret;
568
569	ctx = devh->dev->ctx;
570	GET_CONTEXT(ctx);
571	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_control_transfer enter");
572
573	if (devh == NULL || data == NULL)
574		return (LIBUSB_ERROR_NO_MEM);
575
576	xfer = libusb_alloc_transfer(0);
577	if (xfer == NULL)
578		return (LIBUSB_ERROR_NO_MEM);
579
580	buff = malloc(sizeof(libusb_control_setup) + wLength);
581	if (buff == NULL) {
582		libusb_free_transfer(xfer);
583		return (LIBUSB_ERROR_NO_MEM);
584	}
585
586	ctr = (libusb_control_setup *)buff;
587	ctr->bmRequestType = bmRequestType;
588	ctr->bRequest = bRequest;
589	ctr->wValue = wValue;
590	ctr->wIndex = wIndex;
591	ctr->wLength = wLength;
592	if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
593		memcpy(buff + sizeof(libusb_control_setup), data, wLength);
594
595	xfer->dev_handle = devh;
596	xfer->endpoint = 0;
597	xfer->type = LIBUSB_TRANSFER_TYPE_CONTROL;
598	xfer->timeout = timeout;
599	xfer->buffer = buff;
600	xfer->length = sizeof(libusb_control_setup) + wLength;
601	xfer->user_data = &complet;
602	xfer->callback = ctrl_tr_cb;
603	xfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER;
604	complet = 0;
605
606	if ((ret = libusb_submit_transfer(xfer)) < 0) {
607		libusb_free_transfer(xfer);
608		return (ret);
609	}
610
611	while (complet == 0)
612		if ((ret = libusb_handle_events(ctx)) < 0) {
613			libusb_cancel_transfer(xfer);
614			while (complet == 0)
615				if (libusb_handle_events(ctx) < 0) {
616					break;
617				}
618			libusb_free_transfer(xfer);
619			return (ret);
620		}
621
622
623	if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
624		memcpy(data, buff + sizeof(libusb_control_setup), wLength);
625
626	switch (xfer->status) {
627	case LIBUSB_TRANSFER_COMPLETED:
628		ret = xfer->actual_length;
629		break;
630	case LIBUSB_TRANSFER_TIMED_OUT:
631	case LIBUSB_TRANSFER_STALL:
632	case LIBUSB_TRANSFER_NO_DEVICE:
633		ret = xfer->status;
634		break;
635	default:
636		ret = LIBUSB_ERROR_OTHER;
637	}
638	libusb_free_transfer(xfer);
639
640	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_control_transfer leave");
641	return (ret);
642}
643
644static int
645do_transfer(struct libusb_device_handle *devh,
646    unsigned char endpoint, unsigned char *data, int length,
647    int *transferred, unsigned int timeout, int type)
648{
649	struct libusb_transfer *xfer;
650	libusb_context *ctx;
651	int complet;
652	int ret;
653
654	if (devh == NULL || data == NULL)
655		return (LIBUSB_ERROR_NO_MEM);
656
657	xfer = libusb_alloc_transfer(0);
658	if (xfer == NULL)
659		return (LIBUSB_ERROR_NO_MEM);
660
661	ctx = devh->dev->ctx;
662
663	xfer->dev_handle = devh;
664	xfer->endpoint = endpoint;
665	xfer->type = type;
666	xfer->timeout = timeout;
667	xfer->buffer = data;
668	xfer->length = length;
669	xfer->user_data = &complet;
670	xfer->callback = ctrl_tr_cb;
671	complet = 0;
672
673	if ((ret = libusb_submit_transfer(xfer)) < 0) {
674		libusb_free_transfer(xfer);
675		return (ret);
676	}
677
678	while (complet == 0) {
679		if ((ret = libusb_handle_events(ctx)) < 0) {
680			libusb_cancel_transfer(xfer);
681			libusb_free_transfer(xfer);
682			while (complet == 0) {
683				if (libusb_handle_events(ctx) < 0)
684					break ;
685			}
686			return (ret);
687		}
688	}
689
690	*transferred = xfer->actual_length;
691	switch (xfer->status) {
692	case LIBUSB_TRANSFER_COMPLETED:
693		ret = xfer->actual_length;
694		break;
695	case LIBUSB_TRANSFER_TIMED_OUT:
696	case LIBUSB_TRANSFER_OVERFLOW:
697	case LIBUSB_TRANSFER_STALL:
698	case LIBUSB_TRANSFER_NO_DEVICE:
699		ret = xfer->status;
700		break;
701	default:
702		ret = LIBUSB_ERROR_OTHER;
703	}
704
705	libusb_free_transfer(xfer);
706	return (ret);
707}
708
709int
710libusb_bulk_transfer(struct libusb_device_handle *devh,
711    unsigned char endpoint, unsigned char *data, int length,
712    int *transferred, unsigned int timeout)
713{
714	libusb_context *ctx;
715	int ret;
716
717	ctx = NULL;
718	GET_CONTEXT(ctx);
719	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
720
721	ret = do_transfer(devh, endpoint, data, length, transferred,
722	    timeout, LIBUSB_TRANSFER_TYPE_BULK);
723
724	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
725	return (ret);
726}
727
728/*
729 * Need to fix xfer->type
730 */
731int
732libusb_interrupt_transfer(struct libusb_device_handle *devh,
733    unsigned char endpoint, unsigned char *data, int length,
734    int *transferred, unsigned int timeout)
735{
736	libusb_context *ctx;
737	int ret;
738
739	ctx = NULL;
740	GET_CONTEXT(ctx);
741	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
742
743	ret = do_transfer(devh, endpoint, data, length, transferred,
744	    timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
745
746	dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
747	return (ret);
748}
749