xref: /freebsd/lib/libusb/libusb20.c (revision 908e960ea6343acd9515d89d5d5696f9d8bf090c)
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 uint32_t
323 libusb20_tr_get_length(struct libusb20_transfer *xfer, uint16_t frIndex)
324 {
325 	return (xfer->pLength[frIndex]);
326 }
327 
328 void
329 libusb20_tr_set_length(struct libusb20_transfer *xfer, uint32_t length, uint16_t frIndex)
330 {
331 	xfer->pLength[frIndex] = length;
332 	return;
333 }
334 
335 void
336 libusb20_tr_set_priv_sc0(struct libusb20_transfer *xfer, void *sc0)
337 {
338 	xfer->priv_sc0 = sc0;
339 	return;
340 }
341 
342 void
343 libusb20_tr_set_priv_sc1(struct libusb20_transfer *xfer, void *sc1)
344 {
345 	xfer->priv_sc1 = sc1;
346 	return;
347 }
348 
349 void
350 libusb20_tr_set_timeout(struct libusb20_transfer *xfer, uint32_t timeout)
351 {
352 	xfer->timeout = timeout;
353 	return;
354 }
355 
356 void
357 libusb20_tr_set_total_frames(struct libusb20_transfer *xfer, uint32_t nFrames)
358 {
359 	if (nFrames > xfer->maxFrames) {
360 		/* should not happen */
361 		nFrames = xfer->maxFrames;
362 	}
363 	xfer->nFrames = nFrames;
364 	return;
365 }
366 
367 void
368 libusb20_tr_setup_bulk(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
369 {
370 	xfer->ppBuffer[0] = pBuf;
371 	xfer->pLength[0] = length;
372 	xfer->timeout = timeout;
373 	xfer->nFrames = 1;
374 	return;
375 }
376 
377 void
378 libusb20_tr_setup_control(struct libusb20_transfer *xfer, void *psetup, void *pBuf, uint32_t timeout)
379 {
380 	uint16_t len;
381 
382 	xfer->ppBuffer[0] = psetup;
383 	xfer->pLength[0] = 8;		/* fixed */
384 	xfer->timeout = timeout;
385 
386 	len = ((uint8_t *)psetup)[6] | (((uint8_t *)psetup)[7] << 8);
387 
388 	if (len != 0) {
389 		xfer->nFrames = 2;
390 		xfer->ppBuffer[1] = pBuf;
391 		xfer->pLength[1] = len;
392 	} else {
393 		xfer->nFrames = 1;
394 	}
395 	return;
396 }
397 
398 void
399 libusb20_tr_setup_intr(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint32_t timeout)
400 {
401 	xfer->ppBuffer[0] = pBuf;
402 	xfer->pLength[0] = length;
403 	xfer->timeout = timeout;
404 	xfer->nFrames = 1;
405 	return;
406 }
407 
408 void
409 libusb20_tr_setup_isoc(struct libusb20_transfer *xfer, void *pBuf, uint32_t length, uint16_t frIndex)
410 {
411 	if (frIndex >= xfer->maxFrames) {
412 		/* should not happen */
413 		return;
414 	}
415 	xfer->ppBuffer[frIndex] = pBuf;
416 	xfer->pLength[frIndex] = length;
417 	return;
418 }
419 
420 void
421 libusb20_tr_submit(struct libusb20_transfer *xfer)
422 {
423 	if (xfer->is_pending) {
424 		/* should not happen */
425 		return;
426 	}
427 	xfer->is_pending = 1;		/* we are pending */
428 	xfer->is_cancel = 0;		/* not cancelling */
429 	xfer->is_restart = 0;		/* not restarting */
430 
431 	xfer->pdev->methods->tr_submit(xfer);
432 	return;
433 }
434 
435 void
436 libusb20_tr_start(struct libusb20_transfer *xfer)
437 {
438 	if (xfer->is_pending) {
439 		if (xfer->is_cancel) {
440 			/* cancelling - restart */
441 			xfer->is_restart = 1;
442 		}
443 		/* transfer not pending */
444 		return;
445 	}
446 	/* get into the callback */
447 	libusb20_tr_callback_wrapper(xfer);
448 	return;
449 }
450 
451 /* USB device operations */
452 
453 int
454 libusb20_dev_claim_interface(struct libusb20_device *pdev, uint8_t ifaceIndex)
455 {
456 	int error;
457 
458 	if (ifaceIndex >= 32) {
459 		error = LIBUSB20_ERROR_INVALID_PARAM;
460 	} else if (pdev->claimed_interfaces & (1 << ifaceIndex)) {
461 		error = LIBUSB20_ERROR_NOT_FOUND;
462 	} else {
463 		error = pdev->methods->claim_interface(pdev, ifaceIndex);
464 	}
465 	if (!error) {
466 		pdev->claimed_interfaces |= (1 << ifaceIndex);
467 	}
468 	return (error);
469 }
470 
471 int
472 libusb20_dev_close(struct libusb20_device *pdev)
473 {
474 	struct libusb20_transfer *xfer;
475 	uint16_t x;
476 	int error = 0;
477 
478 	if (!pdev->is_opened) {
479 		return (LIBUSB20_ERROR_OTHER);
480 	}
481 	for (x = 0; x != pdev->nTransfer; x++) {
482 		xfer = pdev->pTransfer + x;
483 
484 		libusb20_tr_drain(xfer);
485 	}
486 
487 	if (pdev->pTransfer != NULL) {
488 		free(pdev->pTransfer);
489 		pdev->pTransfer = NULL;
490 	}
491 	error = pdev->beMethods->close_device(pdev);
492 
493 	pdev->methods = &libusb20_dummy_methods;
494 
495 	pdev->is_opened = 0;
496 
497 	pdev->claimed_interfaces = 0;
498 
499 	return (error);
500 }
501 
502 int
503 libusb20_dev_detach_kernel_driver(struct libusb20_device *pdev, uint8_t ifaceIndex)
504 {
505 	int error;
506 
507 	error = pdev->methods->detach_kernel_driver(pdev, ifaceIndex);
508 	return (error);
509 }
510 
511 struct LIBUSB20_DEVICE_DESC_DECODED *
512 libusb20_dev_get_device_desc(struct libusb20_device *pdev)
513 {
514 	return (&(pdev->ddesc));
515 }
516 
517 int
518 libusb20_dev_get_fd(struct libusb20_device *pdev)
519 {
520 	return (pdev->file);
521 }
522 
523 int
524 libusb20_dev_kernel_driver_active(struct libusb20_device *pdev, uint8_t ifaceIndex)
525 {
526 	int error;
527 
528 	error = pdev->methods->kernel_driver_active(pdev, ifaceIndex);
529 	return (error);
530 }
531 
532 int
533 libusb20_dev_open(struct libusb20_device *pdev, uint16_t nTransferMax)
534 {
535 	struct libusb20_transfer *xfer;
536 	uint32_t size;
537 	uint16_t x;
538 	int error;
539 
540 	if (pdev->is_opened) {
541 		return (LIBUSB20_ERROR_BUSY);
542 	}
543 	if (nTransferMax >= 256) {
544 		return (LIBUSB20_ERROR_INVALID_PARAM);
545 	} else if (nTransferMax != 0) {
546 		size = sizeof(pdev->pTransfer[0]) * nTransferMax;
547 		pdev->pTransfer = malloc(size);
548 		if (pdev->pTransfer == NULL) {
549 			return (LIBUSB20_ERROR_NO_MEM);
550 		}
551 		memset(pdev->pTransfer, 0, size);
552 	}
553 	/* initialise all transfers */
554 	for (x = 0; x != nTransferMax; x++) {
555 
556 		xfer = pdev->pTransfer + x;
557 
558 		xfer->pdev = pdev;
559 		xfer->trIndex = x;
560 		xfer->callback = &dummy_callback;
561 	}
562 
563 	/* set "nTransfer" early */
564 	pdev->nTransfer = nTransferMax;
565 
566 	error = pdev->beMethods->open_device(pdev, nTransferMax);
567 
568 	if (error) {
569 		if (pdev->pTransfer != NULL) {
570 			free(pdev->pTransfer);
571 			pdev->pTransfer = NULL;
572 		}
573 		pdev->file = -1;
574 		pdev->file_ctrl = -1;
575 		pdev->nTransfer = 0;
576 	} else {
577 		pdev->is_opened = 1;
578 	}
579 	return (error);
580 }
581 
582 int
583 libusb20_dev_release_interface(struct libusb20_device *pdev, uint8_t ifaceIndex)
584 {
585 	int error;
586 
587 	if (ifaceIndex >= 32) {
588 		error = LIBUSB20_ERROR_INVALID_PARAM;
589 	} else if (!(pdev->claimed_interfaces & (1 << ifaceIndex))) {
590 		error = LIBUSB20_ERROR_NOT_FOUND;
591 	} else {
592 		error = pdev->methods->release_interface(pdev, ifaceIndex);
593 	}
594 	if (!error) {
595 		pdev->claimed_interfaces &= ~(1 << ifaceIndex);
596 	}
597 	return (error);
598 }
599 
600 int
601 libusb20_dev_reset(struct libusb20_device *pdev)
602 {
603 	int error;
604 
605 	error = pdev->methods->reset_device(pdev);
606 	return (error);
607 }
608 
609 int
610 libusb20_dev_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
611 {
612 	int error;
613 
614 	error = pdev->methods->set_power_mode(pdev, power_mode);
615 	return (error);
616 }
617 
618 uint8_t
619 libusb20_dev_get_power_mode(struct libusb20_device *pdev)
620 {
621 	int error;
622 	uint8_t power_mode;
623 
624 	error = pdev->methods->get_power_mode(pdev, &power_mode);
625 	if (error)
626 		power_mode = LIBUSB20_POWER_ON;	/* fake power mode */
627 	return (power_mode);
628 }
629 
630 int
631 libusb20_dev_set_alt_index(struct libusb20_device *pdev, uint8_t ifaceIndex, uint8_t altIndex)
632 {
633 	int error;
634 
635 	error = pdev->methods->set_alt_index(pdev, ifaceIndex, altIndex);
636 	return (error);
637 }
638 
639 int
640 libusb20_dev_set_config_index(struct libusb20_device *pdev, uint8_t configIndex)
641 {
642 	int error;
643 
644 	error = pdev->methods->set_config_index(pdev, configIndex);
645 	return (error);
646 }
647 
648 int
649 libusb20_dev_request_sync(struct libusb20_device *pdev,
650     struct LIBUSB20_CONTROL_SETUP_DECODED *setup, void *data,
651     uint16_t *pactlen, uint32_t timeout, uint8_t flags)
652 {
653 	int error;
654 
655 	error = pdev->methods->do_request_sync(pdev,
656 	    setup, data, pactlen, timeout, flags);
657 	return (error);
658 }
659 
660 int
661 libusb20_dev_req_string_sync(struct libusb20_device *pdev,
662     uint8_t str_index, uint16_t langid, void *ptr, uint16_t len)
663 {
664 	struct LIBUSB20_CONTROL_SETUP_DECODED req;
665 	int error;
666 
667 	if (len < 4) {
668 		/* invalid length */
669 		return (LIBUSB20_ERROR_INVALID_PARAM);
670 	}
671 	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
672 
673 	/*
674 	 * We need to read the USB string in two steps else some USB
675 	 * devices will complain.
676 	 */
677 	req.bmRequestType =
678 	    LIBUSB20_REQUEST_TYPE_STANDARD |
679 	    LIBUSB20_RECIPIENT_DEVICE |
680 	    LIBUSB20_ENDPOINT_IN;
681 	req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
682 	req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
683 	req.wIndex = langid;
684 	req.wLength = 4;		/* bytes */
685 
686 	error = libusb20_dev_request_sync(pdev, &req,
687 	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
688 	if (error) {
689 		return (error);
690 	}
691 	req.wLength = *(uint8_t *)ptr;	/* bytes */
692 	if (req.wLength > len) {
693 		/* partial string read */
694 		req.wLength = len;
695 	}
696 	error = libusb20_dev_request_sync(pdev, &req,
697 	    ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
698 
699 	if (error) {
700 		return (error);
701 	}
702 	if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
703 		return (LIBUSB20_ERROR_OTHER);
704 	}
705 	return (0);			/* success */
706 }
707 
708 int
709 libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
710     uint8_t str_index, void *ptr, uint16_t len)
711 {
712 	char *buf;
713 	int error;
714 	uint16_t langid;
715 	uint16_t n;
716 	uint16_t i;
717 	uint16_t c;
718 	uint8_t temp[255];
719 	uint8_t swap;
720 
721 	/* the following code derives from the FreeBSD USB kernel */
722 
723 	if ((len < 1) || (ptr == NULL)) {
724 		/* too short buffer */
725 		return (LIBUSB20_ERROR_INVALID_PARAM);
726 	}
727 	error = libusb20_dev_req_string_sync(pdev,
728 	    0, 0, temp, sizeof(temp));
729 	if (error < 0) {
730 		*(uint8_t *)ptr = 0;	/* zero terminate */
731 		return (error);
732 	}
733 	langid = temp[2] | (temp[3] << 8);
734 
735 	error = libusb20_dev_req_string_sync(pdev, str_index,
736 	    langid, temp, sizeof(temp));
737 	if (error < 0) {
738 		*(uint8_t *)ptr = 0;	/* zero terminate */
739 		return (error);
740 	}
741 	if (temp[0] < 2) {
742 		/* string length is too short */
743 		*(uint8_t *)ptr = 0;	/* zero terminate */
744 		return (LIBUSB20_ERROR_OTHER);
745 	}
746 	/* reserve one byte for terminating zero */
747 	len--;
748 
749 	/* find maximum length */
750 	n = (temp[0] / 2) - 1;
751 	if (n > len) {
752 		n = len;
753 	}
754 	/* reset swap state */
755 	swap = 3;
756 
757 	/* setup output buffer pointer */
758 	buf = ptr;
759 
760 	/* convert and filter */
761 	for (i = 0; (i != n); i++) {
762 		c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
763 
764 		/* convert from Unicode, handle buggy strings */
765 		if (((c & 0xff00) == 0) && (swap & 1)) {
766 			/* Little Endian, default */
767 			*buf = c;
768 			swap = 1;
769 		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
770 			/* Big Endian */
771 			*buf = c >> 8;
772 			swap = 2;
773 		} else {
774 			/* skip invalid character */
775 			continue;
776 		}
777 		/*
778 		 * Filter by default - we don't allow greater and less than
779 		 * signs because they might confuse the dmesg printouts!
780 		 */
781 		if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
782 			/* skip invalid character */
783 			continue;
784 		}
785 		buf++;
786 	}
787 	*buf = 0;			/* zero terminate string */
788 
789 	return (0);
790 }
791 
792 struct libusb20_config *
793 libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
794 {
795 	struct libusb20_config *retval = NULL;
796 	uint8_t *ptr;
797 	uint16_t len;
798 	uint8_t do_close;
799 	int error;
800 
801 	if (!pdev->is_opened) {
802 		error = libusb20_dev_open(pdev, 0);
803 		if (error) {
804 			return (NULL);
805 		}
806 		do_close = 1;
807 	} else {
808 		do_close = 0;
809 	}
810 	error = pdev->methods->get_config_desc_full(pdev,
811 	    &ptr, &len, configIndex);
812 
813 	if (error) {
814 		goto done;
815 	}
816 	/* parse new config descriptor */
817 	retval = libusb20_parse_config_desc(ptr);
818 
819 	/* free config descriptor */
820 	free(ptr);
821 
822 done:
823 	if (do_close) {
824 		error = libusb20_dev_close(pdev);
825 	}
826 	return (retval);
827 }
828 
829 struct libusb20_device *
830 libusb20_dev_alloc(void)
831 {
832 	struct libusb20_device *pdev;
833 
834 	pdev = malloc(sizeof(*pdev));
835 	if (pdev == NULL) {
836 		return (NULL);
837 	}
838 	memset(pdev, 0, sizeof(*pdev));
839 
840 	pdev->file = -1;
841 	pdev->file_ctrl = -1;
842 	pdev->methods = &libusb20_dummy_methods;
843 	return (pdev);
844 }
845 
846 uint8_t
847 libusb20_dev_get_config_index(struct libusb20_device *pdev)
848 {
849 	int error;
850 	uint8_t cfg_index;
851 	uint8_t do_close;
852 
853 	if (!pdev->is_opened) {
854 		error = libusb20_dev_open(pdev, 0);
855 		if (error == 0) {
856 			do_close = 1;
857 		} else {
858 			do_close = 0;
859 		}
860 	} else {
861 		do_close = 0;
862 	}
863 
864 	error = pdev->methods->get_config_index(pdev, &cfg_index);
865 	if (error) {
866 		cfg_index = 0 - 1;	/* current config index */
867 	}
868 	if (do_close) {
869 		if (libusb20_dev_close(pdev)) {
870 			/* ignore */
871 		}
872 	}
873 	return (cfg_index);
874 }
875 
876 uint8_t
877 libusb20_dev_get_mode(struct libusb20_device *pdev)
878 {
879 	return (pdev->usb_mode);
880 }
881 
882 uint8_t
883 libusb20_dev_get_speed(struct libusb20_device *pdev)
884 {
885 	return (pdev->usb_speed);
886 }
887 
888 /* if this function returns an error, the device is gone */
889 int
890 libusb20_dev_process(struct libusb20_device *pdev)
891 {
892 	int error;
893 
894 	error = pdev->methods->process(pdev);
895 	return (error);
896 }
897 
898 void
899 libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
900 {
901 	struct pollfd pfd[1];
902 
903 	if (!pdev->is_opened) {
904 		return;
905 	}
906 	pfd[0].fd = pdev->file;
907 	pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
908 	pfd[0].revents = 0;
909 
910 	if (poll(pfd, 1, timeout)) {
911 		/* ignore any error */
912 	}
913 	return;
914 }
915 
916 void
917 libusb20_dev_free(struct libusb20_device *pdev)
918 {
919 	if (pdev == NULL) {
920 		/* be NULL safe */
921 		return;
922 	}
923 	if (pdev->is_opened) {
924 		if (libusb20_dev_close(pdev)) {
925 			/* ignore any errors */
926 		}
927 	}
928 	free(pdev);
929 	return;
930 }
931 
932 int
933 libusb20_dev_get_info(struct libusb20_device *pdev,
934     struct usb_device_info *pinfo)
935 {
936 	if (pinfo == NULL)
937 		return (LIBUSB20_ERROR_INVALID_PARAM);
938 
939 	return (pdev->beMethods->dev_get_info(pdev, pinfo));
940 }
941 
942 const char *
943 libusb20_dev_get_backend_name(struct libusb20_device *pdev)
944 {
945 	return (pdev->beMethods->get_backend_name());
946 }
947 
948 const char *
949 libusb20_dev_get_desc(struct libusb20_device *pdev)
950 {
951 	return (pdev->usb_desc);
952 }
953 
954 void
955 libusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
956 {
957 	pdev->debug = debug;
958 	return;
959 }
960 
961 int
962 libusb20_dev_get_debug(struct libusb20_device *pdev)
963 {
964 	return (pdev->debug);
965 }
966 
967 uint8_t
968 libusb20_dev_get_address(struct libusb20_device *pdev)
969 {
970 	return (pdev->device_address);
971 }
972 
973 uint8_t
974 libusb20_dev_get_bus_number(struct libusb20_device *pdev)
975 {
976 	return (pdev->bus_number);
977 }
978 
979 int
980 libusb20_dev_get_iface_desc(struct libusb20_device *pdev,
981     uint8_t iface_index, char *buf, uint8_t len)
982 {
983 	if ((buf == NULL) || (len == 0))
984 		return (LIBUSB20_ERROR_INVALID_PARAM);
985 
986 	return (pdev->beMethods->dev_get_iface_desc(
987 	    pdev, iface_index, buf, len));
988 }
989 
990 /* USB backend operations */
991 
992 int
993 libusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
994     uint16_t quirk_index, struct libusb20_quirk *pq)
995 {
996 	return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
997 }
998 
999 int
1000 libusb20_be_get_quirk_name(struct libusb20_backend *pbe,
1001     uint16_t quirk_index, struct libusb20_quirk *pq)
1002 {
1003 	return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
1004 }
1005 
1006 int
1007 libusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
1008     struct libusb20_quirk *pq)
1009 {
1010 	return (pbe->methods->root_add_dev_quirk(pbe, pq));
1011 }
1012 
1013 int
1014 libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
1015     struct libusb20_quirk *pq)
1016 {
1017 	return (pbe->methods->root_remove_dev_quirk(pbe, pq));
1018 }
1019 
1020 int
1021 libusb20_be_set_template(struct libusb20_backend *pbe, int temp)
1022 {
1023 	return (pbe->methods->root_set_template(pbe, temp));
1024 }
1025 
1026 int
1027 libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
1028 {
1029 	int temp;
1030 
1031 	if (ptemp == NULL)
1032 		ptemp = &temp;
1033 
1034 	return (pbe->methods->root_get_template(pbe, ptemp));
1035 }
1036 
1037 struct libusb20_device *
1038 libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1039 {
1040 	if (pbe == NULL) {
1041 		pdev = NULL;
1042 	} else if (pdev == NULL) {
1043 		pdev = TAILQ_FIRST(&(pbe->usb_devs));
1044 	} else {
1045 		pdev = TAILQ_NEXT(pdev, dev_entry);
1046 	}
1047 	return (pdev);
1048 }
1049 
1050 struct libusb20_backend *
1051 libusb20_be_alloc(const struct libusb20_backend_methods *methods)
1052 {
1053 	struct libusb20_backend *pbe;
1054 
1055 	pbe = malloc(sizeof(*pbe));
1056 	if (pbe == NULL) {
1057 		return (NULL);
1058 	}
1059 	memset(pbe, 0, sizeof(*pbe));
1060 
1061 	TAILQ_INIT(&(pbe->usb_devs));
1062 
1063 	pbe->methods = methods;		/* set backend methods */
1064 
1065 	/* do the initial device scan */
1066 	if (pbe->methods->init_backend) {
1067 		pbe->methods->init_backend(pbe);
1068 	}
1069 	return (pbe);
1070 }
1071 
1072 struct libusb20_backend *
1073 libusb20_be_alloc_linux(void)
1074 {
1075 	struct libusb20_backend *pbe;
1076 
1077 #ifdef __linux__
1078 	pbe = libusb20_be_alloc(&libusb20_linux_backend);
1079 #else
1080 	pbe = NULL;
1081 #endif
1082 	return (pbe);
1083 }
1084 
1085 struct libusb20_backend *
1086 libusb20_be_alloc_ugen20(void)
1087 {
1088 	struct libusb20_backend *pbe;
1089 
1090 #ifdef __FreeBSD__
1091 	pbe = libusb20_be_alloc(&libusb20_ugen20_backend);
1092 #else
1093 	pbe = NULL;
1094 #endif
1095 	return (pbe);
1096 }
1097 
1098 struct libusb20_backend *
1099 libusb20_be_alloc_default(void)
1100 {
1101 	struct libusb20_backend *pbe;
1102 
1103 	pbe = libusb20_be_alloc_linux();
1104 	if (pbe) {
1105 		return (pbe);
1106 	}
1107 	pbe = libusb20_be_alloc_ugen20();
1108 	if (pbe) {
1109 		return (pbe);
1110 	}
1111 	return (NULL);			/* no backend found */
1112 }
1113 
1114 void
1115 libusb20_be_free(struct libusb20_backend *pbe)
1116 {
1117 	struct libusb20_device *pdev;
1118 
1119 	if (pbe == NULL) {
1120 		/* be NULL safe */
1121 		return;
1122 	}
1123 	while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1124 		libusb20_be_dequeue_device(pbe, pdev);
1125 		libusb20_dev_free(pdev);
1126 	}
1127 	if (pbe->methods->exit_backend) {
1128 		pbe->methods->exit_backend(pbe);
1129 	}
1130 	return;
1131 }
1132 
1133 void
1134 libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1135 {
1136 	pdev->beMethods = pbe->methods;	/* copy backend methods */
1137 	TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1138 	return;
1139 }
1140 
1141 void
1142 libusb20_be_dequeue_device(struct libusb20_backend *pbe,
1143     struct libusb20_device *pdev)
1144 {
1145 	TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
1146 	return;
1147 }
1148