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