libusb20.c revision 203147
1184610Salfred/* $FreeBSD: head/lib/libusb/libusb20.c 203147 2010-01-29 02:44:06Z thompsa $ */
2184610Salfred/*-
3199575Sthompsa * Copyright (c) 2008-2009 Hans Petter Selasky. All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred *
14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24184610Salfred * SUCH DAMAGE.
25184610Salfred */
26184610Salfred
27184610Salfred#include <stdio.h>
28184610Salfred#include <stdlib.h>
29184610Salfred#include <string.h>
30184610Salfred#include <poll.h>
31184610Salfred#include <ctype.h>
32184610Salfred#include <sys/queue.h>
33184610Salfred
34184610Salfred#include "libusb20.h"
35184610Salfred#include "libusb20_desc.h"
36184610Salfred#include "libusb20_int.h"
37184610Salfred
38184610Salfredstatic int
39184610Salfreddummy_int(void)
40184610Salfred{
41184610Salfred	return (LIBUSB20_ERROR_NOT_SUPPORTED);
42184610Salfred}
43184610Salfred
44184610Salfredstatic void
45184610Salfreddummy_void(void)
46184610Salfred{
47184610Salfred	return;
48184610Salfred}
49184610Salfred
50184610Salfredstatic void
51184610Salfreddummy_callback(struct libusb20_transfer *xfer)
52184610Salfred{
53184610Salfred	;				/* style fix */
54184610Salfred	switch (libusb20_tr_get_status(xfer)) {
55184610Salfred	case LIBUSB20_TRANSFER_START:
56184610Salfred		libusb20_tr_submit(xfer);
57184610Salfred		break;
58184610Salfred	default:
59184610Salfred		/* complete or error */
60184610Salfred		break;
61184610Salfred	}
62184610Salfred	return;
63184610Salfred}
64184610Salfred
65184610Salfred#define	dummy_get_config_desc_full (void *)dummy_int
66184610Salfred#define	dummy_get_config_index (void *)dummy_int
67184610Salfred#define	dummy_set_config_index (void *)dummy_int
68184610Salfred#define	dummy_set_alt_index (void *)dummy_int
69184610Salfred#define	dummy_reset_device (void *)dummy_int
70203147Sthompsa#define	dummy_check_connected (void *)dummy_int
71184610Salfred#define	dummy_set_power_mode (void *)dummy_int
72184610Salfred#define	dummy_get_power_mode (void *)dummy_int
73184610Salfred#define	dummy_kernel_driver_active (void *)dummy_int
74184610Salfred#define	dummy_detach_kernel_driver (void *)dummy_int
75184610Salfred#define	dummy_do_request_sync (void *)dummy_int
76184610Salfred#define	dummy_tr_open (void *)dummy_int
77184610Salfred#define	dummy_tr_close (void *)dummy_int
78184610Salfred#define	dummy_tr_clear_stall_sync (void *)dummy_int
79184610Salfred#define	dummy_process (void *)dummy_int
80188622Sthompsa#define	dummy_dev_info (void *)dummy_int
81188622Sthompsa#define	dummy_dev_get_iface_driver (void *)dummy_int
82184610Salfred
83184610Salfred#define	dummy_tr_submit (void *)dummy_void
84184610Salfred#define	dummy_tr_cancel_async (void *)dummy_void
85184610Salfred
86184610Salfredstatic const struct libusb20_device_methods libusb20_dummy_methods = {
87184610Salfred	LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy)
88184610Salfred};
89184610Salfred
90184610Salfredvoid
91184610Salfredlibusb20_tr_callback_wrapper(struct libusb20_transfer *xfer)
92184610Salfred{
93184610Salfred	;				/* style fix */
94184610Salfred
95184610Salfredrepeat:
96184610Salfred
97184610Salfred	if (!xfer->is_pending) {
98184610Salfred		xfer->status = LIBUSB20_TRANSFER_START;
99184610Salfred	} else {
100184610Salfred		xfer->is_pending = 0;
101184610Salfred	}
102184610Salfred
103188622Sthompsa	xfer->callback(xfer);
104184610Salfred
105184610Salfred	if (xfer->is_restart) {
106184610Salfred		xfer->is_restart = 0;
107184610Salfred		goto repeat;
108184610Salfred	}
109184610Salfred	if (xfer->is_draining &&
110184610Salfred	    (!xfer->is_pending)) {
111184610Salfred		xfer->is_draining = 0;
112184610Salfred		xfer->status = LIBUSB20_TRANSFER_DRAINED;
113188622Sthompsa		xfer->callback(xfer);
114184610Salfred	}
115184610Salfred	return;
116184610Salfred}
117184610Salfred
118184610Salfredint
119184610Salfredlibusb20_tr_close(struct libusb20_transfer *xfer)
120184610Salfred{
121184610Salfred	int error;
122184610Salfred
123184610Salfred	if (!xfer->is_opened) {
124184610Salfred		return (LIBUSB20_ERROR_OTHER);
125184610Salfred	}
126188622Sthompsa	error = xfer->pdev->methods->tr_close(xfer);
127184610Salfred
128184610Salfred	if (xfer->pLength) {
129184610Salfred		free(xfer->pLength);
130184610Salfred	}
131184610Salfred	if (xfer->ppBuffer) {
132184610Salfred		free(xfer->ppBuffer);
133184610Salfred	}
134202025Sthompsa	/* reset variable fields in case the transfer is opened again */
135202025Sthompsa	xfer->priv_sc0 = 0;
136202025Sthompsa	xfer->priv_sc1 = 0;
137184610Salfred	xfer->is_opened = 0;
138202025Sthompsa	xfer->is_pending = 0;
139202025Sthompsa	xfer->is_cancel = 0;
140202025Sthompsa	xfer->is_draining = 0;
141202025Sthompsa	xfer->is_restart = 0;
142202025Sthompsa	xfer->status = 0;
143202025Sthompsa	xfer->flags = 0;
144202025Sthompsa	xfer->nFrames = 0;
145202025Sthompsa	xfer->aFrames = 0;
146202025Sthompsa	xfer->timeout = 0;
147184610Salfred	xfer->maxFrames = 0;
148184610Salfred	xfer->maxTotalLength = 0;
149184610Salfred	xfer->maxPacketLen = 0;
150184610Salfred	return (error);
151184610Salfred}
152184610Salfred
153184610Salfredint
154184610Salfredlibusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
155184610Salfred    uint32_t MaxFrameCount, uint8_t ep_no)
156184610Salfred{
157184610Salfred	uint32_t size;
158184610Salfred	int error;
159184610Salfred
160184610Salfred	if (xfer->is_opened) {
161184610Salfred		return (LIBUSB20_ERROR_BUSY);
162184610Salfred	}
163184610Salfred	if (MaxFrameCount == 0) {
164184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
165184610Salfred	}
166184610Salfred	xfer->maxFrames = MaxFrameCount;
167184610Salfred
168184610Salfred	size = MaxFrameCount * sizeof(xfer->pLength[0]);
169184610Salfred	xfer->pLength = malloc(size);
170184610Salfred	if (xfer->pLength == NULL) {
171184610Salfred		return (LIBUSB20_ERROR_NO_MEM);
172184610Salfred	}
173184610Salfred	memset(xfer->pLength, 0, size);
174184610Salfred
175184610Salfred	size = MaxFrameCount * sizeof(xfer->ppBuffer[0]);
176184610Salfred	xfer->ppBuffer = malloc(size);
177184610Salfred	if (xfer->ppBuffer == NULL) {
178184610Salfred		free(xfer->pLength);
179184610Salfred		return (LIBUSB20_ERROR_NO_MEM);
180184610Salfred	}
181184610Salfred	memset(xfer->ppBuffer, 0, size);
182184610Salfred
183188622Sthompsa	error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
184184610Salfred	    MaxFrameCount, ep_no);
185184610Salfred
186184610Salfred	if (error) {
187184610Salfred		free(xfer->ppBuffer);
188184610Salfred		free(xfer->pLength);
189184610Salfred	} else {
190184610Salfred		xfer->is_opened = 1;
191184610Salfred	}
192184610Salfred	return (error);
193184610Salfred}
194184610Salfred
195184610Salfredstruct libusb20_transfer *
196184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex)
197184610Salfred{
198184610Salfred	if (trIndex >= pdev->nTransfer) {
199184610Salfred		return (NULL);
200184610Salfred	}
201184610Salfred	return (pdev->pTransfer + trIndex);
202184610Salfred}
203184610Salfred
204184610Salfreduint32_t
205184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer)
206184610Salfred{
207184610Salfred	return (xfer->aFrames);
208184610Salfred}
209184610Salfred
210184610Salfreduint16_t
211184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer)
212184610Salfred{
213184610Salfred	return (xfer->timeComplete);
214184610Salfred}
215184610Salfred
216184610Salfreduint32_t
217184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer)
218184610Salfred{
219184610Salfred	uint32_t x;
220184610Salfred	uint32_t actlen = 0;
221184610Salfred
222184610Salfred	for (x = 0; x != xfer->aFrames; x++) {
223184610Salfred		actlen += xfer->pLength[x];
224184610Salfred	}
225184610Salfred	return (actlen);
226184610Salfred}
227184610Salfred
228184610Salfreduint32_t
229184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer)
230184610Salfred{
231184610Salfred	return (xfer->maxFrames);
232184610Salfred}
233184610Salfred
234184610Salfreduint32_t
235184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer)
236184610Salfred{
237184610Salfred	/*
238184610Salfred	 * Special Case NOTE: If the packet multiplier is non-zero for
239184610Salfred	 * High Speed USB, the value returned is equal to
240184610Salfred	 * "wMaxPacketSize * multiplier" !
241184610Salfred	 */
242184610Salfred	return (xfer->maxPacketLen);
243184610Salfred}
244184610Salfred
245184610Salfreduint32_t
246184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer)
247184610Salfred{
248184610Salfred	return (xfer->maxTotalLength);
249184610Salfred}
250184610Salfred
251184610Salfreduint8_t
252184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer)
253184610Salfred{
254184610Salfred	return (xfer->status);
255184610Salfred}
256184610Salfred
257184610Salfreduint8_t
258184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer)
259184610Salfred{
260184610Salfred	return (xfer->is_pending);
261184610Salfred}
262184610Salfred
263184610Salfredvoid   *
264184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer)
265184610Salfred{
266184610Salfred	return (xfer->priv_sc0);
267184610Salfred}
268184610Salfred
269184610Salfredvoid   *
270184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer)
271184610Salfred{
272184610Salfred	return (xfer->priv_sc1);
273184610Salfred}
274184610Salfred
275184610Salfredvoid
276184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer)
277184610Salfred{
278199575Sthompsa	if (!xfer->is_opened) {
279199575Sthompsa		/* transfer is not opened */
280199575Sthompsa		return;
281199575Sthompsa	}
282184610Salfred	if (!xfer->is_pending) {
283184610Salfred		/* transfer not pending */
284184610Salfred		return;
285184610Salfred	}
286184610Salfred	if (xfer->is_cancel) {
287184610Salfred		/* already cancelling */
288184610Salfred		return;
289184610Salfred	}
290184610Salfred	xfer->is_cancel = 1;		/* we are cancelling */
291184610Salfred
292188622Sthompsa	xfer->pdev->methods->tr_cancel_async(xfer);
293184610Salfred	return;
294184610Salfred}
295184610Salfred
296184610Salfredvoid
297184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer)
298184610Salfred{
299199575Sthompsa	if (!xfer->is_opened) {
300199575Sthompsa		/* transfer is not opened */
301199575Sthompsa		return;
302199575Sthompsa	}
303184610Salfred	/* make sure that we are cancelling */
304184610Salfred	libusb20_tr_stop(xfer);
305184610Salfred
306184610Salfred	if (xfer->is_pending) {
307184610Salfred		xfer->is_draining = 1;
308184610Salfred	}
309184610Salfred	return;
310184610Salfred}
311184610Salfred
312184610Salfredvoid
313184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
314184610Salfred{
315188622Sthompsa	xfer->pdev->methods->tr_clear_stall_sync(xfer);
316184610Salfred	return;
317184610Salfred}
318184610Salfred
319184610Salfredvoid
320184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex)
321184610Salfred{
322184610Salfred	xfer->ppBuffer[frIndex] = buffer;
323184610Salfred	return;
324184610Salfred}
325184610Salfred
326184610Salfredvoid
327184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb)
328184610Salfred{
329184610Salfred	xfer->callback = cb;
330184610Salfred	return;
331184610Salfred}
332184610Salfred
333184610Salfredvoid
334184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags)
335184610Salfred{
336184610Salfred	xfer->flags = flags;
337184610Salfred	return;
338184610Salfred}
339184610Salfred
340193313Sthompsauint32_t
341193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex)
342193313Sthompsa{
343193313Sthompsa	return (xfer->pLength[frIndex]);
344193313Sthompsa}
345193313Sthompsa
346184610Salfredvoid
347184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
348184610Salfred{
349184610Salfred	xfer->pLength[frIndex] = length;
350184610Salfred	return;
351184610Salfred}
352184610Salfred
353184610Salfredvoid
354184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
355184610Salfred{
356184610Salfred	xfer->priv_sc0 = sc0;
357184610Salfred	return;
358184610Salfred}
359184610Salfred
360184610Salfredvoid
361184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
362184610Salfred{
363184610Salfred	xfer->priv_sc1 = sc1;
364184610Salfred	return;
365184610Salfred}
366184610Salfred
367184610Salfredvoid
368184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
369184610Salfred{
370184610Salfred	xfer->timeout = timeout;
371184610Salfred	return;
372184610Salfred}
373184610Salfred
374184610Salfredvoid
375184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
376184610Salfred{
377184610Salfred	if (nFrames > xfer->maxFrames) {
378184610Salfred		/* should not happen */
379184610Salfred		nFrames = xfer->maxFrames;
380184610Salfred	}
381184610Salfred	xfer->nFrames = nFrames;
382184610Salfred	return;
383184610Salfred}
384184610Salfred
385184610Salfredvoid
386184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
387184610Salfred{
388184610Salfred	xfer->ppBuffer[0] = pBuf;
389184610Salfred	xfer->pLength[0] = length;
390184610Salfred	xfer->timeout = timeout;
391184610Salfred	xfer->nFrames = 1;
392184610Salfred	return;
393184610Salfred}
394184610Salfred
395184610Salfredvoid
396184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
397184610Salfred{
398184610Salfred	uint16_t len;
399184610Salfred
400184610Salfred	xfer->ppBuffer[0] = psetup;
401184610Salfred	xfer->pLength[0] = 8;		/* fixed */
402184610Salfred	xfer->timeout = timeout;
403184610Salfred
404184610Salfred	len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
405184610Salfred
406184610Salfred	if (len != 0) {
407184610Salfred		xfer->nFrames = 2;
408184610Salfred		xfer->ppBuffer[1] = pBuf;
409184610Salfred		xfer->pLength[1] = len;
410184610Salfred	} else {
411184610Salfred		xfer->nFrames = 1;
412184610Salfred	}
413184610Salfred	return;
414184610Salfred}
415184610Salfred
416184610Salfredvoid
417184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
418184610Salfred{
419184610Salfred	xfer->ppBuffer[0] = pBuf;
420184610Salfred	xfer->pLength[0] = length;
421184610Salfred	xfer->timeout = timeout;
422184610Salfred	xfer->nFrames = 1;
423184610Salfred	return;
424184610Salfred}
425184610Salfred
426184610Salfredvoid
427184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
428184610Salfred{
429184610Salfred	if (frIndex >= xfer->maxFrames) {
430184610Salfred		/* should not happen */
431184610Salfred		return;
432184610Salfred	}
433184610Salfred	xfer->ppBuffer[frIndex] = pBuf;
434184610Salfred	xfer->pLength[frIndex] = length;
435184610Salfred	return;
436184610Salfred}
437184610Salfred
438199575Sthompsauint8_t
439199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer,
440199575Sthompsa    void *pbuf, uint32_t length, uint32_t *pactlen,
441199575Sthompsa    uint32_t timeout)
442199575Sthompsa{
443199575Sthompsa	struct libusb20_device *pdev = xfer->pdev;
444199575Sthompsa	uint32_t transfer_max;
445199575Sthompsa	uint32_t transfer_act;
446199575Sthompsa	uint8_t retval;
447199575Sthompsa
448199575Sthompsa	/* set some sensible default value */
449199575Sthompsa	if (pactlen != NULL)
450199575Sthompsa		*pactlen = 0;
451199575Sthompsa
452199575Sthompsa	/* check for error condition */
453199575Sthompsa	if (libusb20_tr_pending(xfer))
454199575Sthompsa		return (LIBUSB20_ERROR_OTHER);
455199575Sthompsa
456199575Sthompsa	do {
457199575Sthompsa		/* compute maximum transfer length */
458199575Sthompsa		transfer_max =
459199575Sthompsa		    libusb20_tr_get_max_total_length(xfer);
460199575Sthompsa
461199575Sthompsa		if (transfer_max > length)
462199575Sthompsa			transfer_max = length;
463199575Sthompsa
464199575Sthompsa		/* setup bulk or interrupt transfer */
465199575Sthompsa		libusb20_tr_setup_bulk(xfer, pbuf,
466199575Sthompsa		    transfer_max, timeout);
467199575Sthompsa
468199575Sthompsa		/* start the transfer */
469199575Sthompsa		libusb20_tr_start(xfer);
470199575Sthompsa
471199575Sthompsa		/* wait for transfer completion */
472199575Sthompsa		while (libusb20_dev_process(pdev) == 0) {
473199575Sthompsa
474199575Sthompsa			if (libusb20_tr_pending(xfer) == 0)
475199575Sthompsa				break;
476199575Sthompsa
477199575Sthompsa			libusb20_dev_wait_process(pdev, -1);
478199575Sthompsa		}
479199575Sthompsa
480199575Sthompsa		transfer_act = libusb20_tr_get_actual_length(xfer);
481199575Sthompsa
482199575Sthompsa		/* update actual length, if any */
483199575Sthompsa		if (pactlen != NULL)
484199575Sthompsa			pactlen[0] += transfer_act;
485199575Sthompsa
486199575Sthompsa		/* check transfer status */
487199575Sthompsa		retval = libusb20_tr_get_status(xfer);
488199575Sthompsa		if (retval)
489199575Sthompsa			break;
490199575Sthompsa
491199575Sthompsa		/* check for short transfer */
492199575Sthompsa		if (transfer_act != transfer_max)
493199575Sthompsa			break;
494199575Sthompsa
495199575Sthompsa		/* update buffer pointer and length */
496199575Sthompsa		pbuf = ((uint8_t *)pbuf) + transfer_max;
497199575Sthompsa		length = length - transfer_max;
498199575Sthompsa
499199575Sthompsa	} while (length != 0);
500199575Sthompsa
501199575Sthompsa	return (retval);
502199575Sthompsa}
503199575Sthompsa
504184610Salfredvoid
505184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer)
506184610Salfred{
507199575Sthompsa	if (!xfer->is_opened) {
508199575Sthompsa		/* transfer is not opened */
509199575Sthompsa		return;
510199575Sthompsa	}
511184610Salfred	if (xfer->is_pending) {
512184610Salfred		/* should not happen */
513184610Salfred		return;
514184610Salfred	}
515184610Salfred	xfer->is_pending = 1;		/* we are pending */
516184610Salfred	xfer->is_cancel = 0;		/* not cancelling */
517184610Salfred	xfer->is_restart = 0;		/* not restarting */
518184610Salfred
519188622Sthompsa	xfer->pdev->methods->tr_submit(xfer);
520184610Salfred	return;
521184610Salfred}
522184610Salfred
523184610Salfredvoid
524184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer)
525184610Salfred{
526199575Sthompsa	if (!xfer->is_opened) {
527199575Sthompsa		/* transfer is not opened */
528199575Sthompsa		return;
529199575Sthompsa	}
530184610Salfred	if (xfer->is_pending) {
531184610Salfred		if (xfer->is_cancel) {
532184610Salfred			/* cancelling - restart */
533184610Salfred			xfer->is_restart = 1;
534184610Salfred		}
535184610Salfred		/* transfer not pending */
536184610Salfred		return;
537184610Salfred	}
538184610Salfred	/* get into the callback */
539184610Salfred	libusb20_tr_callback_wrapper(xfer);
540184610Salfred	return;
541184610Salfred}
542184610Salfred
543184610Salfred/* USB device operations */
544184610Salfred
545184610Salfredint
546184610Salfredlibusb20_dev_close(struct libusb20_device *pdev)
547184610Salfred{
548184610Salfred	struct libusb20_transfer *xfer;
549184610Salfred	uint16_t x;
550184610Salfred	int error = 0;
551184610Salfred
552184610Salfred	if (!pdev->is_opened) {
553184610Salfred		return (LIBUSB20_ERROR_OTHER);
554184610Salfred	}
555184610Salfred	for (x = 0; x != pdev->nTransfer; x++) {
556184610Salfred		xfer = pdev->pTransfer + x;
557184610Salfred
558199575Sthompsa		if (!xfer->is_opened) {
559199575Sthompsa			/* transfer is not opened */
560199575Sthompsa			continue;
561199575Sthompsa		}
562199575Sthompsa
563184610Salfred		libusb20_tr_drain(xfer);
564199575Sthompsa
565199575Sthompsa		libusb20_tr_close(xfer);
566184610Salfred	}
567184610Salfred
568184610Salfred	if (pdev->pTransfer != NULL) {
569184610Salfred		free(pdev->pTransfer);
570184610Salfred		pdev->pTransfer = NULL;
571184610Salfred	}
572188622Sthompsa	error = pdev->beMethods->close_device(pdev);
573184610Salfred
574184610Salfred	pdev->methods = &libusb20_dummy_methods;
575184610Salfred
576184610Salfred	pdev->is_opened = 0;
577184610Salfred
578194069Sthompsa	/*
579194069Sthompsa	 * The following variable is only used by the libusb v0.1
580194069Sthompsa	 * compat layer:
581194069Sthompsa	 */
582194069Sthompsa	pdev->claimed_interface = 0;
583187184Sthompsa
584184610Salfred	return (error);
585184610Salfred}
586184610Salfred
587184610Salfredint
588184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
589184610Salfred{
590184610Salfred	int error;
591184610Salfred
592188622Sthompsa	error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
593184610Salfred	return (error);
594184610Salfred}
595184610Salfred
596184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED *
597184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev)
598184610Salfred{
599184610Salfred	return (&(pdev->ddesc));
600184610Salfred}
601184610Salfred
602184610Salfredint
603184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev)
604184610Salfred{
605184610Salfred	return (pdev->file);
606184610Salfred}
607184610Salfred
608184610Salfredint
609184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
610184610Salfred{
611184610Salfred	int error;
612184610Salfred
613188622Sthompsa	error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
614184610Salfred	return (error);
615184610Salfred}
616184610Salfred
617184610Salfredint
618184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
619184610Salfred{
620184610Salfred	struct libusb20_transfer *xfer;
621184610Salfred	uint32_t size;
622184610Salfred	uint16_t x;
623184610Salfred	int error;
624184610Salfred
625184610Salfred	if (pdev->is_opened) {
626184610Salfred		return (LIBUSB20_ERROR_BUSY);
627184610Salfred	}
628184610Salfred	if (nTransferMax >= 256) {
629184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
630184610Salfred	} else if (nTransferMax != 0) {
631184610Salfred		size = sizeof(pdev->pTransfer[0]) * nTransferMax;
632184610Salfred		pdev->pTransfer = malloc(size);
633184610Salfred		if (pdev->pTransfer == NULL) {
634184610Salfred			return (LIBUSB20_ERROR_NO_MEM);
635184610Salfred		}
636184610Salfred		memset(pdev->pTransfer, 0, size);
637184610Salfred	}
638184610Salfred	/* initialise all transfers */
639184610Salfred	for (x = 0; x != nTransferMax; x++) {
640184610Salfred
641184610Salfred		xfer = pdev->pTransfer + x;
642184610Salfred
643184610Salfred		xfer->pdev = pdev;
644184610Salfred		xfer->trIndex = x;
645184610Salfred		xfer->callback = &dummy_callback;
646184610Salfred	}
647184610Salfred
648185087Salfred	/* set "nTransfer" early */
649185087Salfred	pdev->nTransfer = nTransferMax;
650185087Salfred
651188622Sthompsa	error = pdev->beMethods->open_device(pdev, nTransferMax);
652184610Salfred
653184610Salfred	if (error) {
654184610Salfred		if (pdev->pTransfer != NULL) {
655184610Salfred			free(pdev->pTransfer);
656184610Salfred			pdev->pTransfer = NULL;
657184610Salfred		}
658184610Salfred		pdev->file = -1;
659184610Salfred		pdev->file_ctrl = -1;
660184610Salfred		pdev->nTransfer = 0;
661184610Salfred	} else {
662184610Salfred		pdev->is_opened = 1;
663184610Salfred	}
664184610Salfred	return (error);
665184610Salfred}
666184610Salfred
667184610Salfredint
668184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev)
669184610Salfred{
670184610Salfred	int error;
671184610Salfred
672188622Sthompsa	error = pdev->methods->reset_device(pdev);
673184610Salfred	return (error);
674184610Salfred}
675184610Salfred
676184610Salfredint
677203147Sthompsalibusb20_dev_check_connected(struct libusb20_device *pdev)
678203147Sthompsa{
679203147Sthompsa	int error;
680203147Sthompsa
681203147Sthompsa	error = pdev->methods->check_connected(pdev);
682203147Sthompsa	return (error);
683203147Sthompsa}
684203147Sthompsa
685203147Sthompsaint
686184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
687184610Salfred{
688184610Salfred	int error;
689184610Salfred
690188622Sthompsa	error = pdev->methods->set_power_mode(pdev, power_mode);
691184610Salfred	return (error);
692184610Salfred}
693184610Salfred
694184610Salfreduint8_t
695184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev)
696184610Salfred{
697184610Salfred	int error;
698184610Salfred	uint8_t power_mode;
699184610Salfred
700188622Sthompsa	error = pdev->methods->get_power_mode(pdev, &power_mode);
701184610Salfred	if (error)
702184610Salfred		power_mode = LIBUSB20_POWER_ON;	/* fake power mode */
703184610Salfred	return (power_mode);
704184610Salfred}
705184610Salfred
706184610Salfredint
707184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
708184610Salfred{
709184610Salfred	int error;
710184610Salfred
711188622Sthompsa	error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
712184610Salfred	return (error);
713184610Salfred}
714184610Salfred
715184610Salfredint
716184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
717184610Salfred{
718184610Salfred	int error;
719184610Salfred
720188622Sthompsa	error = pdev->methods->set_config_index(pdev, configIndex);
721184610Salfred	return (error);
722184610Salfred}
723184610Salfred
724184610Salfredint
725184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev,
726184610Salfred    struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
727184610Salfred    uint16_t *pactlen, uint32_t timeout, uint8_t flags)
728184610Salfred{
729184610Salfred	int error;
730184610Salfred
731188622Sthompsa	error = pdev->methods->do_request_sync(pdev,
732184610Salfred	    setup, data, pactlen, timeout, flags);
733184610Salfred	return (error);
734184610Salfred}
735184610Salfred
736184610Salfredint
737184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev,
738185087Salfred    uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
739184610Salfred{
740184610Salfred	struct LIBUSB20_CONTROL_SETUP_DECODED req;
741184610Salfred	int error;
742184610Salfred
743199055Sthompsa	/* make sure memory is initialised */
744199055Sthompsa	memset(ptr, 0, len);
745199055Sthompsa
746184610Salfred	if (len < 4) {
747184610Salfred		/* invalid length */
748184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
749184610Salfred	}
750184610Salfred	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
751184610Salfred
752184610Salfred	/*
753184610Salfred	 * We need to read the USB string in two steps else some USB
754184610Salfred	 * devices will complain.
755184610Salfred	 */
756184610Salfred	req.bmRequestType =
757184610Salfred	    LIBUSB20_REQUEST_TYPE_STANDARD |
758184610Salfred	    LIBUSB20_RECIPIENT_DEVICE |
759184610Salfred	    LIBUSB20_ENDPOINT_IN;
760184610Salfred	req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
761185087Salfred	req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
762184610Salfred	req.wIndex = langid;
763184610Salfred	req.wLength = 4;		/* bytes */
764184610Salfred
765184610Salfred	error = libusb20_dev_request_sync(pdev, &req,
766184610Salfred	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
767184610Salfred	if (error) {
768184610Salfred		return (error);
769184610Salfred	}
770184610Salfred	req.wLength = *(uint8_t *)ptr;	/* bytes */
771184610Salfred	if (req.wLength > len) {
772184610Salfred		/* partial string read */
773184610Salfred		req.wLength = len;
774184610Salfred	}
775184610Salfred	error = libusb20_dev_request_sync(pdev, &req,
776184610Salfred	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
777184610Salfred
778184610Salfred	if (error) {
779184610Salfred		return (error);
780184610Salfred	}
781184610Salfred	if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
782184610Salfred		return (LIBUSB20_ERROR_OTHER);
783184610Salfred	}
784184610Salfred	return (0);			/* success */
785184610Salfred}
786184610Salfred
787184610Salfredint
788184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
789185087Salfred    uint8_t str_index, void *ptr, uint16_t len)
790184610Salfred{
791184610Salfred	char *buf;
792184610Salfred	int error;
793184610Salfred	uint16_t langid;
794184610Salfred	uint16_t n;
795184610Salfred	uint16_t i;
796184610Salfred	uint16_t c;
797184610Salfred	uint8_t temp[255];
798184610Salfred	uint8_t swap;
799184610Salfred
800184610Salfred	/* the following code derives from the FreeBSD USB kernel */
801184610Salfred
802184610Salfred	if ((len < 1) || (ptr == NULL)) {
803184610Salfred		/* too short buffer */
804184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
805184610Salfred	}
806184610Salfred	error = libusb20_dev_req_string_sync(pdev,
807184610Salfred	    0, 0, temp, sizeof(temp));
808185087Salfred	if (error < 0) {
809185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
810184610Salfred		return (error);
811185087Salfred	}
812184610Salfred	langid = temp[2] | (temp[3] << 8);
813184610Salfred
814185087Salfred	error = libusb20_dev_req_string_sync(pdev, str_index,
815184610Salfred	    langid, temp, sizeof(temp));
816185087Salfred	if (error < 0) {
817185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
818184610Salfred		return (error);
819185087Salfred	}
820184610Salfred	if (temp[0] < 2) {
821184610Salfred		/* string length is too short */
822185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
823184610Salfred		return (LIBUSB20_ERROR_OTHER);
824184610Salfred	}
825184610Salfred	/* reserve one byte for terminating zero */
826184610Salfred	len--;
827184610Salfred
828184610Salfred	/* find maximum length */
829184610Salfred	n = (temp[0] / 2) - 1;
830184610Salfred	if (n > len) {
831184610Salfred		n = len;
832184610Salfred	}
833184610Salfred	/* reset swap state */
834184610Salfred	swap = 3;
835184610Salfred
836184610Salfred	/* setup output buffer pointer */
837184610Salfred	buf = ptr;
838184610Salfred
839184610Salfred	/* convert and filter */
840184610Salfred	for (i = 0; (i != n); i++) {
841184610Salfred		c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
842184610Salfred
843184610Salfred		/* convert from Unicode, handle buggy strings */
844184610Salfred		if (((c & 0xff00) == 0) && (swap & 1)) {
845184610Salfred			/* Little Endian, default */
846184610Salfred			*buf = c;
847184610Salfred			swap = 1;
848184610Salfred		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
849184610Salfred			/* Big Endian */
850184610Salfred			*buf = c >> 8;
851184610Salfred			swap = 2;
852184610Salfred		} else {
853185087Salfred			/* skip invalid character */
854185087Salfred			continue;
855184610Salfred		}
856184610Salfred		/*
857184610Salfred		 * Filter by default - we don't allow greater and less than
858184610Salfred		 * signs because they might confuse the dmesg printouts!
859184610Salfred		 */
860184610Salfred		if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
861185087Salfred			/* skip invalid character */
862185087Salfred			continue;
863184610Salfred		}
864184610Salfred		buf++;
865184610Salfred	}
866184610Salfred	*buf = 0;			/* zero terminate string */
867184610Salfred
868184610Salfred	return (0);
869184610Salfred}
870184610Salfred
871184610Salfredstruct libusb20_config *
872184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
873184610Salfred{
874184610Salfred	struct libusb20_config *retval = NULL;
875184610Salfred	uint8_t *ptr;
876184610Salfred	uint16_t len;
877184610Salfred	uint8_t do_close;
878184610Salfred	int error;
879184610Salfred
880184610Salfred	if (!pdev->is_opened) {
881184610Salfred		error = libusb20_dev_open(pdev, 0);
882184610Salfred		if (error) {
883184610Salfred			return (NULL);
884184610Salfred		}
885184610Salfred		do_close = 1;
886184610Salfred	} else {
887184610Salfred		do_close = 0;
888184610Salfred	}
889188622Sthompsa	error = pdev->methods->get_config_desc_full(pdev,
890184610Salfred	    &ptr, &len, configIndex);
891184610Salfred
892184610Salfred	if (error) {
893184610Salfred		goto done;
894184610Salfred	}
895184610Salfred	/* parse new config descriptor */
896184610Salfred	retval = libusb20_parse_config_desc(ptr);
897184610Salfred
898184610Salfred	/* free config descriptor */
899184610Salfred	free(ptr);
900184610Salfred
901184610Salfreddone:
902184610Salfred	if (do_close) {
903184610Salfred		error = libusb20_dev_close(pdev);
904184610Salfred	}
905184610Salfred	return (retval);
906184610Salfred}
907184610Salfred
908184610Salfredstruct libusb20_device *
909184610Salfredlibusb20_dev_alloc(void)
910184610Salfred{
911184610Salfred	struct libusb20_device *pdev;
912184610Salfred
913184610Salfred	pdev = malloc(sizeof(*pdev));
914184610Salfred	if (pdev == NULL) {
915184610Salfred		return (NULL);
916184610Salfred	}
917184610Salfred	memset(pdev, 0, sizeof(*pdev));
918184610Salfred
919184610Salfred	pdev->file = -1;
920184610Salfred	pdev->file_ctrl = -1;
921184610Salfred	pdev->methods = &libusb20_dummy_methods;
922184610Salfred	return (pdev);
923184610Salfred}
924184610Salfred
925184610Salfreduint8_t
926184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev)
927184610Salfred{
928184610Salfred	int error;
929185087Salfred	uint8_t cfg_index;
930184610Salfred	uint8_t do_close;
931184610Salfred
932184610Salfred	if (!pdev->is_opened) {
933184610Salfred		error = libusb20_dev_open(pdev, 0);
934184610Salfred		if (error == 0) {
935184610Salfred			do_close = 1;
936184610Salfred		} else {
937184610Salfred			do_close = 0;
938184610Salfred		}
939184610Salfred	} else {
940184610Salfred		do_close = 0;
941184610Salfred	}
942184610Salfred
943188622Sthompsa	error = pdev->methods->get_config_index(pdev, &cfg_index);
944184610Salfred	if (error) {
945185087Salfred		cfg_index = 0 - 1;	/* current config index */
946184610Salfred	}
947184610Salfred	if (do_close) {
948184610Salfred		if (libusb20_dev_close(pdev)) {
949184610Salfred			/* ignore */
950184610Salfred		}
951184610Salfred	}
952185087Salfred	return (cfg_index);
953184610Salfred}
954184610Salfred
955184610Salfreduint8_t
956184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev)
957184610Salfred{
958184610Salfred	return (pdev->usb_mode);
959184610Salfred}
960184610Salfred
961184610Salfreduint8_t
962184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev)
963184610Salfred{
964184610Salfred	return (pdev->usb_speed);
965184610Salfred}
966184610Salfred
967184610Salfred/* if this function returns an error, the device is gone */
968184610Salfredint
969184610Salfredlibusb20_dev_process(struct libusb20_device *pdev)
970184610Salfred{
971184610Salfred	int error;
972184610Salfred
973188622Sthompsa	error = pdev->methods->process(pdev);
974184610Salfred	return (error);
975184610Salfred}
976184610Salfred
977184610Salfredvoid
978184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
979184610Salfred{
980185087Salfred	struct pollfd pfd[1];
981184610Salfred
982184610Salfred	if (!pdev->is_opened) {
983184610Salfred		return;
984184610Salfred	}
985184610Salfred	pfd[0].fd = pdev->file;
986184610Salfred	pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
987184610Salfred	pfd[0].revents = 0;
988184610Salfred
989185087Salfred	if (poll(pfd, 1, timeout)) {
990184610Salfred		/* ignore any error */
991184610Salfred	}
992184610Salfred	return;
993184610Salfred}
994184610Salfred
995184610Salfredvoid
996184610Salfredlibusb20_dev_free(struct libusb20_device *pdev)
997184610Salfred{
998184610Salfred	if (pdev == NULL) {
999184610Salfred		/* be NULL safe */
1000184610Salfred		return;
1001184610Salfred	}
1002184610Salfred	if (pdev->is_opened) {
1003184610Salfred		if (libusb20_dev_close(pdev)) {
1004184610Salfred			/* ignore any errors */
1005184610Salfred		}
1006184610Salfred	}
1007184610Salfred	free(pdev);
1008184610Salfred	return;
1009184610Salfred}
1010184610Salfred
1011188622Sthompsaint
1012188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev,
1013192984Sthompsa    struct usb_device_info *pinfo)
1014188622Sthompsa{
1015188622Sthompsa	if (pinfo == NULL)
1016188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
1017188622Sthompsa
1018188622Sthompsa	return (pdev->beMethods->dev_get_info(pdev, pinfo));
1019188622Sthompsa}
1020188622Sthompsa
1021184610Salfredconst char *
1022184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev)
1023184610Salfred{
1024188622Sthompsa	return (pdev->beMethods->get_backend_name());
1025184610Salfred}
1026184610Salfred
1027184610Salfredconst char *
1028184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev)
1029184610Salfred{
1030184610Salfred	return (pdev->usb_desc);
1031184610Salfred}
1032184610Salfred
1033184610Salfredvoid
1034184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
1035184610Salfred{
1036184610Salfred	pdev->debug = debug;
1037184610Salfred	return;
1038184610Salfred}
1039184610Salfred
1040184610Salfredint
1041184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev)
1042184610Salfred{
1043184610Salfred	return (pdev->debug);
1044184610Salfred}
1045184610Salfred
1046184610Salfreduint8_t
1047184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev)
1048184610Salfred{
1049184610Salfred	return (pdev->device_address);
1050184610Salfred}
1051184610Salfred
1052184610Salfreduint8_t
1053184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev)
1054184610Salfred{
1055184610Salfred	return (pdev->bus_number);
1056184610Salfred}
1057184610Salfred
1058184610Salfredint
1059188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev,
1060188622Sthompsa    uint8_t iface_index, char *buf, uint8_t len)
1061188622Sthompsa{
1062188622Sthompsa	if ((buf == NULL) || (len == 0))
1063188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
1064188622Sthompsa
1065188622Sthompsa	return (pdev->beMethods->dev_get_iface_desc(
1066188622Sthompsa	    pdev, iface_index, buf, len));
1067188622Sthompsa}
1068188622Sthompsa
1069184610Salfred/* USB backend operations */
1070184610Salfred
1071184610Salfredint
1072184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
1073185087Salfred    uint16_t quirk_index, struct libusb20_quirk *pq)
1074184610Salfred{
1075188622Sthompsa	return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
1076184610Salfred}
1077184610Salfred
1078184610Salfredint
1079184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe,
1080185087Salfred    uint16_t quirk_index, struct libusb20_quirk *pq)
1081184610Salfred{
1082188622Sthompsa	return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
1083184610Salfred}
1084184610Salfred
1085184610Salfredint
1086184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
1087184610Salfred    struct libusb20_quirk *pq)
1088184610Salfred{
1089188622Sthompsa	return (pbe->methods->root_add_dev_quirk(pbe, pq));
1090184610Salfred}
1091184610Salfred
1092184610Salfredint
1093184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
1094184610Salfred    struct libusb20_quirk *pq)
1095184610Salfred{
1096188622Sthompsa	return (pbe->methods->root_remove_dev_quirk(pbe, pq));
1097184610Salfred}
1098184610Salfred
1099184610Salfredint
1100188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp)
1101188987Sthompsa{
1102188987Sthompsa	return (pbe->methods->root_set_template(pbe, temp));
1103188987Sthompsa}
1104188987Sthompsa
1105188987Sthompsaint
1106188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
1107188987Sthompsa{
1108188987Sthompsa	int temp;
1109188987Sthompsa
1110188987Sthompsa	if (ptemp == NULL)
1111188987Sthompsa		ptemp = &temp;
1112188987Sthompsa
1113188987Sthompsa	return (pbe->methods->root_get_template(pbe, ptemp));
1114188987Sthompsa}
1115188987Sthompsa
1116184610Salfredstruct libusb20_device *
1117184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1118184610Salfred{
1119184610Salfred	if (pbe == NULL) {
1120184610Salfred		pdev = NULL;
1121184610Salfred	} else if (pdev == NULL) {
1122184610Salfred		pdev = TAILQ_FIRST(&(pbe->usb_devs));
1123184610Salfred	} else {
1124184610Salfred		pdev = TAILQ_NEXT(pdev, dev_entry);
1125184610Salfred	}
1126184610Salfred	return (pdev);
1127184610Salfred}
1128184610Salfred
1129184610Salfredstruct libusb20_backend *
1130184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods)
1131184610Salfred{
1132184610Salfred	struct libusb20_backend *pbe;
1133184610Salfred
1134184610Salfred	pbe = malloc(sizeof(*pbe));
1135184610Salfred	if (pbe == NULL) {
1136184610Salfred		return (NULL);
1137184610Salfred	}
1138184610Salfred	memset(pbe, 0, sizeof(*pbe));
1139184610Salfred
1140184610Salfred	TAILQ_INIT(&(pbe->usb_devs));
1141184610Salfred
1142184610Salfred	pbe->methods = methods;		/* set backend methods */
1143184610Salfred
1144184610Salfred	/* do the initial device scan */
1145184610Salfred	if (pbe->methods->init_backend) {
1146188622Sthompsa		pbe->methods->init_backend(pbe);
1147184610Salfred	}
1148184610Salfred	return (pbe);
1149184610Salfred}
1150184610Salfred
1151184610Salfredstruct libusb20_backend *
1152184610Salfredlibusb20_be_alloc_linux(void)
1153184610Salfred{
1154184610Salfred	struct libusb20_backend *pbe;
1155184610Salfred
1156184610Salfred#ifdef __linux__
1157184610Salfred	pbe = libusb20_be_alloc(&libusb20_linux_backend);
1158184610Salfred#else
1159184610Salfred	pbe = NULL;
1160184610Salfred#endif
1161184610Salfred	return (pbe);
1162184610Salfred}
1163184610Salfred
1164184610Salfredstruct libusb20_backend *
1165184610Salfredlibusb20_be_alloc_ugen20(void)
1166184610Salfred{
1167184610Salfred	struct libusb20_backend *pbe;
1168184610Salfred
1169184610Salfred#ifdef __FreeBSD__
1170184610Salfred	pbe = libusb20_be_alloc(&libusb20_ugen20_backend);
1171184610Salfred#else
1172184610Salfred	pbe = NULL;
1173184610Salfred#endif
1174184610Salfred	return (pbe);
1175184610Salfred}
1176184610Salfred
1177184610Salfredstruct libusb20_backend *
1178184610Salfredlibusb20_be_alloc_default(void)
1179184610Salfred{
1180184610Salfred	struct libusb20_backend *pbe;
1181184610Salfred
1182184610Salfred	pbe = libusb20_be_alloc_linux();
1183184610Salfred	if (pbe) {
1184184610Salfred		return (pbe);
1185184610Salfred	}
1186184610Salfred	pbe = libusb20_be_alloc_ugen20();
1187184610Salfred	if (pbe) {
1188184610Salfred		return (pbe);
1189184610Salfred	}
1190184610Salfred	return (NULL);			/* no backend found */
1191184610Salfred}
1192184610Salfred
1193184610Salfredvoid
1194184610Salfredlibusb20_be_free(struct libusb20_backend *pbe)
1195184610Salfred{
1196184610Salfred	struct libusb20_device *pdev;
1197184610Salfred
1198184610Salfred	if (pbe == NULL) {
1199184610Salfred		/* be NULL safe */
1200184610Salfred		return;
1201184610Salfred	}
1202184610Salfred	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1203184610Salfred		libusb20_be_dequeue_device(pbe, pdev);
1204184610Salfred		libusb20_dev_free(pdev);
1205184610Salfred	}
1206184610Salfred	if (pbe->methods->exit_backend) {
1207188622Sthompsa		pbe->methods->exit_backend(pbe);
1208184610Salfred	}
1209199055Sthompsa	/* free backend */
1210199055Sthompsa	free(pbe);
1211184610Salfred}
1212184610Salfred
1213184610Salfredvoid
1214184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1215184610Salfred{
1216184610Salfred	pdev->beMethods = pbe->methods;	/* copy backend methods */
1217184610Salfred	TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1218184610Salfred}
1219184610Salfred
1220184610Salfredvoid
1221184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe,
1222184610Salfred    struct libusb20_device *pdev)
1223184610Salfred{
1224184610Salfred	TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
1225184610Salfred}
1226