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