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