]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - lib/libusb/libusb20.c
MFC r199055
[FreeBSD/stable/8.git] / lib / libusb / libusb20.c
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         /* make sure memory is initialised */
634         memset(ptr, 0, len);
635
636         if (len < 4) {
637                 /* invalid length */
638                 return (LIBUSB20_ERROR_INVALID_PARAM);
639         }
640         LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &req);
641
642         /*
643          * We need to read the USB string in two steps else some USB
644          * devices will complain.
645          */
646         req.bmRequestType =
647             LIBUSB20_REQUEST_TYPE_STANDARD |
648             LIBUSB20_RECIPIENT_DEVICE |
649             LIBUSB20_ENDPOINT_IN;
650         req.bRequest = LIBUSB20_REQUEST_GET_DESCRIPTOR;
651         req.wValue = (LIBUSB20_DT_STRING << 8) | str_index;
652         req.wIndex = langid;
653         req.wLength = 4;                /* bytes */
654
655         error = libusb20_dev_request_sync(pdev, &req,
656             ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
657         if (error) {
658                 return (error);
659         }
660         req.wLength = *(uint8_t *)ptr;  /* bytes */
661         if (req.wLength > len) {
662                 /* partial string read */
663                 req.wLength = len;
664         }
665         error = libusb20_dev_request_sync(pdev, &req,
666             ptr, NULL, 1000, LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK);
667
668         if (error) {
669                 return (error);
670         }
671         if (((uint8_t *)ptr)[1] != LIBUSB20_DT_STRING) {
672                 return (LIBUSB20_ERROR_OTHER);
673         }
674         return (0);                     /* success */
675 }
676
677 int
678 libusb20_dev_req_string_simple_sync(struct libusb20_device *pdev,
679     uint8_t str_index, void *ptr, uint16_t len)
680 {
681         char *buf;
682         int error;
683         uint16_t langid;
684         uint16_t n;
685         uint16_t i;
686         uint16_t c;
687         uint8_t temp[255];
688         uint8_t swap;
689
690         /* the following code derives from the FreeBSD USB kernel */
691
692         if ((len < 1) || (ptr == NULL)) {
693                 /* too short buffer */
694                 return (LIBUSB20_ERROR_INVALID_PARAM);
695         }
696         error = libusb20_dev_req_string_sync(pdev,
697             0, 0, temp, sizeof(temp));
698         if (error < 0) {
699                 *(uint8_t *)ptr = 0;    /* zero terminate */
700                 return (error);
701         }
702         langid = temp[2] | (temp[3] << 8);
703
704         error = libusb20_dev_req_string_sync(pdev, str_index,
705             langid, temp, sizeof(temp));
706         if (error < 0) {
707                 *(uint8_t *)ptr = 0;    /* zero terminate */
708                 return (error);
709         }
710         if (temp[0] < 2) {
711                 /* string length is too short */
712                 *(uint8_t *)ptr = 0;    /* zero terminate */
713                 return (LIBUSB20_ERROR_OTHER);
714         }
715         /* reserve one byte for terminating zero */
716         len--;
717
718         /* find maximum length */
719         n = (temp[0] / 2) - 1;
720         if (n > len) {
721                 n = len;
722         }
723         /* reset swap state */
724         swap = 3;
725
726         /* setup output buffer pointer */
727         buf = ptr;
728
729         /* convert and filter */
730         for (i = 0; (i != n); i++) {
731                 c = temp[(2 * i) + 2] | (temp[(2 * i) + 3] << 8);
732
733                 /* convert from Unicode, handle buggy strings */
734                 if (((c & 0xff00) == 0) && (swap & 1)) {
735                         /* Little Endian, default */
736                         *buf = c;
737                         swap = 1;
738                 } else if (((c & 0x00ff) == 0) && (swap & 2)) {
739                         /* Big Endian */
740                         *buf = c >> 8;
741                         swap = 2;
742                 } else {
743                         /* skip invalid character */
744                         continue;
745                 }
746                 /*
747                  * Filter by default - we don't allow greater and less than
748                  * signs because they might confuse the dmesg printouts!
749                  */
750                 if ((*buf == '<') || (*buf == '>') || (!isprint(*buf))) {
751                         /* skip invalid character */
752                         continue;
753                 }
754                 buf++;
755         }
756         *buf = 0;                       /* zero terminate string */
757
758         return (0);
759 }
760
761 struct libusb20_config *
762 libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t configIndex)
763 {
764         struct libusb20_config *retval = NULL;
765         uint8_t *ptr;
766         uint16_t len;
767         uint8_t do_close;
768         int error;
769
770         if (!pdev->is_opened) {
771                 error = libusb20_dev_open(pdev, 0);
772                 if (error) {
773                         return (NULL);
774                 }
775                 do_close = 1;
776         } else {
777                 do_close = 0;
778         }
779         error = pdev->methods->get_config_desc_full(pdev,
780             &ptr, &len, configIndex);
781
782         if (error) {
783                 goto done;
784         }
785         /* parse new config descriptor */
786         retval = libusb20_parse_config_desc(ptr);
787
788         /* free config descriptor */
789         free(ptr);
790
791 done:
792         if (do_close) {
793                 error = libusb20_dev_close(pdev);
794         }
795         return (retval);
796 }
797
798 struct libusb20_device *
799 libusb20_dev_alloc(void)
800 {
801         struct libusb20_device *pdev;
802
803         pdev = malloc(sizeof(*pdev));
804         if (pdev == NULL) {
805                 return (NULL);
806         }
807         memset(pdev, 0, sizeof(*pdev));
808
809         pdev->file = -1;
810         pdev->file_ctrl = -1;
811         pdev->methods = &libusb20_dummy_methods;
812         return (pdev);
813 }
814
815 uint8_t
816 libusb20_dev_get_config_index(struct libusb20_device *pdev)
817 {
818         int error;
819         uint8_t cfg_index;
820         uint8_t do_close;
821
822         if (!pdev->is_opened) {
823                 error = libusb20_dev_open(pdev, 0);
824                 if (error == 0) {
825                         do_close = 1;
826                 } else {
827                         do_close = 0;
828                 }
829         } else {
830                 do_close = 0;
831         }
832
833         error = pdev->methods->get_config_index(pdev, &cfg_index);
834         if (error) {
835                 cfg_index = 0 - 1;      /* current config index */
836         }
837         if (do_close) {
838                 if (libusb20_dev_close(pdev)) {
839                         /* ignore */
840                 }
841         }
842         return (cfg_index);
843 }
844
845 uint8_t
846 libusb20_dev_get_mode(struct libusb20_device *pdev)
847 {
848         return (pdev->usb_mode);
849 }
850
851 uint8_t
852 libusb20_dev_get_speed(struct libusb20_device *pdev)
853 {
854         return (pdev->usb_speed);
855 }
856
857 /* if this function returns an error, the device is gone */
858 int
859 libusb20_dev_process(struct libusb20_device *pdev)
860 {
861         int error;
862
863         error = pdev->methods->process(pdev);
864         return (error);
865 }
866
867 void
868 libusb20_dev_wait_process(struct libusb20_device *pdev, int timeout)
869 {
870         struct pollfd pfd[1];
871
872         if (!pdev->is_opened) {
873                 return;
874         }
875         pfd[0].fd = pdev->file;
876         pfd[0].events = (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM);
877         pfd[0].revents = 0;
878
879         if (poll(pfd, 1, timeout)) {
880                 /* ignore any error */
881         }
882         return;
883 }
884
885 void
886 libusb20_dev_free(struct libusb20_device *pdev)
887 {
888         if (pdev == NULL) {
889                 /* be NULL safe */
890                 return;
891         }
892         if (pdev->is_opened) {
893                 if (libusb20_dev_close(pdev)) {
894                         /* ignore any errors */
895                 }
896         }
897         free(pdev);
898         return;
899 }
900
901 int
902 libusb20_dev_get_info(struct libusb20_device *pdev,
903     struct usb_device_info *pinfo)
904 {
905         if (pinfo == NULL)
906                 return (LIBUSB20_ERROR_INVALID_PARAM);
907
908         return (pdev->beMethods->dev_get_info(pdev, pinfo));
909 }
910
911 const char *
912 libusb20_dev_get_backend_name(struct libusb20_device *pdev)
913 {
914         return (pdev->beMethods->get_backend_name());
915 }
916
917 const char *
918 libusb20_dev_get_desc(struct libusb20_device *pdev)
919 {
920         return (pdev->usb_desc);
921 }
922
923 void
924 libusb20_dev_set_debug(struct libusb20_device *pdev, int debug)
925 {
926         pdev->debug = debug;
927         return;
928 }
929
930 int
931 libusb20_dev_get_debug(struct libusb20_device *pdev)
932 {
933         return (pdev->debug);
934 }
935
936 uint8_t
937 libusb20_dev_get_address(struct libusb20_device *pdev)
938 {
939         return (pdev->device_address);
940 }
941
942 uint8_t
943 libusb20_dev_get_bus_number(struct libusb20_device *pdev)
944 {
945         return (pdev->bus_number);
946 }
947
948 int
949 libusb20_dev_get_iface_desc(struct libusb20_device *pdev, 
950     uint8_t iface_index, char *buf, uint8_t len)
951 {
952         if ((buf == NULL) || (len == 0))
953                 return (LIBUSB20_ERROR_INVALID_PARAM);
954
955         return (pdev->beMethods->dev_get_iface_desc(
956             pdev, iface_index, buf, len));
957 }
958
959 /* USB backend operations */
960
961 int
962 libusb20_be_get_dev_quirk(struct libusb20_backend *pbe,
963     uint16_t quirk_index, struct libusb20_quirk *pq)
964 {
965         return (pbe->methods->root_get_dev_quirk(pbe, quirk_index, pq));
966 }
967
968 int
969 libusb20_be_get_quirk_name(struct libusb20_backend *pbe,
970     uint16_t quirk_index, struct libusb20_quirk *pq)
971 {
972         return (pbe->methods->root_get_quirk_name(pbe, quirk_index, pq));
973 }
974
975 int
976 libusb20_be_add_dev_quirk(struct libusb20_backend *pbe,
977     struct libusb20_quirk *pq)
978 {
979         return (pbe->methods->root_add_dev_quirk(pbe, pq));
980 }
981
982 int
983 libusb20_be_remove_dev_quirk(struct libusb20_backend *pbe,
984     struct libusb20_quirk *pq)
985 {
986         return (pbe->methods->root_remove_dev_quirk(pbe, pq));
987 }
988
989 int
990 libusb20_be_set_template(struct libusb20_backend *pbe, int temp)
991 {
992         return (pbe->methods->root_set_template(pbe, temp));
993 }
994
995 int
996 libusb20_be_get_template(struct libusb20_backend *pbe, int *ptemp)
997 {
998         int temp;
999
1000         if (ptemp == NULL)
1001                 ptemp = &temp;
1002
1003         return (pbe->methods->root_get_template(pbe, ptemp));
1004 }
1005
1006 struct libusb20_device *
1007 libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1008 {
1009         if (pbe == NULL) {
1010                 pdev = NULL;
1011         } else if (pdev == NULL) {
1012                 pdev = TAILQ_FIRST(&(pbe->usb_devs));
1013         } else {
1014                 pdev = TAILQ_NEXT(pdev, dev_entry);
1015         }
1016         return (pdev);
1017 }
1018
1019 struct libusb20_backend *
1020 libusb20_be_alloc(const struct libusb20_backend_methods *methods)
1021 {
1022         struct libusb20_backend *pbe;
1023
1024         pbe = malloc(sizeof(*pbe));
1025         if (pbe == NULL) {
1026                 return (NULL);
1027         }
1028         memset(pbe, 0, sizeof(*pbe));
1029
1030         TAILQ_INIT(&(pbe->usb_devs));
1031
1032         pbe->methods = methods;         /* set backend methods */
1033
1034         /* do the initial device scan */
1035         if (pbe->methods->init_backend) {
1036                 pbe->methods->init_backend(pbe);
1037         }
1038         return (pbe);
1039 }
1040
1041 struct libusb20_backend *
1042 libusb20_be_alloc_linux(void)
1043 {
1044         struct libusb20_backend *pbe;
1045
1046 #ifdef __linux__
1047         pbe = libusb20_be_alloc(&libusb20_linux_backend);
1048 #else
1049         pbe = NULL;
1050 #endif
1051         return (pbe);
1052 }
1053
1054 struct libusb20_backend *
1055 libusb20_be_alloc_ugen20(void)
1056 {
1057         struct libusb20_backend *pbe;
1058
1059 #ifdef __FreeBSD__
1060         pbe = libusb20_be_alloc(&libusb20_ugen20_backend);
1061 #else
1062         pbe = NULL;
1063 #endif
1064         return (pbe);
1065 }
1066
1067 struct libusb20_backend *
1068 libusb20_be_alloc_default(void)
1069 {
1070         struct libusb20_backend *pbe;
1071
1072         pbe = libusb20_be_alloc_linux();
1073         if (pbe) {
1074                 return (pbe);
1075         }
1076         pbe = libusb20_be_alloc_ugen20();
1077         if (pbe) {
1078                 return (pbe);
1079         }
1080         return (NULL);                  /* no backend found */
1081 }
1082
1083 void
1084 libusb20_be_free(struct libusb20_backend *pbe)
1085 {
1086         struct libusb20_device *pdev;
1087
1088         if (pbe == NULL) {
1089                 /* be NULL safe */
1090                 return;
1091         }
1092         while ((pdev = libusb20_be_device_foreach(pbe, NULL))) {
1093                 libusb20_be_dequeue_device(pbe, pdev);
1094                 libusb20_dev_free(pdev);
1095         }
1096         if (pbe->methods->exit_backend) {
1097                 pbe->methods->exit_backend(pbe);
1098         }
1099         /* free backend */
1100         free(pbe);
1101 }
1102
1103 void
1104 libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev)
1105 {
1106         pdev->beMethods = pbe->methods; /* copy backend methods */
1107         TAILQ_INSERT_TAIL(&(pbe->usb_devs), pdev, dev_entry);
1108 }
1109
1110 void
1111 libusb20_be_dequeue_device(struct libusb20_backend *pbe,
1112     struct libusb20_device *pdev)
1113 {
1114         TAILQ_REMOVE(&(pbe->usb_devs), pdev, dev_entry);
1115 }