1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/*
268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) * Copyright © 2011-2013 Martin Pieuchot <mpi@openbsd.org>
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * This library is free software; you can redistribute it and/or
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * modify it under the terms of the GNU Lesser General Public
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * License as published by the Free Software Foundation; either
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * version 2.1 of the License, or (at your option) any later version.
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * This library is distributed in the hope that it will be useful,
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * but WITHOUT ANY WARRANTY; without even the implied warranty of
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Lesser General Public License for more details.
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * You should have received a copy of the GNU Lesser General Public
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * License along with this library; if not, write to the Free Software
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <sys/time.h>
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <sys/types.h>
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <errno.h>
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <fcntl.h>
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <stdio.h>
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <stdlib.h>
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string.h>
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <unistd.h>
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <dev/usb/usb.h>
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "libusb.h"
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "libusbi.h"
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct device_priv {
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	char *devname;				/* name of the ugen(4) node */
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	int fd;					/* device file descriptor */
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	unsigned char *cdesc;			/* active config descriptor */
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usb_device_descriptor_t ddesc;		/* usb device descriptor */
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct handle_priv {
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int pipe[2];				/* for event notification */
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int endpoints[USB_MAX_ENDPOINTS];
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/*
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Backend functions
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_get_device_list(struct libusb_context *,
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    struct discovered_devs **);
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_open(struct libusb_device_handle *);
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void obsd_close(struct libusb_device_handle *);
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_get_device_descriptor(struct libusb_device *, unsigned char *,
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int *);
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_get_active_config_descriptor(struct libusb_device *,
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned char *, size_t, int *);
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_get_config_descriptor(struct libusb_device *, uint8_t,
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned char *, size_t, int *);
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_get_configuration(struct libusb_device_handle *, int *);
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_set_configuration(struct libusb_device_handle *, int);
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_claim_interface(struct libusb_device_handle *, int);
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_release_interface(struct libusb_device_handle *, int);
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_set_interface_altsetting(struct libusb_device_handle *, int,
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int);
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_clear_halt(struct libusb_device_handle *, unsigned char);
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_reset_device(struct libusb_device_handle *);
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void obsd_destroy_device(struct libusb_device *);
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_submit_transfer(struct usbi_transfer *);
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_cancel_transfer(struct usbi_transfer *);
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic void obsd_clear_transfer_priv(struct usbi_transfer *);
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_handle_events(struct libusb_context *ctx, struct pollfd *,
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    nfds_t, int);
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int obsd_clock_gettime(int, struct timespec *);
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/*
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Private functions
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int _errno_to_libusb(int);
8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static int _cache_active_config_descriptor(struct libusb_device *);
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int _sync_control_transfer(struct usbi_transfer *);
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int _sync_gen_transfer(struct usbi_transfer *);
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstatic int _access_endpoint(struct libusb_transfer *);
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)static int _bus_open(int);
9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst struct usbi_os_backend openbsd_backend = {
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	"Synchronous OpenBSD backend",
95ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	0,
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	NULL,				/* init() */
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	NULL,				/* exit() */
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_get_device_list,
99ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	NULL,				/* hotplug_poll */
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_open,
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_close,
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_get_device_descriptor,
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_get_active_config_descriptor,
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_get_config_descriptor,
106ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	NULL,				/* get_config_descriptor_by_value() */
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_get_configuration,
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_set_configuration,
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_claim_interface,
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_release_interface,
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_set_interface_altsetting,
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_clear_halt,
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_reset_device,
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	NULL,				/* kernel_driver_active() */
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	NULL,				/* detach_kernel_driver() */
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	NULL,				/* attach_kernel_driver() */
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_destroy_device,
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_submit_transfer,
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_cancel_transfer,
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_clear_transfer_priv,
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_handle_events,
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	obsd_clock_gettime,
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	sizeof(struct device_priv),
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	sizeof(struct handle_priv),
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	0,				/* transfer_priv_size */
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	0,				/* add_iso_packet_size */
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#define DEVPATH	"/dev/"
13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#define USBDEV	DEVPATH "usb"
13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_get_device_list(struct libusb_context * ctx,
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct discovered_devs **discdevs)
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	struct discovered_devs *ddd;
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct libusb_device *dev;
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv;
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct usb_device_info di;
14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	struct usb_device_ddesc dd;
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	unsigned long session_id;
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	char devices[USB_MAX_DEVICES];
15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	char busnode[16];
15268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	char *udevname;
15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	int fd, addr, i, j;
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	for (i = 0; i < 8; i++) {
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		snprintf(busnode, sizeof(busnode), USBDEV "%d", i);
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		if ((fd = open(busnode, O_RDWR)) < 0) {
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if (errno != ENOENT && errno != ENXIO)
16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				usbi_err(ctx, "could not open %s", busnode);
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			continue;
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		bzero(devices, sizeof(devices));
16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			if (devices[addr])
16968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				continue;
17068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
17168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			di.udi_addr = addr;
17268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			if (ioctl(fd, USB_DEVICEINFO, &di) < 0)
17368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				continue;
17468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
17568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			/*
17668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			 * XXX If ugen(4) is attached to the USB device
17768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			 * it will be used.
17868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			 */
17968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			udevname = NULL;
18068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			for (j = 0; j < USB_MAX_DEVNAMES; j++)
18168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				if (!strncmp("ugen", di.udi_devnames[j], 4)) {
18268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					udevname = strdup(di.udi_devnames[j]);
18368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					break;
18468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				}
18568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
18668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			session_id = (di.udi_bus << 8 | di.udi_addr);
18768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			dev = usbi_get_device_by_session_id(ctx, session_id);
18868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
18968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			if (dev == NULL) {
19068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dev = usbi_alloc_device(ctx, session_id);
19168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				if (dev == NULL) {
19268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					close(fd);
19368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					return (LIBUSB_ERROR_NO_MEM);
19468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				}
19568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
19668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dev->bus_number = di.udi_bus;
19768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dev->device_address = di.udi_addr;
19868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dev->speed = di.udi_speed;
19968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
20068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dpriv = (struct device_priv *)dev->os_priv;
20168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dpriv->fd = -1;
20268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dpriv->cdesc = NULL;
20368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dpriv->devname = udevname;
20468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
20568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dd.udd_bus = di.udi_bus;
20668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dd.udd_addr = di.udi_addr;
20768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				if (ioctl(fd, USB_DEVICE_GET_DDESC, &dd) < 0) {
20868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					libusb_unref_device(dev);
20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					continue;
21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				}
21168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				dpriv->ddesc = dd.udd_desc;
21268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
21368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				if (_cache_active_config_descriptor(dev)) {
21468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					libusb_unref_device(dev);
21568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					continue;
21668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				}
21768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
21868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				if (usbi_sanitize_device(dev))
21968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)					libusb_unref_device(dev);
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			}
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
22268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			ddd = discovered_devs_append(*discdevs, dev);
22368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			if (ddd == NULL) {
22468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				close(fd);
22568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)				return (LIBUSB_ERROR_NO_MEM);
226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			}
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
22868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			*discdevs = ddd;
22968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			devices[addr] = 1;
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
23268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		close(fd);
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_open(struct libusb_device_handle *handle)
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
24368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	char devnode[16];
244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
24568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (dpriv->devname) {
24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		/*
24768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		 * Only open ugen(4) attached devices read-write, all
24868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		 * read-only operations are done through the bus node.
24968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		 */
25068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		snprintf(devnode, sizeof(devnode), DEVPATH "%s.00",
25168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		    dpriv->devname);
25268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		dpriv->fd = open(devnode, O_RDWR);
253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (dpriv->fd < 0)
254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			return _errno_to_libusb(errno);
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
25668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		usbi_dbg("open %s: fd %d", devnode, dpriv->fd);
25768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	}
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (pipe(hpriv->pipe) < 0)
260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->pipe[0], POLLIN);
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid
266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_close(struct libusb_device_handle *handle)
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
27168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (dpriv->devname) {
27268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		usbi_dbg("close: fd %d", dpriv->fd);
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
27468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		close(dpriv->fd);
27568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		dpriv->fd = -1;
27668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	}
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	close(hpriv->pipe[0]);
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	close(hpriv->pipe[1]);
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int *host_endian)
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	*host_endian = 0;
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_get_active_config_descriptor(struct libusb_device *dev,
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned char *buf, size_t len, int *host_endian)
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
30468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	len = MIN(len, UGETW(ucd->wTotalLength));
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("len %d", len);
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	memcpy(buf, dpriv->cdesc, len);
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	*host_endian = 0;
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
31468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	return (len);
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned char *buf, size_t len, int *host_endian)
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
32168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	struct usb_device_fdesc udf;
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int fd, err;
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
32468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if ((fd = _bus_open(dev->bus_number)) < 0)
32568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return _errno_to_libusb(errno);
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
32768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_bus = dev->bus_number;
32868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_addr = dev->device_address;
32968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_config_index = idx;
33068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_size = len;
33168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_data = buf;
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
33368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("index %d, len %d", udf.udf_config_index, len);
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
33568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		err = errno;
33768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		close(fd);
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(err);
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
34068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	close(fd);
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	*host_endian = 0;
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
34468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	return (len);
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_get_configuration(struct libusb_device_handle *handle, int *config)
349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
35168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
35368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	*config = ucd->bConfigurationValue;
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
35568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("bConfigurationValue %d", *config);
356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_set_configuration(struct libusb_device_handle *handle, int config)
362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
36568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (dpriv->devname == NULL)
36668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return (LIBUSB_ERROR_NOT_SUPPORTED);
36768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
36868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("bConfigurationValue %d", config);
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
37368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	return _cache_active_config_descriptor(handle->dev);
374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_claim_interface(struct libusb_device_handle *handle, int iface)
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int i;
381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	for (i = 0; i < USB_MAX_ENDPOINTS; i++)
383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		hpriv->endpoints[i] = -1;
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
388eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_release_interface(struct libusb_device_handle *handle, int iface)
390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int i;
393eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	for (i = 0; i < USB_MAX_ENDPOINTS; i++)
395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (hpriv->endpoints[i] >= 0)
396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			close(hpriv->endpoints[i]);
397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
399eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
402eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int altsetting)
404eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
405eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
406eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct usb_alt_interface intf;
407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
40868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (dpriv->devname == NULL)
40968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return (LIBUSB_ERROR_NOT_SUPPORTED);
41068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("iface %d, setting %d", iface, altsetting);
412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	memset(&intf, 0, sizeof(intf));
414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	intf.uai_interface_index = iface;
416eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	intf.uai_alt_no = altsetting;
417eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
420eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
422eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct usb_ctl_request req;
42868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	int fd, err;
42968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
43068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if ((fd = _bus_open(handle->dev->bus_number)) < 0)
43168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return _errno_to_libusb(errno);
432eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
433eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
43568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	req.ucr_addr = handle->dev->device_address;
436eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
437eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	req.ucr_request.bRequest = UR_CLEAR_FEATURE;
438eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	USETW(req.ucr_request.wIndex, endpoint);
440eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	USETW(req.ucr_request.wLength, 0);
441eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
44268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (ioctl(fd, USB_REQUEST, &req) < 0) {
44368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		err = errno;
44468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		close(fd);
44568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return _errno_to_libusb(err);
44668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	}
44768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	close(fd);
448eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_reset_device(struct libusb_device_handle *handle)
454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
455eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
457eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_ERROR_NOT_SUPPORTED);
458eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid
461eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_destroy_device(struct libusb_device *dev)
462eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	free(dpriv->cdesc);
46868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	free(dpriv->devname);
469eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
470eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
472eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_submit_transfer(struct usbi_transfer *itransfer)
473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct libusb_transfer *transfer;
475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct handle_priv *hpriv;
476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int err = 0;
477eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
480eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
481eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	switch (transfer->type) {
484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case LIBUSB_TRANSFER_TYPE_CONTROL:
485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		err = _sync_control_transfer(itransfer);
486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		break;
487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (IS_XFEROUT(transfer)) {
489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			/* Isochronous write is not supported */
490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			err = LIBUSB_ERROR_NOT_SUPPORTED;
491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		err = _sync_gen_transfer(itransfer);
494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		break;
495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case LIBUSB_TRANSFER_TYPE_BULK:
496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (IS_XFEROUT(transfer) &&
498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		    transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			err = LIBUSB_ERROR_NOT_SUPPORTED;
500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		err = _sync_gen_transfer(itransfer);
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		break;
504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (err)
507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return (err);
508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (write(hpriv->pipe[1], &itransfer, sizeof(itransfer)) < 0)
510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_cancel_transfer(struct usbi_transfer *itransfer)
517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_ERROR_NOT_SUPPORTED);
521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
522eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid
524eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_clear_transfer_priv(struct usbi_transfer *itransfer)
525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/* Nothing to do */
529eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
530eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
531eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds,
533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int num_ready)
534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct libusb_device_handle *handle;
536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct handle_priv *hpriv = NULL;
537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct usbi_transfer *itransfer;
538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct pollfd *pollfd;
539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int i, err = 0;
540eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
541eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("");
542eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
543eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	pthread_mutex_lock(&ctx->open_devs_lock);
544eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	for (i = 0; i < nfds && num_ready > 0; i++) {
545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		pollfd = &fds[i];
546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (!pollfd->revents)
548eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			continue;
549eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		hpriv = NULL;
551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		num_ready--;
552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		list_for_each_entry(handle, &ctx->open_devs, list,
553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		    struct libusb_device_handle) {
554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			hpriv = (struct handle_priv *)handle->os_priv;
555eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
556eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if (hpriv->pipe[0] == pollfd->fd)
557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				break;
558eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
559eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			hpriv = NULL;
560eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
561eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
562eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (NULL == hpriv) {
563eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_dbg("fd %d is not an event pipe!", pollfd->fd);
564eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			err = ENOENT;
565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (pollfd->revents & POLLERR) {
569eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]);
570eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			usbi_handle_disconnect(handle);
571eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			continue;
572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (read(hpriv->pipe[0], &itransfer, sizeof(itransfer)) < 0) {
575eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			err = errno;
576eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
577eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		}
578eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
579eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if ((err = usbi_handle_transfer_completion(itransfer,
580eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		    LIBUSB_TRANSFER_COMPLETED)))
581eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			break;
582eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
583eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	pthread_mutex_unlock(&ctx->open_devs_lock);
584eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
585eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (err)
586eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(err);
587eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_SUCCESS);
589eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
590eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
592eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochobsd_clock_gettime(int clkid, struct timespec *tp)
593eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
594eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("clock %d", clkid);
595eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
596eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (clkid == USBI_CLOCK_REALTIME)
597eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return clock_gettime(CLOCK_REALTIME, tp);
598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
599eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (clkid == USBI_CLOCK_MONOTONIC)
600eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return clock_gettime(CLOCK_MONOTONIC, tp);
601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
602eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_ERROR_INVALID_PARAM);
603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
604eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
605eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
606eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch_errno_to_libusb(int err)
607eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
60868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("error: %s (%d)", strerror(err), err);
60968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
610eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	switch (err) {
611eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case EIO:
612eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return (LIBUSB_ERROR_IO);
613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case EACCES:
614eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return (LIBUSB_ERROR_ACCESS);
615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case ENOENT:
616eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return (LIBUSB_ERROR_NO_DEVICE);
617eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	case ENOMEM:
618eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return (LIBUSB_ERROR_NO_MEM);
61968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	case ETIMEDOUT:
62068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return (LIBUSB_ERROR_TIMEOUT);
621eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
622eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
623eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (LIBUSB_ERROR_OTHER);
624eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
625eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
626eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
62768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)_cache_active_config_descriptor(struct libusb_device *dev)
628eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
629eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
63068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	struct usb_device_cdesc udc;
63168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	struct usb_device_fdesc udf;
632eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	unsigned char* buf;
63368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	int fd, len, err;
634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
63568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if ((fd = _bus_open(dev->bus_number)) < 0)
63668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return _errno_to_libusb(errno);
637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
63868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("fd %d, addr %d", fd, dev->device_address);
639eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
64068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udc.udc_bus = dev->bus_number;
64168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udc.udc_addr = dev->device_address;
64268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udc.udc_config_index = USB_CURRENT_CONFIG_INDEX;
64368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (ioctl(fd, USB_DEVICE_GET_CDESC, &udc) < 0) {
64468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		err = errno;
64568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		close(fd);
646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
64768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	}
648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
64968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("active bLength %d", udc.udc_desc.bLength);
650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
65168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	len = UGETW(udc.udc_desc.wTotalLength);
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	buf = malloc(len);
653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (buf == NULL)
654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return (LIBUSB_ERROR_NO_MEM);
655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
65668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_bus = dev->bus_number;
65768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_addr = dev->device_address;
65868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_config_index = udc.udc_config_index;
65968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_size = len;
66068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	udf.udf_data = buf;
661eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("index %d, len %d", udf.udf_config_index, len);
663eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
66568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		err = errno;
66668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		close(fd);
667eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		free(buf);
66868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return _errno_to_libusb(err);
669eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
67068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	close(fd);
671eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
672eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (dpriv->cdesc)
673eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		free(dpriv->cdesc);
674eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	dpriv->cdesc = buf;
675eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
67668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	return (LIBUSB_SUCCESS);
677eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
678eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
679eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
680eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch_sync_control_transfer(struct usbi_transfer *itransfer)
681eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
682eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct libusb_transfer *transfer;
683eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct libusb_control_setup *setup;
684eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv;
685eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct usb_ctl_request req;
686eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
687eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
688eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
689eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	setup = (struct libusb_control_setup *)transfer->buffer;
690eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
69168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	usbi_dbg("type %x request %x value %x index %d length %d timeout %d",
692eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    setup->bmRequestType, setup->bRequest,
693eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    libusb_le16_to_cpu(setup->wValue),
694eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    libusb_le16_to_cpu(setup->wIndex),
695eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	    libusb_le16_to_cpu(setup->wLength), transfer->timeout);
696eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
69768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	req.ucr_addr = transfer->dev_handle->dev->device_address;
698eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	req.ucr_request.bmRequestType = setup->bmRequestType;
699eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	req.ucr_request.bRequest = setup->bRequest;
700ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch	/* Don't use USETW, libusbx already deals with the endianness */
701eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	(*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
702eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	(*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
703eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	(*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
704eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
705eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
706eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
707eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		req.ucr_flags = USBD_SHORT_XFER_OK;
708eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
70968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (dpriv->devname == NULL) {
71068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		/*
71168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		 * XXX If the device is not attached to ugen(4) it is
71268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		 * XXX still possible to submit a control transfer but
71368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		 * XXX with the default timeout only.
71468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		 */
71568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		int fd, err;
716eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
71768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		if ((fd = _bus_open(transfer->dev_handle->dev->bus_number)) < 0)
71868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			return _errno_to_libusb(errno);
71968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
72068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		if ((ioctl(fd, USB_REQUEST, &req)) < 0) {
72168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			err = errno;
72268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			close(fd);
72368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			return _errno_to_libusb(err);
72468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		}
72568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		close(fd);
72668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	} else {
72768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
72868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			return _errno_to_libusb(errno);
72968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
73068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
73168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)			return _errno_to_libusb(errno);
73268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	}
733eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
734eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	itransfer->transferred = req.ucr_actlen;
735eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
736eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("transferred %d", itransfer->transferred);
737eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
738eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (0);
739eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
740eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
741eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
742eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch_access_endpoint(struct libusb_transfer *transfer)
743eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
744eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct handle_priv *hpriv;
745eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct device_priv *dpriv;
74668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	char devnode[16];
747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int fd, endpt;
748eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	mode_t mode;
749eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
752eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
753eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	endpt = UE_GET_ADDR(transfer->endpoint);
754eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
755eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
756eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	usbi_dbg("endpoint %d mode %d", endpt, mode);
757eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
758eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (hpriv->endpoints[endpt] < 0) {
75968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		/* Pick the right endpoint node */
76068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		snprintf(devnode, sizeof(devnode), DEVPATH "%s.%02d",
76168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		    dpriv->devname, endpt);
762eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
763eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		/* We may need to read/write to the same endpoint later. */
764eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
765eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if ((fd = open(devnode, mode)) < 0)
766eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				return (-1);
767eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
768eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		hpriv->endpoints[endpt] = fd;
769eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
770eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
771eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (hpriv->endpoints[endpt]);
772eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
773eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
774eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint
775eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch_sync_gen_transfer(struct usbi_transfer *itransfer)
776eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch{
777eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	struct libusb_transfer *transfer;
77868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	struct device_priv *dpriv;
779eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	int fd, nr = 1;
780eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
781eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
78268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
78368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
78468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	if (dpriv->devname == NULL)
78568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)		return (LIBUSB_ERROR_NOT_SUPPORTED);
786eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
787eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	/*
788eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	 * Bulk, Interrupt or Isochronous transfer depends on the
789eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	 * endpoint and thus the node to open.
790eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	 */
791eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if ((fd = _access_endpoint(transfer)) < 0)
792eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
793eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
794eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
795eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
796eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
797eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (IS_XFERIN(transfer)) {
798eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
799eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch			if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
800eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch				return _errno_to_libusb(errno);
801eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
802eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		nr = read(fd, transfer->buffer, transfer->length);
803eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	} else {
804eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		nr = write(fd, transfer->buffer, transfer->length);
805eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	}
806eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
807eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	if (nr < 0)
808eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch		return _errno_to_libusb(errno);
809eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
810eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	itransfer->transferred = nr;
811eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
812eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch	return (0);
813eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
81468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
81568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int
81668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)_bus_open(int number)
81768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles){
81868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	char busnode[16];
81968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
82068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	snprintf(busnode, sizeof(busnode), USBDEV "%d", number);
82168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
82268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)	return open(busnode, O_RDWR);
82368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
824