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