xref: /dragonfly/lib/libusb/libusb20.c (revision 9b0c1abe)
1*9b0c1abeSSascha Wildner /* $FreeBSD: head/lib/libusb/libusb20.c 253339 2013-07-14 10:22:00Z hselasky $ */
21d96047eSMarkus Pfeiffer /*-
31d96047eSMarkus Pfeiffer  * Copyright (c) 2008-2009 Hans Petter Selasky. All rights reserved.
41d96047eSMarkus Pfeiffer  *
51d96047eSMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
61d96047eSMarkus Pfeiffer  * modification, are permitted provided that the following conditions
71d96047eSMarkus Pfeiffer  * are met:
81d96047eSMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
91d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
101d96047eSMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
111d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
121d96047eSMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
131d96047eSMarkus Pfeiffer  *
141d96047eSMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151d96047eSMarkus Pfeiffer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161d96047eSMarkus Pfeiffer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171d96047eSMarkus Pfeiffer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181d96047eSMarkus Pfeiffer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191d96047eSMarkus Pfeiffer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201d96047eSMarkus Pfeiffer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211d96047eSMarkus Pfeiffer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221d96047eSMarkus Pfeiffer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231d96047eSMarkus Pfeiffer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241d96047eSMarkus Pfeiffer  * SUCH DAMAGE.
251d96047eSMarkus Pfeiffer  */
261d96047eSMarkus Pfeiffer 
27*9b0c1abeSSascha Wildner #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
28*9b0c1abeSSascha Wildner #include LIBUSB_GLOBAL_INCLUDE_FILE
29*9b0c1abeSSascha Wildner #else
301d96047eSMarkus Pfeiffer #include <ctype.h>
311d96047eSMarkus Pfeiffer #include <poll.h>
321d96047eSMarkus Pfeiffer #include <stdio.h>
331d96047eSMarkus Pfeiffer #include <stdlib.h>
341d96047eSMarkus Pfeiffer #include <string.h>
35*9b0c1abeSSascha Wildner #include <time.h>
36*9b0c1abeSSascha Wildner #include <sys/queue.h>
37*9b0c1abeSSascha Wildner #endif
381d96047eSMarkus Pfeiffer 
391d96047eSMarkus Pfeiffer #include "libusb20.h"
401d96047eSMarkus Pfeiffer #include "libusb20_desc.h"
411d96047eSMarkus Pfeiffer #include "libusb20_int.h"
421d96047eSMarkus Pfeiffer 
431d96047eSMarkus Pfeiffer static int
dummy_int(void)441d96047eSMarkus Pfeiffer dummy_int(void)
451d96047eSMarkus Pfeiffer {
461d96047eSMarkus Pfeiffer 	return (LIBUSB20_ERROR_NOT_SUPPORTED);
471d96047eSMarkus Pfeiffer }
481d96047eSMarkus Pfeiffer 
491d96047eSMarkus Pfeiffer static void
dummy_void(void)501d96047eSMarkus Pfeiffer dummy_void(void)
511d96047eSMarkus Pfeiffer {
521d96047eSMarkus Pfeiffer 	return;
531d96047eSMarkus Pfeiffer }
541d96047eSMarkus Pfeiffer 
551d96047eSMarkus Pfeiffer static void
dummy_callback(struct libusb20_transfer * xfer)561d96047eSMarkus Pfeiffer dummy_callback(struct libusb20_transfer *xfer)
571d96047eSMarkus Pfeiffer {
581d96047eSMarkus Pfeiffer 	;				/* style fix */
591d96047eSMarkus Pfeiffer 	switch (libusb20_tr_get_status(xfer)) {
601d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_START:
611d96047eSMarkus Pfeiffer 		libusb20_tr_submit(xfer);
621d96047eSMarkus Pfeiffer 		break;
631d96047eSMarkus Pfeiffer 	default:
641d96047eSMarkus Pfeiffer 		/* complete or error */
651d96047eSMarkus Pfeiffer 		break;
661d96047eSMarkus Pfeiffer 	}
671d96047eSMarkus Pfeiffer 	return;
681d96047eSMarkus Pfeiffer }
691d96047eSMarkus Pfeiffer 
701d96047eSMarkus Pfeiffer #define	dummy_get_config_desc_full (void *)dummy_int
711d96047eSMarkus Pfeiffer #define	dummy_get_config_index (void *)dummy_int
721d96047eSMarkus Pfeiffer #define	dummy_set_config_index (void *)dummy_int
731d96047eSMarkus Pfeiffer #define	dummy_set_alt_index (void *)dummy_int
741d96047eSMarkus Pfeiffer #define	dummy_reset_device (void *)dummy_int
751d96047eSMarkus Pfeiffer #define	dummy_check_connected (void *)dummy_int
761d96047eSMarkus Pfeiffer #define	dummy_set_power_mode (void *)dummy_int
771d96047eSMarkus Pfeiffer #define	dummy_get_power_mode (void *)dummy_int
78*9b0c1abeSSascha Wildner #define	dummy_get_port_path (void *)dummy_int
79*9b0c1abeSSascha Wildner #define	dummy_get_power_usage (void *)dummy_int
801d96047eSMarkus Pfeiffer #define	dummy_kernel_driver_active (void *)dummy_int
811d96047eSMarkus Pfeiffer #define	dummy_detach_kernel_driver (void *)dummy_int
821d96047eSMarkus Pfeiffer #define	dummy_do_request_sync (void *)dummy_int
831d96047eSMarkus Pfeiffer #define	dummy_tr_open (void *)dummy_int
841d96047eSMarkus Pfeiffer #define	dummy_tr_close (void *)dummy_int
851d96047eSMarkus Pfeiffer #define	dummy_tr_clear_stall_sync (void *)dummy_int
861d96047eSMarkus Pfeiffer #define	dummy_process (void *)dummy_int
871d96047eSMarkus Pfeiffer #define	dummy_dev_info (void *)dummy_int
881d96047eSMarkus Pfeiffer #define	dummy_dev_get_iface_driver (void *)dummy_int
891d96047eSMarkus Pfeiffer 
901d96047eSMarkus Pfeiffer #define	dummy_tr_submit (void *)dummy_void
911d96047eSMarkus Pfeiffer #define	dummy_tr_cancel_async (void *)dummy_void
921d96047eSMarkus Pfeiffer 
931d96047eSMarkus Pfeiffer static const struct libusb20_device_methods libusb20_dummy_methods = {
941d96047eSMarkus Pfeiffer 	LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy)
951d96047eSMarkus Pfeiffer };
961d96047eSMarkus Pfeiffer 
971d96047eSMarkus Pfeiffer void
libusb20_tr_callback_wrapper(struct libusb20_transfer * xfer)981d96047eSMarkus Pfeiffer libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer)
991d96047eSMarkus Pfeiffer {
1001d96047eSMarkus Pfeiffer 	;				/* style fix */
1011d96047eSMarkus Pfeiffer 
1021d96047eSMarkus Pfeiffer repeat:
1031d96047eSMarkus Pfeiffer 
1041d96047eSMarkus Pfeiffer 	if (!xfer->is_pending) {
1051d96047eSMarkus Pfeiffer 		xfer->status = LIBUSB20_TRANSFER_START;
1061d96047eSMarkus Pfeiffer 	} else {
1071d96047eSMarkus Pfeiffer 		xfer->is_pending = 0;
1081d96047eSMarkus Pfeiffer 	}
1091d96047eSMarkus Pfeiffer 
1101d96047eSMarkus Pfeiffer 	xfer->callback(xfer);
1111d96047eSMarkus Pfeiffer 
1121d96047eSMarkus Pfeiffer 	if (xfer->is_restart) {
1131d96047eSMarkus Pfeiffer 		xfer->is_restart = 0;
1141d96047eSMarkus Pfeiffer 		goto repeat;
1151d96047eSMarkus Pfeiffer 	}
1161d96047eSMarkus Pfeiffer 	if (xfer->is_draining &&
1171d96047eSMarkus Pfeiffer 	    (!xfer->is_pending)) {
1181d96047eSMarkus Pfeiffer 		xfer->is_draining = 0;
1191d96047eSMarkus Pfeiffer 		xfer->status = LIBUSB20_TRANSFER_DRAINED;
1201d96047eSMarkus Pfeiffer 		xfer->callback(xfer);
1211d96047eSMarkus Pfeiffer 	}
1221d96047eSMarkus Pfeiffer 	return;
1231d96047eSMarkus Pfeiffer }
1241d96047eSMarkus Pfeiffer 
1251d96047eSMarkus Pfeiffer int
libusb20_tr_close(struct libusb20_transfer * xfer)1261d96047eSMarkus Pfeiffer libusb20_tr_close(struct libusb20_transfer *xfer)
1271d96047eSMarkus Pfeiffer {
1281d96047eSMarkus Pfeiffer 	int error;
1291d96047eSMarkus Pfeiffer 
1301d96047eSMarkus Pfeiffer 	if (!xfer->is_opened) {
1311d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_OTHER);
1321d96047eSMarkus Pfeiffer 	}
1331d96047eSMarkus Pfeiffer 	error = xfer->pdev->methods->tr_close(xfer);
1341d96047eSMarkus Pfeiffer 
1351d96047eSMarkus Pfeiffer 	if (xfer->pLength) {
1361d96047eSMarkus Pfeiffer 		free(xfer->pLength);
1371d96047eSMarkus Pfeiffer 	}
1381d96047eSMarkus Pfeiffer 	if (xfer->ppBuffer) {
1391d96047eSMarkus Pfeiffer 		free(xfer->ppBuffer);
1401d96047eSMarkus Pfeiffer 	}
1411d96047eSMarkus Pfeiffer 	/* reset variable fields in case the transfer is opened again */
1421d96047eSMarkus Pfeiffer 	xfer->priv_sc0 = 0;
1431d96047eSMarkus Pfeiffer 	xfer->priv_sc1 = 0;
1441d96047eSMarkus Pfeiffer 	xfer->is_opened = 0;
1451d96047eSMarkus Pfeiffer 	xfer->is_pending = 0;
1461d96047eSMarkus Pfeiffer 	xfer->is_cancel = 0;
1471d96047eSMarkus Pfeiffer 	xfer->is_draining = 0;
1481d96047eSMarkus Pfeiffer 	xfer->is_restart = 0;
1491d96047eSMarkus Pfeiffer 	xfer->status = 0;
1501d96047eSMarkus Pfeiffer 	xfer->flags = 0;
1511d96047eSMarkus Pfeiffer 	xfer->nFrames = 0;
1521d96047eSMarkus Pfeiffer 	xfer->aFrames = 0;
1531d96047eSMarkus Pfeiffer 	xfer->timeout = 0;
1541d96047eSMarkus Pfeiffer 	xfer->maxFrames = 0;
1551d96047eSMarkus Pfeiffer 	xfer->maxTotalLength = 0;
1561d96047eSMarkus Pfeiffer 	xfer->maxPacketLen = 0;
1571d96047eSMarkus Pfeiffer 	return (error);
1581d96047eSMarkus Pfeiffer }
1591d96047eSMarkus Pfeiffer 
1601d96047eSMarkus Pfeiffer int
libusb20_tr_open(struct libusb20_transfer * xfer,uint32_t MaxBufSize,uint32_t MaxFrameCount,uint8_t ep_no)1611d96047eSMarkus Pfeiffer libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
1621d96047eSMarkus Pfeiffer     uint32_t MaxFrameCount, uint8_t ep_no)
1631d96047eSMarkus Pfeiffer {
164*9b0c1abeSSascha Wildner 	return (libusb20_tr_open_stream(xfer, MaxBufSize, MaxFrameCount, ep_no, 0));
165*9b0c1abeSSascha Wildner }
166*9b0c1abeSSascha Wildner 
167*9b0c1abeSSascha Wildner int
libusb20_tr_open_stream(struct libusb20_transfer * xfer,uint32_t MaxBufSize,uint32_t MaxFrameCount,uint8_t ep_no,uint16_t stream_id)168*9b0c1abeSSascha Wildner libusb20_tr_open_stream(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
169*9b0c1abeSSascha Wildner     uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id)
170*9b0c1abeSSascha Wildner {
1711d96047eSMarkus Pfeiffer 	uint32_t size;
1721d96047eSMarkus Pfeiffer 	uint8_t pre_scale;
1731d96047eSMarkus Pfeiffer 	int error;
1741d96047eSMarkus Pfeiffer 
1751d96047eSMarkus Pfeiffer 	if (xfer->is_opened)
1761d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_BUSY);
1771d96047eSMarkus Pfeiffer 	if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) {
1781d96047eSMarkus Pfeiffer 		MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE;
1791d96047eSMarkus Pfeiffer 		pre_scale = 1;
1801d96047eSMarkus Pfeiffer 	} else {
1811d96047eSMarkus Pfeiffer 		pre_scale = 0;
1821d96047eSMarkus Pfeiffer 	}
1831d96047eSMarkus Pfeiffer 	if (MaxFrameCount == 0)
1841d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_INVALID_PARAM);
1851d96047eSMarkus Pfeiffer 
1861d96047eSMarkus Pfeiffer 	xfer->maxFrames = MaxFrameCount;
1871d96047eSMarkus Pfeiffer 
1881d96047eSMarkus Pfeiffer 	size = MaxFrameCount * sizeof(xfer->pLength[0]);
1891d96047eSMarkus Pfeiffer 	xfer->pLength = malloc(size);
1901d96047eSMarkus Pfeiffer 	if (xfer->pLength == NULL) {
1911d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_NO_MEM);
1921d96047eSMarkus Pfeiffer 	}
1931d96047eSMarkus Pfeiffer 	memset(xfer->pLength, 0, size);
1941d96047eSMarkus Pfeiffer 
1951d96047eSMarkus Pfeiffer 	size = MaxFrameCount * sizeof(xfer->ppBuffer[0]);
1961d96047eSMarkus Pfeiffer 	xfer->ppBuffer = malloc(size);
1971d96047eSMarkus Pfeiffer 	if (xfer->ppBuffer == NULL) {
1981d96047eSMarkus Pfeiffer 		free(xfer->pLength);
1991d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_NO_MEM);
2001d96047eSMarkus Pfeiffer 	}
2011d96047eSMarkus Pfeiffer 	memset(xfer->ppBuffer, 0, size);
2021d96047eSMarkus Pfeiffer 
2031d96047eSMarkus Pfeiffer 	error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
204*9b0c1abeSSascha Wildner 	    MaxFrameCount, ep_no, stream_id, pre_scale);
2051d96047eSMarkus Pfeiffer 
2061d96047eSMarkus Pfeiffer 	if (error) {
2071d96047eSMarkus Pfeiffer 		free(xfer->ppBuffer);
2081d96047eSMarkus Pfeiffer 		free(xfer->pLength);
2091d96047eSMarkus Pfeiffer 	} else {
2101d96047eSMarkus Pfeiffer 		xfer->is_opened = 1;
2111d96047eSMarkus Pfeiffer 	}
2121d96047eSMarkus Pfeiffer 	return (error);
2131d96047eSMarkus Pfeiffer }
2141d96047eSMarkus Pfeiffer 
2151d96047eSMarkus Pfeiffer struct libusb20_transfer *
libusb20_tr_get_pointer(struct libusb20_device * pdev,uint16_t trIndex)2161d96047eSMarkus Pfeiffer libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex)
2171d96047eSMarkus Pfeiffer {
2181d96047eSMarkus Pfeiffer 	if (trIndex >= pdev->nTransfer) {
2191d96047eSMarkus Pfeiffer 		return (NULL);
2201d96047eSMarkus Pfeiffer 	}
2211d96047eSMarkus Pfeiffer 	return (pdev->pTransfer + trIndex);
2221d96047eSMarkus Pfeiffer }
2231d96047eSMarkus Pfeiffer 
2241d96047eSMarkus Pfeiffer uint32_t
libusb20_tr_get_actual_frames(struct libusb20_transfer * xfer)2251d96047eSMarkus Pfeiffer libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer)
2261d96047eSMarkus Pfeiffer {
2271d96047eSMarkus Pfeiffer 	return (xfer->aFrames);
2281d96047eSMarkus Pfeiffer }
2291d96047eSMarkus Pfeiffer 
2301d96047eSMarkus Pfeiffer uint16_t
libusb20_tr_get_time_complete(struct libusb20_transfer * xfer)2311d96047eSMarkus Pfeiffer libusb20_tr_get_time_complete(struct libusb20_transfer *xfer)
2321d96047eSMarkus Pfeiffer {
2331d96047eSMarkus Pfeiffer 	return (xfer->timeComplete);
2341d96047eSMarkus Pfeiffer }
2351d96047eSMarkus Pfeiffer 
2361d96047eSMarkus Pfeiffer uint32_t
libusb20_tr_get_actual_length(struct libusb20_transfer * xfer)2371d96047eSMarkus Pfeiffer libusb20_tr_get_actual_length(struct libusb20_transfer *xfer)
2381d96047eSMarkus Pfeiffer {
2391d96047eSMarkus Pfeiffer 	uint32_t x;
2401d96047eSMarkus Pfeiffer 	uint32_t actlen = 0;
2411d96047eSMarkus Pfeiffer 
2421d96047eSMarkus Pfeiffer 	for (x = 0; x != xfer->aFrames; x++) {
2431d96047eSMarkus Pfeiffer 		actlen += xfer->pLength[x];
2441d96047eSMarkus Pfeiffer 	}
2451d96047eSMarkus Pfeiffer 	return (actlen);
2461d96047eSMarkus Pfeiffer }
2471d96047eSMarkus Pfeiffer 
2481d96047eSMarkus Pfeiffer uint32_t
libusb20_tr_get_max_frames(struct libusb20_transfer * xfer)2491d96047eSMarkus Pfeiffer libusb20_tr_get_max_frames(struct libusb20_transfer *xfer)
2501d96047eSMarkus Pfeiffer {
2511d96047eSMarkus Pfeiffer 	return (xfer->maxFrames);
2521d96047eSMarkus Pfeiffer }
2531d96047eSMarkus Pfeiffer 
2541d96047eSMarkus Pfeiffer uint32_t
libusb20_tr_get_max_packet_length(struct libusb20_transfer * xfer)2551d96047eSMarkus Pfeiffer libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer)
2561d96047eSMarkus Pfeiffer {
2571d96047eSMarkus Pfeiffer 	/*
2581d96047eSMarkus Pfeiffer 	 * Special Case NOTE: If the packet multiplier is non-zero for
2591d96047eSMarkus Pfeiffer 	 * High Speed USB, the value returned is equal to
2601d96047eSMarkus Pfeiffer 	 * "wMaxPacketSize * multiplier" !
2611d96047eSMarkus Pfeiffer 	 */
2621d96047eSMarkus Pfeiffer 	return (xfer->maxPacketLen);
2631d96047eSMarkus Pfeiffer }
2641d96047eSMarkus Pfeiffer 
2651d96047eSMarkus Pfeiffer uint32_t
libusb20_tr_get_max_total_length(struct libusb20_transfer * xfer)2661d96047eSMarkus Pfeiffer libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer)
2671d96047eSMarkus Pfeiffer {
2681d96047eSMarkus Pfeiffer 	return (xfer->maxTotalLength);
2691d96047eSMarkus Pfeiffer }
2701d96047eSMarkus Pfeiffer 
2711d96047eSMarkus Pfeiffer uint8_t
libusb20_tr_get_status(struct libusb20_transfer * xfer)2721d96047eSMarkus Pfeiffer libusb20_tr_get_status(struct libusb20_transfer *xfer)
2731d96047eSMarkus Pfeiffer {
2741d96047eSMarkus Pfeiffer 	return (xfer->status);
2751d96047eSMarkus Pfeiffer }
2761d96047eSMarkus Pfeiffer 
2771d96047eSMarkus Pfeiffer uint8_t
libusb20_tr_pending(struct libusb20_transfer * xfer)2781d96047eSMarkus Pfeiffer libusb20_tr_pending(struct libusb20_transfer *xfer)
2791d96047eSMarkus Pfeiffer {
2801d96047eSMarkus Pfeiffer 	return (xfer->is_pending);
2811d96047eSMarkus Pfeiffer }
2821d96047eSMarkus Pfeiffer 
2831d96047eSMarkus Pfeiffer void   *
libusb20_tr_get_priv_sc0(struct libusb20_transfer * xfer)2841d96047eSMarkus Pfeiffer libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer)
2851d96047eSMarkus Pfeiffer {
2861d96047eSMarkus Pfeiffer 	return (xfer->priv_sc0);
2871d96047eSMarkus Pfeiffer }
2881d96047eSMarkus Pfeiffer 
2891d96047eSMarkus Pfeiffer void   *
libusb20_tr_get_priv_sc1(struct libusb20_transfer * xfer)2901d96047eSMarkus Pfeiffer libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer)
2911d96047eSMarkus Pfeiffer {
2921d96047eSMarkus Pfeiffer 	return (xfer->priv_sc1);
2931d96047eSMarkus Pfeiffer }
2941d96047eSMarkus Pfeiffer 
2951d96047eSMarkus Pfeiffer void
libusb20_tr_stop(struct libusb20_transfer * xfer)2961d96047eSMarkus Pfeiffer libusb20_tr_stop(struct libusb20_transfer *xfer)
2971d96047eSMarkus Pfeiffer {
2981d96047eSMarkus Pfeiffer 	if (!xfer->is_opened) {
2991d96047eSMarkus Pfeiffer 		/* transfer is not opened */
3001d96047eSMarkus Pfeiffer 		return;
3011d96047eSMarkus Pfeiffer 	}
3021d96047eSMarkus Pfeiffer 	if (!xfer->is_pending) {
3031d96047eSMarkus Pfeiffer 		/* transfer not pending */
3041d96047eSMarkus Pfeiffer 		return;
3051d96047eSMarkus Pfeiffer 	}
3061d96047eSMarkus Pfeiffer 	if (xfer->is_cancel) {
3071d96047eSMarkus Pfeiffer 		/* already cancelling */
3081d96047eSMarkus Pfeiffer 		return;
3091d96047eSMarkus Pfeiffer 	}
3101d96047eSMarkus Pfeiffer 	xfer->is_cancel = 1;		/* we are cancelling */
3111d96047eSMarkus Pfeiffer 
3121d96047eSMarkus Pfeiffer 	xfer->pdev->methods->tr_cancel_async(xfer);
3131d96047eSMarkus Pfeiffer 	return;
3141d96047eSMarkus Pfeiffer }
3151d96047eSMarkus Pfeiffer 
3161d96047eSMarkus Pfeiffer void
libusb20_tr_drain(struct libusb20_transfer * xfer)3171d96047eSMarkus Pfeiffer libusb20_tr_drain(struct libusb20_transfer *xfer)
3181d96047eSMarkus Pfeiffer {
3191d96047eSMarkus Pfeiffer 	if (!xfer->is_opened) {
3201d96047eSMarkus Pfeiffer 		/* transfer is not opened */
3211d96047eSMarkus Pfeiffer 		return;
3221d96047eSMarkus Pfeiffer 	}
3231d96047eSMarkus Pfeiffer 	/* make sure that we are cancelling */
3241d96047eSMarkus Pfeiffer 	libusb20_tr_stop(xfer);
3251d96047eSMarkus Pfeiffer 
3261d96047eSMarkus Pfeiffer 	if (xfer->is_pending) {
3271d96047eSMarkus Pfeiffer 		xfer->is_draining = 1;
3281d96047eSMarkus Pfeiffer 	}
3291d96047eSMarkus Pfeiffer 	return;
3301d96047eSMarkus Pfeiffer }
3311d96047eSMarkus Pfeiffer 
3321d96047eSMarkus Pfeiffer void
libusb20_tr_clear_stall_sync(struct libusb20_transfer * xfer)3331d96047eSMarkus Pfeiffer libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
3341d96047eSMarkus Pfeiffer {
3351d96047eSMarkus Pfeiffer 	xfer->pdev->methods->tr_clear_stall_sync(xfer);
3361d96047eSMarkus Pfeiffer 	return;
3371d96047eSMarkus Pfeiffer }
3381d96047eSMarkus Pfeiffer 
3391d96047eSMarkus Pfeiffer void
libusb20_tr_set_buffer(struct libusb20_transfer * xfer,void * buffer,uint16_t frIndex)3401d96047eSMarkus Pfeiffer libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex)
3411d96047eSMarkus Pfeiffer {
3421d96047eSMarkus Pfeiffer 	xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer);
3431d96047eSMarkus Pfeiffer 	return;
3441d96047eSMarkus Pfeiffer }
3451d96047eSMarkus Pfeiffer 
3461d96047eSMarkus Pfeiffer void
libusb20_tr_set_callback(struct libusb20_transfer * xfer,libusb20_tr_callback_t * cb)3471d96047eSMarkus Pfeiffer libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb)
3481d96047eSMarkus Pfeiffer {
3491d96047eSMarkus Pfeiffer 	xfer->callback = cb;
3501d96047eSMarkus Pfeiffer 	return;
3511d96047eSMarkus Pfeiffer }
3521d96047eSMarkus Pfeiffer 
3531d96047eSMarkus Pfeiffer void
libusb20_tr_set_flags(struct libusb20_transfer * xfer,uint8_t flags)3541d96047eSMarkus Pfeiffer libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags)
3551d96047eSMarkus Pfeiffer {
3561d96047eSMarkus Pfeiffer 	xfer->flags = flags;
3571d96047eSMarkus Pfeiffer 	return;
3581d96047eSMarkus Pfeiffer }
3591d96047eSMarkus Pfeiffer 
3601d96047eSMarkus Pfeiffer uint32_t
libusb20_tr_get_length(struct libusb20_transfer * xfer,uint16_t frIndex)3611d96047eSMarkus Pfeiffer libusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex)
3621d96047eSMarkus Pfeiffer {
3631d96047eSMarkus Pfeiffer 	return (xfer->pLength[frIndex]);
3641d96047eSMarkus Pfeiffer }
3651d96047eSMarkus Pfeiffer 
3661d96047eSMarkus Pfeiffer void
libusb20_tr_set_length(struct libusb20_transfer * xfer,uint32_t length,uint16_t frIndex)3671d96047eSMarkus Pfeiffer libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
3681d96047eSMarkus Pfeiffer {
3691d96047eSMarkus Pfeiffer 	xfer->pLength[frIndex] = length;
3701d96047eSMarkus Pfeiffer 	return;
3711d96047eSMarkus Pfeiffer }
3721d96047eSMarkus Pfeiffer 
3731d96047eSMarkus Pfeiffer void
libusb20_tr_set_priv_sc0(struct libusb20_transfer * xfer,void * sc0)3741d96047eSMarkus Pfeiffer libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
3751d96047eSMarkus Pfeiffer {
3761d96047eSMarkus Pfeiffer 	xfer->priv_sc0 = sc0;
3771d96047eSMarkus Pfeiffer 	return;
3781d96047eSMarkus Pfeiffer }
3791d96047eSMarkus Pfeiffer 
3801d96047eSMarkus Pfeiffer void
libusb20_tr_set_priv_sc1(struct libusb20_transfer * xfer,void * sc1)3811d96047eSMarkus Pfeiffer libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
3821d96047eSMarkus Pfeiffer {
3831d96047eSMarkus Pfeiffer 	xfer->priv_sc1 = sc1;
3841d96047eSMarkus Pfeiffer 	return;
3851d96047eSMarkus Pfeiffer }
3861d96047eSMarkus Pfeiffer 
3871d96047eSMarkus Pfeiffer void
libusb20_tr_set_timeout(struct libusb20_transfer * xfer,uint32_t timeout)3881d96047eSMarkus Pfeiffer libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
3891d96047eSMarkus Pfeiffer {
3901d96047eSMarkus Pfeiffer 	xfer->timeout = timeout;
3911d96047eSMarkus Pfeiffer 	return;
3921d96047eSMarkus Pfeiffer }
3931d96047eSMarkus Pfeiffer 
3941d96047eSMarkus Pfeiffer void
libusb20_tr_set_total_frames(struct libusb20_transfer * xfer,uint32_t nFrames)3951d96047eSMarkus Pfeiffer libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
3961d96047eSMarkus Pfeiffer {
3971d96047eSMarkus Pfeiffer 	if (nFrames > xfer->maxFrames) {
3981d96047eSMarkus Pfeiffer 		/* should not happen */
3991d96047eSMarkus Pfeiffer 		nFrames = xfer->maxFrames;
4001d96047eSMarkus Pfeiffer 	}
4011d96047eSMarkus Pfeiffer 	xfer->nFrames = nFrames;
4021d96047eSMarkus Pfeiffer 	return;
4031d96047eSMarkus Pfeiffer }
4041d96047eSMarkus Pfeiffer 
4051d96047eSMarkus Pfeiffer void
libusb20_tr_setup_bulk(struct libusb20_transfer * xfer,void * pBuf,uint32_t length,uint32_t timeout)4061d96047eSMarkus Pfeiffer libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
4071d96047eSMarkus Pfeiffer {
4081d96047eSMarkus Pfeiffer 	xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
4091d96047eSMarkus Pfeiffer 	xfer->pLength[0] = length;
4101d96047eSMarkus Pfeiffer 	xfer->timeout = timeout;
4111d96047eSMarkus Pfeiffer 	xfer->nFrames = 1;
4121d96047eSMarkus Pfeiffer 	return;
4131d96047eSMarkus Pfeiffer }
4141d96047eSMarkus Pfeiffer 
4151d96047eSMarkus Pfeiffer void
libusb20_tr_setup_control(struct libusb20_transfer * xfer,void * psetup,void * pBuf,uint32_t timeout)4161d96047eSMarkus Pfeiffer libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
4171d96047eSMarkus Pfeiffer {
4181d96047eSMarkus Pfeiffer 	uint16_t len;
4191d96047eSMarkus Pfeiffer 
4201d96047eSMarkus Pfeiffer 	xfer->ppBuffer[0] = libusb20_pass_ptr(psetup);
4211d96047eSMarkus Pfeiffer 	xfer->pLength[0] = 8;		/* fixed */
4221d96047eSMarkus Pfeiffer 	xfer->timeout = timeout;
4231d96047eSMarkus Pfeiffer 
4241d96047eSMarkus Pfeiffer 	len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
4251d96047eSMarkus Pfeiffer 
4261d96047eSMarkus Pfeiffer 	if (len != 0) {
4271d96047eSMarkus Pfeiffer 		xfer->nFrames = 2;
4281d96047eSMarkus Pfeiffer 		xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf);
4291d96047eSMarkus Pfeiffer 		xfer->pLength[1] = len;
4301d96047eSMarkus Pfeiffer 	} else {
4311d96047eSMarkus Pfeiffer 		xfer->nFrames = 1;
4321d96047eSMarkus Pfeiffer 	}
4331d96047eSMarkus Pfeiffer 	return;
4341d96047eSMarkus Pfeiffer }
4351d96047eSMarkus Pfeiffer 
4361d96047eSMarkus Pfeiffer void
libusb20_tr_setup_intr(struct libusb20_transfer * xfer,void * pBuf,uint32_t length,uint32_t timeout)4371d96047eSMarkus Pfeiffer libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
4381d96047eSMarkus Pfeiffer {
4391d96047eSMarkus Pfeiffer 	xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
4401d96047eSMarkus Pfeiffer 	xfer->pLength[0] = length;
4411d96047eSMarkus Pfeiffer 	xfer->timeout = timeout;
4421d96047eSMarkus Pfeiffer 	xfer->nFrames = 1;
4431d96047eSMarkus Pfeiffer 	return;
4441d96047eSMarkus Pfeiffer }
4451d96047eSMarkus Pfeiffer 
4461d96047eSMarkus Pfeiffer void
libusb20_tr_setup_isoc(struct libusb20_transfer * xfer,void * pBuf,uint32_t length,uint16_t frIndex)4471d96047eSMarkus Pfeiffer libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
4481d96047eSMarkus Pfeiffer {
4491d96047eSMarkus Pfeiffer 	if (frIndex >= xfer->maxFrames) {
4501d96047eSMarkus Pfeiffer 		/* should not happen */
4511d96047eSMarkus Pfeiffer 		return;
4521d96047eSMarkus Pfeiffer 	}
4531d96047eSMarkus Pfeiffer 	xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf);
4541d96047eSMarkus Pfeiffer 	xfer->pLength[frIndex] = length;
4551d96047eSMarkus Pfeiffer 	return;
4561d96047eSMarkus Pfeiffer }
4571d96047eSMarkus Pfeiffer 
4581d96047eSMarkus Pfeiffer uint8_t
libusb20_tr_bulk_intr_sync(struct libusb20_transfer * xfer,void * pbuf,uint32_t length,uint32_t * pactlen,uint32_t timeout)4591d96047eSMarkus Pfeiffer libusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer,
4601d96047eSMarkus Pfeiffer     void *pbuf, uint32_t length, uint32_t *pactlen,
4611d96047eSMarkus Pfeiffer     uint32_t timeout)
4621d96047eSMarkus Pfeiffer {
4631d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev = xfer->pdev;
4641d96047eSMarkus Pfeiffer 	uint32_t transfer_max;
4651d96047eSMarkus Pfeiffer 	uint32_t transfer_act;
4661d96047eSMarkus Pfeiffer 	uint8_t retval;
4671d96047eSMarkus Pfeiffer 
4681d96047eSMarkus Pfeiffer 	/* set some sensible default value */
4691d96047eSMarkus Pfeiffer 	if (pactlen != NULL)
4701d96047eSMarkus Pfeiffer 		*pactlen = 0;
4711d96047eSMarkus Pfeiffer 
4721d96047eSMarkus Pfeiffer 	/* check for error condition */
4731d96047eSMarkus Pfeiffer 	if (libusb20_tr_pending(xfer))
4741d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_OTHER);
4751d96047eSMarkus Pfeiffer 
4761d96047eSMarkus Pfeiffer 	do {
4771d96047eSMarkus Pfeiffer 		/* compute maximum transfer length */
4781d96047eSMarkus Pfeiffer 		transfer_max =
4791d96047eSMarkus Pfeiffer 		    libusb20_tr_get_max_total_length(xfer);
4801d96047eSMarkus Pfeiffer 
4811d96047eSMarkus Pfeiffer 		if (transfer_max > length)
4821d96047eSMarkus Pfeiffer 			transfer_max = length;
4831d96047eSMarkus Pfeiffer 
4841d96047eSMarkus Pfeiffer 		/* setup bulk or interrupt transfer */
4851d96047eSMarkus Pfeiffer 		libusb20_tr_setup_bulk(xfer, pbuf,
4861d96047eSMarkus Pfeiffer 		    transfer_max, timeout);
4871d96047eSMarkus Pfeiffer 
4881d96047eSMarkus Pfeiffer 		/* start the transfer */
4891d96047eSMarkus Pfeiffer 		libusb20_tr_start(xfer);
4901d96047eSMarkus Pfeiffer 
4911d96047eSMarkus Pfeiffer 		/* wait for transfer completion */
4921d96047eSMarkus Pfeiffer 		while (libusb20_dev_process(pdev) == 0) {
4931d96047eSMarkus Pfeiffer 
4941d96047eSMarkus Pfeiffer 			if (libusb20_tr_pending(xfer) == 0)
4951d96047eSMarkus Pfeiffer 				break;
4961d96047eSMarkus Pfeiffer 
4971d96047eSMarkus Pfeiffer 			libusb20_dev_wait_process(pdev, -1);
4981d96047eSMarkus Pfeiffer 		}
4991d96047eSMarkus Pfeiffer 
5001d96047eSMarkus Pfeiffer 		transfer_act = libusb20_tr_get_actual_length(xfer);
5011d96047eSMarkus Pfeiffer 
5021d96047eSMarkus Pfeiffer 		/* update actual length, if any */
5031d96047eSMarkus Pfeiffer 		if (pactlen != NULL)
5041d96047eSMarkus Pfeiffer 			pactlen[0] += transfer_act;
5051d96047eSMarkus Pfeiffer 
5061d96047eSMarkus Pfeiffer 		/* check transfer status */
5071d96047eSMarkus Pfeiffer 		retval = libusb20_tr_get_status(xfer);
5081d96047eSMarkus Pfeiffer 		if (retval)
5091d96047eSMarkus Pfeiffer 			break;
5101d96047eSMarkus Pfeiffer 
5111d96047eSMarkus Pfeiffer 		/* check for short transfer */
5121d96047eSMarkus Pfeiffer 		if (transfer_act != transfer_max)
5131d96047eSMarkus Pfeiffer 			break;
5141d96047eSMarkus Pfeiffer 
5151d96047eSMarkus Pfeiffer 		/* update buffer pointer and length */
5161d96047eSMarkus Pfeiffer 		pbuf = ((uint8_t *)pbuf) + transfer_max;
5171d96047eSMarkus Pfeiffer 		length = length - transfer_max;
5181d96047eSMarkus Pfeiffer 
5191d96047eSMarkus Pfeiffer 	} while (length != 0);
5201d96047eSMarkus Pfeiffer 
5211d96047eSMarkus Pfeiffer 	return (retval);
5221d96047eSMarkus Pfeiffer }
5231d96047eSMarkus Pfeiffer 
5241d96047eSMarkus Pfeiffer void
libusb20_tr_submit(struct libusb20_transfer * xfer)5251d96047eSMarkus Pfeiffer libusb20_tr_submit(struct libusb20_transfer *xfer)
5261d96047eSMarkus Pfeiffer {
5271d96047eSMarkus Pfeiffer 	if (!xfer->is_opened) {
5281d96047eSMarkus Pfeiffer 		/* transfer is not opened */
5291d96047eSMarkus Pfeiffer 		return;
5301d96047eSMarkus Pfeiffer 	}
5311d96047eSMarkus Pfeiffer 	if (xfer->is_pending) {
5321d96047eSMarkus Pfeiffer 		/* should not happen */
5331d96047eSMarkus Pfeiffer 		return;
5341d96047eSMarkus Pfeiffer 	}
5351d96047eSMarkus Pfeiffer 	xfer->is_pending = 1;		/* we are pending */
5361d96047eSMarkus Pfeiffer 	xfer->is_cancel = 0;		/* not cancelling */
5371d96047eSMarkus Pfeiffer 	xfer->is_restart = 0;		/* not restarting */
5381d96047eSMarkus Pfeiffer 
5391d96047eSMarkus Pfeiffer 	xfer->pdev->methods->tr_submit(xfer);
5401d96047eSMarkus Pfeiffer 	return;
5411d96047eSMarkus Pfeiffer }
5421d96047eSMarkus Pfeiffer 
5431d96047eSMarkus Pfeiffer void
libusb20_tr_start(struct libusb20_transfer * xfer)5441d96047eSMarkus Pfeiffer libusb20_tr_start(struct libusb20_transfer *xfer)
5451d96047eSMarkus Pfeiffer {
5461d96047eSMarkus Pfeiffer 	if (!xfer->is_opened) {
5471d96047eSMarkus Pfeiffer 		/* transfer is not opened */
5481d96047eSMarkus Pfeiffer 		return;
5491d96047eSMarkus Pfeiffer 	}
5501d96047eSMarkus Pfeiffer 	if (xfer->is_pending) {
5511d96047eSMarkus Pfeiffer 		if (xfer->is_cancel) {
5521d96047eSMarkus Pfeiffer 			/* cancelling - restart */
5531d96047eSMarkus Pfeiffer 			xfer->is_restart = 1;
5541d96047eSMarkus Pfeiffer 		}
5551d96047eSMarkus Pfeiffer 		/* transfer not pending */
5561d96047eSMarkus Pfeiffer 		return;
5571d96047eSMarkus Pfeiffer 	}
5581d96047eSMarkus Pfeiffer 	/* get into the callback */
5591d96047eSMarkus Pfeiffer 	libusb20_tr_callback_wrapper(xfer);
5601d96047eSMarkus Pfeiffer 	return;
5611d96047eSMarkus Pfeiffer }
5621d96047eSMarkus Pfeiffer 
5631d96047eSMarkus Pfeiffer /* USB device operations */
5641d96047eSMarkus Pfeiffer 
5651d96047eSMarkus Pfeiffer int
libusb20_dev_close(struct libusb20_device * pdev)5661d96047eSMarkus Pfeiffer libusb20_dev_close(struct libusb20_device *pdev)
5671d96047eSMarkus Pfeiffer {
5681d96047eSMarkus Pfeiffer 	struct libusb20_transfer *xfer;
5691d96047eSMarkus Pfeiffer 	uint16_t x;
5701d96047eSMarkus Pfeiffer 	int error = 0;
5711d96047eSMarkus Pfeiffer 
5721d96047eSMarkus Pfeiffer 	if (!pdev->is_opened) {
5731d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_OTHER);
5741d96047eSMarkus Pfeiffer 	}
5751d96047eSMarkus Pfeiffer 	for (x = 0; x != pdev->nTransfer; x++) {
5761d96047eSMarkus Pfeiffer 		xfer = pdev->pTransfer + x;
5771d96047eSMarkus Pfeiffer 
5781d96047eSMarkus Pfeiffer 		if (!xfer->is_opened) {
5791d96047eSMarkus Pfeiffer 			/* transfer is not opened */
5801d96047eSMarkus Pfeiffer 			continue;
5811d96047eSMarkus Pfeiffer 		}
5821d96047eSMarkus Pfeiffer 
5831d96047eSMarkus Pfeiffer 		libusb20_tr_drain(xfer);
5841d96047eSMarkus Pfeiffer 
5851d96047eSMarkus Pfeiffer 		libusb20_tr_close(xfer);
5861d96047eSMarkus Pfeiffer 	}
5871d96047eSMarkus Pfeiffer 
5881d96047eSMarkus Pfeiffer 	if (pdev->pTransfer != NULL) {
5891d96047eSMarkus Pfeiffer 		free(pdev->pTransfer);
5901d96047eSMarkus Pfeiffer 		pdev->pTransfer = NULL;
5911d96047eSMarkus Pfeiffer 	}
5921d96047eSMarkus Pfeiffer 	error = pdev->beMethods->close_device(pdev);
5931d96047eSMarkus Pfeiffer 
5941d96047eSMarkus Pfeiffer 	pdev->methods = &libusb20_dummy_methods;
5951d96047eSMarkus Pfeiffer 
5961d96047eSMarkus Pfeiffer 	pdev->is_opened = 0;
5971d96047eSMarkus Pfeiffer 
5981d96047eSMarkus Pfeiffer 	/*
5991d96047eSMarkus Pfeiffer 	 * The following variable is only used by the libusb v0.1
6001d96047eSMarkus Pfeiffer 	 * compat layer:
6011d96047eSMarkus Pfeiffer 	 */
6021d96047eSMarkus Pfeiffer 	pdev->claimed_interface = 0;
6031d96047eSMarkus Pfeiffer 
6041d96047eSMarkus Pfeiffer 	return (error);
6051d96047eSMarkus Pfeiffer }
6061d96047eSMarkus Pfeiffer 
6071d96047eSMarkus Pfeiffer int
libusb20_dev_detach_kernel_driver(struct libusb20_device * pdev,uint8_t ifaceIndex)6081d96047eSMarkus Pfeiffer libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
6091d96047eSMarkus Pfeiffer {
6101d96047eSMarkus Pfeiffer 	int error;
6111d96047eSMarkus Pfeiffer 
6121d96047eSMarkus Pfeiffer 	error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
6131d96047eSMarkus Pfeiffer 	return (error);
6141d96047eSMarkus Pfeiffer }
6151d96047eSMarkus Pfeiffer 
6161d96047eSMarkus Pfeiffer struct LIBUSB20_DEVICE_DESC_DECODED *
libusb20_dev_get_device_desc(struct libusb20_device * pdev)6171d96047eSMarkus Pfeiffer libusb20_dev_get_device_desc(struct libusb20_device *pdev)
6181d96047eSMarkus Pfeiffer {
6191d96047eSMarkus Pfeiffer 	return (&(pdev->ddesc));
6201d96047eSMarkus Pfeiffer }
6211d96047eSMarkus Pfeiffer 
6221d96047eSMarkus Pfeiffer int
libusb20_dev_get_fd(struct libusb20_device * pdev)6231d96047eSMarkus Pfeiffer libusb20_dev_get_fd(struct libusb20_device *pdev)
6241d96047eSMarkus Pfeiffer {
6251d96047eSMarkus Pfeiffer 	return (pdev->file);
6261d96047eSMarkus Pfeiffer }
6271d96047eSMarkus Pfeiffer 
6281d96047eSMarkus Pfeiffer int
libusb20_dev_kernel_driver_active(struct libusb20_device * pdev,uint8_t ifaceIndex)6291d96047eSMarkus Pfeiffer libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
6301d96047eSMarkus Pfeiffer {
6311d96047eSMarkus Pfeiffer 	int error;
6321d96047eSMarkus Pfeiffer 
6331d96047eSMarkus Pfeiffer 	error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
6341d96047eSMarkus Pfeiffer 	return (error);
6351d96047eSMarkus Pfeiffer }
6361d96047eSMarkus Pfeiffer 
6371d96047eSMarkus Pfeiffer int
libusb20_dev_open(struct libusb20_device * pdev,uint16_t nTransferMax)6381d96047eSMarkus Pfeiffer libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
6391d96047eSMarkus Pfeiffer {
6401d96047eSMarkus Pfeiffer 	struct libusb20_transfer *xfer;
6411d96047eSMarkus Pfeiffer 	uint32_t size;
6421d96047eSMarkus Pfeiffer 	uint16_t x;
6431d96047eSMarkus Pfeiffer 	int error;
6441d96047eSMarkus Pfeiffer 
6451d96047eSMarkus Pfeiffer 	if (pdev->is_opened) {
6461d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_BUSY);
6471d96047eSMarkus Pfeiffer 	}
6481d96047eSMarkus Pfeiffer 	if (nTransferMax >= 256) {
6491d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_INVALID_PARAM);
6501d96047eSMarkus Pfeiffer 	} else if (nTransferMax != 0) {
6511d96047eSMarkus Pfeiffer 		size = sizeof(pdev->pTransfer[0]) * nTransferMax;
6521d96047eSMarkus Pfeiffer 		pdev->pTransfer = malloc(size);
6531d96047eSMarkus Pfeiffer 		if (pdev->pTransfer == NULL) {
6541d96047eSMarkus Pfeiffer 			return (LIBUSB20_ERROR_NO_MEM);
6551d96047eSMarkus Pfeiffer 		}
6561d96047eSMarkus Pfeiffer 		memset(pdev->pTransfer, 0, size);
6571d96047eSMarkus Pfeiffer 	}
6581d96047eSMarkus Pfeiffer 	/* initialise all transfers */
6591d96047eSMarkus Pfeiffer 	for (x = 0; x != nTransferMax; x++) {
6601d96047eSMarkus Pfeiffer 
6611d96047eSMarkus Pfeiffer 		xfer = pdev->pTransfer + x;
6621d96047eSMarkus Pfeiffer 
6631d96047eSMarkus Pfeiffer 		xfer->pdev = pdev;
6641d96047eSMarkus Pfeiffer 		xfer->trIndex = x;
6651d96047eSMarkus Pfeiffer 		xfer->callback = &dummy_callback;
6661d96047eSMarkus Pfeiffer 	}
6671d96047eSMarkus Pfeiffer 
6681d96047eSMarkus Pfeiffer 	/* set "nTransfer" early */
6691d96047eSMarkus Pfeiffer 	pdev->nTransfer = nTransferMax;
6701d96047eSMarkus Pfeiffer 
6711d96047eSMarkus Pfeiffer 	error = pdev->beMethods->open_device(pdev, nTransferMax);
6721d96047eSMarkus Pfeiffer 
6731d96047eSMarkus Pfeiffer 	if (error) {
6741d96047eSMarkus Pfeiffer 		if (pdev->pTransfer != NULL) {
6751d96047eSMarkus Pfeiffer 			free(pdev->pTransfer);
6761d96047eSMarkus Pfeiffer 			pdev->pTransfer = NULL;
6771d96047eSMarkus Pfeiffer 		}
6781d96047eSMarkus Pfeiffer 		pdev->file = -1;
6791d96047eSMarkus Pfeiffer 		pdev->file_ctrl = -1;
6801d96047eSMarkus Pfeiffer 		pdev->nTransfer = 0;
6811d96047eSMarkus Pfeiffer 	} else {
6821d96047eSMarkus Pfeiffer 		pdev->is_opened = 1;
6831d96047eSMarkus Pfeiffer 	}
6841d96047eSMarkus Pfeiffer 	return (error);
6851d96047eSMarkus Pfeiffer }
6861d96047eSMarkus Pfeiffer 
6871d96047eSMarkus Pfeiffer int
libusb20_dev_reset(struct libusb20_device * pdev)6881d96047eSMarkus Pfeiffer libusb20_dev_reset(struct libusb20_device *pdev)
6891d96047eSMarkus Pfeiffer {
6901d96047eSMarkus Pfeiffer 	int error;
6911d96047eSMarkus Pfeiffer 
6921d96047eSMarkus Pfeiffer 	error = pdev->methods->reset_device(pdev);
6931d96047eSMarkus Pfeiffer 	return (error);
6941d96047eSMarkus Pfeiffer }
6951d96047eSMarkus Pfeiffer 
6961d96047eSMarkus Pfeiffer int
libusb20_dev_check_connected(struct libusb20_device * pdev)6971d96047eSMarkus Pfeiffer libusb20_dev_check_connected(struct libusb20_device *pdev)
6981d96047eSMarkus Pfeiffer {
6991d96047eSMarkus Pfeiffer 	int error;
7001d96047eSMarkus Pfeiffer 
7011d96047eSMarkus Pfeiffer 	error = pdev->methods->check_connected(pdev);
7021d96047eSMarkus Pfeiffer 	return (error);
7031d96047eSMarkus Pfeiffer }
7041d96047eSMarkus Pfeiffer 
7051d96047eSMarkus Pfeiffer int
libusb20_dev_set_power_mode(struct libusb20_device * pdev,uint8_t power_mode)7061d96047eSMarkus Pfeiffer libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
7071d96047eSMarkus Pfeiffer {
7081d96047eSMarkus Pfeiffer 	int error;
7091d96047eSMarkus Pfeiffer 
7101d96047eSMarkus Pfeiffer 	error = pdev->methods->set_power_mode(pdev, power_mode);
7111d96047eSMarkus Pfeiffer 	return (error);
7121d96047eSMarkus Pfeiffer }
7131d96047eSMarkus Pfeiffer 
7141d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_power_mode(struct libusb20_device * pdev)7151d96047eSMarkus Pfeiffer libusb20_dev_get_power_mode(struct libusb20_device *pdev)
7161d96047eSMarkus Pfeiffer {
7171d96047eSMarkus Pfeiffer 	int error;
7181d96047eSMarkus Pfeiffer 	uint8_t power_mode;
7191d96047eSMarkus Pfeiffer 
7201d96047eSMarkus Pfeiffer 	error = pdev->methods->get_power_mode(pdev, &power_mode);
7211d96047eSMarkus Pfeiffer 	if (error)
7221d96047eSMarkus Pfeiffer 		power_mode = LIBUSB20_POWER_ON;	/* fake power mode */
7231d96047eSMarkus Pfeiffer 	return (power_mode);
7241d96047eSMarkus Pfeiffer }
7251d96047eSMarkus Pfeiffer 
7261d96047eSMarkus Pfeiffer int
libusb20_dev_get_port_path(struct libusb20_device * pdev,uint8_t * buf,uint8_t bufsize)727*9b0c1abeSSascha Wildner libusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
728*9b0c1abeSSascha Wildner {
729*9b0c1abeSSascha Wildner 	return (pdev->methods->get_port_path(pdev, buf, bufsize));
730*9b0c1abeSSascha Wildner }
731*9b0c1abeSSascha Wildner 
732*9b0c1abeSSascha Wildner uint16_t
libusb20_dev_get_power_usage(struct libusb20_device * pdev)733*9b0c1abeSSascha Wildner libusb20_dev_get_power_usage(struct libusb20_device *pdev)
734*9b0c1abeSSascha Wildner {
735*9b0c1abeSSascha Wildner 	int error;
736*9b0c1abeSSascha Wildner 	uint16_t power_usage;
737*9b0c1abeSSascha Wildner 
738*9b0c1abeSSascha Wildner 	error = pdev->methods->get_power_usage(pdev, &power_usage);
739*9b0c1abeSSascha Wildner 	if (error)
740*9b0c1abeSSascha Wildner 		power_usage = 0;
741*9b0c1abeSSascha Wildner 	return (power_usage);
742*9b0c1abeSSascha Wildner }
743*9b0c1abeSSascha Wildner 
744*9b0c1abeSSascha Wildner int
libusb20_dev_set_alt_index(struct libusb20_device * pdev,uint8_t ifaceIndex,uint8_t altIndex)7451d96047eSMarkus Pfeiffer libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
7461d96047eSMarkus Pfeiffer {
7471d96047eSMarkus Pfeiffer 	int error;
7481d96047eSMarkus Pfeiffer 
7491d96047eSMarkus Pfeiffer 	error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
7501d96047eSMarkus Pfeiffer 	return (error);
7511d96047eSMarkus Pfeiffer }
7521d96047eSMarkus Pfeiffer 
7531d96047eSMarkus Pfeiffer int
libusb20_dev_set_config_index(struct libusb20_device * pdev,uint8_t configIndex)7541d96047eSMarkus Pfeiffer libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
7551d96047eSMarkus Pfeiffer {
7561d96047eSMarkus Pfeiffer 	int error;
7571d96047eSMarkus Pfeiffer 
7581d96047eSMarkus Pfeiffer 	error = pdev->methods->set_config_index(pdev, configIndex);
7591d96047eSMarkus Pfeiffer 	return (error);
7601d96047eSMarkus Pfeiffer }
7611d96047eSMarkus Pfeiffer 
7621d96047eSMarkus Pfeiffer int
libusb20_dev_request_sync(struct libusb20_device * pdev,struct LIBUSB20_CONTROL_SETUP_DECODED * setup,void * data,uint16_t * pactlen,uint32_t timeout,uint8_t flags)7631d96047eSMarkus Pfeiffer libusb20_dev_request_sync(struct libusb20_device *pdev,
7641d96047eSMarkus Pfeiffer     struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
7651d96047eSMarkus Pfeiffer     uint16_t *pactlen, uint32_t timeout, uint8_t flags)
7661d96047eSMarkus Pfeiffer {
7671d96047eSMarkus Pfeiffer 	int error;
7681d96047eSMarkus Pfeiffer 
7691d96047eSMarkus Pfeiffer 	error = pdev->methods->do_request_sync(pdev,
7701d96047eSMarkus Pfeiffer 	    setup, data, pactlen, timeout, flags);
7711d96047eSMarkus Pfeiffer 	return (error);
7721d96047eSMarkus Pfeiffer }
7731d96047eSMarkus Pfeiffer 
7741d96047eSMarkus Pfeiffer int
libusb20_dev_req_string_sync(struct libusb20_device * pdev,uint8_t str_index,uint16_t langid,void * ptr,uint16_t len)7751d96047eSMarkus Pfeiffer libusb20_dev_req_string_sync(struct libusb20_device *pdev,
7761d96047eSMarkus Pfeiffer     uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
7771d96047eSMarkus Pfeiffer {
7781d96047eSMarkus Pfeiffer 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
7791d96047eSMarkus Pfeiffer 	int error;
7801d96047eSMarkus Pfeiffer 
7811d96047eSMarkus Pfeiffer 	/* make sure memory is initialised */
7821d96047eSMarkus Pfeiffer 	memset(ptr, 0, len);
7831d96047eSMarkus Pfeiffer 
7841d96047eSMarkus Pfeiffer 	if (len < 4) {
7851d96047eSMarkus Pfeiffer 		/* invalid length */
7861d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_INVALID_PARAM);
7871d96047eSMarkus Pfeiffer 	}
7881d96047eSMarkus Pfeiffer 	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
7891d96047eSMarkus Pfeiffer 
7901d96047eSMarkus Pfeiffer 	/*
7911d96047eSMarkus Pfeiffer 	 * We need to read the USB string in two steps else some USB
7921d96047eSMarkus Pfeiffer 	 * devices will complain.
7931d96047eSMarkus Pfeiffer 	 */
7941d96047eSMarkus Pfeiffer 	req.bmRequestType =
7951d96047eSMarkus Pfeiffer 	    LIBUSB20_REQUEST_TYPE_STANDARD |
7961d96047eSMarkus Pfeiffer 	    LIBUSB20_RECIPIENT_DEVICE |
7971d96047eSMarkus Pfeiffer 	    LIBUSB20_ENDPOINT_IN;
7981d96047eSMarkus Pfeiffer 	req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
7991d96047eSMarkus Pfeiffer 	req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
8001d96047eSMarkus Pfeiffer 	req.wIndex = langid;
8011d96047eSMarkus Pfeiffer 	req.wLength = 4;		/* bytes */
8021d96047eSMarkus Pfeiffer 
8031d96047eSMarkus Pfeiffer 	error = libusb20_dev_request_sync(pdev, &req,
8041d96047eSMarkus Pfeiffer 	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
8051d96047eSMarkus Pfeiffer 	if (error) {
8061d96047eSMarkus Pfeiffer 		return (error);
8071d96047eSMarkus Pfeiffer 	}
8081d96047eSMarkus Pfeiffer 	req.wLength = *(uint8_t *)ptr;	/* bytes */
8091d96047eSMarkus Pfeiffer 	if (req.wLength > len) {
8101d96047eSMarkus Pfeiffer 		/* partial string read */
8111d96047eSMarkus Pfeiffer 		req.wLength = len;
8121d96047eSMarkus Pfeiffer 	}
8131d96047eSMarkus Pfeiffer 	error = libusb20_dev_request_sync(pdev, &req,
8141d96047eSMarkus Pfeiffer 	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
8151d96047eSMarkus Pfeiffer 
8161d96047eSMarkus Pfeiffer 	if (error) {
8171d96047eSMarkus Pfeiffer 		return (error);
8181d96047eSMarkus Pfeiffer 	}
8191d96047eSMarkus Pfeiffer 	if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
8201d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_OTHER);
8211d96047eSMarkus Pfeiffer 	}
8221d96047eSMarkus Pfeiffer 	return (0);			/* success */
8231d96047eSMarkus Pfeiffer }
8241d96047eSMarkus Pfeiffer 
8251d96047eSMarkus Pfeiffer int
libusb20_dev_req_string_simple_sync(struct libusb20_device * pdev,uint8_t str_index,void * ptr,uint16_t len)8261d96047eSMarkus Pfeiffer libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
8271d96047eSMarkus Pfeiffer     uint8_t str_index, void *ptr, uint16_t len)
8281d96047eSMarkus Pfeiffer {
8291d96047eSMarkus Pfeiffer 	char *buf;
8301d96047eSMarkus Pfeiffer 	int error;
8311d96047eSMarkus Pfeiffer 	uint16_t langid;
8321d96047eSMarkus Pfeiffer 	uint16_t n;
8331d96047eSMarkus Pfeiffer 	uint16_t i;
8341d96047eSMarkus Pfeiffer 	uint16_t c;
8351d96047eSMarkus Pfeiffer 	uint8_t temp[255];
8361d96047eSMarkus Pfeiffer 	uint8_t swap;
8371d96047eSMarkus Pfeiffer 
8381d96047eSMarkus Pfeiffer 	/* the following code derives from the FreeBSD USB kernel */
8391d96047eSMarkus Pfeiffer 
8401d96047eSMarkus Pfeiffer 	if ((len < 1) || (ptr == NULL)) {
8411d96047eSMarkus Pfeiffer 		/* too short buffer */
8421d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_INVALID_PARAM);
8431d96047eSMarkus Pfeiffer 	}
8441d96047eSMarkus Pfeiffer 	error = libusb20_dev_req_string_sync(pdev,
8451d96047eSMarkus Pfeiffer 	    0, 0, temp, sizeof(temp));
8461d96047eSMarkus Pfeiffer 	if (error < 0) {
8471d96047eSMarkus Pfeiffer 		*(uint8_t *)ptr = 0;	/* zero terminate */
8481d96047eSMarkus Pfeiffer 		return (error);
8491d96047eSMarkus Pfeiffer 	}
8501d96047eSMarkus Pfeiffer 	langid = temp[2] | (temp[3] << 8);
8511d96047eSMarkus Pfeiffer 
8521d96047eSMarkus Pfeiffer 	error = libusb20_dev_req_string_sync(pdev, str_index,
8531d96047eSMarkus Pfeiffer 	    langid, temp, sizeof(temp));
8541d96047eSMarkus Pfeiffer 	if (error < 0) {
8551d96047eSMarkus Pfeiffer 		*(uint8_t *)ptr = 0;	/* zero terminate */
8561d96047eSMarkus Pfeiffer 		return (error);
8571d96047eSMarkus Pfeiffer 	}
8581d96047eSMarkus Pfeiffer 	if (temp[0] < 2) {
8591d96047eSMarkus Pfeiffer 		/* string length is too short */
8601d96047eSMarkus Pfeiffer 		*(uint8_t *)ptr = 0;	/* zero terminate */
8611d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_OTHER);
8621d96047eSMarkus Pfeiffer 	}
8631d96047eSMarkus Pfeiffer 	/* reserve one byte for terminating zero */
8641d96047eSMarkus Pfeiffer 	len--;
8651d96047eSMarkus Pfeiffer 
8661d96047eSMarkus Pfeiffer 	/* find maximum length */
8671d96047eSMarkus Pfeiffer 	n = (temp[0] / 2) - 1;
8681d96047eSMarkus Pfeiffer 	if (n > len) {
8691d96047eSMarkus Pfeiffer 		n = len;
8701d96047eSMarkus Pfeiffer 	}
8711d96047eSMarkus Pfeiffer 	/* reset swap state */
8721d96047eSMarkus Pfeiffer 	swap = 3;
8731d96047eSMarkus Pfeiffer 
8741d96047eSMarkus Pfeiffer 	/* setup output buffer pointer */
8751d96047eSMarkus Pfeiffer 	buf = ptr;
8761d96047eSMarkus Pfeiffer 
8771d96047eSMarkus Pfeiffer 	/* convert and filter */
8781d96047eSMarkus Pfeiffer 	for (i = 0; (i != n); i++) {
8791d96047eSMarkus Pfeiffer 		c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
8801d96047eSMarkus Pfeiffer 
8811d96047eSMarkus Pfeiffer 		/* convert from Unicode, handle buggy strings */
8821d96047eSMarkus Pfeiffer 		if (((c & 0xff00) == 0) && (swap & 1)) {
8831d96047eSMarkus Pfeiffer 			/* Little Endian, default */
8841d96047eSMarkus Pfeiffer 			*buf = c;
8851d96047eSMarkus Pfeiffer 			swap = 1;
8861d96047eSMarkus Pfeiffer 		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
8871d96047eSMarkus Pfeiffer 			/* Big Endian */
8881d96047eSMarkus Pfeiffer 			*buf = c >> 8;
8891d96047eSMarkus Pfeiffer 			swap = 2;
8901d96047eSMarkus Pfeiffer 		} else {
8911d96047eSMarkus Pfeiffer 			/* skip invalid character */
8921d96047eSMarkus Pfeiffer 			continue;
8931d96047eSMarkus Pfeiffer 		}
8941d96047eSMarkus Pfeiffer 		/*
8951d96047eSMarkus Pfeiffer 		 * Filter by default - we don't allow greater and less than
8961d96047eSMarkus Pfeiffer 		 * signs because they might confuse the dmesg printouts!
8971d96047eSMarkus Pfeiffer 		 */
8981d96047eSMarkus Pfeiffer 		if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
8991d96047eSMarkus Pfeiffer 			/* skip invalid character */
9001d96047eSMarkus Pfeiffer 			continue;
9011d96047eSMarkus Pfeiffer 		}
9021d96047eSMarkus Pfeiffer 		buf++;
9031d96047eSMarkus Pfeiffer 	}
9041d96047eSMarkus Pfeiffer 	*buf = 0;			/* zero terminate string */
9051d96047eSMarkus Pfeiffer 
9061d96047eSMarkus Pfeiffer 	return (0);
9071d96047eSMarkus Pfeiffer }
9081d96047eSMarkus Pfeiffer 
9091d96047eSMarkus Pfeiffer struct libusb20_config *
libusb20_dev_alloc_config(struct libusb20_device * pdev,uint8_t configIndex)9101d96047eSMarkus Pfeiffer libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
9111d96047eSMarkus Pfeiffer {
9121d96047eSMarkus Pfeiffer 	struct libusb20_config *retval = NULL;
9131d96047eSMarkus Pfeiffer 	uint8_t *ptr;
9141d96047eSMarkus Pfeiffer 	uint16_t len;
9151d96047eSMarkus Pfeiffer 	uint8_t do_close;
9161d96047eSMarkus Pfeiffer 	int error;
9171d96047eSMarkus Pfeiffer 
9181d96047eSMarkus Pfeiffer 	if (!pdev->is_opened) {
9191d96047eSMarkus Pfeiffer 		error = libusb20_dev_open(pdev, 0);
9201d96047eSMarkus Pfeiffer 		if (error) {
9211d96047eSMarkus Pfeiffer 			return (NULL);
9221d96047eSMarkus Pfeiffer 		}
9231d96047eSMarkus Pfeiffer 		do_close = 1;
9241d96047eSMarkus Pfeiffer 	} else {
9251d96047eSMarkus Pfeiffer 		do_close = 0;
9261d96047eSMarkus Pfeiffer 	}
9271d96047eSMarkus Pfeiffer 	error = pdev->methods->get_config_desc_full(pdev,
9281d96047eSMarkus Pfeiffer 	    &ptr, &len, configIndex);
9291d96047eSMarkus Pfeiffer 
9301d96047eSMarkus Pfeiffer 	if (error) {
9311d96047eSMarkus Pfeiffer 		goto done;
9321d96047eSMarkus Pfeiffer 	}
9331d96047eSMarkus Pfeiffer 	/* parse new config descriptor */
9341d96047eSMarkus Pfeiffer 	retval = libusb20_parse_config_desc(ptr);
9351d96047eSMarkus Pfeiffer 
9361d96047eSMarkus Pfeiffer 	/* free config descriptor */
9371d96047eSMarkus Pfeiffer 	free(ptr);
9381d96047eSMarkus Pfeiffer 
9391d96047eSMarkus Pfeiffer done:
9401d96047eSMarkus Pfeiffer 	if (do_close) {
9411d96047eSMarkus Pfeiffer 		error = libusb20_dev_close(pdev);
9421d96047eSMarkus Pfeiffer 	}
9431d96047eSMarkus Pfeiffer 	return (retval);
9441d96047eSMarkus Pfeiffer }
9451d96047eSMarkus Pfeiffer 
9461d96047eSMarkus Pfeiffer struct libusb20_device *
libusb20_dev_alloc(void)9471d96047eSMarkus Pfeiffer libusb20_dev_alloc(void)
9481d96047eSMarkus Pfeiffer {
9491d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
9501d96047eSMarkus Pfeiffer 
9511d96047eSMarkus Pfeiffer 	pdev = malloc(sizeof(*pdev));
9521d96047eSMarkus Pfeiffer 	if (pdev == NULL) {
9531d96047eSMarkus Pfeiffer 		return (NULL);
9541d96047eSMarkus Pfeiffer 	}
9551d96047eSMarkus Pfeiffer 	memset(pdev, 0, sizeof(*pdev));
9561d96047eSMarkus Pfeiffer 
9571d96047eSMarkus Pfeiffer 	pdev->file = -1;
9581d96047eSMarkus Pfeiffer 	pdev->file_ctrl = -1;
9591d96047eSMarkus Pfeiffer 	pdev->methods = &libusb20_dummy_methods;
9601d96047eSMarkus Pfeiffer 	return (pdev);
9611d96047eSMarkus Pfeiffer }
9621d96047eSMarkus Pfeiffer 
9631d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_config_index(struct libusb20_device * pdev)9641d96047eSMarkus Pfeiffer libusb20_dev_get_config_index(struct libusb20_device *pdev)
9651d96047eSMarkus Pfeiffer {
9661d96047eSMarkus Pfeiffer 	int error;
9671d96047eSMarkus Pfeiffer 	uint8_t cfg_index;
9681d96047eSMarkus Pfeiffer 	uint8_t do_close;
9691d96047eSMarkus Pfeiffer 
9701d96047eSMarkus Pfeiffer 	if (!pdev->is_opened) {
9711d96047eSMarkus Pfeiffer 		error = libusb20_dev_open(pdev, 0);
9721d96047eSMarkus Pfeiffer 		if (error == 0) {
9731d96047eSMarkus Pfeiffer 			do_close = 1;
9741d96047eSMarkus Pfeiffer 		} else {
9751d96047eSMarkus Pfeiffer 			do_close = 0;
9761d96047eSMarkus Pfeiffer 		}
9771d96047eSMarkus Pfeiffer 	} else {
9781d96047eSMarkus Pfeiffer 		do_close = 0;
9791d96047eSMarkus Pfeiffer 	}
9801d96047eSMarkus Pfeiffer 
9811d96047eSMarkus Pfeiffer 	error = pdev->methods->get_config_index(pdev, &cfg_index);
982aa3e5c14SSascha Wildner 	if (error)
983aa3e5c14SSascha Wildner 		cfg_index = 0xFF;	/* current config index */
9841d96047eSMarkus Pfeiffer 	if (do_close) {
9851d96047eSMarkus Pfeiffer 		if (libusb20_dev_close(pdev)) {
9861d96047eSMarkus Pfeiffer 			/* ignore */
9871d96047eSMarkus Pfeiffer 		}
9881d96047eSMarkus Pfeiffer 	}
9891d96047eSMarkus Pfeiffer 	return (cfg_index);
9901d96047eSMarkus Pfeiffer }
9911d96047eSMarkus Pfeiffer 
9921d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_mode(struct libusb20_device * pdev)9931d96047eSMarkus Pfeiffer libusb20_dev_get_mode(struct libusb20_device *pdev)
9941d96047eSMarkus Pfeiffer {
9951d96047eSMarkus Pfeiffer 	return (pdev->usb_mode);
9961d96047eSMarkus Pfeiffer }
9971d96047eSMarkus Pfeiffer 
9981d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_speed(struct libusb20_device * pdev)9991d96047eSMarkus Pfeiffer libusb20_dev_get_speed(struct libusb20_device *pdev)
10001d96047eSMarkus Pfeiffer {
10011d96047eSMarkus Pfeiffer 	return (pdev->usb_speed);
10021d96047eSMarkus Pfeiffer }
10031d96047eSMarkus Pfeiffer 
10041d96047eSMarkus Pfeiffer /* if this function returns an error, the device is gone */
10051d96047eSMarkus Pfeiffer int
libusb20_dev_process(struct libusb20_device * pdev)10061d96047eSMarkus Pfeiffer libusb20_dev_process(struct libusb20_device *pdev)
10071d96047eSMarkus Pfeiffer {
10081d96047eSMarkus Pfeiffer 	int error;
10091d96047eSMarkus Pfeiffer 
10101d96047eSMarkus Pfeiffer 	error = pdev->methods->process(pdev);
10111d96047eSMarkus Pfeiffer 	return (error);
10121d96047eSMarkus Pfeiffer }
10131d96047eSMarkus Pfeiffer 
10141d96047eSMarkus Pfeiffer void
libusb20_dev_wait_process(struct libusb20_device * pdev,int timeout)10151d96047eSMarkus Pfeiffer libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
10161d96047eSMarkus Pfeiffer {
10171d96047eSMarkus Pfeiffer 	struct pollfd pfd[1];
10181d96047eSMarkus Pfeiffer 
10191d96047eSMarkus Pfeiffer 	if (!pdev->is_opened) {
10201d96047eSMarkus Pfeiffer 		return;
10211d96047eSMarkus Pfeiffer 	}
10221d96047eSMarkus Pfeiffer 	pfd[0].fd = pdev->file;
10231d96047eSMarkus Pfeiffer 	pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
10241d96047eSMarkus Pfeiffer 	pfd[0].revents = 0;
10251d96047eSMarkus Pfeiffer 
10261d96047eSMarkus Pfeiffer 	if (poll(pfd, 1, timeout)) {
10271d96047eSMarkus Pfeiffer 		/* ignore any error */
10281d96047eSMarkus Pfeiffer 	}
10291d96047eSMarkus Pfeiffer 	return;
10301d96047eSMarkus Pfeiffer }
10311d96047eSMarkus Pfeiffer 
10321d96047eSMarkus Pfeiffer void
libusb20_dev_free(struct libusb20_device * pdev)10331d96047eSMarkus Pfeiffer libusb20_dev_free(struct libusb20_device *pdev)
10341d96047eSMarkus Pfeiffer {
10351d96047eSMarkus Pfeiffer 	if (pdev == NULL) {
10361d96047eSMarkus Pfeiffer 		/* be NULL safe */
10371d96047eSMarkus Pfeiffer 		return;
10381d96047eSMarkus Pfeiffer 	}
10391d96047eSMarkus Pfeiffer 	if (pdev->is_opened) {
10401d96047eSMarkus Pfeiffer 		if (libusb20_dev_close(pdev)) {
10411d96047eSMarkus Pfeiffer 			/* ignore any errors */
10421d96047eSMarkus Pfeiffer 		}
10431d96047eSMarkus Pfeiffer 	}
10441d96047eSMarkus Pfeiffer 	free(pdev);
10451d96047eSMarkus Pfeiffer 	return;
10461d96047eSMarkus Pfeiffer }
10471d96047eSMarkus Pfeiffer 
10481d96047eSMarkus Pfeiffer int
libusb20_dev_get_info(struct libusb20_device * pdev,struct usb_device_info * pinfo)10491d96047eSMarkus Pfeiffer libusb20_dev_get_info(struct libusb20_device *pdev,
10501d96047eSMarkus Pfeiffer     struct usb_device_info *pinfo)
10511d96047eSMarkus Pfeiffer {
10521d96047eSMarkus Pfeiffer 	if (pinfo == NULL)
10531d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_INVALID_PARAM);
10541d96047eSMarkus Pfeiffer 
10551d96047eSMarkus Pfeiffer 	return (pdev->beMethods->dev_get_info(pdev, pinfo));
10561d96047eSMarkus Pfeiffer }
10571d96047eSMarkus Pfeiffer 
10581d96047eSMarkus Pfeiffer const char *
libusb20_dev_get_backend_name(struct libusb20_device * pdev)10591d96047eSMarkus Pfeiffer libusb20_dev_get_backend_name(struct libusb20_device *pdev)
10601d96047eSMarkus Pfeiffer {
10611d96047eSMarkus Pfeiffer 	return (pdev->beMethods->get_backend_name());
10621d96047eSMarkus Pfeiffer }
10631d96047eSMarkus Pfeiffer 
10641d96047eSMarkus Pfeiffer const char *
libusb20_dev_get_desc(struct libusb20_device * pdev)10651d96047eSMarkus Pfeiffer libusb20_dev_get_desc(struct libusb20_device *pdev)
10661d96047eSMarkus Pfeiffer {
10671d96047eSMarkus Pfeiffer 	return (pdev->usb_desc);
10681d96047eSMarkus Pfeiffer }
10691d96047eSMarkus Pfeiffer 
10701d96047eSMarkus Pfeiffer void
libusb20_dev_set_debug(struct libusb20_device * pdev,int debug)10711d96047eSMarkus Pfeiffer libusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
10721d96047eSMarkus Pfeiffer {
10731d96047eSMarkus Pfeiffer 	pdev->debug = debug;
10741d96047eSMarkus Pfeiffer 	return;
10751d96047eSMarkus Pfeiffer }
10761d96047eSMarkus Pfeiffer 
10771d96047eSMarkus Pfeiffer int
libusb20_dev_get_debug(struct libusb20_device * pdev)10781d96047eSMarkus Pfeiffer libusb20_dev_get_debug(struct libusb20_device *pdev)
10791d96047eSMarkus Pfeiffer {
10801d96047eSMarkus Pfeiffer 	return (pdev->debug);
10811d96047eSMarkus Pfeiffer }
10821d96047eSMarkus Pfeiffer 
10831d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_address(struct libusb20_device * pdev)10841d96047eSMarkus Pfeiffer libusb20_dev_get_address(struct libusb20_device *pdev)
10851d96047eSMarkus Pfeiffer {
10861d96047eSMarkus Pfeiffer 	return (pdev->device_address);
10871d96047eSMarkus Pfeiffer }
10881d96047eSMarkus Pfeiffer 
10891d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_parent_address(struct libusb20_device * pdev)10901d96047eSMarkus Pfeiffer libusb20_dev_get_parent_address(struct libusb20_device *pdev)
10911d96047eSMarkus Pfeiffer {
10921d96047eSMarkus Pfeiffer 	return (pdev->parent_address);
10931d96047eSMarkus Pfeiffer }
10941d96047eSMarkus Pfeiffer 
10951d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_parent_port(struct libusb20_device * pdev)10961d96047eSMarkus Pfeiffer libusb20_dev_get_parent_port(struct libusb20_device *pdev)
10971d96047eSMarkus Pfeiffer {
10981d96047eSMarkus Pfeiffer 	return (pdev->parent_port);
10991d96047eSMarkus Pfeiffer }
11001d96047eSMarkus Pfeiffer 
11011d96047eSMarkus Pfeiffer uint8_t
libusb20_dev_get_bus_number(struct libusb20_device * pdev)11021d96047eSMarkus Pfeiffer libusb20_dev_get_bus_number(struct libusb20_device *pdev)
11031d96047eSMarkus Pfeiffer {
11041d96047eSMarkus Pfeiffer 	return (pdev->bus_number);
11051d96047eSMarkus Pfeiffer }
11061d96047eSMarkus Pfeiffer 
11071d96047eSMarkus Pfeiffer int
libusb20_dev_get_iface_desc(struct libusb20_device * pdev,uint8_t iface_index,char * buf,uint8_t len)11081d96047eSMarkus Pfeiffer libusb20_dev_get_iface_desc(struct libusb20_device *pdev,
11091d96047eSMarkus Pfeiffer     uint8_t iface_index, char *buf, uint8_t len)
11101d96047eSMarkus Pfeiffer {
11111d96047eSMarkus Pfeiffer 	if ((buf == NULL) || (len == 0))
11121d96047eSMarkus Pfeiffer 		return (LIBUSB20_ERROR_INVALID_PARAM);
11131d96047eSMarkus Pfeiffer 
11141d96047eSMarkus Pfeiffer 	buf[0] = 0;		/* set default string value */
11151d96047eSMarkus Pfeiffer 
11161d96047eSMarkus Pfeiffer 	return (pdev->beMethods->dev_get_iface_desc(
11171d96047eSMarkus Pfeiffer 	    pdev, iface_index, buf, len));
11181d96047eSMarkus Pfeiffer }
11191d96047eSMarkus Pfeiffer 
11201d96047eSMarkus Pfeiffer /* USB backend operations */
11211d96047eSMarkus Pfeiffer 
11221d96047eSMarkus Pfeiffer int
libusb20_be_get_dev_quirk(struct libusb20_backend * pbe,uint16_t quirk_index,struct libusb20_quirk * pq)11231d96047eSMarkus Pfeiffer libusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
11241d96047eSMarkus Pfeiffer     uint16_t quirk_index, struct libusb20_quirk *pq)
11251d96047eSMarkus Pfeiffer {
11261d96047eSMarkus Pfeiffer 	return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
11271d96047eSMarkus Pfeiffer }
11281d96047eSMarkus Pfeiffer 
11291d96047eSMarkus Pfeiffer int
libusb20_be_get_quirk_name(struct libusb20_backend * pbe,uint16_t quirk_index,struct libusb20_quirk * pq)11301d96047eSMarkus Pfeiffer libusb20_be_get_quirk_name(struct libusb20_backend *pbe,
11311d96047eSMarkus Pfeiffer     uint16_t quirk_index, struct libusb20_quirk *pq)
11321d96047eSMarkus Pfeiffer {
11331d96047eSMarkus Pfeiffer 	return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
11341d96047eSMarkus Pfeiffer }
11351d96047eSMarkus Pfeiffer 
11361d96047eSMarkus Pfeiffer int
libusb20_be_add_dev_quirk(struct libusb20_backend * pbe,struct libusb20_quirk * pq)11371d96047eSMarkus Pfeiffer libusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
11381d96047eSMarkus Pfeiffer     struct libusb20_quirk *pq)
11391d96047eSMarkus Pfeiffer {
11401d96047eSMarkus Pfeiffer 	return (pbe->methods->root_add_dev_quirk(pbe, pq));
11411d96047eSMarkus Pfeiffer }
11421d96047eSMarkus Pfeiffer 
11431d96047eSMarkus Pfeiffer int
libusb20_be_remove_dev_quirk(struct libusb20_backend * pbe,struct libusb20_quirk * pq)11441d96047eSMarkus Pfeiffer libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
11451d96047eSMarkus Pfeiffer     struct libusb20_quirk *pq)
11461d96047eSMarkus Pfeiffer {
11471d96047eSMarkus Pfeiffer 	return (pbe->methods->root_remove_dev_quirk(pbe, pq));
11481d96047eSMarkus Pfeiffer }
11491d96047eSMarkus Pfeiffer 
11501d96047eSMarkus Pfeiffer int
libusb20_be_set_template(struct libusb20_backend * pbe,int temp)11511d96047eSMarkus Pfeiffer libusb20_be_set_template(struct libusb20_backend *pbe, int temp)
11521d96047eSMarkus Pfeiffer {
11531d96047eSMarkus Pfeiffer 	return (pbe->methods->root_set_template(pbe, temp));
11541d96047eSMarkus Pfeiffer }
11551d96047eSMarkus Pfeiffer 
11561d96047eSMarkus Pfeiffer int
libusb20_be_get_template(struct libusb20_backend * pbe,int * ptemp)11571d96047eSMarkus Pfeiffer libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
11581d96047eSMarkus Pfeiffer {
11591d96047eSMarkus Pfeiffer 	int temp;
11601d96047eSMarkus Pfeiffer 
11611d96047eSMarkus Pfeiffer 	if (ptemp == NULL)
11621d96047eSMarkus Pfeiffer 		ptemp = &temp;
11631d96047eSMarkus Pfeiffer 
11641d96047eSMarkus Pfeiffer 	return (pbe->methods->root_get_template(pbe, ptemp));
11651d96047eSMarkus Pfeiffer }
11661d96047eSMarkus Pfeiffer 
11671d96047eSMarkus Pfeiffer struct libusb20_device *
libusb20_be_device_foreach(struct libusb20_backend * pbe,struct libusb20_device * pdev)11681d96047eSMarkus Pfeiffer libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
11691d96047eSMarkus Pfeiffer {
11701d96047eSMarkus Pfeiffer 	if (pbe == NULL) {
11711d96047eSMarkus Pfeiffer 		pdev = NULL;
11721d96047eSMarkus Pfeiffer 	} else if (pdev == NULL) {
11731d96047eSMarkus Pfeiffer 		pdev = TAILQ_FIRST(&(pbe->usb_devs));
11741d96047eSMarkus Pfeiffer 	} else {
11751d96047eSMarkus Pfeiffer 		pdev = TAILQ_NEXT(pdev, dev_entry);
11761d96047eSMarkus Pfeiffer 	}
11771d96047eSMarkus Pfeiffer 	return (pdev);
11781d96047eSMarkus Pfeiffer }
11791d96047eSMarkus Pfeiffer 
11801d96047eSMarkus Pfeiffer struct libusb20_backend *
libusb20_be_alloc(const struct libusb20_backend_methods * methods)11811d96047eSMarkus Pfeiffer libusb20_be_alloc(const struct libusb20_backend_methods *methods)
11821d96047eSMarkus Pfeiffer {
11831d96047eSMarkus Pfeiffer 	struct libusb20_backend *pbe;
11841d96047eSMarkus Pfeiffer 
11851d96047eSMarkus Pfeiffer 	pbe = malloc(sizeof(*pbe));
11861d96047eSMarkus Pfeiffer 	if (pbe == NULL) {
11871d96047eSMarkus Pfeiffer 		return (NULL);
11881d96047eSMarkus Pfeiffer 	}
11891d96047eSMarkus Pfeiffer 	memset(pbe, 0, sizeof(*pbe));
11901d96047eSMarkus Pfeiffer 
11911d96047eSMarkus Pfeiffer 	TAILQ_INIT(&(pbe->usb_devs));
11921d96047eSMarkus Pfeiffer 
11931d96047eSMarkus Pfeiffer 	pbe->methods = methods;		/* set backend methods */
11941d96047eSMarkus Pfeiffer 
11951d96047eSMarkus Pfeiffer 	/* do the initial device scan */
11961d96047eSMarkus Pfeiffer 	if (pbe->methods->init_backend) {
11971d96047eSMarkus Pfeiffer 		pbe->methods->init_backend(pbe);
11981d96047eSMarkus Pfeiffer 	}
11991d96047eSMarkus Pfeiffer 	return (pbe);
12001d96047eSMarkus Pfeiffer }
12011d96047eSMarkus Pfeiffer 
12021d96047eSMarkus Pfeiffer struct libusb20_backend *
libusb20_be_alloc_linux(void)12031d96047eSMarkus Pfeiffer libusb20_be_alloc_linux(void)
12041d96047eSMarkus Pfeiffer {
1205*9b0c1abeSSascha Wildner 	return (NULL);
12061d96047eSMarkus Pfeiffer }
12071d96047eSMarkus Pfeiffer 
12081d96047eSMarkus Pfeiffer struct libusb20_backend *
libusb20_be_alloc_ugen20(void)12091d96047eSMarkus Pfeiffer libusb20_be_alloc_ugen20(void)
12101d96047eSMarkus Pfeiffer {
1211*9b0c1abeSSascha Wildner 	return (libusb20_be_alloc(&libusb20_ugen20_backend));
12121d96047eSMarkus Pfeiffer }
12131d96047eSMarkus Pfeiffer 
12141d96047eSMarkus Pfeiffer struct libusb20_backend *
libusb20_be_alloc_default(void)12151d96047eSMarkus Pfeiffer libusb20_be_alloc_default(void)
12161d96047eSMarkus Pfeiffer {
12171d96047eSMarkus Pfeiffer 	struct libusb20_backend *pbe;
12181d96047eSMarkus Pfeiffer 
1219*9b0c1abeSSascha Wildner #ifdef __linux__
12201d96047eSMarkus Pfeiffer 	pbe = libusb20_be_alloc_linux();
12211d96047eSMarkus Pfeiffer 	if (pbe) {
12221d96047eSMarkus Pfeiffer 		return (pbe);
12231d96047eSMarkus Pfeiffer 	}
1224*9b0c1abeSSascha Wildner #endif
12251d96047eSMarkus Pfeiffer 	pbe = libusb20_be_alloc_ugen20();
12261d96047eSMarkus Pfeiffer 	if (pbe) {
12271d96047eSMarkus Pfeiffer 		return (pbe);
12281d96047eSMarkus Pfeiffer 	}
12291d96047eSMarkus Pfeiffer 	return (NULL);			/* no backend found */
12301d96047eSMarkus Pfeiffer }
12311d96047eSMarkus Pfeiffer 
12321d96047eSMarkus Pfeiffer void
libusb20_be_free(struct libusb20_backend * pbe)12331d96047eSMarkus Pfeiffer libusb20_be_free(struct libusb20_backend *pbe)
12341d96047eSMarkus Pfeiffer {
12351d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
12361d96047eSMarkus Pfeiffer 
12371d96047eSMarkus Pfeiffer 	if (pbe == NULL) {
12381d96047eSMarkus Pfeiffer 		/* be NULL safe */
12391d96047eSMarkus Pfeiffer 		return;
12401d96047eSMarkus Pfeiffer 	}
12411d96047eSMarkus Pfeiffer 	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
12421d96047eSMarkus Pfeiffer 		libusb20_be_dequeue_device(pbe, pdev);
12431d96047eSMarkus Pfeiffer 		libusb20_dev_free(pdev);
12441d96047eSMarkus Pfeiffer 	}
12451d96047eSMarkus Pfeiffer 	if (pbe->methods->exit_backend) {
12461d96047eSMarkus Pfeiffer 		pbe->methods->exit_backend(pbe);
12471d96047eSMarkus Pfeiffer 	}
12481d96047eSMarkus Pfeiffer 	/* free backend */
12491d96047eSMarkus Pfeiffer 	free(pbe);
12501d96047eSMarkus Pfeiffer }
12511d96047eSMarkus Pfeiffer 
12521d96047eSMarkus Pfeiffer void
libusb20_be_enqueue_device(struct libusb20_backend * pbe,struct libusb20_device * pdev)12531d96047eSMarkus Pfeiffer libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
12541d96047eSMarkus Pfeiffer {
12551d96047eSMarkus Pfeiffer 	pdev->beMethods = pbe->methods;	/* copy backend methods */
12561d96047eSMarkus Pfeiffer 	TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
12571d96047eSMarkus Pfeiffer }
12581d96047eSMarkus Pfeiffer 
12591d96047eSMarkus Pfeiffer void
libusb20_be_dequeue_device(struct libusb20_backend * pbe,struct libusb20_device * pdev)12601d96047eSMarkus Pfeiffer libusb20_be_dequeue_device(struct libusb20_backend *pbe,
12611d96047eSMarkus Pfeiffer     struct libusb20_device *pdev)
12621d96047eSMarkus Pfeiffer {
12631d96047eSMarkus Pfeiffer 	TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
12641d96047eSMarkus Pfeiffer }
12651d96047eSMarkus Pfeiffer 
12661d96047eSMarkus Pfeiffer const char *
libusb20_strerror(int code)12671d96047eSMarkus Pfeiffer libusb20_strerror(int code)
12681d96047eSMarkus Pfeiffer {
12691d96047eSMarkus Pfeiffer 	switch (code) {
12701d96047eSMarkus Pfeiffer 	case LIBUSB20_SUCCESS:
12711d96047eSMarkus Pfeiffer 		return ("Success");
12721d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_IO:
12731d96047eSMarkus Pfeiffer 		return ("I/O error");
12741d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_INVALID_PARAM:
12751d96047eSMarkus Pfeiffer 		return ("Invalid parameter");
12761d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_ACCESS:
12771d96047eSMarkus Pfeiffer 		return ("Permissions error");
12781d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NO_DEVICE:
12791d96047eSMarkus Pfeiffer 		return ("No device");
12801d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NOT_FOUND:
12811d96047eSMarkus Pfeiffer 		return ("Not found");
12821d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_BUSY:
12831d96047eSMarkus Pfeiffer 		return ("Device busy");
12841d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_TIMEOUT:
12851d96047eSMarkus Pfeiffer 		return ("Timeout");
12861d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_OVERFLOW:
12871d96047eSMarkus Pfeiffer 		return ("Overflow");
12881d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_PIPE:
12891d96047eSMarkus Pfeiffer 		return ("Pipe error");
12901d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_INTERRUPTED:
12911d96047eSMarkus Pfeiffer 		return ("Interrupted");
12921d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NO_MEM:
12931d96047eSMarkus Pfeiffer 		return ("Out of memory");
12941d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NOT_SUPPORTED:
12951d96047eSMarkus Pfeiffer 		return ("Not supported");
12961d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_OTHER:
12971d96047eSMarkus Pfeiffer 		return ("Other error");
12981d96047eSMarkus Pfeiffer 	default:
12991d96047eSMarkus Pfeiffer 		return ("Unknown error");
13001d96047eSMarkus Pfeiffer 	}
13011d96047eSMarkus Pfeiffer }
13021d96047eSMarkus Pfeiffer 
13031d96047eSMarkus Pfeiffer const char *
libusb20_error_name(int code)13041d96047eSMarkus Pfeiffer libusb20_error_name(int code)
13051d96047eSMarkus Pfeiffer {
13061d96047eSMarkus Pfeiffer 	switch (code) {
13071d96047eSMarkus Pfeiffer 	case LIBUSB20_SUCCESS:
13081d96047eSMarkus Pfeiffer 		return ("LIBUSB20_SUCCESS");
13091d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_IO:
13101d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_IO");
13111d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_INVALID_PARAM:
13121d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_INVALID_PARAM");
13131d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_ACCESS:
13141d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_ACCESS");
13151d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NO_DEVICE:
13161d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_NO_DEVICE");
13171d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NOT_FOUND:
13181d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_NOT_FOUND");
13191d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_BUSY:
13201d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_BUSY");
13211d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_TIMEOUT:
13221d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_TIMEOUT");
13231d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_OVERFLOW:
13241d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_OVERFLOW");
13251d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_PIPE:
13261d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_PIPE");
13271d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_INTERRUPTED:
13281d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_INTERRUPTED");
13291d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NO_MEM:
13301d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_NO_MEM");
13311d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_NOT_SUPPORTED:
13321d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_NOT_SUPPORTED");
13331d96047eSMarkus Pfeiffer 	case LIBUSB20_ERROR_OTHER:
13341d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_OTHER");
13351d96047eSMarkus Pfeiffer 	default:
13361d96047eSMarkus Pfeiffer 		return ("LIBUSB20_ERROR_UNKNOWN");
13371d96047eSMarkus Pfeiffer 	}
13381d96047eSMarkus Pfeiffer }
1339