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