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