libusb20.c revision 302275
1/* $FreeBSD: stable/10/lib/libusb/libusb20.c 302275 2016-06-29 10:58:36Z 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	/*
605	 * The following variable is only used by the libusb v1.0
606	 * compat layer:
607	 */
608	pdev->auto_detach = 0;
609
610	return (error);
611}
612
613int
614libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
615{
616	int error;
617
618	error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
619	return (error);
620}
621
622struct LIBUSB20_DEVICE_DESC_DECODED *
623libusb20_dev_get_device_desc(struct libusb20_device *pdev)
624{
625	return (&(pdev->ddesc));
626}
627
628int
629libusb20_dev_get_fd(struct libusb20_device *pdev)
630{
631	return (pdev->file);
632}
633
634int
635libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
636{
637	int error;
638
639	error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
640	return (error);
641}
642
643int
644libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
645{
646	struct libusb20_transfer *xfer;
647	uint32_t size;
648	uint16_t x;
649	int error;
650
651	if (pdev->is_opened) {
652		return (LIBUSB20_ERROR_BUSY);
653	}
654	if (nTransferMax >= 256) {
655		return (LIBUSB20_ERROR_INVALID_PARAM);
656	} else if (nTransferMax != 0) {
657		size = sizeof(pdev->pTransfer[0]) * nTransferMax;
658		pdev->pTransfer = malloc(size);
659		if (pdev->pTransfer == NULL) {
660			return (LIBUSB20_ERROR_NO_MEM);
661		}
662		memset(pdev->pTransfer, 0, size);
663	}
664	/* initialise all transfers */
665	for (x = 0; x != nTransferMax; x++) {
666
667		xfer = pdev->pTransfer + x;
668
669		xfer->pdev = pdev;
670		xfer->trIndex = x;
671		xfer->callback = &dummy_callback;
672	}
673
674	/* set "nTransfer" early */
675	pdev->nTransfer = nTransferMax;
676
677	error = pdev->beMethods->open_device(pdev, nTransferMax);
678
679	if (error) {
680		if (pdev->pTransfer != NULL) {
681			free(pdev->pTransfer);
682			pdev->pTransfer = NULL;
683		}
684		pdev->file = -1;
685		pdev->file_ctrl = -1;
686		pdev->nTransfer = 0;
687	} else {
688		pdev->is_opened = 1;
689	}
690	return (error);
691}
692
693int
694libusb20_dev_reset(struct libusb20_device *pdev)
695{
696	int error;
697
698	error = pdev->methods->reset_device(pdev);
699	return (error);
700}
701
702int
703libusb20_dev_check_connected(struct libusb20_device *pdev)
704{
705	int error;
706
707	error = pdev->methods->check_connected(pdev);
708	return (error);
709}
710
711int
712libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
713{
714	int error;
715
716	error = pdev->methods->set_power_mode(pdev, power_mode);
717	return (error);
718}
719
720uint8_t
721libusb20_dev_get_power_mode(struct libusb20_device *pdev)
722{
723	int error;
724	uint8_t power_mode;
725
726	error = pdev->methods->get_power_mode(pdev, &power_mode);
727	if (error)
728		power_mode = LIBUSB20_POWER_ON;	/* fake power mode */
729	return (power_mode);
730}
731
732int
733libusb20_dev_get_port_path(struct libusb20_device *pdev, uint8_t *buf, uint8_t bufsize)
734{
735	return (pdev->methods->get_port_path(pdev, buf, bufsize));
736}
737
738uint16_t
739libusb20_dev_get_power_usage(struct libusb20_device *pdev)
740{
741	int error;
742	uint16_t power_usage;
743
744	error = pdev->methods->get_power_usage(pdev, &power_usage);
745	if (error)
746		power_usage = 0;
747	return (power_usage);
748}
749
750int
751libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
752{
753	int error;
754
755	error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
756	return (error);
757}
758
759int
760libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
761{
762	int error;
763
764	error = pdev->methods->set_config_index(pdev, configIndex);
765	return (error);
766}
767
768int
769libusb20_dev_request_sync(struct libusb20_device *pdev,
770    struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
771    uint16_t *pactlen, uint32_t timeout, uint8_t flags)
772{
773	int error;
774
775	error = pdev->methods->do_request_sync(pdev,
776	    setup, data, pactlen, timeout, flags);
777	return (error);
778}
779
780int
781libusb20_dev_req_string_sync(struct libusb20_device *pdev,
782    uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
783{
784	struct LIBUSB20_CONTROL_SETUP_DECODED req;
785	int error;
786
787	/* make sure memory is initialised */
788	memset(ptr, 0, len);
789
790	if (len < 4) {
791		/* invalid length */
792		return (LIBUSB20_ERROR_INVALID_PARAM);
793	}
794	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
795
796	/*
797	 * We need to read the USB string in two steps else some USB
798	 * devices will complain.
799	 */
800	req.bmRequestType =
801	    LIBUSB20_REQUEST_TYPE_STANDARD |
802	    LIBUSB20_RECIPIENT_DEVICE |
803	    LIBUSB20_ENDPOINT_IN;
804	req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
805	req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
806	req.wIndex = langid;
807	req.wLength = 4;		/* bytes */
808
809	error = libusb20_dev_request_sync(pdev, &req,
810	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
811	if (error) {
812		return (error);
813	}
814	req.wLength = *(uint8_t *)ptr;	/* bytes */
815	if (req.wLength > len) {
816		/* partial string read */
817		req.wLength = len;
818	}
819	error = libusb20_dev_request_sync(pdev, &req,
820	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
821
822	if (error) {
823		return (error);
824	}
825	if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
826		return (LIBUSB20_ERROR_OTHER);
827	}
828	return (0);			/* success */
829}
830
831int
832libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
833    uint8_t str_index, void *ptr, uint16_t len)
834{
835	char *buf;
836	int error;
837	uint16_t langid;
838	uint16_t n;
839	uint16_t i;
840	uint16_t c;
841	uint8_t temp[255];
842	uint8_t swap;
843
844	/* the following code derives from the FreeBSD USB kernel */
845
846	if ((len < 1) || (ptr == NULL)) {
847		/* too short buffer */
848		return (LIBUSB20_ERROR_INVALID_PARAM);
849	}
850	error = libusb20_dev_req_string_sync(pdev,
851	    0, 0, temp, sizeof(temp));
852	if (error < 0) {
853		*(uint8_t *)ptr = 0;	/* zero terminate */
854		return (error);
855	}
856	langid = temp[2] | (temp[3] << 8);
857
858	error = libusb20_dev_req_string_sync(pdev, str_index,
859	    langid, temp, sizeof(temp));
860	if (error < 0) {
861		*(uint8_t *)ptr = 0;	/* zero terminate */
862		return (error);
863	}
864	if (temp[0] < 2) {
865		/* string length is too short */
866		*(uint8_t *)ptr = 0;	/* zero terminate */
867		return (LIBUSB20_ERROR_OTHER);
868	}
869	/* reserve one byte for terminating zero */
870	len--;
871
872	/* find maximum length */
873	n = (temp[0] / 2) - 1;
874	if (n > len) {
875		n = len;
876	}
877	/* reset swap state */
878	swap = 3;
879
880	/* setup output buffer pointer */
881	buf = ptr;
882
883	/* convert and filter */
884	for (i = 0; (i != n); i++) {
885		c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
886
887		/* convert from Unicode, handle buggy strings */
888		if (((c & 0xff00) == 0) && (swap & 1)) {
889			/* Little Endian, default */
890			*buf = c;
891			swap = 1;
892		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
893			/* Big Endian */
894			*buf = c >> 8;
895			swap = 2;
896		} else {
897			/* skip invalid character */
898			continue;
899		}
900		/*
901		 * Filter by default - we don't allow greater and less than
902		 * signs because they might confuse the dmesg printouts!
903		 */
904		if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
905			/* skip invalid character */
906			continue;
907		}
908		buf++;
909	}
910	*buf = 0;			/* zero terminate string */
911
912	return (0);
913}
914
915struct libusb20_config *
916libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
917{
918	struct libusb20_config *retval = NULL;
919	uint8_t *ptr;
920	uint16_t len;
921	uint8_t do_close;
922	int error;
923
924	if (!pdev->is_opened) {
925		error = libusb20_dev_open(pdev, 0);
926		if (error) {
927			return (NULL);
928		}
929		do_close = 1;
930	} else {
931		do_close = 0;
932	}
933	error = pdev->methods->get_config_desc_full(pdev,
934	    &ptr, &len, configIndex);
935
936	if (error) {
937		goto done;
938	}
939	/* parse new config descriptor */
940	retval = libusb20_parse_config_desc(ptr);
941
942	/* free config descriptor */
943	free(ptr);
944
945done:
946	if (do_close) {
947		error = libusb20_dev_close(pdev);
948	}
949	return (retval);
950}
951
952struct libusb20_device *
953libusb20_dev_alloc(void)
954{
955	struct libusb20_device *pdev;
956
957	pdev = malloc(sizeof(*pdev));
958	if (pdev == NULL) {
959		return (NULL);
960	}
961	memset(pdev, 0, sizeof(*pdev));
962
963	pdev->file = -1;
964	pdev->file_ctrl = -1;
965	pdev->methods = &libusb20_dummy_methods;
966	return (pdev);
967}
968
969uint8_t
970libusb20_dev_get_config_index(struct libusb20_device *pdev)
971{
972	int error;
973	uint8_t cfg_index;
974	uint8_t do_close;
975
976	if (!pdev->is_opened) {
977		error = libusb20_dev_open(pdev, 0);
978		if (error == 0) {
979			do_close = 1;
980		} else {
981			do_close = 0;
982		}
983	} else {
984		do_close = 0;
985	}
986
987	error = pdev->methods->get_config_index(pdev, &cfg_index);
988	if (error)
989		cfg_index = 0xFF;	/* current config index */
990	if (do_close) {
991		if (libusb20_dev_close(pdev)) {
992			/* ignore */
993		}
994	}
995	return (cfg_index);
996}
997
998uint8_t
999libusb20_dev_get_mode(struct libusb20_device *pdev)
1000{
1001	return (pdev->usb_mode);
1002}
1003
1004uint8_t
1005libusb20_dev_get_speed(struct libusb20_device *pdev)
1006{
1007	return (pdev->usb_speed);
1008}
1009
1010/* if this function returns an error, the device is gone */
1011int
1012libusb20_dev_process(struct libusb20_device *pdev)
1013{
1014	int error;
1015
1016	error = pdev->methods->process(pdev);
1017	return (error);
1018}
1019
1020void
1021libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
1022{
1023	struct pollfd pfd[1];
1024
1025	if (!pdev->is_opened) {
1026		return;
1027	}
1028	pfd[0].fd = pdev->file;
1029	pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
1030	pfd[0].revents = 0;
1031
1032	if (poll(pfd, 1, timeout)) {
1033		/* ignore any error */
1034	}
1035	return;
1036}
1037
1038void
1039libusb20_dev_free(struct libusb20_device *pdev)
1040{
1041	if (pdev == NULL) {
1042		/* be NULL safe */
1043		return;
1044	}
1045	if (pdev->is_opened) {
1046		if (libusb20_dev_close(pdev)) {
1047			/* ignore any errors */
1048		}
1049	}
1050	free(pdev);
1051	return;
1052}
1053
1054int
1055libusb20_dev_get_info(struct libusb20_device *pdev,
1056    struct usb_device_info *pinfo)
1057{
1058	if (pinfo == NULL)
1059		return (LIBUSB20_ERROR_INVALID_PARAM);
1060
1061	return (pdev->beMethods->dev_get_info(pdev, pinfo));
1062}
1063
1064const char *
1065libusb20_dev_get_backend_name(struct libusb20_device *pdev)
1066{
1067	return (pdev->beMethods->get_backend_name());
1068}
1069
1070const char *
1071libusb20_dev_get_desc(struct libusb20_device *pdev)
1072{
1073	return (pdev->usb_desc);
1074}
1075
1076void
1077libusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
1078{
1079	pdev->debug = debug;
1080	return;
1081}
1082
1083int
1084libusb20_dev_get_debug(struct libusb20_device *pdev)
1085{
1086	return (pdev->debug);
1087}
1088
1089uint8_t
1090libusb20_dev_get_address(struct libusb20_device *pdev)
1091{
1092	return (pdev->device_address);
1093}
1094
1095uint8_t
1096libusb20_dev_get_parent_address(struct libusb20_device *pdev)
1097{
1098	return (pdev->parent_address);
1099}
1100
1101uint8_t
1102libusb20_dev_get_parent_port(struct libusb20_device *pdev)
1103{
1104	return (pdev->parent_port);
1105}
1106
1107uint8_t
1108libusb20_dev_get_bus_number(struct libusb20_device *pdev)
1109{
1110	return (pdev->bus_number);
1111}
1112
1113int
1114libusb20_dev_get_iface_desc(struct libusb20_device *pdev,
1115    uint8_t iface_index, char *buf, uint8_t len)
1116{
1117	if ((buf == NULL) || (len == 0))
1118		return (LIBUSB20_ERROR_INVALID_PARAM);
1119
1120	buf[0] = 0;		/* set default string value */
1121
1122	return (pdev->beMethods->dev_get_iface_desc(
1123	    pdev, iface_index, buf, len));
1124}
1125
1126/* USB backend operations */
1127
1128int
1129libusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
1130    uint16_t quirk_index, struct libusb20_quirk *pq)
1131{
1132	return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
1133}
1134
1135int
1136libusb20_be_get_quirk_name(struct libusb20_backend *pbe,
1137    uint16_t quirk_index, struct libusb20_quirk *pq)
1138{
1139	return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
1140}
1141
1142int
1143libusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
1144    struct libusb20_quirk *pq)
1145{
1146	return (pbe->methods->root_add_dev_quirk(pbe, pq));
1147}
1148
1149int
1150libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
1151    struct libusb20_quirk *pq)
1152{
1153	return (pbe->methods->root_remove_dev_quirk(pbe, pq));
1154}
1155
1156int
1157libusb20_be_set_template(struct libusb20_backend *pbe, int temp)
1158{
1159	return (pbe->methods->root_set_template(pbe, temp));
1160}
1161
1162int
1163libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
1164{
1165	int temp;
1166
1167	if (ptemp == NULL)
1168		ptemp = &temp;
1169
1170	return (pbe->methods->root_get_template(pbe, ptemp));
1171}
1172
1173struct libusb20_device *
1174libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1175{
1176	if (pbe == NULL) {
1177		pdev = NULL;
1178	} else if (pdev == NULL) {
1179		pdev = TAILQ_FIRST(&(pbe->usb_devs));
1180	} else {
1181		pdev = TAILQ_NEXT(pdev, dev_entry);
1182	}
1183	return (pdev);
1184}
1185
1186struct libusb20_backend *
1187libusb20_be_alloc(const struct libusb20_backend_methods *methods)
1188{
1189	struct libusb20_backend *pbe;
1190
1191	pbe = malloc(sizeof(*pbe));
1192	if (pbe == NULL) {
1193		return (NULL);
1194	}
1195	memset(pbe, 0, sizeof(*pbe));
1196
1197	TAILQ_INIT(&(pbe->usb_devs));
1198
1199	pbe->methods = methods;		/* set backend methods */
1200
1201	/* do the initial device scan */
1202	if (pbe->methods->init_backend) {
1203		pbe->methods->init_backend(pbe);
1204	}
1205	return (pbe);
1206}
1207
1208struct libusb20_backend *
1209libusb20_be_alloc_linux(void)
1210{
1211	return (NULL);
1212}
1213
1214struct libusb20_backend *
1215libusb20_be_alloc_ugen20(void)
1216{
1217	return (libusb20_be_alloc(&libusb20_ugen20_backend));
1218}
1219
1220struct libusb20_backend *
1221libusb20_be_alloc_default(void)
1222{
1223	struct libusb20_backend *pbe;
1224
1225#ifdef __linux__
1226	pbe = libusb20_be_alloc_linux();
1227	if (pbe) {
1228		return (pbe);
1229	}
1230#endif
1231	pbe = libusb20_be_alloc_ugen20();
1232	if (pbe) {
1233		return (pbe);
1234	}
1235	return (NULL);			/* no backend found */
1236}
1237
1238void
1239libusb20_be_free(struct libusb20_backend *pbe)
1240{
1241	struct libusb20_device *pdev;
1242
1243	if (pbe == NULL) {
1244		/* be NULL safe */
1245		return;
1246	}
1247	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1248		libusb20_be_dequeue_device(pbe, pdev);
1249		libusb20_dev_free(pdev);
1250	}
1251	if (pbe->methods->exit_backend) {
1252		pbe->methods->exit_backend(pbe);
1253	}
1254	/* free backend */
1255	free(pbe);
1256}
1257
1258void
1259libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1260{
1261	pdev->beMethods = pbe->methods;	/* copy backend methods */
1262	TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1263}
1264
1265void
1266libusb20_be_dequeue_device(struct libusb20_backend *pbe,
1267    struct libusb20_device *pdev)
1268{
1269	TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
1270}
1271
1272const char *
1273libusb20_strerror(int code)
1274{
1275	switch (code) {
1276	case LIBUSB20_SUCCESS:
1277		return ("Success");
1278	case LIBUSB20_ERROR_IO:
1279		return ("I/O error");
1280	case LIBUSB20_ERROR_INVALID_PARAM:
1281		return ("Invalid parameter");
1282	case LIBUSB20_ERROR_ACCESS:
1283		return ("Permissions error");
1284	case LIBUSB20_ERROR_NO_DEVICE:
1285		return ("No device");
1286	case LIBUSB20_ERROR_NOT_FOUND:
1287		return ("Not found");
1288	case LIBUSB20_ERROR_BUSY:
1289		return ("Device busy");
1290	case LIBUSB20_ERROR_TIMEOUT:
1291		return ("Timeout");
1292	case LIBUSB20_ERROR_OVERFLOW:
1293		return ("Overflow");
1294	case LIBUSB20_ERROR_PIPE:
1295		return ("Pipe error");
1296	case LIBUSB20_ERROR_INTERRUPTED:
1297		return ("Interrupted");
1298	case LIBUSB20_ERROR_NO_MEM:
1299		return ("Out of memory");
1300	case LIBUSB20_ERROR_NOT_SUPPORTED:
1301		return ("Not supported");
1302	case LIBUSB20_ERROR_OTHER:
1303		return ("Other error");
1304	default:
1305		return ("Unknown error");
1306	}
1307}
1308
1309const char *
1310libusb20_error_name(int code)
1311{
1312	switch (code) {
1313	case LIBUSB20_SUCCESS:
1314		return ("LIBUSB20_SUCCESS");
1315	case LIBUSB20_ERROR_IO:
1316		return ("LIBUSB20_ERROR_IO");
1317	case LIBUSB20_ERROR_INVALID_PARAM:
1318		return ("LIBUSB20_ERROR_INVALID_PARAM");
1319	case LIBUSB20_ERROR_ACCESS:
1320		return ("LIBUSB20_ERROR_ACCESS");
1321	case LIBUSB20_ERROR_NO_DEVICE:
1322		return ("LIBUSB20_ERROR_NO_DEVICE");
1323	case LIBUSB20_ERROR_NOT_FOUND:
1324		return ("LIBUSB20_ERROR_NOT_FOUND");
1325	case LIBUSB20_ERROR_BUSY:
1326		return ("LIBUSB20_ERROR_BUSY");
1327	case LIBUSB20_ERROR_TIMEOUT:
1328		return ("LIBUSB20_ERROR_TIMEOUT");
1329	case LIBUSB20_ERROR_OVERFLOW:
1330		return ("LIBUSB20_ERROR_OVERFLOW");
1331	case LIBUSB20_ERROR_PIPE:
1332		return ("LIBUSB20_ERROR_PIPE");
1333	case LIBUSB20_ERROR_INTERRUPTED:
1334		return ("LIBUSB20_ERROR_INTERRUPTED");
1335	case LIBUSB20_ERROR_NO_MEM:
1336		return ("LIBUSB20_ERROR_NO_MEM");
1337	case LIBUSB20_ERROR_NOT_SUPPORTED:
1338		return ("LIBUSB20_ERROR_NOT_SUPPORTED");
1339	case LIBUSB20_ERROR_OTHER:
1340		return ("LIBUSB20_ERROR_OTHER");
1341	default:
1342		return ("LIBUSB20_ERROR_UNKNOWN");
1343	}
1344}
1345