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