libusb20_ugen20.c revision 189110
1184610Salfred/* $FreeBSD: head/lib/libusb20/libusb20_ugen20.c 189110 2009-02-27 17:27:16Z thompsa $ */
2184610Salfred/*-
3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred *
14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24184610Salfred * SUCH DAMAGE.
25184610Salfred */
26184610Salfred
27184610Salfred#include <sys/queue.h>
28184610Salfred#include <sys/types.h>
29184610Salfred
30184610Salfred#include <stdio.h>
31184610Salfred#include <stdlib.h>
32184610Salfred#include <unistd.h>
33184610Salfred#include <string.h>
34184610Salfred#include <poll.h>
35184610Salfred#include <fcntl.h>
36184610Salfred#include <errno.h>
37184610Salfred
38184610Salfred#include "libusb20.h"
39184610Salfred#include "libusb20_desc.h"
40184610Salfred#include "libusb20_int.h"
41184610Salfred
42188945Sthompsa#include <dev/usb/usb.h>
43188945Sthompsa#include <dev/usb/usb_ioctl.h>
44188945Sthompsa#include <dev/usb/usb_mfunc.h>
45188945Sthompsa#include <dev/usb/usb_error.h>
46188945Sthompsa#include <dev/usb/usb_revision.h>
47184610Salfred
48184610Salfredstatic libusb20_init_backend_t ugen20_init_backend;
49184610Salfredstatic libusb20_open_device_t ugen20_open_device;
50184610Salfredstatic libusb20_close_device_t ugen20_close_device;
51184610Salfredstatic libusb20_get_backend_name_t ugen20_get_backend_name;
52184610Salfredstatic libusb20_exit_backend_t ugen20_exit_backend;
53188622Sthompsastatic libusb20_dev_get_iface_desc_t ugen20_dev_get_iface_desc;
54188622Sthompsastatic libusb20_dev_get_info_t ugen20_dev_get_info;
55184610Salfredstatic libusb20_root_get_dev_quirk_t ugen20_root_get_dev_quirk;
56184610Salfredstatic libusb20_root_get_quirk_name_t ugen20_root_get_quirk_name;
57184610Salfredstatic libusb20_root_add_dev_quirk_t ugen20_root_add_dev_quirk;
58184610Salfredstatic libusb20_root_remove_dev_quirk_t ugen20_root_remove_dev_quirk;
59188987Sthompsastatic libusb20_root_set_template_t ugen20_root_set_template;
60188987Sthompsastatic libusb20_root_get_template_t ugen20_root_get_template;
61184610Salfred
62184610Salfredconst struct libusb20_backend_methods libusb20_ugen20_backend = {
63184610Salfred	LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
64184610Salfred};
65184610Salfred
66184610Salfred/* USB device specific */
67184610Salfredstatic libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
68184610Salfredstatic libusb20_get_config_index_t ugen20_get_config_index;
69184610Salfredstatic libusb20_set_config_index_t ugen20_set_config_index;
70184610Salfredstatic libusb20_claim_interface_t ugen20_claim_interface;
71184610Salfredstatic libusb20_release_interface_t ugen20_release_interface;
72184610Salfredstatic libusb20_set_alt_index_t ugen20_set_alt_index;
73184610Salfredstatic libusb20_reset_device_t ugen20_reset_device;
74184610Salfredstatic libusb20_set_power_mode_t ugen20_set_power_mode;
75184610Salfredstatic libusb20_get_power_mode_t ugen20_get_power_mode;
76184610Salfredstatic libusb20_kernel_driver_active_t ugen20_kernel_driver_active;
77184610Salfredstatic libusb20_detach_kernel_driver_t ugen20_detach_kernel_driver;
78184610Salfredstatic libusb20_do_request_sync_t ugen20_do_request_sync;
79184610Salfredstatic libusb20_process_t ugen20_process;
80184610Salfred
81184610Salfred/* USB transfer specific */
82184610Salfredstatic libusb20_tr_open_t ugen20_tr_open;
83184610Salfredstatic libusb20_tr_close_t ugen20_tr_close;
84184610Salfredstatic libusb20_tr_clear_stall_sync_t ugen20_tr_clear_stall_sync;
85184610Salfredstatic libusb20_tr_submit_t ugen20_tr_submit;
86184610Salfredstatic libusb20_tr_cancel_async_t ugen20_tr_cancel_async;
87184610Salfred
88184610Salfredstatic const struct libusb20_device_methods libusb20_ugen20_device_methods = {
89184610Salfred	LIBUSB20_DEVICE(LIBUSB20_DECLARE, ugen20)
90184610Salfred};
91184610Salfred
92184610Salfredstatic const char *
93184610Salfredugen20_get_backend_name(void)
94184610Salfred{
95184610Salfred	return ("FreeBSD UGEN 2.0");
96184610Salfred}
97184610Salfred
98184610Salfredstatic uint32_t
99184610Salfredugen20_path_convert_one(const char **pp)
100184610Salfred{
101184610Salfred	const char *ptr;
102184610Salfred	uint32_t temp = 0;
103184610Salfred
104184610Salfred	ptr = *pp;
105184610Salfred
106184610Salfred	while ((*ptr >= '0') && (*ptr <= '9')) {
107184610Salfred		temp *= 10;
108184610Salfred		temp += (*ptr - '0');
109184610Salfred		if (temp >= 1000000) {
110184610Salfred			/* catch overflow early */
111184610Salfred			return (0 - 1);
112184610Salfred		}
113184610Salfred		ptr++;
114184610Salfred	}
115184610Salfred
116184610Salfred	if (*ptr == '.') {
117184610Salfred		/* skip dot */
118184610Salfred		ptr++;
119184610Salfred	}
120184610Salfred	*pp = ptr;
121184610Salfred
122184610Salfred	return (temp);
123184610Salfred}
124184610Salfred
125184610Salfredstatic int
126184610Salfredugen20_enumerate(struct libusb20_device *pdev, const char *id)
127184610Salfred{
128184610Salfred	const char *tmp = id;
129184610Salfred	struct usb2_device_descriptor ddesc;
130184610Salfred	struct usb2_device_info devinfo;
131184610Salfred	uint32_t plugtime;
132184610Salfred	char buf[64];
133184610Salfred	int f;
134184610Salfred	int error;
135184610Salfred
136184610Salfred	pdev->bus_number = ugen20_path_convert_one(&tmp);
137184610Salfred	pdev->device_address = ugen20_path_convert_one(&tmp);
138184610Salfred
139189110Sthompsa	snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
140184610Salfred	    pdev->bus_number, pdev->device_address);
141184610Salfred
142184610Salfred	f = open(buf, O_RDWR);
143184610Salfred	if (f < 0) {
144184610Salfred		return (LIBUSB20_ERROR_OTHER);
145184610Salfred	}
146184610Salfred	if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
147184610Salfred		error = LIBUSB20_ERROR_OTHER;
148184610Salfred		goto done;
149184610Salfred	}
150184610Salfred	/* store when the device was plugged */
151184610Salfred	pdev->session_data.plugtime = plugtime;
152184610Salfred
153184610Salfred	if (ioctl(f, USB_GET_DEVICE_DESC, &ddesc)) {
154184610Salfred		error = LIBUSB20_ERROR_OTHER;
155184610Salfred		goto done;
156184610Salfred	}
157184610Salfred	LIBUSB20_INIT(LIBUSB20_DEVICE_DESC, &(pdev->ddesc));
158184610Salfred
159184610Salfred	libusb20_me_decode(&ddesc, sizeof(ddesc), &(pdev->ddesc));
160184610Salfred
161184610Salfred	if (pdev->ddesc.bNumConfigurations == 0) {
162184610Salfred		error = LIBUSB20_ERROR_OTHER;
163184610Salfred		goto done;
164184610Salfred	} else if (pdev->ddesc.bNumConfigurations >= 8) {
165184610Salfred		error = LIBUSB20_ERROR_OTHER;
166184610Salfred		goto done;
167184610Salfred	}
168184610Salfred	if (ioctl(f, USB_GET_DEVICEINFO, &devinfo)) {
169184610Salfred		error = LIBUSB20_ERROR_OTHER;
170184610Salfred		goto done;
171184610Salfred	}
172184610Salfred	switch (devinfo.udi_mode) {
173184610Salfred	case USB_MODE_DEVICE:
174184610Salfred		pdev->usb_mode = LIBUSB20_MODE_DEVICE;
175184610Salfred		break;
176184610Salfred	default:
177184610Salfred		pdev->usb_mode = LIBUSB20_MODE_HOST;
178184610Salfred		break;
179184610Salfred	}
180184610Salfred
181184610Salfred	switch (devinfo.udi_speed) {
182184610Salfred	case USB_SPEED_LOW:
183184610Salfred		pdev->usb_speed = LIBUSB20_SPEED_LOW;
184184610Salfred		break;
185184610Salfred	case USB_SPEED_FULL:
186184610Salfred		pdev->usb_speed = LIBUSB20_SPEED_FULL;
187184610Salfred		break;
188184610Salfred	case USB_SPEED_HIGH:
189184610Salfred		pdev->usb_speed = LIBUSB20_SPEED_HIGH;
190184610Salfred		break;
191184610Salfred	case USB_SPEED_VARIABLE:
192184610Salfred		pdev->usb_speed = LIBUSB20_SPEED_VARIABLE;
193184610Salfred		break;
194184610Salfred	case USB_SPEED_SUPER:
195184610Salfred		pdev->usb_speed = LIBUSB20_SPEED_SUPER;
196184610Salfred		break;
197184610Salfred	default:
198184610Salfred		pdev->usb_speed = LIBUSB20_SPEED_UNKNOWN;
199184610Salfred		break;
200184610Salfred	}
201184610Salfred
202184610Salfred	/* generate a nice description for printout */
203184610Salfred
204184610Salfred	snprintf(pdev->usb_desc, sizeof(pdev->usb_desc),
205189110Sthompsa	    USB_GENERIC_NAME "%u.%u: <%s %s> at usbus%u", pdev->bus_number,
206184610Salfred	    pdev->device_address, devinfo.udi_product,
207184610Salfred	    devinfo.udi_vendor, pdev->bus_number);
208184610Salfred
209184610Salfred	error = 0;
210184610Salfreddone:
211184610Salfred	close(f);
212184610Salfred	return (error);
213184610Salfred}
214184610Salfred
215184610Salfredstruct ugen20_urd_state {
216184610Salfred	struct usb2_read_dir urd;
217184610Salfred	uint32_t nparsed;
218184610Salfred	int	f;
219184610Salfred	uint8_t *ptr;
220184610Salfred	const char *src;
221184610Salfred	const char *dst;
222184610Salfred	uint8_t	buf[256];
223184610Salfred	uint8_t	dummy_zero[1];
224184610Salfred};
225184610Salfred
226184610Salfredstatic int
227184610Salfredugen20_readdir(struct ugen20_urd_state *st)
228184610Salfred{
229184610Salfred	;				/* style fix */
230184610Salfredrepeat:
231184610Salfred	if (st->ptr == NULL) {
232184610Salfred		st->urd.urd_startentry += st->nparsed;
233184610Salfred		st->urd.urd_data = st->buf;
234184610Salfred		st->urd.urd_maxlen = sizeof(st->buf);
235184610Salfred		st->nparsed = 0;
236184610Salfred
237184610Salfred		if (ioctl(st->f, USB_READ_DIR, &st->urd)) {
238184610Salfred			return (EINVAL);
239184610Salfred		}
240184610Salfred		st->ptr = st->buf;
241184610Salfred	}
242184610Salfred	if (st->ptr[0] == 0) {
243184610Salfred		if (st->nparsed) {
244184610Salfred			st->ptr = NULL;
245184610Salfred			goto repeat;
246184610Salfred		} else {
247184610Salfred			return (ENXIO);
248184610Salfred		}
249184610Salfred	}
250184610Salfred	st->src = (void *)(st->ptr + 1);
251184610Salfred	st->dst = st->src + strlen(st->src) + 1;
252184610Salfred	st->ptr = st->ptr + st->ptr[0];
253184610Salfred	st->nparsed++;
254184610Salfred
255184610Salfred	if ((st->ptr < st->buf) ||
256184610Salfred	    (st->ptr > st->dummy_zero)) {
257184610Salfred		/* invalid entry */
258184610Salfred		return (EINVAL);
259184610Salfred	}
260184610Salfred	return (0);
261184610Salfred}
262184610Salfred
263184610Salfredstatic int
264184610Salfredugen20_init_backend(struct libusb20_backend *pbe)
265184610Salfred{
266184610Salfred	struct ugen20_urd_state state;
267184610Salfred	struct libusb20_device *pdev;
268184610Salfred
269184610Salfred	memset(&state, 0, sizeof(state));
270184610Salfred
271189110Sthompsa	state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
272184610Salfred	if (state.f < 0)
273184610Salfred		return (LIBUSB20_ERROR_OTHER);
274184610Salfred
275184610Salfred	while (ugen20_readdir(&state) == 0) {
276184610Salfred
277184610Salfred		if ((state.src[0] != 'u') ||
278184610Salfred		    (state.src[1] != 'g') ||
279184610Salfred		    (state.src[2] != 'e') ||
280184610Salfred		    (state.src[3] != 'n')) {
281184610Salfred			continue;
282184610Salfred		}
283184610Salfred		pdev = libusb20_dev_alloc();
284184610Salfred		if (pdev == NULL) {
285184610Salfred			continue;
286184610Salfred		}
287184610Salfred		if (ugen20_enumerate(pdev, state.src + 4)) {
288184610Salfred			libusb20_dev_free(pdev);
289184610Salfred			continue;
290184610Salfred		}
291184610Salfred		/* put the device on the backend list */
292184610Salfred		libusb20_be_enqueue_device(pbe, pdev);
293184610Salfred	}
294184610Salfred	close(state.f);
295184610Salfred	return (0);			/* success */
296184610Salfred}
297184610Salfred
298185290Salfredstatic void
299185290Salfredugen20_tr_release(struct libusb20_device *pdev)
300185290Salfred{
301185290Salfred	struct usb2_fs_uninit fs_uninit;
302185290Salfred
303185290Salfred	if (pdev->nTransfer == 0) {
304185290Salfred		return;
305185290Salfred	}
306185290Salfred	/* release all pending USB transfers */
307185290Salfred	if (pdev->privBeData != NULL) {
308185290Salfred		memset(&fs_uninit, 0, sizeof(fs_uninit));
309185290Salfred		if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
310185290Salfred			/* ignore any errors of this kind */
311185290Salfred		}
312185290Salfred	}
313185290Salfred	return;
314185290Salfred}
315185290Salfred
316184610Salfredstatic int
317185087Salfredugen20_tr_renew(struct libusb20_device *pdev)
318185087Salfred{
319185087Salfred	struct usb2_fs_init fs_init;
320185087Salfred	struct usb2_fs_endpoint *pfse;
321185087Salfred	int error;
322185087Salfred	uint32_t size;
323185087Salfred	uint16_t nMaxTransfer;
324185087Salfred
325185087Salfred	nMaxTransfer = pdev->nTransfer;
326185087Salfred	error = 0;
327185087Salfred
328185087Salfred	if (nMaxTransfer == 0) {
329185087Salfred		goto done;
330185087Salfred	}
331185087Salfred	size = nMaxTransfer * sizeof(*pfse);
332185087Salfred
333185290Salfred	if (pdev->privBeData == NULL) {
334185087Salfred		pfse = malloc(size);
335185087Salfred		if (pfse == NULL) {
336185087Salfred			error = LIBUSB20_ERROR_NO_MEM;
337185087Salfred			goto done;
338185087Salfred		}
339185087Salfred		pdev->privBeData = pfse;
340185087Salfred	}
341185087Salfred	/* reset endpoint data */
342185087Salfred	memset(pdev->privBeData, 0, size);
343185087Salfred
344185087Salfred	memset(&fs_init, 0, sizeof(fs_init));
345185087Salfred
346185087Salfred	fs_init.pEndpoints = pdev->privBeData;
347185087Salfred	fs_init.ep_index_max = nMaxTransfer;
348185087Salfred
349185087Salfred	if (ioctl(pdev->file, USB_FS_INIT, &fs_init)) {
350185087Salfred		error = LIBUSB20_ERROR_OTHER;
351185087Salfred		goto done;
352185087Salfred	}
353185087Salfreddone:
354185087Salfred	return (error);
355185087Salfred}
356185087Salfred
357185087Salfredstatic int
358184610Salfredugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
359184610Salfred{
360184610Salfred	uint32_t plugtime;
361184610Salfred	char buf[64];
362184610Salfred	int f;
363184610Salfred	int g;
364184610Salfred	int error;
365184610Salfred
366189110Sthompsa	snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
367184610Salfred	    pdev->bus_number, pdev->device_address);
368184610Salfred
369184610Salfred	/*
370184610Salfred	 * We need two file handles, one for the control endpoint and one
371184610Salfred	 * for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
372184610Salfred	 * kernel locking.
373184610Salfred	 */
374184610Salfred	g = open(buf, O_RDWR);
375184610Salfred	if (g < 0) {
376184610Salfred		return (LIBUSB20_ERROR_NO_DEVICE);
377184610Salfred	}
378184610Salfred	f = open(buf, O_RDWR);
379184610Salfred	if (f < 0) {
380184610Salfred		close(g);
381184610Salfred		return (LIBUSB20_ERROR_NO_DEVICE);
382184610Salfred	}
383184610Salfred	if (ioctl(f, USB_GET_PLUGTIME, &plugtime)) {
384184610Salfred		error = LIBUSB20_ERROR_OTHER;
385184610Salfred		goto done;
386184610Salfred	}
387184610Salfred	/* check that the correct device is still plugged */
388184610Salfred	if (pdev->session_data.plugtime != plugtime) {
389184610Salfred		error = LIBUSB20_ERROR_NO_DEVICE;
390184610Salfred		goto done;
391184610Salfred	}
392185087Salfred	/* need to set this before "tr_renew()" */
393185087Salfred	pdev->file = f;
394185087Salfred	pdev->file_ctrl = g;
395184610Salfred
396185087Salfred	/* renew all USB transfers */
397185087Salfred	error = ugen20_tr_renew(pdev);
398185087Salfred	if (error) {
399185087Salfred		goto done;
400184610Salfred	}
401184610Salfred	/* set methods */
402184610Salfred	pdev->methods = &libusb20_ugen20_device_methods;
403185087Salfred
404184610Salfreddone:
405184610Salfred	if (error) {
406185087Salfred		if (pdev->privBeData) {
407185087Salfred			/* cleanup after "tr_renew()" */
408185087Salfred			free(pdev->privBeData);
409185087Salfred			pdev->privBeData = NULL;
410184610Salfred		}
411185087Salfred		pdev->file = -1;
412185087Salfred		pdev->file_ctrl = -1;
413184610Salfred		close(f);
414184610Salfred		close(g);
415184610Salfred	}
416184610Salfred	return (error);
417184610Salfred}
418184610Salfred
419184610Salfredstatic int
420184610Salfredugen20_close_device(struct libusb20_device *pdev)
421184610Salfred{
422185087Salfred	struct usb2_fs_uninit fs_uninit;
423184610Salfred
424184610Salfred	if (pdev->privBeData) {
425185087Salfred		memset(&fs_uninit, 0, sizeof(fs_uninit));
426184610Salfred		if (ioctl(pdev->file, USB_FS_UNINIT, &fs_uninit)) {
427185290Salfred			/* ignore this error */
428184610Salfred		}
429184610Salfred		free(pdev->privBeData);
430184610Salfred	}
431184610Salfred	pdev->nTransfer = 0;
432184610Salfred	pdev->privBeData = NULL;
433184610Salfred	close(pdev->file);
434184610Salfred	close(pdev->file_ctrl);
435184610Salfred	pdev->file = -1;
436184610Salfred	pdev->file_ctrl = -1;
437185290Salfred	return (0);			/* success */
438184610Salfred}
439184610Salfred
440184610Salfredstatic void
441184610Salfredugen20_exit_backend(struct libusb20_backend *pbe)
442184610Salfred{
443184610Salfred	return;				/* nothing to do */
444184610Salfred}
445184610Salfred
446184610Salfredstatic int
447184610Salfredugen20_get_config_desc_full(struct libusb20_device *pdev,
448185087Salfred    uint8_t **ppbuf, uint16_t *plen, uint8_t cfg_index)
449184610Salfred{
450185087Salfred	struct usb2_gen_descriptor gen_desc;
451184610Salfred	struct usb2_config_descriptor cdesc;
452184610Salfred	uint8_t *ptr;
453184610Salfred	uint16_t len;
454184610Salfred	int error;
455184610Salfred
456185087Salfred	memset(&gen_desc, 0, sizeof(gen_desc));
457185087Salfred
458184610Salfred	gen_desc.ugd_data = &cdesc;
459184610Salfred	gen_desc.ugd_maxlen = sizeof(cdesc);
460185087Salfred	gen_desc.ugd_config_index = cfg_index;
461184610Salfred
462184610Salfred	error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
463184610Salfred	if (error) {
464184610Salfred		return (LIBUSB20_ERROR_OTHER);
465184610Salfred	}
466184610Salfred	len = UGETW(cdesc.wTotalLength);
467184610Salfred	if (len < sizeof(cdesc)) {
468184610Salfred		/* corrupt descriptor */
469184610Salfred		return (LIBUSB20_ERROR_OTHER);
470184610Salfred	}
471184610Salfred	ptr = malloc(len);
472184610Salfred	if (!ptr) {
473184610Salfred		return (LIBUSB20_ERROR_NO_MEM);
474184610Salfred	}
475184610Salfred	gen_desc.ugd_data = ptr;
476184610Salfred	gen_desc.ugd_maxlen = len;
477184610Salfred
478184610Salfred	error = ioctl(pdev->file_ctrl, USB_GET_FULL_DESC, &gen_desc);
479184610Salfred	if (error) {
480184610Salfred		free(ptr);
481184610Salfred		return (LIBUSB20_ERROR_OTHER);
482184610Salfred	}
483184610Salfred	/* make sure that the device doesn't fool us */
484184610Salfred	memcpy(ptr, &cdesc, sizeof(cdesc));
485184610Salfred
486184610Salfred	*ppbuf = ptr;
487184610Salfred	*plen = len;
488184610Salfred
489184610Salfred	return (0);			/* success */
490184610Salfred}
491184610Salfred
492184610Salfredstatic int
493184610Salfredugen20_get_config_index(struct libusb20_device *pdev, uint8_t *pindex)
494184610Salfred{
495184610Salfred	int temp;
496184610Salfred
497184610Salfred	if (ioctl(pdev->file_ctrl, USB_GET_CONFIG, &temp)) {
498184610Salfred		return (LIBUSB20_ERROR_OTHER);
499184610Salfred	}
500184610Salfred	*pindex = temp;
501184610Salfred
502184610Salfred	return (0);
503184610Salfred}
504184610Salfred
505184610Salfredstatic int
506185087Salfredugen20_set_config_index(struct libusb20_device *pdev, uint8_t cfg_index)
507184610Salfred{
508185087Salfred	int temp = cfg_index;
509184610Salfred
510185290Salfred	/* release all active USB transfers */
511185290Salfred	ugen20_tr_release(pdev);
512185290Salfred
513184610Salfred	if (ioctl(pdev->file_ctrl, USB_SET_CONFIG, &temp)) {
514184610Salfred		return (LIBUSB20_ERROR_OTHER);
515184610Salfred	}
516185087Salfred	return (ugen20_tr_renew(pdev));
517184610Salfred}
518184610Salfred
519184610Salfredstatic int
520184610Salfredugen20_claim_interface(struct libusb20_device *pdev, uint8_t iface_index)
521184610Salfred{
522184610Salfred	int temp = iface_index;
523184610Salfred
524184610Salfred	if (ioctl(pdev->file_ctrl, USB_CLAIM_INTERFACE, &temp)) {
525184610Salfred		return (LIBUSB20_ERROR_OTHER);
526184610Salfred	}
527184610Salfred	return (0);
528184610Salfred}
529184610Salfred
530184610Salfredstatic int
531184610Salfredugen20_release_interface(struct libusb20_device *pdev, uint8_t iface_index)
532184610Salfred{
533184610Salfred	int temp = iface_index;
534184610Salfred
535184610Salfred	if (ioctl(pdev->file_ctrl, USB_RELEASE_INTERFACE, &temp)) {
536184610Salfred		return (LIBUSB20_ERROR_OTHER);
537184610Salfred	}
538184610Salfred	return (0);
539184610Salfred}
540184610Salfred
541184610Salfredstatic int
542184610Salfredugen20_set_alt_index(struct libusb20_device *pdev,
543184610Salfred    uint8_t iface_index, uint8_t alt_index)
544184610Salfred{
545185087Salfred	struct usb2_alt_interface alt_iface;
546184610Salfred
547185087Salfred	memset(&alt_iface, 0, sizeof(alt_iface));
548185087Salfred
549184610Salfred	alt_iface.uai_interface_index = iface_index;
550184610Salfred	alt_iface.uai_alt_index = alt_index;
551184610Salfred
552185290Salfred	/* release all active USB transfers */
553185290Salfred	ugen20_tr_release(pdev);
554185290Salfred
555184610Salfred	if (ioctl(pdev->file_ctrl, USB_SET_ALTINTERFACE, &alt_iface)) {
556184610Salfred		return (LIBUSB20_ERROR_OTHER);
557184610Salfred	}
558185087Salfred	return (ugen20_tr_renew(pdev));
559184610Salfred}
560184610Salfred
561184610Salfredstatic int
562184610Salfredugen20_reset_device(struct libusb20_device *pdev)
563184610Salfred{
564184610Salfred	int temp = 0;
565184610Salfred
566185290Salfred	/* release all active USB transfers */
567185290Salfred	ugen20_tr_release(pdev);
568185290Salfred
569184610Salfred	if (ioctl(pdev->file_ctrl, USB_DEVICEENUMERATE, &temp)) {
570184610Salfred		return (LIBUSB20_ERROR_OTHER);
571184610Salfred	}
572185087Salfred	return (ugen20_tr_renew(pdev));
573184610Salfred}
574184610Salfred
575184610Salfredstatic int
576184610Salfredugen20_set_power_mode(struct libusb20_device *pdev, uint8_t power_mode)
577184610Salfred{
578184610Salfred	int temp;
579184610Salfred
580184610Salfred	switch (power_mode) {
581184610Salfred	case LIBUSB20_POWER_OFF:
582184610Salfred		temp = USB_POWER_MODE_OFF;
583184610Salfred		break;
584184610Salfred	case LIBUSB20_POWER_ON:
585184610Salfred		temp = USB_POWER_MODE_ON;
586184610Salfred		break;
587184610Salfred	case LIBUSB20_POWER_SAVE:
588184610Salfred		temp = USB_POWER_MODE_SAVE;
589184610Salfred		break;
590184610Salfred	case LIBUSB20_POWER_SUSPEND:
591184610Salfred		temp = USB_POWER_MODE_SUSPEND;
592184610Salfred		break;
593184610Salfred	case LIBUSB20_POWER_RESUME:
594184610Salfred		temp = USB_POWER_MODE_RESUME;
595184610Salfred		break;
596184610Salfred	default:
597184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
598184610Salfred	}
599184610Salfred	if (ioctl(pdev->file_ctrl, USB_SET_POWER_MODE, &temp)) {
600184610Salfred		return (LIBUSB20_ERROR_OTHER);
601184610Salfred	}
602184610Salfred	return (0);
603184610Salfred}
604184610Salfred
605184610Salfredstatic int
606184610Salfredugen20_get_power_mode(struct libusb20_device *pdev, uint8_t *power_mode)
607184610Salfred{
608184610Salfred	int temp;
609184610Salfred
610184610Salfred	if (ioctl(pdev->file_ctrl, USB_GET_POWER_MODE, &temp)) {
611184610Salfred		return (LIBUSB20_ERROR_OTHER);
612184610Salfred	}
613184610Salfred	switch (temp) {
614184610Salfred	case USB_POWER_MODE_OFF:
615184610Salfred		temp = LIBUSB20_POWER_OFF;
616184610Salfred		break;
617184610Salfred	case USB_POWER_MODE_ON:
618184610Salfred		temp = LIBUSB20_POWER_ON;
619184610Salfred		break;
620184610Salfred	case USB_POWER_MODE_SAVE:
621184610Salfred		temp = LIBUSB20_POWER_SAVE;
622184610Salfred		break;
623184610Salfred	case USB_POWER_MODE_SUSPEND:
624184610Salfred		temp = LIBUSB20_POWER_SUSPEND;
625184610Salfred		break;
626184610Salfred	case USB_POWER_MODE_RESUME:
627184610Salfred		temp = LIBUSB20_POWER_RESUME;
628184610Salfred		break;
629184610Salfred	default:
630184610Salfred		temp = LIBUSB20_POWER_ON;
631184610Salfred		break;
632184610Salfred	}
633184610Salfred	*power_mode = temp;
634184610Salfred	return (0);			/* success */
635184610Salfred}
636184610Salfred
637184610Salfredstatic int
638184610Salfredugen20_kernel_driver_active(struct libusb20_device *pdev,
639184610Salfred    uint8_t iface_index)
640184610Salfred{
641184610Salfred	int temp = iface_index;
642184610Salfred
643184610Salfred	if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_ACTIVE, &temp)) {
644184610Salfred		return (LIBUSB20_ERROR_OTHER);
645184610Salfred	}
646184610Salfred	return (0);			/* kernel driver is active */
647184610Salfred}
648184610Salfred
649184610Salfredstatic int
650184610Salfredugen20_detach_kernel_driver(struct libusb20_device *pdev,
651184610Salfred    uint8_t iface_index)
652184610Salfred{
653184610Salfred	int temp = iface_index;
654184610Salfred
655184610Salfred	if (ioctl(pdev->file_ctrl, USB_IFACE_DRIVER_DETACH, &temp)) {
656184610Salfred		return (LIBUSB20_ERROR_OTHER);
657184610Salfred	}
658184610Salfred	return (0);			/* kernel driver is active */
659184610Salfred}
660184610Salfred
661184610Salfredstatic int
662184610Salfredugen20_do_request_sync(struct libusb20_device *pdev,
663184610Salfred    struct LIBUSB20_CONTROL_SETUP_DECODED *setup,
664184610Salfred    void *data, uint16_t *pactlen, uint32_t timeout, uint8_t flags)
665184610Salfred{
666185087Salfred	struct usb2_ctl_request req;
667184610Salfred
668185087Salfred	memset(&req, 0, sizeof(req));
669185087Salfred
670184610Salfred	req.ucr_data = data;
671184610Salfred	if (!(flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
672184610Salfred		req.ucr_flags |= USB_SHORT_XFER_OK;
673184610Salfred	}
674184610Salfred	if (libusb20_me_encode(&req.ucr_request,
675184610Salfred	    sizeof(req.ucr_request), setup)) {
676184610Salfred		/* ignore */
677184610Salfred	}
678184610Salfred	if (ioctl(pdev->file_ctrl, USB_DO_REQUEST, &req)) {
679184610Salfred		return (LIBUSB20_ERROR_OTHER);
680184610Salfred	}
681184610Salfred	if (pactlen) {
682184610Salfred		/* get actual length */
683184610Salfred		*pactlen = req.ucr_actlen;
684184610Salfred	}
685184610Salfred	return (0);			/* kernel driver is active */
686184610Salfred}
687184610Salfred
688184610Salfredstatic int
689184610Salfredugen20_process(struct libusb20_device *pdev)
690184610Salfred{
691184610Salfred	struct usb2_fs_complete temp;
692184610Salfred	struct usb2_fs_endpoint *fsep;
693184610Salfred	struct libusb20_transfer *xfer;
694184610Salfred
695184610Salfred	while (1) {
696184610Salfred
697184610Salfred		if (ioctl(pdev->file, USB_FS_COMPLETE, &temp)) {
698184610Salfred			if (errno == EBUSY) {
699184610Salfred				break;
700184610Salfred			} else {
701184610Salfred				/* device detached */
702184610Salfred				return (LIBUSB20_ERROR_OTHER);
703184610Salfred			}
704184610Salfred		}
705184610Salfred		fsep = pdev->privBeData;
706184610Salfred		xfer = pdev->pTransfer;
707184610Salfred		fsep += temp.ep_index;
708184610Salfred		xfer += temp.ep_index;
709184610Salfred
710184610Salfred		/* update transfer status */
711184610Salfred
712184610Salfred		if (fsep->status == 0) {
713184610Salfred			xfer->aFrames = fsep->aFrames;
714184610Salfred			xfer->timeComplete = fsep->isoc_time_complete;
715184610Salfred			xfer->status = LIBUSB20_TRANSFER_COMPLETED;
716184610Salfred		} else if (fsep->status == USB_ERR_CANCELLED) {
717184610Salfred			xfer->aFrames = 0;
718184610Salfred			xfer->timeComplete = 0;
719184610Salfred			xfer->status = LIBUSB20_TRANSFER_CANCELLED;
720184610Salfred		} else if (fsep->status == USB_ERR_STALLED) {
721184610Salfred			xfer->aFrames = 0;
722184610Salfred			xfer->timeComplete = 0;
723184610Salfred			xfer->status = LIBUSB20_TRANSFER_STALL;
724184610Salfred		} else if (fsep->status == USB_ERR_TIMEOUT) {
725184610Salfred			xfer->aFrames = 0;
726184610Salfred			xfer->timeComplete = 0;
727184610Salfred			xfer->status = LIBUSB20_TRANSFER_TIMED_OUT;
728184610Salfred		} else {
729184610Salfred			xfer->aFrames = 0;
730184610Salfred			xfer->timeComplete = 0;
731184610Salfred			xfer->status = LIBUSB20_TRANSFER_ERROR;
732184610Salfred		}
733184610Salfred		libusb20_tr_callback_wrapper(xfer);
734184610Salfred	}
735184610Salfred	return (0);			/* done */
736184610Salfred}
737184610Salfred
738184610Salfredstatic int
739184610Salfredugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize,
740184610Salfred    uint32_t MaxFrameCount, uint8_t ep_no)
741184610Salfred{
742185087Salfred	struct usb2_fs_open temp;
743184610Salfred	struct usb2_fs_endpoint *fsep;
744184610Salfred
745185087Salfred	memset(&temp, 0, sizeof(temp));
746185087Salfred
747184610Salfred	fsep = xfer->pdev->privBeData;
748184610Salfred	fsep += xfer->trIndex;
749184610Salfred
750184610Salfred	temp.max_bufsize = MaxBufSize;
751184610Salfred	temp.max_frames = MaxFrameCount;
752184610Salfred	temp.ep_index = xfer->trIndex;
753184610Salfred	temp.ep_no = ep_no;
754184610Salfred
755184610Salfred	if (ioctl(xfer->pdev->file, USB_FS_OPEN, &temp)) {
756184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
757184610Salfred	}
758184610Salfred	/* maximums might have changed - update */
759184610Salfred	xfer->maxFrames = temp.max_frames;
760184610Salfred
761184610Salfred	/* "max_bufsize" should be multiple of "max_packet_length" */
762184610Salfred	xfer->maxTotalLength = temp.max_bufsize;
763184610Salfred	xfer->maxPacketLen = temp.max_packet_length;
764184610Salfred
765184610Salfred	/* setup buffer and length lists */
766184610Salfred	fsep->ppBuffer = xfer->ppBuffer;/* zero copy */
767184610Salfred	fsep->pLength = xfer->pLength;	/* zero copy */
768184610Salfred
769184610Salfred	return (0);			/* success */
770184610Salfred}
771184610Salfred
772184610Salfredstatic int
773184610Salfredugen20_tr_close(struct libusb20_transfer *xfer)
774184610Salfred{
775185087Salfred	struct usb2_fs_close temp;
776184610Salfred
777185087Salfred	memset(&temp, 0, sizeof(temp));
778185087Salfred
779184610Salfred	temp.ep_index = xfer->trIndex;
780184610Salfred
781184610Salfred	if (ioctl(xfer->pdev->file, USB_FS_CLOSE, &temp)) {
782184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
783184610Salfred	}
784184610Salfred	return (0);			/* success */
785184610Salfred}
786184610Salfred
787184610Salfredstatic int
788184610Salfredugen20_tr_clear_stall_sync(struct libusb20_transfer *xfer)
789184610Salfred{
790185087Salfred	struct usb2_fs_clear_stall_sync temp;
791184610Salfred
792185087Salfred	memset(&temp, 0, sizeof(temp));
793185087Salfred
794184610Salfred	/* if the transfer is active, an error will be returned */
795184610Salfred
796184610Salfred	temp.ep_index = xfer->trIndex;
797184610Salfred
798184610Salfred	if (ioctl(xfer->pdev->file, USB_FS_CLEAR_STALL_SYNC, &temp)) {
799184610Salfred		return (LIBUSB20_ERROR_INVALID_PARAM);
800184610Salfred	}
801184610Salfred	return (0);			/* success */
802184610Salfred}
803184610Salfred
804184610Salfredstatic void
805184610Salfredugen20_tr_submit(struct libusb20_transfer *xfer)
806184610Salfred{
807185087Salfred	struct usb2_fs_start temp;
808184610Salfred	struct usb2_fs_endpoint *fsep;
809184610Salfred
810185087Salfred	memset(&temp, 0, sizeof(temp));
811185087Salfred
812184610Salfred	fsep = xfer->pdev->privBeData;
813184610Salfred	fsep += xfer->trIndex;
814184610Salfred
815184610Salfred	fsep->nFrames = xfer->nFrames;
816184610Salfred	fsep->flags = 0;
817184610Salfred	if (!(xfer->flags & LIBUSB20_TRANSFER_SINGLE_SHORT_NOT_OK)) {
818184610Salfred		fsep->flags |= USB_FS_FLAG_SINGLE_SHORT_OK;
819184610Salfred	}
820184610Salfred	if (!(xfer->flags & LIBUSB20_TRANSFER_MULTI_SHORT_NOT_OK)) {
821184610Salfred		fsep->flags |= USB_FS_FLAG_MULTI_SHORT_OK;
822184610Salfred	}
823184610Salfred	if (xfer->flags & LIBUSB20_TRANSFER_FORCE_SHORT) {
824184610Salfred		fsep->flags |= USB_FS_FLAG_FORCE_SHORT;
825184610Salfred	}
826184610Salfred	if (xfer->flags & LIBUSB20_TRANSFER_DO_CLEAR_STALL) {
827184610Salfred		fsep->flags |= USB_FS_FLAG_CLEAR_STALL;
828184610Salfred	}
829184610Salfred	fsep->timeout = xfer->timeout;
830184610Salfred
831184610Salfred	temp.ep_index = xfer->trIndex;
832184610Salfred
833184610Salfred	if (ioctl(xfer->pdev->file, USB_FS_START, &temp)) {
834184610Salfred		/* ignore any errors - should never happen */
835184610Salfred	}
836184610Salfred	return;				/* success */
837184610Salfred}
838184610Salfred
839184610Salfredstatic void
840184610Salfredugen20_tr_cancel_async(struct libusb20_transfer *xfer)
841184610Salfred{
842185087Salfred	struct usb2_fs_stop temp;
843184610Salfred
844185087Salfred	memset(&temp, 0, sizeof(temp));
845185087Salfred
846184610Salfred	temp.ep_index = xfer->trIndex;
847184610Salfred
848184610Salfred	if (ioctl(xfer->pdev->file, USB_FS_STOP, &temp)) {
849184610Salfred		/* ignore any errors - should never happen */
850184610Salfred	}
851184610Salfred	return;
852184610Salfred}
853184610Salfred
854184610Salfredstatic int
855184610Salfredugen20_be_ioctl(uint32_t cmd, void *data)
856184610Salfred{
857184610Salfred	int f;
858185087Salfred	int error;
859184610Salfred
860189110Sthompsa	f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
861184610Salfred	if (f < 0)
862184610Salfred		return (LIBUSB20_ERROR_OTHER);
863185087Salfred	error = ioctl(f, cmd, data);
864185087Salfred	if (error == -1) {
865184610Salfred		if (errno == EPERM) {
866185087Salfred			error = LIBUSB20_ERROR_ACCESS;
867184610Salfred		} else {
868185087Salfred			error = LIBUSB20_ERROR_OTHER;
869184610Salfred		}
870184610Salfred	}
871184610Salfred	close(f);
872185087Salfred	return (error);
873184610Salfred}
874184610Salfred
875184610Salfredstatic int
876188622Sthompsaugen20_dev_get_iface_desc(struct libusb20_device *pdev,
877188622Sthompsa    uint8_t iface_index, char *buf, uint8_t len)
878188622Sthompsa{
879188622Sthompsa	struct usb2_gen_descriptor ugd;
880188622Sthompsa
881188622Sthompsa	memset(&ugd, 0, sizeof(ugd));
882188622Sthompsa
883188622Sthompsa	ugd.ugd_data = buf;
884188622Sthompsa	ugd.ugd_maxlen = len;
885188622Sthompsa	ugd.ugd_iface_index = iface_index;
886188622Sthompsa
887188622Sthompsa	if (ioctl(pdev->file, USB_GET_IFACE_DRIVER, &ugd)) {
888188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
889188622Sthompsa	}
890188622Sthompsa	return (0);
891188622Sthompsa}
892188622Sthompsa
893188622Sthompsastatic int
894188622Sthompsaugen20_dev_get_info(struct libusb20_device *pdev,
895188622Sthompsa    struct usb2_device_info *pinfo)
896188622Sthompsa{
897188622Sthompsa	if (ioctl(pdev->file, USB_GET_DEVICEINFO, pinfo)) {
898188622Sthompsa		return (LIBUSB20_ERROR_INVALID_PARAM);
899188622Sthompsa	}
900188622Sthompsa	return (0);
901188622Sthompsa}
902188622Sthompsa
903188622Sthompsastatic int
904184610Salfredugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
905185087Salfred    uint16_t quirk_index, struct libusb20_quirk *pq)
906184610Salfred{
907184610Salfred	struct usb2_gen_quirk q;
908185087Salfred	int error;
909184610Salfred
910184610Salfred	memset(&q, 0, sizeof(q));
911184610Salfred
912185087Salfred	q.index = quirk_index;
913184610Salfred
914185087Salfred	error = ugen20_be_ioctl(USB_DEV_QUIRK_GET, &q);
915184610Salfred
916185087Salfred	if (error) {
917184610Salfred		if (errno == EINVAL) {
918184610Salfred			return (LIBUSB20_ERROR_NOT_FOUND);
919184610Salfred		}
920184610Salfred	} else {
921184610Salfred		pq->vid = q.vid;
922184610Salfred		pq->pid = q.pid;
923184610Salfred		pq->bcdDeviceLow = q.bcdDeviceLow;
924184610Salfred		pq->bcdDeviceHigh = q.bcdDeviceHigh;
925184610Salfred		strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
926184610Salfred	}
927185087Salfred	return (error);
928184610Salfred}
929184610Salfred
930184610Salfredstatic int
931185087Salfredugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
932184610Salfred    struct libusb20_quirk *pq)
933184610Salfred{
934184610Salfred	struct usb2_gen_quirk q;
935185087Salfred	int error;
936184610Salfred
937184610Salfred	memset(&q, 0, sizeof(q));
938184610Salfred
939185087Salfred	q.index = quirk_index;
940184610Salfred
941185087Salfred	error = ugen20_be_ioctl(USB_QUIRK_NAME_GET, &q);
942184610Salfred
943185087Salfred	if (error) {
944184610Salfred		if (errno == EINVAL) {
945184610Salfred			return (LIBUSB20_ERROR_NOT_FOUND);
946184610Salfred		}
947184610Salfred	} else {
948184610Salfred		strlcpy(pq->quirkname, q.quirkname, sizeof(pq->quirkname));
949184610Salfred	}
950185087Salfred	return (error);
951184610Salfred}
952184610Salfred
953184610Salfredstatic int
954184610Salfredugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
955184610Salfred    struct libusb20_quirk *pq)
956184610Salfred{
957184610Salfred	struct usb2_gen_quirk q;
958185087Salfred	int error;
959184610Salfred
960184610Salfred	memset(&q, 0, sizeof(q));
961184610Salfred
962184610Salfred	q.vid = pq->vid;
963184610Salfred	q.pid = pq->pid;
964184610Salfred	q.bcdDeviceLow = pq->bcdDeviceLow;
965184610Salfred	q.bcdDeviceHigh = pq->bcdDeviceHigh;
966184610Salfred	strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
967184610Salfred
968185087Salfred	error = ugen20_be_ioctl(USB_DEV_QUIRK_ADD, &q);
969185087Salfred	if (error) {
970184610Salfred		if (errno == ENOMEM) {
971184610Salfred			return (LIBUSB20_ERROR_NO_MEM);
972184610Salfred		}
973184610Salfred	}
974185087Salfred	return (error);
975184610Salfred}
976184610Salfred
977184610Salfredstatic int
978184610Salfredugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
979184610Salfred    struct libusb20_quirk *pq)
980184610Salfred{
981184610Salfred	struct usb2_gen_quirk q;
982185087Salfred	int error;
983184610Salfred
984184610Salfred	memset(&q, 0, sizeof(q));
985184610Salfred
986184610Salfred	q.vid = pq->vid;
987184610Salfred	q.pid = pq->pid;
988184610Salfred	q.bcdDeviceLow = pq->bcdDeviceLow;
989184610Salfred	q.bcdDeviceHigh = pq->bcdDeviceHigh;
990184610Salfred	strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
991184610Salfred
992185087Salfred	error = ugen20_be_ioctl(USB_DEV_QUIRK_REMOVE, &q);
993185087Salfred	if (error) {
994184610Salfred		if (errno == EINVAL) {
995184610Salfred			return (LIBUSB20_ERROR_NOT_FOUND);
996184610Salfred		}
997184610Salfred	}
998185087Salfred	return (error);
999184610Salfred}
1000184610Salfred
1001184610Salfredstatic int
1002188987Sthompsaugen20_root_set_template(struct libusb20_backend *pbe, int temp)
1003188987Sthompsa{
1004188987Sthompsa	return (ugen20_be_ioctl(USB_SET_TEMPLATE, &temp));
1005188987Sthompsa}
1006188987Sthompsa
1007188987Sthompsastatic int
1008188987Sthompsaugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
1009188987Sthompsa{
1010188987Sthompsa	return (ugen20_be_ioctl(USB_GET_TEMPLATE, ptemp));
1011188987Sthompsa}
1012