libusb20.c revision 202025
1184610Salfred/* $FreeBSD: head/lib/libusb/libusb20.c 202025 2010-01-10 19:18:49Z 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
70184610Salfred#define	dummy_set_power_mode (void *)dummy_int
71184610Salfred#define	dummy_get_power_mode (void *)dummy_int
72184610Salfred#define	dummy_kernel_driver_active (void *)dummy_int
73184610Salfred#define	dummy_detach_kernel_driver (void *)dummy_int
74184610Salfred#define	dummy_do_request_sync (void *)dummy_int
75184610Salfred#define	dummy_tr_open (void *)dummy_int
76184610Salfred#define	dummy_tr_close (void *)dummy_int
77184610Salfred#define	dummy_tr_clear_stall_sync (void *)dummy_int
78184610Salfred#define	dummy_process (void *)dummy_int
79188622Sthompsa#define	dummy_dev_info (void *)dummy_int
80188622Sthompsa#define	dummy_dev_get_iface_driver (void *)dummy_int
81184610Salfred
82184610Salfred#define	dummy_tr_submit (void *)dummy_void
83184610Salfred#define	dummy_tr_cancel_async (void *)dummy_void
84184610Salfred
85184610Salfredstatic const struct libusb20_device_methods libusb20_dummy_methods = {
86184610Salfred	LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy)
87184610Salfred};
88184610Salfred
89184610Salfredvoid
90184610Salfredlibusb20_tr_callback_wrapper(struct libusb20_transfer *xfer)
91184610Salfred{
92184610Salfred	;				/* style fix */
93184610Salfred
94184610Salfredrepeat:
95184610Salfred
96184610Salfred	if (!xfer->is_pending) {
97184610Salfred		xfer->status = LIBUSB20_TRANSFER_START;
98184610Salfred	} else {
99184610Salfred		xfer->is_pending = 0;
100184610Salfred	}
101184610Salfred
102188622Sthompsa	xfer->callback(xfer);
103184610Salfred
104184610Salfred	if (xfer->is_restart) {
105184610Salfred		xfer->is_restart = 0;
106184610Salfred		goto repeat;
107184610Salfred	}
108184610Salfred	if (xfer->is_draining &&
109184610Salfred	    (!xfer->is_pending)) {
110184610Salfred		xfer->is_draining = 0;
111184610Salfred		xfer->status = LIBUSB20_TRANSFER_DRAINED;
112188622Sthompsa		xfer->callback(xfer);
113184610Salfred	}
114184610Salfred	return;
115184610Salfred}
116184610Salfred
117184610Salfredint
118184610Salfredlibusb20_tr_close(struct libusb20_transfer *xfer)
119184610Salfred{
120184610Salfred	int error;
121184610Salfred
122184610Salfred	if (!xfer->is_opened) {
123184610Salfred		return (LIBUSB20_ERROR_OTHER);
124184610Salfred	}
125188622Sthompsa	error = xfer->pdev->methods->tr_close(xfer);
126184610Salfred
127184610Salfred	if (xfer->pLength) {
128184610Salfred		free(xfer->pLength);
129184610Salfred	}
130184610Salfred	if (xfer->ppBuffer) {
131184610Salfred		free(xfer->ppBuffer);
132184610Salfred	}
133202025Sthompsa	/* reset variable fields in case the transfer is opened again */
134202025Sthompsa	xfer->priv_sc0 = 0;
135202025Sthompsa	xfer->priv_sc1 = 0;
136184610Salfred	xfer->is_opened = 0;
137202025Sthompsa	xfer->is_pending = 0;
138202025Sthompsa	xfer->is_cancel = 0;
139202025Sthompsa	xfer->is_draining = 0;
140202025Sthompsa	xfer->is_restart = 0;
141202025Sthompsa	xfer->status = 0;
142202025Sthompsa	xfer->flags = 0;
143202025Sthompsa	xfer->nFrames = 0;
144202025Sthompsa	xfer->aFrames = 0;
145202025Sthompsa	xfer->timeout = 0;
146184610Salfred	xfer->maxFrames = 0;
147184610Salfred	xfer->maxTotalLength = 0;
148184610Salfred	xfer->maxPacketLen = 0;
149184610Salfred	return (error);
150184610Salfred}
151184610Salfred
152184610Salfredint
153184610Salfredlibusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
154184610Salfred    uint32_t MaxFrameCount, uint8_t ep_no)
155184610Salfred{
156184610Salfred	uint32_t size;
157184610Salfred	int error;
158184610Salfred
159184610Salfred	if (xfer->is_opened) {
160184610Salfred		return (LIBUSB20_ERROR_BUSY);
161184610Salfred	}
162184610Salfred	if (MaxFrameCount == 0) {
163184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
164184610Salfred	}
165184610Salfred	xfer->maxFrames = MaxFrameCount;
166184610Salfred
167184610Salfred	size = MaxFrameCount * sizeof(xfer->pLength[0]);
168184610Salfred	xfer->pLength = malloc(size);
169184610Salfred	if (xfer->pLength == NULL) {
170184610Salfred		return (LIBUSB20_ERROR_NO_MEM);
171184610Salfred	}
172184610Salfred	memset(xfer->pLength, 0, size);
173184610Salfred
174184610Salfred	size = MaxFrameCount * sizeof(xfer->ppBuffer[0]);
175184610Salfred	xfer->ppBuffer = malloc(size);
176184610Salfred	if (xfer->ppBuffer == NULL) {
177184610Salfred		free(xfer->pLength);
178184610Salfred		return (LIBUSB20_ERROR_NO_MEM);
179184610Salfred	}
180184610Salfred	memset(xfer->ppBuffer, 0, size);
181184610Salfred
182188622Sthompsa	error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
183184610Salfred	    MaxFrameCount, ep_no);
184184610Salfred
185184610Salfred	if (error) {
186184610Salfred		free(xfer->ppBuffer);
187184610Salfred		free(xfer->pLength);
188184610Salfred	} else {
189184610Salfred		xfer->is_opened = 1;
190184610Salfred	}
191184610Salfred	return (error);
192184610Salfred}
193184610Salfred
194184610Salfredstruct libusb20_transfer *
195184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex)
196184610Salfred{
197184610Salfred	if (trIndex >= pdev->nTransfer) {
198184610Salfred		return (NULL);
199184610Salfred	}
200184610Salfred	return (pdev->pTransfer + trIndex);
201184610Salfred}
202184610Salfred
203184610Salfreduint32_t
204184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer)
205184610Salfred{
206184610Salfred	return (xfer->aFrames);
207184610Salfred}
208184610Salfred
209184610Salfreduint16_t
210184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer)
211184610Salfred{
212184610Salfred	return (xfer->timeComplete);
213184610Salfred}
214184610Salfred
215184610Salfreduint32_t
216184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer)
217184610Salfred{
218184610Salfred	uint32_t x;
219184610Salfred	uint32_t actlen = 0;
220184610Salfred
221184610Salfred	for (x = 0; x != xfer->aFrames; x++) {
222184610Salfred		actlen += xfer->pLength[x];
223184610Salfred	}
224184610Salfred	return (actlen);
225184610Salfred}
226184610Salfred
227184610Salfreduint32_t
228184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer)
229184610Salfred{
230184610Salfred	return (xfer->maxFrames);
231184610Salfred}
232184610Salfred
233184610Salfreduint32_t
234184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer)
235184610Salfred{
236184610Salfred	/*
237184610Salfred	 * Special Case NOTE: If the packet multiplier is non-zero for
238184610Salfred	 * High Speed USB, the value returned is equal to
239184610Salfred	 * "wMaxPacketSize * multiplier" !
240184610Salfred	 */
241184610Salfred	return (xfer->maxPacketLen);
242184610Salfred}
243184610Salfred
244184610Salfreduint32_t
245184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer)
246184610Salfred{
247184610Salfred	return (xfer->maxTotalLength);
248184610Salfred}
249184610Salfred
250184610Salfreduint8_t
251184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer)
252184610Salfred{
253184610Salfred	return (xfer->status);
254184610Salfred}
255184610Salfred
256184610Salfreduint8_t
257184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer)
258184610Salfred{
259184610Salfred	return (xfer->is_pending);
260184610Salfred}
261184610Salfred
262184610Salfredvoid   *
263184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer)
264184610Salfred{
265184610Salfred	return (xfer->priv_sc0);
266184610Salfred}
267184610Salfred
268184610Salfredvoid   *
269184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer)
270184610Salfred{
271184610Salfred	return (xfer->priv_sc1);
272184610Salfred}
273184610Salfred
274184610Salfredvoid
275184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer)
276184610Salfred{
277199575Sthompsa	if (!xfer->is_opened) {
278199575Sthompsa		/* transfer is not opened */
279199575Sthompsa		return;
280199575Sthompsa	}
281184610Salfred	if (!xfer->is_pending) {
282184610Salfred		/* transfer not pending */
283184610Salfred		return;
284184610Salfred	}
285184610Salfred	if (xfer->is_cancel) {
286184610Salfred		/* already cancelling */
287184610Salfred		return;
288184610Salfred	}
289184610Salfred	xfer->is_cancel = 1;		/* we are cancelling */
290184610Salfred
291188622Sthompsa	xfer->pdev->methods->tr_cancel_async(xfer);
292184610Salfred	return;
293184610Salfred}
294184610Salfred
295184610Salfredvoid
296184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer)
297184610Salfred{
298199575Sthompsa	if (!xfer->is_opened) {
299199575Sthompsa		/* transfer is not opened */
300199575Sthompsa		return;
301199575Sthompsa	}
302184610Salfred	/* make sure that we are cancelling */
303184610Salfred	libusb20_tr_stop(xfer);
304184610Salfred
305184610Salfred	if (xfer->is_pending) {
306184610Salfred		xfer->is_draining = 1;
307184610Salfred	}
308184610Salfred	return;
309184610Salfred}
310184610Salfred
311184610Salfredvoid
312184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
313184610Salfred{
314188622Sthompsa	xfer->pdev->methods->tr_clear_stall_sync(xfer);
315184610Salfred	return;
316184610Salfred}
317184610Salfred
318184610Salfredvoid
319184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex)
320184610Salfred{
321184610Salfred	xfer->ppBuffer[frIndex] = buffer;
322184610Salfred	return;
323184610Salfred}
324184610Salfred
325184610Salfredvoid
326184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb)
327184610Salfred{
328184610Salfred	xfer->callback = cb;
329184610Salfred	return;
330184610Salfred}
331184610Salfred
332184610Salfredvoid
333184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags)
334184610Salfred{
335184610Salfred	xfer->flags = flags;
336184610Salfred	return;
337184610Salfred}
338184610Salfred
339193313Sthompsauint32_t
340193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex)
341193313Sthompsa{
342193313Sthompsa	return (xfer->pLength[frIndex]);
343193313Sthompsa}
344193313Sthompsa
345184610Salfredvoid
346184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
347184610Salfred{
348184610Salfred	xfer->pLength[frIndex] = length;
349184610Salfred	return;
350184610Salfred}
351184610Salfred
352184610Salfredvoid
353184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
354184610Salfred{
355184610Salfred	xfer->priv_sc0 = sc0;
356184610Salfred	return;
357184610Salfred}
358184610Salfred
359184610Salfredvoid
360184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
361184610Salfred{
362184610Salfred	xfer->priv_sc1 = sc1;
363184610Salfred	return;
364184610Salfred}
365184610Salfred
366184610Salfredvoid
367184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
368184610Salfred{
369184610Salfred	xfer->timeout = timeout;
370184610Salfred	return;
371184610Salfred}
372184610Salfred
373184610Salfredvoid
374184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
375184610Salfred{
376184610Salfred	if (nFrames > xfer->maxFrames) {
377184610Salfred		/* should not happen */
378184610Salfred		nFrames = xfer->maxFrames;
379184610Salfred	}
380184610Salfred	xfer->nFrames = nFrames;
381184610Salfred	return;
382184610Salfred}
383184610Salfred
384184610Salfredvoid
385184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
386184610Salfred{
387184610Salfred	xfer->ppBuffer[0] = pBuf;
388184610Salfred	xfer->pLength[0] = length;
389184610Salfred	xfer->timeout = timeout;
390184610Salfred	xfer->nFrames = 1;
391184610Salfred	return;
392184610Salfred}
393184610Salfred
394184610Salfredvoid
395184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
396184610Salfred{
397184610Salfred	uint16_t len;
398184610Salfred
399184610Salfred	xfer->ppBuffer[0] = psetup;
400184610Salfred	xfer->pLength[0] = 8;		/* fixed */
401184610Salfred	xfer->timeout = timeout;
402184610Salfred
403184610Salfred	len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
404184610Salfred
405184610Salfred	if (len != 0) {
406184610Salfred		xfer->nFrames = 2;
407184610Salfred		xfer->ppBuffer[1] = pBuf;
408184610Salfred		xfer->pLength[1] = len;
409184610Salfred	} else {
410184610Salfred		xfer->nFrames = 1;
411184610Salfred	}
412184610Salfred	return;
413184610Salfred}
414184610Salfred
415184610Salfredvoid
416184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
417184610Salfred{
418184610Salfred	xfer->ppBuffer[0] = pBuf;
419184610Salfred	xfer->pLength[0] = length;
420184610Salfred	xfer->timeout = timeout;
421184610Salfred	xfer->nFrames = 1;
422184610Salfred	return;
423184610Salfred}
424184610Salfred
425184610Salfredvoid
426184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
427184610Salfred{
428184610Salfred	if (frIndex >= xfer->maxFrames) {
429184610Salfred		/* should not happen */
430184610Salfred		return;
431184610Salfred	}
432184610Salfred	xfer->ppBuffer[frIndex] = pBuf;
433184610Salfred	xfer->pLength[frIndex] = length;
434184610Salfred	return;
435184610Salfred}
436184610Salfred
437199575Sthompsauint8_t
438199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer,
439199575Sthompsa    void *pbuf, uint32_t length, uint32_t *pactlen,
440199575Sthompsa    uint32_t timeout)
441199575Sthompsa{
442199575Sthompsa	struct libusb20_device *pdev = xfer->pdev;
443199575Sthompsa	uint32_t transfer_max;
444199575Sthompsa	uint32_t transfer_act;
445199575Sthompsa	uint8_t retval;
446199575Sthompsa
447199575Sthompsa	/* set some sensible default value */
448199575Sthompsa	if (pactlen != NULL)
449199575Sthompsa		*pactlen = 0;
450199575Sthompsa
451199575Sthompsa	/* check for error condition */
452199575Sthompsa	if (libusb20_tr_pending(xfer))
453199575Sthompsa		return (LIBUSB20_ERROR_OTHER);
454199575Sthompsa
455199575Sthompsa	do {
456199575Sthompsa		/* compute maximum transfer length */
457199575Sthompsa		transfer_max =
458199575Sthompsa		    libusb20_tr_get_max_total_length(xfer);
459199575Sthompsa
460199575Sthompsa		if (transfer_max > length)
461199575Sthompsa			transfer_max = length;
462199575Sthompsa
463199575Sthompsa		/* setup bulk or interrupt transfer */
464199575Sthompsa		libusb20_tr_setup_bulk(xfer, pbuf,
465199575Sthompsa		    transfer_max, timeout);
466199575Sthompsa
467199575Sthompsa		/* start the transfer */
468199575Sthompsa		libusb20_tr_start(xfer);
469199575Sthompsa
470199575Sthompsa		/* wait for transfer completion */
471199575Sthompsa		while (libusb20_dev_process(pdev) == 0) {
472199575Sthompsa
473199575Sthompsa			if (libusb20_tr_pending(xfer) == 0)
474199575Sthompsa				break;
475199575Sthompsa
476199575Sthompsa			libusb20_dev_wait_process(pdev, -1);
477199575Sthompsa		}
478199575Sthompsa
479199575Sthompsa		transfer_act = libusb20_tr_get_actual_length(xfer);
480199575Sthompsa
481199575Sthompsa		/* update actual length, if any */
482199575Sthompsa		if (pactlen != NULL)
483199575Sthompsa			pactlen[0] += transfer_act;
484199575Sthompsa
485199575Sthompsa		/* check transfer status */
486199575Sthompsa		retval = libusb20_tr_get_status(xfer);
487199575Sthompsa		if (retval)
488199575Sthompsa			break;
489199575Sthompsa
490199575Sthompsa		/* check for short transfer */
491199575Sthompsa		if (transfer_act != transfer_max)
492199575Sthompsa			break;
493199575Sthompsa
494199575Sthompsa		/* update buffer pointer and length */
495199575Sthompsa		pbuf = ((uint8_t *)pbuf) + transfer_max;
496199575Sthompsa		length = length - transfer_max;
497199575Sthompsa
498199575Sthompsa	} while (length != 0);
499199575Sthompsa
500199575Sthompsa	return (retval);
501199575Sthompsa}
502199575Sthompsa
503184610Salfredvoid
504184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer)
505184610Salfred{
506199575Sthompsa	if (!xfer->is_opened) {
507199575Sthompsa		/* transfer is not opened */
508199575Sthompsa		return;
509199575Sthompsa	}
510184610Salfred	if (xfer->is_pending) {
511184610Salfred		/* should not happen */
512184610Salfred		return;
513184610Salfred	}
514184610Salfred	xfer->is_pending = 1;		/* we are pending */
515184610Salfred	xfer->is_cancel = 0;		/* not cancelling */
516184610Salfred	xfer->is_restart = 0;		/* not restarting */
517184610Salfred
518188622Sthompsa	xfer->pdev->methods->tr_submit(xfer);
519184610Salfred	return;
520184610Salfred}
521184610Salfred
522184610Salfredvoid
523184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer)
524184610Salfred{
525199575Sthompsa	if (!xfer->is_opened) {
526199575Sthompsa		/* transfer is not opened */
527199575Sthompsa		return;
528199575Sthompsa	}
529184610Salfred	if (xfer->is_pending) {
530184610Salfred		if (xfer->is_cancel) {
531184610Salfred			/* cancelling - restart */
532184610Salfred			xfer->is_restart = 1;
533184610Salfred		}
534184610Salfred		/* transfer not pending */
535184610Salfred		return;
536184610Salfred	}
537184610Salfred	/* get into the callback */
538184610Salfred	libusb20_tr_callback_wrapper(xfer);
539184610Salfred	return;
540184610Salfred}
541184610Salfred
542184610Salfred/* USB device operations */
543184610Salfred
544184610Salfredint
545184610Salfredlibusb20_dev_close(struct libusb20_device *pdev)
546184610Salfred{
547184610Salfred	struct libusb20_transfer *xfer;
548184610Salfred	uint16_t x;
549184610Salfred	int error = 0;
550184610Salfred
551184610Salfred	if (!pdev->is_opened) {
552184610Salfred		return (LIBUSB20_ERROR_OTHER);
553184610Salfred	}
554184610Salfred	for (x = 0; x != pdev->nTransfer; x++) {
555184610Salfred		xfer = pdev->pTransfer + x;
556184610Salfred
557199575Sthompsa		if (!xfer->is_opened) {
558199575Sthompsa			/* transfer is not opened */
559199575Sthompsa			continue;
560199575Sthompsa		}
561199575Sthompsa
562184610Salfred		libusb20_tr_drain(xfer);
563199575Sthompsa
564199575Sthompsa		libusb20_tr_close(xfer);
565184610Salfred	}
566184610Salfred
567184610Salfred	if (pdev->pTransfer != NULL) {
568184610Salfred		free(pdev->pTransfer);
569184610Salfred		pdev->pTransfer = NULL;
570184610Salfred	}
571188622Sthompsa	error = pdev->beMethods->close_device(pdev);
572184610Salfred
573184610Salfred	pdev->methods = &libusb20_dummy_methods;
574184610Salfred
575184610Salfred	pdev->is_opened = 0;
576184610Salfred
577194069Sthompsa	/*
578194069Sthompsa	 * The following variable is only used by the libusb v0.1
579194069Sthompsa	 * compat layer:
580194069Sthompsa	 */
581194069Sthompsa	pdev->claimed_interface = 0;
582187184Sthompsa
583184610Salfred	return (error);
584184610Salfred}
585184610Salfred
586184610Salfredint
587184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
588184610Salfred{
589184610Salfred	int error;
590184610Salfred
591188622Sthompsa	error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
592184610Salfred	return (error);
593184610Salfred}
594184610Salfred
595184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED *
596184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev)
597184610Salfred{
598184610Salfred	return (&(pdev->ddesc));
599184610Salfred}
600184610Salfred
601184610Salfredint
602184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev)
603184610Salfred{
604184610Salfred	return (pdev->file);
605184610Salfred}
606184610Salfred
607184610Salfredint
608184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
609184610Salfred{
610184610Salfred	int error;
611184610Salfred
612188622Sthompsa	error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
613184610Salfred	return (error);
614184610Salfred}
615184610Salfred
616184610Salfredint
617184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
618184610Salfred{
619184610Salfred	struct libusb20_transfer *xfer;
620184610Salfred	uint32_t size;
621184610Salfred	uint16_t x;
622184610Salfred	int error;
623184610Salfred
624184610Salfred	if (pdev->is_opened) {
625184610Salfred		return (LIBUSB20_ERROR_BUSY);
626184610Salfred	}
627184610Salfred	if (nTransferMax >= 256) {
628184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
629184610Salfred	} else if (nTransferMax != 0) {
630184610Salfred		size = sizeof(pdev->pTransfer[0]) * nTransferMax;
631184610Salfred		pdev->pTransfer = malloc(size);
632184610Salfred		if (pdev->pTransfer == NULL) {
633184610Salfred			return (LIBUSB20_ERROR_NO_MEM);
634184610Salfred		}
635184610Salfred		memset(pdev->pTransfer, 0, size);
636184610Salfred	}
637184610Salfred	/* initialise all transfers */
638184610Salfred	for (x = 0; x != nTransferMax; x++) {
639184610Salfred
640184610Salfred		xfer = pdev->pTransfer + x;
641184610Salfred
642184610Salfred		xfer->pdev = pdev;
643184610Salfred		xfer->trIndex = x;
644184610Salfred		xfer->callback = &dummy_callback;
645184610Salfred	}
646184610Salfred
647185087Salfred	/* set "nTransfer" early */
648185087Salfred	pdev->nTransfer = nTransferMax;
649185087Salfred
650188622Sthompsa	error = pdev->beMethods->open_device(pdev, nTransferMax);
651184610Salfred
652184610Salfred	if (error) {
653184610Salfred		if (pdev->pTransfer != NULL) {
654184610Salfred			free(pdev->pTransfer);
655184610Salfred			pdev->pTransfer = NULL;
656184610Salfred		}
657184610Salfred		pdev->file = -1;
658184610Salfred		pdev->file_ctrl = -1;
659184610Salfred		pdev->nTransfer = 0;
660184610Salfred	} else {
661184610Salfred		pdev->is_opened = 1;
662184610Salfred	}
663184610Salfred	return (error);
664184610Salfred}
665184610Salfred
666184610Salfredint
667184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev)
668184610Salfred{
669184610Salfred	int error;
670184610Salfred
671188622Sthompsa	error = pdev->methods->reset_device(pdev);
672184610Salfred	return (error);
673184610Salfred}
674184610Salfred
675184610Salfredint
676184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
677184610Salfred{
678184610Salfred	int error;
679184610Salfred
680188622Sthompsa	error = pdev->methods->set_power_mode(pdev, power_mode);
681184610Salfred	return (error);
682184610Salfred}
683184610Salfred
684184610Salfreduint8_t
685184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev)
686184610Salfred{
687184610Salfred	int error;
688184610Salfred	uint8_t power_mode;
689184610Salfred
690188622Sthompsa	error = pdev->methods->get_power_mode(pdev, &power_mode);
691184610Salfred	if (error)
692184610Salfred		power_mode = LIBUSB20_POWER_ON;	/* fake power mode */
693184610Salfred	return (power_mode);
694184610Salfred}
695184610Salfred
696184610Salfredint
697184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
698184610Salfred{
699184610Salfred	int error;
700184610Salfred
701188622Sthompsa	error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
702184610Salfred	return (error);
703184610Salfred}
704184610Salfred
705184610Salfredint
706184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
707184610Salfred{
708184610Salfred	int error;
709184610Salfred
710188622Sthompsa	error = pdev->methods->set_config_index(pdev, configIndex);
711184610Salfred	return (error);
712184610Salfred}
713184610Salfred
714184610Salfredint
715184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev,
716184610Salfred    struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
717184610Salfred    uint16_t *pactlen, uint32_t timeout, uint8_t flags)
718184610Salfred{
719184610Salfred	int error;
720184610Salfred
721188622Sthompsa	error = pdev->methods->do_request_sync(pdev,
722184610Salfred	    setup, data, pactlen, timeout, flags);
723184610Salfred	return (error);
724184610Salfred}
725184610Salfred
726184610Salfredint
727184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev,
728185087Salfred    uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
729184610Salfred{
730184610Salfred	struct LIBUSB20_CONTROL_SETUP_DECODED req;
731184610Salfred	int error;
732184610Salfred
733199055Sthompsa	/* make sure memory is initialised */
734199055Sthompsa	memset(ptr, 0, len);
735199055Sthompsa
736184610Salfred	if (len < 4) {
737184610Salfred		/* invalid length */
738184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
739184610Salfred	}
740184610Salfred	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
741184610Salfred
742184610Salfred	/*
743184610Salfred	 * We need to read the USB string in two steps else some USB
744184610Salfred	 * devices will complain.
745184610Salfred	 */
746184610Salfred	req.bmRequestType =
747184610Salfred	    LIBUSB20_REQUEST_TYPE_STANDARD |
748184610Salfred	    LIBUSB20_RECIPIENT_DEVICE |
749184610Salfred	    LIBUSB20_ENDPOINT_IN;
750184610Salfred	req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
751185087Salfred	req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
752184610Salfred	req.wIndex = langid;
753184610Salfred	req.wLength = 4;		/* bytes */
754184610Salfred
755184610Salfred	error = libusb20_dev_request_sync(pdev, &req,
756184610Salfred	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
757184610Salfred	if (error) {
758184610Salfred		return (error);
759184610Salfred	}
760184610Salfred	req.wLength = *(uint8_t *)ptr;	/* bytes */
761184610Salfred	if (req.wLength > len) {
762184610Salfred		/* partial string read */
763184610Salfred		req.wLength = len;
764184610Salfred	}
765184610Salfred	error = libusb20_dev_request_sync(pdev, &req,
766184610Salfred	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
767184610Salfred
768184610Salfred	if (error) {
769184610Salfred		return (error);
770184610Salfred	}
771184610Salfred	if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
772184610Salfred		return (LIBUSB20_ERROR_OTHER);
773184610Salfred	}
774184610Salfred	return (0);			/* success */
775184610Salfred}
776184610Salfred
777184610Salfredint
778184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
779185087Salfred    uint8_t str_index, void *ptr, uint16_t len)
780184610Salfred{
781184610Salfred	char *buf;
782184610Salfred	int error;
783184610Salfred	uint16_t langid;
784184610Salfred	uint16_t n;
785184610Salfred	uint16_t i;
786184610Salfred	uint16_t c;
787184610Salfred	uint8_t temp[255];
788184610Salfred	uint8_t swap;
789184610Salfred
790184610Salfred	/* the following code derives from the FreeBSD USB kernel */
791184610Salfred
792184610Salfred	if ((len < 1) || (ptr == NULL)) {
793184610Salfred		/* too short buffer */
794184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
795184610Salfred	}
796184610Salfred	error = libusb20_dev_req_string_sync(pdev,
797184610Salfred	    0, 0, temp, sizeof(temp));
798185087Salfred	if (error < 0) {
799185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
800184610Salfred		return (error);
801185087Salfred	}
802184610Salfred	langid = temp[2] | (temp[3] << 8);
803184610Salfred
804185087Salfred	error = libusb20_dev_req_string_sync(pdev, str_index,
805184610Salfred	    langid, temp, sizeof(temp));
806185087Salfred	if (error < 0) {
807185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
808184610Salfred		return (error);
809185087Salfred	}
810184610Salfred	if (temp[0] < 2) {
811184610Salfred		/* string length is too short */
812185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
813184610Salfred		return (LIBUSB20_ERROR_OTHER);
814184610Salfred	}
815184610Salfred	/* reserve one byte for terminating zero */
816184610Salfred	len--;
817184610Salfred
818184610Salfred	/* find maximum length */
819184610Salfred	n = (temp[0] / 2) - 1;
820184610Salfred	if (n > len) {
821184610Salfred		n = len;
822184610Salfred	}
823184610Salfred	/* reset swap state */
824184610Salfred	swap = 3;
825184610Salfred
826184610Salfred	/* setup output buffer pointer */
827184610Salfred	buf = ptr;
828184610Salfred
829184610Salfred	/* convert and filter */
830184610Salfred	for (i = 0; (i != n); i++) {
831184610Salfred		c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
832184610Salfred
833184610Salfred		/* convert from Unicode, handle buggy strings */
834184610Salfred		if (((c & 0xff00) == 0) && (swap & 1)) {
835184610Salfred			/* Little Endian, default */
836184610Salfred			*buf = c;
837184610Salfred			swap = 1;
838184610Salfred		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
839184610Salfred			/* Big Endian */
840184610Salfred			*buf = c >> 8;
841184610Salfred			swap = 2;
842184610Salfred		} else {
843185087Salfred			/* skip invalid character */
844185087Salfred			continue;
845184610Salfred		}
846184610Salfred		/*
847184610Salfred		 * Filter by default - we don't allow greater and less than
848184610Salfred		 * signs because they might confuse the dmesg printouts!
849184610Salfred		 */
850184610Salfred		if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
851185087Salfred			/* skip invalid character */
852185087Salfred			continue;
853184610Salfred		}
854184610Salfred		buf++;
855184610Salfred	}
856184610Salfred	*buf = 0;			/* zero terminate string */
857184610Salfred
858184610Salfred	return (0);
859184610Salfred}
860184610Salfred
861184610Salfredstruct libusb20_config *
862184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
863184610Salfred{
864184610Salfred	struct libusb20_config *retval = NULL;
865184610Salfred	uint8_t *ptr;
866184610Salfred	uint16_t len;
867184610Salfred	uint8_t do_close;
868184610Salfred	int error;
869184610Salfred
870184610Salfred	if (!pdev->is_opened) {
871184610Salfred		error = libusb20_dev_open(pdev, 0);
872184610Salfred		if (error) {
873184610Salfred			return (NULL);
874184610Salfred		}
875184610Salfred		do_close = 1;
876184610Salfred	} else {
877184610Salfred		do_close = 0;
878184610Salfred	}
879188622Sthompsa	error = pdev->methods->get_config_desc_full(pdev,
880184610Salfred	    &ptr, &len, configIndex);
881184610Salfred
882184610Salfred	if (error) {
883184610Salfred		goto done;
884184610Salfred	}
885184610Salfred	/* parse new config descriptor */
886184610Salfred	retval = libusb20_parse_config_desc(ptr);
887184610Salfred
888184610Salfred	/* free config descriptor */
889184610Salfred	free(ptr);
890184610Salfred
891184610Salfreddone:
892184610Salfred	if (do_close) {
893184610Salfred		error = libusb20_dev_close(pdev);
894184610Salfred	}
895184610Salfred	return (retval);
896184610Salfred}
897184610Salfred
898184610Salfredstruct libusb20_device *
899184610Salfredlibusb20_dev_alloc(void)
900184610Salfred{
901184610Salfred	struct libusb20_device *pdev;
902184610Salfred
903184610Salfred	pdev = malloc(sizeof(*pdev));
904184610Salfred	if (pdev == NULL) {
905184610Salfred		return (NULL);
906184610Salfred	}
907184610Salfred	memset(pdev, 0, sizeof(*pdev));
908184610Salfred
909184610Salfred	pdev->file = -1;
910184610Salfred	pdev->file_ctrl = -1;
911184610Salfred	pdev->methods = &libusb20_dummy_methods;
912184610Salfred	return (pdev);
913184610Salfred}
914184610Salfred
915184610Salfreduint8_t
916184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev)
917184610Salfred{
918184610Salfred	int error;
919185087Salfred	uint8_t cfg_index;
920184610Salfred	uint8_t do_close;
921184610Salfred
922184610Salfred	if (!pdev->is_opened) {
923184610Salfred		error = libusb20_dev_open(pdev, 0);
924184610Salfred		if (error == 0) {
925184610Salfred			do_close = 1;
926184610Salfred		} else {
927184610Salfred			do_close = 0;
928184610Salfred		}
929184610Salfred	} else {
930184610Salfred		do_close = 0;
931184610Salfred	}
932184610Salfred
933188622Sthompsa	error = pdev->methods->get_config_index(pdev, &cfg_index);
934184610Salfred	if (error) {
935185087Salfred		cfg_index = 0 - 1;	/* current config index */
936184610Salfred	}
937184610Salfred	if (do_close) {
938184610Salfred		if (libusb20_dev_close(pdev)) {
939184610Salfred			/* ignore */
940184610Salfred		}
941184610Salfred	}
942185087Salfred	return (cfg_index);
943184610Salfred}
944184610Salfred
945184610Salfreduint8_t
946184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev)
947184610Salfred{
948184610Salfred	return (pdev->usb_mode);
949184610Salfred}
950184610Salfred
951184610Salfreduint8_t
952184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev)
953184610Salfred{
954184610Salfred	return (pdev->usb_speed);
955184610Salfred}
956184610Salfred
957184610Salfred/* if this function returns an error, the device is gone */
958184610Salfredint
959184610Salfredlibusb20_dev_process(struct libusb20_device *pdev)
960184610Salfred{
961184610Salfred	int error;
962184610Salfred
963188622Sthompsa	error = pdev->methods->process(pdev);
964184610Salfred	return (error);
965184610Salfred}
966184610Salfred
967184610Salfredvoid
968184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
969184610Salfred{
970185087Salfred	struct pollfd pfd[1];
971184610Salfred
972184610Salfred	if (!pdev->is_opened) {
973184610Salfred		return;
974184610Salfred	}
975184610Salfred	pfd[0].fd = pdev->file;
976184610Salfred	pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
977184610Salfred	pfd[0].revents = 0;
978184610Salfred
979185087Salfred	if (poll(pfd, 1, timeout)) {
980184610Salfred		/* ignore any error */
981184610Salfred	}
982184610Salfred	return;
983184610Salfred}
984184610Salfred
985184610Salfredvoid
986184610Salfredlibusb20_dev_free(struct libusb20_device *pdev)
987184610Salfred{
988184610Salfred	if (pdev == NULL) {
989184610Salfred		/* be NULL safe */
990184610Salfred		return;
991184610Salfred	}
992184610Salfred	if (pdev->is_opened) {
993184610Salfred		if (libusb20_dev_close(pdev)) {
994184610Salfred			/* ignore any errors */
995184610Salfred		}
996184610Salfred	}
997184610Salfred	free(pdev);
998184610Salfred	return;
999184610Salfred}
1000184610Salfred
1001188622Sthompsaint
1002188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev,
1003192984Sthompsa    struct usb_device_info *pinfo)
1004188622Sthompsa{
1005188622Sthompsa	if (pinfo == NULL)
1006188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
1007188622Sthompsa
1008188622Sthompsa	return (pdev->beMethods->dev_get_info(pdev, pinfo));
1009188622Sthompsa}
1010188622Sthompsa
1011184610Salfredconst char *
1012184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev)
1013184610Salfred{
1014188622Sthompsa	return (pdev->beMethods->get_backend_name());
1015184610Salfred}
1016184610Salfred
1017184610Salfredconst char *
1018184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev)
1019184610Salfred{
1020184610Salfred	return (pdev->usb_desc);
1021184610Salfred}
1022184610Salfred
1023184610Salfredvoid
1024184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
1025184610Salfred{
1026184610Salfred	pdev->debug = debug;
1027184610Salfred	return;
1028184610Salfred}
1029184610Salfred
1030184610Salfredint
1031184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev)
1032184610Salfred{
1033184610Salfred	return (pdev->debug);
1034184610Salfred}
1035184610Salfred
1036184610Salfreduint8_t
1037184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev)
1038184610Salfred{
1039184610Salfred	return (pdev->device_address);
1040184610Salfred}
1041184610Salfred
1042184610Salfreduint8_t
1043184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev)
1044184610Salfred{
1045184610Salfred	return (pdev->bus_number);
1046184610Salfred}
1047184610Salfred
1048184610Salfredint
1049188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev,
1050188622Sthompsa    uint8_t iface_index, char *buf, uint8_t len)
1051188622Sthompsa{
1052188622Sthompsa	if ((buf == NULL) || (len == 0))
1053188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
1054188622Sthompsa
1055188622Sthompsa	return (pdev->beMethods->dev_get_iface_desc(
1056188622Sthompsa	    pdev, iface_index, buf, len));
1057188622Sthompsa}
1058188622Sthompsa
1059184610Salfred/* USB backend operations */
1060184610Salfred
1061184610Salfredint
1062184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
1063185087Salfred    uint16_t quirk_index, struct libusb20_quirk *pq)
1064184610Salfred{
1065188622Sthompsa	return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
1066184610Salfred}
1067184610Salfred
1068184610Salfredint
1069184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe,
1070185087Salfred    uint16_t quirk_index, struct libusb20_quirk *pq)
1071184610Salfred{
1072188622Sthompsa	return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
1073184610Salfred}
1074184610Salfred
1075184610Salfredint
1076184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
1077184610Salfred    struct libusb20_quirk *pq)
1078184610Salfred{
1079188622Sthompsa	return (pbe->methods->root_add_dev_quirk(pbe, pq));
1080184610Salfred}
1081184610Salfred
1082184610Salfredint
1083184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
1084184610Salfred    struct libusb20_quirk *pq)
1085184610Salfred{
1086188622Sthompsa	return (pbe->methods->root_remove_dev_quirk(pbe, pq));
1087184610Salfred}
1088184610Salfred
1089184610Salfredint
1090188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp)
1091188987Sthompsa{
1092188987Sthompsa	return (pbe->methods->root_set_template(pbe, temp));
1093188987Sthompsa}
1094188987Sthompsa
1095188987Sthompsaint
1096188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
1097188987Sthompsa{
1098188987Sthompsa	int temp;
1099188987Sthompsa
1100188987Sthompsa	if (ptemp == NULL)
1101188987Sthompsa		ptemp = &temp;
1102188987Sthompsa
1103188987Sthompsa	return (pbe->methods->root_get_template(pbe, ptemp));
1104188987Sthompsa}
1105188987Sthompsa
1106184610Salfredstruct libusb20_device *
1107184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1108184610Salfred{
1109184610Salfred	if (pbe == NULL) {
1110184610Salfred		pdev = NULL;
1111184610Salfred	} else if (pdev == NULL) {
1112184610Salfred		pdev = TAILQ_FIRST(&(pbe->usb_devs));
1113184610Salfred	} else {
1114184610Salfred		pdev = TAILQ_NEXT(pdev, dev_entry);
1115184610Salfred	}
1116184610Salfred	return (pdev);
1117184610Salfred}
1118184610Salfred
1119184610Salfredstruct libusb20_backend *
1120184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods)
1121184610Salfred{
1122184610Salfred	struct libusb20_backend *pbe;
1123184610Salfred
1124184610Salfred	pbe = malloc(sizeof(*pbe));
1125184610Salfred	if (pbe == NULL) {
1126184610Salfred		return (NULL);
1127184610Salfred	}
1128184610Salfred	memset(pbe, 0, sizeof(*pbe));
1129184610Salfred
1130184610Salfred	TAILQ_INIT(&(pbe->usb_devs));
1131184610Salfred
1132184610Salfred	pbe->methods = methods;		/* set backend methods */
1133184610Salfred
1134184610Salfred	/* do the initial device scan */
1135184610Salfred	if (pbe->methods->init_backend) {
1136188622Sthompsa		pbe->methods->init_backend(pbe);
1137184610Salfred	}
1138184610Salfred	return (pbe);
1139184610Salfred}
1140184610Salfred
1141184610Salfredstruct libusb20_backend *
1142184610Salfredlibusb20_be_alloc_linux(void)
1143184610Salfred{
1144184610Salfred	struct libusb20_backend *pbe;
1145184610Salfred
1146184610Salfred#ifdef __linux__
1147184610Salfred	pbe = libusb20_be_alloc(&libusb20_linux_backend);
1148184610Salfred#else
1149184610Salfred	pbe = NULL;
1150184610Salfred#endif
1151184610Salfred	return (pbe);
1152184610Salfred}
1153184610Salfred
1154184610Salfredstruct libusb20_backend *
1155184610Salfredlibusb20_be_alloc_ugen20(void)
1156184610Salfred{
1157184610Salfred	struct libusb20_backend *pbe;
1158184610Salfred
1159184610Salfred#ifdef __FreeBSD__
1160184610Salfred	pbe = libusb20_be_alloc(&libusb20_ugen20_backend);
1161184610Salfred#else
1162184610Salfred	pbe = NULL;
1163184610Salfred#endif
1164184610Salfred	return (pbe);
1165184610Salfred}
1166184610Salfred
1167184610Salfredstruct libusb20_backend *
1168184610Salfredlibusb20_be_alloc_default(void)
1169184610Salfred{
1170184610Salfred	struct libusb20_backend *pbe;
1171184610Salfred
1172184610Salfred	pbe = libusb20_be_alloc_linux();
1173184610Salfred	if (pbe) {
1174184610Salfred		return (pbe);
1175184610Salfred	}
1176184610Salfred	pbe = libusb20_be_alloc_ugen20();
1177184610Salfred	if (pbe) {
1178184610Salfred		return (pbe);
1179184610Salfred	}
1180184610Salfred	return (NULL);			/* no backend found */
1181184610Salfred}
1182184610Salfred
1183184610Salfredvoid
1184184610Salfredlibusb20_be_free(struct libusb20_backend *pbe)
1185184610Salfred{
1186184610Salfred	struct libusb20_device *pdev;
1187184610Salfred
1188184610Salfred	if (pbe == NULL) {
1189184610Salfred		/* be NULL safe */
1190184610Salfred		return;
1191184610Salfred	}
1192184610Salfred	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1193184610Salfred		libusb20_be_dequeue_device(pbe, pdev);
1194184610Salfred		libusb20_dev_free(pdev);
1195184610Salfred	}
1196184610Salfred	if (pbe->methods->exit_backend) {
1197188622Sthompsa		pbe->methods->exit_backend(pbe);
1198184610Salfred	}
1199199055Sthompsa	/* free backend */
1200199055Sthompsa	free(pbe);
1201184610Salfred}
1202184610Salfred
1203184610Salfredvoid
1204184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1205184610Salfred{
1206184610Salfred	pdev->beMethods = pbe->methods;	/* copy backend methods */
1207184610Salfred	TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1208184610Salfred}
1209184610Salfred
1210184610Salfredvoid
1211184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe,
1212184610Salfred    struct libusb20_device *pdev)
1213184610Salfred{
1214184610Salfred	TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
1215184610Salfred}
1216