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