1/* $FreeBSD$ */
2/*-
3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 *
5 * Copyright (c) 2008-2009 Hans Petter Selasky. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#ifdef LIBUSB_GLOBAL_INCLUDE_FILE
30#include LIBUSB_GLOBAL_INCLUDE_FILE
31#else
32#include <ctype.h>
33#include <poll.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <time.h>
38#include <sys/queue.h>
39#endif
40
41#include "libusb20.h"
42#include "libusb20_desc.h"
43#include "libusb20_int.h"
44
45static int
46dummy_int(void)
47{
48	return (LIBUSB20_ERROR_NOT_SUPPORTED);
49}
50
51static void
52dummy_void(void)
53{
54	return;
55}
56
57static void
58dummy_callback(struct libusb20_transfer *xfer)
59{
60	;				/* style fix */
61	switch (libusb20_tr_get_status(xfer)) {
62	case LIBUSB20_TRANSFER_START:
63		libusb20_tr_submit(xfer);
64		break;
65	default:
66		/* complete or error */
67		break;
68	}
69	return;
70}
71
72#define	dummy_get_config_desc_full (void *)dummy_int
73#define	dummy_get_config_index (void *)dummy_int
74#define	dummy_set_config_index (void *)dummy_int
75#define	dummy_set_alt_index (void *)dummy_int
76#define	dummy_reset_device (void *)dummy_int
77#define	dummy_check_connected (void *)dummy_int
78#define	dummy_set_power_mode (void *)dummy_int
79#define	dummy_get_power_mode (void *)dummy_int
80#define	dummy_get_power_usage (void *)dummy_int
81#define	dummy_get_stats (void *)dummy_int
82#define	dummy_kernel_driver_active (void *)dummy_int
83#define	dummy_detach_kernel_driver (void *)dummy_int
84#define	dummy_do_request_sync (void *)dummy_int
85#define	dummy_tr_open (void *)dummy_int
86#define	dummy_tr_close (void *)dummy_int
87#define	dummy_tr_clear_stall_sync (void *)dummy_int
88#define	dummy_process (void *)dummy_int
89#define	dummy_dev_info (void *)dummy_int
90#define	dummy_dev_get_iface_driver (void *)dummy_int
91
92#define	dummy_tr_submit (void *)dummy_void
93#define	dummy_tr_cancel_async (void *)dummy_void
94
95static const struct libusb20_device_methods libusb20_dummy_methods = {
96	LIBUSB20_DEVICE(LIBUSB20_DECLARE, dummy)
97};
98
99void
100libusb20_tr_callback_wrapper(struct libusb20_transfer *xfer)
101{
102	;				/* style fix */
103
104repeat:
105
106	if (!xfer->is_pending) {
107		xfer->status = LIBUSB20_TRANSFER_START;
108	} else {
109		xfer->is_pending = 0;
110	}
111
112	xfer->callback(xfer);
113
114	if (xfer->is_restart) {
115		xfer->is_restart = 0;
116		goto repeat;
117	}
118	if (xfer->is_draining &&
119	    (!xfer->is_pending)) {
120		xfer->is_draining = 0;
121		xfer->status = LIBUSB20_TRANSFER_DRAINED;
122		xfer->callback(xfer);
123	}
124	return;
125}
126
127int
128libusb20_tr_close(struct libusb20_transfer *xfer)
129{
130	int error;
131
132	if (!xfer->is_opened) {
133		return (LIBUSB20_ERROR_OTHER);
134	}
135	error = xfer->pdev->methods->tr_close(xfer);
136
137	if (xfer->pLength) {
138		free(xfer->pLength);
139	}
140	if (xfer->ppBuffer) {
141		free(xfer->ppBuffer);
142	}
143	/* reset variable fields in case the transfer is opened again */
144	xfer->priv_sc0 = NULL;
145	xfer->priv_sc1 = NULL;
146	xfer->is_opened = 0;
147	xfer->is_pending = 0;
148	xfer->is_cancel = 0;
149	xfer->is_draining = 0;
150	xfer->is_restart = 0;
151	xfer->status = 0;
152	xfer->flags = 0;
153	xfer->nFrames = 0;
154	xfer->aFrames = 0;
155	xfer->timeout = 0;
156	xfer->maxFrames = 0;
157	xfer->maxTotalLength = 0;
158	xfer->maxPacketLen = 0;
159	return (error);
160}
161
162int
163libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
164    uint32_t MaxFrameCount, uint8_t ep_no)
165{
166	return (libusb20_tr_open_stream(xfer, MaxBufSize, MaxFrameCount, ep_no, 0));
167}
168
169int
170libusb20_tr_open_stream(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
171    uint32_t MaxFrameCount, uint8_t ep_no, uint16_t stream_id)
172{
173	uint32_t size;
174	uint8_t pre_scale;
175	int error;
176
177	if (xfer->is_opened)
178		return (LIBUSB20_ERROR_BUSY);
179	if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) {
180		MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE;
181		/*
182		 * The kernel can setup 8 times more frames when
183		 * pre-scaling ISOCHRONOUS transfers. Make sure the
184		 * length and pointer buffers are big enough:
185		 */
186		MaxFrameCount *= 8;
187		pre_scale = 1;
188	} else {
189		pre_scale = 0;
190	}
191	if (MaxFrameCount == 0)
192		return (LIBUSB20_ERROR_INVALID_PARAM);
193
194	xfer->maxFrames = MaxFrameCount;
195
196	size = MaxFrameCount * sizeof(xfer->pLength[0]);
197	xfer->pLength = malloc(size);
198	if (xfer->pLength == NULL) {
199		return (LIBUSB20_ERROR_NO_MEM);
200	}
201	memset(xfer->pLength, 0, size);
202
203	size = MaxFrameCount * sizeof(xfer->ppBuffer[0]);
204	xfer->ppBuffer = malloc(size);
205	if (xfer->ppBuffer == NULL) {
206		free(xfer->pLength);
207		return (LIBUSB20_ERROR_NO_MEM);
208	}
209	memset(xfer->ppBuffer, 0, size);
210
211	if (pre_scale) {
212		error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
213		    MaxFrameCount / 8, ep_no, stream_id, 1);
214	} else {
215		error = xfer->pdev->methods->tr_open(xfer, MaxBufSize,
216		    MaxFrameCount, ep_no, stream_id, 0);
217	}
218
219	if (error) {
220		free(xfer->ppBuffer);
221		free(xfer->pLength);
222	} else {
223		xfer->is_opened = 1;
224	}
225	return (error);
226}
227
228struct libusb20_transfer *
229libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t trIndex)
230{
231	if (trIndex >= pdev->nTransfer) {
232		return (NULL);
233	}
234	return (pdev->pTransfer + trIndex);
235}
236
237uint32_t
238libusb20_tr_get_actual_frames(struct libusb20_transfer *xfer)
239{
240	return (xfer->aFrames);
241}
242
243uint16_t
244libusb20_tr_get_time_complete(struct libusb20_transfer *xfer)
245{
246	return (xfer->timeComplete);
247}
248
249uint32_t
250libusb20_tr_get_actual_length(struct libusb20_transfer *xfer)
251{
252	uint32_t x;
253	uint32_t actlen = 0;
254
255	for (x = 0; x != xfer->aFrames; x++) {
256		actlen += xfer->pLength[x];
257	}
258	return (actlen);
259}
260
261uint32_t
262libusb20_tr_get_max_frames(struct libusb20_transfer *xfer)
263{
264	return (xfer->maxFrames);
265}
266
267uint32_t
268libusb20_tr_get_max_packet_length(struct libusb20_transfer *xfer)
269{
270	/*
271	 * Special Case NOTE: If the packet multiplier is non-zero for
272	 * High Speed USB, the value returned is equal to
273	 * "wMaxPacketSize * multiplier" !
274	 */
275	return (xfer->maxPacketLen);
276}
277
278uint32_t
279libusb20_tr_get_max_total_length(struct libusb20_transfer *xfer)
280{
281	return (xfer->maxTotalLength);
282}
283
284uint8_t
285libusb20_tr_get_status(struct libusb20_transfer *xfer)
286{
287	return (xfer->status);
288}
289
290uint8_t
291libusb20_tr_pending(struct libusb20_transfer *xfer)
292{
293	return (xfer->is_pending);
294}
295
296void   *
297libusb20_tr_get_priv_sc0(struct libusb20_transfer *xfer)
298{
299	return (xfer->priv_sc0);
300}
301
302void   *
303libusb20_tr_get_priv_sc1(struct libusb20_transfer *xfer)
304{
305	return (xfer->priv_sc1);
306}
307
308void
309libusb20_tr_stop(struct libusb20_transfer *xfer)
310{
311	if (!xfer->is_opened) {
312		/* transfer is not opened */
313		return;
314	}
315	if (!xfer->is_pending) {
316		/* transfer not pending */
317		return;
318	}
319	if (xfer->is_cancel) {
320		/* already cancelling */
321		return;
322	}
323	xfer->is_cancel = 1;		/* we are cancelling */
324
325	xfer->pdev->methods->tr_cancel_async(xfer);
326	return;
327}
328
329void
330libusb20_tr_drain(struct libusb20_transfer *xfer)
331{
332	if (!xfer->is_opened) {
333		/* transfer is not opened */
334		return;
335	}
336	/* make sure that we are cancelling */
337	libusb20_tr_stop(xfer);
338
339	if (xfer->is_pending) {
340		xfer->is_draining = 1;
341	}
342	return;
343}
344
345void
346libusb20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
347{
348	xfer->pdev->methods->tr_clear_stall_sync(xfer);
349	return;
350}
351
352void
353libusb20_tr_set_buffer(struct libusb20_transfer *xfer, void *buffer, uint16_t frIndex)
354{
355	xfer->ppBuffer[frIndex] = libusb20_pass_ptr(buffer);
356	return;
357}
358
359void
360libusb20_tr_set_callback(struct libusb20_transfer *xfer, libusb20_tr_callback_t *cb)
361{
362	xfer->callback = cb;
363	return;
364}
365
366void
367libusb20_tr_set_flags(struct libusb20_transfer *xfer, uint8_t flags)
368{
369	xfer->flags = flags;
370	return;
371}
372
373uint32_t
374libusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex)
375{
376	return (xfer->pLength[frIndex]);
377}
378
379void
380libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
381{
382	xfer->pLength[frIndex] = length;
383	return;
384}
385
386void
387libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
388{
389	xfer->priv_sc0 = sc0;
390	return;
391}
392
393void
394libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
395{
396	xfer->priv_sc1 = sc1;
397	return;
398}
399
400void
401libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
402{
403	xfer->timeout = timeout;
404	return;
405}
406
407void
408libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
409{
410	if (nFrames > xfer->maxFrames) {
411		/* should not happen */
412		nFrames = xfer->maxFrames;
413	}
414	xfer->nFrames = nFrames;
415	return;
416}
417
418void
419libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
420{
421	xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
422	xfer->pLength[0] = length;
423	xfer->timeout = timeout;
424	xfer->nFrames = 1;
425	return;
426}
427
428void
429libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
430{
431	uint16_t len;
432
433	xfer->ppBuffer[0] = libusb20_pass_ptr(psetup);
434	xfer->pLength[0] = 8;		/* fixed */
435	xfer->timeout = timeout;
436
437	len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
438
439	if (len != 0) {
440		xfer->nFrames = 2;
441		xfer->ppBuffer[1] = libusb20_pass_ptr(pBuf);
442		xfer->pLength[1] = len;
443	} else {
444		xfer->nFrames = 1;
445	}
446	return;
447}
448
449void
450libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
451{
452	xfer->ppBuffer[0] = libusb20_pass_ptr(pBuf);
453	xfer->pLength[0] = length;
454	xfer->timeout = timeout;
455	xfer->nFrames = 1;
456	return;
457}
458
459void
460libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
461{
462	if (frIndex >= xfer->maxFrames) {
463		/* should not happen */
464		return;
465	}
466	xfer->ppBuffer[frIndex] = libusb20_pass_ptr(pBuf);
467	xfer->pLength[frIndex] = length;
468	return;
469}
470
471uint8_t
472libusb20_tr_bulk_intr_sync(struct libusb20_transfer *xfer,
473    void *pbuf, uint32_t length, uint32_t *pactlen,
474    uint32_t timeout)
475{
476	struct libusb20_device *pdev = xfer->pdev;
477	uint32_t transfer_max;
478	uint32_t transfer_act;
479	uint8_t retval;
480
481	/* set some sensible default value */
482	if (pactlen != NULL)
483		*pactlen = 0;
484
485	/* check for error condition */
486	if (libusb20_tr_pending(xfer))
487		return (LIBUSB20_ERROR_OTHER);
488
489	do {
490		/* compute maximum transfer length */
491		transfer_max =
492		    libusb20_tr_get_max_total_length(xfer);
493
494		if (transfer_max > length)
495			transfer_max = length;
496
497		/* setup bulk or interrupt transfer */
498		libusb20_tr_setup_bulk(xfer, pbuf,
499		    transfer_max, timeout);
500
501		/* start the transfer */
502		libusb20_tr_start(xfer);
503
504		/* wait for transfer completion */
505		while (libusb20_dev_process(pdev) == 0) {
506
507			if (libusb20_tr_pending(xfer) == 0)
508				break;
509
510			libusb20_dev_wait_process(pdev, -1);
511		}
512
513		transfer_act = libusb20_tr_get_actual_length(xfer);
514
515		/* update actual length, if any */
516		if (pactlen != NULL)
517			pactlen[0] += transfer_act;
518
519		/* check transfer status */
520		retval = libusb20_tr_get_status(xfer);
521		if (retval)
522			break;
523
524		/* check for short transfer */
525		if (transfer_act != transfer_max)
526			break;
527
528		/* update buffer pointer and length */
529		pbuf = ((uint8_t *)pbuf) + transfer_max;
530		length = length - transfer_max;
531
532	} while (length != 0);
533
534	return (retval);
535}
536
537void
538libusb20_tr_submit(struct libusb20_transfer *xfer)
539{
540	if (!xfer->is_opened) {
541		/* transfer is not opened */
542		return;
543	}
544	if (xfer->is_pending) {
545		/* should not happen */
546		return;
547	}
548	xfer->is_pending = 1;		/* we are pending */
549	xfer->is_cancel = 0;		/* not cancelling */
550	xfer->is_restart = 0;		/* not restarting */
551
552	xfer->pdev->methods->tr_submit(xfer);
553	return;
554}
555
556void
557libusb20_tr_start(struct libusb20_transfer *xfer)
558{
559	if (!xfer->is_opened) {
560		/* transfer is not opened */
561		return;
562	}
563	if (xfer->is_pending) {
564		if (xfer->is_cancel) {
565			/* cancelling - restart */
566			xfer->is_restart = 1;
567		}
568		/* transfer not pending */
569		return;
570	}
571	/* get into the callback */
572	libusb20_tr_callback_wrapper(xfer);
573	return;
574}
575
576/* USB device operations */
577
578int
579libusb20_dev_close(struct libusb20_device *pdev)
580{
581	struct libusb20_transfer *xfer;
582	uint16_t x;
583	int error = 0;
584
585	if (!pdev->is_opened) {
586		return (LIBUSB20_ERROR_OTHER);
587	}
588	for (x = 0; x != pdev->nTransfer; x++) {
589		xfer = pdev->pTransfer + x;
590
591		if (!xfer->is_opened) {
592			/* transfer is not opened */
593			continue;
594		}
595
596		libusb20_tr_drain(xfer);
597
598		libusb20_tr_close(xfer);
599	}
600
601	if (pdev->pTransfer != NULL) {
602		free(pdev->pTransfer);
603		pdev->pTransfer = NULL;
604	}
605	error = pdev->beMethods->close_device(pdev);
606
607	pdev->methods = &libusb20_dummy_methods;
608
609	pdev->is_opened = 0;
610
611	/*
612	 * The following variable is only used by the libusb v0.1
613	 * compat layer:
614	 */
615	pdev->claimed_interface = 0;
616
617	/*
618	 * The following variable is only used by the libusb v1.0
619	 * compat layer:
620	 */
621	pdev->auto_detach = 0;
622
623	return (error);
624}
625
626int
627libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
628{
629	int error;
630
631	error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
632	return (error);
633}
634
635struct LIBUSB20_DEVICE_DESC_DECODED *
636libusb20_dev_get_device_desc(struct libusb20_device *pdev)
637{
638	return (&(pdev->ddesc));
639}
640
641int
642libusb20_dev_get_fd(struct libusb20_device *pdev)
643{
644	return (pdev->file);
645}
646
647int
648libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
649{
650	int error;
651
652	error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
653	return (error);
654}
655
656int
657libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
658{
659	struct libusb20_transfer *xfer;
660	uint32_t size;
661	uint16_t x;
662	int error;
663
664	if (pdev->is_opened) {
665		return (LIBUSB20_ERROR_BUSY);
666	}
667	if (nTransferMax >= 256) {
668		return (LIBUSB20_ERROR_INVALID_PARAM);
669	} else if (nTransferMax != 0) {
670		size = sizeof(pdev->pTransfer[0]) * nTransferMax;
671		pdev->pTransfer = malloc(size);
672		if (pdev->pTransfer == NULL) {
673			return (LIBUSB20_ERROR_NO_MEM);
674		}
675		memset(pdev->pTransfer, 0, size);
676	}
677	/* initialise all transfers */
678	for (x = 0; x != nTransferMax; x++) {
679
680		xfer = pdev->pTransfer + x;
681
682		xfer->pdev = pdev;
683		xfer->trIndex = x;
684		xfer->callback = &dummy_callback;
685	}
686
687	/* set "nTransfer" early */
688	pdev->nTransfer = nTransferMax;
689
690	error = pdev->beMethods->open_device(pdev, nTransferMax);
691
692	if (error) {
693		if (pdev->pTransfer != NULL) {
694			free(pdev->pTransfer);
695			pdev->pTransfer = NULL;
696		}
697		pdev->file = -1;
698		pdev->file_ctrl = -1;
699		pdev->nTransfer = 0;
700	} else {
701		pdev->is_opened = 1;
702	}
703	return (error);
704}
705
706int
707libusb20_dev_reset(struct libusb20_device *pdev)
708{
709	int error;
710
711	error = pdev->methods->reset_device(pdev);
712	return (error);
713}
714
715int
716libusb20_dev_check_connected(struct libusb20_device *pdev)
717{
718	int error;
719
720	error = pdev->methods->check_connected(pdev);
721	return (error);
722}
723
724int
725libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
726{
727	int error;
728
729	error = pdev->methods->set_power_mode(pdev, power_mode);
730	return (error);
731}
732
733uint8_t
734libusb20_dev_get_power_mode(struct libusb20_device *pdev)
735{
736	int error;
737	uint8_t power_mode;
738
739	error = pdev->methods->get_power_mode(pdev, &power_mode);
740	if (error)
741		power_mode = LIBUSB20_POWER_ON;	/* fake power mode */
742	return (power_mode);
743}
744
745int
746libusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
747{
748
749	if (pdev->port_level == 0) {
750		/*
751		 * Fallback for backends without port path:
752		 */
753		if (bufsize < 2)
754			return (LIBUSB20_ERROR_OVERFLOW);
755		buf[0] = pdev->parent_address;
756		buf[1] = pdev->parent_port;
757		return (2);
758	}
759
760	/* check if client buffer is too small */
761	if (pdev->port_level > bufsize)
762		return (LIBUSB20_ERROR_OVERFLOW);
763
764	/* copy port number information */
765	memcpy(buf, pdev->port_path, pdev->port_level);
766
767	return (pdev->port_level);	/* success */
768}
769
770uint16_t
771libusb20_dev_get_power_usage(struct libusb20_device *pdev)
772{
773	int error;
774	uint16_t power_usage;
775
776	error = pdev->methods->get_power_usage(pdev, &power_usage);
777	if (error)
778		power_usage = 0;
779	return (power_usage);
780}
781
782int
783libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
784{
785	int error;
786
787	error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
788	return (error);
789}
790
791int
792libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
793{
794	int error;
795
796	error = pdev->methods->set_config_index(pdev, configIndex);
797	return (error);
798}
799
800int
801libusb20_dev_request_sync(struct libusb20_device *pdev,
802    struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
803    uint16_t *pactlen, uint32_t timeout, uint8_t flags)
804{
805	int error;
806
807	error = pdev->methods->do_request_sync(pdev,
808	    setup, data, pactlen, timeout, flags);
809	return (error);
810}
811
812int
813libusb20_dev_req_string_sync(struct libusb20_device *pdev,
814    uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
815{
816	struct LIBUSB20_CONTROL_SETUP_DECODED req;
817	int error;
818	int flags;
819
820	/* make sure memory is initialised */
821	memset(ptr, 0, len);
822
823	if (len < 4) {
824		/* invalid length */
825		return (LIBUSB20_ERROR_INVALID_PARAM);
826	}
827	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
828
829	/*
830	 * We need to read the USB string in two steps else some USB
831	 * devices will complain.
832	 */
833	req.bmRequestType =
834	    LIBUSB20_REQUEST_TYPE_STANDARD |
835	    LIBUSB20_RECIPIENT_DEVICE |
836	    LIBUSB20_ENDPOINT_IN;
837	req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
838	req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
839	req.wIndex = langid;
840	req.wLength = 4;		/* bytes */
841
842	error = libusb20_dev_request_sync(pdev, &req,
843	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
844	if (error) {
845		/* try to request full string */
846		req.wLength = 255;
847		flags = 0;
848	} else {
849		/* extract length and request full string */
850		req.wLength = *(uint8_t *)ptr;
851		flags = LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK;
852	}
853	if (req.wLength > len) {
854		/* partial string read */
855		req.wLength = len;
856	}
857	error = libusb20_dev_request_sync(pdev, &req, ptr, NULL, 1000, flags);
858	if (error)
859		return (error);
860
861	if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING)
862		return (LIBUSB20_ERROR_OTHER);
863	return (0);			/* success */
864}
865
866int
867libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
868    uint8_t str_index, void *ptr, uint16_t len)
869{
870	char *buf;
871	int error;
872	uint16_t langid;
873	uint16_t n;
874	uint16_t i;
875	uint16_t c;
876	uint8_t temp[255];
877	uint8_t swap;
878
879	/* the following code derives from the FreeBSD USB kernel */
880
881	if ((len < 1) || (ptr == NULL)) {
882		/* too short buffer */
883		return (LIBUSB20_ERROR_INVALID_PARAM);
884	}
885	error = libusb20_dev_req_string_sync(pdev,
886	    0, 0, temp, sizeof(temp));
887	if (error < 0) {
888		*(uint8_t *)ptr = 0;	/* zero terminate */
889		return (error);
890	}
891	langid = temp[2] | (temp[3] << 8);
892
893	error = libusb20_dev_req_string_sync(pdev, str_index,
894	    langid, temp, sizeof(temp));
895	if (error < 0) {
896		*(uint8_t *)ptr = 0;	/* zero terminate */
897		return (error);
898	}
899	if (temp[0] < 2) {
900		/* string length is too short */
901		*(uint8_t *)ptr = 0;	/* zero terminate */
902		return (LIBUSB20_ERROR_OTHER);
903	}
904	/* reserve one byte for terminating zero */
905	len--;
906
907	/* find maximum length */
908	n = (temp[0] / 2) - 1;
909	if (n > len) {
910		n = len;
911	}
912	/* reset swap state */
913	swap = 3;
914
915	/* setup output buffer pointer */
916	buf = ptr;
917
918	/* convert and filter */
919	for (i = 0; (i != n); i++) {
920		c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
921
922		/* convert from Unicode, handle buggy strings */
923		if (((c & 0xff00) == 0) && (swap & 1)) {
924			/* Little Endian, default */
925			*buf = c;
926			swap = 1;
927		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
928			/* Big Endian */
929			*buf = c >> 8;
930			swap = 2;
931		} else {
932			/* skip invalid character */
933			continue;
934		}
935		/*
936		 * Filter by default - we don't allow greater and less than
937		 * signs because they might confuse the dmesg printouts!
938		 */
939		if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
940			/* skip invalid character */
941			continue;
942		}
943		buf++;
944	}
945	*buf = 0;			/* zero terminate string */
946
947	return (0);
948}
949
950struct libusb20_config *
951libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
952{
953	struct libusb20_config *retval = NULL;
954	uint8_t *ptr;
955	uint16_t len;
956	uint8_t do_close;
957	int error;
958
959	/*
960	 * Catch invalid configuration descriptor reads early on to
961	 * avoid issues with devices that don't check for a valid USB
962	 * configuration read request.
963	 */
964	if (configIndex >= pdev->ddesc.bNumConfigurations)
965		return (NULL);
966
967	if (!pdev->is_opened) {
968		error = libusb20_dev_open(pdev, 0);
969		if (error) {
970			return (NULL);
971		}
972		do_close = 1;
973	} else {
974		do_close = 0;
975	}
976	error = pdev->methods->get_config_desc_full(pdev,
977	    &ptr, &len, configIndex);
978
979	if (error) {
980		goto done;
981	}
982	/* parse new config descriptor */
983	retval = libusb20_parse_config_desc(ptr);
984
985	/* free config descriptor */
986	free(ptr);
987
988done:
989	if (do_close) {
990		error = libusb20_dev_close(pdev);
991	}
992	return (retval);
993}
994
995struct libusb20_device *
996libusb20_dev_alloc(void)
997{
998	struct libusb20_device *pdev;
999
1000	pdev = malloc(sizeof(*pdev));
1001	if (pdev == NULL) {
1002		return (NULL);
1003	}
1004	memset(pdev, 0, sizeof(*pdev));
1005
1006	pdev->file = -1;
1007	pdev->file_ctrl = -1;
1008	pdev->methods = &libusb20_dummy_methods;
1009	return (pdev);
1010}
1011
1012uint8_t
1013libusb20_dev_get_config_index(struct libusb20_device *pdev)
1014{
1015	int error;
1016	uint8_t cfg_index;
1017	uint8_t do_close;
1018
1019	if (!pdev->is_opened) {
1020		error = libusb20_dev_open(pdev, 0);
1021		if (error == 0) {
1022			do_close = 1;
1023		} else {
1024			do_close = 0;
1025		}
1026	} else {
1027		do_close = 0;
1028	}
1029
1030	error = pdev->methods->get_config_index(pdev, &cfg_index);
1031	if (error)
1032		cfg_index = 0xFF;	/* current config index */
1033	if (do_close) {
1034		if (libusb20_dev_close(pdev)) {
1035			/* ignore */
1036		}
1037	}
1038	return (cfg_index);
1039}
1040
1041uint8_t
1042libusb20_dev_get_mode(struct libusb20_device *pdev)
1043{
1044	return (pdev->usb_mode);
1045}
1046
1047uint8_t
1048libusb20_dev_get_speed(struct libusb20_device *pdev)
1049{
1050	return (pdev->usb_speed);
1051}
1052
1053int
1054libusb20_dev_get_stats(struct libusb20_device *pdev, struct libusb20_device_stats *pstats)
1055{
1056	uint8_t do_close;
1057	int error;
1058
1059	if (!pdev->is_opened) {
1060		error = libusb20_dev_open(pdev, 0);
1061		if (error == 0) {
1062			do_close = 1;
1063		} else {
1064			do_close = 0;
1065		}
1066	} else {
1067		do_close = 0;
1068	}
1069
1070	error = pdev->methods->get_stats(pdev, pstats);
1071
1072	if (do_close)
1073		(void) libusb20_dev_close(pdev);
1074
1075	return (error);
1076}
1077
1078/* if this function returns an error, the device is gone */
1079int
1080libusb20_dev_process(struct libusb20_device *pdev)
1081{
1082	int error;
1083
1084	error = pdev->methods->process(pdev);
1085	return (error);
1086}
1087
1088void
1089libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
1090{
1091	struct pollfd pfd[1];
1092
1093	if (!pdev->is_opened) {
1094		return;
1095	}
1096	pfd[0].fd = pdev->file;
1097	pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
1098	pfd[0].revents = 0;
1099
1100	if (poll(pfd, 1, timeout)) {
1101		/* ignore any error */
1102	}
1103	return;
1104}
1105
1106void
1107libusb20_dev_free(struct libusb20_device *pdev)
1108{
1109	if (pdev == NULL) {
1110		/* be NULL safe */
1111		return;
1112	}
1113	if (pdev->is_opened) {
1114		if (libusb20_dev_close(pdev)) {
1115			/* ignore any errors */
1116		}
1117	}
1118	free(pdev);
1119	return;
1120}
1121
1122int
1123libusb20_dev_get_info(struct libusb20_device *pdev,
1124    struct usb_device_info *pinfo)
1125{
1126	if (pinfo == NULL)
1127		return (LIBUSB20_ERROR_INVALID_PARAM);
1128
1129	return (pdev->beMethods->dev_get_info(pdev, pinfo));
1130}
1131
1132const char *
1133libusb20_dev_get_backend_name(struct libusb20_device *pdev)
1134{
1135	return (pdev->beMethods->get_backend_name());
1136}
1137
1138const char *
1139libusb20_dev_get_desc(struct libusb20_device *pdev)
1140{
1141	return (pdev->usb_desc);
1142}
1143
1144void
1145libusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
1146{
1147	pdev->debug = debug;
1148	return;
1149}
1150
1151int
1152libusb20_dev_get_debug(struct libusb20_device *pdev)
1153{
1154	return (pdev->debug);
1155}
1156
1157uint8_t
1158libusb20_dev_get_address(struct libusb20_device *pdev)
1159{
1160	return (pdev->device_address);
1161}
1162
1163uint8_t
1164libusb20_dev_get_parent_address(struct libusb20_device *pdev)
1165{
1166	return (pdev->parent_address);
1167}
1168
1169uint8_t
1170libusb20_dev_get_parent_port(struct libusb20_device *pdev)
1171{
1172	return (pdev->parent_port);
1173}
1174
1175uint8_t
1176libusb20_dev_get_bus_number(struct libusb20_device *pdev)
1177{
1178	return (pdev->bus_number);
1179}
1180
1181int
1182libusb20_dev_get_iface_desc(struct libusb20_device *pdev,
1183    uint8_t iface_index, char *buf, uint8_t len)
1184{
1185	if ((buf == NULL) || (len == 0))
1186		return (LIBUSB20_ERROR_INVALID_PARAM);
1187
1188	buf[0] = 0;		/* set default string value */
1189
1190	return (pdev->beMethods->dev_get_iface_desc(
1191	    pdev, iface_index, buf, len));
1192}
1193
1194/* USB backend operations */
1195
1196int
1197libusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
1198    uint16_t quirk_index, struct libusb20_quirk *pq)
1199{
1200	return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
1201}
1202
1203int
1204libusb20_be_get_quirk_name(struct libusb20_backend *pbe,
1205    uint16_t quirk_index, struct libusb20_quirk *pq)
1206{
1207	return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
1208}
1209
1210int
1211libusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
1212    struct libusb20_quirk *pq)
1213{
1214	return (pbe->methods->root_add_dev_quirk(pbe, pq));
1215}
1216
1217int
1218libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
1219    struct libusb20_quirk *pq)
1220{
1221	return (pbe->methods->root_remove_dev_quirk(pbe, pq));
1222}
1223
1224int
1225libusb20_be_set_template(struct libusb20_backend *pbe, int temp)
1226{
1227	return (pbe->methods->root_set_template(pbe, temp));
1228}
1229
1230int
1231libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
1232{
1233	int temp;
1234
1235	if (ptemp == NULL)
1236		ptemp = &temp;
1237
1238	return (pbe->methods->root_get_template(pbe, ptemp));
1239}
1240
1241struct libusb20_device *
1242libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1243{
1244	if (pbe == NULL) {
1245		pdev = NULL;
1246	} else if (pdev == NULL) {
1247		pdev = TAILQ_FIRST(&(pbe->usb_devs));
1248	} else {
1249		pdev = TAILQ_NEXT(pdev, dev_entry);
1250	}
1251	return (pdev);
1252}
1253
1254struct libusb20_backend *
1255libusb20_be_alloc(const struct libusb20_backend_methods *methods)
1256{
1257	struct libusb20_backend *pbe;
1258
1259	pbe = malloc(sizeof(*pbe));
1260	if (pbe == NULL) {
1261		return (NULL);
1262	}
1263	memset(pbe, 0, sizeof(*pbe));
1264
1265	TAILQ_INIT(&(pbe->usb_devs));
1266
1267	pbe->methods = methods;		/* set backend methods */
1268
1269	/* do the initial device scan */
1270	if (pbe->methods->init_backend) {
1271		pbe->methods->init_backend(pbe);
1272	}
1273	return (pbe);
1274}
1275
1276struct libusb20_backend *
1277libusb20_be_alloc_linux(void)
1278{
1279	return (NULL);
1280}
1281
1282struct libusb20_backend *
1283libusb20_be_alloc_ugen20(void)
1284{
1285	return (libusb20_be_alloc(&libusb20_ugen20_backend));
1286}
1287
1288struct libusb20_backend *
1289libusb20_be_alloc_default(void)
1290{
1291	struct libusb20_backend *pbe;
1292
1293#ifdef __linux__
1294	pbe = libusb20_be_alloc_linux();
1295	if (pbe) {
1296		return (pbe);
1297	}
1298#endif
1299	pbe = libusb20_be_alloc_ugen20();
1300	if (pbe) {
1301		return (pbe);
1302	}
1303	return (NULL);			/* no backend found */
1304}
1305
1306void
1307libusb20_be_free(struct libusb20_backend *pbe)
1308{
1309	struct libusb20_device *pdev;
1310
1311	if (pbe == NULL) {
1312		/* be NULL safe */
1313		return;
1314	}
1315	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1316		libusb20_be_dequeue_device(pbe, pdev);
1317		libusb20_dev_free(pdev);
1318	}
1319	if (pbe->methods->exit_backend) {
1320		pbe->methods->exit_backend(pbe);
1321	}
1322	/* free backend */
1323	free(pbe);
1324}
1325
1326void
1327libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1328{
1329	pdev->beMethods = pbe->methods;	/* copy backend methods */
1330	TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1331}
1332
1333void
1334libusb20_be_dequeue_device(struct libusb20_backend *pbe,
1335    struct libusb20_device *pdev)
1336{
1337	TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
1338}
1339
1340const char *
1341libusb20_strerror(int code)
1342{
1343	switch (code) {
1344	case LIBUSB20_SUCCESS:
1345		return ("Success");
1346	case LIBUSB20_ERROR_IO:
1347		return ("I/O error");
1348	case LIBUSB20_ERROR_INVALID_PARAM:
1349		return ("Invalid parameter");
1350	case LIBUSB20_ERROR_ACCESS:
1351		return ("Permissions error");
1352	case LIBUSB20_ERROR_NO_DEVICE:
1353		return ("No device");
1354	case LIBUSB20_ERROR_NOT_FOUND:
1355		return ("Not found");
1356	case LIBUSB20_ERROR_BUSY:
1357		return ("Device busy");
1358	case LIBUSB20_ERROR_TIMEOUT:
1359		return ("Timeout");
1360	case LIBUSB20_ERROR_OVERFLOW:
1361		return ("Overflow");
1362	case LIBUSB20_ERROR_PIPE:
1363		return ("Pipe error");
1364	case LIBUSB20_ERROR_INTERRUPTED:
1365		return ("Interrupted");
1366	case LIBUSB20_ERROR_NO_MEM:
1367		return ("Out of memory");
1368	case LIBUSB20_ERROR_NOT_SUPPORTED:
1369		return ("Not supported");
1370	case LIBUSB20_ERROR_OTHER:
1371		return ("Other error");
1372	default:
1373		return ("Unknown error");
1374	}
1375}
1376
1377const char *
1378libusb20_error_name(int code)
1379{
1380	switch (code) {
1381	case LIBUSB20_SUCCESS:
1382		return ("LIBUSB20_SUCCESS");
1383	case LIBUSB20_ERROR_IO:
1384		return ("LIBUSB20_ERROR_IO");
1385	case LIBUSB20_ERROR_INVALID_PARAM:
1386		return ("LIBUSB20_ERROR_INVALID_PARAM");
1387	case LIBUSB20_ERROR_ACCESS:
1388		return ("LIBUSB20_ERROR_ACCESS");
1389	case LIBUSB20_ERROR_NO_DEVICE:
1390		return ("LIBUSB20_ERROR_NO_DEVICE");
1391	case LIBUSB20_ERROR_NOT_FOUND:
1392		return ("LIBUSB20_ERROR_NOT_FOUND");
1393	case LIBUSB20_ERROR_BUSY:
1394		return ("LIBUSB20_ERROR_BUSY");
1395	case LIBUSB20_ERROR_TIMEOUT:
1396		return ("LIBUSB20_ERROR_TIMEOUT");
1397	case LIBUSB20_ERROR_OVERFLOW:
1398		return ("LIBUSB20_ERROR_OVERFLOW");
1399	case LIBUSB20_ERROR_PIPE:
1400		return ("LIBUSB20_ERROR_PIPE");
1401	case LIBUSB20_ERROR_INTERRUPTED:
1402		return ("LIBUSB20_ERROR_INTERRUPTED");
1403	case LIBUSB20_ERROR_NO_MEM:
1404		return ("LIBUSB20_ERROR_NO_MEM");
1405	case LIBUSB20_ERROR_NOT_SUPPORTED:
1406		return ("LIBUSB20_ERROR_NOT_SUPPORTED");
1407	case LIBUSB20_ERROR_OTHER:
1408		return ("LIBUSB20_ERROR_OTHER");
1409	default:
1410		return ("LIBUSB20_ERROR_UNKNOWN");
1411	}
1412}
1413