1194676Sthompsa/* $FreeBSD: stable/10/lib/libusb/libusb10.c 362224 2020-06-16 12:21:55Z kevans $ */
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
28248236Shselasky#ifdef LIBUSB_GLOBAL_INCLUDE_FILE
29248236Shselasky#include LIBUSB_GLOBAL_INCLUDE_FILE
30248236Shselasky#else
31203774Swkoszek#include <assert.h>
32203815Swkoszek#include <errno.h>
33203815Swkoszek#include <poll.h>
34203815Swkoszek#include <pthread.h>
35203815Swkoszek#include <stdio.h>
36194676Sthompsa#include <stdlib.h>
37248236Shselasky#include <string.h>
38194676Sthompsa#include <unistd.h>
39248236Shselasky#include <time.h>
40248236Shselasky#include <sys/fcntl.h>
41248236Shselasky#include <sys/ioctl.h>
42248236Shselasky#include <sys/queue.h>
43248236Shselasky#include <sys/endian.h>
44248236Shselasky#endif
45194676Sthompsa
46208020Sthompsa#define	libusb_device_handle libusb20_device
47208020Sthompsa
48194676Sthompsa#include "libusb20.h"
49194676Sthompsa#include "libusb20_desc.h"
50194676Sthompsa#include "libusb20_int.h"
51194676Sthompsa#include "libusb.h"
52194676Sthompsa#include "libusb10.h"
53194676Sthompsa
54302272Shselasky#define	LIBUSB_NUM_SW_ENDPOINTS	(16 * 4)
55302272Shselasky
56194676Sthompsastatic pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER;
57194676Sthompsastruct libusb_context *usbi_default_context = NULL;
58194676Sthompsa
59195957Salfred/* Prototypes */
60195957Salfred
61195957Salfredstatic struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t);
62195957Salfredstatic int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *);
63195957Salfredstatic int libusb10_convert_error(uint8_t status);
64195957Salfredstatic void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int);
65195957Salfredstatic void libusb10_isoc_proxy(struct libusb20_transfer *);
66195957Salfredstatic void libusb10_bulk_intr_proxy(struct libusb20_transfer *);
67195957Salfredstatic void libusb10_ctrl_proxy(struct libusb20_transfer *);
68195957Salfredstatic void libusb10_submit_transfer_sub(struct libusb20_device *, uint8_t);
69195957Salfred
70194676Sthompsa/*  Library initialisation / deinitialisation */
71194676Sthompsa
72302275Shselaskystatic const struct libusb_version libusb_version = {
73302275Shselasky	.major = 1,
74302275Shselasky	.minor = 0,
75302275Shselasky	.micro = 0,
76302275Shselasky	.nano = 2016,
77302275Shselasky	.rc = "",
78302275Shselasky	.describe = "http://www.freebsd.org"
79302275Shselasky};
80302275Shselasky
81302275Shselaskyconst struct libusb_version *
82302275Shselaskylibusb_get_version(void)
83302275Shselasky{
84302275Shselasky
85302275Shselasky	return (&libusb_version);
86302275Shselasky}
87302275Shselasky
88194676Sthompsavoid
89195957Salfredlibusb_set_debug(libusb_context *ctx, int level)
90194676Sthompsa{
91195957Salfred	ctx = GET_CONTEXT(ctx);
92194676Sthompsa	if (ctx)
93194676Sthompsa		ctx->debug = level;
94194676Sthompsa}
95194676Sthompsa
96213853Shselaskystatic void
97213853Shselaskylibusb_set_nonblocking(int f)
98213853Shselasky{
99213853Shselasky	int flags;
100213853Shselasky
101213853Shselasky	/*
102213853Shselasky	 * We ignore any failures in this function, hence the
103213853Shselasky	 * non-blocking flag is not critical to the operation of
104213853Shselasky	 * libUSB. We use F_GETFL and F_SETFL to be compatible with
105213853Shselasky	 * Linux.
106213853Shselasky	 */
107213853Shselasky
108213853Shselasky	flags = fcntl(f, F_GETFL, NULL);
109213853Shselasky	if (flags == -1)
110213853Shselasky		return;
111213853Shselasky	flags |= O_NONBLOCK;
112213853Shselasky	fcntl(f, F_SETFL, flags);
113213853Shselasky}
114213853Shselasky
115338789Shselaskystatic void
116338789Shselaskylibusb10_wakeup_event_loop(libusb_context *ctx)
117338789Shselasky{
118338789Shselasky	uint8_t dummy = 0;
119338789Shselasky	int err;
120338789Shselasky
121338789Shselasky	err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
122338789Shselasky	if (err < (int)sizeof(dummy)) {
123338789Shselasky		/* ignore error, if any */
124338789Shselasky		DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "Waking up event loop failed!");
125338789Shselasky	}
126338789Shselasky}
127338789Shselasky
128194676Sthompsaint
129195957Salfredlibusb_init(libusb_context **context)
130194676Sthompsa{
131194676Sthompsa	struct libusb_context *ctx;
132236944Shselasky	pthread_condattr_t attr;
133195957Salfred	char *debug;
134194676Sthompsa	int ret;
135194676Sthompsa
136194676Sthompsa	ctx = malloc(sizeof(*ctx));
137194676Sthompsa	if (!ctx)
138194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
139194676Sthompsa
140194676Sthompsa	memset(ctx, 0, sizeof(*ctx));
141194676Sthompsa
142194676Sthompsa	debug = getenv("LIBUSB_DEBUG");
143194676Sthompsa	if (debug != NULL) {
144194676Sthompsa		ctx->debug = atoi(debug);
145194676Sthompsa		if (ctx->debug != 0)
146194676Sthompsa			ctx->debug_fixed = 1;
147194676Sthompsa	}
148195957Salfred	TAILQ_INIT(&ctx->pollfds);
149195957Salfred	TAILQ_INIT(&ctx->tr_done);
150302275Shselasky	TAILQ_INIT(&ctx->hotplug_cbh);
151302275Shselasky	TAILQ_INIT(&ctx->hotplug_devs);
152194676Sthompsa
153236944Shselasky	if (pthread_mutex_init(&ctx->ctx_lock, NULL) != 0) {
154236944Shselasky		free(ctx);
155236944Shselasky		return (LIBUSB_ERROR_NO_MEM);
156236944Shselasky	}
157302275Shselasky	if (pthread_mutex_init(&ctx->hotplug_lock, NULL) != 0) {
158302275Shselasky		pthread_mutex_destroy(&ctx->ctx_lock);
159302275Shselasky		free(ctx);
160302275Shselasky		return (LIBUSB_ERROR_NO_MEM);
161302275Shselasky	}
162236944Shselasky	if (pthread_condattr_init(&attr) != 0) {
163236944Shselasky		pthread_mutex_destroy(&ctx->ctx_lock);
164302275Shselasky		pthread_mutex_destroy(&ctx->hotplug_lock);
165236944Shselasky		free(ctx);
166236944Shselasky		return (LIBUSB_ERROR_NO_MEM);
167236944Shselasky	}
168236944Shselasky	if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) {
169236944Shselasky		pthread_mutex_destroy(&ctx->ctx_lock);
170302275Shselasky		pthread_mutex_destroy(&ctx->hotplug_lock);
171236944Shselasky		pthread_condattr_destroy(&attr);
172236944Shselasky		free(ctx);
173236944Shselasky		return (LIBUSB_ERROR_OTHER);
174236944Shselasky	}
175236944Shselasky	if (pthread_cond_init(&ctx->ctx_cond, &attr) != 0) {
176236944Shselasky		pthread_mutex_destroy(&ctx->ctx_lock);
177302275Shselasky		pthread_mutex_destroy(&ctx->hotplug_lock);
178236944Shselasky		pthread_condattr_destroy(&attr);
179236944Shselasky		free(ctx);
180236944Shselasky		return (LIBUSB_ERROR_NO_MEM);
181236944Shselasky	}
182236944Shselasky	pthread_condattr_destroy(&attr);
183194676Sthompsa
184195957Salfred	ctx->ctx_handler = NO_THREAD;
185302275Shselasky	ctx->hotplug_handler = NO_THREAD;
186194676Sthompsa
187194676Sthompsa	ret = pipe(ctx->ctrl_pipe);
188194676Sthompsa	if (ret < 0) {
189195957Salfred		pthread_mutex_destroy(&ctx->ctx_lock);
190302275Shselasky		pthread_mutex_destroy(&ctx->hotplug_lock);
191195957Salfred		pthread_cond_destroy(&ctx->ctx_cond);
192194676Sthompsa		free(ctx);
193194676Sthompsa		return (LIBUSB_ERROR_OTHER);
194194676Sthompsa	}
195195957Salfred	/* set non-blocking mode on the control pipe to avoid deadlock */
196213853Shselasky	libusb_set_nonblocking(ctx->ctrl_pipe[0]);
197213853Shselasky	libusb_set_nonblocking(ctx->ctrl_pipe[1]);
198194676Sthompsa
199195957Salfred	libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN);
200194676Sthompsa
201194676Sthompsa	pthread_mutex_lock(&default_context_lock);
202194676Sthompsa	if (usbi_default_context == NULL) {
203194676Sthompsa		usbi_default_context = ctx;
204194676Sthompsa	}
205194676Sthompsa	pthread_mutex_unlock(&default_context_lock);
206194676Sthompsa
207194676Sthompsa	if (context)
208194676Sthompsa		*context = ctx;
209194676Sthompsa
210195957Salfred	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
211195957Salfred
212194676Sthompsa	return (0);
213194676Sthompsa}
214194676Sthompsa
215194676Sthompsavoid
216195957Salfredlibusb_exit(libusb_context *ctx)
217194676Sthompsa{
218195957Salfred	ctx = GET_CONTEXT(ctx);
219194676Sthompsa
220195957Salfred	if (ctx == NULL)
221195957Salfred		return;
222195957Salfred
223302275Shselasky	/* stop hotplug thread, if any */
224302275Shselasky
225302275Shselasky	if (ctx->hotplug_handler != NO_THREAD) {
226302275Shselasky		pthread_t td;
227302275Shselasky		void *ptr;
228302275Shselasky
229302275Shselasky		HOTPLUG_LOCK(ctx);
230302275Shselasky		td = ctx->hotplug_handler;
231302275Shselasky		ctx->hotplug_handler = NO_THREAD;
232302275Shselasky		HOTPLUG_UNLOCK(ctx);
233302275Shselasky
234302275Shselasky		pthread_join(td, &ptr);
235302275Shselasky	}
236302275Shselasky
237195957Salfred	/* XXX cleanup devices */
238195957Salfred
239195957Salfred	libusb10_remove_pollfd(ctx, &ctx->ctx_poll);
240194676Sthompsa	close(ctx->ctrl_pipe[0]);
241194676Sthompsa	close(ctx->ctrl_pipe[1]);
242195957Salfred	pthread_mutex_destroy(&ctx->ctx_lock);
243302275Shselasky	pthread_mutex_destroy(&ctx->hotplug_lock);
244195957Salfred	pthread_cond_destroy(&ctx->ctx_cond);
245194676Sthompsa
246194676Sthompsa	pthread_mutex_lock(&default_context_lock);
247194676Sthompsa	if (ctx == usbi_default_context) {
248194676Sthompsa		usbi_default_context = NULL;
249194676Sthompsa	}
250194676Sthompsa	pthread_mutex_unlock(&default_context_lock);
251194676Sthompsa
252194676Sthompsa	free(ctx);
253194676Sthompsa}
254194676Sthompsa
255194676Sthompsa/* Device handling and initialisation. */
256194676Sthompsa
257194676Sthompsassize_t
258195957Salfredlibusb_get_device_list(libusb_context *ctx, libusb_device ***list)
259194676Sthompsa{
260195957Salfred	struct libusb20_backend *usb_backend;
261194676Sthompsa	struct libusb20_device *pdev;
262194676Sthompsa	struct libusb_device *dev;
263194676Sthompsa	int i;
264194676Sthompsa
265195957Salfred	ctx = GET_CONTEXT(ctx);
266194676Sthompsa
267195957Salfred	if (ctx == NULL)
268195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
269195957Salfred
270195957Salfred	if (list == NULL)
271195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
272195957Salfred
273194676Sthompsa	usb_backend = libusb20_be_alloc_default();
274194676Sthompsa	if (usb_backend == NULL)
275195957Salfred		return (LIBUSB_ERROR_NO_MEM);
276194676Sthompsa
277195957Salfred	/* figure out how many USB devices are present */
278194676Sthompsa	pdev = NULL;
279194676Sthompsa	i = 0;
280194676Sthompsa	while ((pdev = libusb20_be_device_foreach(usb_backend, pdev)))
281194676Sthompsa		i++;
282194676Sthompsa
283195957Salfred	/* allocate device pointer list */
284194676Sthompsa	*list = malloc((i + 1) * sizeof(void *));
285194676Sthompsa	if (*list == NULL) {
286194676Sthompsa		libusb20_be_free(usb_backend);
287194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
288194676Sthompsa	}
289195957Salfred	/* create libusb v1.0 compliant devices */
290194676Sthompsa	i = 0;
291194676Sthompsa	while ((pdev = libusb20_be_device_foreach(usb_backend, NULL))) {
292194676Sthompsa
293194676Sthompsa		dev = malloc(sizeof(*dev));
294194676Sthompsa		if (dev == NULL) {
295195560Sthompsa			while (i != 0) {
296195560Sthompsa				libusb_unref_device((*list)[i - 1]);
297195560Sthompsa				i--;
298195560Sthompsa			}
299194676Sthompsa			free(*list);
300195957Salfred			*list = NULL;
301194676Sthompsa			libusb20_be_free(usb_backend);
302194676Sthompsa			return (LIBUSB_ERROR_NO_MEM);
303194676Sthompsa		}
304199055Sthompsa		/* get device into libUSB v1.0 list */
305199055Sthompsa		libusb20_be_dequeue_device(usb_backend, pdev);
306199055Sthompsa
307194676Sthompsa		memset(dev, 0, sizeof(*dev));
308194676Sthompsa
309195957Salfred		/* init transfer queues */
310195957Salfred		TAILQ_INIT(&dev->tr_head);
311195957Salfred
312195957Salfred		/* set context we belong to */
313194676Sthompsa		dev->ctx = ctx;
314194676Sthompsa
315194676Sthompsa		/* link together the two structures */
316194676Sthompsa		dev->os_priv = pdev;
317195957Salfred		pdev->privLuData = dev;
318194676Sthompsa
319194676Sthompsa		(*list)[i] = libusb_ref_device(dev);
320194676Sthompsa		i++;
321194676Sthompsa	}
322194676Sthompsa	(*list)[i] = NULL;
323194676Sthompsa
324194676Sthompsa	libusb20_be_free(usb_backend);
325194676Sthompsa	return (i);
326194676Sthompsa}
327194676Sthompsa
328194676Sthompsavoid
329194676Sthompsalibusb_free_device_list(libusb_device **list, int unref_devices)
330194676Sthompsa{
331194676Sthompsa	int i;
332194676Sthompsa
333194676Sthompsa	if (list == NULL)
334195957Salfred		return;			/* be NULL safe */
335194676Sthompsa
336194676Sthompsa	if (unref_devices) {
337194676Sthompsa		for (i = 0; list[i] != NULL; i++)
338194676Sthompsa			libusb_unref_device(list[i]);
339194676Sthompsa	}
340194676Sthompsa	free(list);
341194676Sthompsa}
342194676Sthompsa
343194676Sthompsauint8_t
344195957Salfredlibusb_get_bus_number(libusb_device *dev)
345194676Sthompsa{
346194676Sthompsa	if (dev == NULL)
347195957Salfred		return (0);		/* should not happen */
348195957Salfred	return (libusb20_dev_get_bus_number(dev->os_priv));
349194676Sthompsa}
350194676Sthompsa
351302275Shselaskyuint8_t
352302275Shselaskylibusb_get_port_number(libusb_device *dev)
353302275Shselasky{
354302275Shselasky	if (dev == NULL)
355302275Shselasky		return (0);		/* should not happen */
356302275Shselasky	return (libusb20_dev_get_parent_port(dev->os_priv));
357302275Shselasky}
358302275Shselasky
359250342Semasteint
360251495Semastelibusb_get_port_numbers(libusb_device *dev, uint8_t *buf, uint8_t bufsize)
361251495Semaste{
362251495Semaste	return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize));
363251495Semaste}
364251495Semaste
365251495Semasteint
366250342Semastelibusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t *buf,
367250342Semaste    uint8_t bufsize)
368250342Semaste{
369250342Semaste	return (libusb20_dev_get_port_path(dev->os_priv, buf, bufsize));
370250342Semaste}
371250342Semaste
372194676Sthompsauint8_t
373195957Salfredlibusb_get_device_address(libusb_device *dev)
374194676Sthompsa{
375194676Sthompsa	if (dev == NULL)
376195957Salfred		return (0);		/* should not happen */
377195957Salfred	return (libusb20_dev_get_address(dev->os_priv));
378194676Sthompsa}
379194676Sthompsa
380224903Shselaskyenum libusb_speed
381224903Shselaskylibusb_get_device_speed(libusb_device *dev)
382224903Shselasky{
383224903Shselasky	if (dev == NULL)
384225035Shselasky		return (LIBUSB_SPEED_UNKNOWN);	/* should not happen */
385224903Shselasky
386224903Shselasky	switch (libusb20_dev_get_speed(dev->os_priv)) {
387224903Shselasky	case LIBUSB20_SPEED_LOW:
388224903Shselasky		return (LIBUSB_SPEED_LOW);
389224903Shselasky	case LIBUSB20_SPEED_FULL:
390224903Shselasky		return (LIBUSB_SPEED_FULL);
391224903Shselasky	case LIBUSB20_SPEED_HIGH:
392224903Shselasky		return (LIBUSB_SPEED_HIGH);
393224903Shselasky	case LIBUSB20_SPEED_SUPER:
394224903Shselasky		return (LIBUSB_SPEED_SUPER);
395224903Shselasky	default:
396224903Shselasky		break;
397224903Shselasky	}
398224903Shselasky	return (LIBUSB_SPEED_UNKNOWN);
399224903Shselasky}
400224903Shselasky
401194676Sthompsaint
402195957Salfredlibusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint)
403194676Sthompsa{
404194676Sthompsa	struct libusb_config_descriptor *pdconf;
405194676Sthompsa	struct libusb_interface *pinf;
406194676Sthompsa	struct libusb_interface_descriptor *pdinf;
407194676Sthompsa	struct libusb_endpoint_descriptor *pdend;
408195957Salfred	int i;
409195957Salfred	int j;
410195957Salfred	int k;
411195957Salfred	int ret;
412194676Sthompsa
413194676Sthompsa	if (dev == NULL)
414194676Sthompsa		return (LIBUSB_ERROR_NO_DEVICE);
415194676Sthompsa
416195957Salfred	ret = libusb_get_active_config_descriptor(dev, &pdconf);
417195957Salfred	if (ret < 0)
418195957Salfred		return (ret);
419195957Salfred
420194676Sthompsa	ret = LIBUSB_ERROR_NOT_FOUND;
421195957Salfred	for (i = 0; i < pdconf->bNumInterfaces; i++) {
422194676Sthompsa		pinf = &pdconf->interface[i];
423195957Salfred		for (j = 0; j < pinf->num_altsetting; j++) {
424194676Sthompsa			pdinf = &pinf->altsetting[j];
425195957Salfred			for (k = 0; k < pdinf->bNumEndpoints; k++) {
426194676Sthompsa				pdend = &pdinf->endpoint[k];
427194676Sthompsa				if (pdend->bEndpointAddress == endpoint) {
428194676Sthompsa					ret = pdend->wMaxPacketSize;
429194676Sthompsa					goto out;
430194676Sthompsa				}
431194676Sthompsa			}
432194676Sthompsa		}
433194676Sthompsa	}
434194676Sthompsa
435194676Sthompsaout:
436194676Sthompsa	libusb_free_config_descriptor(pdconf);
437194676Sthompsa	return (ret);
438194676Sthompsa}
439194676Sthompsa
440234193Shselaskyint
441234193Shselaskylibusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint)
442234193Shselasky{
443234193Shselasky	int multiplier;
444234193Shselasky	int ret;
445234193Shselasky
446234193Shselasky	ret = libusb_get_max_packet_size(dev, endpoint);
447234193Shselasky
448234193Shselasky	switch (libusb20_dev_get_speed(dev->os_priv)) {
449234193Shselasky	case LIBUSB20_SPEED_LOW:
450234193Shselasky	case LIBUSB20_SPEED_FULL:
451234193Shselasky		break;
452234193Shselasky	default:
453234193Shselasky		if (ret > -1) {
454234193Shselasky			multiplier = (1 + ((ret >> 11) & 3));
455234193Shselasky			if (multiplier > 3)
456234193Shselasky				multiplier = 3;
457234193Shselasky			ret = (ret & 0x7FF) * multiplier;
458234193Shselasky		}
459234193Shselasky		break;
460234193Shselasky	}
461234193Shselasky	return (ret);
462234193Shselasky}
463234193Shselasky
464194676Sthompsalibusb_device *
465195957Salfredlibusb_ref_device(libusb_device *dev)
466194676Sthompsa{
467194676Sthompsa	if (dev == NULL)
468195957Salfred		return (NULL);		/* be NULL safe */
469194676Sthompsa
470195957Salfred	CTX_LOCK(dev->ctx);
471194676Sthompsa	dev->refcnt++;
472195957Salfred	CTX_UNLOCK(dev->ctx);
473194676Sthompsa
474194676Sthompsa	return (dev);
475194676Sthompsa}
476194676Sthompsa
477194676Sthompsavoid
478195957Salfredlibusb_unref_device(libusb_device *dev)
479194676Sthompsa{
480194676Sthompsa	if (dev == NULL)
481195957Salfred		return;			/* be NULL safe */
482194676Sthompsa
483195957Salfred	CTX_LOCK(dev->ctx);
484194676Sthompsa	dev->refcnt--;
485195957Salfred	CTX_UNLOCK(dev->ctx);
486194676Sthompsa
487194676Sthompsa	if (dev->refcnt == 0) {
488194676Sthompsa		libusb20_dev_free(dev->os_priv);
489194676Sthompsa		free(dev);
490194676Sthompsa	}
491194676Sthompsa}
492194676Sthompsa
493194676Sthompsaint
494195957Salfredlibusb_open(libusb_device *dev, libusb_device_handle **devh)
495194676Sthompsa{
496194676Sthompsa	libusb_context *ctx = dev->ctx;
497194676Sthompsa	struct libusb20_device *pdev = dev->os_priv;
498194676Sthompsa	int err;
499194676Sthompsa
500194676Sthompsa	if (devh == NULL)
501194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
502194676Sthompsa
503195957Salfred	/* set default device handle value */
504195957Salfred	*devh = NULL;
505194676Sthompsa
506195957Salfred	dev = libusb_ref_device(dev);
507195957Salfred	if (dev == NULL)
508195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
509195957Salfred
510302272Shselasky	err = libusb20_dev_open(pdev, LIBUSB_NUM_SW_ENDPOINTS);
511194676Sthompsa	if (err) {
512195957Salfred		libusb_unref_device(dev);
513194676Sthompsa		return (LIBUSB_ERROR_NO_MEM);
514194676Sthompsa	}
515195957Salfred	libusb10_add_pollfd(ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
516194676Sthompsa	    POLLOUT | POLLRDNORM | POLLWRNORM);
517194676Sthompsa
518195957Salfred	/* make sure our event loop detects the new device */
519338789Shselasky	libusb10_wakeup_event_loop(ctx);
520338789Shselasky
521195957Salfred	*devh = pdev;
522194676Sthompsa
523194676Sthompsa	return (0);
524194676Sthompsa}
525194676Sthompsa
526194676Sthompsalibusb_device_handle *
527195957Salfredlibusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
528194676Sthompsa    uint16_t product_id)
529194676Sthompsa{
530194676Sthompsa	struct libusb_device **devs;
531194676Sthompsa	struct libusb20_device *pdev;
532194676Sthompsa	struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
533195957Salfred	int i;
534195957Salfred	int j;
535194676Sthompsa
536195957Salfred	ctx = GET_CONTEXT(ctx);
537195957Salfred	if (ctx == NULL)
538195957Salfred		return (NULL);		/* be NULL safe */
539195957Salfred
540345541Shselasky	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid enter");
541194676Sthompsa
542194676Sthompsa	if ((i = libusb_get_device_list(ctx, &devs)) < 0)
543194676Sthompsa		return (NULL);
544194676Sthompsa
545228236Shselasky	pdev = NULL;
546194676Sthompsa	for (j = 0; j < i; j++) {
547228236Shselasky		struct libusb20_device *tdev;
548228236Shselasky
549228236Shselasky		tdev = devs[j]->os_priv;
550228236Shselasky		pdesc = libusb20_dev_get_device_desc(tdev);
551195957Salfred		/*
552195957Salfred		 * NOTE: The USB library will automatically swap the
553195957Salfred		 * fields in the device descriptor to be of host
554195957Salfred		 * endian type!
555195957Salfred		 */
556194676Sthompsa		if (pdesc->idVendor == vendor_id &&
557195560Sthompsa		    pdesc->idProduct == product_id) {
558228235Shselasky			libusb_open(devs[j], &pdev);
559195957Salfred			break;
560195560Sthompsa		}
561194676Sthompsa	}
562194676Sthompsa
563194676Sthompsa	libusb_free_device_list(devs, 1);
564345541Shselasky	DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid leave");
565195957Salfred	return (pdev);
566194676Sthompsa}
567194676Sthompsa
568194676Sthompsavoid
569195957Salfredlibusb_close(struct libusb20_device *pdev)
570194676Sthompsa{
571194676Sthompsa	libusb_context *ctx;
572195957Salfred	struct libusb_device *dev;
573194676Sthompsa
574195957Salfred	if (pdev == NULL)
575195957Salfred		return;			/* be NULL safe */
576194676Sthompsa
577195957Salfred	dev = libusb_get_device(pdev);
578195957Salfred	ctx = dev->ctx;
579194676Sthompsa
580195957Salfred	libusb10_remove_pollfd(ctx, &dev->dev_poll);
581194676Sthompsa
582195957Salfred	libusb20_dev_close(pdev);
583199055Sthompsa
584199055Sthompsa	/* unref will free the "pdev" when the refcount reaches zero */
585195957Salfred	libusb_unref_device(dev);
586194676Sthompsa
587195957Salfred	/* make sure our event loop detects the closed device */
588338789Shselasky	libusb10_wakeup_event_loop(ctx);
589194676Sthompsa}
590194676Sthompsa
591194676Sthompsalibusb_device *
592195957Salfredlibusb_get_device(struct libusb20_device *pdev)
593194676Sthompsa{
594195957Salfred	if (pdev == NULL)
595194676Sthompsa		return (NULL);
596195957Salfred	return ((libusb_device *)pdev->privLuData);
597194676Sthompsa}
598194676Sthompsa
599194676Sthompsaint
600195957Salfredlibusb_get_configuration(struct libusb20_device *pdev, int *config)
601194676Sthompsa{
602195957Salfred	struct libusb20_config *pconf;
603194676Sthompsa
604195957Salfred	if (pdev == NULL || config == NULL)
605194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
606194676Sthompsa
607195957Salfred	pconf = libusb20_dev_alloc_config(pdev, libusb20_dev_get_config_index(pdev));
608195957Salfred	if (pconf == NULL)
609195957Salfred		return (LIBUSB_ERROR_NO_MEM);
610194676Sthompsa
611195957Salfred	*config = pconf->desc.bConfigurationValue;
612195957Salfred
613195957Salfred	free(pconf);
614195957Salfred
615194676Sthompsa	return (0);
616194676Sthompsa}
617194676Sthompsa
618194676Sthompsaint
619195957Salfredlibusb_set_configuration(struct libusb20_device *pdev, int configuration)
620194676Sthompsa{
621195957Salfred	struct libusb20_config *pconf;
622195957Salfred	struct libusb_device *dev;
623195957Salfred	int err;
624195957Salfred	uint8_t i;
625194676Sthompsa
626195957Salfred	dev = libusb_get_device(pdev);
627195957Salfred	if (dev == NULL)
628194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
629194676Sthompsa
630195957Salfred	if (configuration < 1) {
631195957Salfred		/* unconfigure */
632195957Salfred		i = 255;
633195957Salfred	} else {
634195957Salfred		for (i = 0; i != 255; i++) {
635195957Salfred			uint8_t found;
636194676Sthompsa
637195957Salfred			pconf = libusb20_dev_alloc_config(pdev, i);
638195957Salfred			if (pconf == NULL)
639195957Salfred				return (LIBUSB_ERROR_INVALID_PARAM);
640195957Salfred			found = (pconf->desc.bConfigurationValue
641195957Salfred			    == configuration);
642195957Salfred			free(pconf);
643195957Salfred
644195957Salfred			if (found)
645195957Salfred				goto set_config;
646195957Salfred		}
647195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
648195957Salfred	}
649195957Salfred
650195957Salfredset_config:
651195957Salfred
652195957Salfred	libusb10_cancel_all_transfer(dev);
653195957Salfred
654195957Salfred	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
655195957Salfred
656195957Salfred	err = libusb20_dev_set_config_index(pdev, i);
657195957Salfred
658195957Salfred	libusb10_add_pollfd(dev->ctx, &dev->dev_poll, pdev, libusb20_dev_get_fd(pdev), POLLIN |
659195957Salfred	    POLLOUT | POLLRDNORM | POLLWRNORM);
660195957Salfred
661195957Salfred	return (err ? LIBUSB_ERROR_INVALID_PARAM : 0);
662194676Sthompsa}
663194676Sthompsa
664194676Sthompsaint
665195957Salfredlibusb_claim_interface(struct libusb20_device *pdev, int interface_number)
666194676Sthompsa{
667195957Salfred	libusb_device *dev;
668302275Shselasky	int err = 0;
669194676Sthompsa
670195957Salfred	dev = libusb_get_device(pdev);
671194676Sthompsa	if (dev == NULL)
672194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
673194676Sthompsa
674195957Salfred	if (interface_number < 0 || interface_number > 31)
675194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
676194676Sthompsa
677302275Shselasky	if (pdev->auto_detach != 0) {
678302275Shselasky		err = libusb_detach_kernel_driver(pdev, interface_number);
679302275Shselasky		if (err != 0)
680302275Shselasky			goto done;
681302275Shselasky	}
682302275Shselasky
683195957Salfred	CTX_LOCK(dev->ctx);
684261475Shselasky	dev->claimed_interfaces |= (1 << interface_number);
685261475Shselasky	CTX_UNLOCK(dev->ctx);
686302275Shselaskydone:
687302275Shselasky	return (err);
688194676Sthompsa}
689194676Sthompsa
690194676Sthompsaint
691195957Salfredlibusb_release_interface(struct libusb20_device *pdev, int interface_number)
692194676Sthompsa{
693195957Salfred	libusb_device *dev;
694195957Salfred	int err = 0;
695194676Sthompsa
696195957Salfred	dev = libusb_get_device(pdev);
697194676Sthompsa	if (dev == NULL)
698194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
699194676Sthompsa
700195957Salfred	if (interface_number < 0 || interface_number > 31)
701194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
702194676Sthompsa
703302275Shselasky	if (pdev->auto_detach != 0) {
704302275Shselasky		err = libusb_attach_kernel_driver(pdev, interface_number);
705302275Shselasky		if (err != 0)
706302275Shselasky			goto done;
707302275Shselasky	}
708302275Shselasky
709195957Salfred	CTX_LOCK(dev->ctx);
710194676Sthompsa	if (!(dev->claimed_interfaces & (1 << interface_number)))
711195957Salfred		err = LIBUSB_ERROR_NOT_FOUND;
712302275Shselasky	else
713194676Sthompsa		dev->claimed_interfaces &= ~(1 << interface_number);
714195957Salfred	CTX_UNLOCK(dev->ctx);
715302275Shselaskydone:
716195957Salfred	return (err);
717194676Sthompsa}
718194676Sthompsa
719194676Sthompsaint
720195957Salfredlibusb_set_interface_alt_setting(struct libusb20_device *pdev,
721194676Sthompsa    int interface_number, int alternate_setting)
722194676Sthompsa{
723195957Salfred	libusb_device *dev;
724195957Salfred	int err = 0;
725194676Sthompsa
726195957Salfred	dev = libusb_get_device(pdev);
727194676Sthompsa	if (dev == NULL)
728194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
729194676Sthompsa
730195957Salfred	if (interface_number < 0 || interface_number > 31)
731194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
732194676Sthompsa
733195957Salfred	CTX_LOCK(dev->ctx);
734195957Salfred	if (!(dev->claimed_interfaces & (1 << interface_number)))
735195957Salfred		err = LIBUSB_ERROR_NOT_FOUND;
736195957Salfred	CTX_UNLOCK(dev->ctx);
737194676Sthompsa
738195957Salfred	if (err)
739195957Salfred		return (err);
740195957Salfred
741195957Salfred	libusb10_cancel_all_transfer(dev);
742195957Salfred
743195957Salfred	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
744195957Salfred
745195957Salfred	err = libusb20_dev_set_alt_index(pdev,
746195957Salfred	    interface_number, alternate_setting);
747195957Salfred
748195957Salfred	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
749195957Salfred	    pdev, libusb20_dev_get_fd(pdev),
750195957Salfred	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
751195957Salfred
752195957Salfred	return (err ? LIBUSB_ERROR_OTHER : 0);
753194676Sthompsa}
754194676Sthompsa
755195957Salfredstatic struct libusb20_transfer *
756195957Salfredlibusb10_get_transfer(struct libusb20_device *pdev,
757234491Shselasky    uint8_t endpoint, uint8_t xfer_index)
758195957Salfred{
759234491Shselasky	xfer_index &= 1;	/* double buffering */
760195957Salfred
761234491Shselasky	xfer_index |= (endpoint & LIBUSB20_ENDPOINT_ADDRESS_MASK) * 4;
762195957Salfred
763195957Salfred	if (endpoint & LIBUSB20_ENDPOINT_DIR_MASK) {
764195957Salfred		/* this is an IN endpoint */
765234491Shselasky		xfer_index |= 2;
766195957Salfred	}
767234491Shselasky	return (libusb20_tr_get_pointer(pdev, xfer_index));
768195957Salfred}
769195957Salfred
770194676Sthompsaint
771195957Salfredlibusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint)
772194676Sthompsa{
773194676Sthompsa	struct libusb20_transfer *xfer;
774195957Salfred	struct libusb_device *dev;
775195957Salfred	int err;
776194676Sthompsa
777195957Salfred	xfer = libusb10_get_transfer(pdev, endpoint, 0);
778195560Sthompsa	if (xfer == NULL)
779195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
780194676Sthompsa
781195957Salfred	dev = libusb_get_device(pdev);
782213853Shselasky	if (dev == NULL)
783213853Shselasky		return (LIBUSB_ERROR_INVALID_PARAM);
784195957Salfred
785195957Salfred	CTX_LOCK(dev->ctx);
786223642Shselasky	err = libusb20_tr_open(xfer, 0, 1, endpoint);
787195957Salfred	CTX_UNLOCK(dev->ctx);
788195957Salfred
789195957Salfred	if (err != 0 && err != LIBUSB20_ERROR_BUSY)
790194676Sthompsa		return (LIBUSB_ERROR_OTHER);
791194676Sthompsa
792194676Sthompsa	libusb20_tr_clear_stall_sync(xfer);
793195957Salfred
794195957Salfred	/* check if we opened the transfer */
795195957Salfred	if (err == 0) {
796195957Salfred		CTX_LOCK(dev->ctx);
797194676Sthompsa		libusb20_tr_close(xfer);
798195957Salfred		CTX_UNLOCK(dev->ctx);
799195957Salfred	}
800195957Salfred	return (0);			/* success */
801194676Sthompsa}
802194676Sthompsa
803194676Sthompsaint
804195957Salfredlibusb_reset_device(struct libusb20_device *pdev)
805194676Sthompsa{
806195957Salfred	libusb_device *dev;
807195957Salfred	int err;
808194676Sthompsa
809195957Salfred	dev = libusb_get_device(pdev);
810194676Sthompsa	if (dev == NULL)
811213853Shselasky		return (LIBUSB_ERROR_INVALID_PARAM);
812194676Sthompsa
813195957Salfred	libusb10_cancel_all_transfer(dev);
814195957Salfred
815195957Salfred	libusb10_remove_pollfd(dev->ctx, &dev->dev_poll);
816195957Salfred
817195957Salfred	err = libusb20_dev_reset(pdev);
818195957Salfred
819195957Salfred	libusb10_add_pollfd(dev->ctx, &dev->dev_poll,
820195957Salfred	    pdev, libusb20_dev_get_fd(pdev),
821195957Salfred	    POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
822195957Salfred
823195957Salfred	return (err ? LIBUSB_ERROR_OTHER : 0);
824194676Sthompsa}
825194676Sthompsa
826194676Sthompsaint
827213848Shselaskylibusb_check_connected(struct libusb20_device *pdev)
828213848Shselasky{
829213848Shselasky	libusb_device *dev;
830213848Shselasky	int err;
831213848Shselasky
832213848Shselasky	dev = libusb_get_device(pdev);
833213848Shselasky	if (dev == NULL)
834213848Shselasky		return (LIBUSB_ERROR_INVALID_PARAM);
835213848Shselasky
836213848Shselasky	err = libusb20_dev_check_connected(pdev);
837213848Shselasky
838213848Shselasky	return (err ? LIBUSB_ERROR_NO_DEVICE : 0);
839213848Shselasky}
840213848Shselasky
841213848Shselaskyint
842195957Salfredlibusb_kernel_driver_active(struct libusb20_device *pdev, int interface)
843194676Sthompsa{
844195957Salfred	if (pdev == NULL)
845194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
846194676Sthompsa
847226220Shselasky	if (libusb20_dev_kernel_driver_active(pdev, interface))
848226220Shselasky		return (0);		/* no kernel driver is active */
849226220Shselasky	else
850226220Shselasky		return (1);		/* kernel driver is active */
851194676Sthompsa}
852194676Sthompsa
853194676Sthompsaint
854213853Shselaskylibusb_get_driver_np(struct libusb20_device *pdev, int interface,
855213853Shselasky    char *name, int namelen)
856213853Shselasky{
857213853Shselasky	return (libusb_get_driver(pdev, interface, name, namelen));
858213853Shselasky}
859213853Shselasky
860213853Shselaskyint
861213853Shselaskylibusb_get_driver(struct libusb20_device *pdev, int interface,
862213853Shselasky    char *name, int namelen)
863213853Shselasky{
864213853Shselasky	char *ptr;
865213853Shselasky	int err;
866213853Shselasky
867213853Shselasky	if (pdev == NULL)
868213853Shselasky		return (LIBUSB_ERROR_INVALID_PARAM);
869213853Shselasky	if (namelen < 1)
870213853Shselasky		return (LIBUSB_ERROR_INVALID_PARAM);
871224085Shselasky	if (namelen > 255)
872224085Shselasky		namelen = 255;
873213853Shselasky
874213853Shselasky	err = libusb20_dev_get_iface_desc(
875213853Shselasky	    pdev, interface, name, namelen);
876213853Shselasky
877213853Shselasky	if (err != 0)
878213853Shselasky		return (LIBUSB_ERROR_OTHER);
879213853Shselasky
880213853Shselasky	/* we only want the driver name */
881213853Shselasky	ptr = strstr(name, ":");
882213853Shselasky	if (ptr != NULL)
883213853Shselasky		*ptr = 0;
884213853Shselasky
885213853Shselasky	return (0);
886213853Shselasky}
887213853Shselasky
888213853Shselaskyint
889213853Shselaskylibusb_detach_kernel_driver_np(struct libusb20_device *pdev, int interface)
890213853Shselasky{
891213853Shselasky	return (libusb_detach_kernel_driver(pdev, interface));
892213853Shselasky}
893213853Shselasky
894213853Shselaskyint
895195957Salfredlibusb_detach_kernel_driver(struct libusb20_device *pdev, int interface)
896194676Sthompsa{
897195957Salfred	int err;
898194676Sthompsa
899195957Salfred	if (pdev == NULL)
900194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
901194676Sthompsa
902195957Salfred	err = libusb20_dev_detach_kernel_driver(
903195957Salfred	    pdev, interface);
904194676Sthompsa
905213853Shselasky	return (err ? LIBUSB_ERROR_OTHER : 0);
906194676Sthompsa}
907194676Sthompsa
908194676Sthompsaint
909195957Salfredlibusb_attach_kernel_driver(struct libusb20_device *pdev, int interface)
910194676Sthompsa{
911195957Salfred	if (pdev == NULL)
912194676Sthompsa		return (LIBUSB_ERROR_INVALID_PARAM);
913195957Salfred	/* stub - currently not supported by libusb20 */
914194676Sthompsa	return (0);
915194676Sthompsa}
916194676Sthompsa
917302275Shselaskyint
918302275Shselaskylibusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable)
919302275Shselasky{
920302275Shselasky	dev->auto_detach = (enable ? 1 : 0);
921302275Shselasky	return (0);
922302275Shselasky}
923302275Shselasky
924194676Sthompsa/* Asynchronous device I/O */
925194676Sthompsa
926194676Sthompsastruct libusb_transfer *
927194676Sthompsalibusb_alloc_transfer(int iso_packets)
928194676Sthompsa{
929195957Salfred	struct libusb_transfer *uxfer;
930195957Salfred	struct libusb_super_transfer *sxfer;
931194676Sthompsa	int len;
932194676Sthompsa
933194676Sthompsa	len = sizeof(struct libusb_transfer) +
934195957Salfred	    sizeof(struct libusb_super_transfer) +
935194676Sthompsa	    (iso_packets * sizeof(libusb_iso_packet_descriptor));
936194676Sthompsa
937195957Salfred	sxfer = malloc(len);
938195957Salfred	if (sxfer == NULL)
939194676Sthompsa		return (NULL);
940194676Sthompsa
941195957Salfred	memset(sxfer, 0, len);
942194676Sthompsa
943195957Salfred	uxfer = (struct libusb_transfer *)(
944195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
945194676Sthompsa
946195957Salfred	/* set default value */
947195957Salfred	uxfer->num_iso_packets = iso_packets;
948195957Salfred
949195957Salfred	return (uxfer);
950194676Sthompsa}
951194676Sthompsa
952194676Sthompsavoid
953195957Salfredlibusb_free_transfer(struct libusb_transfer *uxfer)
954194676Sthompsa{
955195957Salfred	struct libusb_super_transfer *sxfer;
956194676Sthompsa
957195957Salfred	if (uxfer == NULL)
958195957Salfred		return;			/* be NULL safe */
959194676Sthompsa
960215253Shselasky	/* check if we should free the transfer buffer */
961215253Shselasky	if (uxfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
962215253Shselasky		free(uxfer->buffer);
963215253Shselasky
964195957Salfred	sxfer = (struct libusb_super_transfer *)(
965195957Salfred	    (uint8_t *)uxfer - sizeof(*sxfer));
966194676Sthompsa
967195957Salfred	free(sxfer);
968194676Sthompsa}
969194676Sthompsa
970219100Shselaskystatic uint32_t
971195957Salfredlibusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer)
972195560Sthompsa{
973219100Shselasky	uint32_t ret;
974195560Sthompsa
975195560Sthompsa	switch (xfer->type) {
976195560Sthompsa	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
977219100Shselasky		ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE;	/* 60ms */
978195957Salfred		break;
979195560Sthompsa	case LIBUSB_TRANSFER_TYPE_CONTROL:
980195560Sthompsa		ret = 2;
981195957Salfred		break;
982195560Sthompsa	default:
983195560Sthompsa		ret = 1;
984195957Salfred		break;
985195560Sthompsa	}
986195957Salfred	return (ret);
987195560Sthompsa}
988195560Sthompsa
989195560Sthompsastatic int
990195957Salfredlibusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer)
991195560Sthompsa{
992195560Sthompsa	int ret;
993195560Sthompsa	int usb_speed;
994195560Sthompsa
995195560Sthompsa	usb_speed = libusb20_dev_get_speed(pdev);
996195560Sthompsa
997195560Sthompsa	switch (xfer->type) {
998195560Sthompsa	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
999195957Salfred		ret = 0;		/* kernel will auto-select */
1000195957Salfred		break;
1001195560Sthompsa	case LIBUSB_TRANSFER_TYPE_CONTROL:
1002195957Salfred		ret = 1024;
1003195957Salfred		break;
1004195957Salfred	default:
1005195560Sthompsa		switch (usb_speed) {
1006195957Salfred		case LIBUSB20_SPEED_LOW:
1007195957Salfred			ret = 256;
1008195957Salfred			break;
1009195957Salfred		case LIBUSB20_SPEED_FULL:
1010195957Salfred			ret = 4096;
1011195957Salfred			break;
1012264641Shselasky		case LIBUSB20_SPEED_SUPER:
1013264641Shselasky			ret = 65536;
1014264641Shselasky			break;
1015195957Salfred		default:
1016195957Salfred			ret = 16384;
1017195957Salfred			break;
1018195560Sthompsa		}
1019195957Salfred		break;
1020195560Sthompsa	}
1021195957Salfred	return (ret);
1022195560Sthompsa}
1023195560Sthompsa
1024195957Salfredstatic int
1025195957Salfredlibusb10_convert_error(uint8_t status)
1026195957Salfred{
1027195957Salfred	;				/* indent fix */
1028195957Salfred
1029195957Salfred	switch (status) {
1030195957Salfred	case LIBUSB20_TRANSFER_START:
1031195957Salfred	case LIBUSB20_TRANSFER_COMPLETED:
1032195957Salfred		return (LIBUSB_TRANSFER_COMPLETED);
1033195957Salfred	case LIBUSB20_TRANSFER_OVERFLOW:
1034195957Salfred		return (LIBUSB_TRANSFER_OVERFLOW);
1035195957Salfred	case LIBUSB20_TRANSFER_NO_DEVICE:
1036195957Salfred		return (LIBUSB_TRANSFER_NO_DEVICE);
1037195957Salfred	case LIBUSB20_TRANSFER_STALL:
1038195957Salfred		return (LIBUSB_TRANSFER_STALL);
1039195957Salfred	case LIBUSB20_TRANSFER_CANCELLED:
1040195957Salfred		return (LIBUSB_TRANSFER_CANCELLED);
1041195957Salfred	case LIBUSB20_TRANSFER_TIMED_OUT:
1042195957Salfred		return (LIBUSB_TRANSFER_TIMED_OUT);
1043195957Salfred	default:
1044195957Salfred		return (LIBUSB_TRANSFER_ERROR);
1045195957Salfred	}
1046195957Salfred}
1047195957Salfred
1048195957Salfred/* This function must be called locked */
1049195957Salfred
1050194676Sthompsastatic void
1051195957Salfredlibusb10_complete_transfer(struct libusb20_transfer *pxfer,
1052195957Salfred    struct libusb_super_transfer *sxfer, int status)
1053194676Sthompsa{
1054195957Salfred	struct libusb_transfer *uxfer;
1055195957Salfred	struct libusb_device *dev;
1056195957Salfred
1057195957Salfred	uxfer = (struct libusb_transfer *)(
1058195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1059195957Salfred
1060195957Salfred	if (pxfer != NULL)
1061195957Salfred		libusb20_tr_set_priv_sc1(pxfer, NULL);
1062195957Salfred
1063199575Sthompsa	/* set transfer status */
1064195957Salfred	uxfer->status = status;
1065195957Salfred
1066199575Sthompsa	/* update super transfer state */
1067199575Sthompsa	sxfer->state = LIBUSB_SUPER_XFER_ST_NONE;
1068199575Sthompsa
1069195957Salfred	dev = libusb_get_device(uxfer->dev_handle);
1070195957Salfred
1071195957Salfred	TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry);
1072195957Salfred}
1073195957Salfred
1074195957Salfred/* This function must be called locked */
1075195957Salfred
1076195957Salfredstatic void
1077195957Salfredlibusb10_isoc_proxy(struct libusb20_transfer *pxfer)
1078195957Salfred{
1079195957Salfred	struct libusb_super_transfer *sxfer;
1080195957Salfred	struct libusb_transfer *uxfer;
1081195957Salfred	uint32_t actlen;
1082195957Salfred	uint16_t iso_packets;
1083195957Salfred	uint16_t i;
1084194676Sthompsa	uint8_t status;
1085195957Salfred	uint8_t flags;
1086194676Sthompsa
1087195957Salfred	status = libusb20_tr_get_status(pxfer);
1088195957Salfred	sxfer = libusb20_tr_get_priv_sc1(pxfer);
1089195957Salfred	actlen = libusb20_tr_get_actual_length(pxfer);
1090195957Salfred	iso_packets = libusb20_tr_get_max_frames(pxfer);
1091194676Sthompsa
1092195957Salfred	if (sxfer == NULL)
1093195957Salfred		return;			/* cancelled - nothing to do */
1094195957Salfred
1095195957Salfred	uxfer = (struct libusb_transfer *)(
1096195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1097195957Salfred
1098195957Salfred	if (iso_packets > uxfer->num_iso_packets)
1099195957Salfred		iso_packets = uxfer->num_iso_packets;
1100195957Salfred
1101195957Salfred	if (iso_packets == 0)
1102195957Salfred		return;			/* nothing to do */
1103195957Salfred
1104195957Salfred	/* make sure that the number of ISOCHRONOUS packets is valid */
1105195957Salfred	uxfer->num_iso_packets = iso_packets;
1106195957Salfred
1107195957Salfred	flags = uxfer->flags;
1108195957Salfred
1109194676Sthompsa	switch (status) {
1110194676Sthompsa	case LIBUSB20_TRANSFER_COMPLETED:
1111195560Sthompsa
1112195957Salfred		/* update actual length */
1113195957Salfred		uxfer->actual_length = actlen;
1114195957Salfred		for (i = 0; i != iso_packets; i++) {
1115195957Salfred			uxfer->iso_packet_desc[i].actual_length =
1116195957Salfred			    libusb20_tr_get_length(pxfer, i);
1117195957Salfred		}
1118195957Salfred		libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1119195957Salfred		break;
1120195560Sthompsa
1121194676Sthompsa	case LIBUSB20_TRANSFER_START:
1122195957Salfred
1123195957Salfred		/* setup length(s) */
1124195957Salfred		actlen = 0;
1125195957Salfred		for (i = 0; i != iso_packets; i++) {
1126195957Salfred			libusb20_tr_setup_isoc(pxfer,
1127195957Salfred			    &uxfer->buffer[actlen],
1128195957Salfred			    uxfer->iso_packet_desc[i].length, i);
1129195957Salfred			actlen += uxfer->iso_packet_desc[i].length;
1130194676Sthompsa		}
1131195957Salfred
1132195957Salfred		/* no remainder */
1133195957Salfred		sxfer->rem_len = 0;
1134195957Salfred
1135195957Salfred		libusb20_tr_set_total_frames(pxfer, iso_packets);
1136195957Salfred		libusb20_tr_submit(pxfer);
1137195957Salfred
1138195957Salfred		/* fork another USB transfer, if any */
1139195957Salfred		libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
1140195957Salfred		break;
1141195957Salfred
1142194676Sthompsa	default:
1143195957Salfred		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
1144195957Salfred		break;
1145194676Sthompsa	}
1146195957Salfred}
1147194676Sthompsa
1148195957Salfred/* This function must be called locked */
1149195957Salfred
1150195957Salfredstatic void
1151195957Salfredlibusb10_bulk_intr_proxy(struct libusb20_transfer *pxfer)
1152195957Salfred{
1153195957Salfred	struct libusb_super_transfer *sxfer;
1154195957Salfred	struct libusb_transfer *uxfer;
1155195957Salfred	uint32_t max_bulk;
1156195957Salfred	uint32_t actlen;
1157195957Salfred	uint8_t status;
1158195957Salfred	uint8_t flags;
1159195957Salfred
1160195957Salfred	status = libusb20_tr_get_status(pxfer);
1161195957Salfred	sxfer = libusb20_tr_get_priv_sc1(pxfer);
1162195957Salfred	max_bulk = libusb20_tr_get_max_total_length(pxfer);
1163195957Salfred	actlen = libusb20_tr_get_actual_length(pxfer);
1164195957Salfred
1165195957Salfred	if (sxfer == NULL)
1166195957Salfred		return;			/* cancelled - nothing to do */
1167195957Salfred
1168195957Salfred	uxfer = (struct libusb_transfer *)(
1169195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1170195957Salfred
1171195957Salfred	flags = uxfer->flags;
1172195957Salfred
1173194676Sthompsa	switch (status) {
1174194676Sthompsa	case LIBUSB20_TRANSFER_COMPLETED:
1175195957Salfred
1176195957Salfred		uxfer->actual_length += actlen;
1177195957Salfred
1178195957Salfred		/* check for short packet */
1179195957Salfred		if (sxfer->last_len != actlen) {
1180195957Salfred			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
1181195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
1182195957Salfred			} else {
1183195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1184195957Salfred			}
1185195957Salfred			break;
1186195957Salfred		}
1187195957Salfred		/* check for end of data */
1188195957Salfred		if (sxfer->rem_len == 0) {
1189195957Salfred			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1190195957Salfred			break;
1191195957Salfred		}
1192195957Salfred		/* FALLTHROUGH */
1193195957Salfred
1194195957Salfred	case LIBUSB20_TRANSFER_START:
1195195957Salfred		if (max_bulk > sxfer->rem_len) {
1196195957Salfred			max_bulk = sxfer->rem_len;
1197195957Salfred		}
1198195957Salfred		/* setup new BULK or INTERRUPT transaction */
1199195957Salfred		libusb20_tr_setup_bulk(pxfer,
1200195957Salfred		    sxfer->curr_data, max_bulk, uxfer->timeout);
1201195957Salfred
1202195957Salfred		/* update counters */
1203195957Salfred		sxfer->last_len = max_bulk;
1204195957Salfred		sxfer->curr_data += max_bulk;
1205195957Salfred		sxfer->rem_len -= max_bulk;
1206195957Salfred
1207195957Salfred		libusb20_tr_submit(pxfer);
1208195957Salfred
1209195957Salfred		/* check if we can fork another USB transfer */
1210195957Salfred		if (sxfer->rem_len == 0)
1211195957Salfred			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
1212195957Salfred		break;
1213195957Salfred
1214195957Salfred	default:
1215195957Salfred		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
1216195957Salfred		break;
1217194676Sthompsa	}
1218194676Sthompsa}
1219194676Sthompsa
1220195957Salfred/* This function must be called locked */
1221195957Salfred
1222195957Salfredstatic void
1223195957Salfredlibusb10_ctrl_proxy(struct libusb20_transfer *pxfer)
1224194676Sthompsa{
1225195957Salfred	struct libusb_super_transfer *sxfer;
1226195957Salfred	struct libusb_transfer *uxfer;
1227195957Salfred	uint32_t max_bulk;
1228195957Salfred	uint32_t actlen;
1229195957Salfred	uint8_t status;
1230195957Salfred	uint8_t flags;
1231194676Sthompsa
1232195957Salfred	status = libusb20_tr_get_status(pxfer);
1233195957Salfred	sxfer = libusb20_tr_get_priv_sc1(pxfer);
1234195957Salfred	max_bulk = libusb20_tr_get_max_total_length(pxfer);
1235195957Salfred	actlen = libusb20_tr_get_actual_length(pxfer);
1236194676Sthompsa
1237195957Salfred	if (sxfer == NULL)
1238195957Salfred		return;			/* cancelled - nothing to do */
1239194676Sthompsa
1240195957Salfred	uxfer = (struct libusb_transfer *)(
1241195957Salfred	    ((uint8_t *)sxfer) + sizeof(*sxfer));
1242194676Sthompsa
1243195957Salfred	flags = uxfer->flags;
1244194676Sthompsa
1245195957Salfred	switch (status) {
1246195957Salfred	case LIBUSB20_TRANSFER_COMPLETED:
1247194676Sthompsa
1248195957Salfred		uxfer->actual_length += actlen;
1249195957Salfred
1250195957Salfred		/* subtract length of SETUP packet, if any */
1251195957Salfred		actlen -= libusb20_tr_get_length(pxfer, 0);
1252195957Salfred
1253195957Salfred		/* check for short packet */
1254195957Salfred		if (sxfer->last_len != actlen) {
1255195957Salfred			if (flags & LIBUSB_TRANSFER_SHORT_NOT_OK) {
1256195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_ERROR);
1257195957Salfred			} else {
1258195957Salfred				libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1259195957Salfred			}
1260195957Salfred			break;
1261194676Sthompsa		}
1262195957Salfred		/* check for end of data */
1263195957Salfred		if (sxfer->rem_len == 0) {
1264195957Salfred			libusb10_complete_transfer(pxfer, sxfer, LIBUSB_TRANSFER_COMPLETED);
1265195957Salfred			break;
1266195957Salfred		}
1267195957Salfred		/* FALLTHROUGH */
1268194676Sthompsa
1269195957Salfred	case LIBUSB20_TRANSFER_START:
1270195957Salfred		if (max_bulk > sxfer->rem_len) {
1271195957Salfred			max_bulk = sxfer->rem_len;
1272195957Salfred		}
1273195957Salfred		/* setup new CONTROL transaction */
1274195957Salfred		if (status == LIBUSB20_TRANSFER_COMPLETED) {
1275195957Salfred			/* next fragment - don't send SETUP packet */
1276195957Salfred			libusb20_tr_set_length(pxfer, 0, 0);
1277195957Salfred		} else {
1278195957Salfred			/* first fragment - send SETUP packet */
1279195957Salfred			libusb20_tr_set_length(pxfer, 8, 0);
1280195957Salfred			libusb20_tr_set_buffer(pxfer, uxfer->buffer, 0);
1281195957Salfred		}
1282195957Salfred
1283195957Salfred		if (max_bulk != 0) {
1284195957Salfred			libusb20_tr_set_length(pxfer, max_bulk, 1);
1285195957Salfred			libusb20_tr_set_buffer(pxfer, sxfer->curr_data, 1);
1286195957Salfred			libusb20_tr_set_total_frames(pxfer, 2);
1287195957Salfred		} else {
1288195957Salfred			libusb20_tr_set_total_frames(pxfer, 1);
1289195957Salfred		}
1290195957Salfred
1291195957Salfred		/* update counters */
1292195957Salfred		sxfer->last_len = max_bulk;
1293195957Salfred		sxfer->curr_data += max_bulk;
1294195957Salfred		sxfer->rem_len -= max_bulk;
1295195957Salfred
1296195957Salfred		libusb20_tr_submit(pxfer);
1297195957Salfred
1298195957Salfred		/* check if we can fork another USB transfer */
1299195957Salfred		if (sxfer->rem_len == 0)
1300195957Salfred			libusb10_submit_transfer_sub(libusb20_tr_get_priv_sc0(pxfer), uxfer->endpoint);
1301195957Salfred		break;
1302195957Salfred
1303195957Salfred	default:
1304195957Salfred		libusb10_complete_transfer(pxfer, sxfer, libusb10_convert_error(status));
1305195957Salfred		break;
1306194676Sthompsa	}
1307195957Salfred}
1308195957Salfred
1309195957Salfred/* The following function must be called locked */
1310195957Salfred
1311195957Salfredstatic void
1312195957Salfredlibusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint)
1313195957Salfred{
1314195957Salfred	struct libusb20_transfer *pxfer0;
1315195957Salfred	struct libusb20_transfer *pxfer1;
1316195957Salfred	struct libusb_super_transfer *sxfer;
1317195957Salfred	struct libusb_transfer *uxfer;
1318195957Salfred	struct libusb_device *dev;
1319195957Salfred	int err;
1320195957Salfred	int buffsize;
1321195957Salfred	int maxframe;
1322195957Salfred	int temp;
1323195957Salfred
1324195957Salfred	dev = libusb_get_device(pdev);
1325195957Salfred
1326195957Salfred	pxfer0 = libusb10_get_transfer(pdev, endpoint, 0);
1327195957Salfred	pxfer1 = libusb10_get_transfer(pdev, endpoint, 1);
1328195957Salfred
1329195957Salfred	if (pxfer0 == NULL || pxfer1 == NULL)
1330195957Salfred		return;			/* shouldn't happen */
1331195957Salfred
1332195957Salfred	temp = 0;
1333195957Salfred	if (libusb20_tr_pending(pxfer0))
1334195957Salfred		temp |= 1;
1335195957Salfred	if (libusb20_tr_pending(pxfer1))
1336195957Salfred		temp |= 2;
1337195957Salfred
1338195957Salfred	switch (temp) {
1339195957Salfred	case 3:
1340195957Salfred		/* wait till one of the transfers complete */
1341195957Salfred		return;
1342195957Salfred	case 2:
1343195957Salfred		sxfer = libusb20_tr_get_priv_sc1(pxfer1);
1344199575Sthompsa		if (sxfer == NULL)
1345199575Sthompsa			return;		/* cancelling */
1346195957Salfred		if (sxfer->rem_len)
1347195957Salfred			return;		/* cannot queue another one */
1348195957Salfred		/* swap transfers */
1349195957Salfred		pxfer1 = pxfer0;
1350195957Salfred		break;
1351195957Salfred	case 1:
1352195957Salfred		sxfer = libusb20_tr_get_priv_sc1(pxfer0);
1353199575Sthompsa		if (sxfer == NULL)
1354199575Sthompsa			return;		/* cancelling */
1355195957Salfred		if (sxfer->rem_len)
1356195957Salfred			return;		/* cannot queue another one */
1357195957Salfred		/* swap transfers */
1358195957Salfred		pxfer0 = pxfer1;
1359195957Salfred		break;
1360195957Salfred	default:
1361195957Salfred		break;
1362194676Sthompsa	}
1363195957Salfred
1364195957Salfred	/* find next transfer on same endpoint */
1365195957Salfred	TAILQ_FOREACH(sxfer, &dev->tr_head, entry) {
1366195957Salfred
1367195957Salfred		uxfer = (struct libusb_transfer *)(
1368195957Salfred		    ((uint8_t *)sxfer) + sizeof(*sxfer));
1369195957Salfred
1370195957Salfred		if (uxfer->endpoint == endpoint) {
1371195957Salfred			TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
1372195957Salfred			sxfer->entry.tqe_prev = NULL;
1373195957Salfred			goto found;
1374194676Sthompsa		}
1375195957Salfred	}
1376195957Salfred	return;				/* success */
1377194676Sthompsa
1378195957Salfredfound:
1379194676Sthompsa
1380195957Salfred	libusb20_tr_set_priv_sc0(pxfer0, pdev);
1381195957Salfred	libusb20_tr_set_priv_sc1(pxfer0, sxfer);
1382194676Sthompsa
1383195957Salfred	/* reset super transfer state */
1384195957Salfred	sxfer->rem_len = uxfer->length;
1385195957Salfred	sxfer->curr_data = uxfer->buffer;
1386195957Salfred	uxfer->actual_length = 0;
1387194676Sthompsa
1388195957Salfred	switch (uxfer->type) {
1389195957Salfred	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
1390195957Salfred		libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
1391195957Salfred		break;
1392195957Salfred	case LIBUSB_TRANSFER_TYPE_BULK:
1393195957Salfred	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
1394195957Salfred		libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
1395195957Salfred		break;
1396195957Salfred	case LIBUSB_TRANSFER_TYPE_CONTROL:
1397195957Salfred		libusb20_tr_set_callback(pxfer0, libusb10_ctrl_proxy);
1398195957Salfred		if (sxfer->rem_len < 8)
1399195957Salfred			goto failure;
1400194676Sthompsa
1401195957Salfred		/* remove SETUP packet from data */
1402195957Salfred		sxfer->rem_len -= 8;
1403195957Salfred		sxfer->curr_data += 8;
1404195957Salfred		break;
1405195957Salfred	default:
1406195957Salfred		goto failure;
1407195560Sthompsa	}
1408195957Salfred
1409195957Salfred	buffsize = libusb10_get_buffsize(pdev, uxfer);
1410195957Salfred	maxframe = libusb10_get_maxframe(pdev, uxfer);
1411195957Salfred
1412195957Salfred	/* make sure the transfer is opened */
1413302275Shselasky	err = libusb20_tr_open_stream(pxfer0, buffsize, maxframe,
1414302275Shselasky	    endpoint, sxfer->stream_id);
1415195957Salfred	if (err && (err != LIBUSB20_ERROR_BUSY)) {
1416195957Salfred		goto failure;
1417194676Sthompsa	}
1418195957Salfred	libusb20_tr_start(pxfer0);
1419195957Salfred	return;
1420194676Sthompsa
1421195957Salfredfailure:
1422195957Salfred	libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_ERROR);
1423195957Salfred	/* make sure our event loop spins the done handler */
1424338789Shselasky	libusb10_wakeup_event_loop(dev->ctx);
1425195957Salfred}
1426194676Sthompsa
1427195957Salfred/* The following function must be called unlocked */
1428194676Sthompsa
1429195957Salfredint
1430195957Salfredlibusb_submit_transfer(struct libusb_transfer *uxfer)
1431195957Salfred{
1432195957Salfred	struct libusb20_transfer *pxfer0;
1433195957Salfred	struct libusb20_transfer *pxfer1;
1434195957Salfred	struct libusb_super_transfer *sxfer;
1435195957Salfred	struct libusb_device *dev;
1436234684Shselasky	uint8_t endpoint;
1437195957Salfred	int err;
1438195957Salfred
1439195957Salfred	if (uxfer == NULL)
1440195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1441195957Salfred
1442195957Salfred	if (uxfer->dev_handle == NULL)
1443195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1444195957Salfred
1445195957Salfred	endpoint = uxfer->endpoint;
1446195957Salfred
1447195957Salfred	dev = libusb_get_device(uxfer->dev_handle);
1448195957Salfred
1449195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
1450195957Salfred
1451195957Salfred	sxfer = (struct libusb_super_transfer *)(
1452195957Salfred	    (uint8_t *)uxfer - sizeof(*sxfer));
1453195957Salfred
1454195957Salfred	CTX_LOCK(dev->ctx);
1455195957Salfred
1456195957Salfred	pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0);
1457195957Salfred	pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1);
1458195957Salfred
1459195957Salfred	if (pxfer0 == NULL || pxfer1 == NULL) {
1460195957Salfred		err = LIBUSB_ERROR_OTHER;
1461195957Salfred	} else if ((sxfer->entry.tqe_prev != NULL) ||
1462199575Sthompsa	    (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) ||
1463195957Salfred	    (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) {
1464195957Salfred		err = LIBUSB_ERROR_BUSY;
1465338789Shselasky	} else if (dev->device_is_gone != 0) {
1466338789Shselasky		err = LIBUSB_ERROR_NO_DEVICE;
1467195957Salfred	} else {
1468199575Sthompsa
1469199575Sthompsa		/* set pending state */
1470199575Sthompsa		sxfer->state = LIBUSB_SUPER_XFER_ST_PEND;
1471199575Sthompsa
1472199575Sthompsa		/* insert transfer into transfer head list */
1473195957Salfred		TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry);
1474195957Salfred
1475199575Sthompsa		/* start work transfers */
1476195957Salfred		libusb10_submit_transfer_sub(
1477195957Salfred		    uxfer->dev_handle, endpoint);
1478195957Salfred
1479195957Salfred		err = 0;		/* success */
1480195957Salfred	}
1481195957Salfred
1482195957Salfred	CTX_UNLOCK(dev->ctx);
1483195957Salfred
1484195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
1485195957Salfred
1486195957Salfred	return (err);
1487194676Sthompsa}
1488194676Sthompsa
1489195957Salfred/* Asynchronous transfer cancel */
1490195957Salfred
1491194676Sthompsaint
1492195957Salfredlibusb_cancel_transfer(struct libusb_transfer *uxfer)
1493194676Sthompsa{
1494195957Salfred	struct libusb20_transfer *pxfer0;
1495195957Salfred	struct libusb20_transfer *pxfer1;
1496195957Salfred	struct libusb_super_transfer *sxfer;
1497195957Salfred	struct libusb_device *dev;
1498338789Shselasky	struct libusb_device_handle *devh;
1499234684Shselasky	uint8_t endpoint;
1500199575Sthompsa	int retval;
1501194676Sthompsa
1502195957Salfred	if (uxfer == NULL)
1503195957Salfred		return (LIBUSB_ERROR_INVALID_PARAM);
1504194676Sthompsa
1505199575Sthompsa	/* check if not initialised */
1506338789Shselasky	if ((devh = uxfer->dev_handle) == NULL)
1507199575Sthompsa		return (LIBUSB_ERROR_NOT_FOUND);
1508194676Sthompsa
1509195957Salfred	endpoint = uxfer->endpoint;
1510194676Sthompsa
1511338789Shselasky	dev = libusb_get_device(devh);
1512195957Salfred
1513195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
1514195957Salfred
1515195957Salfred	sxfer = (struct libusb_super_transfer *)(
1516195957Salfred	    (uint8_t *)uxfer - sizeof(*sxfer));
1517195957Salfred
1518199575Sthompsa	retval = 0;
1519199575Sthompsa
1520195957Salfred	CTX_LOCK(dev->ctx);
1521195957Salfred
1522338789Shselasky	pxfer0 = libusb10_get_transfer(devh, endpoint, 0);
1523338789Shselasky	pxfer1 = libusb10_get_transfer(devh, endpoint, 1);
1524195957Salfred
1525199575Sthompsa	if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) {
1526199575Sthompsa		/* only update the transfer status */
1527199575Sthompsa		uxfer->status = LIBUSB_TRANSFER_CANCELLED;
1528199575Sthompsa		retval = LIBUSB_ERROR_NOT_FOUND;
1529199575Sthompsa	} else if (sxfer->entry.tqe_prev != NULL) {
1530195957Salfred		/* we are lucky - transfer is on a queue */
1531195957Salfred		TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
1532195957Salfred		sxfer->entry.tqe_prev = NULL;
1533199575Sthompsa		libusb10_complete_transfer(NULL,
1534199575Sthompsa		    sxfer, LIBUSB_TRANSFER_CANCELLED);
1535338789Shselasky		/* make sure our event loop spins the done handler */
1536338789Shselasky		libusb10_wakeup_event_loop(dev->ctx);
1537195957Salfred	} else if (pxfer0 == NULL || pxfer1 == NULL) {
1538195957Salfred		/* not started */
1539199575Sthompsa		retval = LIBUSB_ERROR_NOT_FOUND;
1540195957Salfred	} else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) {
1541199575Sthompsa		libusb10_complete_transfer(pxfer0,
1542199575Sthompsa		    sxfer, LIBUSB_TRANSFER_CANCELLED);
1543338789Shselasky		if (dev->device_is_gone != 0) {
1544338789Shselasky			/* clear transfer pointer */
1545338789Shselasky			libusb20_tr_set_priv_sc1(pxfer0, NULL);
1546338789Shselasky			/* make sure our event loop spins the done handler */
1547338789Shselasky			libusb10_wakeup_event_loop(dev->ctx);
1548338789Shselasky		} else {
1549338789Shselasky			libusb20_tr_stop(pxfer0);
1550338789Shselasky			/* make sure the queue doesn't stall */
1551338789Shselasky			libusb10_submit_transfer_sub(devh, endpoint);
1552338789Shselasky		}
1553195957Salfred	} else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) {
1554199575Sthompsa		libusb10_complete_transfer(pxfer1,
1555199575Sthompsa		    sxfer, LIBUSB_TRANSFER_CANCELLED);
1556338789Shselasky		/* check if handle is still active */
1557338789Shselasky		if (dev->device_is_gone != 0) {
1558338789Shselasky			/* clear transfer pointer */
1559338789Shselasky			libusb20_tr_set_priv_sc1(pxfer1, NULL);
1560338789Shselasky			/* make sure our event loop spins the done handler */
1561338789Shselasky			libusb10_wakeup_event_loop(dev->ctx);
1562338789Shselasky		} else {
1563338789Shselasky			libusb20_tr_stop(pxfer1);
1564338789Shselasky			/* make sure the queue doesn't stall */
1565338789Shselasky			libusb10_submit_transfer_sub(devh, endpoint);
1566338789Shselasky		}
1567195957Salfred	} else {
1568195957Salfred		/* not started */
1569199575Sthompsa		retval = LIBUSB_ERROR_NOT_FOUND;
1570195957Salfred	}
1571195957Salfred
1572195957Salfred	CTX_UNLOCK(dev->ctx);
1573195957Salfred
1574195957Salfred	DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
1575195957Salfred
1576199575Sthompsa	return (retval);
1577194676Sthompsa}
1578194676Sthompsa
1579195957SalfredUNEXPORTED void
1580195957Salfredlibusb10_cancel_all_transfer(libusb_device *dev)
1581195957Salfred{
1582302272Shselasky	struct libusb20_device *pdev = dev->os_priv;
1583302272Shselasky	unsigned x;
1584302272Shselasky
1585302272Shselasky	for (x = 0; x != LIBUSB_NUM_SW_ENDPOINTS; x++) {
1586302272Shselasky		struct libusb20_transfer *xfer;
1587302272Shselasky
1588302272Shselasky		xfer = libusb20_tr_get_pointer(pdev, x);
1589302272Shselasky		if (xfer == NULL)
1590302272Shselasky			continue;
1591302272Shselasky		libusb20_tr_close(xfer);
1592302272Shselasky	}
1593195957Salfred}
1594199055Sthompsa
1595338789ShselaskyUNEXPORTED void
1596338789Shselaskylibusb10_cancel_all_transfer_locked(struct libusb20_device *pdev, struct libusb_device *dev)
1597338789Shselasky{
1598338789Shselasky	struct libusb_super_transfer *sxfer;
1599338789Shselasky	unsigned x;
1600338789Shselasky
1601338789Shselasky	for (x = 0; x != LIBUSB_NUM_SW_ENDPOINTS; x++) {
1602338789Shselasky		struct libusb20_transfer *xfer;
1603338789Shselasky
1604338789Shselasky		xfer = libusb20_tr_get_pointer(pdev, x);
1605338789Shselasky		if (xfer == NULL)
1606338789Shselasky			continue;
1607338789Shselasky		if (libusb20_tr_pending(xfer) == 0)
1608338789Shselasky			continue;
1609338789Shselasky		sxfer = libusb20_tr_get_priv_sc1(xfer);
1610338789Shselasky		if (sxfer == NULL)
1611338789Shselasky			continue;
1612338789Shselasky		/* complete pending transfer */
1613338789Shselasky		libusb10_complete_transfer(xfer, sxfer, LIBUSB_TRANSFER_ERROR);
1614338789Shselasky	}
1615338789Shselasky
1616338789Shselasky	while ((sxfer = TAILQ_FIRST(&dev->tr_head))) {
1617338789Shselasky		TAILQ_REMOVE(&dev->tr_head, sxfer, entry);
1618338789Shselasky
1619338789Shselasky		/* complete pending transfer */
1620338789Shselasky		libusb10_complete_transfer(NULL, sxfer, LIBUSB_TRANSFER_ERROR);
1621338789Shselasky	}
1622338789Shselasky}
1623338789Shselasky
1624199055Sthompsauint16_t
1625199055Sthompsalibusb_cpu_to_le16(uint16_t x)
1626199055Sthompsa{
1627199055Sthompsa	return (htole16(x));
1628199055Sthompsa}
1629199055Sthompsa
1630199055Sthompsauint16_t
1631199055Sthompsalibusb_le16_to_cpu(uint16_t x)
1632199055Sthompsa{
1633199055Sthompsa	return (le16toh(x));
1634199055Sthompsa}
1635199055Sthompsa
1636213853Shselaskyconst char *
1637213853Shselaskylibusb_strerror(int code)
1638213853Shselasky{
1639225659Shselasky	switch (code) {
1640225659Shselasky	case LIBUSB_SUCCESS:
1641225659Shselasky		return ("Success");
1642225659Shselasky	case LIBUSB_ERROR_IO:
1643225659Shselasky		return ("I/O error");
1644225659Shselasky	case LIBUSB_ERROR_INVALID_PARAM:
1645225659Shselasky		return ("Invalid parameter");
1646225659Shselasky	case LIBUSB_ERROR_ACCESS:
1647225659Shselasky		return ("Permissions error");
1648225659Shselasky	case LIBUSB_ERROR_NO_DEVICE:
1649225659Shselasky		return ("No device");
1650225659Shselasky	case LIBUSB_ERROR_NOT_FOUND:
1651225659Shselasky		return ("Not found");
1652225659Shselasky	case LIBUSB_ERROR_BUSY:
1653225659Shselasky		return ("Device busy");
1654225659Shselasky	case LIBUSB_ERROR_TIMEOUT:
1655225659Shselasky		return ("Timeout");
1656225659Shselasky	case LIBUSB_ERROR_OVERFLOW:
1657225659Shselasky		return ("Overflow");
1658225659Shselasky	case LIBUSB_ERROR_PIPE:
1659225659Shselasky		return ("Pipe error");
1660225659Shselasky	case LIBUSB_ERROR_INTERRUPTED:
1661225659Shselasky		return ("Interrupted");
1662225659Shselasky	case LIBUSB_ERROR_NO_MEM:
1663225659Shselasky		return ("Out of memory");
1664225659Shselasky	case LIBUSB_ERROR_NOT_SUPPORTED:
1665225659Shselasky		return ("Not supported");
1666225659Shselasky	case LIBUSB_ERROR_OTHER:
1667225659Shselasky		return ("Other error");
1668225659Shselasky	default:
1669225659Shselasky		return ("Unknown error");
1670225659Shselasky	}
1671213853Shselasky}
1672225659Shselasky
1673225659Shselaskyconst char *
1674225659Shselaskylibusb_error_name(int code)
1675225659Shselasky{
1676225659Shselasky	switch (code) {
1677225659Shselasky	case LIBUSB_SUCCESS:
1678225659Shselasky		return ("LIBUSB_SUCCESS");
1679225659Shselasky	case LIBUSB_ERROR_IO:
1680225659Shselasky		return ("LIBUSB_ERROR_IO");
1681225659Shselasky	case LIBUSB_ERROR_INVALID_PARAM:
1682225659Shselasky		return ("LIBUSB_ERROR_INVALID_PARAM");
1683225659Shselasky	case LIBUSB_ERROR_ACCESS:
1684225659Shselasky		return ("LIBUSB_ERROR_ACCESS");
1685225659Shselasky	case LIBUSB_ERROR_NO_DEVICE:
1686225659Shselasky		return ("LIBUSB_ERROR_NO_DEVICE");
1687225659Shselasky	case LIBUSB_ERROR_NOT_FOUND:
1688225659Shselasky		return ("LIBUSB_ERROR_NOT_FOUND");
1689225659Shselasky	case LIBUSB_ERROR_BUSY:
1690225659Shselasky		return ("LIBUSB_ERROR_BUSY");
1691225659Shselasky	case LIBUSB_ERROR_TIMEOUT:
1692225659Shselasky		return ("LIBUSB_ERROR_TIMEOUT");
1693225659Shselasky	case LIBUSB_ERROR_OVERFLOW:
1694225659Shselasky		return ("LIBUSB_ERROR_OVERFLOW");
1695225659Shselasky	case LIBUSB_ERROR_PIPE:
1696225659Shselasky		return ("LIBUSB_ERROR_PIPE");
1697225659Shselasky	case LIBUSB_ERROR_INTERRUPTED:
1698225659Shselasky		return ("LIBUSB_ERROR_INTERRUPTED");
1699225659Shselasky	case LIBUSB_ERROR_NO_MEM:
1700225659Shselasky		return ("LIBUSB_ERROR_NO_MEM");
1701225659Shselasky	case LIBUSB_ERROR_NOT_SUPPORTED:
1702225659Shselasky		return ("LIBUSB_ERROR_NOT_SUPPORTED");
1703225659Shselasky	case LIBUSB_ERROR_OTHER:
1704225659Shselasky		return ("LIBUSB_ERROR_OTHER");
1705225659Shselasky	default:
1706225659Shselasky		return ("LIBUSB_ERROR_UNKNOWN");
1707225659Shselasky	}
1708225659Shselasky}
1709362224Skevans
1710362224Skevansint
1711362224Skevanslibusb_has_capability(uint32_t capability)
1712362224Skevans{
1713362224Skevans
1714362224Skevans	switch (capability) {
1715362224Skevans	case LIBUSB_CAP_HAS_CAPABILITY:
1716362224Skevans	case LIBUSB_CAP_HAS_HOTPLUG:
1717362224Skevans	case LIBUSB_CAP_HAS_HID_ACCESS:
1718362224Skevans	case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER:
1719362224Skevans		return (1);
1720362224Skevans	default:
1721362224Skevans		return (0);
1722362224Skevans	}
1723362224Skevans}
1724