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