]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - lib/libusb/libusb20_ugen20.c
MFC r219100
[FreeBSD/stable/8.git] / lib / libusb / libusb20_ugen20.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 <sys/queue.h>
28 #include <sys/types.h>
29
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include "libusb20.h"
38 #include "libusb20_desc.h"
39 #include "libusb20_int.h"
40
41 #include <dev/usb/usb.h>
42 #include <dev/usb/usbdi.h>
43 #include <dev/usb/usb_ioctl.h>
44
45 static libusb20_init_backend_t ugen20_init_backend;
46 static libusb20_open_device_t ugen20_open_device;
47 static libusb20_close_device_t ugen20_close_device;
48 static libusb20_get_backend_name_t ugen20_get_backend_name;
49 static libusb20_exit_backend_t ugen20_exit_backend;
50 static libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
51 static libusb20_dev_get_info_t ugen20_dev_get_info;
52 static libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
53 static libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
54 static libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
55 static libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
56 static libusb20_root_set_template_t ugen20_root_set_template;
57 static libusb20_root_get_template_t ugen20_root_get_template;
58
59 const struct libusb20_backend_methods libusb20_ugen20_backend = {
60         LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
61 };
62
63 /* USB device specific */
64 static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
65 static libusb20_get_config_index_t ugen20_get_config_index;
66 static libusb20_set_config_index_t ugen20_set_config_index;
67 static libusb20_set_alt_index_t ugen20_set_alt_index;
68 static libusb20_reset_device_t ugen20_reset_device;
69 static libusb20_check_connected_t ugen20_check_connected;
70 static libusb20_set_power_mode_t ugen20_set_power_mode;
71 static libusb20_get_power_mode_t ugen20_get_power_mode;
72 static libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
73 static libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
74 static libusb20_do_request_sync_t ugen20_do_request_sync;
75 static libusb20_process_t ugen20_process;
76
77 /* USB transfer specific */
78 static libusb20_tr_open_t ugen20_tr_open;
79 static libusb20_tr_close_t ugen20_tr_close;
80 static libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
81 static libusb20_tr_submit_t ugen20_tr_submit;
82 static libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
83
84 static const struct libusb20_device_methods libusb20_ugen20_device_methods = {
85         LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
86 };
87
88 static const char *
89 ugen20_get_backend_name(void)
90 {
91         return ("FreeBSD UGEN 2.0");
92 }
93
94 static uint32_t
95 ugen20_path_convert_one(const char **pp)
96 {
97         const char *ptr;
98         uint32_t temp = 0;
99
100         ptr = *pp;
101
102         while ((*ptr >= '0') && (*ptr <= '9')) {
103                 temp *= 10;
104                 temp += (*ptr - '0');
105                 if (temp >= 1000000) {
106                         /* catch overflow early */
107                         return (0 - 1);
108                 }
109                 ptr++;
110         }
111
112         if (*ptr == '.') {
113                 /* skip dot */
114                 ptr++;
115         }
116         *pp = ptr;
117
118         return (temp);
119 }
120
121 static int
122 ugen20_enumerate(struct libusb20_device *pdev, const char *id)
123 {
124         const char *tmp = id;
125         struct usb_device_descriptor ddesc;
126         struct usb_device_info devinfo;
127         uint32_t plugtime;
128         char buf[64];
129         int f;
130         int error;
131
132         pdev->bus_number = ugen20_path_convert_one(&tmp);
133         pdev->device_address = ugen20_path_convert_one(&tmp);
134
135         snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
136             pdev->bus_number, pdev->device_address);
137
138         f = open(buf, O_RDWR);
139         if (f < 0) {
140                 return (LIBUSB20_ERROR_OTHER);
141         }
142         if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
143                 error = LIBUSB20_ERROR_OTHER;
144                 goto done;
145         }
146         /* store when the device was plugged */
147         pdev->session_data.plugtime = plugtime;
148
149         if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
150                 error = LIBUSB20_ERROR_OTHER;
151                 goto done;
152         }
153         LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
154
155         libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
156
157         if (pdev->ddesc.bNumConfigurations == 0) {
158                 error = LIBUSB20_ERROR_OTHER;
159                 goto done;
160         } else if (pdev->ddesc.bNumConfigurations >= 8) {
161                 error = LIBUSB20_ERROR_OTHER;
162                 goto done;
163         }
164         if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
165                 error = LIBUSB20_ERROR_OTHER;
166                 goto done;
167         }
168         switch (devinfo.udi_mode) {
169         case USB_MODE_DEVICE:
170                 pdev->usb_mode = LIBUSB20_MODE_DEVICE;
171                 break;
172         default:
173                 pdev->usb_mode = LIBUSB20_MODE_HOST;
174                 break;
175         }
176
177         switch (devinfo.udi_speed) {
178         case USB_SPEED_LOW:
179                 pdev->usb_speed = LIBUSB20_SPEED_LOW;
180                 break;
181         case USB_SPEED_FULL:
182                 pdev->usb_speed = LIBUSB20_SPEED_FULL;
183                 break;
184         case USB_SPEED_HIGH:
185                 pdev->usb_speed = LIBUSB20_SPEED_HIGH;
186                 break;
187         case USB_SPEED_VARIABLE:
188                 pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
189                 break;
190         case USB_SPEED_SUPER:
191                 pdev->usb_speed = LIBUSB20_SPEED_SUPER;
192                 break;
193         default:
194                 pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
195                 break;
196         }
197
198         /* generate a nice description for printout */
199
200         snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
201             USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
202             pdev->device_address, devinfo.udi_product,
203             devinfo.udi_vendor, pdev->bus_number);
204
205         error = 0;
206 done:
207         close(f);
208         return (error);
209 }
210
211 struct ugen20_urd_state {
212         struct usb_read_dir urd;
213         uint32_t nparsed;
214         int     f;
215         uint8_t *ptr;
216         const char *src;
217         const char *dst;
218         uint8_t buf[256];
219         uint8_t dummy_zero[1];
220 };
221
222 static int
223 ugen20_readdir(struct ugen20_urd_state *st)
224 {
225         ;                               /* style fix */
226 repeat:
227         if (st->ptr == NULL) {
228                 st->urd.urd_startentry += st->nparsed;
229                 st->urd.urd_data = st->buf;
230                 st->urd.urd_maxlen = sizeof(st->buf);
231                 st->nparsed = 0;
232
233                 if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
234                         return (EINVAL);
235                 }
236                 st->ptr = st->buf;
237         }
238         if (st->ptr[0] == 0) {
239                 if (st->nparsed) {
240                         st->ptr = NULL;
241                         goto repeat;
242                 } else {
243                         return (ENXIO);
244                 }
245         }
246         st->src = (void *)(st->ptr + 1);
247         st->dst = st->src + strlen(st->src) + 1;
248         st->ptr = st->ptr + st->ptr[0];
249         st->nparsed++;
250
251         if ((st->ptr < st->buf) ||
252             (st->ptr > st->dummy_zero)) {
253                 /* invalid entry */
254                 return (EINVAL);
255         }
256         return (0);
257 }
258
259 static int
260 ugen20_init_backend(struct libusb20_backend *pbe)
261 {
262         struct ugen20_urd_state state;
263         struct libusb20_device *pdev;
264
265         memset(&state, 0, sizeof(state));
266
267         state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
268         if (state.f < 0)
269                 return (LIBUSB20_ERROR_OTHER);
270
271         while (ugen20_readdir(&state) == 0) {
272
273                 if ((state.src[0] != 'u') ||
274                     (state.src[1] != 'g') ||
275                     (state.src[2] != 'e') ||
276                     (state.src[3] != 'n')) {
277                         continue;
278                 }
279                 pdev = libusb20_dev_alloc();
280                 if (pdev == NULL) {
281                         continue;
282                 }
283                 if (ugen20_enumerate(pdev, state.src + 4)) {
284                         libusb20_dev_free(pdev);
285                         continue;
286                 }
287                 /* put the device on the backend list */
288                 libusb20_be_enqueue_device(pbe, pdev);
289         }
290         close(state.f);
291         return (0);                     /* success */
292 }
293
294 static void
295 ugen20_tr_release(struct libusb20_device *pdev)
296 {
297         struct usb_fs_uninit fs_uninit;
298
299         if (pdev->nTransfer == 0) {
300                 return;
301         }
302         /* release all pending USB transfers */
303         if (pdev->privBeData != NULL) {
304                 memset(&fs_uninit, 0, sizeof(fs_uninit));
305                 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
306                         /* ignore any errors of this kind */
307                 }
308         }
309         return;
310 }
311
312 static int
313 ugen20_tr_renew(struct libusb20_device *pdev)
314 {
315         struct usb_fs_init fs_init;
316         struct usb_fs_endpoint *pfse;
317         int error;
318         uint32_t size;
319         uint16_t nMaxTransfer;
320
321         nMaxTransfer = pdev->nTransfer;
322         error = 0;
323
324         if (nMaxTransfer == 0) {
325                 goto done;
326         }
327         size = nMaxTransfer * sizeof(*pfse);
328
329         if (pdev->privBeData == NULL) {
330                 pfse = malloc(size);
331                 if (pfse == NULL) {
332                         error = LIBUSB20_ERROR_NO_MEM;
333                         goto done;
334                 }
335                 pdev->privBeData = pfse;
336         }
337         /* reset endpoint data */
338         memset(pdev->privBeData, 0, size);
339
340         memset(&fs_init, 0, sizeof(fs_init));
341
342         fs_init.pEndpoints = pdev->privBeData;
343         fs_init.ep_index_max = nMaxTransfer;
344
345         if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
346                 error = LIBUSB20_ERROR_OTHER;
347                 goto done;
348         }
349 done:
350         return (error);
351 }
352
353 static int
354 ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
355 {
356         uint32_t plugtime;
357         char buf[64];
358         int f;
359         int g;
360         int error;
361
362         snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
363             pdev->bus_number, pdev->device_address);
364
365         /*
366          * We need two file handles, one for the control endpoint and one
367          * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
368          * kernel locking.
369          */
370         g = open(buf, O_RDWR);
371         if (g < 0) {
372                 return (LIBUSB20_ERROR_NO_DEVICE);
373         }
374         f = open(buf, O_RDWR);
375         if (f < 0) {
376                 close(g);
377                 return (LIBUSB20_ERROR_NO_DEVICE);
378         }
379         if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
380                 error = LIBUSB20_ERROR_OTHER;
381                 goto done;
382         }
383         /* check that the correct device is still plugged */
384         if (pdev->session_data.plugtime != plugtime) {
385                 error = LIBUSB20_ERROR_NO_DEVICE;
386                 goto done;
387         }
388         /* need to set this before "tr_renew()" */
389         pdev->file = f;
390         pdev->file_ctrl = g;
391
392         /* renew all USB transfers */
393         error = ugen20_tr_renew(pdev);
394         if (error) {
395                 goto done;
396         }
397         /* set methods */
398         pdev->methods = &libusb20_ugen20_device_methods;
399
400 done:
401         if (error) {
402                 if (pdev->privBeData) {
403                         /* cleanup after "tr_renew()" */
404                         free(pdev->privBeData);
405                         pdev->privBeData = NULL;
406                 }
407                 pdev->file = -1;
408                 pdev->file_ctrl = -1;
409                 close(f);
410                 close(g);
411         }
412         return (error);
413 }
414
415 static int
416 ugen20_close_device(struct libusb20_device *pdev)
417 {
418         struct usb_fs_uninit fs_uninit;
419
420         if (pdev->privBeData) {
421                 memset(&fs_uninit, 0, sizeof(fs_uninit));
422                 if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
423                         /* ignore this error */
424                 }
425                 free(pdev->privBeData);
426         }
427         pdev->nTransfer = 0;
428         pdev->privBeData = NULL;
429         close(pdev->file);
430         close(pdev->file_ctrl);
431         pdev->file = -1;
432         pdev->file_ctrl = -1;
433         return (0);                     /* success */
434 }
435
436 static void
437 ugen20_exit_backend(struct libusb20_backend *pbe)
438 {
439         return;                         /* nothing to do */
440 }
441
442 static int
443 ugen20_get_config_desc_full(struct libusb20_device *pdev,
444     uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
445 {
446         struct usb_gen_descriptor gen_desc;
447         struct usb_config_descriptor cdesc;
448         uint8_t *ptr;
449         uint16_t len;
450         int error;
451
452         /* make sure memory is initialised */
453         memset(&cdesc, 0, sizeof(cdesc));
454         memset(&gen_desc, 0, sizeof(gen_desc));
455
456         gen_desc.ugd_data = &cdesc;
457         gen_desc.ugd_maxlen = sizeof(cdesc);
458         gen_desc.ugd_config_index = cfg_index;
459
460         error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
461         if (error) {
462                 return (LIBUSB20_ERROR_OTHER);
463         }
464         len = UGETW(cdesc.wTotalLength);
465         if (len < sizeof(cdesc)) {
466                 /* corrupt descriptor */
467                 return (LIBUSB20_ERROR_OTHER);
468         }
469         ptr = malloc(len);
470         if (!ptr) {
471                 return (LIBUSB20_ERROR_NO_MEM);
472         }
473
474         /* make sure memory is initialised */
475         memset(ptr, 0, len);
476
477         gen_desc.ugd_data = ptr;
478         gen_desc.ugd_maxlen = len;
479
480         error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
481         if (error) {
482                 free(ptr);
483                 return (LIBUSB20_ERROR_OTHER);
484         }
485         /* make sure that the device doesn't fool us */
486         memcpy(ptr, &cdesc, sizeof(cdesc));
487
488         *ppbuf = ptr;
489         *plen = len;
490
491         return (0);                     /* success */
492 }
493
494 static int
495 ugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
496 {
497         int temp;
498
499         if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
500                 return (LIBUSB20_ERROR_OTHER);
501         }
502         *pindex = temp;
503
504         return (0);
505 }
506
507 static int
508 ugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
509 {
510         int temp = cfg_index;
511
512         /* release all active USB transfers */
513         ugen20_tr_release(pdev);
514
515         if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
516                 return (LIBUSB20_ERROR_OTHER);
517         }
518         return (ugen20_tr_renew(pdev));
519 }
520
521 static int
522 ugen20_set_alt_index(struct libusb20_device *pdev,
523     uint8_t iface_index, uint8_t alt_index)
524 {
525         struct usb_alt_interface alt_iface;
526
527         memset(&alt_iface, 0, sizeof(alt_iface));
528
529         alt_iface.uai_interface_index = iface_index;
530         alt_iface.uai_alt_index = alt_index;
531
532         /* release all active USB transfers */
533         ugen20_tr_release(pdev);
534
535         if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
536                 return (LIBUSB20_ERROR_OTHER);
537         }
538         return (ugen20_tr_renew(pdev));
539 }
540
541 static int
542 ugen20_reset_device(struct libusb20_device *pdev)
543 {
544         int temp = 0;
545
546         /* release all active USB transfers */
547         ugen20_tr_release(pdev);
548
549         if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
550                 return (LIBUSB20_ERROR_OTHER);
551         }
552         return (ugen20_tr_renew(pdev));
553 }
554
555 static int
556 ugen20_check_connected(struct libusb20_device *pdev)
557 {
558         uint32_t plugtime;
559         int error = 0;
560
561         if (ioctl(pdev->file_ctrl, USB_GET_PLUGTIME, &plugtime)) {
562                 error = LIBUSB20_ERROR_NO_DEVICE;
563                 goto done;
564         }
565
566         if (pdev->session_data.plugtime != plugtime) {
567                 error = LIBUSB20_ERROR_NO_DEVICE;
568                 goto done;
569         }
570 done:
571         return (error);
572 }
573
574 static int
575 ugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
576 {
577         int temp;
578
579         switch (power_mode) {
580         case LIBUSB20_POWER_OFF:
581                 temp = USB_POWER_MODE_OFF;
582                 break;
583         case LIBUSB20_POWER_ON:
584                 temp = USB_POWER_MODE_ON;
585                 break;
586         case LIBUSB20_POWER_SAVE:
587                 temp = USB_POWER_MODE_SAVE;
588                 break;
589         case LIBUSB20_POWER_SUSPEND:
590                 temp = USB_POWER_MODE_SUSPEND;
591                 break;
592         case LIBUSB20_POWER_RESUME:
593                 temp = USB_POWER_MODE_RESUME;
594                 break;
595         default:
596                 return (LIBUSB20_ERROR_INVALID_PARAM);
597         }
598         if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
599                 return (LIBUSB20_ERROR_OTHER);
600         }
601         return (0);
602 }
603
604 static int
605 ugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
606 {
607         int temp;
608
609         if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
610                 return (LIBUSB20_ERROR_OTHER);
611         }
612         switch (temp) {
613         case USB_POWER_MODE_OFF:
614                 temp = LIBUSB20_POWER_OFF;
615                 break;
616         case USB_POWER_MODE_ON:
617                 temp = LIBUSB20_POWER_ON;
618                 break;
619         case USB_POWER_MODE_SAVE:
620                 temp = LIBUSB20_POWER_SAVE;
621                 break;
622         case USB_POWER_MODE_SUSPEND:
623                 temp = LIBUSB20_POWER_SUSPEND;
624                 break;
625         case USB_POWER_MODE_RESUME:
626                 temp = LIBUSB20_POWER_RESUME;
627                 break;
628         default:
629                 temp = LIBUSB20_POWER_ON;
630                 break;
631         }
632         *power_mode = temp;
633         return (0);                     /* success */
634 }
635
636 static int
637 ugen20_kernel_driver_active(struct libusb20_device *pdev,
638     uint8_t iface_index)
639 {
640         int temp = iface_index;
641
642         if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
643                 return (LIBUSB20_ERROR_OTHER);
644         }
645         return (0);                     /* kernel driver is active */
646 }
647
648 static int
649 ugen20_detach_kernel_driver(struct libusb20_device *pdev,
650     uint8_t iface_index)
651 {
652         int temp = iface_index;
653
654         if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
655                 return (LIBUSB20_ERROR_OTHER);
656         }
657         return (0);                     /* kernel driver is active */
658 }
659
660 static int
661 ugen20_do_request_sync(struct libusb20_device *pdev,
662     struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
663     void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
664 {
665         struct usb_ctl_request req;
666
667         memset(&req, 0, sizeof(req));
668
669         req.ucr_data = data;
670         if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
671                 req.ucr_flags |= USB_SHORT_XFER_OK;
672         }
673         if (libusb20_me_encode(&req.ucr_request,
674             sizeof(req.ucr_request), setup)) {
675                 /* ignore */
676         }
677         if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
678                 return (LIBUSB20_ERROR_OTHER);
679         }
680         if (pactlen) {
681                 /* get actual length */
682                 *pactlen = req.ucr_actlen;
683         }
684         return (0);                     /* kernel driver is active */
685 }
686
687 static int
688 ugen20_process(struct libusb20_device *pdev)
689 {
690         struct usb_fs_complete temp;
691         struct usb_fs_endpoint *fsep;
692         struct libusb20_transfer *xfer;
693
694         while (1) {
695
696                 if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
697                         if (errno == EBUSY) {
698                                 break;
699                         } else {
700                                 /* device detached */
701                                 return (LIBUSB20_ERROR_OTHER);
702                         }
703                 }
704                 fsep = pdev->privBeData;
705                 xfer = pdev->pTransfer;
706                 fsep += temp.ep_index;
707                 xfer += temp.ep_index;
708
709                 /* update transfer status */
710
711                 if (fsep->status == 0) {
712                         xfer->aFrames = fsep->aFrames;
713                         xfer->timeComplete = fsep->isoc_time_complete;
714                         xfer->status = LIBUSB20_TRANSFER_COMPLETED;
715                 } else if (fsep->status == USB_ERR_CANCELLED) {
716                         xfer->aFrames = 0;
717                         xfer->timeComplete = 0;
718                         xfer->status = LIBUSB20_TRANSFER_CANCELLED;
719                 } else if (fsep->status == USB_ERR_STALLED) {
720                         xfer->aFrames = 0;
721                         xfer->timeComplete = 0;
722                         xfer->status = LIBUSB20_TRANSFER_STALL;
723                 } else if (fsep->status == USB_ERR_TIMEOUT) {
724                         xfer->aFrames = 0;
725                         xfer->timeComplete = 0;
726                         xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
727                 } else {
728                         xfer->aFrames = 0;
729                         xfer->timeComplete = 0;
730                         xfer->status = LIBUSB20_TRANSFER_ERROR;
731                 }
732                 libusb20_tr_callback_wrapper(xfer);
733         }
734         return (0);                     /* done */
735 }
736
737 static int
738 ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
739     uint32_t MaxFrameCount, uint8_t ep_no, uint8_t pre_scale)
740 {
741         struct usb_fs_open temp;
742         struct usb_fs_endpoint *fsep;
743
744         if (pre_scale)
745                 MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE;
746
747         memset(&temp, 0, sizeof(temp));
748
749         fsep = xfer->pdev->privBeData;
750         fsep += xfer->trIndex;
751
752         temp.max_bufsize = MaxBufSize;
753         temp.max_frames = MaxFrameCount;
754         temp.ep_index = xfer->trIndex;
755         temp.ep_no = ep_no;
756
757         if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
758                 return (LIBUSB20_ERROR_INVALID_PARAM);
759         }
760         /* maximums might have changed - update */
761         xfer->maxFrames = temp.max_frames;
762
763         /* "max_bufsize" should be multiple of "max_packet_length" */
764         xfer->maxTotalLength = temp.max_bufsize;
765         xfer->maxPacketLen = temp.max_packet_length;
766
767         /* setup buffer and length lists */
768         fsep->ppBuffer = xfer->ppBuffer;/* zero copy */
769         fsep->pLength = xfer->pLength;  /* zero copy */
770
771         return (0);                     /* success */
772 }
773
774 static int
775 ugen20_tr_close(struct libusb20_transfer *xfer)
776 {
777         struct usb_fs_close temp;
778
779         memset(&temp, 0, sizeof(temp));
780
781         temp.ep_index = xfer->trIndex;
782
783         if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
784                 return (LIBUSB20_ERROR_INVALID_PARAM);
785         }
786         return (0);                     /* success */
787 }
788
789 static int
790 ugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
791 {
792         struct usb_fs_clear_stall_sync temp;
793
794         memset(&temp, 0, sizeof(temp));
795
796         /* if the transfer is active, an error will be returned */
797
798         temp.ep_index = xfer->trIndex;
799
800         if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
801                 return (LIBUSB20_ERROR_INVALID_PARAM);
802         }
803         return (0);                     /* success */
804 }
805
806 static void
807 ugen20_tr_submit(struct libusb20_transfer *xfer)
808 {
809         struct usb_fs_start temp;
810         struct usb_fs_endpoint *fsep;
811
812         memset(&temp, 0, sizeof(temp));
813
814         fsep = xfer->pdev->privBeData;
815         fsep += xfer->trIndex;
816
817         fsep->nFrames = xfer->nFrames;
818         fsep->flags = 0;
819         if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
820                 fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
821         }
822         if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
823                 fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
824         }
825         if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
826                 fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
827         }
828         if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
829                 fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
830         }
831         /* NOTE: The "fsep->timeout" variable is 16-bit. */
832         if (xfer->timeout > 65535)
833                 fsep->timeout = 65535;
834         else
835                 fsep->timeout = xfer->timeout;
836
837         temp.ep_index = xfer->trIndex;
838
839         if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
840                 /* ignore any errors - should never happen */
841         }
842         return;                         /* success */
843 }
844
845 static void
846 ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
847 {
848         struct usb_fs_stop temp;
849
850         memset(&temp, 0, sizeof(temp));
851
852         temp.ep_index = xfer->trIndex;
853
854         if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
855                 /* ignore any errors - should never happen */
856         }
857         return;
858 }
859
860 static int
861 ugen20_be_ioctl(uint32_t cmd, void *data)
862 {
863         int f;
864         int error;
865
866         f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
867         if (f < 0)
868                 return (LIBUSB20_ERROR_OTHER);
869         error = ioctl(f, cmd, data);
870         if (error == -1) {
871                 if (errno == EPERM) {
872                         error = LIBUSB20_ERROR_ACCESS;
873                 } else {
874                         error = LIBUSB20_ERROR_OTHER;
875                 }
876         }
877         close(f);
878         return (error);
879 }
880
881 static int
882 ugen20_dev_get_iface_desc(struct libusb20_device *pdev, 
883     uint8_t iface_index, char *buf, uint8_t len)
884 {
885         struct usb_gen_descriptor ugd;
886
887         memset(&ugd, 0, sizeof(ugd));
888
889         ugd.ugd_data = buf;
890         ugd.ugd_maxlen = len;
891         ugd.ugd_iface_index = iface_index;
892
893         if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
894                 return (LIBUSB20_ERROR_INVALID_PARAM);
895         }
896         return (0);
897 }
898
899 static int
900 ugen20_dev_get_info(struct libusb20_device *pdev,
901     struct usb_device_info *pinfo)
902 {
903         if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
904                 return (LIBUSB20_ERROR_INVALID_PARAM);
905         }
906         return (0);
907 }
908
909 static int
910 ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
911     uint16_t quirk_index, struct libusb20_quirk *pq)
912 {
913         struct usb_gen_quirk q;
914         int error;
915
916         memset(&q, 0, sizeof(q));
917
918         q.index = quirk_index;
919
920         error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
921
922         if (error) {
923                 if (errno == EINVAL) {
924                         return (LIBUSB20_ERROR_NOT_FOUND);
925                 }
926         } else {
927                 pq->vid = q.vid;
928                 pq->pid = q.pid;
929                 pq->bcdDeviceLow = q.bcdDeviceLow;
930                 pq->bcdDeviceHigh = q.bcdDeviceHigh;
931                 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
932         }
933         return (error);
934 }
935
936 static int
937 ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
938     struct libusb20_quirk *pq)
939 {
940         struct usb_gen_quirk q;
941         int error;
942
943         memset(&q, 0, sizeof(q));
944
945         q.index = quirk_index;
946
947         error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
948
949         if (error) {
950                 if (errno == EINVAL) {
951                         return (LIBUSB20_ERROR_NOT_FOUND);
952                 }
953         } else {
954                 strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
955         }
956         return (error);
957 }
958
959 static int
960 ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
961     struct libusb20_quirk *pq)
962 {
963         struct usb_gen_quirk q;
964         int error;
965
966         memset(&q, 0, sizeof(q));
967
968         q.vid = pq->vid;
969         q.pid = pq->pid;
970         q.bcdDeviceLow = pq->bcdDeviceLow;
971         q.bcdDeviceHigh = pq->bcdDeviceHigh;
972         strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
973
974         error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
975         if (error) {
976                 if (errno == ENOMEM) {
977                         return (LIBUSB20_ERROR_NO_MEM);
978                 }
979         }
980         return (error);
981 }
982
983 static int
984 ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
985     struct libusb20_quirk *pq)
986 {
987         struct usb_gen_quirk q;
988         int error;
989
990         memset(&q, 0, sizeof(q));
991
992         q.vid = pq->vid;
993         q.pid = pq->pid;
994         q.bcdDeviceLow = pq->bcdDeviceLow;
995         q.bcdDeviceHigh = pq->bcdDeviceHigh;
996         strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
997
998         error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
999         if (error) {
1000                 if (errno == EINVAL) {
1001                         return (LIBUSB20_ERROR_NOT_FOUND);
1002                 }
1003         }
1004         return (error);
1005 }
1006
1007 static int
1008 ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1009 {
1010         return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
1011 }
1012
1013 static int
1014 ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1015 {
1016         return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));
1017 }