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