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