xref: /freebsd/lib/libusb/libusb10.c (revision a9205626a7e2f89486e637d6187ff99c17efeb10)
18c8fff31SAndrew Thompson /* $FreeBSD$ */
28c8fff31SAndrew Thompson /*-
38c8fff31SAndrew Thompson  * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
4390065b1SAlfred Perlstein  * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
58c8fff31SAndrew Thompson  *
68c8fff31SAndrew Thompson  * Redistribution and use in source and binary forms, with or without
78c8fff31SAndrew Thompson  * modification, are permitted provided that the following conditions
88c8fff31SAndrew Thompson  * are met:
98c8fff31SAndrew Thompson  * 1. Redistributions of source code must retain the above copyright
108c8fff31SAndrew Thompson  *    notice, this list of conditions and the following disclaimer.
118c8fff31SAndrew Thompson  * 2. Redistributions in binary form must reproduce the above copyright
128c8fff31SAndrew Thompson  *    notice, this list of conditions and the following disclaimer in the
138c8fff31SAndrew Thompson  *    documentation and/or other materials provided with the distribution.
148c8fff31SAndrew Thompson  *
158c8fff31SAndrew Thompson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
168c8fff31SAndrew Thompson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
178c8fff31SAndrew Thompson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
188c8fff31SAndrew Thompson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
198c8fff31SAndrew Thompson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
208c8fff31SAndrew Thompson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
218c8fff31SAndrew Thompson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
228c8fff31SAndrew Thompson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
238c8fff31SAndrew Thompson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
248c8fff31SAndrew Thompson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
258c8fff31SAndrew Thompson  * SUCH DAMAGE.
268c8fff31SAndrew Thompson  */
278c8fff31SAndrew Thompson 
2866194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
2966194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE
3066194130SHans Petter Selasky #else
31ac840bfcSWojciech A. Koszek #include <assert.h>
32f3cba95cSWojciech A. Koszek #include <errno.h>
338c8fff31SAndrew Thompson #include <poll.h>
348c8fff31SAndrew Thompson #include <pthread.h>
35f3cba95cSWojciech A. Koszek #include <stdio.h>
36f3cba95cSWojciech A. Koszek #include <stdlib.h>
3766194130SHans Petter Selasky #include <string.h>
38f3cba95cSWojciech A. Koszek #include <unistd.h>
3966194130SHans Petter Selasky #include <time.h>
4066194130SHans Petter Selasky #include <sys/fcntl.h>
4166194130SHans Petter Selasky #include <sys/ioctl.h>
4266194130SHans Petter Selasky #include <sys/queue.h>
4366194130SHans Petter Selasky #include <sys/endian.h>
4466194130SHans Petter Selasky #endif
458c8fff31SAndrew Thompson 
469c087c5aSAndrew Thompson #define	libusb_device_handle libusb20_device
479c087c5aSAndrew Thompson 
488c8fff31SAndrew Thompson #include "libusb20.h"
498c8fff31SAndrew Thompson #include "libusb20_desc.h"
508c8fff31SAndrew Thompson #include "libusb20_int.h"
518c8fff31SAndrew Thompson #include "libusb.h"
528c8fff31SAndrew Thompson #include "libusb10.h"
538c8fff31SAndrew Thompson 
548c8fff31SAndrew Thompson static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER;
558c8fff31SAndrew Thompson struct libusb_context *usbi_default_context = NULL;
56390065b1SAlfred Perlstein 
57390065b1SAlfred Perlstein /* Prototypes */
58390065b1SAlfred Perlstein 
59390065b1SAlfred Perlstein static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t);
60390065b1SAlfred Perlstein static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *);
61390065b1SAlfred Perlstein static int libusb10_convert_error(uint8_t status);
62390065b1SAlfred Perlstein static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int);
63390065b1SAlfred Perlstein static void libusb10_isoc_proxy(struct libusb20_transfer *);
64390065b1SAlfred Perlstein static void libusb10_bulk_intr_proxy(struct libusb20_transfer *);
65390065b1SAlfred Perlstein static void libusb10_ctrl_proxy(struct libusb20_transfer *);
66390065b1SAlfred Perlstein static void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t);
678c8fff31SAndrew Thompson 
688c8fff31SAndrew Thompson /*  Library initialisation / deinitialisation */
698c8fff31SAndrew Thompson 
708c8fff31SAndrew Thompson void
718c8fff31SAndrew Thompson libusb_set_debug(libusb_context *ctx, int level)
728c8fff31SAndrew Thompson {
73390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
748c8fff31SAndrew Thompson 	if (ctx)
758c8fff31SAndrew Thompson 		ctx->debug = level;
768c8fff31SAndrew Thompson }
778c8fff31SAndrew Thompson 
78698e791aSHans Petter Selasky static void
79698e791aSHans Petter Selasky libusb_set_nonblocking(int f)
80698e791aSHans Petter Selasky {
81698e791aSHans Petter Selasky 	int flags;
82698e791aSHans Petter Selasky 
83698e791aSHans Petter Selasky 	/*
84698e791aSHans Petter Selasky 	 * We ignore any failures in this function, hence the
85698e791aSHans Petter Selasky 	 * non-blocking flag is not critical to the operation of
86698e791aSHans Petter Selasky 	 * libUSB. We use F_GETFL and F_SETFL to be compatible with
87698e791aSHans Petter Selasky 	 * Linux.
88698e791aSHans Petter Selasky 	 */
89698e791aSHans Petter Selasky 
90698e791aSHans Petter Selasky 	flags = fcntl(f, F_GETFL, NULL);
91698e791aSHans Petter Selasky 	if (flags == -1)
92698e791aSHans Petter Selasky 		return;
93698e791aSHans Petter Selasky 	flags |= O_NONBLOCK;
94698e791aSHans Petter Selasky 	fcntl(f, F_SETFL, flags);
95698e791aSHans Petter Selasky }
96698e791aSHans Petter Selasky 
978c8fff31SAndrew Thompson int
988c8fff31SAndrew Thompson libusb_init(libusb_context **context)
998c8fff31SAndrew Thompson {
1008c8fff31SAndrew Thompson 	struct libusb_context *ctx;
101f7287225SHans Petter Selasky 	pthread_condattr_t attr;
1028c8fff31SAndrew Thompson 	char *debug;
1038c8fff31SAndrew Thompson 	int ret;
1048c8fff31SAndrew Thompson 
1058c8fff31SAndrew Thompson 	ctx = malloc(sizeof(*ctx));
1068c8fff31SAndrew Thompson 	if (!ctx)
1078c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_INVALID_PARAM);
1088c8fff31SAndrew Thompson 
1098c8fff31SAndrew Thompson 	memset(ctx, 0, sizeof(*ctx));
1108c8fff31SAndrew Thompson 
1118c8fff31SAndrew Thompson 	debug = getenv("LIBUSB_DEBUG");
1128c8fff31SAndrew Thompson 	if (debug != NULL) {
1138c8fff31SAndrew Thompson 		ctx->debug = atoi(debug);
1148c8fff31SAndrew Thompson 		if (ctx->debug != 0)
1158c8fff31SAndrew Thompson 			ctx->debug_fixed = 1;
1168c8fff31SAndrew Thompson 	}
117c500e4ddSAndrew Thompson 	TAILQ_INIT(&ctx->pollfds);
118390065b1SAlfred Perlstein 	TAILQ_INIT(&ctx->tr_done);
119390065b1SAlfred Perlstein 
120f7287225SHans Petter Selasky 	if (pthread_mutex_init(&ctx->ctx_lock, NULL) != 0) {
121f7287225SHans Petter Selasky 		free(ctx);
122f7287225SHans Petter Selasky 		return (LIBUSB_ERROR_NO_MEM);
123f7287225SHans Petter Selasky 	}
124f7287225SHans Petter Selasky 	if (pthread_condattr_init(&attr) != 0) {
125f7287225SHans Petter Selasky 		pthread_mutex_destroy(&ctx->ctx_lock);
126f7287225SHans Petter Selasky 		free(ctx);
127f7287225SHans Petter Selasky 		return (LIBUSB_ERROR_NO_MEM);
128f7287225SHans Petter Selasky 	}
129f7287225SHans Petter Selasky 	if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) {
130f7287225SHans Petter Selasky 		pthread_mutex_destroy(&ctx->ctx_lock);
131f7287225SHans Petter Selasky 		pthread_condattr_destroy(&attr);
132f7287225SHans Petter Selasky 		free(ctx);
133f7287225SHans Petter Selasky 		return (LIBUSB_ERROR_OTHER);
134f7287225SHans Petter Selasky 	}
135f7287225SHans Petter Selasky 	if (pthread_cond_init(&ctx->ctx_cond, &attr) != 0) {
136f7287225SHans Petter Selasky 		pthread_mutex_destroy(&ctx->ctx_lock);
137f7287225SHans Petter Selasky 		pthread_condattr_destroy(&attr);
138f7287225SHans Petter Selasky 		free(ctx);
139f7287225SHans Petter Selasky 		return (LIBUSB_ERROR_NO_MEM);
140f7287225SHans Petter Selasky 	}
141f7287225SHans Petter Selasky 	pthread_condattr_destroy(&attr);
142390065b1SAlfred Perlstein 
143390065b1SAlfred Perlstein 	ctx->ctx_handler = NO_THREAD;
1448c8fff31SAndrew Thompson 
1458c8fff31SAndrew Thompson 	ret = pipe(ctx->ctrl_pipe);
1468c8fff31SAndrew Thompson 	if (ret < 0) {
147390065b1SAlfred Perlstein 		pthread_mutex_destroy(&ctx->ctx_lock);
148390065b1SAlfred Perlstein 		pthread_cond_destroy(&ctx->ctx_cond);
1498c8fff31SAndrew Thompson 		free(ctx);
1508c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_OTHER);
1518c8fff31SAndrew Thompson 	}
152390065b1SAlfred Perlstein 	/* set non-blocking mode on the control pipe to avoid deadlock */
153698e791aSHans Petter Selasky 	libusb_set_nonblocking(ctx->ctrl_pipe[0]);
154698e791aSHans Petter Selasky 	libusb_set_nonblocking(ctx->ctrl_pipe[1]);
1558c8fff31SAndrew Thompson 
156390065b1SAlfred Perlstein 	libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN);
1578c8fff31SAndrew Thompson 
1588c8fff31SAndrew Thompson 	pthread_mutex_lock(&default_context_lock);
1598c8fff31SAndrew Thompson 	if (usbi_default_context == NULL) {
1608c8fff31SAndrew Thompson 		usbi_default_context = ctx;
1618c8fff31SAndrew Thompson 	}
1628c8fff31SAndrew Thompson 	pthread_mutex_unlock(&default_context_lock);
1638c8fff31SAndrew Thompson 
1648c8fff31SAndrew Thompson 	if (context)
1658c8fff31SAndrew Thompson 		*context = ctx;
1668c8fff31SAndrew Thompson 
167390065b1SAlfred Perlstein 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
168390065b1SAlfred Perlstein 
1698c8fff31SAndrew Thompson 	return (0);
1708c8fff31SAndrew Thompson }
1718c8fff31SAndrew Thompson 
1728c8fff31SAndrew Thompson void
1738c8fff31SAndrew Thompson libusb_exit(libusb_context *ctx)
1748c8fff31SAndrew Thompson {
175390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
1768c8fff31SAndrew Thompson 
177390065b1SAlfred Perlstein 	if (ctx == NULL)
178390065b1SAlfred Perlstein 		return;
179390065b1SAlfred Perlstein 
180390065b1SAlfred Perlstein 	/* XXX cleanup devices */
181390065b1SAlfred Perlstein 
182390065b1SAlfred Perlstein 	libusb10_remove_pollfd(ctx, &ctx->ctx_poll);
1838c8fff31SAndrew Thompson 	close(ctx->ctrl_pipe[0]);
1848c8fff31SAndrew Thompson 	close(ctx->ctrl_pipe[1]);
185390065b1SAlfred Perlstein 	pthread_mutex_destroy(&ctx->ctx_lock);
186390065b1SAlfred Perlstein 	pthread_cond_destroy(&ctx->ctx_cond);
1878c8fff31SAndrew Thompson 
1888c8fff31SAndrew Thompson 	pthread_mutex_lock(&default_context_lock);
1898c8fff31SAndrew Thompson 	if (ctx == usbi_default_context) {
1908c8fff31SAndrew Thompson 		usbi_default_context = NULL;
1918c8fff31SAndrew Thompson 	}
1928c8fff31SAndrew Thompson 	pthread_mutex_unlock(&default_context_lock);
1938c8fff31SAndrew Thompson 
1948c8fff31SAndrew Thompson 	free(ctx);
1958c8fff31SAndrew Thompson }
1968c8fff31SAndrew Thompson 
1978c8fff31SAndrew Thompson /* Device handling and initialisation. */
1988c8fff31SAndrew Thompson 
1998c8fff31SAndrew Thompson ssize_t
2008c8fff31SAndrew Thompson libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
2018c8fff31SAndrew Thompson {
2028c8fff31SAndrew Thompson 	struct libusb20_backend *usb_backend;
203390065b1SAlfred Perlstein 	struct libusb20_device *pdev;
204390065b1SAlfred Perlstein 	struct libusb_device *dev;
2058c8fff31SAndrew Thompson 	int i;
2068c8fff31SAndrew Thompson 
207390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
208390065b1SAlfred Perlstein 
209390065b1SAlfred Perlstein 	if (ctx == NULL)
210390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
211390065b1SAlfred Perlstein 
212390065b1SAlfred Perlstein 	if (list == NULL)
213390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
2148c8fff31SAndrew Thompson 
2158c8fff31SAndrew Thompson 	usb_backend = libusb20_be_alloc_default();
2168c8fff31SAndrew Thompson 	if (usb_backend == NULL)
217390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_NO_MEM);
2188c8fff31SAndrew Thompson 
219390065b1SAlfred Perlstein 	/* figure out how many USB devices are present */
2208c8fff31SAndrew Thompson 	pdev = NULL;
2218c8fff31SAndrew Thompson 	i = 0;
2228c8fff31SAndrew Thompson 	while ((pdev = libusb20_be_device_foreach(usb_backend, pdev)))
2238c8fff31SAndrew Thompson 		i++;
2248c8fff31SAndrew Thompson 
225390065b1SAlfred Perlstein 	/* allocate device pointer list */
2268c8fff31SAndrew Thompson 	*list = malloc((i + 1) * sizeof(void *));
2278c8fff31SAndrew Thompson 	if (*list == NULL) {
2288c8fff31SAndrew Thompson 		libusb20_be_free(usb_backend);
2298c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_NO_MEM);
2308c8fff31SAndrew Thompson 	}
231390065b1SAlfred Perlstein 	/* create libusb v1.0 compliant devices */
2328c8fff31SAndrew Thompson 	i = 0;
2338c8fff31SAndrew Thompson 	while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
2348c8fff31SAndrew Thompson 
2358c8fff31SAndrew Thompson 		dev = malloc(sizeof(*dev));
2368c8fff31SAndrew Thompson 		if (dev == NULL) {
237c500e4ddSAndrew Thompson 			while (i != 0) {
238c500e4ddSAndrew Thompson 				libusb_unref_device((*list)[i - 1]);
239c500e4ddSAndrew Thompson 				i--;
240c500e4ddSAndrew Thompson 			}
2418c8fff31SAndrew Thompson 			free(*list);
242390065b1SAlfred Perlstein 			*list = NULL;
2438c8fff31SAndrew Thompson 			libusb20_be_free(usb_backend);
2448c8fff31SAndrew Thompson 			return (LIBUSB_ERROR_NO_MEM);
2458c8fff31SAndrew Thompson 		}
246ccef4ddfSAndrew Thompson 		/* get device into libUSB v1.0 list */
247ccef4ddfSAndrew Thompson 		libusb20_be_dequeue_device(usb_backend, pdev);
248ccef4ddfSAndrew Thompson 
2498c8fff31SAndrew Thompson 		memset(dev, 0, sizeof(*dev));
2508c8fff31SAndrew Thompson 
251390065b1SAlfred Perlstein 		/* init transfer queues */
252390065b1SAlfred Perlstein 		TAILQ_INIT(&dev->tr_head);
253390065b1SAlfred Perlstein 
254390065b1SAlfred Perlstein 		/* set context we belong to */
2558c8fff31SAndrew Thompson 		dev->ctx = ctx;
2568c8fff31SAndrew Thompson 
2578c8fff31SAndrew Thompson 		/* link together the two structures */
2588c8fff31SAndrew Thompson 		dev->os_priv = pdev;
259390065b1SAlfred Perlstein 		pdev->privLuData = dev;
2608c8fff31SAndrew Thompson 
2618c8fff31SAndrew Thompson 		(*list)[i] = libusb_ref_device(dev);
2628c8fff31SAndrew Thompson 		i++;
2638c8fff31SAndrew Thompson 	}
2648c8fff31SAndrew Thompson 	(*list)[i] = NULL;
2658c8fff31SAndrew Thompson 
2668c8fff31SAndrew Thompson 	libusb20_be_free(usb_backend);
2678c8fff31SAndrew Thompson 	return (i);
2688c8fff31SAndrew Thompson }
2698c8fff31SAndrew Thompson 
2708c8fff31SAndrew Thompson void
2718c8fff31SAndrew Thompson libusb_free_device_list(libusb_device **list, int unref_devices)
2728c8fff31SAndrew Thompson {
2738c8fff31SAndrew Thompson 	int i;
2748c8fff31SAndrew Thompson 
2758c8fff31SAndrew Thompson 	if (list == NULL)
276390065b1SAlfred Perlstein 		return;			/* be NULL safe */
2778c8fff31SAndrew Thompson 
2788c8fff31SAndrew Thompson 	if (unref_devices) {
2798c8fff31SAndrew Thompson 		for (i = 0; list[i] != NULL; i++)
2808c8fff31SAndrew Thompson 			libusb_unref_device(list[i]);
2818c8fff31SAndrew Thompson 	}
2828c8fff31SAndrew Thompson 	free(list);
2838c8fff31SAndrew Thompson }
2848c8fff31SAndrew Thompson 
2858c8fff31SAndrew Thompson uint8_t
2868c8fff31SAndrew Thompson libusb_get_bus_number(libusb_device *dev)
2878c8fff31SAndrew Thompson {
2888c8fff31SAndrew Thompson 	if (dev == NULL)
289390065b1SAlfred Perlstein 		return (0);		/* should not happen */
290390065b1SAlfred Perlstein 	return (libusb20_dev_get_bus_number(dev->os_priv));
2918c8fff31SAndrew Thompson }
2928c8fff31SAndrew Thompson 
2935906bf49SEd Maste int
294*a9205626SEd Maste libusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize)
295*a9205626SEd Maste {
296*a9205626SEd Maste 	return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize));
297*a9205626SEd Maste }
298*a9205626SEd Maste 
299*a9205626SEd Maste int
3005906bf49SEd Maste libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t *buf,
3015906bf49SEd Maste     uint8_t bufsize)
3025906bf49SEd Maste {
3035906bf49SEd Maste 	return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize));
3045906bf49SEd Maste }
3055906bf49SEd Maste 
3068c8fff31SAndrew Thompson uint8_t
3078c8fff31SAndrew Thompson libusb_get_device_address(libusb_device *dev)
3088c8fff31SAndrew Thompson {
3098c8fff31SAndrew Thompson 	if (dev == NULL)
310390065b1SAlfred Perlstein 		return (0);		/* should not happen */
311390065b1SAlfred Perlstein 	return (libusb20_dev_get_address(dev->os_priv));
3128c8fff31SAndrew Thompson }
3138c8fff31SAndrew Thompson 
3149a46d467SHans Petter Selasky enum libusb_speed
3159a46d467SHans Petter Selasky libusb_get_device_speed(libusb_device *dev)
3169a46d467SHans Petter Selasky {
3179a46d467SHans Petter Selasky 	if (dev == NULL)
31833ec9f0cSHans Petter Selasky 		return (LIBUSB_SPEED_UNKNOWN);	/* should not happen */
3199a46d467SHans Petter Selasky 
3209a46d467SHans Petter Selasky 	switch (libusb20_dev_get_speed(dev->os_priv)) {
3219a46d467SHans Petter Selasky 	case LIBUSB20_SPEED_LOW:
3229a46d467SHans Petter Selasky 		return (LIBUSB_SPEED_LOW);
3239a46d467SHans Petter Selasky 	case LIBUSB20_SPEED_FULL:
3249a46d467SHans Petter Selasky 		return (LIBUSB_SPEED_FULL);
3259a46d467SHans Petter Selasky 	case LIBUSB20_SPEED_HIGH:
3269a46d467SHans Petter Selasky 		return (LIBUSB_SPEED_HIGH);
3279a46d467SHans Petter Selasky 	case LIBUSB20_SPEED_SUPER:
3289a46d467SHans Petter Selasky 		return (LIBUSB_SPEED_SUPER);
3299a46d467SHans Petter Selasky 	default:
3309a46d467SHans Petter Selasky 		break;
3319a46d467SHans Petter Selasky 	}
3329a46d467SHans Petter Selasky 	return (LIBUSB_SPEED_UNKNOWN);
3339a46d467SHans Petter Selasky }
3349a46d467SHans Petter Selasky 
3358c8fff31SAndrew Thompson int
336390065b1SAlfred Perlstein libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint)
3378c8fff31SAndrew Thompson {
3388c8fff31SAndrew Thompson 	struct libusb_config_descriptor *pdconf;
3398c8fff31SAndrew Thompson 	struct libusb_interface *pinf;
3408c8fff31SAndrew Thompson 	struct libusb_interface_descriptor *pdinf;
3418c8fff31SAndrew Thompson 	struct libusb_endpoint_descriptor *pdend;
342390065b1SAlfred Perlstein 	int i;
343390065b1SAlfred Perlstein 	int j;
344390065b1SAlfred Perlstein 	int k;
345390065b1SAlfred Perlstein 	int ret;
3468c8fff31SAndrew Thompson 
3478c8fff31SAndrew Thompson 	if (dev == NULL)
3488c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_NO_DEVICE);
3498c8fff31SAndrew Thompson 
350390065b1SAlfred Perlstein 	ret = libusb_get_active_config_descriptor(dev, &pdconf);
351390065b1SAlfred Perlstein 	if (ret < 0)
352390065b1SAlfred Perlstein 		return (ret);
3538c8fff31SAndrew Thompson 
3548c8fff31SAndrew Thompson 	ret = LIBUSB_ERROR_NOT_FOUND;
3558c8fff31SAndrew Thompson 	for (i = 0; i < pdconf->bNumInterfaces; i++) {
3568c8fff31SAndrew Thompson 		pinf = &pdconf->interface[i];
3578c8fff31SAndrew Thompson 		for (j = 0; j < pinf->num_altsetting; j++) {
3588c8fff31SAndrew Thompson 			pdinf = &pinf->altsetting[j];
3598c8fff31SAndrew Thompson 			for (k = 0; k < pdinf->bNumEndpoints; k++) {
3608c8fff31SAndrew Thompson 				pdend = &pdinf->endpoint[k];
3618c8fff31SAndrew Thompson 				if (pdend->bEndpointAddress == endpoint) {
3628c8fff31SAndrew Thompson 					ret = pdend->wMaxPacketSize;
3638c8fff31SAndrew Thompson 					goto out;
3648c8fff31SAndrew Thompson 				}
3658c8fff31SAndrew Thompson 			}
3668c8fff31SAndrew Thompson 		}
3678c8fff31SAndrew Thompson 	}
3688c8fff31SAndrew Thompson 
3698c8fff31SAndrew Thompson out:
3708c8fff31SAndrew Thompson 	libusb_free_config_descriptor(pdconf);
3718c8fff31SAndrew Thompson 	return (ret);
3728c8fff31SAndrew Thompson }
3738c8fff31SAndrew Thompson 
374748205a3SHans Petter Selasky int
375748205a3SHans Petter Selasky libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint)
376748205a3SHans Petter Selasky {
377748205a3SHans Petter Selasky 	int multiplier;
378748205a3SHans Petter Selasky 	int ret;
379748205a3SHans Petter Selasky 
380748205a3SHans Petter Selasky 	ret = libusb_get_max_packet_size(dev, endpoint);
381748205a3SHans Petter Selasky 
382748205a3SHans Petter Selasky 	switch (libusb20_dev_get_speed(dev->os_priv)) {
383748205a3SHans Petter Selasky 	case LIBUSB20_SPEED_LOW:
384748205a3SHans Petter Selasky 	case LIBUSB20_SPEED_FULL:
385748205a3SHans Petter Selasky 		break;
386748205a3SHans Petter Selasky 	default:
387748205a3SHans Petter Selasky 		if (ret > -1) {
388748205a3SHans Petter Selasky 			multiplier = (1 + ((ret >> 11) & 3));
389748205a3SHans Petter Selasky 			if (multiplier > 3)
390748205a3SHans Petter Selasky 				multiplier = 3;
391748205a3SHans Petter Selasky 			ret = (ret & 0x7FF) * multiplier;
392748205a3SHans Petter Selasky 		}
393748205a3SHans Petter Selasky 		break;
394748205a3SHans Petter Selasky 	}
395748205a3SHans Petter Selasky 	return (ret);
396748205a3SHans Petter Selasky }
397748205a3SHans Petter Selasky 
3988c8fff31SAndrew Thompson libusb_device *
3998c8fff31SAndrew Thompson libusb_ref_device(libusb_device *dev)
4008c8fff31SAndrew Thompson {
4018c8fff31SAndrew Thompson 	if (dev == NULL)
402390065b1SAlfred Perlstein 		return (NULL);		/* be NULL safe */
4038c8fff31SAndrew Thompson 
404390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
4058c8fff31SAndrew Thompson 	dev->refcnt++;
406390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
4078c8fff31SAndrew Thompson 
4088c8fff31SAndrew Thompson 	return (dev);
4098c8fff31SAndrew Thompson }
4108c8fff31SAndrew Thompson 
4118c8fff31SAndrew Thompson void
4128c8fff31SAndrew Thompson libusb_unref_device(libusb_device *dev)
4138c8fff31SAndrew Thompson {
4148c8fff31SAndrew Thompson 	if (dev == NULL)
415390065b1SAlfred Perlstein 		return;			/* be NULL safe */
4168c8fff31SAndrew Thompson 
417390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
4188c8fff31SAndrew Thompson 	dev->refcnt--;
419390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
4208c8fff31SAndrew Thompson 
4218c8fff31SAndrew Thompson 	if (dev->refcnt == 0) {
4228c8fff31SAndrew Thompson 		libusb20_dev_free(dev->os_priv);
4238c8fff31SAndrew Thompson 		free(dev);
4248c8fff31SAndrew Thompson 	}
4258c8fff31SAndrew Thompson }
4268c8fff31SAndrew Thompson 
4278c8fff31SAndrew Thompson int
4288c8fff31SAndrew Thompson libusb_open(libusb_device *dev, libusb_device_handle **devh)
4298c8fff31SAndrew Thompson {
4308c8fff31SAndrew Thompson 	libusb_context *ctx = dev->ctx;
4318c8fff31SAndrew Thompson 	struct libusb20_device *pdev = dev->os_priv;
432390065b1SAlfred Perlstein 	uint8_t dummy;
4338c8fff31SAndrew Thompson 	int err;
4348c8fff31SAndrew Thompson 
4358c8fff31SAndrew Thompson 	if (devh == NULL)
4368c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_INVALID_PARAM);
4378c8fff31SAndrew Thompson 
438390065b1SAlfred Perlstein 	/* set default device handle value */
439390065b1SAlfred Perlstein 	*devh = NULL;
440390065b1SAlfred Perlstein 
441390065b1SAlfred Perlstein 	dev = libusb_ref_device(dev);
442390065b1SAlfred Perlstein 	if (dev == NULL)
443390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
4448c8fff31SAndrew Thompson 
4458c8fff31SAndrew Thompson 	err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ );
4468c8fff31SAndrew Thompson 	if (err) {
447390065b1SAlfred Perlstein 		libusb_unref_device(dev);
4488c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_NO_MEM);
4498c8fff31SAndrew Thompson 	}
450390065b1SAlfred Perlstein 	libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
4518c8fff31SAndrew Thompson 	    POLLOUT | POLLRDNORM | POLLWRNORM);
4528c8fff31SAndrew Thompson 
453390065b1SAlfred Perlstein 	/* make sure our event loop detects the new device */
454390065b1SAlfred Perlstein 	dummy = 0;
4558c8fff31SAndrew Thompson 	err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
456698e791aSHans Petter Selasky 	if (err < (int)sizeof(dummy)) {
457390065b1SAlfred Perlstein 		/* ignore error, if any */
458390065b1SAlfred Perlstein 		DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!");
4598c8fff31SAndrew Thompson 	}
460390065b1SAlfred Perlstein 	*devh = pdev;
4618c8fff31SAndrew Thompson 
4628c8fff31SAndrew Thompson 	return (0);
4638c8fff31SAndrew Thompson }
4648c8fff31SAndrew Thompson 
4658c8fff31SAndrew Thompson libusb_device_handle *
4668c8fff31SAndrew Thompson libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
4678c8fff31SAndrew Thompson     uint16_t product_id)
4688c8fff31SAndrew Thompson {
4698c8fff31SAndrew Thompson 	struct libusb_device **devs;
4708c8fff31SAndrew Thompson 	struct libusb20_device *pdev;
4718c8fff31SAndrew Thompson 	struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
472390065b1SAlfred Perlstein 	int i;
473390065b1SAlfred Perlstein 	int j;
4748c8fff31SAndrew Thompson 
475390065b1SAlfred Perlstein 	ctx = GET_CONTEXT(ctx);
476390065b1SAlfred Perlstein 	if (ctx == NULL)
477390065b1SAlfred Perlstein 		return (NULL);		/* be NULL safe */
478390065b1SAlfred Perlstein 
479c500e4ddSAndrew Thompson 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter");
4808c8fff31SAndrew Thompson 
4818c8fff31SAndrew Thompson 	if ((i = libusb_get_device_list(ctx, &devs)) < 0)
4828c8fff31SAndrew Thompson 		return (NULL);
4838c8fff31SAndrew Thompson 
4843f709d07SHans Petter Selasky 	pdev = NULL;
4858c8fff31SAndrew Thompson 	for (j = 0; j < i; j++) {
4863f709d07SHans Petter Selasky 		struct libusb20_device *tdev;
4873f709d07SHans Petter Selasky 
4883f709d07SHans Petter Selasky 		tdev = devs[j]->os_priv;
4893f709d07SHans Petter Selasky 		pdesc = libusb20_dev_get_device_desc(tdev);
490390065b1SAlfred Perlstein 		/*
491390065b1SAlfred Perlstein 		 * NOTE: The USB library will automatically swap the
492390065b1SAlfred Perlstein 		 * fields in the device descriptor to be of host
493390065b1SAlfred Perlstein 		 * endian type!
494390065b1SAlfred Perlstein 		 */
4958c8fff31SAndrew Thompson 		if (pdesc->idVendor == vendor_id &&
496c500e4ddSAndrew Thompson 		    pdesc->idProduct == product_id) {
497dc934803SHans Petter Selasky 			libusb_open(devs[j], &pdev);
498c500e4ddSAndrew Thompson 			break;
499c500e4ddSAndrew Thompson 		}
5008c8fff31SAndrew Thompson 	}
5018c8fff31SAndrew Thompson 
5028c8fff31SAndrew Thompson 	libusb_free_device_list(devs, 1);
503c500e4ddSAndrew Thompson 	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave");
504390065b1SAlfred Perlstein 	return (pdev);
5058c8fff31SAndrew Thompson }
5068c8fff31SAndrew Thompson 
5078c8fff31SAndrew Thompson void
508390065b1SAlfred Perlstein libusb_close(struct libusb20_device *pdev)
5098c8fff31SAndrew Thompson {
5108c8fff31SAndrew Thompson 	libusb_context *ctx;
511390065b1SAlfred Perlstein 	struct libusb_device *dev;
512390065b1SAlfred Perlstein 	uint8_t dummy;
5138c8fff31SAndrew Thompson 	int err;
5148c8fff31SAndrew Thompson 
515390065b1SAlfred Perlstein 	if (pdev == NULL)
516390065b1SAlfred Perlstein 		return;			/* be NULL safe */
5178c8fff31SAndrew Thompson 
518390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
519390065b1SAlfred Perlstein 	ctx = dev->ctx;
5208c8fff31SAndrew Thompson 
521390065b1SAlfred Perlstein 	libusb10_remove_pollfd(ctx, &dev->dev_poll);
5228c8fff31SAndrew Thompson 
523390065b1SAlfred Perlstein 	libusb20_dev_close(pdev);
524ccef4ddfSAndrew Thompson 
525ccef4ddfSAndrew Thompson 	/* unref will free the "pdev" when the refcount reaches zero */
526390065b1SAlfred Perlstein 	libusb_unref_device(dev);
5278c8fff31SAndrew Thompson 
528390065b1SAlfred Perlstein 	/* make sure our event loop detects the closed device */
529390065b1SAlfred Perlstein 	dummy = 0;
5308c8fff31SAndrew Thompson 	err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
531698e791aSHans Petter Selasky 	if (err < (int)sizeof(dummy)) {
532390065b1SAlfred Perlstein 		/* ignore error, if any */
533390065b1SAlfred Perlstein 		DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!");
534c500e4ddSAndrew Thompson 	}
5358c8fff31SAndrew Thompson }
5368c8fff31SAndrew Thompson 
5378c8fff31SAndrew Thompson libusb_device *
538390065b1SAlfred Perlstein libusb_get_device(struct libusb20_device *pdev)
5398c8fff31SAndrew Thompson {
540390065b1SAlfred Perlstein 	if (pdev == NULL)
5418c8fff31SAndrew Thompson 		return (NULL);
542390065b1SAlfred Perlstein 	return ((libusb_device *)pdev->privLuData);
5438c8fff31SAndrew Thompson }
5448c8fff31SAndrew Thompson 
5458c8fff31SAndrew Thompson int
546390065b1SAlfred Perlstein libusb_get_configuration(struct libusb20_device *pdev, int *config)
5478c8fff31SAndrew Thompson {
548390065b1SAlfred Perlstein 	struct libusb20_config *pconf;
5498c8fff31SAndrew Thompson 
550390065b1SAlfred Perlstein 	if (pdev == NULL || config == NULL)
5518c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_INVALID_PARAM);
5528c8fff31SAndrew Thompson 
553390065b1SAlfred Perlstein 	pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev));
554390065b1SAlfred Perlstein 	if (pconf == NULL)
555c500e4ddSAndrew Thompson 		return (LIBUSB_ERROR_NO_MEM);
5568c8fff31SAndrew Thompson 
557390065b1SAlfred Perlstein 	*config = pconf->desc.bConfigurationValue;
5588c8fff31SAndrew Thompson 
559390065b1SAlfred Perlstein 	free(pconf);
5608c8fff31SAndrew Thompson 
5618c8fff31SAndrew Thompson 	return (0);
5628c8fff31SAndrew Thompson }
5638c8fff31SAndrew Thompson 
5648c8fff31SAndrew Thompson int
565390065b1SAlfred Perlstein libusb_set_configuration(struct libusb20_device *pdev, int configuration)
5668c8fff31SAndrew Thompson {
567390065b1SAlfred Perlstein 	struct libusb20_config *pconf;
568390065b1SAlfred Perlstein 	struct libusb_device *dev;
569390065b1SAlfred Perlstein 	int err;
570390065b1SAlfred Perlstein 	uint8_t i;
5718c8fff31SAndrew Thompson 
572390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
5738c8fff31SAndrew Thompson 	if (dev == NULL)
574390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
575390065b1SAlfred Perlstein 
576390065b1SAlfred Perlstein 	if (configuration < 1) {
577390065b1SAlfred Perlstein 		/* unconfigure */
578390065b1SAlfred Perlstein 		i = 255;
579390065b1SAlfred Perlstein 	} else {
580390065b1SAlfred Perlstein 		for (i = 0; i != 255; i++) {
581390065b1SAlfred Perlstein 			uint8_t found;
582390065b1SAlfred Perlstein 
583390065b1SAlfred Perlstein 			pconf = libusb20_dev_alloc_config(pdev, i);
584390065b1SAlfred Perlstein 			if (pconf == NULL)
585390065b1SAlfred Perlstein 				return (LIBUSB_ERROR_INVALID_PARAM);
586390065b1SAlfred Perlstein 			found = (pconf->desc.bConfigurationValue
587390065b1SAlfred Perlstein 			    == configuration);
588390065b1SAlfred Perlstein 			free(pconf);
589390065b1SAlfred Perlstein 
590390065b1SAlfred Perlstein 			if (found)
591390065b1SAlfred Perlstein 				goto set_config;
592390065b1SAlfred Perlstein 		}
593390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
594390065b1SAlfred Perlstein 	}
595390065b1SAlfred Perlstein 
596390065b1SAlfred Perlstein set_config:
597390065b1SAlfred Perlstein 
598390065b1SAlfred Perlstein 	libusb10_cancel_all_transfer(dev);
599390065b1SAlfred Perlstein 
600390065b1SAlfred Perlstein 	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
601390065b1SAlfred Perlstein 
602390065b1SAlfred Perlstein 	err = libusb20_dev_set_config_index(pdev, i);
603390065b1SAlfred Perlstein 
604390065b1SAlfred Perlstein 	libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
605390065b1SAlfred Perlstein 	    POLLOUT | POLLRDNORM | POLLWRNORM);
606390065b1SAlfred Perlstein 
607390065b1SAlfred Perlstein 	return (err ? LIBUSB_ERROR_INVALID_PARAM : 0);
608390065b1SAlfred Perlstein }
609390065b1SAlfred Perlstein 
610390065b1SAlfred Perlstein int
611390065b1SAlfred Perlstein libusb_claim_interface(struct libusb20_device *pdev, int interface_number)
612390065b1SAlfred Perlstein {
613390065b1SAlfred Perlstein 	libusb_device *dev;
614390065b1SAlfred Perlstein 	int err = 0;
615390065b1SAlfred Perlstein 
616390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
617390065b1SAlfred Perlstein 	if (dev == NULL)
618390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
619390065b1SAlfred Perlstein 
620390065b1SAlfred Perlstein 	if (interface_number < 0 || interface_number > 31)
621390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
622390065b1SAlfred Perlstein 
623390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
624390065b1SAlfred Perlstein 	if (dev->claimed_interfaces & (1 << interface_number))
625390065b1SAlfred Perlstein 		err = LIBUSB_ERROR_BUSY;
626390065b1SAlfred Perlstein 
627390065b1SAlfred Perlstein 	if (!err)
628390065b1SAlfred Perlstein 		dev->claimed_interfaces |= (1 << interface_number);
629390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
630390065b1SAlfred Perlstein 	return (err);
631390065b1SAlfred Perlstein }
632390065b1SAlfred Perlstein 
633390065b1SAlfred Perlstein int
634390065b1SAlfred Perlstein libusb_release_interface(struct libusb20_device *pdev, int interface_number)
635390065b1SAlfred Perlstein {
636390065b1SAlfred Perlstein 	libusb_device *dev;
637390065b1SAlfred Perlstein 	int err = 0;
638390065b1SAlfred Perlstein 
639390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
640390065b1SAlfred Perlstein 	if (dev == NULL)
641390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
642390065b1SAlfred Perlstein 
643390065b1SAlfred Perlstein 	if (interface_number < 0 || interface_number > 31)
644390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
645390065b1SAlfred Perlstein 
646390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
647390065b1SAlfred Perlstein 	if (!(dev->claimed_interfaces & (1 << interface_number)))
648390065b1SAlfred Perlstein 		err = LIBUSB_ERROR_NOT_FOUND;
649390065b1SAlfred Perlstein 
650390065b1SAlfred Perlstein 	if (!err)
651390065b1SAlfred Perlstein 		dev->claimed_interfaces &= ~(1 << interface_number);
652390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
653390065b1SAlfred Perlstein 	return (err);
654390065b1SAlfred Perlstein }
655390065b1SAlfred Perlstein 
656390065b1SAlfred Perlstein int
657390065b1SAlfred Perlstein libusb_set_interface_alt_setting(struct libusb20_device *pdev,
658390065b1SAlfred Perlstein     int interface_number, int alternate_setting)
659390065b1SAlfred Perlstein {
660390065b1SAlfred Perlstein 	libusb_device *dev;
661390065b1SAlfred Perlstein 	int err = 0;
662390065b1SAlfred Perlstein 
663390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
664390065b1SAlfred Perlstein 	if (dev == NULL)
665390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
666390065b1SAlfred Perlstein 
667390065b1SAlfred Perlstein 	if (interface_number < 0 || interface_number > 31)
668390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
669390065b1SAlfred Perlstein 
670390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
671390065b1SAlfred Perlstein 	if (!(dev->claimed_interfaces & (1 << interface_number)))
672390065b1SAlfred Perlstein 		err = LIBUSB_ERROR_NOT_FOUND;
673390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
674390065b1SAlfred Perlstein 
675390065b1SAlfred Perlstein 	if (err)
676390065b1SAlfred Perlstein 		return (err);
677390065b1SAlfred Perlstein 
678390065b1SAlfred Perlstein 	libusb10_cancel_all_transfer(dev);
679390065b1SAlfred Perlstein 
680390065b1SAlfred Perlstein 	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
681390065b1SAlfred Perlstein 
682390065b1SAlfred Perlstein 	err = libusb20_dev_set_alt_index(pdev,
683390065b1SAlfred Perlstein 	    interface_number, alternate_setting);
684390065b1SAlfred Perlstein 
685390065b1SAlfred Perlstein 	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
686390065b1SAlfred Perlstein 	    pdev, libusb20_dev_get_fd(pdev),
687390065b1SAlfred Perlstein 	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
688390065b1SAlfred Perlstein 
689390065b1SAlfred Perlstein 	return (err ? LIBUSB_ERROR_OTHER : 0);
690390065b1SAlfred Perlstein }
691390065b1SAlfred Perlstein 
692390065b1SAlfred Perlstein static struct libusb20_transfer *
693390065b1SAlfred Perlstein libusb10_get_transfer(struct libusb20_device *pdev,
694d81535d1SHans Petter Selasky     uint8_t endpoint, uint8_t xfer_index)
695390065b1SAlfred Perlstein {
696d81535d1SHans Petter Selasky 	xfer_index &= 1;	/* double buffering */
697390065b1SAlfred Perlstein 
698d81535d1SHans Petter Selasky 	xfer_index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4;
699390065b1SAlfred Perlstein 
700390065b1SAlfred Perlstein 	if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) {
701390065b1SAlfred Perlstein 		/* this is an IN endpoint */
702d81535d1SHans Petter Selasky 		xfer_index |= 2;
703390065b1SAlfred Perlstein 	}
704d81535d1SHans Petter Selasky 	return (libusb20_tr_get_pointer(pdev, xfer_index));
705390065b1SAlfred Perlstein }
706390065b1SAlfred Perlstein 
707390065b1SAlfred Perlstein int
708390065b1SAlfred Perlstein libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint)
709390065b1SAlfred Perlstein {
710390065b1SAlfred Perlstein 	struct libusb20_transfer *xfer;
711390065b1SAlfred Perlstein 	struct libusb_device *dev;
712390065b1SAlfred Perlstein 	int err;
713390065b1SAlfred Perlstein 
714390065b1SAlfred Perlstein 	xfer = libusb10_get_transfer(pdev, endpoint, 0);
715390065b1SAlfred Perlstein 	if (xfer == NULL)
716390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
717390065b1SAlfred Perlstein 
718390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
719698e791aSHans Petter Selasky 	if (dev == NULL)
720698e791aSHans Petter Selasky 		return (LIBUSB_ERROR_INVALID_PARAM);
721390065b1SAlfred Perlstein 
722390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
723a7e048a2SHans Petter Selasky 	err = libusb20_tr_open(xfer, 0, 1, endpoint);
724390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
725390065b1SAlfred Perlstein 
726390065b1SAlfred Perlstein 	if (err != 0 && err != LIBUSB20_ERROR_BUSY)
727390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_OTHER);
728390065b1SAlfred Perlstein 
729390065b1SAlfred Perlstein 	libusb20_tr_clear_stall_sync(xfer);
730390065b1SAlfred Perlstein 
731390065b1SAlfred Perlstein 	/* check if we opened the transfer */
732390065b1SAlfred Perlstein 	if (err == 0) {
733390065b1SAlfred Perlstein 		CTX_LOCK(dev->ctx);
734390065b1SAlfred Perlstein 		libusb20_tr_close(xfer);
735390065b1SAlfred Perlstein 		CTX_UNLOCK(dev->ctx);
736390065b1SAlfred Perlstein 	}
737390065b1SAlfred Perlstein 	return (0);			/* success */
738390065b1SAlfred Perlstein }
739390065b1SAlfred Perlstein 
740390065b1SAlfred Perlstein int
741390065b1SAlfred Perlstein libusb_reset_device(struct libusb20_device *pdev)
742390065b1SAlfred Perlstein {
743390065b1SAlfred Perlstein 	libusb_device *dev;
744390065b1SAlfred Perlstein 	int err;
745390065b1SAlfred Perlstein 
746390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
747390065b1SAlfred Perlstein 	if (dev == NULL)
748698e791aSHans Petter Selasky 		return (LIBUSB_ERROR_INVALID_PARAM);
7498c8fff31SAndrew Thompson 
750390065b1SAlfred Perlstein 	libusb10_cancel_all_transfer(dev);
751390065b1SAlfred Perlstein 
752390065b1SAlfred Perlstein 	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
753390065b1SAlfred Perlstein 
754390065b1SAlfred Perlstein 	err = libusb20_dev_reset(pdev);
755390065b1SAlfred Perlstein 
756390065b1SAlfred Perlstein 	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
757390065b1SAlfred Perlstein 	    pdev, libusb20_dev_get_fd(pdev),
758390065b1SAlfred Perlstein 	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
759390065b1SAlfred Perlstein 
760390065b1SAlfred Perlstein 	return (err ? LIBUSB_ERROR_OTHER : 0);
7618c8fff31SAndrew Thompson }
7628c8fff31SAndrew Thompson 
7638c8fff31SAndrew Thompson int
764f1b5fa6eSHans Petter Selasky libusb_check_connected(struct libusb20_device *pdev)
765f1b5fa6eSHans Petter Selasky {
766f1b5fa6eSHans Petter Selasky 	libusb_device *dev;
767f1b5fa6eSHans Petter Selasky 	int err;
768f1b5fa6eSHans Petter Selasky 
769f1b5fa6eSHans Petter Selasky 	dev = libusb_get_device(pdev);
770f1b5fa6eSHans Petter Selasky 	if (dev == NULL)
771f1b5fa6eSHans Petter Selasky 		return (LIBUSB_ERROR_INVALID_PARAM);
772f1b5fa6eSHans Petter Selasky 
773f1b5fa6eSHans Petter Selasky 	err = libusb20_dev_check_connected(pdev);
774f1b5fa6eSHans Petter Selasky 
775f1b5fa6eSHans Petter Selasky 	return (err ? LIBUSB_ERROR_NO_DEVICE : 0);
776f1b5fa6eSHans Petter Selasky }
777f1b5fa6eSHans Petter Selasky 
778f1b5fa6eSHans Petter Selasky int
779390065b1SAlfred Perlstein libusb_kernel_driver_active(struct libusb20_device *pdev, int interface)
7808c8fff31SAndrew Thompson {
781390065b1SAlfred Perlstein 	if (pdev == NULL)
7828c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_INVALID_PARAM);
7838c8fff31SAndrew Thompson 
7844d2472aaSHans Petter Selasky 	if (libusb20_dev_kernel_driver_active(pdev, interface))
7854d2472aaSHans Petter Selasky 		return (0);		/* no kernel driver is active */
7864d2472aaSHans Petter Selasky 	else
7874d2472aaSHans Petter Selasky 		return (1);		/* kernel driver is active */
7888c8fff31SAndrew Thompson }
7898c8fff31SAndrew Thompson 
7908c8fff31SAndrew Thompson int
791698e791aSHans Petter Selasky libusb_get_driver_np(struct libusb20_device *pdev, int interface,
792698e791aSHans Petter Selasky     char *name, int namelen)
793698e791aSHans Petter Selasky {
794698e791aSHans Petter Selasky 	return (libusb_get_driver(pdev, interface, name, namelen));
795698e791aSHans Petter Selasky }
796698e791aSHans Petter Selasky 
797698e791aSHans Petter Selasky int
798698e791aSHans Petter Selasky libusb_get_driver(struct libusb20_device *pdev, int interface,
799698e791aSHans Petter Selasky     char *name, int namelen)
800698e791aSHans Petter Selasky {
801698e791aSHans Petter Selasky 	char *ptr;
802698e791aSHans Petter Selasky 	int err;
803698e791aSHans Petter Selasky 
804698e791aSHans Petter Selasky 	if (pdev == NULL)
805698e791aSHans Petter Selasky 		return (LIBUSB_ERROR_INVALID_PARAM);
806698e791aSHans Petter Selasky 	if (namelen < 1)
807698e791aSHans Petter Selasky 		return (LIBUSB_ERROR_INVALID_PARAM);
8084eb5923dSHans Petter Selasky 	if (namelen > 255)
8094eb5923dSHans Petter Selasky 		namelen = 255;
810698e791aSHans Petter Selasky 
811698e791aSHans Petter Selasky 	err = libusb20_dev_get_iface_desc(
812698e791aSHans Petter Selasky 	    pdev, interface, name, namelen);
813698e791aSHans Petter Selasky 
814698e791aSHans Petter Selasky 	if (err != 0)
815698e791aSHans Petter Selasky 		return (LIBUSB_ERROR_OTHER);
816698e791aSHans Petter Selasky 
817698e791aSHans Petter Selasky 	/* we only want the driver name */
818698e791aSHans Petter Selasky 	ptr = strstr(name, ":");
819698e791aSHans Petter Selasky 	if (ptr != NULL)
820698e791aSHans Petter Selasky 		*ptr = 0;
821698e791aSHans Petter Selasky 
822698e791aSHans Petter Selasky 	return (0);
823698e791aSHans Petter Selasky }
824698e791aSHans Petter Selasky 
825698e791aSHans Petter Selasky int
826698e791aSHans Petter Selasky libusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface)
827698e791aSHans Petter Selasky {
828698e791aSHans Petter Selasky 	return (libusb_detach_kernel_driver(pdev, interface));
829698e791aSHans Petter Selasky }
830698e791aSHans Petter Selasky 
831698e791aSHans Petter Selasky int
832390065b1SAlfred Perlstein libusb_detach_kernel_driver(struct libusb20_device *pdev, int interface)
8338c8fff31SAndrew Thompson {
834390065b1SAlfred Perlstein 	int err;
8358c8fff31SAndrew Thompson 
836390065b1SAlfred Perlstein 	if (pdev == NULL)
8378c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_INVALID_PARAM);
8388c8fff31SAndrew Thompson 
839390065b1SAlfred Perlstein 	err = libusb20_dev_detach_kernel_driver(
840390065b1SAlfred Perlstein 	    pdev, interface);
8418c8fff31SAndrew Thompson 
842698e791aSHans Petter Selasky 	return (err ? LIBUSB_ERROR_OTHER : 0);
8438c8fff31SAndrew Thompson }
8448c8fff31SAndrew Thompson 
8458c8fff31SAndrew Thompson int
846390065b1SAlfred Perlstein libusb_attach_kernel_driver(struct libusb20_device *pdev, int interface)
8478c8fff31SAndrew Thompson {
848390065b1SAlfred Perlstein 	if (pdev == NULL)
8498c8fff31SAndrew Thompson 		return (LIBUSB_ERROR_INVALID_PARAM);
850390065b1SAlfred Perlstein 	/* stub - currently not supported by libusb20 */
8518c8fff31SAndrew Thompson 	return (0);
8528c8fff31SAndrew Thompson }
8538c8fff31SAndrew Thompson 
8548c8fff31SAndrew Thompson /* Asynchronous device I/O */
8558c8fff31SAndrew Thompson 
8568c8fff31SAndrew Thompson struct libusb_transfer *
8578c8fff31SAndrew Thompson libusb_alloc_transfer(int iso_packets)
8588c8fff31SAndrew Thompson {
859390065b1SAlfred Perlstein 	struct libusb_transfer *uxfer;
860390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
8618c8fff31SAndrew Thompson 	int len;
8628c8fff31SAndrew Thompson 
8638c8fff31SAndrew Thompson 	len = sizeof(struct libusb_transfer) +
864390065b1SAlfred Perlstein 	    sizeof(struct libusb_super_transfer) +
8658c8fff31SAndrew Thompson 	    (iso_packets * sizeof(libusb_iso_packet_descriptor));
8668c8fff31SAndrew Thompson 
867390065b1SAlfred Perlstein 	sxfer = malloc(len);
868390065b1SAlfred Perlstein 	if (sxfer == NULL)
8698c8fff31SAndrew Thompson 		return (NULL);
8708c8fff31SAndrew Thompson 
871390065b1SAlfred Perlstein 	memset(sxfer, 0, len);
8728c8fff31SAndrew Thompson 
873390065b1SAlfred Perlstein 	uxfer = (struct libusb_transfer *)(
874390065b1SAlfred Perlstein 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
8758c8fff31SAndrew Thompson 
876390065b1SAlfred Perlstein 	/* set default value */
877390065b1SAlfred Perlstein 	uxfer->num_iso_packets = iso_packets;
878390065b1SAlfred Perlstein 
879390065b1SAlfred Perlstein 	return (uxfer);
8808c8fff31SAndrew Thompson }
8818c8fff31SAndrew Thompson 
8828c8fff31SAndrew Thompson void
883390065b1SAlfred Perlstein libusb_free_transfer(struct libusb_transfer *uxfer)
8848c8fff31SAndrew Thompson {
885390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
8868c8fff31SAndrew Thompson 
887390065b1SAlfred Perlstein 	if (uxfer == NULL)
888390065b1SAlfred Perlstein 		return;			/* be NULL safe */
8898c8fff31SAndrew Thompson 
89031f7072cSHans Petter Selasky 	/* check if we should free the transfer buffer */
89131f7072cSHans Petter Selasky 	if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
89231f7072cSHans Petter Selasky 		free(uxfer->buffer);
89331f7072cSHans Petter Selasky 
894390065b1SAlfred Perlstein 	sxfer = (struct libusb_super_transfer *)(
895390065b1SAlfred Perlstein 	    (uint8_t *)uxfer - sizeof(*sxfer));
8968c8fff31SAndrew Thompson 
897390065b1SAlfred Perlstein 	free(sxfer);
8988c8fff31SAndrew Thompson }
8998c8fff31SAndrew Thompson 
9001c497368SHans Petter Selasky static uint32_t
901390065b1SAlfred Perlstein libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer)
9028c8fff31SAndrew Thompson {
9031c497368SHans Petter Selasky 	uint32_t ret;
9048c8fff31SAndrew Thompson 
9058c8fff31SAndrew Thompson 	switch (xfer->type) {
9068c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
9071c497368SHans Petter Selasky 		ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE;	/* 60ms */
9088c8fff31SAndrew Thompson 		break;
9098c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_TYPE_CONTROL:
9108c8fff31SAndrew Thompson 		ret = 2;
9118c8fff31SAndrew Thompson 		break;
9128c8fff31SAndrew Thompson 	default:
9138c8fff31SAndrew Thompson 		ret = 1;
9148c8fff31SAndrew Thompson 		break;
9158c8fff31SAndrew Thompson 	}
916390065b1SAlfred Perlstein 	return (ret);
9178c8fff31SAndrew Thompson }
9188c8fff31SAndrew Thompson 
9198c8fff31SAndrew Thompson static int
920390065b1SAlfred Perlstein libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer)
9218c8fff31SAndrew Thompson {
9228c8fff31SAndrew Thompson 	int ret;
9238c8fff31SAndrew Thompson 	int usb_speed;
9248c8fff31SAndrew Thompson 
9258c8fff31SAndrew Thompson 	usb_speed = libusb20_dev_get_speed(pdev);
9268c8fff31SAndrew Thompson 
9278c8fff31SAndrew Thompson 	switch (xfer->type) {
9288c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
929390065b1SAlfred Perlstein 		ret = 0;		/* kernel will auto-select */
9308c8fff31SAndrew Thompson 		break;
9318c8fff31SAndrew Thompson 	case LIBUSB_TRANSFER_TYPE_CONTROL:
932390065b1SAlfred Perlstein 		ret = 1024;
9338c8fff31SAndrew Thompson 		break;
9348c8fff31SAndrew Thompson 	default:
9358c8fff31SAndrew Thompson 		switch (usb_speed) {
9368c8fff31SAndrew Thompson 		case LIBUSB20_SPEED_LOW:
9378c8fff31SAndrew Thompson 			ret = 256;
9388c8fff31SAndrew Thompson 			break;
9398c8fff31SAndrew Thompson 		case LIBUSB20_SPEED_FULL:
9408c8fff31SAndrew Thompson 			ret = 4096;
9418c8fff31SAndrew Thompson 			break;
9428c8fff31SAndrew Thompson 		default:
9438c8fff31SAndrew Thompson 			ret = 16384;
9448c8fff31SAndrew Thompson 			break;
9458c8fff31SAndrew Thompson 		}
9468c8fff31SAndrew Thompson 		break;
9478c8fff31SAndrew Thompson 	}
948390065b1SAlfred Perlstein 	return (ret);
9498c8fff31SAndrew Thompson }
9508c8fff31SAndrew Thompson 
951390065b1SAlfred Perlstein static int
952390065b1SAlfred Perlstein libusb10_convert_error(uint8_t status)
953390065b1SAlfred Perlstein {
954390065b1SAlfred Perlstein 	;				/* indent fix */
955390065b1SAlfred Perlstein 
956390065b1SAlfred Perlstein 	switch (status) {
957390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_START:
958390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_COMPLETED:
959390065b1SAlfred Perlstein 		return (LIBUSB_TRANSFER_COMPLETED);
960390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_OVERFLOW:
961390065b1SAlfred Perlstein 		return (LIBUSB_TRANSFER_OVERFLOW);
962390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_NO_DEVICE:
963390065b1SAlfred Perlstein 		return (LIBUSB_TRANSFER_NO_DEVICE);
964390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_STALL:
965390065b1SAlfred Perlstein 		return (LIBUSB_TRANSFER_STALL);
966390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_CANCELLED:
967390065b1SAlfred Perlstein 		return (LIBUSB_TRANSFER_CANCELLED);
968390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_TIMED_OUT:
969390065b1SAlfred Perlstein 		return (LIBUSB_TRANSFER_TIMED_OUT);
970390065b1SAlfred Perlstein 	default:
971390065b1SAlfred Perlstein 		return (LIBUSB_TRANSFER_ERROR);
972390065b1SAlfred Perlstein 	}
973390065b1SAlfred Perlstein }
974390065b1SAlfred Perlstein 
975390065b1SAlfred Perlstein /* This function must be called locked */
976390065b1SAlfred Perlstein 
977c500e4ddSAndrew Thompson static void
978390065b1SAlfred Perlstein libusb10_complete_transfer(struct libusb20_transfer *pxfer,
979390065b1SAlfred Perlstein     struct libusb_super_transfer *sxfer, int status)
980c500e4ddSAndrew Thompson {
981390065b1SAlfred Perlstein 	struct libusb_transfer *uxfer;
982390065b1SAlfred Perlstein 	struct libusb_device *dev;
983c500e4ddSAndrew Thompson 
984390065b1SAlfred Perlstein 	uxfer = (struct libusb_transfer *)(
985390065b1SAlfred Perlstein 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
986390065b1SAlfred Perlstein 
987390065b1SAlfred Perlstein 	if (pxfer != NULL)
988390065b1SAlfred Perlstein 		libusb20_tr_set_priv_sc1(pxfer, NULL);
989390065b1SAlfred Perlstein 
9904594d907SAndrew Thompson 	/* set transfer status */
991390065b1SAlfred Perlstein 	uxfer->status = status;
992390065b1SAlfred Perlstein 
9934594d907SAndrew Thompson 	/* update super transfer state */
9944594d907SAndrew Thompson 	sxfer->state = LIBUSB_SUPER_XFER_ST_NONE;
9954594d907SAndrew Thompson 
996390065b1SAlfred Perlstein 	dev = libusb_get_device(uxfer->dev_handle);
997390065b1SAlfred Perlstein 
998390065b1SAlfred Perlstein 	TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry);
999390065b1SAlfred Perlstein }
1000390065b1SAlfred Perlstein 
1001390065b1SAlfred Perlstein /* This function must be called locked */
1002390065b1SAlfred Perlstein 
1003390065b1SAlfred Perlstein static void
1004390065b1SAlfred Perlstein libusb10_isoc_proxy(struct libusb20_transfer *pxfer)
1005390065b1SAlfred Perlstein {
1006390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
1007390065b1SAlfred Perlstein 	struct libusb_transfer *uxfer;
1008390065b1SAlfred Perlstein 	uint32_t actlen;
1009390065b1SAlfred Perlstein 	uint16_t iso_packets;
1010390065b1SAlfred Perlstein 	uint16_t i;
1011390065b1SAlfred Perlstein 	uint8_t status;
1012390065b1SAlfred Perlstein 	uint8_t flags;
1013390065b1SAlfred Perlstein 
1014390065b1SAlfred Perlstein 	status = libusb20_tr_get_status(pxfer);
1015390065b1SAlfred Perlstein 	sxfer = libusb20_tr_get_priv_sc1(pxfer);
1016390065b1SAlfred Perlstein 	actlen = libusb20_tr_get_actual_length(pxfer);
1017390065b1SAlfred Perlstein 	iso_packets = libusb20_tr_get_max_frames(pxfer);
1018390065b1SAlfred Perlstein 
1019390065b1SAlfred Perlstein 	if (sxfer == NULL)
1020390065b1SAlfred Perlstein 		return;			/* cancelled - nothing to do */
1021390065b1SAlfred Perlstein 
1022390065b1SAlfred Perlstein 	uxfer = (struct libusb_transfer *)(
1023390065b1SAlfred Perlstein 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1024390065b1SAlfred Perlstein 
1025390065b1SAlfred Perlstein 	if (iso_packets > uxfer->num_iso_packets)
1026390065b1SAlfred Perlstein 		iso_packets = uxfer->num_iso_packets;
1027390065b1SAlfred Perlstein 
1028390065b1SAlfred Perlstein 	if (iso_packets == 0)
1029390065b1SAlfred Perlstein 		return;			/* nothing to do */
1030390065b1SAlfred Perlstein 
1031390065b1SAlfred Perlstein 	/* make sure that the number of ISOCHRONOUS packets is valid */
1032390065b1SAlfred Perlstein 	uxfer->num_iso_packets = iso_packets;
1033390065b1SAlfred Perlstein 
1034390065b1SAlfred Perlstein 	flags = uxfer->flags;
1035c500e4ddSAndrew Thompson 
1036c500e4ddSAndrew Thompson 	switch (status) {
1037c500e4ddSAndrew Thompson 	case LIBUSB20_TRANSFER_COMPLETED:
1038c500e4ddSAndrew Thompson 
1039390065b1SAlfred Perlstein 		/* update actual length */
1040390065b1SAlfred Perlstein 		uxfer->actual_length = actlen;
1041390065b1SAlfred Perlstein 		for (i = 0; i != iso_packets; i++) {
1042390065b1SAlfred Perlstein 			uxfer->iso_packet_desc[i].actual_length =
1043390065b1SAlfred Perlstein 			    libusb20_tr_get_length(pxfer, i);
1044390065b1SAlfred Perlstein 		}
1045390065b1SAlfred Perlstein 		libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1046c500e4ddSAndrew Thompson 		break;
1047390065b1SAlfred Perlstein 
1048c500e4ddSAndrew Thompson 	case LIBUSB20_TRANSFER_START:
1049390065b1SAlfred Perlstein 
1050390065b1SAlfred Perlstein 		/* setup length(s) */
1051390065b1SAlfred Perlstein 		actlen = 0;
1052390065b1SAlfred Perlstein 		for (i = 0; i != iso_packets; i++) {
1053390065b1SAlfred Perlstein 			libusb20_tr_setup_isoc(pxfer,
1054390065b1SAlfred Perlstein 			    &uxfer->buffer[actlen],
1055390065b1SAlfred Perlstein 			    uxfer->iso_packet_desc[i].length, i);
1056390065b1SAlfred Perlstein 			actlen += uxfer->iso_packet_desc[i].length;
1057c500e4ddSAndrew Thompson 		}
1058390065b1SAlfred Perlstein 
1059390065b1SAlfred Perlstein 		/* no remainder */
1060390065b1SAlfred Perlstein 		sxfer->rem_len = 0;
1061390065b1SAlfred Perlstein 
1062390065b1SAlfred Perlstein 		libusb20_tr_set_total_frames(pxfer, iso_packets);
1063390065b1SAlfred Perlstein 		libusb20_tr_submit(pxfer);
1064390065b1SAlfred Perlstein 
1065390065b1SAlfred Perlstein 		/* fork another USB transfer, if any */
1066390065b1SAlfred Perlstein 		libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
1067c500e4ddSAndrew Thompson 		break;
1068390065b1SAlfred Perlstein 
1069390065b1SAlfred Perlstein 	default:
1070390065b1SAlfred Perlstein 		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
1071c500e4ddSAndrew Thompson 		break;
1072c500e4ddSAndrew Thompson 	}
1073390065b1SAlfred Perlstein }
1074390065b1SAlfred Perlstein 
1075390065b1SAlfred Perlstein /* This function must be called locked */
1076390065b1SAlfred Perlstein 
1077390065b1SAlfred Perlstein static void
1078390065b1SAlfred Perlstein libusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer)
1079390065b1SAlfred Perlstein {
1080390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
1081390065b1SAlfred Perlstein 	struct libusb_transfer *uxfer;
1082390065b1SAlfred Perlstein 	uint32_t max_bulk;
1083390065b1SAlfred Perlstein 	uint32_t actlen;
1084390065b1SAlfred Perlstein 	uint8_t status;
1085390065b1SAlfred Perlstein 	uint8_t flags;
1086390065b1SAlfred Perlstein 
1087390065b1SAlfred Perlstein 	status = libusb20_tr_get_status(pxfer);
1088390065b1SAlfred Perlstein 	sxfer = libusb20_tr_get_priv_sc1(pxfer);
1089390065b1SAlfred Perlstein 	max_bulk = libusb20_tr_get_max_total_length(pxfer);
1090390065b1SAlfred Perlstein 	actlen = libusb20_tr_get_actual_length(pxfer);
1091390065b1SAlfred Perlstein 
1092390065b1SAlfred Perlstein 	if (sxfer == NULL)
1093390065b1SAlfred Perlstein 		return;			/* cancelled - nothing to do */
1094390065b1SAlfred Perlstein 
1095390065b1SAlfred Perlstein 	uxfer = (struct libusb_transfer *)(
1096390065b1SAlfred Perlstein 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1097390065b1SAlfred Perlstein 
1098390065b1SAlfred Perlstein 	flags = uxfer->flags;
1099390065b1SAlfred Perlstein 
1100390065b1SAlfred Perlstein 	switch (status) {
1101390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_COMPLETED:
1102390065b1SAlfred Perlstein 
1103390065b1SAlfred Perlstein 		uxfer->actual_length += actlen;
1104390065b1SAlfred Perlstein 
1105390065b1SAlfred Perlstein 		/* check for short packet */
1106390065b1SAlfred Perlstein 		if (sxfer->last_len != actlen) {
1107390065b1SAlfred Perlstein 			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
1108390065b1SAlfred Perlstein 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
1109390065b1SAlfred Perlstein 			} else {
1110390065b1SAlfred Perlstein 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1111390065b1SAlfred Perlstein 			}
1112390065b1SAlfred Perlstein 			break;
1113390065b1SAlfred Perlstein 		}
1114390065b1SAlfred Perlstein 		/* check for end of data */
1115390065b1SAlfred Perlstein 		if (sxfer->rem_len == 0) {
1116390065b1SAlfred Perlstein 			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1117390065b1SAlfred Perlstein 			break;
1118390065b1SAlfred Perlstein 		}
1119390065b1SAlfred Perlstein 		/* FALLTHROUGH */
1120390065b1SAlfred Perlstein 
1121390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_START:
1122390065b1SAlfred Perlstein 		if (max_bulk > sxfer->rem_len) {
1123390065b1SAlfred Perlstein 			max_bulk = sxfer->rem_len;
1124390065b1SAlfred Perlstein 		}
1125390065b1SAlfred Perlstein 		/* setup new BULK or INTERRUPT transaction */
1126390065b1SAlfred Perlstein 		libusb20_tr_setup_bulk(pxfer,
1127390065b1SAlfred Perlstein 		    sxfer->curr_data, max_bulk, uxfer->timeout);
1128390065b1SAlfred Perlstein 
1129390065b1SAlfred Perlstein 		/* update counters */
1130390065b1SAlfred Perlstein 		sxfer->last_len = max_bulk;
1131390065b1SAlfred Perlstein 		sxfer->curr_data += max_bulk;
1132390065b1SAlfred Perlstein 		sxfer->rem_len -= max_bulk;
1133390065b1SAlfred Perlstein 
1134390065b1SAlfred Perlstein 		libusb20_tr_submit(pxfer);
1135390065b1SAlfred Perlstein 
1136390065b1SAlfred Perlstein 		/* check if we can fork another USB transfer */
1137390065b1SAlfred Perlstein 		if (sxfer->rem_len == 0)
1138390065b1SAlfred Perlstein 			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
1139390065b1SAlfred Perlstein 		break;
1140390065b1SAlfred Perlstein 
1141390065b1SAlfred Perlstein 	default:
1142390065b1SAlfred Perlstein 		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
1143390065b1SAlfred Perlstein 		break;
1144390065b1SAlfred Perlstein 	}
1145390065b1SAlfred Perlstein }
1146390065b1SAlfred Perlstein 
1147390065b1SAlfred Perlstein /* This function must be called locked */
1148390065b1SAlfred Perlstein 
1149390065b1SAlfred Perlstein static void
1150390065b1SAlfred Perlstein libusb10_ctrl_proxy(struct libusb20_transfer *pxfer)
1151390065b1SAlfred Perlstein {
1152390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
1153390065b1SAlfred Perlstein 	struct libusb_transfer *uxfer;
1154390065b1SAlfred Perlstein 	uint32_t max_bulk;
1155390065b1SAlfred Perlstein 	uint32_t actlen;
1156390065b1SAlfred Perlstein 	uint8_t status;
1157390065b1SAlfred Perlstein 	uint8_t flags;
1158390065b1SAlfred Perlstein 
1159390065b1SAlfred Perlstein 	status = libusb20_tr_get_status(pxfer);
1160390065b1SAlfred Perlstein 	sxfer = libusb20_tr_get_priv_sc1(pxfer);
1161390065b1SAlfred Perlstein 	max_bulk = libusb20_tr_get_max_total_length(pxfer);
1162390065b1SAlfred Perlstein 	actlen = libusb20_tr_get_actual_length(pxfer);
1163390065b1SAlfred Perlstein 
1164390065b1SAlfred Perlstein 	if (sxfer == NULL)
1165390065b1SAlfred Perlstein 		return;			/* cancelled - nothing to do */
1166390065b1SAlfred Perlstein 
1167390065b1SAlfred Perlstein 	uxfer = (struct libusb_transfer *)(
1168390065b1SAlfred Perlstein 	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1169390065b1SAlfred Perlstein 
1170390065b1SAlfred Perlstein 	flags = uxfer->flags;
1171390065b1SAlfred Perlstein 
1172390065b1SAlfred Perlstein 	switch (status) {
1173390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_COMPLETED:
1174390065b1SAlfred Perlstein 
1175390065b1SAlfred Perlstein 		uxfer->actual_length += actlen;
1176390065b1SAlfred Perlstein 
1177390065b1SAlfred Perlstein 		/* subtract length of SETUP packet, if any */
1178390065b1SAlfred Perlstein 		actlen -= libusb20_tr_get_length(pxfer, 0);
1179390065b1SAlfred Perlstein 
1180390065b1SAlfred Perlstein 		/* check for short packet */
1181390065b1SAlfred Perlstein 		if (sxfer->last_len != actlen) {
1182390065b1SAlfred Perlstein 			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
1183390065b1SAlfred Perlstein 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
1184390065b1SAlfred Perlstein 			} else {
1185390065b1SAlfred Perlstein 				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1186390065b1SAlfred Perlstein 			}
1187390065b1SAlfred Perlstein 			break;
1188390065b1SAlfred Perlstein 		}
1189390065b1SAlfred Perlstein 		/* check for end of data */
1190390065b1SAlfred Perlstein 		if (sxfer->rem_len == 0) {
1191390065b1SAlfred Perlstein 			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1192390065b1SAlfred Perlstein 			break;
1193390065b1SAlfred Perlstein 		}
1194390065b1SAlfred Perlstein 		/* FALLTHROUGH */
1195390065b1SAlfred Perlstein 
1196390065b1SAlfred Perlstein 	case LIBUSB20_TRANSFER_START:
1197390065b1SAlfred Perlstein 		if (max_bulk > sxfer->rem_len) {
1198390065b1SAlfred Perlstein 			max_bulk = sxfer->rem_len;
1199390065b1SAlfred Perlstein 		}
1200390065b1SAlfred Perlstein 		/* setup new CONTROL transaction */
1201390065b1SAlfred Perlstein 		if (status == LIBUSB20_TRANSFER_COMPLETED) {
1202390065b1SAlfred Perlstein 			/* next fragment - don't send SETUP packet */
1203390065b1SAlfred Perlstein 			libusb20_tr_set_length(pxfer, 0, 0);
1204390065b1SAlfred Perlstein 		} else {
1205390065b1SAlfred Perlstein 			/* first fragment - send SETUP packet */
1206390065b1SAlfred Perlstein 			libusb20_tr_set_length(pxfer, 8, 0);
1207390065b1SAlfred Perlstein 			libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0);
1208390065b1SAlfred Perlstein 		}
1209390065b1SAlfred Perlstein 
1210390065b1SAlfred Perlstein 		if (max_bulk != 0) {
1211390065b1SAlfred Perlstein 			libusb20_tr_set_length(pxfer, max_bulk, 1);
1212390065b1SAlfred Perlstein 			libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1);
1213390065b1SAlfred Perlstein 			libusb20_tr_set_total_frames(pxfer, 2);
1214390065b1SAlfred Perlstein 		} else {
1215390065b1SAlfred Perlstein 			libusb20_tr_set_total_frames(pxfer, 1);
1216390065b1SAlfred Perlstein 		}
1217390065b1SAlfred Perlstein 
1218390065b1SAlfred Perlstein 		/* update counters */
1219390065b1SAlfred Perlstein 		sxfer->last_len = max_bulk;
1220390065b1SAlfred Perlstein 		sxfer->curr_data += max_bulk;
1221390065b1SAlfred Perlstein 		sxfer->rem_len -= max_bulk;
1222390065b1SAlfred Perlstein 
1223390065b1SAlfred Perlstein 		libusb20_tr_submit(pxfer);
1224390065b1SAlfred Perlstein 
1225390065b1SAlfred Perlstein 		/* check if we can fork another USB transfer */
1226390065b1SAlfred Perlstein 		if (sxfer->rem_len == 0)
1227390065b1SAlfred Perlstein 			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
1228390065b1SAlfred Perlstein 		break;
1229390065b1SAlfred Perlstein 
1230390065b1SAlfred Perlstein 	default:
1231390065b1SAlfred Perlstein 		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
1232390065b1SAlfred Perlstein 		break;
1233390065b1SAlfred Perlstein 	}
1234390065b1SAlfred Perlstein }
1235390065b1SAlfred Perlstein 
1236390065b1SAlfred Perlstein /* The following function must be called locked */
1237390065b1SAlfred Perlstein 
1238390065b1SAlfred Perlstein static void
1239390065b1SAlfred Perlstein libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint)
1240390065b1SAlfred Perlstein {
1241390065b1SAlfred Perlstein 	struct libusb20_transfer *pxfer0;
1242390065b1SAlfred Perlstein 	struct libusb20_transfer *pxfer1;
1243390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
1244390065b1SAlfred Perlstein 	struct libusb_transfer *uxfer;
1245390065b1SAlfred Perlstein 	struct libusb_device *dev;
1246390065b1SAlfred Perlstein 	int err;
1247390065b1SAlfred Perlstein 	int buffsize;
1248390065b1SAlfred Perlstein 	int maxframe;
1249390065b1SAlfred Perlstein 	int temp;
1250390065b1SAlfred Perlstein 	uint8_t dummy;
1251390065b1SAlfred Perlstein 
1252390065b1SAlfred Perlstein 	dev = libusb_get_device(pdev);
1253390065b1SAlfred Perlstein 
1254390065b1SAlfred Perlstein 	pxfer0 = libusb10_get_transfer(pdev, endpoint, 0);
1255390065b1SAlfred Perlstein 	pxfer1 = libusb10_get_transfer(pdev, endpoint, 1);
1256390065b1SAlfred Perlstein 
1257390065b1SAlfred Perlstein 	if (pxfer0 == NULL || pxfer1 == NULL)
1258390065b1SAlfred Perlstein 		return;			/* shouldn't happen */
1259390065b1SAlfred Perlstein 
1260390065b1SAlfred Perlstein 	temp = 0;
1261390065b1SAlfred Perlstein 	if (libusb20_tr_pending(pxfer0))
1262390065b1SAlfred Perlstein 		temp |= 1;
1263390065b1SAlfred Perlstein 	if (libusb20_tr_pending(pxfer1))
1264390065b1SAlfred Perlstein 		temp |= 2;
1265390065b1SAlfred Perlstein 
1266390065b1SAlfred Perlstein 	switch (temp) {
1267390065b1SAlfred Perlstein 	case 3:
1268390065b1SAlfred Perlstein 		/* wait till one of the transfers complete */
1269390065b1SAlfred Perlstein 		return;
1270390065b1SAlfred Perlstein 	case 2:
1271390065b1SAlfred Perlstein 		sxfer = libusb20_tr_get_priv_sc1(pxfer1);
12724594d907SAndrew Thompson 		if (sxfer == NULL)
12734594d907SAndrew Thompson 			return;		/* cancelling */
1274390065b1SAlfred Perlstein 		if (sxfer->rem_len)
1275390065b1SAlfred Perlstein 			return;		/* cannot queue another one */
1276390065b1SAlfred Perlstein 		/* swap transfers */
1277390065b1SAlfred Perlstein 		pxfer1 = pxfer0;
1278390065b1SAlfred Perlstein 		break;
1279390065b1SAlfred Perlstein 	case 1:
1280390065b1SAlfred Perlstein 		sxfer = libusb20_tr_get_priv_sc1(pxfer0);
12814594d907SAndrew Thompson 		if (sxfer == NULL)
12824594d907SAndrew Thompson 			return;		/* cancelling */
1283390065b1SAlfred Perlstein 		if (sxfer->rem_len)
1284390065b1SAlfred Perlstein 			return;		/* cannot queue another one */
1285390065b1SAlfred Perlstein 		/* swap transfers */
1286390065b1SAlfred Perlstein 		pxfer0 = pxfer1;
1287c500e4ddSAndrew Thompson 		break;
1288c500e4ddSAndrew Thompson 	default:
1289c500e4ddSAndrew Thompson 		break;
1290c500e4ddSAndrew Thompson 	}
1291c500e4ddSAndrew Thompson 
1292390065b1SAlfred Perlstein 	/* find next transfer on same endpoint */
1293390065b1SAlfred Perlstein 	TAILQ_FOREACH(sxfer, &dev->tr_head, entry) {
1294390065b1SAlfred Perlstein 
1295390065b1SAlfred Perlstein 		uxfer = (struct libusb_transfer *)(
1296390065b1SAlfred Perlstein 		    ((uint8_t *)sxfer) + sizeof(*sxfer));
1297390065b1SAlfred Perlstein 
1298390065b1SAlfred Perlstein 		if (uxfer->endpoint == endpoint) {
1299390065b1SAlfred Perlstein 			TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
1300390065b1SAlfred Perlstein 			sxfer->entry.tqe_prev = NULL;
1301390065b1SAlfred Perlstein 			goto found;
1302c500e4ddSAndrew Thompson 		}
1303c500e4ddSAndrew Thompson 	}
1304390065b1SAlfred Perlstein 	return;				/* success */
1305390065b1SAlfred Perlstein 
1306390065b1SAlfred Perlstein found:
1307390065b1SAlfred Perlstein 
1308390065b1SAlfred Perlstein 	libusb20_tr_set_priv_sc0(pxfer0, pdev);
1309390065b1SAlfred Perlstein 	libusb20_tr_set_priv_sc1(pxfer0, sxfer);
1310390065b1SAlfred Perlstein 
1311390065b1SAlfred Perlstein 	/* reset super transfer state */
1312390065b1SAlfred Perlstein 	sxfer->rem_len = uxfer->length;
1313390065b1SAlfred Perlstein 	sxfer->curr_data = uxfer->buffer;
1314390065b1SAlfred Perlstein 	uxfer->actual_length = 0;
1315390065b1SAlfred Perlstein 
1316390065b1SAlfred Perlstein 	switch (uxfer->type) {
1317390065b1SAlfred Perlstein 	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
1318390065b1SAlfred Perlstein 		libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
1319390065b1SAlfred Perlstein 		break;
1320390065b1SAlfred Perlstein 	case LIBUSB_TRANSFER_TYPE_BULK:
1321390065b1SAlfred Perlstein 	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
1322390065b1SAlfred Perlstein 		libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
1323390065b1SAlfred Perlstein 		break;
1324390065b1SAlfred Perlstein 	case LIBUSB_TRANSFER_TYPE_CONTROL:
1325390065b1SAlfred Perlstein 		libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy);
1326390065b1SAlfred Perlstein 		if (sxfer->rem_len < 8)
1327390065b1SAlfred Perlstein 			goto failure;
1328390065b1SAlfred Perlstein 
1329390065b1SAlfred Perlstein 		/* remove SETUP packet from data */
1330390065b1SAlfred Perlstein 		sxfer->rem_len -= 8;
1331390065b1SAlfred Perlstein 		sxfer->curr_data += 8;
1332390065b1SAlfred Perlstein 		break;
1333390065b1SAlfred Perlstein 	default:
1334390065b1SAlfred Perlstein 		goto failure;
1335390065b1SAlfred Perlstein 	}
1336390065b1SAlfred Perlstein 
1337390065b1SAlfred Perlstein 	buffsize = libusb10_get_buffsize(pdev, uxfer);
1338390065b1SAlfred Perlstein 	maxframe = libusb10_get_maxframe(pdev, uxfer);
1339390065b1SAlfred Perlstein 
1340390065b1SAlfred Perlstein 	/* make sure the transfer is opened */
1341390065b1SAlfred Perlstein 	err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint);
1342390065b1SAlfred Perlstein 	if (err && (err != LIBUSB20_ERROR_BUSY)) {
1343390065b1SAlfred Perlstein 		goto failure;
1344390065b1SAlfred Perlstein 	}
1345390065b1SAlfred Perlstein 	libusb20_tr_start(pxfer0);
1346390065b1SAlfred Perlstein 	return;
1347390065b1SAlfred Perlstein 
1348390065b1SAlfred Perlstein failure:
1349390065b1SAlfred Perlstein 	libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
1350390065b1SAlfred Perlstein 
1351390065b1SAlfred Perlstein 	/* make sure our event loop spins the done handler */
1352390065b1SAlfred Perlstein 	dummy = 0;
135366194130SHans Petter Selasky 	err = write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
1354390065b1SAlfred Perlstein }
1355390065b1SAlfred Perlstein 
1356390065b1SAlfred Perlstein /* The following function must be called unlocked */
1357c500e4ddSAndrew Thompson 
13588c8fff31SAndrew Thompson int
1359390065b1SAlfred Perlstein libusb_submit_transfer(struct libusb_transfer *uxfer)
13608c8fff31SAndrew Thompson {
1361390065b1SAlfred Perlstein 	struct libusb20_transfer *pxfer0;
1362390065b1SAlfred Perlstein 	struct libusb20_transfer *pxfer1;
1363390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
1364390065b1SAlfred Perlstein 	struct libusb_device *dev;
136585ff9a03SHans Petter Selasky 	uint8_t endpoint;
1366390065b1SAlfred Perlstein 	int err;
13678c8fff31SAndrew Thompson 
1368390065b1SAlfred Perlstein 	if (uxfer == NULL)
1369390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
13708c8fff31SAndrew Thompson 
1371390065b1SAlfred Perlstein 	if (uxfer->dev_handle == NULL)
1372390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
13738c8fff31SAndrew Thompson 
1374390065b1SAlfred Perlstein 	endpoint = uxfer->endpoint;
13758c8fff31SAndrew Thompson 
1376390065b1SAlfred Perlstein 	dev = libusb_get_device(uxfer->dev_handle);
13778c8fff31SAndrew Thompson 
1378390065b1SAlfred Perlstein 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
13798c8fff31SAndrew Thompson 
1380390065b1SAlfred Perlstein 	sxfer = (struct libusb_super_transfer *)(
1381390065b1SAlfred Perlstein 	    (uint8_t *)uxfer - sizeof(*sxfer));
1382390065b1SAlfred Perlstein 
1383390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
1384390065b1SAlfred Perlstein 
1385390065b1SAlfred Perlstein 	pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
1386390065b1SAlfred Perlstein 	pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
1387390065b1SAlfred Perlstein 
1388390065b1SAlfred Perlstein 	if (pxfer0 == NULL || pxfer1 == NULL) {
1389390065b1SAlfred Perlstein 		err = LIBUSB_ERROR_OTHER;
1390390065b1SAlfred Perlstein 	} else if ((sxfer->entry.tqe_prev != NULL) ||
1391390065b1SAlfred Perlstein 	    (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) ||
1392390065b1SAlfred Perlstein 	    (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) {
1393390065b1SAlfred Perlstein 		err = LIBUSB_ERROR_BUSY;
1394390065b1SAlfred Perlstein 	} else {
13954594d907SAndrew Thompson 
13964594d907SAndrew Thompson 		/* set pending state */
13974594d907SAndrew Thompson 		sxfer->state = LIBUSB_SUPER_XFER_ST_PEND;
13984594d907SAndrew Thompson 
13994594d907SAndrew Thompson 		/* insert transfer into transfer head list */
1400390065b1SAlfred Perlstein 		TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry);
1401390065b1SAlfred Perlstein 
14024594d907SAndrew Thompson 		/* start work transfers */
1403390065b1SAlfred Perlstein 		libusb10_submit_transfer_sub(
1404390065b1SAlfred Perlstein 		    uxfer->dev_handle, endpoint);
1405390065b1SAlfred Perlstein 
1406390065b1SAlfred Perlstein 		err = 0;		/* success */
14078c8fff31SAndrew Thompson 	}
14088c8fff31SAndrew Thompson 
1409390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
1410390065b1SAlfred Perlstein 
1411390065b1SAlfred Perlstein 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
1412390065b1SAlfred Perlstein 
1413390065b1SAlfred Perlstein 	return (err);
14148c8fff31SAndrew Thompson }
14158c8fff31SAndrew Thompson 
1416390065b1SAlfred Perlstein /* Asynchronous transfer cancel */
14178c8fff31SAndrew Thompson 
1418390065b1SAlfred Perlstein int
1419390065b1SAlfred Perlstein libusb_cancel_transfer(struct libusb_transfer *uxfer)
1420390065b1SAlfred Perlstein {
1421390065b1SAlfred Perlstein 	struct libusb20_transfer *pxfer0;
1422390065b1SAlfred Perlstein 	struct libusb20_transfer *pxfer1;
1423390065b1SAlfred Perlstein 	struct libusb_super_transfer *sxfer;
1424390065b1SAlfred Perlstein 	struct libusb_device *dev;
142585ff9a03SHans Petter Selasky 	uint8_t endpoint;
14264594d907SAndrew Thompson 	int retval;
14278c8fff31SAndrew Thompson 
1428390065b1SAlfred Perlstein 	if (uxfer == NULL)
1429390065b1SAlfred Perlstein 		return (LIBUSB_ERROR_INVALID_PARAM);
14308c8fff31SAndrew Thompson 
14314594d907SAndrew Thompson 	/* check if not initialised */
1432390065b1SAlfred Perlstein 	if (uxfer->dev_handle == NULL)
14334594d907SAndrew Thompson 		return (LIBUSB_ERROR_NOT_FOUND);
14348c8fff31SAndrew Thompson 
1435390065b1SAlfred Perlstein 	endpoint = uxfer->endpoint;
14368c8fff31SAndrew Thompson 
1437390065b1SAlfred Perlstein 	dev = libusb_get_device(uxfer->dev_handle);
14388c8fff31SAndrew Thompson 
1439390065b1SAlfred Perlstein 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
14408c8fff31SAndrew Thompson 
1441390065b1SAlfred Perlstein 	sxfer = (struct libusb_super_transfer *)(
1442390065b1SAlfred Perlstein 	    (uint8_t *)uxfer - sizeof(*sxfer));
1443390065b1SAlfred Perlstein 
14444594d907SAndrew Thompson 	retval = 0;
14454594d907SAndrew Thompson 
1446390065b1SAlfred Perlstein 	CTX_LOCK(dev->ctx);
1447390065b1SAlfred Perlstein 
1448390065b1SAlfred Perlstein 	pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
1449390065b1SAlfred Perlstein 	pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
1450390065b1SAlfred Perlstein 
14514594d907SAndrew Thompson 	if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) {
14524594d907SAndrew Thompson 		/* only update the transfer status */
14534594d907SAndrew Thompson 		uxfer->status = LIBUSB_TRANSFER_CANCELLED;
14544594d907SAndrew Thompson 		retval = LIBUSB_ERROR_NOT_FOUND;
14554594d907SAndrew Thompson 	} else if (sxfer->entry.tqe_prev != NULL) {
1456390065b1SAlfred Perlstein 		/* we are lucky - transfer is on a queue */
1457390065b1SAlfred Perlstein 		TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
1458390065b1SAlfred Perlstein 		sxfer->entry.tqe_prev = NULL;
14594594d907SAndrew Thompson 		libusb10_complete_transfer(NULL,
14604594d907SAndrew Thompson 		    sxfer, LIBUSB_TRANSFER_CANCELLED);
1461390065b1SAlfred Perlstein 	} else if (pxfer0 == NULL || pxfer1 == NULL) {
1462390065b1SAlfred Perlstein 		/* not started */
14634594d907SAndrew Thompson 		retval = LIBUSB_ERROR_NOT_FOUND;
1464390065b1SAlfred Perlstein 	} else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) {
14654594d907SAndrew Thompson 		libusb10_complete_transfer(pxfer0,
14664594d907SAndrew Thompson 		    sxfer, LIBUSB_TRANSFER_CANCELLED);
1467390065b1SAlfred Perlstein 		libusb20_tr_stop(pxfer0);
1468390065b1SAlfred Perlstein 		/* make sure the queue doesn't stall */
1469390065b1SAlfred Perlstein 		libusb10_submit_transfer_sub(
1470390065b1SAlfred Perlstein 		    uxfer->dev_handle, endpoint);
1471390065b1SAlfred Perlstein 	} else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) {
14724594d907SAndrew Thompson 		libusb10_complete_transfer(pxfer1,
14734594d907SAndrew Thompson 		    sxfer, LIBUSB_TRANSFER_CANCELLED);
1474390065b1SAlfred Perlstein 		libusb20_tr_stop(pxfer1);
1475390065b1SAlfred Perlstein 		/* make sure the queue doesn't stall */
1476390065b1SAlfred Perlstein 		libusb10_submit_transfer_sub(
1477390065b1SAlfred Perlstein 		    uxfer->dev_handle, endpoint);
1478390065b1SAlfred Perlstein 	} else {
1479390065b1SAlfred Perlstein 		/* not started */
14804594d907SAndrew Thompson 		retval = LIBUSB_ERROR_NOT_FOUND;
1481c500e4ddSAndrew Thompson 	}
14828c8fff31SAndrew Thompson 
1483390065b1SAlfred Perlstein 	CTX_UNLOCK(dev->ctx);
14848c8fff31SAndrew Thompson 
1485390065b1SAlfred Perlstein 	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
14868c8fff31SAndrew Thompson 
14874594d907SAndrew Thompson 	return (retval);
14888c8fff31SAndrew Thompson }
14898c8fff31SAndrew Thompson 
1490390065b1SAlfred Perlstein UNEXPORTED void
1491390065b1SAlfred Perlstein libusb10_cancel_all_transfer(libusb_device *dev)
14928c8fff31SAndrew Thompson {
1493390065b1SAlfred Perlstein 	/* TODO */
14948c8fff31SAndrew Thompson }
1495ccef4ddfSAndrew Thompson 
1496ccef4ddfSAndrew Thompson uint16_t
1497ccef4ddfSAndrew Thompson libusb_cpu_to_le16(uint16_t x)
1498ccef4ddfSAndrew Thompson {
1499ccef4ddfSAndrew Thompson 	return (htole16(x));
1500ccef4ddfSAndrew Thompson }
1501ccef4ddfSAndrew Thompson 
1502ccef4ddfSAndrew Thompson uint16_t
1503ccef4ddfSAndrew Thompson libusb_le16_to_cpu(uint16_t x)
1504ccef4ddfSAndrew Thompson {
1505ccef4ddfSAndrew Thompson 	return (le16toh(x));
1506ccef4ddfSAndrew Thompson }
1507ccef4ddfSAndrew Thompson 
1508698e791aSHans Petter Selasky const char *
1509698e791aSHans Petter Selasky libusb_strerror(int code)
1510698e791aSHans Petter Selasky {
1511c61f2561SHans Petter Selasky 	switch (code) {
1512c61f2561SHans Petter Selasky 	case LIBUSB_SUCCESS:
1513c61f2561SHans Petter Selasky 		return ("Success");
1514c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_IO:
1515c61f2561SHans Petter Selasky 		return ("I/O error");
1516c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_INVALID_PARAM:
1517c61f2561SHans Petter Selasky 		return ("Invalid parameter");
1518c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_ACCESS:
1519c61f2561SHans Petter Selasky 		return ("Permissions error");
1520c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NO_DEVICE:
1521c61f2561SHans Petter Selasky 		return ("No device");
1522c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NOT_FOUND:
1523c61f2561SHans Petter Selasky 		return ("Not found");
1524c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_BUSY:
1525c61f2561SHans Petter Selasky 		return ("Device busy");
1526c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_TIMEOUT:
1527c61f2561SHans Petter Selasky 		return ("Timeout");
1528c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_OVERFLOW:
1529c61f2561SHans Petter Selasky 		return ("Overflow");
1530c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_PIPE:
1531c61f2561SHans Petter Selasky 		return ("Pipe error");
1532c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_INTERRUPTED:
1533c61f2561SHans Petter Selasky 		return ("Interrupted");
1534c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NO_MEM:
1535c61f2561SHans Petter Selasky 		return ("Out of memory");
1536c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NOT_SUPPORTED:
1537c61f2561SHans Petter Selasky 		return ("Not supported");
1538c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_OTHER:
1539c61f2561SHans Petter Selasky 		return ("Other error");
1540c61f2561SHans Petter Selasky 	default:
1541698e791aSHans Petter Selasky 		return ("Unknown error");
1542698e791aSHans Petter Selasky 	}
1543c61f2561SHans Petter Selasky }
1544c61f2561SHans Petter Selasky 
1545c61f2561SHans Petter Selasky const char *
1546c61f2561SHans Petter Selasky libusb_error_name(int code)
1547c61f2561SHans Petter Selasky {
1548c61f2561SHans Petter Selasky 	switch (code) {
1549c61f2561SHans Petter Selasky 	case LIBUSB_SUCCESS:
1550c61f2561SHans Petter Selasky 		return ("LIBUSB_SUCCESS");
1551c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_IO:
1552c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_IO");
1553c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_INVALID_PARAM:
1554c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_INVALID_PARAM");
1555c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_ACCESS:
1556c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_ACCESS");
1557c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NO_DEVICE:
1558c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_NO_DEVICE");
1559c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NOT_FOUND:
1560c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_NOT_FOUND");
1561c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_BUSY:
1562c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_BUSY");
1563c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_TIMEOUT:
1564c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_TIMEOUT");
1565c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_OVERFLOW:
1566c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_OVERFLOW");
1567c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_PIPE:
1568c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_PIPE");
1569c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_INTERRUPTED:
1570c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_INTERRUPTED");
1571c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NO_MEM:
1572c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_NO_MEM");
1573c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_NOT_SUPPORTED:
1574c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_NOT_SUPPORTED");
1575c61f2561SHans Petter Selasky 	case LIBUSB_ERROR_OTHER:
1576c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_OTHER");
1577c61f2561SHans Petter Selasky 	default:
1578c61f2561SHans Petter Selasky 		return ("LIBUSB_ERROR_UNKNOWN");
1579c61f2561SHans Petter Selasky 	}
1580c61f2561SHans Petter Selasky }
1581