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