1184610Salfred/* $FreeBSD$ */
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
27248236Shselasky#ifdef LIBUSB_GLOBAL_INCLUDE_FILE
28248236Shselasky#include LIBUSB_GLOBAL_INCLUDE_FILE
29248236Shselasky#else
30203815Swkoszek#include <ctype.h>
31203815Swkoszek#include <poll.h>
32184610Salfred#include <stdio.h>
33184610Salfred#include <stdlib.h>
34184610Salfred#include <string.h>
35248236Shselasky#include <time.h>
36248236Shselasky#include <sys/queue.h>
37248236Shselasky#endif
38184610Salfred
39184610Salfred#include "libusb20.h"
40184610Salfred#include "libusb20_desc.h"
41184610Salfred#include "libusb20_int.h"
42184610Salfred
43184610Salfredstatic int
44184610Salfreddummy_int(void)
45184610Salfred{
46184610Salfred	return (LIBUSB20_ERROR_NOT_SUPPORTED);
47184610Salfred}
48184610Salfred
49184610Salfredstatic void
50184610Salfreddummy_void(void)
51184610Salfred{
52184610Salfred	return;
53184610Salfred}
54184610Salfred
55184610Salfredstatic void
56184610Salfreddummy_callback(struct libusb20_transfer *xfer)
57184610Salfred{
58184610Salfred	;				/* style fix */
59184610Salfred	switch (libusb20_tr_get_status(xfer)) {
60184610Salfred	case LIBUSB20_TRANSFER_START:
61184610Salfred		libusb20_tr_submit(xfer);
62184610Salfred		break;
63184610Salfred	default:
64184610Salfred		/* complete or error */
65184610Salfred		break;
66184610Salfred	}
67184610Salfred	return;
68184610Salfred}
69184610Salfred
70184610Salfred#define	dummy_get_config_desc_full (void *)dummy_int
71184610Salfred#define	dummy_get_config_index (void *)dummy_int
72184610Salfred#define	dummy_set_config_index (void *)dummy_int
73184610Salfred#define	dummy_set_alt_index (void *)dummy_int
74184610Salfred#define	dummy_reset_device (void *)dummy_int
75203147Sthompsa#define	dummy_check_connected (void *)dummy_int
76184610Salfred#define	dummy_set_power_mode (void *)dummy_int
77184610Salfred#define	dummy_get_power_mode (void *)dummy_int
78250201Shselasky#define	dummy_get_port_path (void *)dummy_int
79246789Shselasky#define	dummy_get_power_usage (void *)dummy_int
80184610Salfred#define	dummy_kernel_driver_active (void *)dummy_int
81184610Salfred#define	dummy_detach_kernel_driver (void *)dummy_int
82184610Salfred#define	dummy_do_request_sync (void *)dummy_int
83184610Salfred#define	dummy_tr_open (void *)dummy_int
84184610Salfred#define	dummy_tr_close (void *)dummy_int
85184610Salfred#define	dummy_tr_clear_stall_sync (void *)dummy_int
86184610Salfred#define	dummy_process (void *)dummy_int
87188622Sthompsa#define	dummy_dev_info (void *)dummy_int
88188622Sthompsa#define	dummy_dev_get_iface_driver (void *)dummy_int
89184610Salfred
90184610Salfred#define	dummy_tr_submit (void *)dummy_void
91184610Salfred#define	dummy_tr_cancel_async (void *)dummy_void
92184610Salfred
93184610Salfredstatic const struct libusb20_device_methods libusb20_dummy_methods = {
94184610Salfred	LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy)
95184610Salfred};
96184610Salfred
97184610Salfredvoid
98184610Salfredlibusb20_tr_callback_wrapper(struct libusb20_transfer *xfer)
99184610Salfred{
100184610Salfred	;				/* style fix */
101184610Salfred
102184610Salfredrepeat:
103184610Salfred
104184610Salfred	if (!xfer->is_pending) {
105184610Salfred		xfer->status = LIBUSB20_TRANSFER_START;
106184610Salfred	} else {
107184610Salfred		xfer->is_pending = 0;
108184610Salfred	}
109184610Salfred
110188622Sthompsa	xfer->callback(xfer);
111184610Salfred
112184610Salfred	if (xfer->is_restart) {
113184610Salfred		xfer->is_restart = 0;
114184610Salfred		goto repeat;
115184610Salfred	}
116184610Salfred	if (xfer->is_draining &&
117184610Salfred	    (!xfer->is_pending)) {
118184610Salfred		xfer->is_draining = 0;
119184610Salfred		xfer->status = LIBUSB20_TRANSFER_DRAINED;
120188622Sthompsa		xfer->callback(xfer);
121184610Salfred	}
122184610Salfred	return;
123184610Salfred}
124184610Salfred
125184610Salfredint
126184610Salfredlibusb20_tr_close(struct libusb20_transfer *xfer)
127184610Salfred{
128184610Salfred	int error;
129184610Salfred
130184610Salfred	if (!xfer->is_opened) {
131184610Salfred		return (LIBUSB20_ERROR_OTHER);
132184610Salfred	}
133188622Sthompsa	error = xfer->pdev->methods->tr_close(xfer);
134184610Salfred
135184610Salfred	if (xfer->pLength) {
136184610Salfred		free(xfer->pLength);
137184610Salfred	}
138184610Salfred	if (xfer->ppBuffer) {
139184610Salfred		free(xfer->ppBuffer);
140184610Salfred	}
141202025Sthompsa	/* reset variable fields in case the transfer is opened again */
142202025Sthompsa	xfer->priv_sc0 = 0;
143202025Sthompsa	xfer->priv_sc1 = 0;
144184610Salfred	xfer->is_opened = 0;
145202025Sthompsa	xfer->is_pending = 0;
146202025Sthompsa	xfer->is_cancel = 0;
147202025Sthompsa	xfer->is_draining = 0;
148202025Sthompsa	xfer->is_restart = 0;
149202025Sthompsa	xfer->status = 0;
150202025Sthompsa	xfer->flags = 0;
151202025Sthompsa	xfer->nFrames = 0;
152202025Sthompsa	xfer->aFrames = 0;
153202025Sthompsa	xfer->timeout = 0;
154184610Salfred	xfer->maxFrames = 0;
155184610Salfred	xfer->maxTotalLength = 0;
156184610Salfred	xfer->maxPacketLen = 0;
157184610Salfred	return (error);
158184610Salfred}
159184610Salfred
160184610Salfredint
161184610Salfredlibusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
162184610Salfred    uint32_t MaxFrameCount, uint8_t ep_no)
163184610Salfred{
164239239Shselasky	return (libusb20_tr_open_stream(xfer, MaxBufSize, MaxFrameCount, ep_no, 0));
165239239Shselasky}
166239239Shselasky
167239239Shselaskyint
168239239Shselaskylibusb20_tr_open_stream(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
169239239Shselasky    uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id)
170239239Shselasky{
171184610Salfred	uint32_t size;
172219100Shselasky	uint8_t pre_scale;
173184610Salfred	int error;
174184610Salfred
175219100Shselasky	if (xfer->is_opened)
176184610Salfred		return (LIBUSB20_ERROR_BUSY);
177219100Shselasky	if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) {
178219100Shselasky		MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE;
179219100Shselasky		pre_scale = 1;
180219100Shselasky	} else {
181219100Shselasky		pre_scale = 0;
182184610Salfred	}
183219100Shselasky	if (MaxFrameCount == 0)
184184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
185219100Shselasky
186184610Salfred	xfer->maxFrames = MaxFrameCount;
187184610Salfred
188184610Salfred	size = MaxFrameCount * sizeof(xfer->pLength[0]);
189184610Salfred	xfer->pLength = malloc(size);
190184610Salfred	if (xfer->pLength == NULL) {
191184610Salfred		return (LIBUSB20_ERROR_NO_MEM);
192184610Salfred	}
193184610Salfred	memset(xfer->pLength, 0, size);
194184610Salfred
195184610Salfred	size = MaxFrameCount * sizeof(xfer->ppBuffer[0]);
196184610Salfred	xfer->ppBuffer = malloc(size);
197184610Salfred	if (xfer->ppBuffer == NULL) {
198184610Salfred		free(xfer->pLength);
199184610Salfred		return (LIBUSB20_ERROR_NO_MEM);
200184610Salfred	}
201184610Salfred	memset(xfer->ppBuffer, 0, size);
202184610Salfred
203188622Sthompsa	error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
204239239Shselasky	    MaxFrameCount, ep_no, stream_id, pre_scale);
205184610Salfred
206184610Salfred	if (error) {
207184610Salfred		free(xfer->ppBuffer);
208184610Salfred		free(xfer->pLength);
209184610Salfred	} else {
210184610Salfred		xfer->is_opened = 1;
211184610Salfred	}
212184610Salfred	return (error);
213184610Salfred}
214184610Salfred
215184610Salfredstruct libusb20_transfer *
216184610Salfredlibusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex)
217184610Salfred{
218184610Salfred	if (trIndex >= pdev->nTransfer) {
219184610Salfred		return (NULL);
220184610Salfred	}
221184610Salfred	return (pdev->pTransfer + trIndex);
222184610Salfred}
223184610Salfred
224184610Salfreduint32_t
225184610Salfredlibusb20_tr_get_actual_frames(struct libusb20_transfer *xfer)
226184610Salfred{
227184610Salfred	return (xfer->aFrames);
228184610Salfred}
229184610Salfred
230184610Salfreduint16_t
231184610Salfredlibusb20_tr_get_time_complete(struct libusb20_transfer *xfer)
232184610Salfred{
233184610Salfred	return (xfer->timeComplete);
234184610Salfred}
235184610Salfred
236184610Salfreduint32_t
237184610Salfredlibusb20_tr_get_actual_length(struct libusb20_transfer *xfer)
238184610Salfred{
239184610Salfred	uint32_t x;
240184610Salfred	uint32_t actlen = 0;
241184610Salfred
242184610Salfred	for (x = 0; x != xfer->aFrames; x++) {
243184610Salfred		actlen += xfer->pLength[x];
244184610Salfred	}
245184610Salfred	return (actlen);
246184610Salfred}
247184610Salfred
248184610Salfreduint32_t
249184610Salfredlibusb20_tr_get_max_frames(struct libusb20_transfer *xfer)
250184610Salfred{
251184610Salfred	return (xfer->maxFrames);
252184610Salfred}
253184610Salfred
254184610Salfreduint32_t
255184610Salfredlibusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer)
256184610Salfred{
257184610Salfred	/*
258184610Salfred	 * Special Case NOTE: If the packet multiplier is non-zero for
259184610Salfred	 * High Speed USB, the value returned is equal to
260184610Salfred	 * "wMaxPacketSize * multiplier" !
261184610Salfred	 */
262184610Salfred	return (xfer->maxPacketLen);
263184610Salfred}
264184610Salfred
265184610Salfreduint32_t
266184610Salfredlibusb20_tr_get_max_total_length(struct libusb20_transfer *xfer)
267184610Salfred{
268184610Salfred	return (xfer->maxTotalLength);
269184610Salfred}
270184610Salfred
271184610Salfreduint8_t
272184610Salfredlibusb20_tr_get_status(struct libusb20_transfer *xfer)
273184610Salfred{
274184610Salfred	return (xfer->status);
275184610Salfred}
276184610Salfred
277184610Salfreduint8_t
278184610Salfredlibusb20_tr_pending(struct libusb20_transfer *xfer)
279184610Salfred{
280184610Salfred	return (xfer->is_pending);
281184610Salfred}
282184610Salfred
283184610Salfredvoid   *
284184610Salfredlibusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer)
285184610Salfred{
286184610Salfred	return (xfer->priv_sc0);
287184610Salfred}
288184610Salfred
289184610Salfredvoid   *
290184610Salfredlibusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer)
291184610Salfred{
292184610Salfred	return (xfer->priv_sc1);
293184610Salfred}
294184610Salfred
295184610Salfredvoid
296184610Salfredlibusb20_tr_stop(struct libusb20_transfer *xfer)
297184610Salfred{
298199575Sthompsa	if (!xfer->is_opened) {
299199575Sthompsa		/* transfer is not opened */
300199575Sthompsa		return;
301199575Sthompsa	}
302184610Salfred	if (!xfer->is_pending) {
303184610Salfred		/* transfer not pending */
304184610Salfred		return;
305184610Salfred	}
306184610Salfred	if (xfer->is_cancel) {
307184610Salfred		/* already cancelling */
308184610Salfred		return;
309184610Salfred	}
310184610Salfred	xfer->is_cancel = 1;		/* we are cancelling */
311184610Salfred
312188622Sthompsa	xfer->pdev->methods->tr_cancel_async(xfer);
313184610Salfred	return;
314184610Salfred}
315184610Salfred
316184610Salfredvoid
317184610Salfredlibusb20_tr_drain(struct libusb20_transfer *xfer)
318184610Salfred{
319199575Sthompsa	if (!xfer->is_opened) {
320199575Sthompsa		/* transfer is not opened */
321199575Sthompsa		return;
322199575Sthompsa	}
323184610Salfred	/* make sure that we are cancelling */
324184610Salfred	libusb20_tr_stop(xfer);
325184610Salfred
326184610Salfred	if (xfer->is_pending) {
327184610Salfred		xfer->is_draining = 1;
328184610Salfred	}
329184610Salfred	return;
330184610Salfred}
331184610Salfred
332184610Salfredvoid
333184610Salfredlibusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
334184610Salfred{
335188622Sthompsa	xfer->pdev->methods->tr_clear_stall_sync(xfer);
336184610Salfred	return;
337184610Salfred}
338184610Salfred
339184610Salfredvoid
340184610Salfredlibusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex)
341184610Salfred{
342213852Shselasky	xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer);
343184610Salfred	return;
344184610Salfred}
345184610Salfred
346184610Salfredvoid
347184610Salfredlibusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb)
348184610Salfred{
349184610Salfred	xfer->callback = cb;
350184610Salfred	return;
351184610Salfred}
352184610Salfred
353184610Salfredvoid
354184610Salfredlibusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags)
355184610Salfred{
356184610Salfred	xfer->flags = flags;
357184610Salfred	return;
358184610Salfred}
359184610Salfred
360193313Sthompsauint32_t
361193313Sthompsalibusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex)
362193313Sthompsa{
363193313Sthompsa	return (xfer->pLength[frIndex]);
364193313Sthompsa}
365193313Sthompsa
366184610Salfredvoid
367184610Salfredlibusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
368184610Salfred{
369184610Salfred	xfer->pLength[frIndex] = length;
370184610Salfred	return;
371184610Salfred}
372184610Salfred
373184610Salfredvoid
374184610Salfredlibusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
375184610Salfred{
376184610Salfred	xfer->priv_sc0 = sc0;
377184610Salfred	return;
378184610Salfred}
379184610Salfred
380184610Salfredvoid
381184610Salfredlibusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
382184610Salfred{
383184610Salfred	xfer->priv_sc1 = sc1;
384184610Salfred	return;
385184610Salfred}
386184610Salfred
387184610Salfredvoid
388184610Salfredlibusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
389184610Salfred{
390184610Salfred	xfer->timeout = timeout;
391184610Salfred	return;
392184610Salfred}
393184610Salfred
394184610Salfredvoid
395184610Salfredlibusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
396184610Salfred{
397184610Salfred	if (nFrames > xfer->maxFrames) {
398184610Salfred		/* should not happen */
399184610Salfred		nFrames = xfer->maxFrames;
400184610Salfred	}
401184610Salfred	xfer->nFrames = nFrames;
402184610Salfred	return;
403184610Salfred}
404184610Salfred
405184610Salfredvoid
406184610Salfredlibusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
407184610Salfred{
408213852Shselasky	xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
409184610Salfred	xfer->pLength[0] = length;
410184610Salfred	xfer->timeout = timeout;
411184610Salfred	xfer->nFrames = 1;
412184610Salfred	return;
413184610Salfred}
414184610Salfred
415184610Salfredvoid
416184610Salfredlibusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
417184610Salfred{
418184610Salfred	uint16_t len;
419184610Salfred
420213852Shselasky	xfer->ppBuffer[0] = libusb20_pass_ptr(psetup);
421184610Salfred	xfer->pLength[0] = 8;		/* fixed */
422184610Salfred	xfer->timeout = timeout;
423184610Salfred
424184610Salfred	len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
425184610Salfred
426184610Salfred	if (len != 0) {
427184610Salfred		xfer->nFrames = 2;
428213852Shselasky		xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf);
429184610Salfred		xfer->pLength[1] = len;
430184610Salfred	} else {
431184610Salfred		xfer->nFrames = 1;
432184610Salfred	}
433184610Salfred	return;
434184610Salfred}
435184610Salfred
436184610Salfredvoid
437184610Salfredlibusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
438184610Salfred{
439213852Shselasky	xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
440184610Salfred	xfer->pLength[0] = length;
441184610Salfred	xfer->timeout = timeout;
442184610Salfred	xfer->nFrames = 1;
443184610Salfred	return;
444184610Salfred}
445184610Salfred
446184610Salfredvoid
447184610Salfredlibusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
448184610Salfred{
449184610Salfred	if (frIndex >= xfer->maxFrames) {
450184610Salfred		/* should not happen */
451184610Salfred		return;
452184610Salfred	}
453213852Shselasky	xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf);
454184610Salfred	xfer->pLength[frIndex] = length;
455184610Salfred	return;
456184610Salfred}
457184610Salfred
458199575Sthompsauint8_t
459199575Sthompsalibusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer,
460199575Sthompsa    void *pbuf, uint32_t length, uint32_t *pactlen,
461199575Sthompsa    uint32_t timeout)
462199575Sthompsa{
463199575Sthompsa	struct libusb20_device *pdev = xfer->pdev;
464199575Sthompsa	uint32_t transfer_max;
465199575Sthompsa	uint32_t transfer_act;
466199575Sthompsa	uint8_t retval;
467199575Sthompsa
468199575Sthompsa	/* set some sensible default value */
469199575Sthompsa	if (pactlen != NULL)
470199575Sthompsa		*pactlen = 0;
471199575Sthompsa
472199575Sthompsa	/* check for error condition */
473199575Sthompsa	if (libusb20_tr_pending(xfer))
474199575Sthompsa		return (LIBUSB20_ERROR_OTHER);
475199575Sthompsa
476199575Sthompsa	do {
477199575Sthompsa		/* compute maximum transfer length */
478199575Sthompsa		transfer_max =
479199575Sthompsa		    libusb20_tr_get_max_total_length(xfer);
480199575Sthompsa
481199575Sthompsa		if (transfer_max > length)
482199575Sthompsa			transfer_max = length;
483199575Sthompsa
484199575Sthompsa		/* setup bulk or interrupt transfer */
485199575Sthompsa		libusb20_tr_setup_bulk(xfer, pbuf,
486199575Sthompsa		    transfer_max, timeout);
487199575Sthompsa
488199575Sthompsa		/* start the transfer */
489199575Sthompsa		libusb20_tr_start(xfer);
490199575Sthompsa
491199575Sthompsa		/* wait for transfer completion */
492199575Sthompsa		while (libusb20_dev_process(pdev) == 0) {
493199575Sthompsa
494199575Sthompsa			if (libusb20_tr_pending(xfer) == 0)
495199575Sthompsa				break;
496199575Sthompsa
497199575Sthompsa			libusb20_dev_wait_process(pdev, -1);
498199575Sthompsa		}
499199575Sthompsa
500199575Sthompsa		transfer_act = libusb20_tr_get_actual_length(xfer);
501199575Sthompsa
502199575Sthompsa		/* update actual length, if any */
503199575Sthompsa		if (pactlen != NULL)
504199575Sthompsa			pactlen[0] += transfer_act;
505199575Sthompsa
506199575Sthompsa		/* check transfer status */
507199575Sthompsa		retval = libusb20_tr_get_status(xfer);
508199575Sthompsa		if (retval)
509199575Sthompsa			break;
510199575Sthompsa
511199575Sthompsa		/* check for short transfer */
512199575Sthompsa		if (transfer_act != transfer_max)
513199575Sthompsa			break;
514199575Sthompsa
515199575Sthompsa		/* update buffer pointer and length */
516199575Sthompsa		pbuf = ((uint8_t *)pbuf) + transfer_max;
517199575Sthompsa		length = length - transfer_max;
518199575Sthompsa
519199575Sthompsa	} while (length != 0);
520199575Sthompsa
521199575Sthompsa	return (retval);
522199575Sthompsa}
523199575Sthompsa
524184610Salfredvoid
525184610Salfredlibusb20_tr_submit(struct libusb20_transfer *xfer)
526184610Salfred{
527199575Sthompsa	if (!xfer->is_opened) {
528199575Sthompsa		/* transfer is not opened */
529199575Sthompsa		return;
530199575Sthompsa	}
531184610Salfred	if (xfer->is_pending) {
532184610Salfred		/* should not happen */
533184610Salfred		return;
534184610Salfred	}
535184610Salfred	xfer->is_pending = 1;		/* we are pending */
536184610Salfred	xfer->is_cancel = 0;		/* not cancelling */
537184610Salfred	xfer->is_restart = 0;		/* not restarting */
538184610Salfred
539188622Sthompsa	xfer->pdev->methods->tr_submit(xfer);
540184610Salfred	return;
541184610Salfred}
542184610Salfred
543184610Salfredvoid
544184610Salfredlibusb20_tr_start(struct libusb20_transfer *xfer)
545184610Salfred{
546199575Sthompsa	if (!xfer->is_opened) {
547199575Sthompsa		/* transfer is not opened */
548199575Sthompsa		return;
549199575Sthompsa	}
550184610Salfred	if (xfer->is_pending) {
551184610Salfred		if (xfer->is_cancel) {
552184610Salfred			/* cancelling - restart */
553184610Salfred			xfer->is_restart = 1;
554184610Salfred		}
555184610Salfred		/* transfer not pending */
556184610Salfred		return;
557184610Salfred	}
558184610Salfred	/* get into the callback */
559184610Salfred	libusb20_tr_callback_wrapper(xfer);
560184610Salfred	return;
561184610Salfred}
562184610Salfred
563184610Salfred/* USB device operations */
564184610Salfred
565184610Salfredint
566184610Salfredlibusb20_dev_close(struct libusb20_device *pdev)
567184610Salfred{
568184610Salfred	struct libusb20_transfer *xfer;
569184610Salfred	uint16_t x;
570184610Salfred	int error = 0;
571184610Salfred
572184610Salfred	if (!pdev->is_opened) {
573184610Salfred		return (LIBUSB20_ERROR_OTHER);
574184610Salfred	}
575184610Salfred	for (x = 0; x != pdev->nTransfer; x++) {
576184610Salfred		xfer = pdev->pTransfer + x;
577184610Salfred
578199575Sthompsa		if (!xfer->is_opened) {
579199575Sthompsa			/* transfer is not opened */
580199575Sthompsa			continue;
581199575Sthompsa		}
582199575Sthompsa
583184610Salfred		libusb20_tr_drain(xfer);
584199575Sthompsa
585199575Sthompsa		libusb20_tr_close(xfer);
586184610Salfred	}
587184610Salfred
588184610Salfred	if (pdev->pTransfer != NULL) {
589184610Salfred		free(pdev->pTransfer);
590184610Salfred		pdev->pTransfer = NULL;
591184610Salfred	}
592188622Sthompsa	error = pdev->beMethods->close_device(pdev);
593184610Salfred
594184610Salfred	pdev->methods = &libusb20_dummy_methods;
595184610Salfred
596184610Salfred	pdev->is_opened = 0;
597184610Salfred
598194069Sthompsa	/*
599194069Sthompsa	 * The following variable is only used by the libusb v0.1
600194069Sthompsa	 * compat layer:
601194069Sthompsa	 */
602194069Sthompsa	pdev->claimed_interface = 0;
603187184Sthompsa
604184610Salfred	return (error);
605184610Salfred}
606184610Salfred
607184610Salfredint
608184610Salfredlibusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
609184610Salfred{
610184610Salfred	int error;
611184610Salfred
612188622Sthompsa	error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
613184610Salfred	return (error);
614184610Salfred}
615184610Salfred
616184610Salfredstruct LIBUSB20_DEVICE_DESC_DECODED *
617184610Salfredlibusb20_dev_get_device_desc(struct libusb20_device *pdev)
618184610Salfred{
619184610Salfred	return (&(pdev->ddesc));
620184610Salfred}
621184610Salfred
622184610Salfredint
623184610Salfredlibusb20_dev_get_fd(struct libusb20_device *pdev)
624184610Salfred{
625184610Salfred	return (pdev->file);
626184610Salfred}
627184610Salfred
628184610Salfredint
629184610Salfredlibusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
630184610Salfred{
631184610Salfred	int error;
632184610Salfred
633188622Sthompsa	error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
634184610Salfred	return (error);
635184610Salfred}
636184610Salfred
637184610Salfredint
638184610Salfredlibusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
639184610Salfred{
640184610Salfred	struct libusb20_transfer *xfer;
641184610Salfred	uint32_t size;
642184610Salfred	uint16_t x;
643184610Salfred	int error;
644184610Salfred
645184610Salfred	if (pdev->is_opened) {
646184610Salfred		return (LIBUSB20_ERROR_BUSY);
647184610Salfred	}
648184610Salfred	if (nTransferMax >= 256) {
649184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
650184610Salfred	} else if (nTransferMax != 0) {
651184610Salfred		size = sizeof(pdev->pTransfer[0]) * nTransferMax;
652184610Salfred		pdev->pTransfer = malloc(size);
653184610Salfred		if (pdev->pTransfer == NULL) {
654184610Salfred			return (LIBUSB20_ERROR_NO_MEM);
655184610Salfred		}
656184610Salfred		memset(pdev->pTransfer, 0, size);
657184610Salfred	}
658184610Salfred	/* initialise all transfers */
659184610Salfred	for (x = 0; x != nTransferMax; x++) {
660184610Salfred
661184610Salfred		xfer = pdev->pTransfer + x;
662184610Salfred
663184610Salfred		xfer->pdev = pdev;
664184610Salfred		xfer->trIndex = x;
665184610Salfred		xfer->callback = &dummy_callback;
666184610Salfred	}
667184610Salfred
668185087Salfred	/* set "nTransfer" early */
669185087Salfred	pdev->nTransfer = nTransferMax;
670185087Salfred
671188622Sthompsa	error = pdev->beMethods->open_device(pdev, nTransferMax);
672184610Salfred
673184610Salfred	if (error) {
674184610Salfred		if (pdev->pTransfer != NULL) {
675184610Salfred			free(pdev->pTransfer);
676184610Salfred			pdev->pTransfer = NULL;
677184610Salfred		}
678184610Salfred		pdev->file = -1;
679184610Salfred		pdev->file_ctrl = -1;
680184610Salfred		pdev->nTransfer = 0;
681184610Salfred	} else {
682184610Salfred		pdev->is_opened = 1;
683184610Salfred	}
684184610Salfred	return (error);
685184610Salfred}
686184610Salfred
687184610Salfredint
688184610Salfredlibusb20_dev_reset(struct libusb20_device *pdev)
689184610Salfred{
690184610Salfred	int error;
691184610Salfred
692188622Sthompsa	error = pdev->methods->reset_device(pdev);
693184610Salfred	return (error);
694184610Salfred}
695184610Salfred
696184610Salfredint
697203147Sthompsalibusb20_dev_check_connected(struct libusb20_device *pdev)
698203147Sthompsa{
699203147Sthompsa	int error;
700203147Sthompsa
701203147Sthompsa	error = pdev->methods->check_connected(pdev);
702203147Sthompsa	return (error);
703203147Sthompsa}
704203147Sthompsa
705203147Sthompsaint
706184610Salfredlibusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
707184610Salfred{
708184610Salfred	int error;
709184610Salfred
710188622Sthompsa	error = pdev->methods->set_power_mode(pdev, power_mode);
711184610Salfred	return (error);
712184610Salfred}
713184610Salfred
714184610Salfreduint8_t
715184610Salfredlibusb20_dev_get_power_mode(struct libusb20_device *pdev)
716184610Salfred{
717184610Salfred	int error;
718184610Salfred	uint8_t power_mode;
719184610Salfred
720188622Sthompsa	error = pdev->methods->get_power_mode(pdev, &power_mode);
721184610Salfred	if (error)
722184610Salfred		power_mode = LIBUSB20_POWER_ON;	/* fake power mode */
723184610Salfred	return (power_mode);
724184610Salfred}
725184610Salfred
726250201Shselaskyint
727250201Shselaskylibusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
728250201Shselasky{
729250201Shselasky	return (pdev->methods->get_port_path(pdev, buf, bufsize));
730250201Shselasky}
731250201Shselasky
732246789Shselaskyuint16_t
733246789Shselaskylibusb20_dev_get_power_usage(struct libusb20_device *pdev)
734246789Shselasky{
735246789Shselasky	int error;
736246789Shselasky	uint16_t power_usage;
737246789Shselasky
738246789Shselasky	error = pdev->methods->get_power_usage(pdev, &power_usage);
739246789Shselasky	if (error)
740246789Shselasky		power_usage = 0;
741246789Shselasky	return (power_usage);
742246789Shselasky}
743246789Shselasky
744184610Salfredint
745184610Salfredlibusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
746184610Salfred{
747184610Salfred	int error;
748184610Salfred
749188622Sthompsa	error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
750184610Salfred	return (error);
751184610Salfred}
752184610Salfred
753184610Salfredint
754184610Salfredlibusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
755184610Salfred{
756184610Salfred	int error;
757184610Salfred
758188622Sthompsa	error = pdev->methods->set_config_index(pdev, configIndex);
759184610Salfred	return (error);
760184610Salfred}
761184610Salfred
762184610Salfredint
763184610Salfredlibusb20_dev_request_sync(struct libusb20_device *pdev,
764184610Salfred    struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
765184610Salfred    uint16_t *pactlen, uint32_t timeout, uint8_t flags)
766184610Salfred{
767184610Salfred	int error;
768184610Salfred
769188622Sthompsa	error = pdev->methods->do_request_sync(pdev,
770184610Salfred	    setup, data, pactlen, timeout, flags);
771184610Salfred	return (error);
772184610Salfred}
773184610Salfred
774184610Salfredint
775184610Salfredlibusb20_dev_req_string_sync(struct libusb20_device *pdev,
776185087Salfred    uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
777184610Salfred{
778184610Salfred	struct LIBUSB20_CONTROL_SETUP_DECODED req;
779184610Salfred	int error;
780184610Salfred
781199055Sthompsa	/* make sure memory is initialised */
782199055Sthompsa	memset(ptr, 0, len);
783199055Sthompsa
784184610Salfred	if (len < 4) {
785184610Salfred		/* invalid length */
786184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
787184610Salfred	}
788184610Salfred	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
789184610Salfred
790184610Salfred	/*
791184610Salfred	 * We need to read the USB string in two steps else some USB
792184610Salfred	 * devices will complain.
793184610Salfred	 */
794184610Salfred	req.bmRequestType =
795184610Salfred	    LIBUSB20_REQUEST_TYPE_STANDARD |
796184610Salfred	    LIBUSB20_RECIPIENT_DEVICE |
797184610Salfred	    LIBUSB20_ENDPOINT_IN;
798184610Salfred	req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
799185087Salfred	req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
800184610Salfred	req.wIndex = langid;
801184610Salfred	req.wLength = 4;		/* bytes */
802184610Salfred
803184610Salfred	error = libusb20_dev_request_sync(pdev, &req,
804184610Salfred	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
805184610Salfred	if (error) {
806184610Salfred		return (error);
807184610Salfred	}
808184610Salfred	req.wLength = *(uint8_t *)ptr;	/* bytes */
809184610Salfred	if (req.wLength > len) {
810184610Salfred		/* partial string read */
811184610Salfred		req.wLength = len;
812184610Salfred	}
813184610Salfred	error = libusb20_dev_request_sync(pdev, &req,
814184610Salfred	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
815184610Salfred
816184610Salfred	if (error) {
817184610Salfred		return (error);
818184610Salfred	}
819184610Salfred	if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
820184610Salfred		return (LIBUSB20_ERROR_OTHER);
821184610Salfred	}
822184610Salfred	return (0);			/* success */
823184610Salfred}
824184610Salfred
825184610Salfredint
826184610Salfredlibusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
827185087Salfred    uint8_t str_index, void *ptr, uint16_t len)
828184610Salfred{
829184610Salfred	char *buf;
830184610Salfred	int error;
831184610Salfred	uint16_t langid;
832184610Salfred	uint16_t n;
833184610Salfred	uint16_t i;
834184610Salfred	uint16_t c;
835184610Salfred	uint8_t temp[255];
836184610Salfred	uint8_t swap;
837184610Salfred
838184610Salfred	/* the following code derives from the FreeBSD USB kernel */
839184610Salfred
840184610Salfred	if ((len < 1) || (ptr == NULL)) {
841184610Salfred		/* too short buffer */
842184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
843184610Salfred	}
844184610Salfred	error = libusb20_dev_req_string_sync(pdev,
845184610Salfred	    0, 0, temp, sizeof(temp));
846185087Salfred	if (error < 0) {
847185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
848184610Salfred		return (error);
849185087Salfred	}
850184610Salfred	langid = temp[2] | (temp[3] << 8);
851184610Salfred
852185087Salfred	error = libusb20_dev_req_string_sync(pdev, str_index,
853184610Salfred	    langid, temp, sizeof(temp));
854185087Salfred	if (error < 0) {
855185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
856184610Salfred		return (error);
857185087Salfred	}
858184610Salfred	if (temp[0] < 2) {
859184610Salfred		/* string length is too short */
860185087Salfred		*(uint8_t *)ptr = 0;	/* zero terminate */
861184610Salfred		return (LIBUSB20_ERROR_OTHER);
862184610Salfred	}
863184610Salfred	/* reserve one byte for terminating zero */
864184610Salfred	len--;
865184610Salfred
866184610Salfred	/* find maximum length */
867184610Salfred	n = (temp[0] / 2) - 1;
868184610Salfred	if (n > len) {
869184610Salfred		n = len;
870184610Salfred	}
871184610Salfred	/* reset swap state */
872184610Salfred	swap = 3;
873184610Salfred
874184610Salfred	/* setup output buffer pointer */
875184610Salfred	buf = ptr;
876184610Salfred
877184610Salfred	/* convert and filter */
878184610Salfred	for (i = 0; (i != n); i++) {
879184610Salfred		c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
880184610Salfred
881184610Salfred		/* convert from Unicode, handle buggy strings */
882184610Salfred		if (((c & 0xff00) == 0) && (swap & 1)) {
883184610Salfred			/* Little Endian, default */
884184610Salfred			*buf = c;
885184610Salfred			swap = 1;
886184610Salfred		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
887184610Salfred			/* Big Endian */
888184610Salfred			*buf = c >> 8;
889184610Salfred			swap = 2;
890184610Salfred		} else {
891185087Salfred			/* skip invalid character */
892185087Salfred			continue;
893184610Salfred		}
894184610Salfred		/*
895184610Salfred		 * Filter by default - we don't allow greater and less than
896184610Salfred		 * signs because they might confuse the dmesg printouts!
897184610Salfred		 */
898184610Salfred		if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
899185087Salfred			/* skip invalid character */
900185087Salfred			continue;
901184610Salfred		}
902184610Salfred		buf++;
903184610Salfred	}
904184610Salfred	*buf = 0;			/* zero terminate string */
905184610Salfred
906184610Salfred	return (0);
907184610Salfred}
908184610Salfred
909184610Salfredstruct libusb20_config *
910184610Salfredlibusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
911184610Salfred{
912184610Salfred	struct libusb20_config *retval = NULL;
913184610Salfred	uint8_t *ptr;
914184610Salfred	uint16_t len;
915184610Salfred	uint8_t do_close;
916184610Salfred	int error;
917184610Salfred
918184610Salfred	if (!pdev->is_opened) {
919184610Salfred		error = libusb20_dev_open(pdev, 0);
920184610Salfred		if (error) {
921184610Salfred			return (NULL);
922184610Salfred		}
923184610Salfred		do_close = 1;
924184610Salfred	} else {
925184610Salfred		do_close = 0;
926184610Salfred	}
927188622Sthompsa	error = pdev->methods->get_config_desc_full(pdev,
928184610Salfred	    &ptr, &len, configIndex);
929184610Salfred
930184610Salfred	if (error) {
931184610Salfred		goto done;
932184610Salfred	}
933184610Salfred	/* parse new config descriptor */
934184610Salfred	retval = libusb20_parse_config_desc(ptr);
935184610Salfred
936184610Salfred	/* free config descriptor */
937184610Salfred	free(ptr);
938184610Salfred
939184610Salfreddone:
940184610Salfred	if (do_close) {
941184610Salfred		error = libusb20_dev_close(pdev);
942184610Salfred	}
943184610Salfred	return (retval);
944184610Salfred}
945184610Salfred
946184610Salfredstruct libusb20_device *
947184610Salfredlibusb20_dev_alloc(void)
948184610Salfred{
949184610Salfred	struct libusb20_device *pdev;
950184610Salfred
951184610Salfred	pdev = malloc(sizeof(*pdev));
952184610Salfred	if (pdev == NULL) {
953184610Salfred		return (NULL);
954184610Salfred	}
955184610Salfred	memset(pdev, 0, sizeof(*pdev));
956184610Salfred
957184610Salfred	pdev->file = -1;
958184610Salfred	pdev->file_ctrl = -1;
959184610Salfred	pdev->methods = &libusb20_dummy_methods;
960184610Salfred	return (pdev);
961184610Salfred}
962184610Salfred
963184610Salfreduint8_t
964184610Salfredlibusb20_dev_get_config_index(struct libusb20_device *pdev)
965184610Salfred{
966184610Salfred	int error;
967185087Salfred	uint8_t cfg_index;
968184610Salfred	uint8_t do_close;
969184610Salfred
970184610Salfred	if (!pdev->is_opened) {
971184610Salfred		error = libusb20_dev_open(pdev, 0);
972184610Salfred		if (error == 0) {
973184610Salfred			do_close = 1;
974184610Salfred		} else {
975184610Salfred			do_close = 0;
976184610Salfred		}
977184610Salfred	} else {
978184610Salfred		do_close = 0;
979184610Salfred	}
980184610Salfred
981188622Sthompsa	error = pdev->methods->get_config_index(pdev, &cfg_index);
982234491Shselasky	if (error)
983234491Shselasky		cfg_index = 0xFF;	/* current config index */
984184610Salfred	if (do_close) {
985184610Salfred		if (libusb20_dev_close(pdev)) {
986184610Salfred			/* ignore */
987184610Salfred		}
988184610Salfred	}
989185087Salfred	return (cfg_index);
990184610Salfred}
991184610Salfred
992184610Salfreduint8_t
993184610Salfredlibusb20_dev_get_mode(struct libusb20_device *pdev)
994184610Salfred{
995184610Salfred	return (pdev->usb_mode);
996184610Salfred}
997184610Salfred
998184610Salfreduint8_t
999184610Salfredlibusb20_dev_get_speed(struct libusb20_device *pdev)
1000184610Salfred{
1001184610Salfred	return (pdev->usb_speed);
1002184610Salfred}
1003184610Salfred
1004184610Salfred/* if this function returns an error, the device is gone */
1005184610Salfredint
1006184610Salfredlibusb20_dev_process(struct libusb20_device *pdev)
1007184610Salfred{
1008184610Salfred	int error;
1009184610Salfred
1010188622Sthompsa	error = pdev->methods->process(pdev);
1011184610Salfred	return (error);
1012184610Salfred}
1013184610Salfred
1014184610Salfredvoid
1015184610Salfredlibusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
1016184610Salfred{
1017185087Salfred	struct pollfd pfd[1];
1018184610Salfred
1019184610Salfred	if (!pdev->is_opened) {
1020184610Salfred		return;
1021184610Salfred	}
1022184610Salfred	pfd[0].fd = pdev->file;
1023184610Salfred	pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
1024184610Salfred	pfd[0].revents = 0;
1025184610Salfred
1026185087Salfred	if (poll(pfd, 1, timeout)) {
1027184610Salfred		/* ignore any error */
1028184610Salfred	}
1029184610Salfred	return;
1030184610Salfred}
1031184610Salfred
1032184610Salfredvoid
1033184610Salfredlibusb20_dev_free(struct libusb20_device *pdev)
1034184610Salfred{
1035184610Salfred	if (pdev == NULL) {
1036184610Salfred		/* be NULL safe */
1037184610Salfred		return;
1038184610Salfred	}
1039184610Salfred	if (pdev->is_opened) {
1040184610Salfred		if (libusb20_dev_close(pdev)) {
1041184610Salfred			/* ignore any errors */
1042184610Salfred		}
1043184610Salfred	}
1044184610Salfred	free(pdev);
1045184610Salfred	return;
1046184610Salfred}
1047184610Salfred
1048188622Sthompsaint
1049188622Sthompsalibusb20_dev_get_info(struct libusb20_device *pdev,
1050192984Sthompsa    struct usb_device_info *pinfo)
1051188622Sthompsa{
1052188622Sthompsa	if (pinfo == NULL)
1053188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
1054188622Sthompsa
1055188622Sthompsa	return (pdev->beMethods->dev_get_info(pdev, pinfo));
1056188622Sthompsa}
1057188622Sthompsa
1058184610Salfredconst char *
1059184610Salfredlibusb20_dev_get_backend_name(struct libusb20_device *pdev)
1060184610Salfred{
1061188622Sthompsa	return (pdev->beMethods->get_backend_name());
1062184610Salfred}
1063184610Salfred
1064184610Salfredconst char *
1065184610Salfredlibusb20_dev_get_desc(struct libusb20_device *pdev)
1066184610Salfred{
1067184610Salfred	return (pdev->usb_desc);
1068184610Salfred}
1069184610Salfred
1070184610Salfredvoid
1071184610Salfredlibusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
1072184610Salfred{
1073184610Salfred	pdev->debug = debug;
1074184610Salfred	return;
1075184610Salfred}
1076184610Salfred
1077184610Salfredint
1078184610Salfredlibusb20_dev_get_debug(struct libusb20_device *pdev)
1079184610Salfred{
1080184610Salfred	return (pdev->debug);
1081184610Salfred}
1082184610Salfred
1083184610Salfreduint8_t
1084184610Salfredlibusb20_dev_get_address(struct libusb20_device *pdev)
1085184610Salfred{
1086184610Salfred	return (pdev->device_address);
1087184610Salfred}
1088184610Salfred
1089184610Salfreduint8_t
1090223495Shselaskylibusb20_dev_get_parent_address(struct libusb20_device *pdev)
1091223495Shselasky{
1092223495Shselasky	return (pdev->parent_address);
1093223495Shselasky}
1094223495Shselasky
1095223495Shselaskyuint8_t
1096223495Shselaskylibusb20_dev_get_parent_port(struct libusb20_device *pdev)
1097223495Shselasky{
1098223495Shselasky	return (pdev->parent_port);
1099223495Shselasky}
1100223495Shselasky
1101223495Shselaskyuint8_t
1102184610Salfredlibusb20_dev_get_bus_number(struct libusb20_device *pdev)
1103184610Salfred{
1104184610Salfred	return (pdev->bus_number);
1105184610Salfred}
1106184610Salfred
1107184610Salfredint
1108188622Sthompsalibusb20_dev_get_iface_desc(struct libusb20_device *pdev,
1109188622Sthompsa    uint8_t iface_index, char *buf, uint8_t len)
1110188622Sthompsa{
1111188622Sthompsa	if ((buf == NULL) || (len == 0))
1112188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
1113188622Sthompsa
1114224085Shselasky	buf[0] = 0;		/* set default string value */
1115224085Shselasky
1116188622Sthompsa	return (pdev->beMethods->dev_get_iface_desc(
1117188622Sthompsa	    pdev, iface_index, buf, len));
1118188622Sthompsa}
1119188622Sthompsa
1120184610Salfred/* USB backend operations */
1121184610Salfred
1122184610Salfredint
1123184610Salfredlibusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
1124185087Salfred    uint16_t quirk_index, struct libusb20_quirk *pq)
1125184610Salfred{
1126188622Sthompsa	return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
1127184610Salfred}
1128184610Salfred
1129184610Salfredint
1130184610Salfredlibusb20_be_get_quirk_name(struct libusb20_backend *pbe,
1131185087Salfred    uint16_t quirk_index, struct libusb20_quirk *pq)
1132184610Salfred{
1133188622Sthompsa	return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
1134184610Salfred}
1135184610Salfred
1136184610Salfredint
1137184610Salfredlibusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
1138184610Salfred    struct libusb20_quirk *pq)
1139184610Salfred{
1140188622Sthompsa	return (pbe->methods->root_add_dev_quirk(pbe, pq));
1141184610Salfred}
1142184610Salfred
1143184610Salfredint
1144184610Salfredlibusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
1145184610Salfred    struct libusb20_quirk *pq)
1146184610Salfred{
1147188622Sthompsa	return (pbe->methods->root_remove_dev_quirk(pbe, pq));
1148184610Salfred}
1149184610Salfred
1150184610Salfredint
1151188987Sthompsalibusb20_be_set_template(struct libusb20_backend *pbe, int temp)
1152188987Sthompsa{
1153188987Sthompsa	return (pbe->methods->root_set_template(pbe, temp));
1154188987Sthompsa}
1155188987Sthompsa
1156188987Sthompsaint
1157188987Sthompsalibusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
1158188987Sthompsa{
1159188987Sthompsa	int temp;
1160188987Sthompsa
1161188987Sthompsa	if (ptemp == NULL)
1162188987Sthompsa		ptemp = &temp;
1163188987Sthompsa
1164188987Sthompsa	return (pbe->methods->root_get_template(pbe, ptemp));
1165188987Sthompsa}
1166188987Sthompsa
1167184610Salfredstruct libusb20_device *
1168184610Salfredlibusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1169184610Salfred{
1170184610Salfred	if (pbe == NULL) {
1171184610Salfred		pdev = NULL;
1172184610Salfred	} else if (pdev == NULL) {
1173184610Salfred		pdev = TAILQ_FIRST(&(pbe->usb_devs));
1174184610Salfred	} else {
1175184610Salfred		pdev = TAILQ_NEXT(pdev, dev_entry);
1176184610Salfred	}
1177184610Salfred	return (pdev);
1178184610Salfred}
1179184610Salfred
1180184610Salfredstruct libusb20_backend *
1181184610Salfredlibusb20_be_alloc(const struct libusb20_backend_methods *methods)
1182184610Salfred{
1183184610Salfred	struct libusb20_backend *pbe;
1184184610Salfred
1185184610Salfred	pbe = malloc(sizeof(*pbe));
1186184610Salfred	if (pbe == NULL) {
1187184610Salfred		return (NULL);
1188184610Salfred	}
1189184610Salfred	memset(pbe, 0, sizeof(*pbe));
1190184610Salfred
1191184610Salfred	TAILQ_INIT(&(pbe->usb_devs));
1192184610Salfred
1193184610Salfred	pbe->methods = methods;		/* set backend methods */
1194184610Salfred
1195184610Salfred	/* do the initial device scan */
1196184610Salfred	if (pbe->methods->init_backend) {
1197188622Sthompsa		pbe->methods->init_backend(pbe);
1198184610Salfred	}
1199184610Salfred	return (pbe);
1200184610Salfred}
1201184610Salfred
1202184610Salfredstruct libusb20_backend *
1203184610Salfredlibusb20_be_alloc_linux(void)
1204184610Salfred{
1205253339Shselasky	return (NULL);
1206184610Salfred}
1207184610Salfred
1208184610Salfredstruct libusb20_backend *
1209184610Salfredlibusb20_be_alloc_ugen20(void)
1210184610Salfred{
1211253339Shselasky	return (libusb20_be_alloc(&libusb20_ugen20_backend));
1212184610Salfred}
1213184610Salfred
1214184610Salfredstruct libusb20_backend *
1215184610Salfredlibusb20_be_alloc_default(void)
1216184610Salfred{
1217184610Salfred	struct libusb20_backend *pbe;
1218184610Salfred
1219253339Shselasky#ifdef __linux__
1220184610Salfred	pbe = libusb20_be_alloc_linux();
1221184610Salfred	if (pbe) {
1222184610Salfred		return (pbe);
1223184610Salfred	}
1224253339Shselasky#endif
1225184610Salfred	pbe = libusb20_be_alloc_ugen20();
1226184610Salfred	if (pbe) {
1227184610Salfred		return (pbe);
1228184610Salfred	}
1229184610Salfred	return (NULL);			/* no backend found */
1230184610Salfred}
1231184610Salfred
1232184610Salfredvoid
1233184610Salfredlibusb20_be_free(struct libusb20_backend *pbe)
1234184610Salfred{
1235184610Salfred	struct libusb20_device *pdev;
1236184610Salfred
1237184610Salfred	if (pbe == NULL) {
1238184610Salfred		/* be NULL safe */
1239184610Salfred		return;
1240184610Salfred	}
1241184610Salfred	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1242184610Salfred		libusb20_be_dequeue_device(pbe, pdev);
1243184610Salfred		libusb20_dev_free(pdev);
1244184610Salfred	}
1245184610Salfred	if (pbe->methods->exit_backend) {
1246188622Sthompsa		pbe->methods->exit_backend(pbe);
1247184610Salfred	}
1248199055Sthompsa	/* free backend */
1249199055Sthompsa	free(pbe);
1250184610Salfred}
1251184610Salfred
1252184610Salfredvoid
1253184610Salfredlibusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1254184610Salfred{
1255184610Salfred	pdev->beMethods = pbe->methods;	/* copy backend methods */
1256184610Salfred	TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1257184610Salfred}
1258184610Salfred
1259184610Salfredvoid
1260184610Salfredlibusb20_be_dequeue_device(struct libusb20_backend *pbe,
1261184610Salfred    struct libusb20_device *pdev)
1262184610Salfred{
1263184610Salfred	TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
1264184610Salfred}
1265225659Shselasky
1266225659Shselaskyconst char *
1267225659Shselaskylibusb20_strerror(int code)
1268225659Shselasky{
1269225659Shselasky	switch (code) {
1270225659Shselasky	case LIBUSB20_SUCCESS:
1271225659Shselasky		return ("Success");
1272225659Shselasky	case LIBUSB20_ERROR_IO:
1273225659Shselasky		return ("I/O error");
1274225659Shselasky	case LIBUSB20_ERROR_INVALID_PARAM:
1275225659Shselasky		return ("Invalid parameter");
1276225659Shselasky	case LIBUSB20_ERROR_ACCESS:
1277225659Shselasky		return ("Permissions error");
1278225659Shselasky	case LIBUSB20_ERROR_NO_DEVICE:
1279225659Shselasky		return ("No device");
1280225659Shselasky	case LIBUSB20_ERROR_NOT_FOUND:
1281225659Shselasky		return ("Not found");
1282225659Shselasky	case LIBUSB20_ERROR_BUSY:
1283225659Shselasky		return ("Device busy");
1284225659Shselasky	case LIBUSB20_ERROR_TIMEOUT:
1285225659Shselasky		return ("Timeout");
1286225659Shselasky	case LIBUSB20_ERROR_OVERFLOW:
1287225659Shselasky		return ("Overflow");
1288225659Shselasky	case LIBUSB20_ERROR_PIPE:
1289225659Shselasky		return ("Pipe error");
1290225659Shselasky	case LIBUSB20_ERROR_INTERRUPTED:
1291225659Shselasky		return ("Interrupted");
1292225659Shselasky	case LIBUSB20_ERROR_NO_MEM:
1293225659Shselasky		return ("Out of memory");
1294225659Shselasky	case LIBUSB20_ERROR_NOT_SUPPORTED:
1295225659Shselasky		return ("Not supported");
1296225659Shselasky	case LIBUSB20_ERROR_OTHER:
1297225659Shselasky		return ("Other error");
1298225659Shselasky	default:
1299225659Shselasky		return ("Unknown error");
1300225659Shselasky	}
1301225659Shselasky}
1302225659Shselasky
1303225659Shselaskyconst char *
1304225659Shselaskylibusb20_error_name(int code)
1305225659Shselasky{
1306225659Shselasky	switch (code) {
1307225659Shselasky	case LIBUSB20_SUCCESS:
1308225659Shselasky		return ("LIBUSB20_SUCCESS");
1309225659Shselasky	case LIBUSB20_ERROR_IO:
1310225659Shselasky		return ("LIBUSB20_ERROR_IO");
1311225659Shselasky	case LIBUSB20_ERROR_INVALID_PARAM:
1312225659Shselasky		return ("LIBUSB20_ERROR_INVALID_PARAM");
1313225659Shselasky	case LIBUSB20_ERROR_ACCESS:
1314225659Shselasky		return ("LIBUSB20_ERROR_ACCESS");
1315225659Shselasky	case LIBUSB20_ERROR_NO_DEVICE:
1316225659Shselasky		return ("LIBUSB20_ERROR_NO_DEVICE");
1317225659Shselasky	case LIBUSB20_ERROR_NOT_FOUND:
1318225659Shselasky		return ("LIBUSB20_ERROR_NOT_FOUND");
1319225659Shselasky	case LIBUSB20_ERROR_BUSY:
1320225659Shselasky		return ("LIBUSB20_ERROR_BUSY");
1321225659Shselasky	case LIBUSB20_ERROR_TIMEOUT:
1322225659Shselasky		return ("LIBUSB20_ERROR_TIMEOUT");
1323225659Shselasky	case LIBUSB20_ERROR_OVERFLOW:
1324225659Shselasky		return ("LIBUSB20_ERROR_OVERFLOW");
1325225659Shselasky	case LIBUSB20_ERROR_PIPE:
1326225659Shselasky		return ("LIBUSB20_ERROR_PIPE");
1327225659Shselasky	case LIBUSB20_ERROR_INTERRUPTED:
1328225659Shselasky		return ("LIBUSB20_ERROR_INTERRUPTED");
1329225659Shselasky	case LIBUSB20_ERROR_NO_MEM:
1330225659Shselasky		return ("LIBUSB20_ERROR_NO_MEM");
1331225659Shselasky	case LIBUSB20_ERROR_NOT_SUPPORTED:
1332225659Shselasky		return ("LIBUSB20_ERROR_NOT_SUPPORTED");
1333225659Shselasky	case LIBUSB20_ERROR_OTHER:
1334225659Shselasky		return ("LIBUSB20_ERROR_OTHER");
1335225659Shselasky	default:
1336225659Shselasky		return ("LIBUSB20_ERROR_UNKNOWN");
1337225659Shselasky	}
1338225659Shselasky}
1339