libusb10.c revision 195957
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10.c 195957 2009-07-30 00:11:41Z alfred $ */
2194676Sthompsa/*-
3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
4195957Salfred * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
5194676Sthompsa *
6194676Sthompsa * Redistribution and use in source and binary forms, with or without
7194676Sthompsa * modification, are permitted provided that the following conditions
8194676Sthompsa * are met:
9194676Sthompsa * 1. Redistributions of source code must retain the above copyright
10194676Sthompsa *    notice, this list of conditions and the following disclaimer.
11194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright
12194676Sthompsa *    notice, this list of conditions and the following disclaimer in the
13194676Sthompsa *    documentation and/or other materials provided with the distribution.
14194676Sthompsa *
15194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18194676Sthompsa * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25194676Sthompsa * SUCH DAMAGE.
26194676Sthompsa */
27194676Sthompsa
28194676Sthompsa#include <stdlib.h>
29194676Sthompsa#include <unistd.h>
30194676Sthompsa#include <stdio.h>
31194676Sthompsa#include <poll.h>
32194676Sthompsa#include <pthread.h>
33194676Sthompsa#include <time.h>
34194676Sthompsa#include <errno.h>
35195957Salfred#include <sys/ioctl.h>
36195957Salfred#include <sys/filio.h>
37195957Salfred#include <sys/queue.h>
38194676Sthompsa
39194676Sthompsa#include "libusb20.h"
40194676Sthompsa#include "libusb20_desc.h"
41194676Sthompsa#include "libusb20_int.h"
42194676Sthompsa#include "libusb.h"
43194676Sthompsa#include "libusb10.h"
44194676Sthompsa
45194676Sthompsastatic pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER;
46194676Sthompsastruct libusb_context *usbi_default_context = NULL;
47194676Sthompsa
48195957Salfred/* Prototypes */
49195957Salfred
50195957Salfredstatic struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t);
51195957Salfredstatic int libusb10_get_maxframe(struct libusb20_device *, libusb_transfer *);
52195957Salfredstatic int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *);
53195957Salfredstatic int libusb10_convert_error(uint8_t status);
54195957Salfredstatic void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int);
55195957Salfredstatic void libusb10_isoc_proxy(struct libusb20_transfer *);
56195957Salfredstatic void libusb10_bulk_intr_proxy(struct libusb20_transfer *);
57195957Salfredstatic void libusb10_ctrl_proxy(struct libusb20_transfer *);
58195957Salfredstatic void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t);
59195957Salfred
60194676Sthompsa/*  Library initialisation / deinitialisation */
61194676Sthompsa
62194676Sthompsavoid
63195957Salfredlibusb_set_debug(libusb_context *ctx, int level)
64194676Sthompsa{
65195957Salfred	ctx = GET_CONTEXT(ctx);
66194676Sthompsa	if (ctx)
67194676Sthompsa		ctx->debug = level;
68194676Sthompsa}
69194676Sthompsa
70194676Sthompsaint
71195957Salfredlibusb_init(libusb_context **context)
72194676Sthompsa{
73194676Sthompsa	struct libusb_context *ctx;
74195957Salfred	char *debug;
75194676Sthompsa	int ret;
76194676Sthompsa
77194676Sthompsa	ctx = malloc(sizeof(*ctx));
78194676Sthompsa	if (!ctx)
79194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
80194676Sthompsa
81194676Sthompsa	memset(ctx, 0, sizeof(*ctx));
82194676Sthompsa
83194676Sthompsa	debug = getenv("LIBUSB_DEBUG");
84194676Sthompsa	if (debug != NULL) {
85194676Sthompsa		ctx->debug = atoi(debug);
86194676Sthompsa		if (ctx->debug != 0)
87194676Sthompsa			ctx->debug_fixed = 1;
88194676Sthompsa	}
89195957Salfred	TAILQ_INIT(&ctx->pollfds);
90195957Salfred	TAILQ_INIT(&ctx->tr_done);
91194676Sthompsa
92195957Salfred	pthread_mutex_init(&ctx->ctx_lock, NULL);
93195957Salfred	pthread_cond_init(&ctx->ctx_cond, NULL);
94194676Sthompsa
95195957Salfred	ctx->ctx_handler = NO_THREAD;
96194676Sthompsa
97194676Sthompsa	ret = pipe(ctx->ctrl_pipe);
98194676Sthompsa	if (ret < 0) {
99195957Salfred		pthread_mutex_destroy(&ctx->ctx_lock);
100195957Salfred		pthread_cond_destroy(&ctx->ctx_cond);
101194676Sthompsa		free(ctx);
102194676Sthompsa		return (LIBUSB_ERROR_OTHER);
103194676Sthompsa	}
104195957Salfred	/* set non-blocking mode on the control pipe to avoid deadlock */
105195957Salfred	ret = 1;
106195957Salfred	ioctl(ctx->ctrl_pipe[0], FIONBIO, &ret);
107195957Salfred	ret = 1;
108195957Salfred	ioctl(ctx->ctrl_pipe[1], FIONBIO, &ret);
109194676Sthompsa
110195957Salfred	libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN);
111194676Sthompsa
112194676Sthompsa	pthread_mutex_lock(&default_context_lock);
113194676Sthompsa	if (usbi_default_context == NULL) {
114194676Sthompsa		usbi_default_context = ctx;
115194676Sthompsa	}
116194676Sthompsa	pthread_mutex_unlock(&default_context_lock);
117194676Sthompsa
118194676Sthompsa	if (context)
119194676Sthompsa		*context = ctx;
120194676Sthompsa
121195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
122195957Salfred
123194676Sthompsa	return (0);
124194676Sthompsa}
125194676Sthompsa
126194676Sthompsavoid
127195957Salfredlibusb_exit(libusb_context *ctx)
128194676Sthompsa{
129195957Salfred	ctx = GET_CONTEXT(ctx);
130194676Sthompsa
131195957Salfred	if (ctx == NULL)
132195957Salfred		return;
133195957Salfred
134195957Salfred	/* XXX cleanup devices */
135195957Salfred
136195957Salfred	libusb10_remove_pollfd(ctx, &ctx->ctx_poll);
137194676Sthompsa	close(ctx->ctrl_pipe[0]);
138194676Sthompsa	close(ctx->ctrl_pipe[1]);
139195957Salfred	pthread_mutex_destroy(&ctx->ctx_lock);
140195957Salfred	pthread_cond_destroy(&ctx->ctx_cond);
141194676Sthompsa
142194676Sthompsa	pthread_mutex_lock(&default_context_lock);
143194676Sthompsa	if (ctx == usbi_default_context) {
144194676Sthompsa		usbi_default_context = NULL;
145194676Sthompsa	}
146194676Sthompsa	pthread_mutex_unlock(&default_context_lock);
147194676Sthompsa
148194676Sthompsa	free(ctx);
149194676Sthompsa}
150194676Sthompsa
151194676Sthompsa/* Device handling and initialisation. */
152194676Sthompsa
153194676Sthompsassize_t
154195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list)
155194676Sthompsa{
156195957Salfred	struct libusb20_backend *usb_backend;
157194676Sthompsa	struct libusb20_device *pdev;
158194676Sthompsa	struct libusb_device *dev;
159194676Sthompsa	int i;
160194676Sthompsa
161195957Salfred	ctx = GET_CONTEXT(ctx);
162194676Sthompsa
163195957Salfred	if (ctx == NULL)
164195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
165195957Salfred
166195957Salfred	if (list == NULL)
167195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
168195957Salfred
169194676Sthompsa	usb_backend = libusb20_be_alloc_default();
170194676Sthompsa	if (usb_backend == NULL)
171195957Salfred		return (LIBUSB_ERROR_NO_MEM);
172194676Sthompsa
173195957Salfred	/* figure out how many USB devices are present */
174194676Sthompsa	pdev = NULL;
175194676Sthompsa	i = 0;
176194676Sthompsa	while ((pdev = libusb20_be_device_foreach(usb_backend, pdev)))
177194676Sthompsa		i++;
178194676Sthompsa
179195957Salfred	/* allocate device pointer list */
180194676Sthompsa	*list = malloc((i + 1) * sizeof(void *));
181194676Sthompsa	if (*list == NULL) {
182194676Sthompsa		libusb20_be_free(usb_backend);
183194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
184194676Sthompsa	}
185195957Salfred	/* create libusb v1.0 compliant devices */
186194676Sthompsa	i = 0;
187194676Sthompsa	while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
188194676Sthompsa		/* get device into libUSB v1.0 list */
189194676Sthompsa		libusb20_be_dequeue_device(usb_backend, pdev);
190194676Sthompsa
191194676Sthompsa		dev = malloc(sizeof(*dev));
192194676Sthompsa		if (dev == NULL) {
193195560Sthompsa			while (i != 0) {
194195560Sthompsa				libusb_unref_device((*list)[i - 1]);
195195560Sthompsa				i--;
196195560Sthompsa			}
197194676Sthompsa			free(*list);
198195957Salfred			*list = NULL;
199194676Sthompsa			libusb20_be_free(usb_backend);
200194676Sthompsa			return (LIBUSB_ERROR_NO_MEM);
201194676Sthompsa		}
202194676Sthompsa		memset(dev, 0, sizeof(*dev));
203194676Sthompsa
204195957Salfred		/* init transfer queues */
205195957Salfred		TAILQ_INIT(&dev->tr_head);
206195957Salfred
207195957Salfred		/* set context we belong to */
208194676Sthompsa		dev->ctx = ctx;
209194676Sthompsa
210194676Sthompsa		/* link together the two structures */
211194676Sthompsa		dev->os_priv = pdev;
212195957Salfred		pdev->privLuData = dev;
213194676Sthompsa
214194676Sthompsa		(*list)[i] = libusb_ref_device(dev);
215194676Sthompsa		i++;
216194676Sthompsa	}
217194676Sthompsa	(*list)[i] = NULL;
218194676Sthompsa
219194676Sthompsa	libusb20_be_free(usb_backend);
220194676Sthompsa	return (i);
221194676Sthompsa}
222194676Sthompsa
223194676Sthompsavoid
224194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices)
225194676Sthompsa{
226194676Sthompsa	int i;
227194676Sthompsa
228194676Sthompsa	if (list == NULL)
229195957Salfred		return;			/* be NULL safe */
230194676Sthompsa
231194676Sthompsa	if (unref_devices) {
232194676Sthompsa		for (i = 0; list[i] != NULL; i++)
233194676Sthompsa			libusb_unref_device(list[i]);
234194676Sthompsa	}
235194676Sthompsa	free(list);
236194676Sthompsa}
237194676Sthompsa
238194676Sthompsauint8_t
239195957Salfredlibusb_get_bus_number(libusb_device *dev)
240194676Sthompsa{
241194676Sthompsa	if (dev == NULL)
242195957Salfred		return (0);		/* should not happen */
243195957Salfred	return (libusb20_dev_get_bus_number(dev->os_priv));
244194676Sthompsa}
245194676Sthompsa
246194676Sthompsauint8_t
247195957Salfredlibusb_get_device_address(libusb_device *dev)
248194676Sthompsa{
249194676Sthompsa	if (dev == NULL)
250195957Salfred		return (0);		/* should not happen */
251195957Salfred	return (libusb20_dev_get_address(dev->os_priv));
252194676Sthompsa}
253194676Sthompsa
254194676Sthompsaint
255195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint)
256194676Sthompsa{
257194676Sthompsa	struct libusb_config_descriptor *pdconf;
258194676Sthompsa	struct libusb_interface *pinf;
259194676Sthompsa	struct libusb_interface_descriptor *pdinf;
260194676Sthompsa	struct libusb_endpoint_descriptor *pdend;
261195957Salfred	int i;
262195957Salfred	int j;
263195957Salfred	int k;
264195957Salfred	int ret;
265194676Sthompsa
266194676Sthompsa	if (dev == NULL)
267194676Sthompsa		return (LIBUSB_ERROR_NO_DEVICE);
268194676Sthompsa
269195957Salfred	ret = libusb_get_active_config_descriptor(dev, &pdconf);
270195957Salfred	if (ret < 0)
271195957Salfred		return (ret);
272195957Salfred
273194676Sthompsa	ret = LIBUSB_ERROR_NOT_FOUND;
274195957Salfred	for (i = 0; i < pdconf->bNumInterfaces; i++) {
275194676Sthompsa		pinf = &pdconf->interface[i];
276195957Salfred		for (j = 0; j < pinf->num_altsetting; j++) {
277194676Sthompsa			pdinf = &pinf->altsetting[j];
278195957Salfred			for (k = 0; k < pdinf->bNumEndpoints; k++) {
279194676Sthompsa				pdend = &pdinf->endpoint[k];
280194676Sthompsa				if (pdend->bEndpointAddress == endpoint) {
281194676Sthompsa					ret = pdend->wMaxPacketSize;
282194676Sthompsa					goto out;
283194676Sthompsa				}
284194676Sthompsa			}
285194676Sthompsa		}
286194676Sthompsa	}
287194676Sthompsa
288194676Sthompsaout:
289194676Sthompsa	libusb_free_config_descriptor(pdconf);
290194676Sthompsa	return (ret);
291194676Sthompsa}
292194676Sthompsa
293194676Sthompsalibusb_device *
294195957Salfredlibusb_ref_device(libusb_device *dev)
295194676Sthompsa{
296194676Sthompsa	if (dev == NULL)
297195957Salfred		return (NULL);		/* be NULL safe */
298194676Sthompsa
299195957Salfred	CTX_LOCK(dev->ctx);
300194676Sthompsa	dev->refcnt++;
301195957Salfred	CTX_UNLOCK(dev->ctx);
302194676Sthompsa
303194676Sthompsa	return (dev);
304194676Sthompsa}
305194676Sthompsa
306194676Sthompsavoid
307195957Salfredlibusb_unref_device(libusb_device *dev)
308194676Sthompsa{
309194676Sthompsa	if (dev == NULL)
310195957Salfred		return;			/* be NULL safe */
311194676Sthompsa
312195957Salfred	CTX_LOCK(dev->ctx);
313194676Sthompsa	dev->refcnt--;
314195957Salfred	CTX_UNLOCK(dev->ctx);
315194676Sthompsa
316194676Sthompsa	if (dev->refcnt == 0) {
317194676Sthompsa		libusb20_dev_free(dev->os_priv);
318194676Sthompsa		free(dev);
319194676Sthompsa	}
320194676Sthompsa}
321194676Sthompsa
322194676Sthompsaint
323195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh)
324194676Sthompsa{
325194676Sthompsa	libusb_context *ctx = dev->ctx;
326194676Sthompsa	struct libusb20_device *pdev = dev->os_priv;
327195957Salfred	uint8_t dummy;
328194676Sthompsa	int err;
329194676Sthompsa
330194676Sthompsa	if (devh == NULL)
331194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
332194676Sthompsa
333195957Salfred	/* set default device handle value */
334195957Salfred	*devh = NULL;
335194676Sthompsa
336195957Salfred	dev = libusb_ref_device(dev);
337195957Salfred	if (dev == NULL)
338195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
339195957Salfred
340194676Sthompsa	err = libusb20_dev_open(pdev, 16 * 4 /* number of endpoints */ );
341194676Sthompsa	if (err) {
342195957Salfred		libusb_unref_device(dev);
343194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
344194676Sthompsa	}
345195957Salfred	libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
346194676Sthompsa	    POLLOUT | POLLRDNORM | POLLWRNORM);
347194676Sthompsa
348195957Salfred	/* make sure our event loop detects the new device */
349195957Salfred	dummy = 0;
350194676Sthompsa	err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
351195957Salfred	if (err < sizeof(dummy)) {
352195957Salfred		/* ignore error, if any */
353195957Salfred		DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open write failed!");
354194676Sthompsa	}
355195957Salfred	*devh = pdev;
356194676Sthompsa
357194676Sthompsa	return (0);
358194676Sthompsa}
359194676Sthompsa
360194676Sthompsalibusb_device_handle *
361195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
362194676Sthompsa    uint16_t product_id)
363194676Sthompsa{
364194676Sthompsa	struct libusb_device **devs;
365194676Sthompsa	struct libusb20_device *pdev;
366194676Sthompsa	struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
367195957Salfred	int i;
368195957Salfred	int j;
369194676Sthompsa
370195957Salfred	ctx = GET_CONTEXT(ctx);
371195957Salfred	if (ctx == NULL)
372195957Salfred		return (NULL);		/* be NULL safe */
373195957Salfred
374195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid enter");
375194676Sthompsa
376194676Sthompsa	if ((i = libusb_get_device_list(ctx, &devs)) < 0)
377194676Sthompsa		return (NULL);
378194676Sthompsa
379195957Salfred	pdev = NULL;
380195957Salfred
381194676Sthompsa	for (j = 0; j < i; j++) {
382195957Salfred		pdev = devs[j]->os_priv;
383194676Sthompsa		pdesc = libusb20_dev_get_device_desc(pdev);
384195957Salfred		/*
385195957Salfred		 * NOTE: The USB library will automatically swap the
386195957Salfred		 * fields in the device descriptor to be of host
387195957Salfred		 * endian type!
388195957Salfred		 */
389194676Sthompsa		if (pdesc->idVendor == vendor_id &&
390195560Sthompsa		    pdesc->idProduct == product_id) {
391195957Salfred			if (libusb_open(devs[j], &pdev) < 0)
392195957Salfred				pdev = NULL;
393195957Salfred			break;
394195560Sthompsa		}
395194676Sthompsa	}
396194676Sthompsa
397194676Sthompsa	libusb_free_device_list(devs, 1);
398195560Sthompsa	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_width_vid_pid leave");
399195957Salfred	return (pdev);
400194676Sthompsa}
401194676Sthompsa
402194676Sthompsavoid
403195957Salfredlibusb_close(struct libusb20_device *pdev)
404194676Sthompsa{
405194676Sthompsa	libusb_context *ctx;
406195957Salfred	struct libusb_device *dev;
407195957Salfred	uint8_t dummy;
408194676Sthompsa	int err;
409194676Sthompsa
410195957Salfred	if (pdev == NULL)
411195957Salfred		return;			/* be NULL safe */
412194676Sthompsa
413195957Salfred	dev = libusb_get_device(pdev);
414195957Salfred	ctx = dev->ctx;
415194676Sthompsa
416195957Salfred	libusb10_remove_pollfd(ctx, &dev->dev_poll);
417194676Sthompsa
418195957Salfred	libusb20_dev_close(pdev);
419195957Salfred	libusb_unref_device(dev);
420194676Sthompsa
421195957Salfred	/* make sure our event loop detects the closed device */
422195957Salfred	dummy = 0;
423194676Sthompsa	err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
424195957Salfred	if (err < sizeof(dummy)) {
425195957Salfred		/* ignore error, if any */
426195957Salfred		DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_close write failed!");
427194676Sthompsa	}
428194676Sthompsa}
429194676Sthompsa
430194676Sthompsalibusb_device *
431195957Salfredlibusb_get_device(struct libusb20_device *pdev)
432194676Sthompsa{
433195957Salfred	if (pdev == NULL)
434194676Sthompsa		return (NULL);
435195957Salfred	return ((libusb_device *)pdev->privLuData);
436194676Sthompsa}
437194676Sthompsa
438194676Sthompsaint
439195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config)
440194676Sthompsa{
441195957Salfred	struct libusb20_config *pconf;
442194676Sthompsa
443195957Salfred	if (pdev == NULL || config == NULL)
444194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
445194676Sthompsa
446195957Salfred	pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev));
447195957Salfred	if (pconf == NULL)
448195957Salfred		return (LIBUSB_ERROR_NO_MEM);
449194676Sthompsa
450195957Salfred	*config = pconf->desc.bConfigurationValue;
451195957Salfred
452195957Salfred	free(pconf);
453195957Salfred
454194676Sthompsa	return (0);
455194676Sthompsa}
456194676Sthompsa
457194676Sthompsaint
458195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration)
459194676Sthompsa{
460195957Salfred	struct libusb20_config *pconf;
461195957Salfred	struct libusb_device *dev;
462195957Salfred	int err;
463195957Salfred	uint8_t i;
464194676Sthompsa
465195957Salfred	dev = libusb_get_device(pdev);
466194676Sthompsa
467195957Salfred	if (dev == NULL)
468194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
469194676Sthompsa
470195957Salfred	if (configuration < 1) {
471195957Salfred		/* unconfigure */
472195957Salfred		i = 255;
473195957Salfred	} else {
474195957Salfred		for (i = 0; i != 255; i++) {
475195957Salfred			uint8_t found;
476194676Sthompsa
477195957Salfred			pconf = libusb20_dev_alloc_config(pdev, i);
478195957Salfred			if (pconf == NULL)
479195957Salfred				return (LIBUSB_ERROR_INVALID_PARAM);
480195957Salfred			found = (pconf->desc.bConfigurationValue
481195957Salfred			    == configuration);
482195957Salfred			free(pconf);
483195957Salfred
484195957Salfred			if (found)
485195957Salfred				goto set_config;
486195957Salfred		}
487195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
488195957Salfred	}
489195957Salfred
490195957Salfredset_config:
491195957Salfred
492195957Salfred	libusb10_cancel_all_transfer(dev);
493195957Salfred
494195957Salfred	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
495195957Salfred
496195957Salfred	err = libusb20_dev_set_config_index(pdev, i);
497195957Salfred
498195957Salfred	libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
499195957Salfred	    POLLOUT | POLLRDNORM | POLLWRNORM);
500195957Salfred
501195957Salfred	return (err ? LIBUSB_ERROR_INVALID_PARAM : 0);
502194676Sthompsa}
503194676Sthompsa
504194676Sthompsaint
505195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number)
506194676Sthompsa{
507195957Salfred	libusb_device *dev;
508195957Salfred	int err = 0;
509194676Sthompsa
510195957Salfred	dev = libusb_get_device(pdev);
511194676Sthompsa	if (dev == NULL)
512194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
513194676Sthompsa
514195957Salfred	if (interface_number < 0 || interface_number > 31)
515194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
516194676Sthompsa
517195957Salfred	CTX_LOCK(dev->ctx);
518194676Sthompsa	if (dev->claimed_interfaces & (1 << interface_number))
519195957Salfred		err = LIBUSB_ERROR_BUSY;
520194676Sthompsa
521195957Salfred	if (!err)
522194676Sthompsa		dev->claimed_interfaces |= (1 << interface_number);
523195957Salfred	CTX_UNLOCK(dev->ctx);
524195957Salfred	return (err);
525194676Sthompsa}
526194676Sthompsa
527194676Sthompsaint
528195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number)
529194676Sthompsa{
530195957Salfred	libusb_device *dev;
531195957Salfred	int err = 0;
532194676Sthompsa
533195957Salfred	dev = libusb_get_device(pdev);
534194676Sthompsa	if (dev == NULL)
535194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
536194676Sthompsa
537195957Salfred	if (interface_number < 0 || interface_number > 31)
538194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
539194676Sthompsa
540195957Salfred	CTX_LOCK(dev->ctx);
541194676Sthompsa	if (!(dev->claimed_interfaces & (1 << interface_number)))
542195957Salfred		err = LIBUSB_ERROR_NOT_FOUND;
543194676Sthompsa
544195957Salfred	if (!err)
545194676Sthompsa		dev->claimed_interfaces &= ~(1 << interface_number);
546195957Salfred	CTX_UNLOCK(dev->ctx);
547195957Salfred	return (err);
548194676Sthompsa}
549194676Sthompsa
550194676Sthompsaint
551195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev,
552194676Sthompsa    int interface_number, int alternate_setting)
553194676Sthompsa{
554195957Salfred	libusb_device *dev;
555195957Salfred	int err = 0;
556194676Sthompsa
557195957Salfred	dev = libusb_get_device(pdev);
558194676Sthompsa	if (dev == NULL)
559194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
560194676Sthompsa
561195957Salfred	if (interface_number < 0 || interface_number > 31)
562194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
563194676Sthompsa
564195957Salfred	CTX_LOCK(dev->ctx);
565195957Salfred	if (!(dev->claimed_interfaces & (1 << interface_number)))
566195957Salfred		err = LIBUSB_ERROR_NOT_FOUND;
567195957Salfred	CTX_UNLOCK(dev->ctx);
568194676Sthompsa
569195957Salfred	if (err)
570195957Salfred		return (err);
571195957Salfred
572195957Salfred	libusb10_cancel_all_transfer(dev);
573195957Salfred
574195957Salfred	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
575195957Salfred
576195957Salfred	err = libusb20_dev_set_alt_index(pdev,
577195957Salfred	    interface_number, alternate_setting);
578195957Salfred
579195957Salfred	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
580195957Salfred	    pdev, libusb20_dev_get_fd(pdev),
581195957Salfred	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
582195957Salfred
583195957Salfred	return (err ? LIBUSB_ERROR_OTHER : 0);
584194676Sthompsa}
585194676Sthompsa
586195957Salfredstatic struct libusb20_transfer *
587195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev,
588195957Salfred    uint8_t endpoint, uint8_t index)
589195957Salfred{
590195957Salfred	index &= 1;			/* double buffering */
591195957Salfred
592195957Salfred	index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4;
593195957Salfred
594195957Salfred	if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) {
595195957Salfred		/* this is an IN endpoint */
596195957Salfred		index |= 2;
597195957Salfred	}
598195957Salfred	return (libusb20_tr_get_pointer(pdev, index));
599195957Salfred}
600195957Salfred
601194676Sthompsaint
602195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint)
603194676Sthompsa{
604194676Sthompsa	struct libusb20_transfer *xfer;
605195957Salfred	struct libusb_device *dev;
606195957Salfred	int err;
607194676Sthompsa
608195957Salfred	xfer = libusb10_get_transfer(pdev, endpoint, 0);
609195560Sthompsa	if (xfer == NULL)
610195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
611194676Sthompsa
612195957Salfred	dev = libusb_get_device(pdev);
613195957Salfred
614195957Salfred	CTX_LOCK(dev->ctx);
615195957Salfred	err = libusb20_tr_open(xfer, 0, 0, endpoint);
616195957Salfred	CTX_UNLOCK(dev->ctx);
617195957Salfred
618195957Salfred	if (err != 0 && err != LIBUSB20_ERROR_BUSY)
619194676Sthompsa		return (LIBUSB_ERROR_OTHER);
620194676Sthompsa
621194676Sthompsa	libusb20_tr_clear_stall_sync(xfer);
622195957Salfred
623195957Salfred	/* check if we opened the transfer */
624195957Salfred	if (err == 0) {
625195957Salfred		CTX_LOCK(dev->ctx);
626194676Sthompsa		libusb20_tr_close(xfer);
627195957Salfred		CTX_UNLOCK(dev->ctx);
628195957Salfred	}
629195957Salfred	return (0);			/* success */
630194676Sthompsa}
631194676Sthompsa
632194676Sthompsaint
633195957Salfredlibusb_reset_device(struct libusb20_device *pdev)
634194676Sthompsa{
635195957Salfred	libusb_device *dev;
636195957Salfred	int err;
637194676Sthompsa
638195957Salfred	dev = libusb_get_device(pdev);
639194676Sthompsa	if (dev == NULL)
640194676Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
641194676Sthompsa
642195957Salfred	libusb10_cancel_all_transfer(dev);
643195957Salfred
644195957Salfred	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
645195957Salfred
646195957Salfred	err = libusb20_dev_reset(pdev);
647195957Salfred
648195957Salfred	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
649195957Salfred	    pdev, libusb20_dev_get_fd(pdev),
650195957Salfred	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
651195957Salfred
652195957Salfred	return (err ? LIBUSB_ERROR_OTHER : 0);
653194676Sthompsa}
654194676Sthompsa
655194676Sthompsaint
656195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface)
657194676Sthompsa{
658195957Salfred	if (pdev == NULL)
659194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
660194676Sthompsa
661195957Salfred	return (libusb20_dev_kernel_driver_active(
662195957Salfred	    pdev, interface));
663194676Sthompsa}
664194676Sthompsa
665194676Sthompsaint
666195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface)
667194676Sthompsa{
668195957Salfred	int err;
669194676Sthompsa
670195957Salfred	if (pdev == NULL)
671194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
672194676Sthompsa
673195957Salfred	err = libusb20_dev_detach_kernel_driver(
674195957Salfred	    pdev, interface);
675194676Sthompsa
676195957Salfred	return (err ? LIBUSB20_ERROR_OTHER : 0);
677194676Sthompsa}
678194676Sthompsa
679194676Sthompsaint
680195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface)
681194676Sthompsa{
682195957Salfred	if (pdev == NULL)
683194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
684195957Salfred	/* stub - currently not supported by libusb20 */
685194676Sthompsa	return (0);
686194676Sthompsa}
687194676Sthompsa
688194676Sthompsa/* Asynchronous device I/O */
689194676Sthompsa
690194676Sthompsastruct libusb_transfer *
691194676Sthompsalibusb_alloc_transfer(int iso_packets)
692194676Sthompsa{
693195957Salfred	struct libusb_transfer *uxfer;
694195957Salfred	struct libusb_super_transfer *sxfer;
695194676Sthompsa	int len;
696194676Sthompsa
697194676Sthompsa	len = sizeof(struct libusb_transfer) +
698195957Salfred	    sizeof(struct libusb_super_transfer) +
699194676Sthompsa	    (iso_packets * sizeof(libusb_iso_packet_descriptor));
700194676Sthompsa
701195957Salfred	sxfer = malloc(len);
702195957Salfred	if (sxfer == NULL)
703194676Sthompsa		return (NULL);
704194676Sthompsa
705195957Salfred	memset(sxfer, 0, len);
706194676Sthompsa
707195957Salfred	uxfer = (struct libusb_transfer *)(
708195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
709194676Sthompsa
710195957Salfred	/* set default value */
711195957Salfred	uxfer->num_iso_packets = iso_packets;
712195957Salfred
713195957Salfred	return (uxfer);
714194676Sthompsa}
715194676Sthompsa
716194676Sthompsavoid
717195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer)
718194676Sthompsa{
719195957Salfred	struct libusb_super_transfer *sxfer;
720194676Sthompsa
721195957Salfred	if (uxfer == NULL)
722195957Salfred		return;			/* be NULL safe */
723194676Sthompsa
724195957Salfred	sxfer = (struct libusb_super_transfer *)(
725195957Salfred	    (uint8_t *)uxfer - sizeof(*sxfer));
726194676Sthompsa
727195957Salfred	free(sxfer);
728194676Sthompsa}
729194676Sthompsa
730195560Sthompsastatic int
731195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer)
732195560Sthompsa{
733195560Sthompsa	int ret;
734195560Sthompsa	int usb_speed;
735195560Sthompsa
736195560Sthompsa	usb_speed = libusb20_dev_get_speed(pdev);
737195560Sthompsa
738195560Sthompsa	switch (xfer->type) {
739195560Sthompsa	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
740195560Sthompsa		switch (usb_speed) {
741195560Sthompsa		case LIBUSB20_SPEED_LOW:
742195560Sthompsa		case LIBUSB20_SPEED_FULL:
743195560Sthompsa			ret = 60 * 1;
744195957Salfred			break;
745195957Salfred		default:
746195560Sthompsa			ret = 60 * 8;
747195957Salfred			break;
748195560Sthompsa		}
749195957Salfred		break;
750195560Sthompsa	case LIBUSB_TRANSFER_TYPE_CONTROL:
751195560Sthompsa		ret = 2;
752195957Salfred		break;
753195560Sthompsa	default:
754195560Sthompsa		ret = 1;
755195957Salfred		break;
756195560Sthompsa	}
757195957Salfred	return (ret);
758195560Sthompsa}
759195560Sthompsa
760195560Sthompsastatic int
761195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer)
762195560Sthompsa{
763195560Sthompsa	int ret;
764195560Sthompsa	int usb_speed;
765195560Sthompsa
766195560Sthompsa	usb_speed = libusb20_dev_get_speed(pdev);
767195560Sthompsa
768195560Sthompsa	switch (xfer->type) {
769195560Sthompsa	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
770195957Salfred		ret = 0;		/* kernel will auto-select */
771195957Salfred		break;
772195560Sthompsa	case LIBUSB_TRANSFER_TYPE_CONTROL:
773195957Salfred		ret = 1024;
774195957Salfred		break;
775195957Salfred	default:
776195560Sthompsa		switch (usb_speed) {
777195957Salfred		case LIBUSB20_SPEED_LOW:
778195957Salfred			ret = 256;
779195957Salfred			break;
780195957Salfred		case LIBUSB20_SPEED_FULL:
781195957Salfred			ret = 4096;
782195957Salfred			break;
783195957Salfred		default:
784195957Salfred			ret = 16384;
785195957Salfred			break;
786195560Sthompsa		}
787195957Salfred		break;
788195560Sthompsa	}
789195957Salfred	return (ret);
790195560Sthompsa}
791195560Sthompsa
792195957Salfredstatic int
793195957Salfredlibusb10_convert_error(uint8_t status)
794195957Salfred{
795195957Salfred	;				/* indent fix */
796195957Salfred
797195957Salfred	switch (status) {
798195957Salfred	case LIBUSB20_TRANSFER_START:
799195957Salfred	case LIBUSB20_TRANSFER_COMPLETED:
800195957Salfred		return (LIBUSB_TRANSFER_COMPLETED);
801195957Salfred	case LIBUSB20_TRANSFER_OVERFLOW:
802195957Salfred		return (LIBUSB_TRANSFER_OVERFLOW);
803195957Salfred	case LIBUSB20_TRANSFER_NO_DEVICE:
804195957Salfred		return (LIBUSB_TRANSFER_NO_DEVICE);
805195957Salfred	case LIBUSB20_TRANSFER_STALL:
806195957Salfred		return (LIBUSB_TRANSFER_STALL);
807195957Salfred	case LIBUSB20_TRANSFER_CANCELLED:
808195957Salfred		return (LIBUSB_TRANSFER_CANCELLED);
809195957Salfred	case LIBUSB20_TRANSFER_TIMED_OUT:
810195957Salfred		return (LIBUSB_TRANSFER_TIMED_OUT);
811195957Salfred	default:
812195957Salfred		return (LIBUSB_TRANSFER_ERROR);
813195957Salfred	}
814195957Salfred}
815195957Salfred
816195957Salfred/* This function must be called locked */
817195957Salfred
818194676Sthompsastatic void
819195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer,
820195957Salfred    struct libusb_super_transfer *sxfer, int status)
821194676Sthompsa{
822195957Salfred	struct libusb_transfer *uxfer;
823195957Salfred	struct libusb_device *dev;
824195957Salfred
825195957Salfred	uxfer = (struct libusb_transfer *)(
826195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
827195957Salfred
828195957Salfred	if (pxfer != NULL)
829195957Salfred		libusb20_tr_set_priv_sc1(pxfer, NULL);
830195957Salfred
831195957Salfred	uxfer->status = status;
832195957Salfred
833195957Salfred	dev = libusb_get_device(uxfer->dev_handle);
834195957Salfred
835195957Salfred	TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry);
836195957Salfred}
837195957Salfred
838195957Salfred/* This function must be called locked */
839195957Salfred
840195957Salfredstatic void
841195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer)
842195957Salfred{
843195957Salfred	struct libusb_super_transfer *sxfer;
844195957Salfred	struct libusb_transfer *uxfer;
845195957Salfred	uint32_t actlen;
846195957Salfred	uint16_t iso_packets;
847195957Salfred	uint16_t i;
848194676Sthompsa	uint8_t status;
849195957Salfred	uint8_t flags;
850194676Sthompsa
851195957Salfred	status = libusb20_tr_get_status(pxfer);
852195957Salfred	sxfer = libusb20_tr_get_priv_sc1(pxfer);
853195957Salfred	actlen = libusb20_tr_get_actual_length(pxfer);
854195957Salfred	iso_packets = libusb20_tr_get_max_frames(pxfer);
855194676Sthompsa
856195957Salfred	if (sxfer == NULL)
857195957Salfred		return;			/* cancelled - nothing to do */
858195957Salfred
859195957Salfred	uxfer = (struct libusb_transfer *)(
860195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
861195957Salfred
862195957Salfred	if (iso_packets > uxfer->num_iso_packets)
863195957Salfred		iso_packets = uxfer->num_iso_packets;
864195957Salfred
865195957Salfred	if (iso_packets == 0)
866195957Salfred		return;			/* nothing to do */
867195957Salfred
868195957Salfred	/* make sure that the number of ISOCHRONOUS packets is valid */
869195957Salfred	uxfer->num_iso_packets = iso_packets;
870195957Salfred
871195957Salfred	flags = uxfer->flags;
872195957Salfred
873194676Sthompsa	switch (status) {
874194676Sthompsa	case LIBUSB20_TRANSFER_COMPLETED:
875195560Sthompsa
876195957Salfred		/* update actual length */
877195957Salfred		uxfer->actual_length = actlen;
878195957Salfred		for (i = 0; i != iso_packets; i++) {
879195957Salfred			uxfer->iso_packet_desc[i].actual_length =
880195957Salfred			    libusb20_tr_get_length(pxfer, i);
881195957Salfred		}
882195957Salfred		libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
883195957Salfred		break;
884195560Sthompsa
885194676Sthompsa	case LIBUSB20_TRANSFER_START:
886195957Salfred
887195957Salfred		/* setup length(s) */
888195957Salfred		actlen = 0;
889195957Salfred		for (i = 0; i != iso_packets; i++) {
890195957Salfred			libusb20_tr_setup_isoc(pxfer,
891195957Salfred			    &uxfer->buffer[actlen],
892195957Salfred			    uxfer->iso_packet_desc[i].length, i);
893195957Salfred			actlen += uxfer->iso_packet_desc[i].length;
894194676Sthompsa		}
895195957Salfred
896195957Salfred		/* no remainder */
897195957Salfred		sxfer->rem_len = 0;
898195957Salfred
899195957Salfred		libusb20_tr_set_total_frames(pxfer, iso_packets);
900195957Salfred		libusb20_tr_submit(pxfer);
901195957Salfred
902195957Salfred		/* fork another USB transfer, if any */
903195957Salfred		libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
904195957Salfred		break;
905195957Salfred
906194676Sthompsa	default:
907195957Salfred		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
908195957Salfred		break;
909194676Sthompsa	}
910195957Salfred}
911194676Sthompsa
912195957Salfred/* This function must be called locked */
913195957Salfred
914195957Salfredstatic void
915195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer)
916195957Salfred{
917195957Salfred	struct libusb_super_transfer *sxfer;
918195957Salfred	struct libusb_transfer *uxfer;
919195957Salfred	uint32_t max_bulk;
920195957Salfred	uint32_t actlen;
921195957Salfred	uint8_t status;
922195957Salfred	uint8_t flags;
923195957Salfred
924195957Salfred	status = libusb20_tr_get_status(pxfer);
925195957Salfred	sxfer = libusb20_tr_get_priv_sc1(pxfer);
926195957Salfred	max_bulk = libusb20_tr_get_max_total_length(pxfer);
927195957Salfred	actlen = libusb20_tr_get_actual_length(pxfer);
928195957Salfred
929195957Salfred	if (sxfer == NULL)
930195957Salfred		return;			/* cancelled - nothing to do */
931195957Salfred
932195957Salfred	uxfer = (struct libusb_transfer *)(
933195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
934195957Salfred
935195957Salfred	flags = uxfer->flags;
936195957Salfred
937194676Sthompsa	switch (status) {
938194676Sthompsa	case LIBUSB20_TRANSFER_COMPLETED:
939195957Salfred
940195957Salfred		uxfer->actual_length += actlen;
941195957Salfred
942195957Salfred		/* check for short packet */
943195957Salfred		if (sxfer->last_len != actlen) {
944195957Salfred			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
945195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
946195957Salfred			} else {
947195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
948195957Salfred			}
949195957Salfred			break;
950195957Salfred		}
951195957Salfred		/* check for end of data */
952195957Salfred		if (sxfer->rem_len == 0) {
953195957Salfred			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
954195957Salfred			break;
955195957Salfred		}
956195957Salfred		/* FALLTHROUGH */
957195957Salfred
958195957Salfred	case LIBUSB20_TRANSFER_START:
959195957Salfred		if (max_bulk > sxfer->rem_len) {
960195957Salfred			max_bulk = sxfer->rem_len;
961195957Salfred		}
962195957Salfred		/* setup new BULK or INTERRUPT transaction */
963195957Salfred		libusb20_tr_setup_bulk(pxfer,
964195957Salfred		    sxfer->curr_data, max_bulk, uxfer->timeout);
965195957Salfred
966195957Salfred		/* update counters */
967195957Salfred		sxfer->last_len = max_bulk;
968195957Salfred		sxfer->curr_data += max_bulk;
969195957Salfred		sxfer->rem_len -= max_bulk;
970195957Salfred
971195957Salfred		libusb20_tr_submit(pxfer);
972195957Salfred
973195957Salfred		/* check if we can fork another USB transfer */
974195957Salfred		if (sxfer->rem_len == 0)
975195957Salfred			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
976195957Salfred		break;
977195957Salfred
978195957Salfred	default:
979195957Salfred		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
980195957Salfred		break;
981194676Sthompsa	}
982194676Sthompsa}
983194676Sthompsa
984195957Salfred/* This function must be called locked */
985195957Salfred
986195957Salfredstatic void
987195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer)
988194676Sthompsa{
989195957Salfred	struct libusb_super_transfer *sxfer;
990195957Salfred	struct libusb_transfer *uxfer;
991195957Salfred	uint32_t max_bulk;
992195957Salfred	uint32_t actlen;
993195957Salfred	uint8_t status;
994195957Salfred	uint8_t flags;
995194676Sthompsa
996195957Salfred	status = libusb20_tr_get_status(pxfer);
997195957Salfred	sxfer = libusb20_tr_get_priv_sc1(pxfer);
998195957Salfred	max_bulk = libusb20_tr_get_max_total_length(pxfer);
999195957Salfred	actlen = libusb20_tr_get_actual_length(pxfer);
1000194676Sthompsa
1001195957Salfred	if (sxfer == NULL)
1002195957Salfred		return;			/* cancelled - nothing to do */
1003194676Sthompsa
1004195957Salfred	uxfer = (struct libusb_transfer *)(
1005195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1006194676Sthompsa
1007195957Salfred	flags = uxfer->flags;
1008194676Sthompsa
1009195957Salfred	switch (status) {
1010195957Salfred	case LIBUSB20_TRANSFER_COMPLETED:
1011194676Sthompsa
1012195957Salfred		uxfer->actual_length += actlen;
1013195957Salfred
1014195957Salfred		/* subtract length of SETUP packet, if any */
1015195957Salfred		actlen -= libusb20_tr_get_length(pxfer, 0);
1016195957Salfred
1017195957Salfred		/* check for short packet */
1018195957Salfred		if (sxfer->last_len != actlen) {
1019195957Salfred			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
1020195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
1021195957Salfred			} else {
1022195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1023195957Salfred			}
1024195957Salfred			break;
1025194676Sthompsa		}
1026195957Salfred		/* check for end of data */
1027195957Salfred		if (sxfer->rem_len == 0) {
1028195957Salfred			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1029195957Salfred			break;
1030195957Salfred		}
1031195957Salfred		/* FALLTHROUGH */
1032194676Sthompsa
1033195957Salfred	case LIBUSB20_TRANSFER_START:
1034195957Salfred		if (max_bulk > sxfer->rem_len) {
1035195957Salfred			max_bulk = sxfer->rem_len;
1036195957Salfred		}
1037195957Salfred		/* setup new CONTROL transaction */
1038195957Salfred		if (status == LIBUSB20_TRANSFER_COMPLETED) {
1039195957Salfred			/* next fragment - don't send SETUP packet */
1040195957Salfred			libusb20_tr_set_length(pxfer, 0, 0);
1041195957Salfred		} else {
1042195957Salfred			/* first fragment - send SETUP packet */
1043195957Salfred			libusb20_tr_set_length(pxfer, 8, 0);
1044195957Salfred			libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0);
1045195957Salfred		}
1046195957Salfred
1047195957Salfred		if (max_bulk != 0) {
1048195957Salfred			libusb20_tr_set_length(pxfer, max_bulk, 1);
1049195957Salfred			libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1);
1050195957Salfred			libusb20_tr_set_total_frames(pxfer, 2);
1051195957Salfred		} else {
1052195957Salfred			libusb20_tr_set_total_frames(pxfer, 1);
1053195957Salfred		}
1054195957Salfred
1055195957Salfred		/* update counters */
1056195957Salfred		sxfer->last_len = max_bulk;
1057195957Salfred		sxfer->curr_data += max_bulk;
1058195957Salfred		sxfer->rem_len -= max_bulk;
1059195957Salfred
1060195957Salfred		libusb20_tr_submit(pxfer);
1061195957Salfred
1062195957Salfred		/* check if we can fork another USB transfer */
1063195957Salfred		if (sxfer->rem_len == 0)
1064195957Salfred			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
1065195957Salfred		break;
1066195957Salfred
1067195957Salfred	default:
1068195957Salfred		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
1069195957Salfred		break;
1070194676Sthompsa	}
1071195957Salfred}
1072195957Salfred
1073195957Salfred/* The following function must be called locked */
1074195957Salfred
1075195957Salfredstatic void
1076195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint)
1077195957Salfred{
1078195957Salfred	struct libusb20_transfer *pxfer0;
1079195957Salfred	struct libusb20_transfer *pxfer1;
1080195957Salfred	struct libusb_super_transfer *sxfer;
1081195957Salfred	struct libusb_transfer *uxfer;
1082195957Salfred	struct libusb_device *dev;
1083195957Salfred	int err;
1084195957Salfred	int buffsize;
1085195957Salfred	int maxframe;
1086195957Salfred	int temp;
1087195957Salfred	uint8_t dummy;
1088195957Salfred
1089195957Salfred	dev = libusb_get_device(pdev);
1090195957Salfred
1091195957Salfred	pxfer0 = libusb10_get_transfer(pdev, endpoint, 0);
1092195957Salfred	pxfer1 = libusb10_get_transfer(pdev, endpoint, 1);
1093195957Salfred
1094195957Salfred	if (pxfer0 == NULL || pxfer1 == NULL)
1095195957Salfred		return;			/* shouldn't happen */
1096195957Salfred
1097195957Salfred	temp = 0;
1098195957Salfred	if (libusb20_tr_pending(pxfer0))
1099195957Salfred		temp |= 1;
1100195957Salfred	if (libusb20_tr_pending(pxfer1))
1101195957Salfred		temp |= 2;
1102195957Salfred
1103195957Salfred	switch (temp) {
1104195957Salfred	case 3:
1105195957Salfred		/* wait till one of the transfers complete */
1106195957Salfred		return;
1107195957Salfred	case 2:
1108195957Salfred		sxfer = libusb20_tr_get_priv_sc1(pxfer1);
1109195957Salfred		if (sxfer->rem_len)
1110195957Salfred			return;		/* cannot queue another one */
1111195957Salfred		/* swap transfers */
1112195957Salfred		pxfer1 = pxfer0;
1113195957Salfred		break;
1114195957Salfred	case 1:
1115195957Salfred		sxfer = libusb20_tr_get_priv_sc1(pxfer0);
1116195957Salfred		if (sxfer->rem_len)
1117195957Salfred			return;		/* cannot queue another one */
1118195957Salfred		/* swap transfers */
1119195957Salfred		pxfer0 = pxfer1;
1120195957Salfred		break;
1121195957Salfred	default:
1122195957Salfred		break;
1123194676Sthompsa	}
1124195957Salfred
1125195957Salfred	/* find next transfer on same endpoint */
1126195957Salfred	TAILQ_FOREACH(sxfer, &dev->tr_head, entry) {
1127195957Salfred
1128195957Salfred		uxfer = (struct libusb_transfer *)(
1129195957Salfred		    ((uint8_t *)sxfer) + sizeof(*sxfer));
1130195957Salfred
1131195957Salfred		if (uxfer->endpoint == endpoint) {
1132195957Salfred			TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
1133195957Salfred			sxfer->entry.tqe_prev = NULL;
1134195957Salfred			goto found;
1135194676Sthompsa		}
1136195957Salfred	}
1137195957Salfred	return;				/* success */
1138194676Sthompsa
1139195957Salfredfound:
1140194676Sthompsa
1141195957Salfred	libusb20_tr_set_priv_sc0(pxfer0, pdev);
1142195957Salfred	libusb20_tr_set_priv_sc1(pxfer0, sxfer);
1143194676Sthompsa
1144195957Salfred	/* reset super transfer state */
1145195957Salfred	sxfer->rem_len = uxfer->length;
1146195957Salfred	sxfer->curr_data = uxfer->buffer;
1147195957Salfred	uxfer->actual_length = 0;
1148194676Sthompsa
1149195957Salfred	switch (uxfer->type) {
1150195957Salfred	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
1151195957Salfred		libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
1152195957Salfred		break;
1153195957Salfred	case LIBUSB_TRANSFER_TYPE_BULK:
1154195957Salfred	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
1155195957Salfred		libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
1156195957Salfred		break;
1157195957Salfred	case LIBUSB_TRANSFER_TYPE_CONTROL:
1158195957Salfred		libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy);
1159195957Salfred		if (sxfer->rem_len < 8)
1160195957Salfred			goto failure;
1161194676Sthompsa
1162195957Salfred		/* remove SETUP packet from data */
1163195957Salfred		sxfer->rem_len -= 8;
1164195957Salfred		sxfer->curr_data += 8;
1165195957Salfred		break;
1166195957Salfred	default:
1167195957Salfred		goto failure;
1168195560Sthompsa	}
1169195957Salfred
1170195957Salfred	buffsize = libusb10_get_buffsize(pdev, uxfer);
1171195957Salfred	maxframe = libusb10_get_maxframe(pdev, uxfer);
1172195957Salfred
1173195957Salfred	/* make sure the transfer is opened */
1174195957Salfred	err = libusb20_tr_open(pxfer0, buffsize, maxframe, endpoint);
1175195957Salfred	if (err && (err != LIBUSB20_ERROR_BUSY)) {
1176195957Salfred		goto failure;
1177194676Sthompsa	}
1178195957Salfred	libusb20_tr_start(pxfer0);
1179195957Salfred	return;
1180194676Sthompsa
1181195957Salfredfailure:
1182195957Salfred	libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
1183194676Sthompsa
1184195957Salfred	/* make sure our event loop spins the done handler */
1185195957Salfred	dummy = 0;
1186195957Salfred	write(dev->ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
1187195957Salfred}
1188194676Sthompsa
1189195957Salfred/* The following function must be called unlocked */
1190194676Sthompsa
1191195957Salfredint
1192195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer)
1193195957Salfred{
1194195957Salfred	struct libusb20_transfer *pxfer0;
1195195957Salfred	struct libusb20_transfer *pxfer1;
1196195957Salfred	struct libusb_super_transfer *sxfer;
1197195957Salfred	struct libusb_device *dev;
1198195957Salfred	unsigned int endpoint;
1199195957Salfred	int err;
1200195957Salfred
1201195957Salfred	if (uxfer == NULL)
1202195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1203195957Salfred
1204195957Salfred	if (uxfer->dev_handle == NULL)
1205195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1206195957Salfred
1207195957Salfred	endpoint = uxfer->endpoint;
1208195957Salfred
1209195957Salfred	if (endpoint > 255)
1210195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1211195957Salfred
1212195957Salfred	dev = libusb_get_device(uxfer->dev_handle);
1213195957Salfred
1214195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
1215195957Salfred
1216195957Salfred	sxfer = (struct libusb_super_transfer *)(
1217195957Salfred	    (uint8_t *)uxfer - sizeof(*sxfer));
1218195957Salfred
1219195957Salfred	CTX_LOCK(dev->ctx);
1220195957Salfred
1221195957Salfred	pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
1222195957Salfred	pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
1223195957Salfred
1224195957Salfred	if (pxfer0 == NULL || pxfer1 == NULL) {
1225195957Salfred		err = LIBUSB_ERROR_OTHER;
1226195957Salfred	} else if ((sxfer->entry.tqe_prev != NULL) ||
1227195957Salfred		    (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) ||
1228195957Salfred	    (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) {
1229195957Salfred		err = LIBUSB_ERROR_BUSY;
1230195957Salfred	} else {
1231195957Salfred		TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry);
1232195957Salfred
1233195957Salfred		libusb10_submit_transfer_sub(
1234195957Salfred		    uxfer->dev_handle, endpoint);
1235195957Salfred
1236195957Salfred		err = 0;		/* success */
1237195957Salfred	}
1238195957Salfred
1239195957Salfred	CTX_UNLOCK(dev->ctx);
1240195957Salfred
1241195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
1242195957Salfred
1243195957Salfred	return (err);
1244194676Sthompsa}
1245194676Sthompsa
1246195957Salfred/* Asynchronous transfer cancel */
1247195957Salfred
1248194676Sthompsaint
1249195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer)
1250194676Sthompsa{
1251195957Salfred	struct libusb20_transfer *pxfer0;
1252195957Salfred	struct libusb20_transfer *pxfer1;
1253195957Salfred	struct libusb_super_transfer *sxfer;
1254195957Salfred	struct libusb_device *dev;
1255195957Salfred	unsigned int endpoint;
1256194676Sthompsa
1257195957Salfred	if (uxfer == NULL)
1258195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1259194676Sthompsa
1260195957Salfred	if (uxfer->dev_handle == NULL)
1261195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1262194676Sthompsa
1263195957Salfred	endpoint = uxfer->endpoint;
1264194676Sthompsa
1265195957Salfred	if (endpoint > 255)
1266195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1267195957Salfred
1268195957Salfred	dev = libusb_get_device(uxfer->dev_handle);
1269195957Salfred
1270195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
1271195957Salfred
1272195957Salfred	sxfer = (struct libusb_super_transfer *)(
1273195957Salfred	    (uint8_t *)uxfer - sizeof(*sxfer));
1274195957Salfred
1275195957Salfred	CTX_LOCK(dev->ctx);
1276195957Salfred
1277195957Salfred	pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
1278195957Salfred	pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
1279195957Salfred
1280195957Salfred	if (sxfer->entry.tqe_prev != NULL) {
1281195957Salfred		/* we are lucky - transfer is on a queue */
1282195957Salfred		TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
1283195957Salfred		sxfer->entry.tqe_prev = NULL;
1284195957Salfred		libusb10_complete_transfer(NULL, sxfer, LIBUSB_TRANSFER_CANCELLED);
1285195957Salfred	} else if (pxfer0 == NULL || pxfer1 == NULL) {
1286195957Salfred		/* not started */
1287195957Salfred	} else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) {
1288195957Salfred		libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_CANCELLED);
1289195957Salfred		libusb20_tr_stop(pxfer0);
1290195957Salfred		/* make sure the queue doesn't stall */
1291195957Salfred		libusb10_submit_transfer_sub(
1292195957Salfred		    uxfer->dev_handle, endpoint);
1293195957Salfred	} else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) {
1294195957Salfred		libusb10_complete_transfer(pxfer1, sxfer, LIBUSB_TRANSFER_CANCELLED);
1295195957Salfred		libusb20_tr_stop(pxfer1);
1296195957Salfred		/* make sure the queue doesn't stall */
1297195957Salfred		libusb10_submit_transfer_sub(
1298195957Salfred		    uxfer->dev_handle, endpoint);
1299195957Salfred	} else {
1300195957Salfred		/* not started */
1301195957Salfred	}
1302195957Salfred
1303195957Salfred	CTX_UNLOCK(dev->ctx);
1304195957Salfred
1305195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
1306195957Salfred
1307194676Sthompsa	return (0);
1308194676Sthompsa}
1309194676Sthompsa
1310195957SalfredUNEXPORTED void
1311195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev)
1312195957Salfred{
1313195957Salfred	/* TODO */
1314195957Salfred}
1315