xref: /dragonfly/lib/libusb/libusb10.c (revision c4031fc1)
1c5739aa6SSascha Wildner /* $FreeBSD: head/lib/libusb/libusb10.c 264344 2014-04-11 14:11:55Z hselasky $ */
21d96047eSMarkus Pfeiffer /*-
31d96047eSMarkus Pfeiffer  * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
41d96047eSMarkus Pfeiffer  * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
51d96047eSMarkus Pfeiffer  *
61d96047eSMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
71d96047eSMarkus Pfeiffer  * modification, are permitted provided that the following conditions
81d96047eSMarkus Pfeiffer  * are met:
91d96047eSMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
101d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
111d96047eSMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
121d96047eSMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
131d96047eSMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
141d96047eSMarkus Pfeiffer  *
151d96047eSMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161d96047eSMarkus Pfeiffer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171d96047eSMarkus Pfeiffer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181d96047eSMarkus Pfeiffer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191d96047eSMarkus Pfeiffer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201d96047eSMarkus Pfeiffer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211d96047eSMarkus Pfeiffer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221d96047eSMarkus Pfeiffer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231d96047eSMarkus Pfeiffer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241d96047eSMarkus Pfeiffer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251d96047eSMarkus Pfeiffer  * SUCH DAMAGE.
261d96047eSMarkus Pfeiffer  */
271d96047eSMarkus Pfeiffer 
289b0c1abeSSascha Wildner #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
299b0c1abeSSascha Wildner #include LIBUSB_GLOBAL_INCLUDE_FILE
309b0c1abeSSascha Wildner #else
311d96047eSMarkus Pfeiffer #include <assert.h>
321d96047eSMarkus Pfeiffer #include <errno.h>
331d96047eSMarkus Pfeiffer #include <poll.h>
341d96047eSMarkus Pfeiffer #include <pthread.h>
351d96047eSMarkus Pfeiffer #include <stdio.h>
361d96047eSMarkus Pfeiffer #include <stdlib.h>
379b0c1abeSSascha Wildner #include <string.h>
381d96047eSMarkus Pfeiffer #include <unistd.h>
399b0c1abeSSascha Wildner #include <time.h>
409b0c1abeSSascha Wildner #include <sys/fcntl.h>
419b0c1abeSSascha Wildner #include <sys/ioctl.h>
429b0c1abeSSascha Wildner #include <sys/queue.h>
439b0c1abeSSascha Wildner #include <sys/endian.h>
449b0c1abeSSascha Wildner #endif
451d96047eSMarkus Pfeiffer 
461d96047eSMarkus Pfeiffer #define	libusb_device_handle libusb20_device
471d96047eSMarkus Pfeiffer 
481d96047eSMarkus Pfeiffer #include "libusb20.h"
491d96047eSMarkus Pfeiffer #include "libusb20_desc.h"
501d96047eSMarkus Pfeiffer #include "libusb20_int.h"
511d96047eSMarkus Pfeiffer #include "libusb.h"
521d96047eSMarkus Pfeiffer #include "libusb10.h"
531d96047eSMarkus Pfeiffer 
541d96047eSMarkus Pfeiffer static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER;
551d96047eSMarkus Pfeiffer struct libusb_context *usbi_default_context = NULL;
561d96047eSMarkus Pfeiffer 
571d96047eSMarkus Pfeiffer /* Prototypes */
581d96047eSMarkus Pfeiffer 
591d96047eSMarkus Pfeiffer static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t);
601d96047eSMarkus Pfeiffer static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *);
611d96047eSMarkus Pfeiffer static int libusb10_convert_error(uint8_t status);
621d96047eSMarkus Pfeiffer static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int);
631d96047eSMarkus Pfeiffer static void libusb10_isoc_proxy(struct libusb20_transfer *);
641d96047eSMarkus Pfeiffer static void libusb10_bulk_intr_proxy(struct libusb20_transfer *);
651d96047eSMarkus Pfeiffer static void libusb10_ctrl_proxy(struct libusb20_transfer *);
661d96047eSMarkus Pfeiffer static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t);
671d96047eSMarkus Pfeiffer 
681d96047eSMarkus Pfeiffer /*  Library initialisation / deinitialisation */
691d96047eSMarkus Pfeiffer 
701d96047eSMarkus Pfeiffer void
libusb_set_debug(libusb_context * ctx,int level)711d96047eSMarkus Pfeiffer libusb_set_debug(libusb_context *ctx, int level)
721d96047eSMarkus Pfeiffer {
731d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
741d96047eSMarkus Pfeiffer 	if (ctx)
751d96047eSMarkus Pfeiffer 		ctx->debug = level;
761d96047eSMarkus Pfeiffer }
771d96047eSMarkus Pfeiffer 
781d96047eSMarkus Pfeiffer static void
libusb_set_nonblocking(int f)791d96047eSMarkus Pfeiffer libusb_set_nonblocking(int f)
801d96047eSMarkus Pfeiffer {
811d96047eSMarkus Pfeiffer 	int flags;
821d96047eSMarkus Pfeiffer 
831d96047eSMarkus Pfeiffer 	/*
841d96047eSMarkus Pfeiffer 	 * We ignore any failures in this function, hence the
851d96047eSMarkus Pfeiffer 	 * non-blocking flag is not critical to the operation of
861d96047eSMarkus Pfeiffer 	 * libUSB. We use F_GETFL and F_SETFL to be compatible with
871d96047eSMarkus Pfeiffer 	 * Linux.
881d96047eSMarkus Pfeiffer 	 */
891d96047eSMarkus Pfeiffer 
901d96047eSMarkus Pfeiffer 	flags = fcntl(f, F_GETFL, NULL);
911d96047eSMarkus Pfeiffer 	if (flags == -1)
921d96047eSMarkus Pfeiffer 		return;
931d96047eSMarkus Pfeiffer 	flags |= O_NONBLOCK;
941d96047eSMarkus Pfeiffer 	fcntl(f, F_SETFL, flags);
951d96047eSMarkus Pfeiffer }
961d96047eSMarkus Pfeiffer 
971d96047eSMarkus Pfeiffer int
libusb_init(libusb_context ** context)981d96047eSMarkus Pfeiffer libusb_init(libusb_context **context)
991d96047eSMarkus Pfeiffer {
1001d96047eSMarkus Pfeiffer 	struct libusb_context *ctx;
101aa3e5c14SSascha Wildner 	pthread_condattr_t attr;
1021d96047eSMarkus Pfeiffer 	char *debug;
1031d96047eSMarkus Pfeiffer 	int ret;
1041d96047eSMarkus Pfeiffer 
1051d96047eSMarkus Pfeiffer 	ctx = malloc(sizeof(*ctx));
1061d96047eSMarkus Pfeiffer 	if (!ctx)
1071d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
1081d96047eSMarkus Pfeiffer 
1091d96047eSMarkus Pfeiffer 	memset(ctx, 0, sizeof(*ctx));
1101d96047eSMarkus Pfeiffer 
1111d96047eSMarkus Pfeiffer 	debug = getenv("LIBUSB_DEBUG");
1121d96047eSMarkus Pfeiffer 	if (debug != NULL) {
1131d96047eSMarkus Pfeiffer 		ctx->debug = atoi(debug);
1141d96047eSMarkus Pfeiffer 		if (ctx->debug != 0)
1151d96047eSMarkus Pfeiffer 			ctx->debug_fixed = 1;
1161d96047eSMarkus Pfeiffer 	}
1171d96047eSMarkus Pfeiffer 	TAILQ_INIT(&ctx->pollfds);
1181d96047eSMarkus Pfeiffer 	TAILQ_INIT(&ctx->tr_done);
119*c4031fc1SImre Vadász 	TAILQ_INIT(&ctx->hotplug_cbh);
120*c4031fc1SImre Vadász 	TAILQ_INIT(&ctx->hotplug_devs);
1211d96047eSMarkus Pfeiffer 
122aa3e5c14SSascha Wildner 	if (pthread_mutex_init(&ctx->ctx_lock, NULL) != 0) {
123aa3e5c14SSascha Wildner 		free(ctx);
124aa3e5c14SSascha Wildner 		return (LIBUSB_ERROR_NO_MEM);
125aa3e5c14SSascha Wildner 	}
126*c4031fc1SImre Vadász 	if (pthread_mutex_init(&ctx->hotplug_lock, NULL) != 0) {
127*c4031fc1SImre Vadász 		pthread_mutex_destroy(&ctx->ctx_lock);
128*c4031fc1SImre Vadász 		free(ctx);
129*c4031fc1SImre Vadász 		return (LIBUSB_ERROR_NO_MEM);
130*c4031fc1SImre Vadász 	}
131aa3e5c14SSascha Wildner 	if (pthread_condattr_init(&attr) != 0) {
132aa3e5c14SSascha Wildner 		pthread_mutex_destroy(&ctx->ctx_lock);
133*c4031fc1SImre Vadász 		pthread_mutex_destroy(&ctx->hotplug_lock);
134aa3e5c14SSascha Wildner 		free(ctx);
135aa3e5c14SSascha Wildner 		return (LIBUSB_ERROR_NO_MEM);
136aa3e5c14SSascha Wildner 	}
137aa3e5c14SSascha Wildner 	if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) {
138aa3e5c14SSascha Wildner 		pthread_mutex_destroy(&ctx->ctx_lock);
139*c4031fc1SImre Vadász 		pthread_mutex_destroy(&ctx->hotplug_lock);
140aa3e5c14SSascha Wildner 		pthread_condattr_destroy(&attr);
141aa3e5c14SSascha Wildner 		free(ctx);
142aa3e5c14SSascha Wildner 		return (LIBUSB_ERROR_OTHER);
143aa3e5c14SSascha Wildner 	}
144aa3e5c14SSascha Wildner 	if (pthread_cond_init(&ctx->ctx_cond, &attr) != 0) {
145aa3e5c14SSascha Wildner 		pthread_mutex_destroy(&ctx->ctx_lock);
146*c4031fc1SImre Vadász 		pthread_mutex_destroy(&ctx->hotplug_lock);
147aa3e5c14SSascha Wildner 		pthread_condattr_destroy(&attr);
148aa3e5c14SSascha Wildner 		free(ctx);
149aa3e5c14SSascha Wildner 		return (LIBUSB_ERROR_NO_MEM);
150aa3e5c14SSascha Wildner 	}
151aa3e5c14SSascha Wildner 	pthread_condattr_destroy(&attr);
1521d96047eSMarkus Pfeiffer 
1531d96047eSMarkus Pfeiffer 	ctx->ctx_handler = NO_THREAD;
154*c4031fc1SImre Vadász 	ctx->hotplug_handler = NO_THREAD;
1551d96047eSMarkus Pfeiffer 
1561d96047eSMarkus Pfeiffer 	ret = pipe(ctx->ctrl_pipe);
1571d96047eSMarkus Pfeiffer 	if (ret < 0) {
1581d96047eSMarkus Pfeiffer 		pthread_mutex_destroy(&ctx->ctx_lock);
159*c4031fc1SImre Vadász 		pthread_mutex_destroy(&ctx->hotplug_lock);
1601d96047eSMarkus Pfeiffer 		pthread_cond_destroy(&ctx->ctx_cond);
1611d96047eSMarkus Pfeiffer 		free(ctx);
1621d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_OTHER);
1631d96047eSMarkus Pfeiffer 	}
1641d96047eSMarkus Pfeiffer 	/* set non-blocking mode on the control pipe to avoid deadlock */
1651d96047eSMarkus Pfeiffer 	libusb_set_nonblocking(ctx->ctrl_pipe[0]);
1661d96047eSMarkus Pfeiffer 	libusb_set_nonblocking(ctx->ctrl_pipe[1]);
1671d96047eSMarkus Pfeiffer 
1681d96047eSMarkus Pfeiffer 	libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN);
1691d96047eSMarkus Pfeiffer 
1701d96047eSMarkus Pfeiffer 	pthread_mutex_lock(&default_context_lock);
1711d96047eSMarkus Pfeiffer 	if (usbi_default_context == NULL) {
1721d96047eSMarkus Pfeiffer 		usbi_default_context = ctx;
1731d96047eSMarkus Pfeiffer 	}
1741d96047eSMarkus Pfeiffer 	pthread_mutex_unlock(&default_context_lock);
1751d96047eSMarkus Pfeiffer 
1761d96047eSMarkus Pfeiffer 	if (context)
1771d96047eSMarkus Pfeiffer 		*context = ctx;
1781d96047eSMarkus Pfeiffer 
1791d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
1801d96047eSMarkus Pfeiffer 
1811d96047eSMarkus Pfeiffer 	return (0);
1821d96047eSMarkus Pfeiffer }
1831d96047eSMarkus Pfeiffer 
1841d96047eSMarkus Pfeiffer void
libusb_exit(libusb_context * ctx)1851d96047eSMarkus Pfeiffer libusb_exit(libusb_context *ctx)
1861d96047eSMarkus Pfeiffer {
1871d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
1881d96047eSMarkus Pfeiffer 
1891d96047eSMarkus Pfeiffer 	if (ctx == NULL)
1901d96047eSMarkus Pfeiffer 		return;
1911d96047eSMarkus Pfeiffer 
192*c4031fc1SImre Vadász 	/* stop hotplug thread, if any */
193*c4031fc1SImre Vadász 
194*c4031fc1SImre Vadász 	if (ctx->hotplug_handler != NO_THREAD) {
195*c4031fc1SImre Vadász 		pthread_t td;
196*c4031fc1SImre Vadász 		void *ptr;
197*c4031fc1SImre Vadász 
198*c4031fc1SImre Vadász 		HOTPLUG_LOCK(ctx);
199*c4031fc1SImre Vadász 		td = ctx->hotplug_handler;
200*c4031fc1SImre Vadász 		ctx->hotplug_handler = NO_THREAD;
201*c4031fc1SImre Vadász 		HOTPLUG_UNLOCK(ctx);
202*c4031fc1SImre Vadász 
203*c4031fc1SImre Vadász 		pthread_join(td, &ptr);
204*c4031fc1SImre Vadász 	}
205*c4031fc1SImre Vadász 
2061d96047eSMarkus Pfeiffer 	/* XXX cleanup devices */
2071d96047eSMarkus Pfeiffer 
2081d96047eSMarkus Pfeiffer 	libusb10_remove_pollfd(ctx, &ctx->ctx_poll);
2091d96047eSMarkus Pfeiffer 	close(ctx->ctrl_pipe[0]);
2101d96047eSMarkus Pfeiffer 	close(ctx->ctrl_pipe[1]);
2111d96047eSMarkus Pfeiffer 	pthread_mutex_destroy(&ctx->ctx_lock);
212*c4031fc1SImre Vadász 	pthread_mutex_destroy(&ctx->hotplug_lock);
2131d96047eSMarkus Pfeiffer 	pthread_cond_destroy(&ctx->ctx_cond);
2141d96047eSMarkus Pfeiffer 
2151d96047eSMarkus Pfeiffer 	pthread_mutex_lock(&default_context_lock);
2161d96047eSMarkus Pfeiffer 	if (ctx == usbi_default_context) {
2171d96047eSMarkus Pfeiffer 		usbi_default_context = NULL;
2181d96047eSMarkus Pfeiffer 	}
2191d96047eSMarkus Pfeiffer 	pthread_mutex_unlock(&default_context_lock);
2201d96047eSMarkus Pfeiffer 
2211d96047eSMarkus Pfeiffer 	free(ctx);
2221d96047eSMarkus Pfeiffer }
2231d96047eSMarkus Pfeiffer 
2241d96047eSMarkus Pfeiffer /* Device handling and initialisation. */
2251d96047eSMarkus Pfeiffer 
2261d96047eSMarkus Pfeiffer ssize_t
libusb_get_device_list(libusb_context * ctx,libusb_device *** list)2271d96047eSMarkus Pfeiffer libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
2281d96047eSMarkus Pfeiffer {
2291d96047eSMarkus Pfeiffer 	struct libusb20_backend *usb_backend;
2301d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
2311d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
2321d96047eSMarkus Pfeiffer 	int i;
2331d96047eSMarkus Pfeiffer 
2341d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
2351d96047eSMarkus Pfeiffer 
2361d96047eSMarkus Pfeiffer 	if (ctx == NULL)
2371d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
2381d96047eSMarkus Pfeiffer 
2391d96047eSMarkus Pfeiffer 	if (list == NULL)
2401d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
2411d96047eSMarkus Pfeiffer 
2421d96047eSMarkus Pfeiffer 	usb_backend = libusb20_be_alloc_default();
2431d96047eSMarkus Pfeiffer 	if (usb_backend == NULL)
2441d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_MEM);
2451d96047eSMarkus Pfeiffer 
2461d96047eSMarkus Pfeiffer 	/* figure out how many USB devices are present */
2471d96047eSMarkus Pfeiffer 	pdev = NULL;
2481d96047eSMarkus Pfeiffer 	i = 0;
2491d96047eSMarkus Pfeiffer 	while ((pdev = libusb20_be_device_foreach(usb_backend, pdev)))
2501d96047eSMarkus Pfeiffer 		i++;
2511d96047eSMarkus Pfeiffer 
2521d96047eSMarkus Pfeiffer 	/* allocate device pointer list */
2531d96047eSMarkus Pfeiffer 	*list = malloc((i + 1) * sizeof(void *));
2541d96047eSMarkus Pfeiffer 	if (*list == NULL) {
2551d96047eSMarkus Pfeiffer 		libusb20_be_free(usb_backend);
2561d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_MEM);
2571d96047eSMarkus Pfeiffer 	}
2581d96047eSMarkus Pfeiffer 	/* create libusb v1.0 compliant devices */
2591d96047eSMarkus Pfeiffer 	i = 0;
2601d96047eSMarkus Pfeiffer 	while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
2611d96047eSMarkus Pfeiffer 
2621d96047eSMarkus Pfeiffer 		dev = malloc(sizeof(*dev));
2631d96047eSMarkus Pfeiffer 		if (dev == NULL) {
2641d96047eSMarkus Pfeiffer 			while (i != 0) {
2651d96047eSMarkus Pfeiffer 				libusb_unref_device((*list)[i - 1]);
2661d96047eSMarkus Pfeiffer 				i--;
2671d96047eSMarkus Pfeiffer 			}
2681d96047eSMarkus Pfeiffer 			free(*list);
2691d96047eSMarkus Pfeiffer 			*list = NULL;
2701d96047eSMarkus Pfeiffer 			libusb20_be_free(usb_backend);
2711d96047eSMarkus Pfeiffer 			return (LIBUSB_ERROR_NO_MEM);
2721d96047eSMarkus Pfeiffer 		}
2731d96047eSMarkus Pfeiffer 		/* get device into libUSB v1.0 list */
2741d96047eSMarkus Pfeiffer 		libusb20_be_dequeue_device(usb_backend, pdev);
2751d96047eSMarkus Pfeiffer 
2761d96047eSMarkus Pfeiffer 		memset(dev, 0, sizeof(*dev));
2771d96047eSMarkus Pfeiffer 
2781d96047eSMarkus Pfeiffer 		/* init transfer queues */
2791d96047eSMarkus Pfeiffer 		TAILQ_INIT(&dev->tr_head);
2801d96047eSMarkus Pfeiffer 
2811d96047eSMarkus Pfeiffer 		/* set context we belong to */
2821d96047eSMarkus Pfeiffer 		dev->ctx = ctx;
2831d96047eSMarkus Pfeiffer 
2841d96047eSMarkus Pfeiffer 		/* link together the two structures */
2851d96047eSMarkus Pfeiffer 		dev->os_priv = pdev;
2861d96047eSMarkus Pfeiffer 		pdev->privLuData = dev;
2871d96047eSMarkus Pfeiffer 
2881d96047eSMarkus Pfeiffer 		(*list)[i] = libusb_ref_device(dev);
2891d96047eSMarkus Pfeiffer 		i++;
2901d96047eSMarkus Pfeiffer 	}
2911d96047eSMarkus Pfeiffer 	(*list)[i] = NULL;
2921d96047eSMarkus Pfeiffer 
2931d96047eSMarkus Pfeiffer 	libusb20_be_free(usb_backend);
2941d96047eSMarkus Pfeiffer 	return (i);
2951d96047eSMarkus Pfeiffer }
2961d96047eSMarkus Pfeiffer 
2971d96047eSMarkus Pfeiffer void
libusb_free_device_list(libusb_device ** list,int unref_devices)2981d96047eSMarkus Pfeiffer libusb_free_device_list(libusb_device **list, int unref_devices)
2991d96047eSMarkus Pfeiffer {
3001d96047eSMarkus Pfeiffer 	int i;
3011d96047eSMarkus Pfeiffer 
3021d96047eSMarkus Pfeiffer 	if (list == NULL)
3031d96047eSMarkus Pfeiffer 		return;			/* be NULL safe */
3041d96047eSMarkus Pfeiffer 
3051d96047eSMarkus Pfeiffer 	if (unref_devices) {
3061d96047eSMarkus Pfeiffer 		for (i = 0; list[i] != NULL; i++)
3071d96047eSMarkus Pfeiffer 			libusb_unref_device(list[i]);
3081d96047eSMarkus Pfeiffer 	}
3091d96047eSMarkus Pfeiffer 	free(list);
3101d96047eSMarkus Pfeiffer }
3111d96047eSMarkus Pfeiffer 
3121d96047eSMarkus Pfeiffer uint8_t
libusb_get_bus_number(libusb_device * dev)3131d96047eSMarkus Pfeiffer libusb_get_bus_number(libusb_device *dev)
3141d96047eSMarkus Pfeiffer {
3151d96047eSMarkus Pfeiffer 	if (dev == NULL)
3161d96047eSMarkus Pfeiffer 		return (0);		/* should not happen */
3171d96047eSMarkus Pfeiffer 	return (libusb20_dev_get_bus_number(dev->os_priv));
3181d96047eSMarkus Pfeiffer }
3191d96047eSMarkus Pfeiffer 
3209b0c1abeSSascha Wildner int
libusb_get_port_numbers(libusb_device * dev,uint8_t * buf,uint8_t bufsize)3219b0c1abeSSascha Wildner libusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize)
3229b0c1abeSSascha Wildner {
3239b0c1abeSSascha Wildner 	return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize));
3249b0c1abeSSascha Wildner }
3259b0c1abeSSascha Wildner 
3269b0c1abeSSascha Wildner int
libusb_get_port_path(libusb_context * ctx,libusb_device * dev,uint8_t * buf,uint8_t bufsize)3279b0c1abeSSascha Wildner libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t *buf,
3289b0c1abeSSascha Wildner     uint8_t bufsize)
3299b0c1abeSSascha Wildner {
3309b0c1abeSSascha Wildner 	return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize));
3319b0c1abeSSascha Wildner }
3329b0c1abeSSascha Wildner 
3331d96047eSMarkus Pfeiffer uint8_t
libusb_get_device_address(libusb_device * dev)3341d96047eSMarkus Pfeiffer libusb_get_device_address(libusb_device *dev)
3351d96047eSMarkus Pfeiffer {
3361d96047eSMarkus Pfeiffer 	if (dev == NULL)
3371d96047eSMarkus Pfeiffer 		return (0);		/* should not happen */
3381d96047eSMarkus Pfeiffer 	return (libusb20_dev_get_address(dev->os_priv));
3391d96047eSMarkus Pfeiffer }
3401d96047eSMarkus Pfeiffer 
3411d96047eSMarkus Pfeiffer enum libusb_speed
libusb_get_device_speed(libusb_device * dev)3421d96047eSMarkus Pfeiffer libusb_get_device_speed(libusb_device *dev)
3431d96047eSMarkus Pfeiffer {
3441d96047eSMarkus Pfeiffer 	if (dev == NULL)
3451d96047eSMarkus Pfeiffer 		return (LIBUSB_SPEED_UNKNOWN);	/* should not happen */
3461d96047eSMarkus Pfeiffer 
3471d96047eSMarkus Pfeiffer 	switch (libusb20_dev_get_speed(dev->os_priv)) {
3481d96047eSMarkus Pfeiffer 	case LIBUSB20_SPEED_LOW:
3491d96047eSMarkus Pfeiffer 		return (LIBUSB_SPEED_LOW);
3501d96047eSMarkus Pfeiffer 	case LIBUSB20_SPEED_FULL:
3511d96047eSMarkus Pfeiffer 		return (LIBUSB_SPEED_FULL);
3521d96047eSMarkus Pfeiffer 	case LIBUSB20_SPEED_HIGH:
3531d96047eSMarkus Pfeiffer 		return (LIBUSB_SPEED_HIGH);
3541d96047eSMarkus Pfeiffer 	case LIBUSB20_SPEED_SUPER:
3551d96047eSMarkus Pfeiffer 		return (LIBUSB_SPEED_SUPER);
3561d96047eSMarkus Pfeiffer 	default:
3571d96047eSMarkus Pfeiffer 		break;
3581d96047eSMarkus Pfeiffer 	}
3591d96047eSMarkus Pfeiffer 	return (LIBUSB_SPEED_UNKNOWN);
3601d96047eSMarkus Pfeiffer }
3611d96047eSMarkus Pfeiffer 
3621d96047eSMarkus Pfeiffer int
libusb_get_max_packet_size(libusb_device * dev,uint8_t endpoint)3631d96047eSMarkus Pfeiffer libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint)
3641d96047eSMarkus Pfeiffer {
3651d96047eSMarkus Pfeiffer 	struct libusb_config_descriptor *pdconf;
3661d96047eSMarkus Pfeiffer 	struct libusb_interface *pinf;
3671d96047eSMarkus Pfeiffer 	struct libusb_interface_descriptor *pdinf;
3681d96047eSMarkus Pfeiffer 	struct libusb_endpoint_descriptor *pdend;
3691d96047eSMarkus Pfeiffer 	int i;
3701d96047eSMarkus Pfeiffer 	int j;
3711d96047eSMarkus Pfeiffer 	int k;
3721d96047eSMarkus Pfeiffer 	int ret;
3731d96047eSMarkus Pfeiffer 
3741d96047eSMarkus Pfeiffer 	if (dev == NULL)
3751d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_DEVICE);
3761d96047eSMarkus Pfeiffer 
3771d96047eSMarkus Pfeiffer 	ret = libusb_get_active_config_descriptor(dev, &pdconf);
3781d96047eSMarkus Pfeiffer 	if (ret < 0)
3791d96047eSMarkus Pfeiffer 		return (ret);
3801d96047eSMarkus Pfeiffer 
3811d96047eSMarkus Pfeiffer 	ret = LIBUSB_ERROR_NOT_FOUND;
3821d96047eSMarkus Pfeiffer 	for (i = 0; i < pdconf->bNumInterfaces; i++) {
3831d96047eSMarkus Pfeiffer 		pinf = &pdconf->interface[i];
3841d96047eSMarkus Pfeiffer 		for (j = 0; j < pinf->num_altsetting; j++) {
3851d96047eSMarkus Pfeiffer 			pdinf = &pinf->altsetting[j];
3861d96047eSMarkus Pfeiffer 			for (k = 0; k < pdinf->bNumEndpoints; k++) {
3871d96047eSMarkus Pfeiffer 				pdend = &pdinf->endpoint[k];
3881d96047eSMarkus Pfeiffer 				if (pdend->bEndpointAddress == endpoint) {
3891d96047eSMarkus Pfeiffer 					ret = pdend->wMaxPacketSize;
3901d96047eSMarkus Pfeiffer 					goto out;
3911d96047eSMarkus Pfeiffer 				}
3921d96047eSMarkus Pfeiffer 			}
3931d96047eSMarkus Pfeiffer 		}
3941d96047eSMarkus Pfeiffer 	}
3951d96047eSMarkus Pfeiffer 
3961d96047eSMarkus Pfeiffer out:
3971d96047eSMarkus Pfeiffer 	libusb_free_config_descriptor(pdconf);
3981d96047eSMarkus Pfeiffer 	return (ret);
3991d96047eSMarkus Pfeiffer }
4001d96047eSMarkus Pfeiffer 
401aa3e5c14SSascha Wildner int
libusb_get_max_iso_packet_size(libusb_device * dev,uint8_t endpoint)402aa3e5c14SSascha Wildner libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint)
403aa3e5c14SSascha Wildner {
404aa3e5c14SSascha Wildner 	int multiplier;
405aa3e5c14SSascha Wildner 	int ret;
406aa3e5c14SSascha Wildner 
407aa3e5c14SSascha Wildner 	ret = libusb_get_max_packet_size(dev, endpoint);
408aa3e5c14SSascha Wildner 
409aa3e5c14SSascha Wildner 	switch (libusb20_dev_get_speed(dev->os_priv)) {
410aa3e5c14SSascha Wildner 	case LIBUSB20_SPEED_LOW:
411aa3e5c14SSascha Wildner 	case LIBUSB20_SPEED_FULL:
412aa3e5c14SSascha Wildner 		break;
413aa3e5c14SSascha Wildner 	default:
414aa3e5c14SSascha Wildner 		if (ret > -1) {
415aa3e5c14SSascha Wildner 			multiplier = (1 + ((ret >> 11) & 3));
416aa3e5c14SSascha Wildner 			if (multiplier > 3)
417aa3e5c14SSascha Wildner 				multiplier = 3;
418aa3e5c14SSascha Wildner 			ret = (ret & 0x7FF) * multiplier;
419aa3e5c14SSascha Wildner 		}
420aa3e5c14SSascha Wildner 		break;
421aa3e5c14SSascha Wildner 	}
422aa3e5c14SSascha Wildner 	return (ret);
423aa3e5c14SSascha Wildner }
424aa3e5c14SSascha Wildner 
4251d96047eSMarkus Pfeiffer libusb_device *
libusb_ref_device(libusb_device * dev)4261d96047eSMarkus Pfeiffer libusb_ref_device(libusb_device *dev)
4271d96047eSMarkus Pfeiffer {
4281d96047eSMarkus Pfeiffer 	if (dev == NULL)
4291d96047eSMarkus Pfeiffer 		return (NULL);		/* be NULL safe */
4301d96047eSMarkus Pfeiffer 
4311d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
4321d96047eSMarkus Pfeiffer 	dev->refcnt++;
4331d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
4341d96047eSMarkus Pfeiffer 
4351d96047eSMarkus Pfeiffer 	return (dev);
4361d96047eSMarkus Pfeiffer }
4371d96047eSMarkus Pfeiffer 
4381d96047eSMarkus Pfeiffer void
libusb_unref_device(libusb_device * dev)4391d96047eSMarkus Pfeiffer libusb_unref_device(libusb_device *dev)
4401d96047eSMarkus Pfeiffer {
4411d96047eSMarkus Pfeiffer 	if (dev == NULL)
4421d96047eSMarkus Pfeiffer 		return;			/* be NULL safe */
4431d96047eSMarkus Pfeiffer 
4441d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
4451d96047eSMarkus Pfeiffer 	dev->refcnt--;
4461d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
4471d96047eSMarkus Pfeiffer 
4481d96047eSMarkus Pfeiffer 	if (dev->refcnt == 0) {
4491d96047eSMarkus Pfeiffer 		libusb20_dev_free(dev->os_priv);
4501d96047eSMarkus Pfeiffer 		free(dev);
4511d96047eSMarkus Pfeiffer 	}
4521d96047eSMarkus Pfeiffer }
4531d96047eSMarkus Pfeiffer 
4541d96047eSMarkus Pfeiffer int
libusb_open(libusb_device * dev,libusb_device_handle ** devh)4551d96047eSMarkus Pfeiffer libusb_open(libusb_device *dev, libusb_device_handle **devh)
4561d96047eSMarkus Pfeiffer {
4571d96047eSMarkus Pfeiffer 	libusb_context *ctx = dev->ctx;
4581d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev = dev->os_priv;
4591d96047eSMarkus Pfeiffer 	uint8_t dummy;
4601d96047eSMarkus Pfeiffer 	int err;
4611d96047eSMarkus Pfeiffer 
4621d96047eSMarkus Pfeiffer 	if (devh == NULL)
4631d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
4641d96047eSMarkus Pfeiffer 
4651d96047eSMarkus Pfeiffer 	/* set default device handle value */
4661d96047eSMarkus Pfeiffer 	*devh = NULL;
4671d96047eSMarkus Pfeiffer 
4681d96047eSMarkus Pfeiffer 	dev = libusb_ref_device(dev);
4691d96047eSMarkus Pfeiffer 	if (dev == NULL)
4701d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
4711d96047eSMarkus Pfeiffer 
4721d96047eSMarkus Pfeiffer 	err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ );
4731d96047eSMarkus Pfeiffer 	if (err) {
4741d96047eSMarkus Pfeiffer 		libusb_unref_device(dev);
4751d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_MEM);
4761d96047eSMarkus Pfeiffer 	}
4771d96047eSMarkus Pfeiffer 	libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
4781d96047eSMarkus Pfeiffer 	    POLLOUT | POLLRDNORM | POLLWRNORM);
4791d96047eSMarkus Pfeiffer 
4801d96047eSMarkus Pfeiffer 	/* make sure our event loop detects the new device */
4811d96047eSMarkus Pfeiffer 	dummy = 0;
4821d96047eSMarkus Pfeiffer 	err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
4831d96047eSMarkus Pfeiffer 	if (err < (int)sizeof(dummy)) {
4841d96047eSMarkus Pfeiffer 		/* ignore error, if any */
4851d96047eSMarkus Pfeiffer 		DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!");
4861d96047eSMarkus Pfeiffer 	}
4871d96047eSMarkus Pfeiffer 	*devh = pdev;
4881d96047eSMarkus Pfeiffer 
4891d96047eSMarkus Pfeiffer 	return (0);
4901d96047eSMarkus Pfeiffer }
4911d96047eSMarkus Pfeiffer 
4921d96047eSMarkus Pfeiffer libusb_device_handle *
libusb_open_device_with_vid_pid(libusb_context * ctx,uint16_t vendor_id,uint16_t product_id)4931d96047eSMarkus Pfeiffer libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
4941d96047eSMarkus Pfeiffer     uint16_t product_id)
4951d96047eSMarkus Pfeiffer {
4961d96047eSMarkus Pfeiffer 	struct libusb_device **devs;
4971d96047eSMarkus Pfeiffer 	struct libusb20_device *pdev;
4981d96047eSMarkus Pfeiffer 	struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
4991d96047eSMarkus Pfeiffer 	int i;
5001d96047eSMarkus Pfeiffer 	int j;
5011d96047eSMarkus Pfeiffer 
5021d96047eSMarkus Pfeiffer 	ctx = GET_CONTEXT(ctx);
5031d96047eSMarkus Pfeiffer 	if (ctx == NULL)
5041d96047eSMarkus Pfeiffer 		return (NULL);		/* be NULL safe */
5051d96047eSMarkus Pfeiffer 
5061d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter");
5071d96047eSMarkus Pfeiffer 
5081d96047eSMarkus Pfeiffer 	if ((i = libusb_get_device_list(ctx, &devs)) < 0)
5091d96047eSMarkus Pfeiffer 		return (NULL);
5101d96047eSMarkus Pfeiffer 
5111d96047eSMarkus Pfeiffer 	pdev = NULL;
5121d96047eSMarkus Pfeiffer 	for (j = 0; j < i; j++) {
5131d96047eSMarkus Pfeiffer 		struct libusb20_device *tdev;
5141d96047eSMarkus Pfeiffer 
5151d96047eSMarkus Pfeiffer 		tdev = devs[j]->os_priv;
5161d96047eSMarkus Pfeiffer 		pdesc = libusb20_dev_get_device_desc(tdev);
5171d96047eSMarkus Pfeiffer 		/*
5181d96047eSMarkus Pfeiffer 		 * NOTE: The USB library will automatically swap the
5191d96047eSMarkus Pfeiffer 		 * fields in the device descriptor to be of host
5201d96047eSMarkus Pfeiffer 		 * endian type!
5211d96047eSMarkus Pfeiffer 		 */
5221d96047eSMarkus Pfeiffer 		if (pdesc->idVendor == vendor_id &&
5231d96047eSMarkus Pfeiffer 		    pdesc->idProduct == product_id) {
5241d96047eSMarkus Pfeiffer 			libusb_open(devs[j], &pdev);
5251d96047eSMarkus Pfeiffer 			break;
5261d96047eSMarkus Pfeiffer 		}
5271d96047eSMarkus Pfeiffer 	}
5281d96047eSMarkus Pfeiffer 
5291d96047eSMarkus Pfeiffer 	libusb_free_device_list(devs, 1);
5301d96047eSMarkus Pfeiffer 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave");
5311d96047eSMarkus Pfeiffer 	return (pdev);
5321d96047eSMarkus Pfeiffer }
5331d96047eSMarkus Pfeiffer 
5341d96047eSMarkus Pfeiffer void
libusb_close(struct libusb20_device * pdev)5351d96047eSMarkus Pfeiffer libusb_close(struct libusb20_device *pdev)
5361d96047eSMarkus Pfeiffer {
5371d96047eSMarkus Pfeiffer 	libusb_context *ctx;
5381d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
5391d96047eSMarkus Pfeiffer 	uint8_t dummy;
5401d96047eSMarkus Pfeiffer 	int err;
5411d96047eSMarkus Pfeiffer 
5421d96047eSMarkus Pfeiffer 	if (pdev == NULL)
5431d96047eSMarkus Pfeiffer 		return;			/* be NULL safe */
5441d96047eSMarkus Pfeiffer 
5451d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
5461d96047eSMarkus Pfeiffer 	ctx = dev->ctx;
5471d96047eSMarkus Pfeiffer 
5481d96047eSMarkus Pfeiffer 	libusb10_remove_pollfd(ctx, &dev->dev_poll);
5491d96047eSMarkus Pfeiffer 
5501d96047eSMarkus Pfeiffer 	libusb20_dev_close(pdev);
5511d96047eSMarkus Pfeiffer 
5521d96047eSMarkus Pfeiffer 	/* unref will free the "pdev" when the refcount reaches zero */
5531d96047eSMarkus Pfeiffer 	libusb_unref_device(dev);
5541d96047eSMarkus Pfeiffer 
5551d96047eSMarkus Pfeiffer 	/* make sure our event loop detects the closed device */
5561d96047eSMarkus Pfeiffer 	dummy = 0;
5571d96047eSMarkus Pfeiffer 	err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
5581d96047eSMarkus Pfeiffer 	if (err < (int)sizeof(dummy)) {
5591d96047eSMarkus Pfeiffer 		/* ignore error, if any */
5601d96047eSMarkus Pfeiffer 		DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!");
5611d96047eSMarkus Pfeiffer 	}
5621d96047eSMarkus Pfeiffer }
5631d96047eSMarkus Pfeiffer 
5641d96047eSMarkus Pfeiffer libusb_device *
libusb_get_device(struct libusb20_device * pdev)5651d96047eSMarkus Pfeiffer libusb_get_device(struct libusb20_device *pdev)
5661d96047eSMarkus Pfeiffer {
5671d96047eSMarkus Pfeiffer 	if (pdev == NULL)
5681d96047eSMarkus Pfeiffer 		return (NULL);
5691d96047eSMarkus Pfeiffer 	return ((libusb_device *)pdev->privLuData);
5701d96047eSMarkus Pfeiffer }
5711d96047eSMarkus Pfeiffer 
5721d96047eSMarkus Pfeiffer int
libusb_get_configuration(struct libusb20_device * pdev,int * config)5731d96047eSMarkus Pfeiffer libusb_get_configuration(struct libusb20_device *pdev, int *config)
5741d96047eSMarkus Pfeiffer {
5751d96047eSMarkus Pfeiffer 	struct libusb20_config *pconf;
5761d96047eSMarkus Pfeiffer 
5771d96047eSMarkus Pfeiffer 	if (pdev == NULL || config == NULL)
5781d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
5791d96047eSMarkus Pfeiffer 
5801d96047eSMarkus Pfeiffer 	pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev));
5811d96047eSMarkus Pfeiffer 	if (pconf == NULL)
5821d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NO_MEM);
5831d96047eSMarkus Pfeiffer 
5841d96047eSMarkus Pfeiffer 	*config = pconf->desc.bConfigurationValue;
5851d96047eSMarkus Pfeiffer 
5861d96047eSMarkus Pfeiffer 	free(pconf);
5871d96047eSMarkus Pfeiffer 
5881d96047eSMarkus Pfeiffer 	return (0);
5891d96047eSMarkus Pfeiffer }
5901d96047eSMarkus Pfeiffer 
5911d96047eSMarkus Pfeiffer int
libusb_set_configuration(struct libusb20_device * pdev,int configuration)5921d96047eSMarkus Pfeiffer libusb_set_configuration(struct libusb20_device *pdev, int configuration)
5931d96047eSMarkus Pfeiffer {
5941d96047eSMarkus Pfeiffer 	struct libusb20_config *pconf;
5951d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
5961d96047eSMarkus Pfeiffer 	int err;
5971d96047eSMarkus Pfeiffer 	uint8_t i;
5981d96047eSMarkus Pfeiffer 
5991d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
6001d96047eSMarkus Pfeiffer 	if (dev == NULL)
6011d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6021d96047eSMarkus Pfeiffer 
6031d96047eSMarkus Pfeiffer 	if (configuration < 1) {
6041d96047eSMarkus Pfeiffer 		/* unconfigure */
6051d96047eSMarkus Pfeiffer 		i = 255;
6061d96047eSMarkus Pfeiffer 	} else {
6071d96047eSMarkus Pfeiffer 		for (i = 0; i != 255; i++) {
6081d96047eSMarkus Pfeiffer 			uint8_t found;
6091d96047eSMarkus Pfeiffer 
6101d96047eSMarkus Pfeiffer 			pconf = libusb20_dev_alloc_config(pdev, i);
6111d96047eSMarkus Pfeiffer 			if (pconf == NULL)
6121d96047eSMarkus Pfeiffer 				return (LIBUSB_ERROR_INVALID_PARAM);
6131d96047eSMarkus Pfeiffer 			found = (pconf->desc.bConfigurationValue
6141d96047eSMarkus Pfeiffer 			    == configuration);
6151d96047eSMarkus Pfeiffer 			free(pconf);
6161d96047eSMarkus Pfeiffer 
6171d96047eSMarkus Pfeiffer 			if (found)
6181d96047eSMarkus Pfeiffer 				goto set_config;
6191d96047eSMarkus Pfeiffer 		}
6201d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6211d96047eSMarkus Pfeiffer 	}
6221d96047eSMarkus Pfeiffer 
6231d96047eSMarkus Pfeiffer set_config:
6241d96047eSMarkus Pfeiffer 
6251d96047eSMarkus Pfeiffer 	libusb10_cancel_all_transfer(dev);
6261d96047eSMarkus Pfeiffer 
6271d96047eSMarkus Pfeiffer 	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
6281d96047eSMarkus Pfeiffer 
6291d96047eSMarkus Pfeiffer 	err = libusb20_dev_set_config_index(pdev, i);
6301d96047eSMarkus Pfeiffer 
6311d96047eSMarkus Pfeiffer 	libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
6321d96047eSMarkus Pfeiffer 	    POLLOUT | POLLRDNORM | POLLWRNORM);
6331d96047eSMarkus Pfeiffer 
6341d96047eSMarkus Pfeiffer 	return (err ? LIBUSB_ERROR_INVALID_PARAM : 0);
6351d96047eSMarkus Pfeiffer }
6361d96047eSMarkus Pfeiffer 
6371d96047eSMarkus Pfeiffer int
libusb_claim_interface(struct libusb20_device * pdev,int interface_number)6381d96047eSMarkus Pfeiffer libusb_claim_interface(struct libusb20_device *pdev, int interface_number)
6391d96047eSMarkus Pfeiffer {
6401d96047eSMarkus Pfeiffer 	libusb_device *dev;
6411d96047eSMarkus Pfeiffer 
6421d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
6431d96047eSMarkus Pfeiffer 	if (dev == NULL)
6441d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6451d96047eSMarkus Pfeiffer 
6461d96047eSMarkus Pfeiffer 	if (interface_number < 0 || interface_number > 31)
6471d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6481d96047eSMarkus Pfeiffer 
6491d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
6501d96047eSMarkus Pfeiffer 	dev->claimed_interfaces |= (1 << interface_number);
6511d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
6529b0c1abeSSascha Wildner 
6539b0c1abeSSascha Wildner 	return (0);
6541d96047eSMarkus Pfeiffer }
6551d96047eSMarkus Pfeiffer 
6561d96047eSMarkus Pfeiffer int
libusb_release_interface(struct libusb20_device * pdev,int interface_number)6571d96047eSMarkus Pfeiffer libusb_release_interface(struct libusb20_device *pdev, int interface_number)
6581d96047eSMarkus Pfeiffer {
6591d96047eSMarkus Pfeiffer 	libusb_device *dev;
6601d96047eSMarkus Pfeiffer 	int err = 0;
6611d96047eSMarkus Pfeiffer 
6621d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
6631d96047eSMarkus Pfeiffer 	if (dev == NULL)
6641d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6651d96047eSMarkus Pfeiffer 
6661d96047eSMarkus Pfeiffer 	if (interface_number < 0 || interface_number > 31)
6671d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6681d96047eSMarkus Pfeiffer 
6691d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
6701d96047eSMarkus Pfeiffer 	if (!(dev->claimed_interfaces & (1 << interface_number)))
6711d96047eSMarkus Pfeiffer 		err = LIBUSB_ERROR_NOT_FOUND;
6721d96047eSMarkus Pfeiffer 
6731d96047eSMarkus Pfeiffer 	if (!err)
6741d96047eSMarkus Pfeiffer 		dev->claimed_interfaces &= ~(1 << interface_number);
6751d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
6761d96047eSMarkus Pfeiffer 	return (err);
6771d96047eSMarkus Pfeiffer }
6781d96047eSMarkus Pfeiffer 
6791d96047eSMarkus Pfeiffer int
libusb_set_interface_alt_setting(struct libusb20_device * pdev,int interface_number,int alternate_setting)6801d96047eSMarkus Pfeiffer libusb_set_interface_alt_setting(struct libusb20_device *pdev,
6811d96047eSMarkus Pfeiffer     int interface_number, int alternate_setting)
6821d96047eSMarkus Pfeiffer {
6831d96047eSMarkus Pfeiffer 	libusb_device *dev;
6841d96047eSMarkus Pfeiffer 	int err = 0;
6851d96047eSMarkus Pfeiffer 
6861d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
6871d96047eSMarkus Pfeiffer 	if (dev == NULL)
6881d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6891d96047eSMarkus Pfeiffer 
6901d96047eSMarkus Pfeiffer 	if (interface_number < 0 || interface_number > 31)
6911d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
6921d96047eSMarkus Pfeiffer 
6931d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
6941d96047eSMarkus Pfeiffer 	if (!(dev->claimed_interfaces & (1 << interface_number)))
6951d96047eSMarkus Pfeiffer 		err = LIBUSB_ERROR_NOT_FOUND;
6961d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
6971d96047eSMarkus Pfeiffer 
6981d96047eSMarkus Pfeiffer 	if (err)
6991d96047eSMarkus Pfeiffer 		return (err);
7001d96047eSMarkus Pfeiffer 
7011d96047eSMarkus Pfeiffer 	libusb10_cancel_all_transfer(dev);
7021d96047eSMarkus Pfeiffer 
7031d96047eSMarkus Pfeiffer 	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
7041d96047eSMarkus Pfeiffer 
7051d96047eSMarkus Pfeiffer 	err = libusb20_dev_set_alt_index(pdev,
7061d96047eSMarkus Pfeiffer 	    interface_number, alternate_setting);
7071d96047eSMarkus Pfeiffer 
7081d96047eSMarkus Pfeiffer 	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
7091d96047eSMarkus Pfeiffer 	    pdev, libusb20_dev_get_fd(pdev),
7101d96047eSMarkus Pfeiffer 	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
7111d96047eSMarkus Pfeiffer 
7121d96047eSMarkus Pfeiffer 	return (err ? LIBUSB_ERROR_OTHER : 0);
7131d96047eSMarkus Pfeiffer }
7141d96047eSMarkus Pfeiffer 
7151d96047eSMarkus Pfeiffer static struct libusb20_transfer *
libusb10_get_transfer(struct libusb20_device * pdev,uint8_t endpoint,uint8_t xfer_index)7161d96047eSMarkus Pfeiffer libusb10_get_transfer(struct libusb20_device *pdev,
717aa3e5c14SSascha Wildner     uint8_t endpoint, uint8_t xfer_index)
7181d96047eSMarkus Pfeiffer {
719aa3e5c14SSascha Wildner 	xfer_index &= 1;	/* double buffering */
7201d96047eSMarkus Pfeiffer 
721aa3e5c14SSascha Wildner 	xfer_index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4;
7221d96047eSMarkus Pfeiffer 
7231d96047eSMarkus Pfeiffer 	if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) {
7241d96047eSMarkus Pfeiffer 		/* this is an IN endpoint */
725aa3e5c14SSascha Wildner 		xfer_index |= 2;
7261d96047eSMarkus Pfeiffer 	}
727aa3e5c14SSascha Wildner 	return (libusb20_tr_get_pointer(pdev, xfer_index));
7281d96047eSMarkus Pfeiffer }
7291d96047eSMarkus Pfeiffer 
7301d96047eSMarkus Pfeiffer int
libusb_clear_halt(struct libusb20_device * pdev,uint8_t endpoint)7311d96047eSMarkus Pfeiffer libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint)
7321d96047eSMarkus Pfeiffer {
7331d96047eSMarkus Pfeiffer 	struct libusb20_transfer *xfer;
7341d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
7351d96047eSMarkus Pfeiffer 	int err;
7361d96047eSMarkus Pfeiffer 
7371d96047eSMarkus Pfeiffer 	xfer = libusb10_get_transfer(pdev, endpoint, 0);
7381d96047eSMarkus Pfeiffer 	if (xfer == NULL)
7391d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
7401d96047eSMarkus Pfeiffer 
7411d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
7421d96047eSMarkus Pfeiffer 	if (dev == NULL)
7431d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
7441d96047eSMarkus Pfeiffer 
7451d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
7461d96047eSMarkus Pfeiffer 	err = libusb20_tr_open(xfer, 0, 1, endpoint);
7471d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
7481d96047eSMarkus Pfeiffer 
7491d96047eSMarkus Pfeiffer 	if (err != 0 && err != LIBUSB20_ERROR_BUSY)
7501d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_OTHER);
7511d96047eSMarkus Pfeiffer 
7521d96047eSMarkus Pfeiffer 	libusb20_tr_clear_stall_sync(xfer);
7531d96047eSMarkus Pfeiffer 
7541d96047eSMarkus Pfeiffer 	/* check if we opened the transfer */
7551d96047eSMarkus Pfeiffer 	if (err == 0) {
7561d96047eSMarkus Pfeiffer 		CTX_LOCK(dev->ctx);
7571d96047eSMarkus Pfeiffer 		libusb20_tr_close(xfer);
7581d96047eSMarkus Pfeiffer 		CTX_UNLOCK(dev->ctx);
7591d96047eSMarkus Pfeiffer 	}
7601d96047eSMarkus Pfeiffer 	return (0);			/* success */
7611d96047eSMarkus Pfeiffer }
7621d96047eSMarkus Pfeiffer 
7631d96047eSMarkus Pfeiffer int
libusb_reset_device(struct libusb20_device * pdev)7641d96047eSMarkus Pfeiffer libusb_reset_device(struct libusb20_device *pdev)
7651d96047eSMarkus Pfeiffer {
7661d96047eSMarkus Pfeiffer 	libusb_device *dev;
7671d96047eSMarkus Pfeiffer 	int err;
7681d96047eSMarkus Pfeiffer 
7691d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
7701d96047eSMarkus Pfeiffer 	if (dev == NULL)
7711d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
7721d96047eSMarkus Pfeiffer 
7731d96047eSMarkus Pfeiffer 	libusb10_cancel_all_transfer(dev);
7741d96047eSMarkus Pfeiffer 
7751d96047eSMarkus Pfeiffer 	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
7761d96047eSMarkus Pfeiffer 
7771d96047eSMarkus Pfeiffer 	err = libusb20_dev_reset(pdev);
7781d96047eSMarkus Pfeiffer 
7791d96047eSMarkus Pfeiffer 	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
7801d96047eSMarkus Pfeiffer 	    pdev, libusb20_dev_get_fd(pdev),
7811d96047eSMarkus Pfeiffer 	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
7821d96047eSMarkus Pfeiffer 
7831d96047eSMarkus Pfeiffer 	return (err ? LIBUSB_ERROR_OTHER : 0);
7841d96047eSMarkus Pfeiffer }
7851d96047eSMarkus Pfeiffer 
7861d96047eSMarkus Pfeiffer int
libusb_check_connected(struct libusb20_device * pdev)7871d96047eSMarkus Pfeiffer libusb_check_connected(struct libusb20_device *pdev)
7881d96047eSMarkus Pfeiffer {
7891d96047eSMarkus Pfeiffer 	libusb_device *dev;
7901d96047eSMarkus Pfeiffer 	int err;
7911d96047eSMarkus Pfeiffer 
7921d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
7931d96047eSMarkus Pfeiffer 	if (dev == NULL)
7941d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
7951d96047eSMarkus Pfeiffer 
7961d96047eSMarkus Pfeiffer 	err = libusb20_dev_check_connected(pdev);
7971d96047eSMarkus Pfeiffer 
7981d96047eSMarkus Pfeiffer 	return (err ? LIBUSB_ERROR_NO_DEVICE : 0);
7991d96047eSMarkus Pfeiffer }
8001d96047eSMarkus Pfeiffer 
8011d96047eSMarkus Pfeiffer int
libusb_kernel_driver_active(struct libusb20_device * pdev,int interface)8021d96047eSMarkus Pfeiffer libusb_kernel_driver_active(struct libusb20_device *pdev, int interface)
8031d96047eSMarkus Pfeiffer {
8041d96047eSMarkus Pfeiffer 	if (pdev == NULL)
8051d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
8061d96047eSMarkus Pfeiffer 
8071d96047eSMarkus Pfeiffer 	if (libusb20_dev_kernel_driver_active(pdev, interface))
8081d96047eSMarkus Pfeiffer 		return (0);		/* no kernel driver is active */
8091d96047eSMarkus Pfeiffer 	else
8101d96047eSMarkus Pfeiffer 		return (1);		/* kernel driver is active */
8111d96047eSMarkus Pfeiffer }
8121d96047eSMarkus Pfeiffer 
8131d96047eSMarkus Pfeiffer int
libusb_get_driver_np(struct libusb20_device * pdev,int interface,char * name,int namelen)8141d96047eSMarkus Pfeiffer libusb_get_driver_np(struct libusb20_device *pdev, int interface,
8151d96047eSMarkus Pfeiffer     char *name, int namelen)
8161d96047eSMarkus Pfeiffer {
8171d96047eSMarkus Pfeiffer 	return (libusb_get_driver(pdev, interface, name, namelen));
8181d96047eSMarkus Pfeiffer }
8191d96047eSMarkus Pfeiffer 
8201d96047eSMarkus Pfeiffer int
libusb_get_driver(struct libusb20_device * pdev,int interface,char * name,int namelen)8211d96047eSMarkus Pfeiffer libusb_get_driver(struct libusb20_device *pdev, int interface,
8221d96047eSMarkus Pfeiffer     char *name, int namelen)
8231d96047eSMarkus Pfeiffer {
8241d96047eSMarkus Pfeiffer 	char *ptr;
8251d96047eSMarkus Pfeiffer 	int err;
8261d96047eSMarkus Pfeiffer 
8271d96047eSMarkus Pfeiffer 	if (pdev == NULL)
8281d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
8291d96047eSMarkus Pfeiffer 	if (namelen < 1)
8301d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
8311d96047eSMarkus Pfeiffer 	if (namelen > 255)
8321d96047eSMarkus Pfeiffer 		namelen = 255;
8331d96047eSMarkus Pfeiffer 
8341d96047eSMarkus Pfeiffer 	err = libusb20_dev_get_iface_desc(
8351d96047eSMarkus Pfeiffer 	    pdev, interface, name, namelen);
8361d96047eSMarkus Pfeiffer 
8371d96047eSMarkus Pfeiffer 	if (err != 0)
8381d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_OTHER);
8391d96047eSMarkus Pfeiffer 
8401d96047eSMarkus Pfeiffer 	/* we only want the driver name */
8411d96047eSMarkus Pfeiffer 	ptr = strstr(name, ":");
8421d96047eSMarkus Pfeiffer 	if (ptr != NULL)
8431d96047eSMarkus Pfeiffer 		*ptr = 0;
8441d96047eSMarkus Pfeiffer 
8451d96047eSMarkus Pfeiffer 	return (0);
8461d96047eSMarkus Pfeiffer }
8471d96047eSMarkus Pfeiffer 
8481d96047eSMarkus Pfeiffer int
libusb_detach_kernel_driver_np(struct libusb20_device * pdev,int interface)8491d96047eSMarkus Pfeiffer libusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface)
8501d96047eSMarkus Pfeiffer {
8511d96047eSMarkus Pfeiffer 	return (libusb_detach_kernel_driver(pdev, interface));
8521d96047eSMarkus Pfeiffer }
8531d96047eSMarkus Pfeiffer 
8541d96047eSMarkus Pfeiffer int
libusb_detach_kernel_driver(struct libusb20_device * pdev,int interface)8551d96047eSMarkus Pfeiffer libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface)
8561d96047eSMarkus Pfeiffer {
8571d96047eSMarkus Pfeiffer 	int err;
8581d96047eSMarkus Pfeiffer 
8591d96047eSMarkus Pfeiffer 	if (pdev == NULL)
8601d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
8611d96047eSMarkus Pfeiffer 
8621d96047eSMarkus Pfeiffer 	err = libusb20_dev_detach_kernel_driver(
8631d96047eSMarkus Pfeiffer 	    pdev, interface);
8641d96047eSMarkus Pfeiffer 
8651d96047eSMarkus Pfeiffer 	return (err ? LIBUSB_ERROR_OTHER : 0);
8661d96047eSMarkus Pfeiffer }
8671d96047eSMarkus Pfeiffer 
8681d96047eSMarkus Pfeiffer int
libusb_attach_kernel_driver(struct libusb20_device * pdev,int interface)8691d96047eSMarkus Pfeiffer libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface)
8701d96047eSMarkus Pfeiffer {
8711d96047eSMarkus Pfeiffer 	if (pdev == NULL)
8721d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
8731d96047eSMarkus Pfeiffer 	/* stub - currently not supported by libusb20 */
8741d96047eSMarkus Pfeiffer 	return (0);
8751d96047eSMarkus Pfeiffer }
8761d96047eSMarkus Pfeiffer 
8771d96047eSMarkus Pfeiffer /* Asynchronous device I/O */
8781d96047eSMarkus Pfeiffer 
8791d96047eSMarkus Pfeiffer struct libusb_transfer *
libusb_alloc_transfer(int iso_packets)8801d96047eSMarkus Pfeiffer libusb_alloc_transfer(int iso_packets)
8811d96047eSMarkus Pfeiffer {
8821d96047eSMarkus Pfeiffer 	struct libusb_transfer *uxfer;
8831d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
8841d96047eSMarkus Pfeiffer 	int len;
8851d96047eSMarkus Pfeiffer 
8861d96047eSMarkus Pfeiffer 	len = sizeof(struct libusb_transfer) +
8871d96047eSMarkus Pfeiffer 	    sizeof(struct libusb_super_transfer) +
8881d96047eSMarkus Pfeiffer 	    (iso_packets * sizeof(libusb_iso_packet_descriptor));
8891d96047eSMarkus Pfeiffer 
8901d96047eSMarkus Pfeiffer 	sxfer = malloc(len);
8911d96047eSMarkus Pfeiffer 	if (sxfer == NULL)
8921d96047eSMarkus Pfeiffer 		return (NULL);
8931d96047eSMarkus Pfeiffer 
8941d96047eSMarkus Pfeiffer 	memset(sxfer, 0, len);
8951d96047eSMarkus Pfeiffer 
8961d96047eSMarkus Pfeiffer 	uxfer = (struct libusb_transfer *)(
8971d96047eSMarkus Pfeiffer 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
8981d96047eSMarkus Pfeiffer 
8991d96047eSMarkus Pfeiffer 	/* set default value */
9001d96047eSMarkus Pfeiffer 	uxfer->num_iso_packets = iso_packets;
9011d96047eSMarkus Pfeiffer 
9021d96047eSMarkus Pfeiffer 	return (uxfer);
9031d96047eSMarkus Pfeiffer }
9041d96047eSMarkus Pfeiffer 
9051d96047eSMarkus Pfeiffer void
libusb_free_transfer(struct libusb_transfer * uxfer)9061d96047eSMarkus Pfeiffer libusb_free_transfer(struct libusb_transfer *uxfer)
9071d96047eSMarkus Pfeiffer {
9081d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
9091d96047eSMarkus Pfeiffer 
9101d96047eSMarkus Pfeiffer 	if (uxfer == NULL)
9111d96047eSMarkus Pfeiffer 		return;			/* be NULL safe */
9121d96047eSMarkus Pfeiffer 
9131d96047eSMarkus Pfeiffer 	/* check if we should free the transfer buffer */
9141d96047eSMarkus Pfeiffer 	if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
9151d96047eSMarkus Pfeiffer 		free(uxfer->buffer);
9161d96047eSMarkus Pfeiffer 
9171d96047eSMarkus Pfeiffer 	sxfer = (struct libusb_super_transfer *)(
9181d96047eSMarkus Pfeiffer 	    (uint8_t *)uxfer - sizeof(*sxfer));
9191d96047eSMarkus Pfeiffer 
9201d96047eSMarkus Pfeiffer 	free(sxfer);
9211d96047eSMarkus Pfeiffer }
9221d96047eSMarkus Pfeiffer 
9231d96047eSMarkus Pfeiffer static uint32_t
libusb10_get_maxframe(struct libusb20_device * pdev,libusb_transfer * xfer)9241d96047eSMarkus Pfeiffer libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer)
9251d96047eSMarkus Pfeiffer {
9261d96047eSMarkus Pfeiffer 	uint32_t ret;
9271d96047eSMarkus Pfeiffer 
9281d96047eSMarkus Pfeiffer 	switch (xfer->type) {
9291d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
9301d96047eSMarkus Pfeiffer 		ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE;	/* 60ms */
9311d96047eSMarkus Pfeiffer 		break;
9321d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_CONTROL:
9331d96047eSMarkus Pfeiffer 		ret = 2;
9341d96047eSMarkus Pfeiffer 		break;
9351d96047eSMarkus Pfeiffer 	default:
9361d96047eSMarkus Pfeiffer 		ret = 1;
9371d96047eSMarkus Pfeiffer 		break;
9381d96047eSMarkus Pfeiffer 	}
9391d96047eSMarkus Pfeiffer 	return (ret);
9401d96047eSMarkus Pfeiffer }
9411d96047eSMarkus Pfeiffer 
9421d96047eSMarkus Pfeiffer static int
libusb10_get_buffsize(struct libusb20_device * pdev,libusb_transfer * xfer)9431d96047eSMarkus Pfeiffer libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer)
9441d96047eSMarkus Pfeiffer {
9451d96047eSMarkus Pfeiffer 	int ret;
9461d96047eSMarkus Pfeiffer 	int usb_speed;
9471d96047eSMarkus Pfeiffer 
9481d96047eSMarkus Pfeiffer 	usb_speed = libusb20_dev_get_speed(pdev);
9491d96047eSMarkus Pfeiffer 
9501d96047eSMarkus Pfeiffer 	switch (xfer->type) {
9511d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
9521d96047eSMarkus Pfeiffer 		ret = 0;		/* kernel will auto-select */
9531d96047eSMarkus Pfeiffer 		break;
9541d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_CONTROL:
9551d96047eSMarkus Pfeiffer 		ret = 1024;
9561d96047eSMarkus Pfeiffer 		break;
9571d96047eSMarkus Pfeiffer 	default:
9581d96047eSMarkus Pfeiffer 		switch (usb_speed) {
9591d96047eSMarkus Pfeiffer 		case LIBUSB20_SPEED_LOW:
9601d96047eSMarkus Pfeiffer 			ret = 256;
9611d96047eSMarkus Pfeiffer 			break;
9621d96047eSMarkus Pfeiffer 		case LIBUSB20_SPEED_FULL:
9631d96047eSMarkus Pfeiffer 			ret = 4096;
9641d96047eSMarkus Pfeiffer 			break;
965c5739aa6SSascha Wildner 		case LIBUSB20_SPEED_SUPER:
966c5739aa6SSascha Wildner 			ret = 65536;
967c5739aa6SSascha Wildner 			break;
9681d96047eSMarkus Pfeiffer 		default:
9691d96047eSMarkus Pfeiffer 			ret = 16384;
9701d96047eSMarkus Pfeiffer 			break;
9711d96047eSMarkus Pfeiffer 		}
9721d96047eSMarkus Pfeiffer 		break;
9731d96047eSMarkus Pfeiffer 	}
9741d96047eSMarkus Pfeiffer 	return (ret);
9751d96047eSMarkus Pfeiffer }
9761d96047eSMarkus Pfeiffer 
9771d96047eSMarkus Pfeiffer static int
libusb10_convert_error(uint8_t status)9781d96047eSMarkus Pfeiffer libusb10_convert_error(uint8_t status)
9791d96047eSMarkus Pfeiffer {
9801d96047eSMarkus Pfeiffer 	;				/* indent fix */
9811d96047eSMarkus Pfeiffer 
9821d96047eSMarkus Pfeiffer 	switch (status) {
9831d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_START:
9841d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_COMPLETED:
9851d96047eSMarkus Pfeiffer 		return (LIBUSB_TRANSFER_COMPLETED);
9861d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_OVERFLOW:
9871d96047eSMarkus Pfeiffer 		return (LIBUSB_TRANSFER_OVERFLOW);
9881d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_NO_DEVICE:
9891d96047eSMarkus Pfeiffer 		return (LIBUSB_TRANSFER_NO_DEVICE);
9901d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_STALL:
9911d96047eSMarkus Pfeiffer 		return (LIBUSB_TRANSFER_STALL);
9921d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_CANCELLED:
9931d96047eSMarkus Pfeiffer 		return (LIBUSB_TRANSFER_CANCELLED);
9941d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_TIMED_OUT:
9951d96047eSMarkus Pfeiffer 		return (LIBUSB_TRANSFER_TIMED_OUT);
9961d96047eSMarkus Pfeiffer 	default:
9971d96047eSMarkus Pfeiffer 		return (LIBUSB_TRANSFER_ERROR);
9981d96047eSMarkus Pfeiffer 	}
9991d96047eSMarkus Pfeiffer }
10001d96047eSMarkus Pfeiffer 
10011d96047eSMarkus Pfeiffer /* This function must be called locked */
10021d96047eSMarkus Pfeiffer 
10031d96047eSMarkus Pfeiffer static void
libusb10_complete_transfer(struct libusb20_transfer * pxfer,struct libusb_super_transfer * sxfer,int status)10041d96047eSMarkus Pfeiffer libusb10_complete_transfer(struct libusb20_transfer *pxfer,
10051d96047eSMarkus Pfeiffer     struct libusb_super_transfer *sxfer, int status)
10061d96047eSMarkus Pfeiffer {
10071d96047eSMarkus Pfeiffer 	struct libusb_transfer *uxfer;
10081d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
10091d96047eSMarkus Pfeiffer 
10101d96047eSMarkus Pfeiffer 	uxfer = (struct libusb_transfer *)(
10111d96047eSMarkus Pfeiffer 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
10121d96047eSMarkus Pfeiffer 
10131d96047eSMarkus Pfeiffer 	if (pxfer != NULL)
10141d96047eSMarkus Pfeiffer 		libusb20_tr_set_priv_sc1(pxfer, NULL);
10151d96047eSMarkus Pfeiffer 
10161d96047eSMarkus Pfeiffer 	/* set transfer status */
10171d96047eSMarkus Pfeiffer 	uxfer->status = status;
10181d96047eSMarkus Pfeiffer 
10191d96047eSMarkus Pfeiffer 	/* update super transfer state */
10201d96047eSMarkus Pfeiffer 	sxfer->state = LIBUSB_SUPER_XFER_ST_NONE;
10211d96047eSMarkus Pfeiffer 
10221d96047eSMarkus Pfeiffer 	dev = libusb_get_device(uxfer->dev_handle);
10231d96047eSMarkus Pfeiffer 
10241d96047eSMarkus Pfeiffer 	TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry);
10251d96047eSMarkus Pfeiffer }
10261d96047eSMarkus Pfeiffer 
10271d96047eSMarkus Pfeiffer /* This function must be called locked */
10281d96047eSMarkus Pfeiffer 
10291d96047eSMarkus Pfeiffer static void
libusb10_isoc_proxy(struct libusb20_transfer * pxfer)10301d96047eSMarkus Pfeiffer libusb10_isoc_proxy(struct libusb20_transfer *pxfer)
10311d96047eSMarkus Pfeiffer {
10321d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
10331d96047eSMarkus Pfeiffer 	struct libusb_transfer *uxfer;
10341d96047eSMarkus Pfeiffer 	uint32_t actlen;
10351d96047eSMarkus Pfeiffer 	uint16_t iso_packets;
10361d96047eSMarkus Pfeiffer 	uint16_t i;
10371d96047eSMarkus Pfeiffer 	uint8_t status;
10389b0c1abeSSascha Wildner 	uint8_t flags;
10391d96047eSMarkus Pfeiffer 
10401d96047eSMarkus Pfeiffer 	status = libusb20_tr_get_status(pxfer);
10411d96047eSMarkus Pfeiffer 	sxfer = libusb20_tr_get_priv_sc1(pxfer);
10421d96047eSMarkus Pfeiffer 	actlen = libusb20_tr_get_actual_length(pxfer);
10431d96047eSMarkus Pfeiffer 	iso_packets = libusb20_tr_get_max_frames(pxfer);
10441d96047eSMarkus Pfeiffer 
10451d96047eSMarkus Pfeiffer 	if (sxfer == NULL)
10461d96047eSMarkus Pfeiffer 		return;			/* cancelled - nothing to do */
10471d96047eSMarkus Pfeiffer 
10481d96047eSMarkus Pfeiffer 	uxfer = (struct libusb_transfer *)(
10491d96047eSMarkus Pfeiffer 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
10501d96047eSMarkus Pfeiffer 
10511d96047eSMarkus Pfeiffer 	if (iso_packets > uxfer->num_iso_packets)
10521d96047eSMarkus Pfeiffer 		iso_packets = uxfer->num_iso_packets;
10531d96047eSMarkus Pfeiffer 
10541d96047eSMarkus Pfeiffer 	if (iso_packets == 0)
10551d96047eSMarkus Pfeiffer 		return;			/* nothing to do */
10561d96047eSMarkus Pfeiffer 
10571d96047eSMarkus Pfeiffer 	/* make sure that the number of ISOCHRONOUS packets is valid */
10581d96047eSMarkus Pfeiffer 	uxfer->num_iso_packets = iso_packets;
10591d96047eSMarkus Pfeiffer 
10609b0c1abeSSascha Wildner 	flags = uxfer->flags;
10619b0c1abeSSascha Wildner 
10621d96047eSMarkus Pfeiffer 	switch (status) {
10631d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_COMPLETED:
10641d96047eSMarkus Pfeiffer 
10651d96047eSMarkus Pfeiffer 		/* update actual length */
10661d96047eSMarkus Pfeiffer 		uxfer->actual_length = actlen;
10671d96047eSMarkus Pfeiffer 		for (i = 0; i != iso_packets; i++) {
10681d96047eSMarkus Pfeiffer 			uxfer->iso_packet_desc[i].actual_length =
10691d96047eSMarkus Pfeiffer 			    libusb20_tr_get_length(pxfer, i);
10701d96047eSMarkus Pfeiffer 		}
10711d96047eSMarkus Pfeiffer 		libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
10721d96047eSMarkus Pfeiffer 		break;
10731d96047eSMarkus Pfeiffer 
10741d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_START:
10751d96047eSMarkus Pfeiffer 
10761d96047eSMarkus Pfeiffer 		/* setup length(s) */
10771d96047eSMarkus Pfeiffer 		actlen = 0;
10781d96047eSMarkus Pfeiffer 		for (i = 0; i != iso_packets; i++) {
10791d96047eSMarkus Pfeiffer 			libusb20_tr_setup_isoc(pxfer,
10801d96047eSMarkus Pfeiffer 			    &uxfer->buffer[actlen],
10811d96047eSMarkus Pfeiffer 			    uxfer->iso_packet_desc[i].length, i);
10821d96047eSMarkus Pfeiffer 			actlen += uxfer->iso_packet_desc[i].length;
10831d96047eSMarkus Pfeiffer 		}
10841d96047eSMarkus Pfeiffer 
10851d96047eSMarkus Pfeiffer 		/* no remainder */
10861d96047eSMarkus Pfeiffer 		sxfer->rem_len = 0;
10871d96047eSMarkus Pfeiffer 
10881d96047eSMarkus Pfeiffer 		libusb20_tr_set_total_frames(pxfer, iso_packets);
10891d96047eSMarkus Pfeiffer 		libusb20_tr_submit(pxfer);
10901d96047eSMarkus Pfeiffer 
10911d96047eSMarkus Pfeiffer 		/* fork another USB transfer, if any */
10921d96047eSMarkus Pfeiffer 		libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
10931d96047eSMarkus Pfeiffer 		break;
10941d96047eSMarkus Pfeiffer 
10951d96047eSMarkus Pfeiffer 	default:
10961d96047eSMarkus Pfeiffer 		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
10971d96047eSMarkus Pfeiffer 		break;
10981d96047eSMarkus Pfeiffer 	}
10991d96047eSMarkus Pfeiffer }
11001d96047eSMarkus Pfeiffer 
11011d96047eSMarkus Pfeiffer /* This function must be called locked */
11021d96047eSMarkus Pfeiffer 
11031d96047eSMarkus Pfeiffer static void
libusb10_bulk_intr_proxy(struct libusb20_transfer * pxfer)11041d96047eSMarkus Pfeiffer libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer)
11051d96047eSMarkus Pfeiffer {
11061d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
11071d96047eSMarkus Pfeiffer 	struct libusb_transfer *uxfer;
11081d96047eSMarkus Pfeiffer 	uint32_t max_bulk;
11091d96047eSMarkus Pfeiffer 	uint32_t actlen;
11101d96047eSMarkus Pfeiffer 	uint8_t status;
11111d96047eSMarkus Pfeiffer 	uint8_t flags;
11121d96047eSMarkus Pfeiffer 
11131d96047eSMarkus Pfeiffer 	status = libusb20_tr_get_status(pxfer);
11141d96047eSMarkus Pfeiffer 	sxfer = libusb20_tr_get_priv_sc1(pxfer);
11151d96047eSMarkus Pfeiffer 	max_bulk = libusb20_tr_get_max_total_length(pxfer);
11161d96047eSMarkus Pfeiffer 	actlen = libusb20_tr_get_actual_length(pxfer);
11171d96047eSMarkus Pfeiffer 
11181d96047eSMarkus Pfeiffer 	if (sxfer == NULL)
11191d96047eSMarkus Pfeiffer 		return;			/* cancelled - nothing to do */
11201d96047eSMarkus Pfeiffer 
11211d96047eSMarkus Pfeiffer 	uxfer = (struct libusb_transfer *)(
11221d96047eSMarkus Pfeiffer 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
11231d96047eSMarkus Pfeiffer 
11241d96047eSMarkus Pfeiffer 	flags = uxfer->flags;
11251d96047eSMarkus Pfeiffer 
11261d96047eSMarkus Pfeiffer 	switch (status) {
11271d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_COMPLETED:
11281d96047eSMarkus Pfeiffer 
11291d96047eSMarkus Pfeiffer 		uxfer->actual_length += actlen;
11301d96047eSMarkus Pfeiffer 
11311d96047eSMarkus Pfeiffer 		/* check for short packet */
11321d96047eSMarkus Pfeiffer 		if (sxfer->last_len != actlen) {
11331d96047eSMarkus Pfeiffer 			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
11341d96047eSMarkus Pfeiffer 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
11351d96047eSMarkus Pfeiffer 			} else {
11361d96047eSMarkus Pfeiffer 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
11371d96047eSMarkus Pfeiffer 			}
11381d96047eSMarkus Pfeiffer 			break;
11391d96047eSMarkus Pfeiffer 		}
11401d96047eSMarkus Pfeiffer 		/* check for end of data */
11411d96047eSMarkus Pfeiffer 		if (sxfer->rem_len == 0) {
11421d96047eSMarkus Pfeiffer 			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
11431d96047eSMarkus Pfeiffer 			break;
11441d96047eSMarkus Pfeiffer 		}
11451d96047eSMarkus Pfeiffer 		/* FALLTHROUGH */
11461d96047eSMarkus Pfeiffer 
11471d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_START:
11481d96047eSMarkus Pfeiffer 		if (max_bulk > sxfer->rem_len) {
11491d96047eSMarkus Pfeiffer 			max_bulk = sxfer->rem_len;
11501d96047eSMarkus Pfeiffer 		}
11511d96047eSMarkus Pfeiffer 		/* setup new BULK or INTERRUPT transaction */
11521d96047eSMarkus Pfeiffer 		libusb20_tr_setup_bulk(pxfer,
11531d96047eSMarkus Pfeiffer 		    sxfer->curr_data, max_bulk, uxfer->timeout);
11541d96047eSMarkus Pfeiffer 
11551d96047eSMarkus Pfeiffer 		/* update counters */
11561d96047eSMarkus Pfeiffer 		sxfer->last_len = max_bulk;
11571d96047eSMarkus Pfeiffer 		sxfer->curr_data += max_bulk;
11581d96047eSMarkus Pfeiffer 		sxfer->rem_len -= max_bulk;
11591d96047eSMarkus Pfeiffer 
11601d96047eSMarkus Pfeiffer 		libusb20_tr_submit(pxfer);
11611d96047eSMarkus Pfeiffer 
11621d96047eSMarkus Pfeiffer 		/* check if we can fork another USB transfer */
11631d96047eSMarkus Pfeiffer 		if (sxfer->rem_len == 0)
11641d96047eSMarkus Pfeiffer 			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
11651d96047eSMarkus Pfeiffer 		break;
11661d96047eSMarkus Pfeiffer 
11671d96047eSMarkus Pfeiffer 	default:
11681d96047eSMarkus Pfeiffer 		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
11691d96047eSMarkus Pfeiffer 		break;
11701d96047eSMarkus Pfeiffer 	}
11711d96047eSMarkus Pfeiffer }
11721d96047eSMarkus Pfeiffer 
11731d96047eSMarkus Pfeiffer /* This function must be called locked */
11741d96047eSMarkus Pfeiffer 
11751d96047eSMarkus Pfeiffer static void
libusb10_ctrl_proxy(struct libusb20_transfer * pxfer)11761d96047eSMarkus Pfeiffer libusb10_ctrl_proxy(struct libusb20_transfer *pxfer)
11771d96047eSMarkus Pfeiffer {
11781d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
11791d96047eSMarkus Pfeiffer 	struct libusb_transfer *uxfer;
11801d96047eSMarkus Pfeiffer 	uint32_t max_bulk;
11811d96047eSMarkus Pfeiffer 	uint32_t actlen;
11821d96047eSMarkus Pfeiffer 	uint8_t status;
11831d96047eSMarkus Pfeiffer 	uint8_t flags;
11841d96047eSMarkus Pfeiffer 
11851d96047eSMarkus Pfeiffer 	status = libusb20_tr_get_status(pxfer);
11861d96047eSMarkus Pfeiffer 	sxfer = libusb20_tr_get_priv_sc1(pxfer);
11871d96047eSMarkus Pfeiffer 	max_bulk = libusb20_tr_get_max_total_length(pxfer);
11881d96047eSMarkus Pfeiffer 	actlen = libusb20_tr_get_actual_length(pxfer);
11891d96047eSMarkus Pfeiffer 
11901d96047eSMarkus Pfeiffer 	if (sxfer == NULL)
11911d96047eSMarkus Pfeiffer 		return;			/* cancelled - nothing to do */
11921d96047eSMarkus Pfeiffer 
11931d96047eSMarkus Pfeiffer 	uxfer = (struct libusb_transfer *)(
11941d96047eSMarkus Pfeiffer 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
11951d96047eSMarkus Pfeiffer 
11961d96047eSMarkus Pfeiffer 	flags = uxfer->flags;
11971d96047eSMarkus Pfeiffer 
11981d96047eSMarkus Pfeiffer 	switch (status) {
11991d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_COMPLETED:
12001d96047eSMarkus Pfeiffer 
12011d96047eSMarkus Pfeiffer 		uxfer->actual_length += actlen;
12021d96047eSMarkus Pfeiffer 
12031d96047eSMarkus Pfeiffer 		/* subtract length of SETUP packet, if any */
12041d96047eSMarkus Pfeiffer 		actlen -= libusb20_tr_get_length(pxfer, 0);
12051d96047eSMarkus Pfeiffer 
12061d96047eSMarkus Pfeiffer 		/* check for short packet */
12071d96047eSMarkus Pfeiffer 		if (sxfer->last_len != actlen) {
12081d96047eSMarkus Pfeiffer 			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
12091d96047eSMarkus Pfeiffer 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
12101d96047eSMarkus Pfeiffer 			} else {
12111d96047eSMarkus Pfeiffer 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
12121d96047eSMarkus Pfeiffer 			}
12131d96047eSMarkus Pfeiffer 			break;
12141d96047eSMarkus Pfeiffer 		}
12151d96047eSMarkus Pfeiffer 		/* check for end of data */
12161d96047eSMarkus Pfeiffer 		if (sxfer->rem_len == 0) {
12171d96047eSMarkus Pfeiffer 			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
12181d96047eSMarkus Pfeiffer 			break;
12191d96047eSMarkus Pfeiffer 		}
12201d96047eSMarkus Pfeiffer 		/* FALLTHROUGH */
12211d96047eSMarkus Pfeiffer 
12221d96047eSMarkus Pfeiffer 	case LIBUSB20_TRANSFER_START:
12231d96047eSMarkus Pfeiffer 		if (max_bulk > sxfer->rem_len) {
12241d96047eSMarkus Pfeiffer 			max_bulk = sxfer->rem_len;
12251d96047eSMarkus Pfeiffer 		}
12261d96047eSMarkus Pfeiffer 		/* setup new CONTROL transaction */
12271d96047eSMarkus Pfeiffer 		if (status == LIBUSB20_TRANSFER_COMPLETED) {
12281d96047eSMarkus Pfeiffer 			/* next fragment - don't send SETUP packet */
12291d96047eSMarkus Pfeiffer 			libusb20_tr_set_length(pxfer, 0, 0);
12301d96047eSMarkus Pfeiffer 		} else {
12311d96047eSMarkus Pfeiffer 			/* first fragment - send SETUP packet */
12321d96047eSMarkus Pfeiffer 			libusb20_tr_set_length(pxfer, 8, 0);
12331d96047eSMarkus Pfeiffer 			libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0);
12341d96047eSMarkus Pfeiffer 		}
12351d96047eSMarkus Pfeiffer 
12361d96047eSMarkus Pfeiffer 		if (max_bulk != 0) {
12371d96047eSMarkus Pfeiffer 			libusb20_tr_set_length(pxfer, max_bulk, 1);
12381d96047eSMarkus Pfeiffer 			libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1);
12391d96047eSMarkus Pfeiffer 			libusb20_tr_set_total_frames(pxfer, 2);
12401d96047eSMarkus Pfeiffer 		} else {
12411d96047eSMarkus Pfeiffer 			libusb20_tr_set_total_frames(pxfer, 1);
12421d96047eSMarkus Pfeiffer 		}
12431d96047eSMarkus Pfeiffer 
12441d96047eSMarkus Pfeiffer 		/* update counters */
12451d96047eSMarkus Pfeiffer 		sxfer->last_len = max_bulk;
12461d96047eSMarkus Pfeiffer 		sxfer->curr_data += max_bulk;
12471d96047eSMarkus Pfeiffer 		sxfer->rem_len -= max_bulk;
12481d96047eSMarkus Pfeiffer 
12491d96047eSMarkus Pfeiffer 		libusb20_tr_submit(pxfer);
12501d96047eSMarkus Pfeiffer 
12511d96047eSMarkus Pfeiffer 		/* check if we can fork another USB transfer */
12521d96047eSMarkus Pfeiffer 		if (sxfer->rem_len == 0)
12531d96047eSMarkus Pfeiffer 			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
12541d96047eSMarkus Pfeiffer 		break;
12551d96047eSMarkus Pfeiffer 
12561d96047eSMarkus Pfeiffer 	default:
12571d96047eSMarkus Pfeiffer 		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
12581d96047eSMarkus Pfeiffer 		break;
12591d96047eSMarkus Pfeiffer 	}
12601d96047eSMarkus Pfeiffer }
12611d96047eSMarkus Pfeiffer 
12621d96047eSMarkus Pfeiffer /* The following function must be called locked */
12631d96047eSMarkus Pfeiffer 
12641d96047eSMarkus Pfeiffer static void
libusb10_submit_transfer_sub(struct libusb20_device * pdev,uint8_t endpoint)12651d96047eSMarkus Pfeiffer libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint)
12661d96047eSMarkus Pfeiffer {
12671d96047eSMarkus Pfeiffer 	struct libusb20_transfer *pxfer0;
12681d96047eSMarkus Pfeiffer 	struct libusb20_transfer *pxfer1;
12691d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
12701d96047eSMarkus Pfeiffer 	struct libusb_transfer *uxfer;
12711d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
12721d96047eSMarkus Pfeiffer 	int err;
12731d96047eSMarkus Pfeiffer 	int buffsize;
12741d96047eSMarkus Pfeiffer 	int maxframe;
12751d96047eSMarkus Pfeiffer 	int temp;
12761d96047eSMarkus Pfeiffer 	uint8_t dummy;
12771d96047eSMarkus Pfeiffer 
12781d96047eSMarkus Pfeiffer 	dev = libusb_get_device(pdev);
12791d96047eSMarkus Pfeiffer 
12801d96047eSMarkus Pfeiffer 	pxfer0 = libusb10_get_transfer(pdev, endpoint, 0);
12811d96047eSMarkus Pfeiffer 	pxfer1 = libusb10_get_transfer(pdev, endpoint, 1);
12821d96047eSMarkus Pfeiffer 
12831d96047eSMarkus Pfeiffer 	if (pxfer0 == NULL || pxfer1 == NULL)
12841d96047eSMarkus Pfeiffer 		return;			/* shouldn't happen */
12851d96047eSMarkus Pfeiffer 
12861d96047eSMarkus Pfeiffer 	temp = 0;
12871d96047eSMarkus Pfeiffer 	if (libusb20_tr_pending(pxfer0))
12881d96047eSMarkus Pfeiffer 		temp |= 1;
12891d96047eSMarkus Pfeiffer 	if (libusb20_tr_pending(pxfer1))
12901d96047eSMarkus Pfeiffer 		temp |= 2;
12911d96047eSMarkus Pfeiffer 
12921d96047eSMarkus Pfeiffer 	switch (temp) {
12931d96047eSMarkus Pfeiffer 	case 3:
12941d96047eSMarkus Pfeiffer 		/* wait till one of the transfers complete */
12951d96047eSMarkus Pfeiffer 		return;
12961d96047eSMarkus Pfeiffer 	case 2:
12971d96047eSMarkus Pfeiffer 		sxfer = libusb20_tr_get_priv_sc1(pxfer1);
12981d96047eSMarkus Pfeiffer 		if (sxfer == NULL)
12991d96047eSMarkus Pfeiffer 			return;		/* cancelling */
13001d96047eSMarkus Pfeiffer 		if (sxfer->rem_len)
13011d96047eSMarkus Pfeiffer 			return;		/* cannot queue another one */
13021d96047eSMarkus Pfeiffer 		/* swap transfers */
13031d96047eSMarkus Pfeiffer 		pxfer1 = pxfer0;
13041d96047eSMarkus Pfeiffer 		break;
13051d96047eSMarkus Pfeiffer 	case 1:
13061d96047eSMarkus Pfeiffer 		sxfer = libusb20_tr_get_priv_sc1(pxfer0);
13071d96047eSMarkus Pfeiffer 		if (sxfer == NULL)
13081d96047eSMarkus Pfeiffer 			return;		/* cancelling */
13091d96047eSMarkus Pfeiffer 		if (sxfer->rem_len)
13101d96047eSMarkus Pfeiffer 			return;		/* cannot queue another one */
13111d96047eSMarkus Pfeiffer 		/* swap transfers */
13121d96047eSMarkus Pfeiffer 		pxfer0 = pxfer1;
13131d96047eSMarkus Pfeiffer 		break;
13141d96047eSMarkus Pfeiffer 	default:
13151d96047eSMarkus Pfeiffer 		break;
13161d96047eSMarkus Pfeiffer 	}
13171d96047eSMarkus Pfeiffer 
13181d96047eSMarkus Pfeiffer 	/* find next transfer on same endpoint */
13191d96047eSMarkus Pfeiffer 	TAILQ_FOREACH(sxfer, &dev->tr_head, entry) {
13201d96047eSMarkus Pfeiffer 
13211d96047eSMarkus Pfeiffer 		uxfer = (struct libusb_transfer *)(
13221d96047eSMarkus Pfeiffer 		    ((uint8_t *)sxfer) + sizeof(*sxfer));
13231d96047eSMarkus Pfeiffer 
13241d96047eSMarkus Pfeiffer 		if (uxfer->endpoint == endpoint) {
13251d96047eSMarkus Pfeiffer 			TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
13261d96047eSMarkus Pfeiffer 			sxfer->entry.tqe_prev = NULL;
13271d96047eSMarkus Pfeiffer 			goto found;
13281d96047eSMarkus Pfeiffer 		}
13291d96047eSMarkus Pfeiffer 	}
13301d96047eSMarkus Pfeiffer 	return;				/* success */
13311d96047eSMarkus Pfeiffer 
13321d96047eSMarkus Pfeiffer found:
13331d96047eSMarkus Pfeiffer 
13341d96047eSMarkus Pfeiffer 	libusb20_tr_set_priv_sc0(pxfer0, pdev);
13351d96047eSMarkus Pfeiffer 	libusb20_tr_set_priv_sc1(pxfer0, sxfer);
13361d96047eSMarkus Pfeiffer 
13371d96047eSMarkus Pfeiffer 	/* reset super transfer state */
13381d96047eSMarkus Pfeiffer 	sxfer->rem_len = uxfer->length;
13391d96047eSMarkus Pfeiffer 	sxfer->curr_data = uxfer->buffer;
13401d96047eSMarkus Pfeiffer 	uxfer->actual_length = 0;
13411d96047eSMarkus Pfeiffer 
13421d96047eSMarkus Pfeiffer 	switch (uxfer->type) {
13431d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
13441d96047eSMarkus Pfeiffer 		libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
13451d96047eSMarkus Pfeiffer 		break;
13461d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_BULK:
13471d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
13481d96047eSMarkus Pfeiffer 		libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
13491d96047eSMarkus Pfeiffer 		break;
13501d96047eSMarkus Pfeiffer 	case LIBUSB_TRANSFER_TYPE_CONTROL:
13511d96047eSMarkus Pfeiffer 		libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy);
13521d96047eSMarkus Pfeiffer 		if (sxfer->rem_len < 8)
13531d96047eSMarkus Pfeiffer 			goto failure;
13541d96047eSMarkus Pfeiffer 
13551d96047eSMarkus Pfeiffer 		/* remove SETUP packet from data */
13561d96047eSMarkus Pfeiffer 		sxfer->rem_len -= 8;
13571d96047eSMarkus Pfeiffer 		sxfer->curr_data += 8;
13581d96047eSMarkus Pfeiffer 		break;
13591d96047eSMarkus Pfeiffer 	default:
13601d96047eSMarkus Pfeiffer 		goto failure;
13611d96047eSMarkus Pfeiffer 	}
13621d96047eSMarkus Pfeiffer 
13631d96047eSMarkus Pfeiffer 	buffsize = libusb10_get_buffsize(pdev, uxfer);
13641d96047eSMarkus Pfeiffer 	maxframe = libusb10_get_maxframe(pdev, uxfer);
13651d96047eSMarkus Pfeiffer 
13661d96047eSMarkus Pfeiffer 	/* make sure the transfer is opened */
13671d96047eSMarkus Pfeiffer 	err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint);
13681d96047eSMarkus Pfeiffer 	if (err && (err != LIBUSB20_ERROR_BUSY)) {
13691d96047eSMarkus Pfeiffer 		goto failure;
13701d96047eSMarkus Pfeiffer 	}
13711d96047eSMarkus Pfeiffer 	libusb20_tr_start(pxfer0);
13721d96047eSMarkus Pfeiffer 	return;
13731d96047eSMarkus Pfeiffer 
13741d96047eSMarkus Pfeiffer failure:
13751d96047eSMarkus Pfeiffer 	libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
13761d96047eSMarkus Pfeiffer 
13771d96047eSMarkus Pfeiffer 	/* make sure our event loop spins the done handler */
13781d96047eSMarkus Pfeiffer 	dummy = 0;
13799b0c1abeSSascha Wildner 	err = write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
13801d96047eSMarkus Pfeiffer }
13811d96047eSMarkus Pfeiffer 
13821d96047eSMarkus Pfeiffer /* The following function must be called unlocked */
13831d96047eSMarkus Pfeiffer 
13841d96047eSMarkus Pfeiffer int
libusb_submit_transfer(struct libusb_transfer * uxfer)13851d96047eSMarkus Pfeiffer libusb_submit_transfer(struct libusb_transfer *uxfer)
13861d96047eSMarkus Pfeiffer {
13871d96047eSMarkus Pfeiffer 	struct libusb20_transfer *pxfer0;
13881d96047eSMarkus Pfeiffer 	struct libusb20_transfer *pxfer1;
13891d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
13901d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
1391aa3e5c14SSascha Wildner 	uint8_t endpoint;
13921d96047eSMarkus Pfeiffer 	int err;
13931d96047eSMarkus Pfeiffer 
13941d96047eSMarkus Pfeiffer 	if (uxfer == NULL)
13951d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
13961d96047eSMarkus Pfeiffer 
13971d96047eSMarkus Pfeiffer 	if (uxfer->dev_handle == NULL)
13981d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
13991d96047eSMarkus Pfeiffer 
14001d96047eSMarkus Pfeiffer 	endpoint = uxfer->endpoint;
14011d96047eSMarkus Pfeiffer 
14021d96047eSMarkus Pfeiffer 	dev = libusb_get_device(uxfer->dev_handle);
14031d96047eSMarkus Pfeiffer 
14041d96047eSMarkus Pfeiffer 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
14051d96047eSMarkus Pfeiffer 
14061d96047eSMarkus Pfeiffer 	sxfer = (struct libusb_super_transfer *)(
14071d96047eSMarkus Pfeiffer 	    (uint8_t *)uxfer - sizeof(*sxfer));
14081d96047eSMarkus Pfeiffer 
14091d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
14101d96047eSMarkus Pfeiffer 
14111d96047eSMarkus Pfeiffer 	pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
14121d96047eSMarkus Pfeiffer 	pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
14131d96047eSMarkus Pfeiffer 
14141d96047eSMarkus Pfeiffer 	if (pxfer0 == NULL || pxfer1 == NULL) {
14151d96047eSMarkus Pfeiffer 		err = LIBUSB_ERROR_OTHER;
14161d96047eSMarkus Pfeiffer 	} else if ((sxfer->entry.tqe_prev != NULL) ||
14171d96047eSMarkus Pfeiffer 	    (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) ||
14181d96047eSMarkus Pfeiffer 	    (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) {
14191d96047eSMarkus Pfeiffer 		err = LIBUSB_ERROR_BUSY;
14201d96047eSMarkus Pfeiffer 	} else {
14211d96047eSMarkus Pfeiffer 
14221d96047eSMarkus Pfeiffer 		/* set pending state */
14231d96047eSMarkus Pfeiffer 		sxfer->state = LIBUSB_SUPER_XFER_ST_PEND;
14241d96047eSMarkus Pfeiffer 
14251d96047eSMarkus Pfeiffer 		/* insert transfer into transfer head list */
14261d96047eSMarkus Pfeiffer 		TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry);
14271d96047eSMarkus Pfeiffer 
14281d96047eSMarkus Pfeiffer 		/* start work transfers */
14291d96047eSMarkus Pfeiffer 		libusb10_submit_transfer_sub(
14301d96047eSMarkus Pfeiffer 		    uxfer->dev_handle, endpoint);
14311d96047eSMarkus Pfeiffer 
14321d96047eSMarkus Pfeiffer 		err = 0;		/* success */
14331d96047eSMarkus Pfeiffer 	}
14341d96047eSMarkus Pfeiffer 
14351d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
14361d96047eSMarkus Pfeiffer 
14371d96047eSMarkus Pfeiffer 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
14381d96047eSMarkus Pfeiffer 
14391d96047eSMarkus Pfeiffer 	return (err);
14401d96047eSMarkus Pfeiffer }
14411d96047eSMarkus Pfeiffer 
14421d96047eSMarkus Pfeiffer /* Asynchronous transfer cancel */
14431d96047eSMarkus Pfeiffer 
14441d96047eSMarkus Pfeiffer int
libusb_cancel_transfer(struct libusb_transfer * uxfer)14451d96047eSMarkus Pfeiffer libusb_cancel_transfer(struct libusb_transfer *uxfer)
14461d96047eSMarkus Pfeiffer {
14471d96047eSMarkus Pfeiffer 	struct libusb20_transfer *pxfer0;
14481d96047eSMarkus Pfeiffer 	struct libusb20_transfer *pxfer1;
14491d96047eSMarkus Pfeiffer 	struct libusb_super_transfer *sxfer;
14501d96047eSMarkus Pfeiffer 	struct libusb_device *dev;
1451aa3e5c14SSascha Wildner 	uint8_t endpoint;
14521d96047eSMarkus Pfeiffer 	int retval;
14531d96047eSMarkus Pfeiffer 
14541d96047eSMarkus Pfeiffer 	if (uxfer == NULL)
14551d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_INVALID_PARAM);
14561d96047eSMarkus Pfeiffer 
14571d96047eSMarkus Pfeiffer 	/* check if not initialised */
14581d96047eSMarkus Pfeiffer 	if (uxfer->dev_handle == NULL)
14591d96047eSMarkus Pfeiffer 		return (LIBUSB_ERROR_NOT_FOUND);
14601d96047eSMarkus Pfeiffer 
14611d96047eSMarkus Pfeiffer 	endpoint = uxfer->endpoint;
14621d96047eSMarkus Pfeiffer 
14631d96047eSMarkus Pfeiffer 	dev = libusb_get_device(uxfer->dev_handle);
14641d96047eSMarkus Pfeiffer 
14651d96047eSMarkus Pfeiffer 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
14661d96047eSMarkus Pfeiffer 
14671d96047eSMarkus Pfeiffer 	sxfer = (struct libusb_super_transfer *)(
14681d96047eSMarkus Pfeiffer 	    (uint8_t *)uxfer - sizeof(*sxfer));
14691d96047eSMarkus Pfeiffer 
14701d96047eSMarkus Pfeiffer 	retval = 0;
14711d96047eSMarkus Pfeiffer 
14721d96047eSMarkus Pfeiffer 	CTX_LOCK(dev->ctx);
14731d96047eSMarkus Pfeiffer 
14741d96047eSMarkus Pfeiffer 	pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
14751d96047eSMarkus Pfeiffer 	pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
14761d96047eSMarkus Pfeiffer 
14771d96047eSMarkus Pfeiffer 	if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) {
14781d96047eSMarkus Pfeiffer 		/* only update the transfer status */
14791d96047eSMarkus Pfeiffer 		uxfer->status = LIBUSB_TRANSFER_CANCELLED;
14801d96047eSMarkus Pfeiffer 		retval = LIBUSB_ERROR_NOT_FOUND;
14811d96047eSMarkus Pfeiffer 	} else if (sxfer->entry.tqe_prev != NULL) {
14821d96047eSMarkus Pfeiffer 		/* we are lucky - transfer is on a queue */
14831d96047eSMarkus Pfeiffer 		TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
14841d96047eSMarkus Pfeiffer 		sxfer->entry.tqe_prev = NULL;
14851d96047eSMarkus Pfeiffer 		libusb10_complete_transfer(NULL,
14861d96047eSMarkus Pfeiffer 		    sxfer, LIBUSB_TRANSFER_CANCELLED);
14871d96047eSMarkus Pfeiffer 	} else if (pxfer0 == NULL || pxfer1 == NULL) {
14881d96047eSMarkus Pfeiffer 		/* not started */
14891d96047eSMarkus Pfeiffer 		retval = LIBUSB_ERROR_NOT_FOUND;
14901d96047eSMarkus Pfeiffer 	} else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) {
14911d96047eSMarkus Pfeiffer 		libusb10_complete_transfer(pxfer0,
14921d96047eSMarkus Pfeiffer 		    sxfer, LIBUSB_TRANSFER_CANCELLED);
14931d96047eSMarkus Pfeiffer 		libusb20_tr_stop(pxfer0);
14941d96047eSMarkus Pfeiffer 		/* make sure the queue doesn't stall */
14951d96047eSMarkus Pfeiffer 		libusb10_submit_transfer_sub(
14961d96047eSMarkus Pfeiffer 		    uxfer->dev_handle, endpoint);
14971d96047eSMarkus Pfeiffer 	} else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) {
14981d96047eSMarkus Pfeiffer 		libusb10_complete_transfer(pxfer1,
14991d96047eSMarkus Pfeiffer 		    sxfer, LIBUSB_TRANSFER_CANCELLED);
15001d96047eSMarkus Pfeiffer 		libusb20_tr_stop(pxfer1);
15011d96047eSMarkus Pfeiffer 		/* make sure the queue doesn't stall */
15021d96047eSMarkus Pfeiffer 		libusb10_submit_transfer_sub(
15031d96047eSMarkus Pfeiffer 		    uxfer->dev_handle, endpoint);
15041d96047eSMarkus Pfeiffer 	} else {
15051d96047eSMarkus Pfeiffer 		/* not started */
15061d96047eSMarkus Pfeiffer 		retval = LIBUSB_ERROR_NOT_FOUND;
15071d96047eSMarkus Pfeiffer 	}
15081d96047eSMarkus Pfeiffer 
15091d96047eSMarkus Pfeiffer 	CTX_UNLOCK(dev->ctx);
15101d96047eSMarkus Pfeiffer 
15111d96047eSMarkus Pfeiffer 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
15121d96047eSMarkus Pfeiffer 
15131d96047eSMarkus Pfeiffer 	return (retval);
15141d96047eSMarkus Pfeiffer }
15151d96047eSMarkus Pfeiffer 
15161d96047eSMarkus Pfeiffer UNEXPORTED void
libusb10_cancel_all_transfer(libusb_device * dev)15171d96047eSMarkus Pfeiffer libusb10_cancel_all_transfer(libusb_device *dev)
15181d96047eSMarkus Pfeiffer {
15191d96047eSMarkus Pfeiffer 	/* TODO */
15201d96047eSMarkus Pfeiffer }
15211d96047eSMarkus Pfeiffer 
15221d96047eSMarkus Pfeiffer uint16_t
libusb_cpu_to_le16(uint16_t x)15231d96047eSMarkus Pfeiffer libusb_cpu_to_le16(uint16_t x)
15241d96047eSMarkus Pfeiffer {
15251d96047eSMarkus Pfeiffer 	return (htole16(x));
15261d96047eSMarkus Pfeiffer }
15271d96047eSMarkus Pfeiffer 
15281d96047eSMarkus Pfeiffer uint16_t
libusb_le16_to_cpu(uint16_t x)15291d96047eSMarkus Pfeiffer libusb_le16_to_cpu(uint16_t x)
15301d96047eSMarkus Pfeiffer {
15311d96047eSMarkus Pfeiffer 	return (le16toh(x));
15321d96047eSMarkus Pfeiffer }
15331d96047eSMarkus Pfeiffer 
15341d96047eSMarkus Pfeiffer const char *
libusb_strerror(int code)15351d96047eSMarkus Pfeiffer libusb_strerror(int code)
15361d96047eSMarkus Pfeiffer {
15371d96047eSMarkus Pfeiffer 	switch (code) {
15381d96047eSMarkus Pfeiffer 	case LIBUSB_SUCCESS:
15391d96047eSMarkus Pfeiffer 		return ("Success");
15401d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_IO:
15411d96047eSMarkus Pfeiffer 		return ("I/O error");
15421d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_INVALID_PARAM:
15431d96047eSMarkus Pfeiffer 		return ("Invalid parameter");
15441d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_ACCESS:
15451d96047eSMarkus Pfeiffer 		return ("Permissions error");
15461d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NO_DEVICE:
15471d96047eSMarkus Pfeiffer 		return ("No device");
15481d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NOT_FOUND:
15491d96047eSMarkus Pfeiffer 		return ("Not found");
15501d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_BUSY:
15511d96047eSMarkus Pfeiffer 		return ("Device busy");
15521d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_TIMEOUT:
15531d96047eSMarkus Pfeiffer 		return ("Timeout");
15541d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_OVERFLOW:
15551d96047eSMarkus Pfeiffer 		return ("Overflow");
15561d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_PIPE:
15571d96047eSMarkus Pfeiffer 		return ("Pipe error");
15581d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_INTERRUPTED:
15591d96047eSMarkus Pfeiffer 		return ("Interrupted");
15601d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NO_MEM:
15611d96047eSMarkus Pfeiffer 		return ("Out of memory");
15621d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NOT_SUPPORTED:
15631d96047eSMarkus Pfeiffer 		return ("Not supported");
15641d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_OTHER:
15651d96047eSMarkus Pfeiffer 		return ("Other error");
15661d96047eSMarkus Pfeiffer 	default:
15671d96047eSMarkus Pfeiffer 		return ("Unknown error");
15681d96047eSMarkus Pfeiffer 	}
15691d96047eSMarkus Pfeiffer }
15701d96047eSMarkus Pfeiffer 
15711d96047eSMarkus Pfeiffer const char *
libusb_error_name(int code)15721d96047eSMarkus Pfeiffer libusb_error_name(int code)
15731d96047eSMarkus Pfeiffer {
15741d96047eSMarkus Pfeiffer 	switch (code) {
15751d96047eSMarkus Pfeiffer 	case LIBUSB_SUCCESS:
15761d96047eSMarkus Pfeiffer 		return ("LIBUSB_SUCCESS");
15771d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_IO:
15781d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_IO");
15791d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_INVALID_PARAM:
15801d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_INVALID_PARAM");
15811d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_ACCESS:
15821d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_ACCESS");
15831d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NO_DEVICE:
15841d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_NO_DEVICE");
15851d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NOT_FOUND:
15861d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_NOT_FOUND");
15871d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_BUSY:
15881d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_BUSY");
15891d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_TIMEOUT:
15901d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_TIMEOUT");
15911d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_OVERFLOW:
15921d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_OVERFLOW");
15931d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_PIPE:
15941d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_PIPE");
15951d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_INTERRUPTED:
15961d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_INTERRUPTED");
15971d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NO_MEM:
15981d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_NO_MEM");
15991d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_NOT_SUPPORTED:
16001d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_NOT_SUPPORTED");
16011d96047eSMarkus Pfeiffer 	case LIBUSB_ERROR_OTHER:
16021d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_OTHER");
16031d96047eSMarkus Pfeiffer 	default:
16041d96047eSMarkus Pfeiffer 		return ("LIBUSB_ERROR_UNKNOWN");
16051d96047eSMarkus Pfeiffer 	}
16061d96047eSMarkus Pfeiffer }
1607